LCOV - code coverage report
Current view: top level - EnergyPlus - HVACInterfaceManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 48.5 % 623 302
Test Date: 2025-05-22 16:09:37 Functions: 42.9 % 7 3

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <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       152726 : 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       152726 :     auto &TmpRealARR = state.dataHVACInterfaceMgr->TmpRealARR;
     109       152726 :     auto &airLoopConv = state.dataConvergeParams->AirLoopConvergence(AirLoopNum);
     110       152726 :     auto &thisInletNode = state.dataLoopNodes->Node(InletNode);
     111       152726 :     int const iCall = (int)CalledFrom;
     112              : 
     113       152726 :     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            0 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     117            0 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     118            0 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     119            0 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     120              : 
     121            0 :         Real64 totDemandSideMassFlow = 0.0;
     122            0 :         Real64 totDemandSideMinAvail = 0.0;
     123            0 :         Real64 totDemandSideMaxAvail = 0.0;
     124            0 :         for (int demIn = 1; demIn <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumSupplyNodes; ++demIn) {
     125            0 :             int demInNode = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).ZoneEquipSupplyNodeNum(demIn);
     126            0 :             auto const &node = state.dataLoopNodes->Node(demInNode);
     127            0 :             totDemandSideMassFlow += node.MassFlowRate;
     128            0 :             totDemandSideMinAvail += node.MassFlowRateMinAvail;
     129            0 :             totDemandSideMaxAvail += node.MassFlowRateMaxAvail;
     130              :         }
     131            0 :         TmpRealARR = airLoopConv.HVACFlowDemandToSupplyTolValue;
     132            0 :         airLoopConv.HVACFlowDemandToSupplyTolValue[0] = std::abs(totDemandSideMassFlow - thisInletNode.MassFlowRate);
     133            0 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     134            0 :             airLoopConv.HVACFlowDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     135              :         }
     136            0 :         if (airLoopConv.HVACFlowDemandToSupplyTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     137            0 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     138            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     139              :         }
     140              : 
     141            0 :         thisInletNode.MassFlowRate = totDemandSideMassFlow;
     142            0 :         thisInletNode.MassFlowRateMinAvail = totDemandSideMinAvail;
     143            0 :         thisInletNode.MassFlowRateMaxAvail = totDemandSideMaxAvail;
     144            0 :         return;
     145              :     }
     146              : 
     147              :     // Calculate the approximate energy difference across interface for comparison
     148              :     Real64 DeltaEnergy =
     149       152726 :         DataConvergParams::HVACCpApprox * ((state.dataLoopNodes->Node(OutletNode).MassFlowRate * state.dataLoopNodes->Node(OutletNode).Temp) -
     150       152726 :                                            (thisInletNode.MassFlowRate * thisInletNode.Temp));
     151              : 
     152       152726 :     if ((CalledFrom == DataConvergParams::CalledFrom::AirSystemDemandSide) && (OutletNode > 0)) {
     153              : 
     154        75815 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     155        75815 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     156        75815 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     157        75815 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     158        75815 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     159            2 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     160              :         }
     161        75815 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     162            2 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     163              :         }
     164              : 
     165        75815 :         TmpRealARR = airLoopConv.HVACFlowDemandToSupplyTolValue;
     166        75815 :         airLoopConv.HVACFlowDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     167       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     168       682335 :             airLoopConv.HVACFlowDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     169              :         }
     170        75815 :         if (airLoopConv.HVACFlowDemandToSupplyTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     171        13631 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     172        13631 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     173              :         }
     174              : 
     175        75815 :         TmpRealARR = airLoopConv.HVACHumDemandToSupplyTolValue;
     176        75815 :         airLoopConv.HVACHumDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     177       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     178       682335 :             airLoopConv.HVACHumDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     179              :         }
     180        75815 :         if (airLoopConv.HVACHumDemandToSupplyTolValue[0] > DataConvergParams::HVACHumRatToler) {
     181         2347 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     182         2347 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     183              :         }
     184              : 
     185        75815 :         TmpRealARR = airLoopConv.HVACTempDemandToSupplyTolValue;
     186        75815 :         airLoopConv.HVACTempDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     187       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     188       682335 :             airLoopConv.HVACTempDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     189              :         }
     190        75815 :         if (airLoopConv.HVACTempDemandToSupplyTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     191        19157 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     192        19157 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     193              :         }
     194              : 
     195        75815 :         TmpRealARR = airLoopConv.HVACEnergyDemandToSupplyTolValue;
     196        75815 :         airLoopConv.HVACEnergyDemandToSupplyTolValue[0] = std::abs(DeltaEnergy);
     197       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     198       682335 :             airLoopConv.HVACEnergyDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     199              :         }
     200        75815 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     201        25961 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     202        25961 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     203              :         }
     204              : 
     205        75815 :         TmpRealARR = airLoopConv.HVACEnthalpyDemandToSupplyTolValue;
     206        75815 :         airLoopConv.HVACEnthalpyDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     207       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     208       682335 :             airLoopConv.HVACEnthalpyDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     209              :         }
     210        75815 :         if (airLoopConv.HVACEnthalpyDemandToSupplyTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     211         8614 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     212              :         }
     213              : 
     214        75815 :         TmpRealARR = airLoopConv.HVACPressureDemandToSupplyTolValue;
     215        75815 :         airLoopConv.HVACPressureDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     216       758150 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     217       682335 :             airLoopConv.HVACPressureDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     218              :         }
     219        75815 :         if (airLoopConv.HVACPressureDemandToSupplyTolValue[0] > DataConvergParams::HVACPressToler) {
     220           92 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     221              :         }
     222              : 
     223        75815 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     224            2 :             TmpRealARR = airLoopConv.HVACCO2DemandToSupplyTolValue;
     225            2 :             airLoopConv.HVACCO2DemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     226           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     227           18 :                 airLoopConv.HVACCO2DemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     228              :             }
     229            2 :             if (airLoopConv.HVACCO2DemandToSupplyTolValue[0] > DataConvergParams::HVACCO2Toler) {
     230            1 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     231            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     232              :             }
     233              :         }
     234              : 
     235        75815 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     236            2 :             TmpRealARR = airLoopConv.HVACGenContamDemandToSupplyTolValue;
     237            2 :             airLoopConv.HVACGenContamDemandToSupplyTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     238           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     239           18 :                 airLoopConv.HVACGenContamDemandToSupplyTolValue[logIndex] = TmpRealARR[logIndex - 1];
     240              :             }
     241            2 :             if (airLoopConv.HVACGenContamDemandToSupplyTolValue[0] > DataConvergParams::HVACGenContamToler) {
     242            1 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     243            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     244              :             }
     245              :         }
     246              : 
     247       152726 :     } else if (CalledFrom == DataConvergParams::CalledFrom::AirSystemSupplySideDeck1) {
     248              : 
     249        76909 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     250        76909 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     251        76909 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     252        76909 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     253        76909 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     254            2 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     255              :         }
     256        76909 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     257            2 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     258              :         }
     259              : 
     260        76909 :         TmpRealARR = airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue;
     261        76909 :         airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[0] =
     262        76909 :             std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     263       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     264       692181 :             airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     265              :         }
     266        76909 :         if (airLoopConv.HVACFlowSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     267        14909 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     268        14909 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     269              :         }
     270              : 
     271        76909 :         TmpRealARR = airLoopConv.HVACHumSupplyDeck1ToDemandTolValue;
     272        76909 :         airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     273       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     274       692181 :             airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     275              :         }
     276        76909 :         if (airLoopConv.HVACHumSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACHumRatToler) {
     277        12553 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     278        12553 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     279              :         }
     280              : 
     281        76909 :         TmpRealARR = airLoopConv.HVACTempSupplyDeck1ToDemandTolValue;
     282        76909 :         airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     283       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     284       692181 :             airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     285              :         }
     286        76909 :         if (airLoopConv.HVACTempSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     287        38616 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     288        38616 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     289              :         }
     290              : 
     291        76909 :         TmpRealARR = airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue;
     292        76909 :         airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue[0] = DeltaEnergy;
     293       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     294       692181 :             airLoopConv.HVACEnergySupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     295              :         }
     296        76909 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     297        32477 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     298        32477 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     299              :         }
     300              : 
     301        76909 :         TmpRealARR = airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue;
     302        76909 :         airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     303       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     304       692181 :             airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     305              :         }
     306        76909 :         if (airLoopConv.HVACEnthalpySupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     307        28375 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     308              :         }
     309              : 
     310        76909 :         TmpRealARR = airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue;
     311        76909 :         airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     312       769090 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     313       692181 :             airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     314              :         }
     315        76909 :         if (airLoopConv.HVACPressureSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACPressToler) {
     316           16 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     317              :         }
     318              :         // CO2 check
     319        76909 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     320            2 :             TmpRealARR = airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue;
     321            2 :             airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     322           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     323           18 :                 airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     324              :             }
     325            2 :             if (airLoopConv.HVACCO2SupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACCO2Toler) {
     326            1 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     327            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     328              :             }
     329              :         }
     330              : 
     331        76909 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     332            2 :             TmpRealARR = airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue;
     333            2 :             airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[0] =
     334            2 :                 std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     335           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     336           18 :                 airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     337              :             }
     338            2 :             if (airLoopConv.HVACGenContamSupplyDeck1ToDemandTolValue[0] > DataConvergParams::HVACGenContamToler) {
     339            1 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     340            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     341              :             }
     342              :         }
     343              : 
     344            2 :     } else if (CalledFrom == DataConvergParams::CalledFrom::AirSystemSupplySideDeck2) {
     345              : 
     346            2 :         airLoopConv.HVACMassFlowNotConverged[iCall] = false;
     347            2 :         airLoopConv.HVACHumRatNotConverged[iCall] = false;
     348            2 :         airLoopConv.HVACTempNotConverged[iCall] = false;
     349            2 :         airLoopConv.HVACEnergyNotConverged[iCall] = false;
     350            2 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     351            2 :             airLoopConv.HVACCO2NotConverged[iCall] = false;
     352              :         }
     353            2 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     354            2 :             airLoopConv.HVACGenContamNotConverged[iCall] = false;
     355              :         }
     356              : 
     357            2 :         TmpRealARR = airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue;
     358            2 :         airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[0] =
     359            2 :             std::abs(state.dataLoopNodes->Node(OutletNode).MassFlowRate - thisInletNode.MassFlowRate);
     360           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     361           18 :             airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     362              :         }
     363            2 :         if (airLoopConv.HVACFlowSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACFlowRateToler) {
     364            0 :             airLoopConv.HVACMassFlowNotConverged[iCall] = true;
     365            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     366              :         }
     367              : 
     368            2 :         TmpRealARR = airLoopConv.HVACHumSupplyDeck2ToDemandTolValue;
     369            2 :         airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).HumRat - thisInletNode.HumRat);
     370           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     371           18 :             airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     372              :         }
     373            2 :         if (airLoopConv.HVACHumSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACHumRatToler) {
     374            0 :             airLoopConv.HVACHumRatNotConverged[iCall] = true;
     375            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     376              :         }
     377              : 
     378            2 :         TmpRealARR = airLoopConv.HVACTempSupplyDeck2ToDemandTolValue;
     379            2 :         airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Temp - thisInletNode.Temp);
     380           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     381           18 :             airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     382              :         }
     383            2 :         if (airLoopConv.HVACTempSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACTemperatureToler) {
     384            0 :             airLoopConv.HVACTempNotConverged[iCall] = true;
     385            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     386              :         }
     387              : 
     388            2 :         TmpRealARR = airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue;
     389            2 :         airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue[0] = DeltaEnergy;
     390           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     391           18 :             airLoopConv.HVACEnergySupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     392              :         }
     393            2 :         if (std::abs(DeltaEnergy) > DataConvergParams::HVACEnergyToler) {
     394            0 :             airLoopConv.HVACEnergyNotConverged[iCall] = true;
     395            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     396              :         }
     397              : 
     398            2 :         TmpRealARR = airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue;
     399            2 :         airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Enthalpy - thisInletNode.Enthalpy);
     400           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     401           18 :             airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     402              :         }
     403            2 :         if (airLoopConv.HVACEnthalpySupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACEnthalpyToler) {
     404            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     405              :         }
     406              : 
     407            2 :         TmpRealARR = airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue;
     408            2 :         airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).Press - thisInletNode.Press);
     409           20 :         for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     410           18 :             airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     411              :         }
     412            2 :         if (airLoopConv.HVACPressueSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACPressToler) {
     413            0 :             OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     414              :         }
     415              : 
     416            2 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     417            2 :             TmpRealARR = airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue;
     418            2 :             airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[0] = std::abs(state.dataLoopNodes->Node(OutletNode).CO2 - thisInletNode.CO2);
     419           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     420           18 :                 airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     421              :             }
     422            2 :             if (airLoopConv.HVACCO2SupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACCO2Toler) {
     423            1 :                 airLoopConv.HVACCO2NotConverged[iCall] = true;
     424            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     425              :             }
     426              :         }
     427            2 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     428            2 :             TmpRealARR = airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue;
     429            2 :             airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[0] =
     430            2 :                 std::abs(state.dataLoopNodes->Node(OutletNode).GenContam - thisInletNode.GenContam);
     431           20 :             for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
     432           18 :                 airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[logIndex] = TmpRealARR[logIndex - 1];
     433              :             }
     434            2 :             if (airLoopConv.HVACGenContamSupplyDeck2ToDemandTolValue[0] > DataConvergParams::HVACGenContamToler) {
     435            1 :                 airLoopConv.HVACGenContamNotConverged[iCall] = true;
     436            1 :                 OutOfToleranceFlag = true; // Something has changed--resimulate the other side of the loop
     437              :             }
     438              :         }
     439              :     }
     440              : 
     441              :     // Always update the new inlet conditions
     442       152726 :     thisInletNode.Temp = state.dataLoopNodes->Node(OutletNode).Temp;
     443       152726 :     thisInletNode.MassFlowRate = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
     444       152726 :     thisInletNode.MassFlowRateMinAvail = state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail;
     445       152726 :     thisInletNode.MassFlowRateMaxAvail = state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail;
     446       152726 :     thisInletNode.Quality = state.dataLoopNodes->Node(OutletNode).Quality;
     447       152726 :     thisInletNode.Press = state.dataLoopNodes->Node(OutletNode).Press;
     448       152726 :     thisInletNode.Enthalpy = state.dataLoopNodes->Node(OutletNode).Enthalpy;
     449       152726 :     thisInletNode.HumRat = state.dataLoopNodes->Node(OutletNode).HumRat;
     450              : 
     451       152726 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     452            6 :         thisInletNode.CO2 = state.dataLoopNodes->Node(OutletNode).CO2;
     453              :     }
     454              : 
     455       152726 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     456            6 :         thisInletNode.GenContam = state.dataLoopNodes->Node(OutletNode).GenContam;
     457              :     }
     458              : }
     459              : 
     460       176418 : 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       176418 :     int LoopNum = plantLoc.loopNum;
     494       176418 :     DataPlant::LoopSideLocation ThisLoopSideNum = plantLoc.loopSideNum;
     495       176418 :     auto &convergence(state.dataConvergeParams->PlantConvergence(LoopNum));
     496              : 
     497              :     // reset out of tolerance flags
     498       176418 :     convergence.PlantMassFlowNotConverged = false;
     499       176418 :     convergence.PlantTempNotConverged = false;
     500              : 
     501              :     // set the LoopSide inlet node
     502       176418 :     int ThisLoopSideInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSideNum).NodeNumIn;
     503              : 
     504              :     // save the inlet node temp for DeltaEnergy check
     505       176418 :     Real64 OldOtherLoopSideInletMdot = state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate;
     506       176418 :     Real64 OldTankOutletTemp = state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp;
     507              : 
     508              :     // calculate the specific heat
     509       176418 :     Real64 Cp = state.dataPlnt->PlantLoop(LoopNum).glycol->getSpecificHeat(state, OldTankOutletTemp, RoutineName);
     510              : 
     511              :     // update the enthalpy
     512       176418 :     state.dataLoopNodes->Node(OtherLoopSideInletNode).Enthalpy = Cp * state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp;
     513              : 
     514              :     // update the temperatures and flow rates
     515       176418 :     auto &flow_demand_to_supply_tol(convergence.PlantFlowDemandToSupplyTolValue);
     516       176418 :     auto &flow_supply_to_demand_tol(convergence.PlantFlowSupplyToDemandTolValue);
     517              :     Real64 MixedOutletTemp;
     518              :     Real64 TankOutletTemp;
     519       176418 :     if (CommonPipeType == DataPlant::CommonPipeType::Single || CommonPipeType == DataPlant::CommonPipeType::TwoWay) {
     520              :         // update the temperature
     521            0 :         UpdateCommonPipe(state, plantLoc, CommonPipeType, MixedOutletTemp);
     522            0 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp = MixedOutletTemp;
     523            0 :         TankOutletTemp = MixedOutletTemp;
     524            0 :         if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     525            0 :             rshift1(flow_demand_to_supply_tol);
     526            0 :             flow_demand_to_supply_tol[0] = std::abs(OldOtherLoopSideInletMdot - state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     527            0 :             if (flow_demand_to_supply_tol[0] > DataConvergParams::PlantFlowRateToler) {
     528            0 :                 convergence.PlantMassFlowNotConverged = true;
     529              :             }
     530              :         } else {
     531            0 :             rshift1(flow_supply_to_demand_tol);
     532            0 :             flow_supply_to_demand_tol[0] = std::abs(OldOtherLoopSideInletMdot - state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     533            0 :             if (flow_supply_to_demand_tol[0] > DataConvergParams::PlantFlowRateToler) {
     534            0 :                 convergence.PlantMassFlowNotConverged = true;
     535              :             }
     536              :         }
     537              :         // Set the flow rate.  Continuity requires that the flow rates at the half loop inlet and outlet match
     538            0 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRate = state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate;
     539              :         // Update this LoopSide inlet node Min/MaxAvail to this LoopSide outlet node Min/MaxAvail
     540            0 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRateMinAvail =
     541            0 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMinAvail;
     542            0 :         state.dataLoopNodes->Node(ThisLoopSideInletNode).MassFlowRateMaxAvail =
     543            0 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMaxAvail;
     544              : 
     545              :     } else { // no common pipe
     546       176418 :         UpdateHalfLoopInletTemp(state, LoopNum, ThisLoopSideNum, TankOutletTemp);
     547              :         // update the temperature
     548       176418 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp = TankOutletTemp;
     549              :         // Set the flow tolerance array
     550       176418 :         if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     551        88210 :             rshift1(flow_demand_to_supply_tol);
     552       176420 :             flow_demand_to_supply_tol[0] = std::abs(state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate -
     553        88210 :                                                     state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     554        88210 :             if (flow_demand_to_supply_tol[0] > DataConvergParams::PlantFlowRateToler) {
     555         9420 :                 convergence.PlantMassFlowNotConverged = true;
     556              :             }
     557              :         } else {
     558        88208 :             rshift1(flow_supply_to_demand_tol);
     559       176416 :             flow_supply_to_demand_tol[0] = std::abs(state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate -
     560        88208 :                                                     state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate);
     561        88208 :             if (flow_supply_to_demand_tol[0] > DataConvergParams::PlantFlowRateToler) {
     562         2720 :                 convergence.PlantMassFlowNotConverged = true;
     563              :             }
     564              :         }
     565              :         //    PlantFlowTolValue(PlantQuePtr)  = ABS(Node(ThisLoopSideOutletNode)%MassFlowRate-Node(OtherLoopSideInletNode)%MassFlowRate)
     566              :         // Set the flow rate
     567       176418 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRate = state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRate;
     568              :         // update the MIN/MAX available flow rates
     569       176418 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRateMinAvail =
     570       176418 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMinAvail;
     571       176418 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).MassFlowRateMaxAvail =
     572       176418 :             state.dataLoopNodes->Node(ThisLoopSideOutletNode).MassFlowRateMaxAvail;
     573              :         // update Quality.  Note: This update assumes that STEAM cannot be used with common pipes.
     574       176418 :         state.dataLoopNodes->Node(OtherLoopSideInletNode).Quality = state.dataLoopNodes->Node(ThisLoopSideOutletNode).Quality;
     575              :         // pressure update  Note: This update assumes that PRESSURE SIMULATION cannot be used with common pipes.
     576       176418 :         if (state.dataPlnt->PlantLoop(LoopNum).HasPressureComponents) {
     577              :             // Don't update pressure, let the pressure simulation handle pressures
     578              :         } else {
     579              :             // Do update pressure!
     580       176418 :             state.dataLoopNodes->Node(OtherLoopSideInletNode).Press = state.dataLoopNodes->Node(ThisLoopSideOutletNode).Press;
     581              :         }
     582              :     }
     583              : 
     584              :     // temperature
     585       176418 :     if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     586        88210 :         auto &temp_demand_to_supply_tol(convergence.PlantTempDemandToSupplyTolValue);
     587        88210 :         rshift1(temp_demand_to_supply_tol);
     588        88210 :         temp_demand_to_supply_tol[0] = std::abs(OldTankOutletTemp - state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp);
     589        88210 :         if (temp_demand_to_supply_tol[0] > DataConvergParams::PlantTemperatureToler) {
     590        25049 :             convergence.PlantTempNotConverged = true;
     591              :         }
     592              :     } else {
     593        88208 :         auto &temp_supply_to_demand_tol(convergence.PlantTempSupplyToDemandTolValue);
     594        88208 :         rshift1(temp_supply_to_demand_tol);
     595        88208 :         temp_supply_to_demand_tol[0] = std::abs(OldTankOutletTemp - state.dataLoopNodes->Node(OtherLoopSideInletNode).Temp);
     596        88208 :         if (temp_supply_to_demand_tol[0] > DataConvergParams::PlantTemperatureToler) {
     597        11052 :             convergence.PlantTempNotConverged = true;
     598              :         }
     599              :     }
     600              : 
     601              :     // Set out of tolerance flags
     602       176418 :     if (ThisLoopSideNum == DataPlant::LoopSideLocation::Demand) {
     603        88210 :         if (convergence.PlantMassFlowNotConverged || convergence.PlantTempNotConverged) {
     604        25717 :             OutOfToleranceFlag = true;
     605              :         }
     606              :     } else {
     607        88208 :         if (convergence.PlantMassFlowNotConverged) {
     608         2720 :             OutOfToleranceFlag = true;
     609              :         }
     610              :     }
     611       176418 : }
     612              : 
     613       176420 : void UpdateHalfLoopInletTemp(EnergyPlusData &state, int const LoopNum, const DataPlant::LoopSideLocation TankInletLoopSide, Real64 &TankOutletTemp)
     614              : {
     615              : 
     616              :     // SUBROUTINE INFORMATION:
     617              :     //       AUTHOR         Rick Strand
     618              :     //       DATE WRITTEN   September 2001
     619              :     //       MODIFIED       Simon Rees, July 2007
     620              :     //                      Brent Griffith, Feb. 2010, add LoopNum arg
     621              :     //       RE-ENGINEERED  Brent Griffith, Sept 2010, generalize for both loop sides
     622              :     //                                           add pump heat from other loop
     623              :     //                      B.Griffith and L.Gu, Oct 2011, solve via analytical soln, use average over timestep
     624              : 
     625              :     // PURPOSE OF THIS SUBROUTINE:
     626              :     // This subroutine calculates the new loop side inlet temperature
     627              :     // based on the previous temperature of the mixed tank, mass flow rate and the new
     628              :     // outlet temperature on the supply side.  The temperature does not
     629              :     // pass directly across because the loop has some capacitance. It is
     630              :     // called separately but used for both supply-to-demand, and demand-to-supply
     631              : 
     632              :     // METHODOLOGY EMPLOYED:
     633              :     // This uses a analytical solution for changes in the
     634              :     // fluid loop temperature.  The user defines some volume of fluid
     635              :     // for the loop which gets converted to a fixed amount of mass.
     636              :     // The loop side inlet node is modeled as the outlet of a fully mixed
     637              :     // tank. Note that this routine is called repeatedly to re calculate
     638              :     // loop capacitance based on current plant conditions
     639              : 
     640       176420 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     641              : 
     642              :     // SUBROUTINE PARAMETER DEFINITIONS:
     643       176420 :     Real64 constexpr FracTotLoopMass(0.5); // Fraction of total loop mass assigned to the half loop
     644              :     static constexpr std::string_view RoutineName("UpdateHalfLoopInletTemp");
     645              : 
     646              :     // find tank inlet and outlet nodes
     647       176420 :     DataPlant::LoopSideLocation TankOutletLoopSide = DataPlant::LoopSideOther[static_cast<int>(TankInletLoopSide)];
     648       176420 :     int TankInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).NodeNumOut;
     649       176420 :     Real64 TankInletTemp = state.dataLoopNodes->Node(TankInletNode).Temp;
     650              : 
     651              :     // This needs to be based on time to deal with system downstepping and repeated timesteps
     652       176420 :     Real64 TimeElapsed = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + SysTimeElapsed;
     653       176420 :     if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed != TimeElapsed) {
     654        39653 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet =
     655        39653 :             state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet;
     656        39653 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed = TimeElapsed;
     657              :     }
     658              : 
     659       176420 :     Real64 LastTankOutletTemp = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet;
     660              : 
     661              :     // calculate the specific heat for the capacitance calculation
     662       176420 :     Real64 Cp = state.dataPlnt->PlantLoop(LoopNum).glycol->getSpecificHeat(state, LastTankOutletTemp, RoutineName);
     663              :     // set the fraction of loop mass assigned to each half loop outlet capacitance ('tank') calculation
     664              : 
     665              :     // calculate new loop inlet temperature.  The calculation is a simple 'tank' (thermal capacitance) calculation that includes:
     666              :     //--half of loop mass.  The other half is accounted for at the other half loop interface
     667              :     //--pump heat.  Pump heat for a single loop setpoint with pumps only on the supply side is added at the supply side inlet.
     668              :     //   Pump heat for a dual setpoint loop is added to each loop side inlet
     669              :     //  The previous tank temperature value is used to prevent accumulation of pump heat during iterations while recalculating
     670              :     // tank conditions each call.
     671              :     // Analytical solution for ODE, formulated for both final tank temp and average tank temp.
     672              : 
     673       176420 :     Real64 TimeStepSeconds = state.dataHVACGlobal->TimeStepSysSec;
     674       176420 :     Real64 MassFlowRate = state.dataLoopNodes->Node(TankInletNode).MassFlowRate;
     675       176420 :     Real64 PumpHeat = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TotalPumpHeat;
     676       176420 :     Real64 ThisTankMass = FracTotLoopMass * state.dataPlnt->PlantLoop(LoopNum).Mass;
     677              :     Real64 TankFinalTemp;
     678              :     Real64 TankAverageTemp;
     679       176420 :     if (ThisTankMass <= 0.0) { // no mass, no plant loop volume
     680            0 :         if (MassFlowRate > 0.0) {
     681            0 :             TankFinalTemp = TankInletTemp + PumpHeat / (MassFlowRate * Cp);
     682            0 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     683              :         } else {
     684            0 :             TankFinalTemp = LastTankOutletTemp;
     685            0 :             TankAverageTemp = LastTankOutletTemp;
     686              :         }
     687              : 
     688              :     } else { // tank has mass
     689       176420 :         if (MassFlowRate > 0.0) {
     690        93852 :             Real64 const mdotCp = MassFlowRate * Cp;
     691        93852 :             Real64 const mdotCpTempIn = mdotCp * TankInletTemp;
     692        93852 :             Real64 const tankMassCp = ThisTankMass * Cp;
     693        93852 :             Real64 const ExponentTerm = mdotCp / tankMassCp * TimeStepSeconds;
     694        93852 :             if (ExponentTerm >= 700.0) {
     695            2 :                 TankFinalTemp = (mdotCp * TankInletTemp + PumpHeat) / mdotCp;
     696              : 
     697            2 :                 TankAverageTemp = (tankMassCp / mdotCp * (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) / TimeStepSeconds +
     698            2 :                                    (mdotCpTempIn + PumpHeat) / mdotCp);
     699              :             } else {
     700        93850 :                 TankFinalTemp = (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) * std::exp(-ExponentTerm) +
     701        93850 :                                 (mdotCpTempIn + PumpHeat) / (MassFlowRate * Cp);
     702              : 
     703        93850 :                 TankAverageTemp = (tankMassCp / mdotCp * (LastTankOutletTemp - (mdotCpTempIn + PumpHeat) / mdotCp) * (1.0 - std::exp(-ExponentTerm)) /
     704              :                                        TimeStepSeconds +
     705        93850 :                                    (mdotCpTempIn + PumpHeat) / mdotCp);
     706              :             }
     707              :         } else {
     708        82568 :             TankFinalTemp = PumpHeat / (ThisTankMass * Cp) * TimeStepSeconds + LastTankOutletTemp;
     709        82568 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     710              :         }
     711              :     }
     712              : 
     713              :     // update last tank outlet temperature
     714       176420 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet = TankFinalTemp;
     715              : 
     716              :     // update heat transport and heat storage rates
     717       176420 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_MdotCpDeltaT =
     718       176420 :         (TankInletTemp - TankAverageTemp) * Cp * MassFlowRate;
     719       176420 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_McpDTdt =
     720       176420 :         (ThisTankMass * Cp * (TankFinalTemp - LastTankOutletTemp)) / TimeStepSeconds;
     721              : 
     722              :     // update report variable
     723       176420 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_TankTemp = TankAverageTemp;
     724              : 
     725       176420 :     TankOutletTemp = TankAverageTemp;
     726       176420 : }
     727              : 
     728            0 : void UpdateCommonPipe(EnergyPlusData &state,
     729              :                       PlantLocation const &TankInletPlantLoc,
     730              :                       DataPlant::CommonPipeType const CommonPipeType,
     731              :                       Real64 &MixedOutletTemp)
     732              : {
     733              : 
     734              :     // SUBROUTINE INFORMATION:
     735              :     //       AUTHOR         Rick Strand
     736              :     //       DATE WRITTEN   September 2001
     737              :     //       MODIFIED       Simon Rees, July 2007
     738              :     //                      Brent Griffith, Feb. 2010, add LoopNum arg
     739              :     //       RE-ENGINEERED  Brent Griffith, Sept 2010, generalize for both loop sides
     740              :     //                                           add pump heat from other loop
     741              :     //                      B.Griffith and L.Gu, Oct 2011, solve via analytical soln, use average over timestep
     742              : 
     743              :     // PURPOSE OF THIS SUBROUTINE:
     744              :     // This subroutine calculates the new loop side inlet temperature
     745              :     // based on the previous temperature of the mixed tank, mass flow rate and the new
     746              :     // outlet temperature on the supply side.  The temperature does not
     747              :     // pass directly across because the loop has some capacitance. It is
     748              :     // called separately but used for both supply-to-demand, and demand-to-supply
     749              : 
     750              :     // METHODOLOGY EMPLOYED:
     751              :     // This uses a analytical solution for changes in the
     752              :     // fluid loop temperature.  The user defines some volume of fluid
     753              :     // for the loop which gets converted to a fixed amount of mass.
     754              :     // The loop side inlet node is modeled as the outlet of a fully mixed
     755              :     // tank. Note that this routine is called repeatedly to re calculate
     756              :     // loop capacitance based on current plant conditions
     757              : 
     758              :     // Using/Aliasing
     759            0 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     760              : 
     761              :     // SUBROUTINE PARAMETER DEFINITIONS:
     762              :     static constexpr std::string_view RoutineName("UpdateCommonPipe");
     763              : 
     764              :     // find tank inlet and outlet nodes
     765            0 :     int LoopNum = TankInletPlantLoc.loopNum;
     766            0 :     DataPlant::LoopSideLocation TankInletLoopSide = TankInletPlantLoc.loopSideNum;
     767            0 :     DataPlant::LoopSideLocation TankOutletLoopSide = DataPlant::LoopSideOther[static_cast<int>(TankInletPlantLoc.loopSideNum)]; // Outlet loopside
     768            0 :     int TankInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).NodeNumOut;
     769            0 :     int TankOutletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).NodeNumIn;
     770              : 
     771            0 :     Real64 TankInletTemp = state.dataLoopNodes->Node(TankInletNode).Temp;
     772              : 
     773              :     Real64 FracTotLoopMass; // Fraction of total loop mass assigned to the half loop
     774            0 :     if (TankInletLoopSide == DataPlant::LoopSideLocation::Demand) {
     775              :         // for common pipe loops, assume 75% of plant loop volume is on the demand side
     776            0 :         FracTotLoopMass = 0.25;
     777              :     } else {
     778            0 :         FracTotLoopMass = 0.75;
     779              :     }
     780              : 
     781              :     // This needs to be based on time to deal with system downstepping and repeated timesteps
     782            0 :     Real64 TimeElapsed = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + SysTimeElapsed;
     783            0 :     if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed != TimeElapsed) {
     784            0 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet =
     785            0 :             state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet;
     786            0 :         state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TimeElapsed = TimeElapsed;
     787              :     }
     788              : 
     789            0 :     Real64 LastTankOutletTemp = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LastTempInterfaceTankOutlet;
     790              : 
     791              :     // calculate the specific heat for the capacitance calculation
     792            0 :     Real64 Cp = state.dataPlnt->PlantLoop(LoopNum).glycol->getSpecificHeat(state, LastTankOutletTemp, RoutineName);
     793              : 
     794              :     // set the fraction of loop mass assigned to each half loop outlet capacitance ('tank') calculation
     795              : 
     796              :     // calculate new loop inlet temperature.  The calculation is a simple 'tank' (thermal capacitance) calculation that includes:
     797              :     //--half of loop mass.  The other half is accounted for at the other half loop interface
     798              :     //--pump heat.  Pump heat for a single loop setpoint with pumps only on the supply side is added at the supply side inlet.
     799              :     // Pump heat for a dual setpoint loop is added to each loop side inlet
     800              :     // The previous inlet side temp,'ThisLoopSideTankOutletTemp' is used to prevent accumulation of pump heat during iterations.
     801              :     // The placement of the 'tank' for common pipes is *after* the outlet node and *before* the flow split or flow mixing.
     802              :     // This requires no logical check in the code since for purposes of temperature calculations, it is identical to the
     803              :     // no common pipe case.
     804              :     // calculation is separated because for common pipe, a different split for mass fraction is applied
     805              :     // The pump heat source is swapped around here compared to no common pipe (so pump heat sort stays on its own side).
     806            0 :     Real64 TimeStepSeconds = state.dataHVACGlobal->TimeStepSysSec;
     807            0 :     Real64 MassFlowRate = state.dataLoopNodes->Node(TankInletNode).MassFlowRate;
     808            0 :     Real64 PumpHeat = state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankInletLoopSide).TotalPumpHeat;
     809            0 :     Real64 ThisTankMass = FracTotLoopMass * state.dataPlnt->PlantLoop(LoopNum).Mass;
     810              : 
     811              :     Real64 TankFinalTemp;
     812              :     Real64 TankAverageTemp;
     813            0 :     if (ThisTankMass <= 0.0) { // no mass, no plant loop volume
     814            0 :         if (MassFlowRate > 0.0) {
     815            0 :             TankFinalTemp = TankInletTemp + PumpHeat / (MassFlowRate * Cp);
     816            0 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     817              :         } else {
     818            0 :             TankFinalTemp = LastTankOutletTemp;
     819            0 :             TankAverageTemp = LastTankOutletTemp;
     820              :         }
     821              : 
     822              :     } else { // tank has mass
     823            0 :         if (MassFlowRate > 0.0) {
     824            0 :             TankFinalTemp = (LastTankOutletTemp - (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp)) *
     825            0 :                                 std::exp(-(MassFlowRate * Cp) / (ThisTankMass * Cp) * TimeStepSeconds) +
     826            0 :                             (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp);
     827            0 :             TankAverageTemp = ((ThisTankMass * Cp) / (MassFlowRate * Cp) *
     828            0 :                                    (LastTankOutletTemp - (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp)) *
     829            0 :                                    (1.0 - std::exp(-(MassFlowRate * Cp) / (ThisTankMass * Cp) * TimeStepSeconds)) / TimeStepSeconds +
     830            0 :                                (MassFlowRate * Cp * TankInletTemp + PumpHeat) / (MassFlowRate * Cp));
     831              :         } else {
     832              : 
     833            0 :             TankFinalTemp = PumpHeat / (ThisTankMass * Cp) * TimeStepSeconds + LastTankOutletTemp;
     834            0 :             TankAverageTemp = (TankFinalTemp + LastTankOutletTemp) / 2.0;
     835              :         }
     836              :     }
     837              :     // Common Pipe Simulation
     838            0 :     if (CommonPipeType == DataPlant::CommonPipeType::Single) {
     839            0 :         ManageSingleCommonPipe(state, LoopNum, TankOutletLoopSide, TankAverageTemp, MixedOutletTemp);
     840              :         // 2-way (controlled) common pipe simulation
     841            0 :     } else if (CommonPipeType == DataPlant::CommonPipeType::TwoWay) {
     842            0 :         PlantLocation TankOutletPlantLoc = {LoopNum, TankOutletLoopSide, 0, 0};
     843              : 
     844            0 :         ManageTwoWayCommonPipe(state, TankOutletPlantLoc, TankAverageTemp);
     845            0 :         MixedOutletTemp = state.dataLoopNodes->Node(TankOutletNode).Temp;
     846              :     }
     847              : 
     848            0 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).TempInterfaceTankOutlet = TankFinalTemp;
     849              : 
     850            0 :     state.dataPlnt->PlantLoop(LoopNum).LoopSide(TankOutletLoopSide).LoopSideInlet_TankTemp = TankAverageTemp;
     851            0 : }
     852              : 
     853            0 : void ManageSingleCommonPipe(EnergyPlusData &state,
     854              :                             int const LoopNum,                          // plant loop number
     855              :                             DataPlant::LoopSideLocation const LoopSide, // plant loop side number
     856              :                             Real64 const TankOutletTemp, // inlet temperature to the common pipe passed in from the capacitance calculation
     857              :                             Real64 &MixedOutletTemp      // inlet temperature to the common pipe passed in from the capacitance calculation
     858              : )
     859              : {
     860              : 
     861              :     // SUBROUTINE INFORMATION:
     862              :     //       AUTHOR         Sankaranarayanan K P
     863              :     //       DATE WRITTEN   November 2006
     864              :     //       MODIFIED       B. Griffith, Jan 2010 clean up setup to allow mixing common pipe modes
     865              :     //                      B. Griffith, Mar 2010 add LoopNum arg and simplify
     866              :     //       RE-ENGINEERED  D. Fisher, Sept. 2010
     867              :     //                      B. Griffith, Oct 2011, major rewrite for plant upgrade
     868              : 
     869              :     // PURPOSE OF THIS SUBROUTINE:
     870              :     // To determine the conditions in common pipe viz., the flow flow temperature and direction of flow.
     871              : 
     872              :     // METHODOLOGY EMPLOYED:
     873              :     // Determine the flow on both sides of the common pipe. Decide if flow is coming into common pipe
     874              :     // or going out of common pipe. After that determine which interface calls the subroutine, i.e. if
     875              :     // called from "Demand to Supply" interface or "Supply to Demand" interface. Update the node temperatures
     876              :     // accordingly.
     877              : 
     878              :     // One time call to set up report variables and set common pipe 'type' flag
     879            0 :     if (!state.dataHVACInterfaceMgr->CommonPipeSetupFinished) SetupCommonPipes(state);
     880              : 
     881            0 :     auto &plantCommonPipe = state.dataHVACInterfaceMgr->PlantCommonPipe(LoopNum);
     882              : 
     883              :     // fill local node indexes
     884            0 :     int NodeNumPriIn = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn;
     885            0 :     int NodeNumPriOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut;
     886            0 :     int NodeNumSecIn = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumIn;
     887            0 :     int NodeNumSecOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumOut;
     888              : 
     889            0 :     if (plantCommonPipe.MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
     890            0 :         plantCommonPipe.Flow = 0.0;
     891            0 :         plantCommonPipe.Temp = 0.0;
     892            0 :         plantCommonPipe.FlowDir = NoRecircFlow;
     893            0 :         plantCommonPipe.MyEnvrnFlag = false;
     894              :     }
     895            0 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     896            0 :         plantCommonPipe.MyEnvrnFlag = true;
     897              :     }
     898              : 
     899              :     // every time inits
     900            0 :     Real64 MdotSec = state.dataLoopNodes->Node(NodeNumSecOut).MassFlowRate;
     901            0 :     Real64 MdotPri = state.dataLoopNodes->Node(NodeNumPriOut).MassFlowRate;
     902              : 
     903              :     Real64 TempSecOutTankOut;
     904              :     Real64 TempPriOutTankOut;
     905            0 :     if (LoopSide == DataPlant::LoopSideLocation::Supply) {
     906            0 :         TempSecOutTankOut = TankOutletTemp;
     907            0 :         TempPriOutTankOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Demand).LoopSideInlet_TankTemp;
     908              :     } else {
     909            0 :         TempPriOutTankOut = TankOutletTemp;
     910            0 :         TempSecOutTankOut = state.dataPlnt->PlantLoop(LoopNum).LoopSide(DataPlant::LoopSideLocation::Supply).LoopSideInlet_TankTemp;
     911              :     }
     912              : 
     913              :     // first do mass balances and find common pipe flow rate and direction
     914              :     Real64 MdotPriRCLeg; // flow rate of primary recirculation thru common pipe kg/s
     915              :     Real64 MdotSecRCLeg; // flow rate of secondary recirculation thru common pipe kg/s
     916              :     Real64 TempSecInlet; // temperature at secondary inlet deg C
     917              :     Real64 TempPriInlet; // temperature at primary inlet deg C
     918              :     int CPFlowDir;       // flow direction in single common pipe
     919              :     Real64 CommonPipeTemp;
     920            0 :     if (MdotPri > MdotSec) {
     921            0 :         MdotPriRCLeg = MdotPri - MdotSec;
     922            0 :         if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) {
     923            0 :             MdotPriRCLeg = 0.0;
     924            0 :             CPFlowDir = NoRecircFlow;
     925              :         } else {
     926            0 :             CPFlowDir = PrimaryRecirc;
     927              :         }
     928            0 :         MdotSecRCLeg = 0.0;
     929            0 :         CommonPipeTemp = TempPriOutTankOut;
     930            0 :     } else if (MdotPri < MdotSec) {
     931            0 :         MdotSecRCLeg = MdotSec - MdotPri;
     932            0 :         if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) {
     933            0 :             MdotSecRCLeg = 0.0;
     934            0 :             CPFlowDir = NoRecircFlow;
     935              :         } else {
     936            0 :             CPFlowDir = SecondaryRecirc;
     937              :         }
     938            0 :         MdotPriRCLeg = 0.0;
     939            0 :         CommonPipeTemp = TempSecOutTankOut;
     940              :     } else { // equal
     941            0 :         MdotPriRCLeg = 0.0;
     942            0 :         MdotSecRCLeg = 0.0;
     943            0 :         CPFlowDir = NoRecircFlow;
     944            0 :         CommonPipeTemp = (TempPriOutTankOut + TempSecOutTankOut) / 2.0;
     945              :     }
     946              : 
     947              :     // now calculate inlet temps
     948              : 
     949            0 :     if (MdotSec > 0.0) {
     950            0 :         TempSecInlet = (MdotPri * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut - MdotPriRCLeg * TempPriOutTankOut) / (MdotSec);
     951              :     } else {
     952            0 :         TempSecInlet = TempPriOutTankOut;
     953              :     }
     954            0 :     if (MdotPri > 0.0) {
     955            0 :         TempPriInlet = (MdotSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut - MdotSecRCLeg * TempSecOutTankOut) / (MdotPri);
     956              :     } else {
     957            0 :         TempPriInlet = TempSecOutTankOut;
     958              :     }
     959              : 
     960              :     // Update the Common Pipe Data structure for reporting purposes.
     961            0 :     plantCommonPipe.Flow = max(MdotPriRCLeg, MdotSecRCLeg);
     962            0 :     plantCommonPipe.Temp = CommonPipeTemp;
     963            0 :     plantCommonPipe.FlowDir = CPFlowDir;
     964            0 :     state.dataLoopNodes->Node(NodeNumSecIn).Temp = TempSecInlet;
     965            0 :     state.dataLoopNodes->Node(NodeNumPriIn).Temp = TempPriInlet;
     966              : 
     967            0 :     if (LoopSide == DataPlant::LoopSideLocation::Supply) {
     968            0 :         MixedOutletTemp = TempPriInlet;
     969              :     } else {
     970            0 :         MixedOutletTemp = TempSecInlet;
     971              :     }
     972            0 : }
     973              : 
     974            0 : void ManageTwoWayCommonPipe(EnergyPlusData &state, PlantLocation const &plantLoc, Real64 const TankOutletTemp)
     975              : {
     976              : 
     977              :     // SUBROUTINE INFORMATION:
     978              :     //       AUTHOR         B. Griffith
     979              :     //       DATE WRITTEN   June 2011
     980              :     //       MODIFIED       na
     981              :     //       RE-ENGINEERED  B. Griffith, Oct 2011.  rewrite
     982              : 
     983              :     // PURPOSE OF THIS SUBROUTINE:
     984              :     // manage two-way common pipe modeling at half-loop interface
     985              : 
     986              :     // METHODOLOGY EMPLOYED:
     987              :     // calculate mixed temperatures and various flow rates
     988              :     // sequential substitution of system of equations
     989              : 
     990              :     // REFERENCES:
     991              :     // reimplementation of CheckTwoWayCommonPipeConditions by Sankaranarayanan K P Jan 2007
     992              : 
     993              :     // SUBROUTINE PARAMETER DEFINITIONS:
     994              :     enum class UpdateType
     995              :     {
     996              :         DemandLedPrimaryInlet,
     997              :         DemandLedSecondaryInlet,
     998              :         SupplyLedPrimaryInlet,
     999              :         SupplyLedSecondaryInlet
    1000            0 :     } curCallingCase = UpdateType::SupplyLedPrimaryInlet;
    1001            0 :     constexpr int MaxIterLimitCaseA(8);
    1002            0 :     constexpr int MaxIterLimitCaseB(4);
    1003              : 
    1004              :     // one time setups
    1005            0 :     if (!state.dataHVACInterfaceMgr->CommonPipeSetupFinished) SetupCommonPipes(state);
    1006              : 
    1007            0 :     auto &plantCommonPipe(state.dataHVACInterfaceMgr->PlantCommonPipe(plantLoc.loopNum));
    1008            0 :     auto &thisPlantLoop = state.dataPlnt->PlantLoop(plantLoc.loopNum);
    1009              : 
    1010              :     // fill local node indexes
    1011            0 :     int const NodeNumPriIn = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn;
    1012            0 :     int const NodeNumPriOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut;
    1013            0 :     int const NodeNumSecIn = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumIn;
    1014            0 :     int const NodeNumSecOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumOut;
    1015              : 
    1016              :     // begin environment inits
    1017            0 :     if (plantCommonPipe.MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
    1018            0 :         plantCommonPipe.PriToSecFlow = 0.0;
    1019            0 :         plantCommonPipe.SecToPriFlow = 0.0;
    1020            0 :         plantCommonPipe.PriCPLegFlow = 0.0;
    1021            0 :         plantCommonPipe.SecCPLegFlow = 0.0;
    1022            0 :         plantCommonPipe.MyEnvrnFlag = false;
    1023              :     }
    1024              : 
    1025            0 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1026            0 :         plantCommonPipe.MyEnvrnFlag = true;
    1027              :     }
    1028              : 
    1029              :     // every time inits
    1030            0 :     Real64 MdotSec = state.dataLoopNodes->Node(NodeNumSecOut).MassFlowRate; // assume known and fixed by demand side operation
    1031            0 :     Real64 TempCPPrimaryCntrlSetPoint = state.dataLoopNodes->Node(NodeNumPriIn).TempSetPoint;
    1032            0 :     Real64 TempCPSecondaryCntrlSetPoint = state.dataLoopNodes->Node(NodeNumSecIn).TempSetPoint;
    1033              : 
    1034              :     // 6 unknowns follow, fill with current values
    1035            0 :     Real64 MdotPriToSec = plantCommonPipe.PriToSecFlow;
    1036            0 :     Real64 MdotPriRCLeg = plantCommonPipe.PriCPLegFlow;
    1037            0 :     Real64 MdotSecRCLeg = plantCommonPipe.SecCPLegFlow;
    1038            0 :     Real64 TempSecInlet = state.dataLoopNodes->Node(NodeNumSecIn).Temp;
    1039            0 :     Real64 TempPriInlet = state.dataLoopNodes->Node(NodeNumPriIn).Temp;
    1040              :     Real64 MdotPri =
    1041            0 :         state.dataLoopNodes->Node(NodeNumPriOut).MassFlowRate; // may or may not be an unknown, If variable speed primary side, then unknown
    1042              : 
    1043              :     Real64 TempPriOutTankOut;
    1044              :     Real64 TempSecOutTankOut;
    1045            0 :     if (plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
    1046            0 :         TempSecOutTankOut = TankOutletTemp;
    1047            0 :         TempPriOutTankOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).LoopSideInlet_TankTemp;
    1048              :     } else {
    1049            0 :         TempPriOutTankOut = TankOutletTemp;
    1050            0 :         TempSecOutTankOut = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).LoopSideInlet_TankTemp;
    1051              :     }
    1052              : 
    1053              :     // determine current case
    1054              :     // which side is being updated
    1055              :     // commonpipe control point is the inlet of one of the half loops
    1056            0 :     if (plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) { // update primary inlet
    1057            0 :         if (thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1058            0 :             !thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1059            0 :             curCallingCase = UpdateType::SupplyLedPrimaryInlet;
    1060              : 
    1061            0 :         } else if (!thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1062            0 :                    thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1063            0 :             curCallingCase = UpdateType::DemandLedPrimaryInlet;
    1064              :         }
    1065              :     } else { // update secondary inlet
    1066            0 :         if (thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1067            0 :             !thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1068            0 :             curCallingCase = UpdateType::SupplyLedSecondaryInlet;
    1069              : 
    1070            0 :         } else if (!thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).InletNodeSetPt &&
    1071            0 :                    thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).InletNodeSetPt) {
    1072            0 :             curCallingCase = UpdateType::DemandLedSecondaryInlet;
    1073              :         }
    1074              :     }
    1075              : 
    1076            0 :     switch (curCallingCase) {
    1077            0 :     case UpdateType::SupplyLedPrimaryInlet:
    1078              :     case UpdateType::SupplyLedSecondaryInlet:
    1079              :         // CASE A, Primary/Supply Led
    1080              :         // six equations and six unknowns (although one has a setpoint)
    1081            0 :         for (int loop = 1; loop <= MaxIterLimitCaseA; ++loop) {
    1082              : 
    1083              :             // eq 1
    1084            0 :             if (std::abs(TempSecOutTankOut - TempCPPrimaryCntrlSetPoint) > DataPlant::DeltaTempTol) {
    1085            0 :                 MdotPriToSec = MdotPriRCLeg * (TempCPPrimaryCntrlSetPoint - TempPriOutTankOut) / (TempSecOutTankOut - TempCPPrimaryCntrlSetPoint);
    1086            0 :                 if (MdotPriToSec < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriToSec = 0.0;
    1087            0 :                 if (MdotPriToSec > MdotSec) MdotPriToSec = MdotSec;
    1088              :             } else {
    1089            0 :                 MdotPriToSec = MdotSec; //  what to do (?)
    1090              :             }
    1091              :             // eq. 5
    1092            0 :             MdotPriRCLeg = MdotPri - MdotPriToSec;
    1093            0 :             if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriRCLeg = 0.0;
    1094              : 
    1095              :             // eq. 4
    1096            0 :             MdotSecRCLeg = MdotSec - MdotPriToSec;
    1097            0 :             if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotSecRCLeg = 0.0;
    1098              : 
    1099              :             // eq  6
    1100            0 :             if ((MdotPriToSec + MdotSecRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1101            0 :                 TempSecInlet = (MdotPriToSec * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut) / (MdotPriToSec + MdotSecRCLeg);
    1102              :             } else {
    1103            0 :                 TempSecInlet = TempPriOutTankOut;
    1104              :             }
    1105              : 
    1106              :             // eq. 3
    1107            0 :             if ((plantCommonPipe.SupplySideInletPumpType == FlowType::Variable) && (curCallingCase == UpdateType::SupplyLedPrimaryInlet)) {
    1108              :                 // MdotPri is a variable to be calculated and flow request needs to be made
    1109            0 :                 if (std::abs(TempCPPrimaryCntrlSetPoint) > DataPlant::DeltaTempTol) {
    1110              : 
    1111            0 :                     MdotPri = (MdotPriRCLeg * TempPriOutTankOut + MdotPriToSec * TempSecOutTankOut) / (TempCPPrimaryCntrlSetPoint);
    1112              : 
    1113            0 :                     if (MdotPri < DataBranchAirLoopPlant::MassFlowTolerance) MdotPri = 0.0;
    1114              :                 } else {
    1115            0 :                     MdotPri = MdotSec;
    1116              :                 }
    1117            0 :                 PlantLocation thisPlantLoc = {plantLoc.loopNum, DataPlant::LoopSideLocation::Supply, 1, 0};
    1118            0 :                 PlantUtilities::SetActuatedBranchFlowRate(state, MdotPri, NodeNumPriIn, thisPlantLoc, false);
    1119              :             }
    1120              : 
    1121              :             // eq. 2
    1122            0 :             if ((MdotPriToSec + MdotPriRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1123            0 :                 TempPriInlet = (MdotPriToSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut) / (MdotPriToSec + MdotPriRCLeg);
    1124              :             } else {
    1125            0 :                 TempPriInlet = TempSecOutTankOut;
    1126              :             }
    1127              :         }
    1128            0 :         break;
    1129            0 :     case UpdateType::DemandLedPrimaryInlet:
    1130              :     case UpdateType::DemandLedSecondaryInlet:
    1131              :         // case B. Secondary/demand led
    1132              : 
    1133              :         // six equations and six unknowns (although one has a setpoint)
    1134            0 :         for (int loop = 1; loop <= MaxIterLimitCaseB; ++loop) {
    1135              :             // eq 1,
    1136            0 :             if (std::abs(TempPriOutTankOut - TempSecOutTankOut) > DataPlant::DeltaTempTol) {
    1137            0 :                 MdotPriToSec = MdotSec * (TempCPSecondaryCntrlSetPoint - TempSecOutTankOut) / (TempPriOutTankOut - TempSecOutTankOut);
    1138            0 :                 if (MdotPriToSec < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriToSec = 0.0;
    1139            0 :                 if (MdotPriToSec > MdotSec) MdotPriToSec = MdotSec;
    1140              :             } else {
    1141            0 :                 MdotPriToSec = MdotSec;
    1142              :             }
    1143              : 
    1144              :             // eq. 2,
    1145            0 :             if ((MdotPriToSec + MdotPriRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1146            0 :                 TempPriInlet = (MdotPriToSec * TempSecOutTankOut + MdotPriRCLeg * TempPriOutTankOut) / (MdotPriToSec + MdotPriRCLeg);
    1147              :             } else {
    1148            0 :                 TempPriInlet = TempSecOutTankOut;
    1149              :             }
    1150              : 
    1151              :             // eq. 3
    1152            0 :             if ((plantCommonPipe.SupplySideInletPumpType == FlowType::Variable) && (curCallingCase == UpdateType::DemandLedPrimaryInlet)) {
    1153              :                 // MdotPri is a variable to be calculated and flow request made
    1154            0 :                 if (std::abs(TempPriOutTankOut - TempPriInlet) > DataPlant::DeltaTempTol) {
    1155            0 :                     MdotPri = MdotSec * (TempCPSecondaryCntrlSetPoint - TempSecOutTankOut) / (TempPriOutTankOut - TempPriInlet);
    1156            0 :                     if (MdotPri < DataBranchAirLoopPlant::MassFlowTolerance) MdotPri = 0.0;
    1157              :                 } else {
    1158            0 :                     MdotPri = MdotSec;
    1159              :                 }
    1160            0 :                 PlantLocation thisPlantLoc = {plantLoc.loopNum, DataPlant::LoopSideLocation::Supply, 1, 0};
    1161            0 :                 PlantUtilities::SetActuatedBranchFlowRate(state, MdotPri, NodeNumPriIn, thisPlantLoc, false);
    1162              :             }
    1163              : 
    1164              :             // eq. 4
    1165            0 :             MdotSecRCLeg = MdotSec - MdotPriToSec;
    1166            0 :             if (MdotSecRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotSecRCLeg = 0.0;
    1167              : 
    1168              :             // eq. 5
    1169            0 :             MdotPriRCLeg = MdotPri - MdotPriToSec;
    1170            0 :             if (MdotPriRCLeg < DataBranchAirLoopPlant::MassFlowTolerance) MdotPriRCLeg = 0.0;
    1171              : 
    1172              :             // eq  6
    1173            0 :             if ((MdotPriToSec + MdotSecRCLeg) > DataBranchAirLoopPlant::MassFlowTolerance) {
    1174            0 :                 TempSecInlet = (MdotPriToSec * TempPriOutTankOut + MdotSecRCLeg * TempSecOutTankOut) / (MdotPriToSec + MdotSecRCLeg);
    1175              :             } else {
    1176            0 :                 TempSecInlet = TempPriOutTankOut;
    1177              :             }
    1178              :         }
    1179              :     }
    1180              : 
    1181              :     // update
    1182            0 :     plantCommonPipe.PriToSecFlow = MdotPriToSec;
    1183            0 :     plantCommonPipe.SecToPriFlow = MdotPriToSec;
    1184            0 :     plantCommonPipe.PriCPLegFlow = MdotPriRCLeg;
    1185            0 :     plantCommonPipe.SecCPLegFlow = MdotSecRCLeg;
    1186            0 :     state.dataLoopNodes->Node(NodeNumSecIn).Temp = TempSecInlet;
    1187            0 :     state.dataLoopNodes->Node(NodeNumPriIn).Temp = TempPriInlet;
    1188            0 : }
    1189              : 
    1190            0 : void SetupCommonPipes(EnergyPlusData &state)
    1191              : {
    1192              : 
    1193              :     // SUBROUTINE INFORMATION:
    1194              :     //       AUTHOR         B. Griffith
    1195              :     //       DATE WRITTEN   Jan. 2010
    1196              :     //       MODIFIED       B. Griffith Oct. 2011
    1197              :     //       RE-ENGINEERED  na
    1198              : 
    1199              :     // PURPOSE OF THIS SUBROUTINE:
    1200              :     // collect allocation, outputs, and other set up for common pipes
    1201              : 
    1202            0 :     state.dataHVACInterfaceMgr->PlantCommonPipe.allocate(state.dataPlnt->TotNumLoops);
    1203              : 
    1204            0 :     for (int CurLoopNum = 1; CurLoopNum <= state.dataPlnt->TotNumLoops; ++CurLoopNum) {
    1205              : 
    1206              :         // reference to easily lookup the first item once
    1207            0 :         auto &thisPlantLoop = state.dataPlnt->PlantLoop(CurLoopNum);
    1208            0 :         auto &thisCommonPipe = state.dataHVACInterfaceMgr->PlantCommonPipe(CurLoopNum);
    1209            0 :         auto const &first_demand_component_type = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).Branch(1).Comp(1).Type;
    1210            0 :         auto const &first_supply_component_type = thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp(1).Type;
    1211              : 
    1212            0 :         switch (thisPlantLoop.CommonPipeType) {
    1213            0 :         case DataPlant::CommonPipeType::No:
    1214            0 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::No;
    1215            0 :             break;
    1216            0 :         case DataPlant::CommonPipeType::Single: // Uncontrolled ('single') common pipe
    1217            0 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::Single;
    1218            0 :             SetupOutputVariable(state,
    1219              :                                 "Plant Common Pipe Mass Flow Rate",
    1220              :                                 Constant::Units::kg_s,
    1221            0 :                                 thisCommonPipe.Flow,
    1222              :                                 OutputProcessor::TimeStepType::System,
    1223              :                                 OutputProcessor::StoreType::Average,
    1224            0 :                                 thisPlantLoop.Name);
    1225            0 :             SetupOutputVariable(state,
    1226              :                                 "Plant Common Pipe Temperature",
    1227              :                                 Constant::Units::C,
    1228            0 :                                 thisCommonPipe.Temp,
    1229              :                                 OutputProcessor::TimeStepType::System,
    1230              :                                 OutputProcessor::StoreType::Average,
    1231            0 :                                 thisPlantLoop.Name);
    1232            0 :             SetupOutputVariable(state,
    1233              :                                 "Plant Common Pipe Flow Direction Status",
    1234              :                                 Constant::Units::None,
    1235            0 :                                 thisCommonPipe.FlowDir,
    1236              :                                 OutputProcessor::TimeStepType::System,
    1237              :                                 OutputProcessor::StoreType::Average,
    1238            0 :                                 thisPlantLoop.Name);
    1239              : 
    1240            0 :             if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1241              :                 // If/when the model supports variable-pumping primary, this can be removed.
    1242            0 :                 ShowWarningError(state, "SetupCommonPipes: detected variable speed pump on supply inlet of CommonPipe plant loop");
    1243            0 :                 ShowContinueError(state, format("Occurs on plant loop name = {}", thisPlantLoop.Name));
    1244            0 :                 ShowContinueError(state, "The common pipe model does not support varying the flow rate on the primary/supply side");
    1245            0 :                 ShowContinueError(state, "The primary/supply side will operate as if constant speed, and the simulation continues");
    1246              :             }
    1247            0 :             break;
    1248            0 :         case DataPlant::CommonPipeType::TwoWay: // Controlled ('two-way') common pipe
    1249            0 :             thisCommonPipe.CommonPipeType = DataPlant::CommonPipeType::TwoWay;
    1250            0 :             SetupOutputVariable(state,
    1251              :                                 "Plant Common Pipe Primary Mass Flow Rate",
    1252              :                                 Constant::Units::kg_s,
    1253            0 :                                 thisCommonPipe.PriCPLegFlow,
    1254              :                                 OutputProcessor::TimeStepType::System,
    1255              :                                 OutputProcessor::StoreType::Average,
    1256            0 :                                 thisPlantLoop.Name);
    1257            0 :             SetupOutputVariable(state,
    1258              :                                 "Plant Common Pipe Secondary Mass Flow Rate",
    1259              :                                 Constant::Units::kg_s,
    1260            0 :                                 thisCommonPipe.SecCPLegFlow,
    1261              :                                 OutputProcessor::TimeStepType::System,
    1262              :                                 OutputProcessor::StoreType::Average,
    1263            0 :                                 thisPlantLoop.Name);
    1264            0 :             SetupOutputVariable(state,
    1265              :                                 "Plant Common Pipe Primary to Secondary Mass Flow Rate",
    1266              :                                 Constant::Units::kg_s,
    1267            0 :                                 thisCommonPipe.PriToSecFlow,
    1268              :                                 OutputProcessor::TimeStepType::System,
    1269              :                                 OutputProcessor::StoreType::Average,
    1270            0 :                                 thisPlantLoop.Name);
    1271            0 :             SetupOutputVariable(state,
    1272              :                                 "Plant Common Pipe Secondary to Primary Mass Flow Rate",
    1273              :                                 Constant::Units::kg_s,
    1274            0 :                                 thisCommonPipe.SecToPriFlow,
    1275              :                                 OutputProcessor::TimeStepType::System,
    1276              :                                 OutputProcessor::StoreType::Average,
    1277            0 :                                 thisPlantLoop.Name);
    1278              : 
    1279              :             // check type of pump on supply side inlet
    1280            0 :             if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpConstantSpeed) {
    1281            0 :                 thisCommonPipe.SupplySideInletPumpType = FlowType::Constant;
    1282            0 :             } else if (first_supply_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1283            0 :                 thisCommonPipe.SupplySideInletPumpType = FlowType::Variable;
    1284              :                 // If/when the model supports variable-pumping primary, this can be removed.
    1285            0 :                 ShowWarningError(state, "SetupCommonPipes: detected variable speed pump on supply inlet of TwoWayCommonPipe plant loop");
    1286            0 :                 ShowContinueError(state, format("Occurs on plant loop name = {}", thisPlantLoop.Name));
    1287            0 :                 ShowContinueError(state, "The common pipe model does not support varying the flow rate on the primary/supply side");
    1288            0 :                 ShowContinueError(state, "The primary/supply side will operate as if constant speed, and the simulation continues");
    1289              :             }
    1290              :             // check type of pump on demand side inlet
    1291            0 :             if (first_demand_component_type == DataPlant::PlantEquipmentType::PumpConstantSpeed) {
    1292            0 :                 thisCommonPipe.DemandSideInletPumpType = FlowType::Constant;
    1293            0 :             } else if (first_demand_component_type == DataPlant::PlantEquipmentType::PumpVariableSpeed) {
    1294            0 :                 thisCommonPipe.DemandSideInletPumpType = FlowType::Variable;
    1295              :             }
    1296            0 :             break;
    1297            0 :         default:
    1298            0 :             assert(false);
    1299              :         }
    1300              :     }
    1301              : 
    1302            0 :     state.dataHVACInterfaceMgr->CommonPipeSetupFinished = true;
    1303            0 : }
    1304              : 
    1305              : } // namespace EnergyPlus::HVACInterfaceManager
        

Generated by: LCOV version 2.0-1