LCOV - code coverage report
Current view: top level - EnergyPlus - HVACInterfaceManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 569 626 90.9 %
Date: 2024-08-24 18:31:18 Functions: 7 7 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 <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Fmath.hh>
      53             : 
      54             : // EnergyPlus Headers
      55             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      56             : #include <EnergyPlus/DataAirLoop.hh>
      57             : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      58             : #include <EnergyPlus/DataContaminantBalance.hh>
      59             : #include <EnergyPlus/DataConvergParams.hh>
      60             : #include <EnergyPlus/DataHVACGlobals.hh>
      61             : #include <EnergyPlus/FluidProperties.hh>
      62             : #include <EnergyPlus/HVACInterfaceManager.hh>
      63             : #include <EnergyPlus/OutputProcessor.hh>
      64             : #include <EnergyPlus/Plant/DataPlant.hh>
      65             : #include <EnergyPlus/PlantUtilities.hh>
      66             : #include <EnergyPlus/UtilityRoutines.hh>
      67             : 
      68             : namespace EnergyPlus::HVACInterfaceManager {
      69             : 
      70             : // MODULE INFORMATION:
      71             : //       AUTHOR         Rick Strand
      72             : //       DATE WRITTEN   October 1998
      73             : //       MODIFIED       na
      74             : //       RE-ENGINEERED  na
      75             : 
      76             : // PURPOSE OF THIS MODULE:
      77             : // This module contains one or more routines for checking the convergence
      78             : // of the various HVAC loops and passing information across interface
      79             : // boundaries.
      80             : 
      81             : // METHODOLOGY EMPLOYED:
      82             : // The upper level HVAC managers call the routine(s) contained in this
      83             : // module as a last step.  The node information is passed across the
      84             : // interface boundary and the logical flag is set if the nodes across
      85             : // from each other are not within tolerance.
      86             : 
      87    25710548 : void UpdateHVACInterface(EnergyPlusData &state,
      88             :                          int const AirLoopNum, // airloop number for which air loop this is
      89             :                          DataConvergParams::CalledFrom const CalledFrom,
      90             :                          int const OutletNode,    // Node number for the outlet of the side of the loop just simulated
      91             :                          int const InletNode,     // Node number for the inlet of the side that needs the outlet node data
      92             :                          bool &OutOfToleranceFlag // True when the other side of the loop need to be (re)simulated
      93             : )
      94             : {
      95             : 
      96             :     // SUBROUTINE INFORMATION:
      97             :     //       AUTHOR         Rick Strand
      98             :     //       DATE WRITTEN   October 1998
      99             : 
     100             :     // PURPOSE OF THIS SUBROUTINE:
     101             :     // This subroutine manages any generic HVAC loop interface.
     102             : 
     103             :     // METHODOLOGY EMPLOYED:
     104             :     // This is a simple "forward" interface where all of the properties
     105             :     // from the outlet of one side of the loop get transferred directly
     106             :     // to the inlet node of the corresponding other side of the loop.
     107             : 
     108    25710548 :     auto &TmpRealARR = state.dataHVACInterfaceMgr->TmpRealARR;
     109    25710548 :     auto &airLoopConv = state.dataConvergeParams->AirLoopConvergence(AirLoopNum);
     110    25710548 :     auto &thisInletNode = state.dataLoopNodes->Node(InletNode);
     111    25710548 :     int const iCall = (int)CalledFrom;
     112             : 
     113    25710548 :     if ((CalledFrom == DataConvergParams::CalledFrom::AirSystemDemandSide) && (OutletNode == 0)) {
     114             :         // Air loop has no return path - only check mass flow and then set return inlet node mass flow to sum of demand side inlet nodes
     115             : 
     116       15269 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     117       15269 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     118       15269 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     119       15269 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     120             : 
     121       15269 :         Real64 totDemandSideMassFlow = 0.0;
     122       15269 :         Real64 totDemandSideMinAvail = 0.0;
     123       15269 :         Real64 totDemandSideMaxAvail = 0.0;
     124       30538 :         for (int demIn = 1; demIn <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumSupplyNodes; ++demIn) {
     125       15269 :             int demInNode = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).ZoneEquipSupplyNodeNum(demIn);
     126       15269 :             auto const &node = state.dataLoopNodes->Node(demInNode);
     127       15269 :             totDemandSideMassFlow += node.MassFlowRate;
     128       15269 :             totDemandSideMinAvail += node.MassFlowRateMinAvail;
     129       15269 :             totDemandSideMaxAvail += node.MassFlowRateMaxAvail;
     130             :         }
     131       15269 :         TmpRealARR = airLoopConv.HVACFlowDemandToSupplyTolValue;
     132       15269 :         airLoopConv.HVACFlowDemandToSupplyTolValue[0] = std::abs(totDemandSideMassFlow - thisInletNode.MassFlowRate);
     133      152690 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     134      137421 :             airLoopConv.HVACFlowDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     135             :         }
     136       15269 :         if (airLoopConv.HVACFlowDemandToSupplyTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     137        5242 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     138        5242 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     139             :         }
     140             : 
     141       15269 :         thisInletNode.MassFlowRate = totDemandSideMassFlow;
     142       15269 :         thisInletNode.MassFlowRateMinAvail = totDemandSideMinAvail;
     143       15269 :         thisInletNode.MassFlowRateMaxAvail = totDemandSideMaxAvail;
     144       15269 :         return;
     145             :     }
     146             : 
     147             :     // Calculate the approximate energy difference across interface for comparison
     148             :     Real64 DeltaEnergy =
     149    25695279 :         DataConvergParams::HVACCpApprox * ((state.dataLoopNodes->Node(OutletNode).MassFlowRate * state.dataLoopNodes->Node(OutletNode).Temp) -
     150    25695279 :                                            (thisInletNode.MassFlowRate * thisInletNode.Temp));
     151             : 
     152    25695279 :     if ((CalledFrom == DataConvergParams::CalledFrom::AirSystemDemandSide) && (OutletNode > 0)) {
     153             : 
     154    12179345 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     155    12179345 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     156    12179345 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     157    12179345 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     158    12179345 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     159       40525 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     160             :         }
     161    12179345 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     162       11609 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     163             :         }
     164             : 
     165    12179345 :         TmpRealARR = airLoopConv.HVACFlowDemandToSupplyTolValue;
     166    12179345 :         airLoopConv.HVACFlowDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     167   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     168   109614105 :             airLoopConv.HVACFlowDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     169             :         }
     170    12179345 :         if (airLoopConv.HVACFlowDemandToSupplyTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     171     3307328 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     172     3307328 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     173             :         }
     174             : 
     175    12179345 :         TmpRealARR = airLoopConv.HVACHumDemandToSupplyTolValue;
     176    12179345 :         airLoopConv.HVACHumDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     177   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     178   109614105 :             airLoopConv.HVACHumDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     179             :         }
     180    12179345 :         if (airLoopConv.HVACHumDemandToSupplyTolValue[0] > DataConvergParams::HVACHumRatToler) {
     181      447486 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     182      447486 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     183             :         }
     184             : 
     185    12179345 :         TmpRealARR = airLoopConv.HVACTempDemandToSupplyTolValue;
     186    12179345 :         airLoopConv.HVACTempDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     187   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     188   109614105 :             airLoopConv.HVACTempDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     189             :         }
     190    12179345 :         if (airLoopConv.HVACTempDemandToSupplyTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     191     2588728 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     192     2588728 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     193             :         }
     194             : 
     195    12179345 :         TmpRealARR = airLoopConv.HVACEnergyDemandToSupplyTolValue;
     196    12179345 :         airLoopConv.HVACEnergyDemandToSupplyTolValue[0] = std::abs(DeltaEnergy);
     197   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     198   109614105 :             airLoopConv.HVACEnergyDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     199             :         }
     200    12179345 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     201     4569379 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     202     4569379 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     203             :         }
     204             : 
     205    12179345 :         TmpRealARR = airLoopConv.HVACEnthalpyDemandToSupplyTolValue;
     206    12179345 :         airLoopConv.HVACEnthalpyDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     207   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     208   109614105 :             airLoopConv.HVACEnthalpyDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     209             :         }
     210    12179345 :         if (airLoopConv.HVACEnthalpyDemandToSupplyTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     211     1126616 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     212             :         }
     213             : 
     214    12179345 :         TmpRealARR = airLoopConv.HVACPressureDemandToSupplyTolValue;
     215    12179345 :         airLoopConv.HVACPressureDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     216   121793450 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     217   109614105 :             airLoopConv.HVACPressureDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     218             :         }
     219    12179345 :         if (airLoopConv.HVACPressureDemandToSupplyTolValue[0] > DataConvergParams::HVACPressToler) {
     220       12141 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     221             :         }
     222             : 
     223    12179345 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     224       40525 :             TmpRealARR = airLoopConv.HVACCO2DemandToSupplyTolValue;
     225       40525 :             airLoopConv.HVACCO2DemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     226      405250 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     227      364725 :                 airLoopConv.HVACCO2DemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     228             :             }
     229       40525 :             if (airLoopConv.HVACCO2DemandToSupplyTolValue[0] > DataConvergParams::HVACCO2Toler) {
     230        9287 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     231        9287 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     232             :             }
     233             :         }
     234             : 
     235    12179345 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     236       11609 :             TmpRealARR = airLoopConv.HVACGenContamDemandToSupplyTolValue;
     237       11609 :             airLoopConv.HVACGenContamDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     238      116090 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     239      104481 :                 airLoopConv.HVACGenContamDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     240             :             }
     241       11609 :             if (airLoopConv.HVACGenContamDemandToSupplyTolValue[0] > DataConvergParams::HVACGenContamToler) {
     242        4028 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     243        4028 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     244             :             }
     245             :         }
     246             : 
     247    25695279 :     } else if (CalledFrom == DataConvergParams::CalledFrom::AirSystemSupplySideDeck1) {
     248             : 
     249    13461342 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     250    13461342 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     251    13461342 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     252    13461342 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     253    13461342 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     254       40486 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     255             :         }
     256    13461342 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     257       11600 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     258             :         }
     259             : 
     260    13461342 :         TmpRealARR = airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue;
     261    13461342 :         airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[0] =
     262    13461342 :             std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     263   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     264   121152078 :             airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     265             :         }
     266    13461342 :         if (airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     267     3228211 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     268     3228211 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     269             :         }
     270             : 
     271    13461342 :         TmpRealARR = airLoopConv.HVACHumSupplyDeck1ToDemandTolValue;
     272    13461342 :         airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     273   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     274   121152078 :             airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     275             :         }
     276    13461342 :         if (airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACHumRatToler) {
     277     1928971 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     278     1928971 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     279             :         }
     280             : 
     281    13461342 :         TmpRealARR = airLoopConv.HVACTempSupplyDeck1ToDemandTolValue;
     282    13461342 :         airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     283   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     284   121152078 :             airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     285             :         }
     286    13461342 :         if (airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     287     6524006 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     288     6524006 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     289             :         }
     290             : 
     291    13461342 :         TmpRealARR = airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue;
     292    13461342 :         airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue[0] = DeltaEnergy;
     293   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     294   121152078 :             airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     295             :         }
     296    13461342 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     297     6849404 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     298     6849404 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     299             :         }
     300             : 
     301    13461342 :         TmpRealARR = airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue;
     302    13461342 :         airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     303   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     304   121152078 :             airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     305             :         }
     306    13461342 :         if (airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     307     4540598 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     308             :         }
     309             : 
     310    13461342 :         TmpRealARR = airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue;
     311    13461342 :         airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     312   134613420 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     313   121152078 :             airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     314             :         }
     315    13461342 :         if (airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACPressToler) {
     316      368369 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     317             :         }
     318             :         // CO2 check
     319    13461342 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     320       40486 :             TmpRealARR = airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue;
     321       40486 :             airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     322      404860 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     323      364374 :                 airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     324             :             }
     325       40486 :             if (airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACCO2Toler) {
     326        9275 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     327        9275 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     328             :             }
     329             :         }
     330             : 
     331    13461342 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     332       11600 :             TmpRealARR = airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue;
     333       11600 :             airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[0] =
     334       11600 :                 std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     335      116000 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     336      104400 :                 airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     337             :             }
     338       11600 :             if (airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACGenContamToler) {
     339        2590 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     340        2590 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     341             :             }
     342             :         }
     343             : 
     344       54592 :     } else if (CalledFrom == DataConvergParams::CalledFrom::AirSystemSupplySideDeck2) {
     345             : 
     346       54592 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     347       54592 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     348       54592 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     349       54592 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     350       54592 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     351           0 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     352             :         }
     353       54592 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     354           0 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     355             :         }
     356             : 
     357       54592 :         TmpRealARR = airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue;
     358       54592 :         airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[0] =
     359       54592 :             std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     360      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     361      491328 :             airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     362             :         }
     363       54592 :         if (airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     364       18390 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     365       18390 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     366             :         }
     367             : 
     368       54592 :         TmpRealARR = airLoopConv.HVACHumSupplyDeck2ToDemandTolValue;
     369       54592 :         airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     370      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     371      491328 :             airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     372             :         }
     373       54592 :         if (airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACHumRatToler) {
     374        6705 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     375        6705 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     376             :         }
     377             : 
     378       54592 :         TmpRealARR = airLoopConv.HVACTempSupplyDeck2ToDemandTolValue;
     379       54592 :         airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     380      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     381      491328 :             airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     382             :         }
     383       54592 :         if (airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     384       11282 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     385       11282 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     386             :         }
     387             : 
     388       54592 :         TmpRealARR = airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue;
     389       54592 :         airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue[0] = DeltaEnergy;
     390      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     391      491328 :             airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     392             :         }
     393       54592 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     394       20338 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     395       20338 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     396             :         }
     397             : 
     398       54592 :         TmpRealARR = airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue;
     399       54592 :         airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     400      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     401      491328 :             airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     402             :         }
     403       54592 :         if (airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     404       12263 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     405             :         }
     406             : 
     407       54592 :         TmpRealARR = airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue;
     408       54592 :         airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     409      545920 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     410      491328 :             airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     411             :         }
     412       54592 :         if (airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACPressToler) {
     413         108 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     414             :         }
     415             : 
     416       54592 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     417           0 :             TmpRealARR = airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue;
     418           0 :             airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     419           0 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     420           0 :                 airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     421             :             }
     422           0 :             if (airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACCO2Toler) {
     423           0 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     424           0 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     425             :             }
     426             :         }
     427       54592 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     428           0 :             TmpRealARR = airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue;
     429           0 :             airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[0] =
     430           0 :                 std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     431           0 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     432           0 :                 airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     433             :             }
     434           0 :             if (airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACGenContamToler) {
     435           0 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     436           0 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     437             :             }
     438             :         }
     439             :     }
     440             : 
     441             :     // Always update the new inlet conditions
     442    25695279 :     thisInletNode.Temp = state.dataLoopNodes->Node(OutletNode).Temp;
     443    25695279 :     thisInletNode.MassFlowRate = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
     444    25695279 :     thisInletNode.MassFlowRateMinAvail = state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail;
     445    25695279 :     thisInletNode.MassFlowRateMaxAvail = state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail;
     446    25695279 :     thisInletNode.Quality = state.dataLoopNodes->Node(OutletNode).Quality;
     447    25695279 :     thisInletNode.Press = state.dataLoopNodes->Node(OutletNode).Press;
     448    25695279 :     thisInletNode.Enthalpy = state.dataLoopNodes->Node(OutletNode).Enthalpy;
     449    25695279 :     thisInletNode.HumRat = state.dataLoopNodes->Node(OutletNode).HumRat;
     450             : 
     451    25695279 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     452       81011 :         thisInletNode.CO2 = state.dataLoopNodes->Node(OutletNode).CO2;
     453             :     }
     454             : 
     455    25695279 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     456       23209 :         thisInletNode.GenContam = state.dataLoopNodes->Node(OutletNode).GenContam;
     457             :     }
     458             : }
     459             : 
     460    36200510 : void UpdatePlantLoopInterface(EnergyPlusData &state,
     461             :                               PlantLocation const &plantLoc,    // The 'outlet node' Location
     462             :                               int const ThisLoopSideOutletNode, // Node number for the inlet of the side that needs the outlet node data
     463             :                               int const OtherLoopSideInletNode, // Node number for the outlet of the side of the loop just simulated
     464             :                               bool &OutOfToleranceFlag,         // True when the other side of the loop need to be (re)simulated
     465             :                               DataPlant::CommonPipeType const CommonPipeType)
     466             : {
     467             : 
     468             :     // SUBROUTINE INFORMATION:
     469             :     //       AUTHOR         Rick Strand
     470             :     //       DATE WRITTEN   October 1998
     471             :     //       MODIFIED       na
     472             :     //       RE-ENGINEERED  Brent Griffith, Sept. 2010
     473             :     //       RE-ENGINEERED  Dan Fisher,     Sept. 2010
     474             : 
     475             :     // PURPOSE OF THIS SUBROUTINE:
     476             :     // This subroutine manages any generic HVAC loop interface.
     477             : 
     478             :     // METHODOLOGY EMPLOYED:
     479             :     // This is a simple "forward" interface where all of the properties
     480             :     // from the outlet of one side of the loop get transfered
     481             :     // to the inlet node of the corresponding other side of the loop.
     482             :     // Temperatures are 'lagged' by loop capacitance (i.e. a 'tank')
     483             :     // between the outlet and inlet nodes.
     484             :     // the update from the demand side to the supply side always triggers
     485             :     // resimulation of the supply side if any state variable (or energy) is
     486             :     // out of tolerance.  Remsimulation of the demand side is only triggered if
     487             :     // flow or energy are out of tolerance.  This in effect checks flow and
     488             :     // ~.25C temperature difference.
     489             : 
     490             :     // SUBROUTINE PARAMETER DEFINITIONS:
     491             :     static constexpr std::string_view RoutineName("UpdatePlantLoopInterface");
     492             : 
     493    36200510 :     int LoopNum = plantLoc.loopNum;
     494    36200510 :     DataPlant::LoopSideLocation ThisLoopSideNum = plantLoc.loopSideNum;
     495    36200510 :     auto &convergence(state.dataConvergeParams->PlantConvergence(LoopNum));
     496             : 
     497             :     // reset out of tolerance flags
     498    36200510 :     convergence.PlantMassFlowNotConverged = false;
     499    36200510 :     convergence.PlantTempNotConverged = false;
     500             : 
     501             :     // set the LoopSide inlet node
     502    36200510 :     int ThisLoopSideInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSideNum).NodeNumIn;
     503             : 
     504             :     // save the inlet node temp for DeltaEnergy check
     505    36200510 :     Real64 OldOtherLoopSideInletMdot = state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate;
     506    36200510 :     Real64 OldTankOutletTemp = state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp;
     507             : 
     508             :     // calculate the specific heat
     509    36200510 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(
     510    36200510 :         state, state.dataPlnt->PlantLoop(LoopNum).FluidName, OldTankOutletTemp, state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName);
     511             : 
     512             :     // update the enthalpy
     513    36200510 :     state.dataLoopNodes->Node(OtherLoopSideInletNode).Enthalpy = Cp * state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp;
     514             : 
     515             :     // update the temperatures and flow rates
     516    36200510 :     auto &flow_demand_to_supply_tol(convergence.PlantFlowDemandToSupplyTolValue);
     517    36200510 :     auto &flow_supply_to_demand_tol(convergence.PlantFlowSupplyToDemandTolValue);
     518             :     Real64 MixedOutletTemp;
     519             :     Real64 TankOutletTemp;
     520    36200510 :     if (CommonPipeType == DataPlant::CommonPipeType::Single || CommonPipeType == DataPlant::CommonPipeType::TwoWay) {
     521             :         // update the temperature
     522      686714 :         UpdateCommonPipe(state, plantLoc, CommonPipeType, MixedOutletTemp);
     523      686714 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp = MixedOutletTemp;
     524      686714 :         TankOutletTemp = MixedOutletTemp;
     525      686714 :         if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     526      343357 :             rshift1(flow_demand_to_supply_tol);
     527      343357 :             flow_demand_to_supply_tol[0] = std::abs(OldOtherLoopSideInletMdot - state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     528      343357 :             if (flow_demand_to_supply_tol[0] > DataConvergParams::PlantFlowRateToler) {
     529           0 :                 convergence.PlantMassFlowNotConverged = true;
     530             :             }
     531             :         } else {
     532      343357 :             rshift1(flow_supply_to_demand_tol);
     533      343357 :             flow_supply_to_demand_tol[0] = std::abs(OldOtherLoopSideInletMdot - state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     534      343357 :             if (flow_supply_to_demand_tol[0] > DataConvergParams::PlantFlowRateToler) {
     535           0 :                 convergence.PlantMassFlowNotConverged = true;
     536             :             }
     537             :         }
     538             :         // Set the flow rate.  Continuity requires that the flow rates at the half loop inlet and outlet match
     539      686714 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRate = state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate;
     540             :         // Update this LoopSide inlet node Min/MaxAvail to this LoopSide outlet node Min/MaxAvail
     541      686714 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRateMinAvail =
     542      686714 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMinAvail;
     543      686714 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRateMaxAvail =
     544      686714 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMaxAvail;
     545             : 
     546             :     } else { // no common pipe
     547    35513796 :         UpdateHalfLoopInletTemp(state, LoopNum, ThisLoopSideNum, TankOutletTemp);
     548             :         // update the temperature
     549    35513796 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp = TankOutletTemp;
     550             :         // Set the flow tolerance array
     551    35513796 :         if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     552    17761823 :             rshift1(flow_demand_to_supply_tol);
     553    35523646 :             flow_demand_to_supply_tol[0] = std::abs(state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate -
     554    17761823 :                                                     state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     555    17761823 :             if (flow_demand_to_supply_tol[0] > DataConvergParams::PlantFlowRateToler) {
     556     1754073 :                 convergence.PlantMassFlowNotConverged = true;
     557             :             }
     558             :         } else {
     559    17751973 :             rshift1(flow_supply_to_demand_tol);
     560    35503946 :             flow_supply_to_demand_tol[0] = std::abs(state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate -
     561    17751973 :                                                     state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     562    17751973 :             if (flow_supply_to_demand_tol[0] > DataConvergParams::PlantFlowRateToler) {
     563      612767 :                 convergence.PlantMassFlowNotConverged = true;
     564             :             }
     565             :         }
     566             :         //    PlantFlowTolValue(PlantQuePtr)  = ABS(Node(ThisLoopSideOutletNode)%MassFlowRate-Node(OtherLoopSideInletNode)%MassFlowRate)
     567             :         // Set the flow rate
     568    35513796 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate = state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate;
     569             :         // update the MIN/MAX available flow rates
     570    35513796 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRateMinAvail =
     571    35513796 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMinAvail;
     572    35513796 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRateMaxAvail =
     573    35513796 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMaxAvail;
     574             :         // update Quality.  Note: This update assumes that STEAM cannot be used with common pipes.
     575    35513796 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Quality = state.dataLoopNodes->Node(ThisLoopSideOutletNode).Quality;
     576             :         // pressure update  Note: This update assumes that PRESSURE SIMULATION cannot be used with common pipes.
     577    35513796 :         if (state.dataPlnt->PlantLoop(LoopNum).HasPressureComponents) {
     578             :             // Don't update pressure, let the pressure simulation handle pressures
     579             :         } else {
     580             :             // Do update pressure!
     581    35492736 :             state.dataLoopNodes->Node(OtherLoopSideInletNode).Press = state.dataLoopNodes->Node(ThisLoopSideOutletNode).Press;
     582             :         }
     583             :     }
     584             : 
     585             :     // temperature
     586    36200510 :     if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     587    18105180 :         auto &temp_demand_to_supply_tol(convergence.PlantTempDemandToSupplyTolValue);
     588    18105180 :         rshift1(temp_demand_to_supply_tol);
     589    18105180 :         temp_demand_to_supply_tol[0] = std::abs(OldTankOutletTemp - state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp);
     590    18105180 :         if (temp_demand_to_supply_tol[0] > DataConvergParams::PlantTemperatureToler) {
     591     4341115 :             convergence.PlantTempNotConverged = true;
     592             :         }
     593             :     } else {
     594    18095330 :         auto &temp_supply_to_demand_tol(convergence.PlantTempSupplyToDemandTolValue);
     595    18095330 :         rshift1(temp_supply_to_demand_tol);
     596    18095330 :         temp_supply_to_demand_tol[0] = std::abs(OldTankOutletTemp - state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp);
     597    18095330 :         if (temp_supply_to_demand_tol[0] > DataConvergParams::PlantTemperatureToler) {
     598     1992967 :             convergence.PlantTempNotConverged = true;
     599             :         }
     600             :     }
     601             : 
     602             :     // Set out of tolerance flags
     603    36200510 :     if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     604    18105180 :         if (convergence.PlantMassFlowNotConverged || convergence.PlantTempNotConverged) {
     605     4731085 :             OutOfToleranceFlag = true;
     606             :         }
     607             :     } else {
     608    18095330 :         if (convergence.PlantMassFlowNotConverged) {
     609      612767 :             OutOfToleranceFlag = true;
     610             :         }
     611             :     }
     612    36200510 : }
     613             : 
     614    35513796 : void UpdateHalfLoopInletTemp(EnergyPlusData &state, int const LoopNum, const DataPlant::LoopSideLocation TankInletLoopSide, Real64 &TankOutletTemp)
     615             : {
     616             : 
     617             :     // SUBROUTINE INFORMATION:
     618             :     //       AUTHOR         Rick Strand
     619             :     //       DATE WRITTEN   September 2001
     620             :     //       MODIFIED       Simon Rees, July 2007
     621             :     //                      Brent Griffith, Feb. 2010, add LoopNum arg
     622             :     //       RE-ENGINEERED  Brent Griffith, Sept 2010, generalize for both loop sides
     623             :     //                                           add pump heat from other loop
     624             :     //                      B.Griffith and L.Gu, Oct 2011, solve via analytical soln, use average over timestep
     625             : 
     626             :     // PURPOSE OF THIS SUBROUTINE:
     627             :     // This subroutine calculates the new loop side inlet temperature
     628             :     // based on the previous temperature of the mixed tank, mass flow rate and the new
     629             :     // outlet temperature on the supply side.  The temperature does not
     630             :     // pass directly across because the loop has some capacitance. It is
     631             :     // called separately but used for both supply-to-demand, and demand-to-supply
     632             : 
     633             :     // METHODOLOGY EMPLOYED:
     634             :     // This uses a analytical solution for changes in the
     635             :     // fluid loop temperature.  The user defines some volume of fluid
     636             :     // for the loop which gets converted to a fixed amount of mass.
     637             :     // The loop side inlet node is modeled as the outlet of a fully mixed
     638             :     // tank. Note that this routine is called repeatedly to re calculate
     639             :     // loop capacitance based on current plant conditions
     640             : 
     641    35513796 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     642             : 
     643             :     // SUBROUTINE PARAMETER DEFINITIONS:
     644    35513796 :     Real64 constexpr FracTotLoopMass(0.5); // Fraction of total loop mass assigned to the half loop
     645             :     static constexpr std::string_view RoutineName("UpdateHalfLoopInletTemp");
     646             : 
     647             :     // find tank inlet and outlet nodes
     648    35513796 :     DataPlant::LoopSideLocation TankOutletLoopSide = DataPlant::LoopSideOther[static_cast<int>(TankInletLoopSide)];
     649    35513796 :     int TankInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).NodeNumOut;
     650    35513796 :     Real64 TankInletTemp = state.dataLoopNodes->Node(TankInletNode).Temp;
     651             : 
     652             :     // This needs to be based on time to deal with system downstepping and repeated timesteps
     653    35513796 :     Real64 TimeElapsed = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + SysTimeElapsed;
     654    35513796 :     if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed != TimeElapsed) {
     655     6690250 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet =
     656     6690250 :             state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet;
     657     6690250 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed = TimeElapsed;
     658             :     }
     659             : 
     660    35513796 :     Real64 LastTankOutletTemp = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet;
     661             : 
     662             :     // calculate the specific heat for the capacitance calculation
     663    35513796 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(
     664    35513796 :         state, state.dataPlnt->PlantLoop(LoopNum).FluidName, LastTankOutletTemp, state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName);
     665             :     // set the fraction of loop mass assigned to each half loop outlet capacitance ('tank') calculation
     666             : 
     667             :     // calculate new loop inlet temperature.  The calculation is a simple 'tank' (thermal capacitance) calculation that includes:
     668             :     //--half of loop mass.  The other half is accounted for at the other half loop interface
     669             :     //--pump heat.  Pump heat for a single loop setpoint with pumps only on the supply side is added at the supply side inlet.
     670             :     //   Pump heat for a dual setpoint loop is added to each loop side inlet
     671             :     //  The previous tank temperature value is used to prevent accumulation of pump heat during iterations while recalculating
     672             :     // tank conditions each call.
     673             :     // Analytical solution for ODE, formulated for both final tank temp and average tank temp.
     674             : 
     675    35513796 :     Real64 TimeStepSeconds = state.dataHVACGlobal->TimeStepSysSec;
     676    35513796 :     Real64 MassFlowRate = state.dataLoopNodes->Node(TankInletNode).MassFlowRate;
     677    35513796 :     Real64 PumpHeat = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TotalPumpHeat;
     678    35513796 :     Real64 ThisTankMass = FracTotLoopMass * state.dataPlnt->PlantLoop(LoopNum).Mass;
     679             :     Real64 TankFinalTemp;
     680             :     Real64 TankAverageTemp;
     681    35513796 :     if (ThisTankMass <= 0.0) { // no mass, no plant loop volume
     682           0 :         if (MassFlowRate > 0.0) {
     683           0 :             TankFinalTemp = TankInletTemp + PumpHeat / (MassFlowRate * Cp);
     684           0 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     685             :         } else {
     686           0 :             TankFinalTemp = LastTankOutletTemp;
     687           0 :             TankAverageTemp = LastTankOutletTemp;
     688             :         }
     689             : 
     690             :     } else { // tank has mass
     691    35513796 :         if (MassFlowRate > 0.0) {
     692    18897368 :             Real64 const mdotCp = MassFlowRate * Cp;
     693    18897368 :             Real64 const mdotCpTempIn = mdotCp * TankInletTemp;
     694    18897368 :             Real64 const tankMassCp = ThisTankMass * Cp;
     695    18897368 :             Real64 const ExponentTerm = mdotCp / tankMassCp * TimeStepSeconds;
     696    18897368 :             if (ExponentTerm >= 700.0) {
     697           0 :                 TankFinalTemp = (mdotCp * TankInletTemp + PumpHeat) / mdotCp;
     698             : 
     699           0 :                 TankAverageTemp = (tankMassCp / mdotCp * (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) / TimeStepSeconds +
     700           0 :                                    (mdotCpTempIn + PumpHeat) / mdotCp);
     701             :             } else {
     702    18897368 :                 TankFinalTemp = (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) * std::exp(-ExponentTerm) +
     703    18897368 :                                 (mdotCpTempIn + PumpHeat) / (MassFlowRate * Cp);
     704             : 
     705    18897368 :                 TankAverageTemp = (tankMassCp / mdotCp * (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) * (1.0 - std::exp(-ExponentTerm)) /
     706             :                                        TimeStepSeconds +
     707    18897368 :                                    (mdotCpTempIn + PumpHeat) / mdotCp);
     708             :             }
     709             :         } else {
     710    16616428 :             TankFinalTemp = PumpHeat / (ThisTankMass * Cp) * TimeStepSeconds + LastTankOutletTemp;
     711    16616428 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     712             :         }
     713             :     }
     714             : 
     715             :     // update last tank outlet temperature
     716    35513796 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet = TankFinalTemp;
     717             : 
     718             :     // update heat transport and heat storage rates
     719    35513796 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_MdotCpDeltaT =
     720    35513796 :         (TankInletTemp - TankAverageTemp) * Cp * MassFlowRate;
     721    35513796 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_McpDTdt =
     722    35513796 :         (ThisTankMass * Cp * (TankFinalTemp - LastTankOutletTemp)) / TimeStepSeconds;
     723             : 
     724             :     // update report variable
     725    35513796 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_TankTemp = TankAverageTemp;
     726             : 
     727    35513796 :     TankOutletTemp = TankAverageTemp;
     728    35513796 : }
     729             : 
     730      686714 : void UpdateCommonPipe(EnergyPlusData &state,
     731             :                       PlantLocation const &TankInletPlantLoc,
     732             :                       DataPlant::CommonPipeType const CommonPipeType,
     733             :                       Real64 &MixedOutletTemp)
     734             : {
     735             : 
     736             :     // SUBROUTINE INFORMATION:
     737             :     //       AUTHOR         Rick Strand
     738             :     //       DATE WRITTEN   September 2001
     739             :     //       MODIFIED       Simon Rees, July 2007
     740             :     //                      Brent Griffith, Feb. 2010, add LoopNum arg
     741             :     //       RE-ENGINEERED  Brent Griffith, Sept 2010, generalize for both loop sides
     742             :     //                                           add pump heat from other loop
     743             :     //                      B.Griffith and L.Gu, Oct 2011, solve via analytical soln, use average over timestep
     744             : 
     745             :     // PURPOSE OF THIS SUBROUTINE:
     746             :     // This subroutine calculates the new loop side inlet temperature
     747             :     // based on the previous temperature of the mixed tank, mass flow rate and the new
     748             :     // outlet temperature on the supply side.  The temperature does not
     749             :     // pass directly across because the loop has some capacitance. It is
     750             :     // called separately but used for both supply-to-demand, and demand-to-supply
     751             : 
     752             :     // METHODOLOGY EMPLOYED:
     753             :     // This uses a analytical solution for changes in the
     754             :     // fluid loop temperature.  The user defines some volume of fluid
     755             :     // for the loop which gets converted to a fixed amount of mass.
     756             :     // The loop side inlet node is modeled as the outlet of a fully mixed
     757             :     // tank. Note that this routine is called repeatedly to re calculate
     758             :     // loop capacitance based on current plant conditions
     759             : 
     760             :     // Using/Aliasing
     761      686714 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     762             : 
     763             :     // SUBROUTINE PARAMETER DEFINITIONS:
     764             :     static constexpr std::string_view RoutineName("UpdateCommonPipe");
     765             : 
     766             :     // find tank inlet and outlet nodes
     767      686714 :     int LoopNum = TankInletPlantLoc.loopNum;
     768      686714 :     DataPlant::LoopSideLocation TankInletLoopSide = TankInletPlantLoc.loopSideNum;
     769      686714 :     DataPlant::LoopSideLocation TankOutletLoopSide = DataPlant::LoopSideOther[static_cast<int>(TankInletPlantLoc.loopSideNum)]; // Outlet loopside
     770      686714 :     int TankInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).NodeNumOut;
     771      686714 :     int TankOutletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).NodeNumIn;
     772             : 
     773      686714 :     Real64 TankInletTemp = state.dataLoopNodes->Node(TankInletNode).Temp;
     774             : 
     775             :     Real64 FracTotLoopMass; // Fraction of total loop mass assigned to the half loop
     776      686714 :     if (TankInletLoopSide == DataPlant::LoopSideLocation::Demand) {
     777             :         // for common pipe loops, assume 75% of plant loop volume is on the demand side
     778      343357 :         FracTotLoopMass = 0.25;
     779             :     } else {
     780      343357 :         FracTotLoopMass = 0.75;
     781             :     }
     782             : 
     783             :     // This needs to be based on time to deal with system downstepping and repeated timesteps
     784      686714 :     Real64 TimeElapsed = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + SysTimeElapsed;
     785      686714 :     if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed != TimeElapsed) {
     786       44218 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet =
     787       44218 :             state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet;
     788       44218 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed = TimeElapsed;
     789             :     }
     790             : 
     791      686714 :     Real64 LastTankOutletTemp = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet;
     792             : 
     793             :     // calculate the specific heat for the capacitance calculation
     794      686714 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(
     795      686714 :         state, state.dataPlnt->PlantLoop(LoopNum).FluidName, LastTankOutletTemp, state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName);
     796             : 
     797             :     // set the fraction of loop mass assigned to each half loop outlet capacitance ('tank') calculation
     798             : 
     799             :     // calculate new loop inlet temperature.  The calculation is a simple 'tank' (thermal capacitance) calculation that includes:
     800             :     //--half of loop mass.  The other half is accounted for at the other half loop interface
     801             :     //--pump heat.  Pump heat for a single loop setpoint with pumps only on the supply side is added at the supply side inlet.
     802             :     // Pump heat for a dual setpoint loop is added to each loop side inlet
     803             :     // The previous inlet side temp,'ThisLoopSideTankOutletTemp' is used to prevent accumulation of pump heat during iterations.
     804             :     // The placement of the 'tank' for common pipes is *after* the outlet node and *before* the flow split or flow mixing.
     805             :     // This requires no logical check in the code since for purposes of temperature calculations, it is identical to the
     806             :     // no common pipe case.
     807             :     // calculation is separated because for common pipe, a different split for mass fraction is applied
     808             :     // The pump heat source is swapped around here compared to no common pipe (so pump heat sort stays on its own side).
     809      686714 :     Real64 TimeStepSeconds = state.dataHVACGlobal->TimeStepSysSec;
     810      686714 :     Real64 MassFlowRate = state.dataLoopNodes->Node(TankInletNode).MassFlowRate;
     811      686714 :     Real64 PumpHeat = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).TotalPumpHeat;
     812      686714 :     Real64 ThisTankMass = FracTotLoopMass * state.dataPlnt->PlantLoop(LoopNum).Mass;
     813             : 
     814             :     Real64 TankFinalTemp;
     815             :     Real64 TankAverageTemp;
     816      686714 :     if (ThisTankMass <= 0.0) { // no mass, no plant loop volume
     817           0 :         if (MassFlowRate > 0.0) {
     818           0 :             TankFinalTemp = TankInletTemp + PumpHeat / (MassFlowRate * Cp);
     819           0 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     820             :         } else {
     821           0 :             TankFinalTemp = LastTankOutletTemp;
     822           0 :             TankAverageTemp = LastTankOutletTemp;
     823             :         }
     824             : 
     825             :     } else { // tank has mass
     826      686714 :         if (MassFlowRate > 0.0) {
     827      301875 :             TankFinalTemp = (LastTankOutletTemp - (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp)) *
     828      301875 :                                 std::exp(-(MassFlowRate * Cp) / (ThisTankMass * Cp) * TimeStepSeconds) +
     829      301875 :                             (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp);
     830      301875 :             TankAverageTemp = ((ThisTankMass * Cp) / (MassFlowRate * Cp) *
     831      301875 :                                    (LastTankOutletTemp - (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp)) *
     832      301875 :                                    (1.0 - std::exp(-(MassFlowRate * Cp) / (ThisTankMass * Cp) * TimeStepSeconds)) / TimeStepSeconds +
     833      301875 :                                (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp));
     834             :         } else {
     835             : 
     836      384839 :             TankFinalTemp = PumpHeat / (ThisTankMass * Cp) * TimeStepSeconds + LastTankOutletTemp;
     837      384839 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     838             :         }
     839             :     }
     840             :     // Common Pipe Simulation
     841      686714 :     if (CommonPipeType == DataPlant::CommonPipeType::Single) {
     842      261156 :         ManageSingleCommonPipe(state, LoopNum, TankOutletLoopSide, TankAverageTemp, MixedOutletTemp);
     843             :         // 2-way (controlled) common pipe simulation
     844      425558 :     } else if (CommonPipeType == DataPlant::CommonPipeType::TwoWay) {
     845      425558 :         PlantLocation TankOutletPlantLoc = {LoopNum, TankOutletLoopSide, 0, 0};
     846             : 
     847      425558 :         ManageTwoWayCommonPipe(state, TankOutletPlantLoc, TankAverageTemp);
     848      425558 :         MixedOutletTemp = state.dataLoopNodes->Node(TankOutletNode).Temp;
     849             :     }
     850             : 
     851      686714 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet = TankFinalTemp;
     852             : 
     853      686714 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_TankTemp = TankAverageTemp;
     854      686714 : }
     855             : 
     856      261156 : void ManageSingleCommonPipe(EnergyPlusData &state,
     857             :                             int const LoopNum,                          // plant loop number
     858             :                             DataPlant::LoopSideLocation const LoopSide, // plant loop side number
     859             :                             Real64 const TankOutletTemp, // inlet temperature to the common pipe passed in from the capacitance calculation
     860             :                             Real64 &MixedOutletTemp      // inlet temperature to the common pipe passed in from the capacitance calculation
     861             : )
     862             : {
     863             : 
     864             :     // SUBROUTINE INFORMATION:
     865             :     //       AUTHOR         Sankaranarayanan K P
     866             :     //       DATE WRITTEN   November 2006
     867             :     //       MODIFIED       B. Griffith, Jan 2010 clean up setup to allow mixing common pipe modes
     868             :     //                      B. Griffith, Mar 2010 add LoopNum arg and simplify
     869             :     //       RE-ENGINEERED  D. Fisher, Sept. 2010
     870             :     //                      B. Griffith, Oct 2011, major rewrite for plant upgrade
     871             : 
     872             :     // PURPOSE OF THIS SUBROUTINE:
     873             :     // To determine the conditions in common pipe viz., the flow flow temperature and direction of flow.
     874             : 
     875             :     // METHODOLOGY EMPLOYED:
     876             :     // Determine the flow on both sides of the common pipe. Decide if flow is coming into common pipe
     877             :     // or going out of common pipe. After that determine which interface calls the subroutine, i.e. if
     878             :     // called from "Demand to Supply" interface or "Supply to Demand" interface. Update the node temperatures
     879             :     // accordingly.
     880             : 
     881             :     // One time call to set up report variables and set common pipe 'type' flag
     882      261156 :     if (!state.dataHVACInterfaceMgr->CommonPipeSetupFinished) SetupCommonPipes(state);
     883             : 
     884      261156 :     auto &plantCommonPipe = state.dataHVACInterfaceMgr->PlantCommonPipe(LoopNum);
     885             : 
     886             :     // fill local node indexes
     887      261156 :     int NodeNumPriIn = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn;
     888      261156 :     int NodeNumPriOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut;
     889      261156 :     int NodeNumSecIn = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumIn;
     890      261156 :     int NodeNumSecOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumOut;
     891             : 
     892      261156 :     if (plantCommonPipe.MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
     893          18 :         plantCommonPipe.Flow = 0.0;
     894          18 :         plantCommonPipe.Temp = 0.0;
     895          18 :         plantCommonPipe.FlowDir = NoRecircFlow;
     896          18 :         plantCommonPipe.MyEnvrnFlag = false;
     897             :     }
     898      261156 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     899      259812 :         plantCommonPipe.MyEnvrnFlag = true;
     900             :     }
     901             : 
     902             :     // every time inits
     903      261156 :     Real64 MdotSec = state.dataLoopNodes->Node(NodeNumSecOut).MassFlowRate;
     904      261156 :     Real64 MdotPri = state.dataLoopNodes->Node(NodeNumPriOut).MassFlowRate;
     905             : 
     906             :     Real64 TempSecOutTankOut;
     907             :     Real64 TempPriOutTankOut;
     908      261156 :     if (LoopSide == DataPlant::LoopSideLocation::Supply) {
     909      130578 :         TempSecOutTankOut = TankOutletTemp;
     910      130578 :         TempPriOutTankOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).LoopSideInlet_TankTemp;
     911             :     } else {
     912      130578 :         TempPriOutTankOut = TankOutletTemp;
     913      130578 :         TempSecOutTankOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).LoopSideInlet_TankTemp;
     914             :     }
     915             : 
     916             :     // first do mass balances and find common pipe flow rate and direction
     917             :     Real64 MdotPriRCLeg; // flow rate of primary recirculation thru common pipe kg/s
     918             :     Real64 MdotSecRCLeg; // flow rate of secondary recirculation thru common pipe kg/s
     919             :     Real64 TempSecInlet; // temperature at secondary inlet deg C
     920             :     Real64 TempPriInlet; // temperature at primary inlet deg C
     921             :     int CPFlowDir;       // flow direction in single common pipe
     922             :     Real64 CommonPipeTemp;
     923      261156 :     if (MdotPri > MdotSec) {
     924       72349 :         MdotPriRCLeg = MdotPri - MdotSec;
     925       72349 :         if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) {
     926           0 :             MdotPriRCLeg = 0.0;
     927           0 :             CPFlowDir = NoRecircFlow;
     928             :         } else {
     929       72349 :             CPFlowDir = PrimaryRecirc;
     930             :         }
     931       72349 :         MdotSecRCLeg = 0.0;
     932       72349 :         CommonPipeTemp = TempPriOutTankOut;
     933      188807 :     } else if (MdotPri < MdotSec) {
     934        5248 :         MdotSecRCLeg = MdotSec - MdotPri;
     935        5248 :         if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) {
     936           0 :             MdotSecRCLeg = 0.0;
     937           0 :             CPFlowDir = NoRecircFlow;
     938             :         } else {
     939        5248 :             CPFlowDir = SecondaryRecirc;
     940             :         }
     941        5248 :         MdotPriRCLeg = 0.0;
     942        5248 :         CommonPipeTemp = TempSecOutTankOut;
     943             :     } else { // equal
     944      183559 :         MdotPriRCLeg = 0.0;
     945      183559 :         MdotSecRCLeg = 0.0;
     946      183559 :         CPFlowDir = NoRecircFlow;
     947      183559 :         CommonPipeTemp = (TempPriOutTankOut + TempSecOutTankOut) / 2.0;
     948             :     }
     949             : 
     950             :     // now calculate inlet temps
     951             : 
     952      261156 :     if (MdotSec > 0.0) {
     953       78818 :         TempSecInlet = (MdotPri * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut - MdotPriRCLeg * TempPriOutTankOut) / (MdotSec);
     954             :     } else {
     955      182338 :         TempSecInlet = TempPriOutTankOut;
     956             :     }
     957      261156 :     if (MdotPri > 0.0) {
     958       76517 :         TempPriInlet = (MdotSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut - MdotSecRCLeg * TempSecOutTankOut) / (MdotPri);
     959             :     } else {
     960      184639 :         TempPriInlet = TempSecOutTankOut;
     961             :     }
     962             : 
     963             :     // Update the Common Pipe Data structure for reporting purposes.
     964      261156 :     plantCommonPipe.Flow = max(MdotPriRCLeg, MdotSecRCLeg);
     965      261156 :     plantCommonPipe.Temp = CommonPipeTemp;
     966      261156 :     plantCommonPipe.FlowDir = CPFlowDir;
     967      261156 :     state.dataLoopNodes->Node(NodeNumSecIn).Temp = TempSecInlet;
     968      261156 :     state.dataLoopNodes->Node(NodeNumPriIn).Temp = TempPriInlet;
     969             : 
     970      261156 :     if (LoopSide == DataPlant::LoopSideLocation::Supply) {
     971      130578 :         MixedOutletTemp = TempPriInlet;
     972             :     } else {
     973      130578 :         MixedOutletTemp = TempSecInlet;
     974             :     }
     975      261156 : }
     976             : 
     977      425558 : void ManageTwoWayCommonPipe(EnergyPlusData &state, PlantLocation const &plantLoc, Real64 const TankOutletTemp)
     978             : {
     979             : 
     980             :     // SUBROUTINE INFORMATION:
     981             :     //       AUTHOR         B. Griffith
     982             :     //       DATE WRITTEN   June 2011
     983             :     //       MODIFIED       na
     984             :     //       RE-ENGINEERED  B. Griffith, Oct 2011.  rewrite
     985             : 
     986             :     // PURPOSE OF THIS SUBROUTINE:
     987             :     // manage two-way common pipe modeling at half-loop interface
     988             : 
     989             :     // METHODOLOGY EMPLOYED:
     990             :     // calculate mixed temperatures and various flow rates
     991             :     // sequential substitution of system of equations
     992             : 
     993             :     // REFERENCES:
     994             :     // reimplementation of CheckTwoWayCommonPipeConditions by Sankaranarayanan K P Jan 2007
     995             : 
     996             :     // SUBROUTINE PARAMETER DEFINITIONS:
     997             :     enum class UpdateType
     998             :     {
     999             :         DemandLedPrimaryInlet,
    1000             :         DemandLedSecondaryInlet,
    1001             :         SupplyLedPrimaryInlet,
    1002             :         SupplyLedSecondaryInlet
    1003      425558 :     } curCallingCase = UpdateType::SupplyLedPrimaryInlet;
    1004      425558 :     constexpr int MaxIterLimitCaseA(8);
    1005      425558 :     constexpr int MaxIterLimitCaseB(4);
    1006             : 
    1007             :     // one time setups
    1008      425558 :     if (!state.dataHVACInterfaceMgr->CommonPipeSetupFinished) SetupCommonPipes(state);
    1009             : 
    1010      425558 :     auto &plantCommonPipe(state.dataHVACInterfaceMgr->PlantCommonPipe(plantLoc.loopNum));
    1011      425558 :     auto &thisPlantLoop = state.dataPlnt->PlantLoop(plantLoc.loopNum);
    1012             : 
    1013             :     // fill local node indexes
    1014      425558 :     int const NodeNumPriIn = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn;
    1015      425558 :     int const NodeNumPriOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut;
    1016      425558 :     int const NodeNumSecIn = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumIn;
    1017      425558 :     int const NodeNumSecOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumOut;
    1018             : 
    1019             :     // begin environment inits
    1020      425558 :     if (plantCommonPipe.MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
    1021          60 :         plantCommonPipe.PriToSecFlow = 0.0;
    1022          60 :         plantCommonPipe.SecToPriFlow = 0.0;
    1023          60 :         plantCommonPipe.PriCPLegFlow = 0.0;
    1024          60 :         plantCommonPipe.SecCPLegFlow = 0.0;
    1025          60 :         plantCommonPipe.MyEnvrnFlag = false;
    1026             :     }
    1027             : 
    1028      425558 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1029      421918 :         plantCommonPipe.MyEnvrnFlag = true;
    1030             :     }
    1031             : 
    1032             :     // every time inits
    1033      425558 :     Real64 MdotSec = state.dataLoopNodes->Node(NodeNumSecOut).MassFlowRate; // assume known and fixed by demand side operation
    1034      425558 :     Real64 TempCPPrimaryCntrlSetPoint = state.dataLoopNodes->Node(NodeNumPriIn).TempSetPoint;
    1035      425558 :     Real64 TempCPSecondaryCntrlSetPoint = state.dataLoopNodes->Node(NodeNumSecIn).TempSetPoint;
    1036             : 
    1037             :     // 6 unknowns follow, fill with current values
    1038      425558 :     Real64 MdotPriToSec = plantCommonPipe.PriToSecFlow;
    1039      425558 :     Real64 MdotPriRCLeg = plantCommonPipe.PriCPLegFlow;
    1040      425558 :     Real64 MdotSecRCLeg = plantCommonPipe.SecCPLegFlow;
    1041      425558 :     Real64 TempSecInlet = state.dataLoopNodes->Node(NodeNumSecIn).Temp;
    1042      425558 :     Real64 TempPriInlet = state.dataLoopNodes->Node(NodeNumPriIn).Temp;
    1043             :     Real64 MdotPri =
    1044      425558 :         state.dataLoopNodes->Node(NodeNumPriOut).MassFlowRate; // may or may not be an unknown, If variable speed primary side, then unknown
    1045             : 
    1046             :     Real64 TempPriOutTankOut;
    1047             :     Real64 TempSecOutTankOut;
    1048      425558 :     if (plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
    1049      212779 :         TempSecOutTankOut = TankOutletTemp;
    1050      212779 :         TempPriOutTankOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).LoopSideInlet_TankTemp;
    1051             :     } else {
    1052      212779 :         TempPriOutTankOut = TankOutletTemp;
    1053      212779 :         TempSecOutTankOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).LoopSideInlet_TankTemp;
    1054             :     }
    1055             : 
    1056             :     // determine current case
    1057             :     // which side is being updated
    1058             :     // commonpipe control point is the inlet of one of the half loops
    1059      425558 :     if (plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) { // update primary inlet
    1060      244685 :         if (thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1061       31906 :             !thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1062       31906 :             curCallingCase = UpdateType::SupplyLedPrimaryInlet;
    1063             : 
    1064      361746 :         } else if (!thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1065      180873 :                    thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1066      180873 :             curCallingCase = UpdateType::DemandLedPrimaryInlet;
    1067             :         }
    1068             :     } else { // update secondary inlet
    1069      244685 :         if (thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1070       31906 :             !thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1071       31906 :             curCallingCase = UpdateType::SupplyLedSecondaryInlet;
    1072             : 
    1073      361746 :         } else if (!thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1074      180873 :                    thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1075      180873 :             curCallingCase = UpdateType::DemandLedSecondaryInlet;
    1076             :         }
    1077             :     }
    1078             : 
    1079      425558 :     switch (curCallingCase) {
    1080       63812 :     case UpdateType::SupplyLedPrimaryInlet:
    1081             :     case UpdateType::SupplyLedSecondaryInlet:
    1082             :         // CASE A, Primary/Supply Led
    1083             :         // six equations and six unknowns (although one has a setpoint)
    1084      574308 :         for (int loop = 1; loop <= MaxIterLimitCaseA; ++loop) {
    1085             : 
    1086             :             // eq 1
    1087      510496 :             if (std::abs(TempSecOutTankOut - TempCPPrimaryCntrlSetPoint) > DataPlant::DeltaTempTol) {
    1088      510496 :                 MdotPriToSec = MdotPriRCLeg * (TempCPPrimaryCntrlSetPoint - TempPriOutTankOut) / (TempSecOutTankOut - TempCPPrimaryCntrlSetPoint);
    1089      510496 :                 if (MdotPriToSec < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriToSec = 0.0;
    1090      510496 :                 if (MdotPriToSec > MdotSec) MdotPriToSec = MdotSec;
    1091             :             } else {
    1092           0 :                 MdotPriToSec = MdotSec; //  what to do (?)
    1093             :             }
    1094             :             // eq. 5
    1095      510496 :             MdotPriRCLeg = MdotPri - MdotPriToSec;
    1096      510496 :             if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriRCLeg = 0.0;
    1097             : 
    1098             :             // eq. 4
    1099      510496 :             MdotSecRCLeg = MdotSec - MdotPriToSec;
    1100      510496 :             if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotSecRCLeg = 0.0;
    1101             : 
    1102             :             // eq  6
    1103      510496 :             if ((MdotPriToSec + MdotSecRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1104      344176 :                 TempSecInlet = (MdotPriToSec * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut) / (MdotPriToSec + MdotSecRCLeg);
    1105             :             } else {
    1106      166320 :                 TempSecInlet = TempPriOutTankOut;
    1107             :             }
    1108             : 
    1109             :             // eq. 3
    1110      510496 :             if ((plantCommonPipe.SupplySideInletPumpType == FlowType::Variable) && (curCallingCase == UpdateType::SupplyLedPrimaryInlet)) {
    1111             :                 // MdotPri is a variable to be calculated and flow request needs to be made
    1112           0 :                 if (std::abs(TempCPPrimaryCntrlSetPoint) > DataPlant::DeltaTempTol) {
    1113             : 
    1114           0 :                     MdotPri = (MdotPriRCLeg * TempPriOutTankOut + MdotPriToSec * TempSecOutTankOut) / (TempCPPrimaryCntrlSetPoint);
    1115             : 
    1116           0 :                     if (MdotPri < DataBranchAirLoopPlant::MassFlowTolerance) MdotPri = 0.0;
    1117             :                 } else {
    1118           0 :                     MdotPri = MdotSec;
    1119             :                 }
    1120           0 :                 PlantLocation thisPlantLoc = {plantLoc.loopNum, DataPlant::LoopSideLocation::Supply, 1, 0};
    1121           0 :                 PlantUtilities::SetActuatedBranchFlowRate(state, MdotPri, NodeNumPriIn, thisPlantLoc, false);
    1122             :             }
    1123             : 
    1124             :             // eq. 2
    1125      510496 :             if ((MdotPriToSec + MdotPriRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1126      344112 :                 TempPriInlet = (MdotPriToSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut) / (MdotPriToSec + MdotPriRCLeg);
    1127             :             } else {
    1128      166384 :                 TempPriInlet = TempSecOutTankOut;
    1129             :             }
    1130             :         }
    1131       63812 :         break;
    1132      361746 :     case UpdateType::DemandLedPrimaryInlet:
    1133             :     case UpdateType::DemandLedSecondaryInlet:
    1134             :         // case B. Secondary/demand led
    1135             : 
    1136             :         // six equations and six unknowns (although one has a setpoint)
    1137     1808730 :         for (int loop = 1; loop <= MaxIterLimitCaseB; ++loop) {
    1138             :             // eq 1,
    1139     1446984 :             if (std::abs(TempPriOutTankOut - TempSecOutTankOut) > DataPlant::DeltaTempTol) {
    1140     1062808 :                 MdotPriToSec = MdotSec * (TempCPSecondaryCntrlSetPoint - TempSecOutTankOut) / (TempPriOutTankOut - TempSecOutTankOut);
    1141     1062808 :                 if (MdotPriToSec < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriToSec = 0.0;
    1142     1062808 :                 if (MdotPriToSec > MdotSec) MdotPriToSec = MdotSec;
    1143             :             } else {
    1144      384176 :                 MdotPriToSec = MdotSec;
    1145             :             }
    1146             : 
    1147             :             // eq. 2,
    1148     1446984 :             if ((MdotPriToSec + MdotPriRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1149      725457 :                 TempPriInlet = (MdotPriToSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut) / (MdotPriToSec + MdotPriRCLeg);
    1150             :             } else {
    1151      721527 :                 TempPriInlet = TempSecOutTankOut;
    1152             :             }
    1153             : 
    1154             :             // eq. 3
    1155     1446984 :             if ((plantCommonPipe.SupplySideInletPumpType == FlowType::Variable) && (curCallingCase == UpdateType::DemandLedPrimaryInlet)) {
    1156             :                 // MdotPri is a variable to be calculated and flow request made
    1157           0 :                 if (std::abs(TempPriOutTankOut - TempPriInlet) > DataPlant::DeltaTempTol) {
    1158           0 :                     MdotPri = MdotSec * (TempCPSecondaryCntrlSetPoint - TempSecOutTankOut) / (TempPriOutTankOut - TempPriInlet);
    1159           0 :                     if (MdotPri < DataBranchAirLoopPlant::MassFlowTolerance) MdotPri = 0.0;
    1160             :                 } else {
    1161           0 :                     MdotPri = MdotSec;
    1162             :                 }
    1163           0 :                 PlantLocation thisPlantLoc = {plantLoc.loopNum, DataPlant::LoopSideLocation::Supply, 1, 0};
    1164           0 :                 PlantUtilities::SetActuatedBranchFlowRate(state, MdotPri, NodeNumPriIn, thisPlantLoc, false);
    1165             :             }
    1166             : 
    1167             :             // eq. 4
    1168     1446984 :             MdotSecRCLeg = MdotSec - MdotPriToSec;
    1169     1446984 :             if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotSecRCLeg = 0.0;
    1170             : 
    1171             :             // eq. 5
    1172     1446984 :             MdotPriRCLeg = MdotPri - MdotPriToSec;
    1173     1446984 :             if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriRCLeg = 0.0;
    1174             : 
    1175             :             // eq  6
    1176     1446984 :             if ((MdotPriToSec + MdotSecRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1177      724536 :                 TempSecInlet = (MdotPriToSec * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut) / (MdotPriToSec + MdotSecRCLeg);
    1178             :             } else {
    1179      722448 :                 TempSecInlet = TempPriOutTankOut;
    1180             :             }
    1181             :         }
    1182             :     }
    1183             : 
    1184             :     // update
    1185      425558 :     plantCommonPipe.PriToSecFlow = MdotPriToSec;
    1186      425558 :     plantCommonPipe.SecToPriFlow = MdotPriToSec;
    1187      425558 :     plantCommonPipe.PriCPLegFlow = MdotPriRCLeg;
    1188      425558 :     plantCommonPipe.SecCPLegFlow = MdotSecRCLeg;
    1189      425558 :     state.dataLoopNodes->Node(NodeNumSecIn).Temp = TempSecInlet;
    1190      425558 :     state.dataLoopNodes->Node(NodeNumPriIn).Temp = TempPriInlet;
    1191      425558 : }
    1192             : 
    1193          14 : void SetupCommonPipes(EnergyPlusData &state)
    1194             : {
    1195             : 
    1196             :     // SUBROUTINE INFORMATION:
    1197             :     //       AUTHOR         B. Griffith
    1198             :     //       DATE WRITTEN   Jan. 2010
    1199             :     //       MODIFIED       B. Griffith Oct. 2011
    1200             :     //       RE-ENGINEERED  na
    1201             : 
    1202             :     // PURPOSE OF THIS SUBROUTINE:
    1203             :     // collect allocation, outputs, and other set up for common pipes
    1204             : 
    1205          14 :     state.dataHVACInterfaceMgr->PlantCommonPipe.allocate(state.dataPlnt->TotNumLoops);
    1206             : 
    1207          52 :     for (int CurLoopNum = 1; CurLoopNum <= state.dataPlnt->TotNumLoops; ++CurLoopNum) {
    1208             : 
    1209             :         // reference to easily lookup the first item once
    1210          38 :         auto &thisPlantLoop = state.dataPlnt->PlantLoop(CurLoopNum);
    1211          38 :         auto &thisCommonPipe = state.dataHVACInterfaceMgr->PlantCommonPipe(CurLoopNum);
    1212          38 :         auto const &first_demand_component_type = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).Branch(1).Comp(1).Type;
    1213          38 :         auto const &first_supply_component_type = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp(1).Type;
    1214             : 
    1215          38 :         switch (thisPlantLoop.CommonPipeType) {
    1216          24 :         case DataPlant::CommonPipeType::No:
    1217          24 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::No;
    1218          24 :             break;
    1219           4 :         case DataPlant::CommonPipeType::Single: // Uncontrolled ('single') common pipe
    1220           4 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::Single;
    1221           8 :             SetupOutputVariable(state,
    1222             :                                 "Plant Common Pipe Mass Flow Rate",
    1223             :                                 Constant::Units::kg_s,
    1224           4 :                                 thisCommonPipe.Flow,
    1225             :                                 OutputProcessor::TimeStepType::System,
    1226             :                                 OutputProcessor::StoreType::Average,
    1227           4 :                                 thisPlantLoop.Name);
    1228           8 :             SetupOutputVariable(state,
    1229             :                                 "Plant Common Pipe Temperature",
    1230             :                                 Constant::Units::C,
    1231           4 :                                 thisCommonPipe.Temp,
    1232             :                                 OutputProcessor::TimeStepType::System,
    1233             :                                 OutputProcessor::StoreType::Average,
    1234           4 :                                 thisPlantLoop.Name);
    1235           4 :             SetupOutputVariable(state,
    1236             :                                 "Plant Common Pipe Flow Direction Status",
    1237             :                                 Constant::Units::None,
    1238           4 :                                 thisCommonPipe.FlowDir,
    1239             :                                 OutputProcessor::TimeStepType::System,
    1240             :                                 OutputProcessor::StoreType::Average,
    1241           4 :                                 thisPlantLoop.Name);
    1242             : 
    1243           4 :             if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1244             :                 // If/when the model supports variable-pumping primary, this can be removed.
    1245           1 :                 ShowWarningError(state, "SetupCommonPipes: detected variable speed pump on supply inlet of CommonPipe plant loop");
    1246           1 :                 ShowContinueError(state, format("Occurs on plant loop name = {}", thisPlantLoop.Name));
    1247           1 :                 ShowContinueError(state, "The common pipe model does not support varying the flow rate on the primary/supply side");
    1248           1 :                 ShowContinueError(state, "The primary/supply side will operate as if constant speed, and the simulation continues");
    1249             :             }
    1250           4 :             break;
    1251          10 :         case DataPlant::CommonPipeType::TwoWay: // Controlled ('two-way') common pipe
    1252          10 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::TwoWay;
    1253          20 :             SetupOutputVariable(state,
    1254             :                                 "Plant Common Pipe Primary Mass Flow Rate",
    1255             :                                 Constant::Units::kg_s,
    1256          10 :                                 thisCommonPipe.PriCPLegFlow,
    1257             :                                 OutputProcessor::TimeStepType::System,
    1258             :                                 OutputProcessor::StoreType::Average,
    1259          10 :                                 thisPlantLoop.Name);
    1260          20 :             SetupOutputVariable(state,
    1261             :                                 "Plant Common Pipe Secondary Mass Flow Rate",
    1262             :                                 Constant::Units::kg_s,
    1263          10 :                                 thisCommonPipe.SecCPLegFlow,
    1264             :                                 OutputProcessor::TimeStepType::System,
    1265             :                                 OutputProcessor::StoreType::Average,
    1266          10 :                                 thisPlantLoop.Name);
    1267          20 :             SetupOutputVariable(state,
    1268             :                                 "Plant Common Pipe Primary to Secondary Mass Flow Rate",
    1269             :                                 Constant::Units::kg_s,
    1270          10 :                                 thisCommonPipe.PriToSecFlow,
    1271             :                                 OutputProcessor::TimeStepType::System,
    1272             :                                 OutputProcessor::StoreType::Average,
    1273          10 :                                 thisPlantLoop.Name);
    1274          20 :             SetupOutputVariable(state,
    1275             :                                 "Plant Common Pipe Secondary to Primary Mass Flow Rate",
    1276             :                                 Constant::Units::kg_s,
    1277          10 :                                 thisCommonPipe.SecToPriFlow,
    1278             :                                 OutputProcessor::TimeStepType::System,
    1279             :                                 OutputProcessor::StoreType::Average,
    1280          10 :                                 thisPlantLoop.Name);
    1281             : 
    1282             :             // check type of pump on supply side inlet
    1283          10 :             if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpConstantSpeed) {
    1284           9 :                 thisCommonPipe.SupplySideInletPumpType = FlowType::Constant;
    1285           1 :             } else if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1286           0 :                 thisCommonPipe.SupplySideInletPumpType = FlowType::Variable;
    1287             :                 // If/when the model supports variable-pumping primary, this can be removed.
    1288           0 :                 ShowWarningError(state, "SetupCommonPipes: detected variable speed pump on supply inlet of TwoWayCommonPipe plant loop");
    1289           0 :                 ShowContinueError(state, format("Occurs on plant loop name = {}", thisPlantLoop.Name));
    1290           0 :                 ShowContinueError(state, "The common pipe model does not support varying the flow rate on the primary/supply side");
    1291           0 :                 ShowContinueError(state, "The primary/supply side will operate as if constant speed, and the simulation continues");
    1292             :             }
    1293             :             // check type of pump on demand side inlet
    1294          10 :             if (first_demand_component_type == DataPlant::PlantEquipmentType::PumpConstantSpeed) {
    1295           0 :                 thisCommonPipe.DemandSideInletPumpType = FlowType::Constant;
    1296          10 :             } else if (first_demand_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1297          10 :                 thisCommonPipe.DemandSideInletPumpType = FlowType::Variable;
    1298             :             }
    1299          10 :             break;
    1300           0 :         default:
    1301           0 :             assert(false);
    1302             :         }
    1303             :     }
    1304             : 
    1305          14 :     state.dataHVACInterfaceMgr->CommonPipeSetupFinished = true;
    1306          14 : }
    1307             : 
    1308             : } // namespace EnergyPlus::HVACInterfaceManager

Generated by: LCOV version 1.14