LCOV - code coverage report
Current view: top level - EnergyPlus/Plant - LoopSide.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 808 962 84.0 %
Date: 2023-01-17 19:17:23 Functions: 22 22 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : #include <ObjexxFCL/Fmath.hh>
      49             : #include <ObjexxFCL/member.functions.hh>
      50             : 
      51             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      52             : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      53             : #include <EnergyPlus/DataConvergParams.hh>
      54             : #include <EnergyPlus/DataHVACGlobals.hh>
      55             : #include <EnergyPlus/FluidProperties.hh>
      56             : #include <EnergyPlus/General.hh>
      57             : #include <EnergyPlus/HVACInterfaceManager.hh>
      58             : #include <EnergyPlus/Plant/DataPlant.hh>
      59             : #include <EnergyPlus/Plant/LoopSide.hh>
      60             : #include <EnergyPlus/PlantCondLoopOperation.hh>
      61             : #include <EnergyPlus/PlantPressureSystem.hh>
      62             : #include <EnergyPlus/PlantUtilities.hh>
      63             : #include <EnergyPlus/Pumps.hh>
      64             : #include <EnergyPlus/UtilityRoutines.hh>
      65             : 
      66             : namespace EnergyPlus {
      67             : namespace DataPlant {
      68             : 
      69             :     static constexpr std::string_view fluidNameSteam("STEAM");
      70             : 
      71    34416411 :     void HalfLoopData::solve(EnergyPlusData &state, bool const FirstHVACIteration, bool &ReSimOtherSideNeeded)
      72             :     {
      73             : 
      74             :         // SUBROUTINE INFORMATION:
      75             :         //       AUTHORS:         Dan Fisher, Sankaranarayanan K P, Edwin Lee
      76             :         //       DATE WRITTEN:    April 1998
      77             :         //       MODIFIED         June 2005(Work in the Plant Super Manager Module)
      78             :         //                        July 2006
      79             :         //       RE-ENGINEERED    July 2010
      80             : 
      81             :         // PURPOSE OF THIS SUBROUTINE:
      82             :         // SimSupplyFlowSolution is the driver routine for plant loops.  It performs
      83             :         //  the following tasks for each half loop (supply or demand side):
      84             :         // 1. Calculate flow request for half loop
      85             :         // 2. Predict Loop Flow
      86             :         // 3. Simulate the inlet branch
      87             :         // 4. Simulate the parallel branches, distributing load if necessary
      88             :         // 5. Set flow rates on parallel branches
      89             :         // 6. Simulate outlet branch and update node and report variables
      90             : 
      91             :         // METHODOLOGY EMPLOYED:
      92             :         // The algorithm operates on a predictor/corrector flow setting method by simulating all available loop components
      93             :         // based on component requested flow rates, then enforcing continuity on all loop branch flows by calling
      94             :         // the flow resolver and locking those flows down.  Available components are then re-simulated using the
      95             :         // corrected flow rates.
      96             : 
      97    34416411 :         auto &thisPlantLoop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
      98    34416411 :         int ThisSideInletNode = this->NodeNumIn;
      99             : 
     100    34416411 :         this->InitialDemandToLoopSetPoint = 0.0;
     101    34416411 :         this->CurrentAlterationsToDemand = 0.0;
     102    34416411 :         this->UpdatedDemandToLoopSetPoint = 0.0;
     103             : 
     104             :         // The following block is related to validating the flow control paths of the loop side
     105             :         // Since the control types are scheduled, I think BeginTimeStep should be a decent check frequency
     106    34416411 :         if (state.dataGlobal->BeginTimeStepFlag && this->OncePerTimeStepOperations) {
     107             : 
     108             :             // Initialize loop side controls -- could just be done for one loop since this routine inherently
     109             :             //  loops over all plant/condenser loops.  Not sure if the penalty is worth investigating.
     110    11558801 :             PlantCondLoopOperation::InitLoadDistribution(state, FirstHVACIteration);
     111             : 
     112             :             // Now that the op scheme types are updated, do LoopSide validation
     113    11558801 :             this->ValidateFlowControlPaths(state);
     114             : 
     115             :             // Set the flag to false so we won't do these again this time step
     116    11558801 :             this->OncePerTimeStepOperations = false;
     117             : 
     118             :         } else {
     119             : 
     120             :             // Set the flag to true so that it is activated for the next time step
     121    22857610 :             this->OncePerTimeStepOperations = true;
     122             :         }
     123             : 
     124             :         // Do pressure system initialize if this is the demand side (therefore once per whole loop)
     125    34416411 :         if (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
     126    17211978 :             PlantPressureSystem::SimPressureDropSystem(state, this->plantLoc.loopNum, FirstHVACIteration, DataPlant::PressureCall::Init);
     127             :         }
     128             : 
     129             :         // Turn on any previously disabled branches due to constant speed branch pump issue
     130    34416411 :         this->TurnOnAllLoopSideBranches();
     131             : 
     132    34416411 :         LoopSideLocation OtherLoopSide = static_cast<LoopSideLocation>(LoopSideOther[static_cast<int>(this->plantLoc.loopSideNum)]);
     133             :         // Do the actual simulation here every time
     134    34416411 :         this->DoFlowAndLoadSolutionPass(state, OtherLoopSide, ThisSideInletNode, FirstHVACIteration);
     135             : 
     136             :         // On constant speed branch pump loop sides we need to re-simulate
     137    34416411 :         if (this->hasConstSpeedBranchPumps) {
     138             :             // turn off any pumps connected to unloaded equipment and re-do the flow/load solution pass
     139       85407 :             this->DisableAnyBranchPumpsConnectedToUnloadedEquipment();
     140       85407 :             this->DoFlowAndLoadSolutionPass(state, OtherLoopSide, ThisSideInletNode, FirstHVACIteration);
     141             :         }
     142             : 
     143             :         // A couple things are specific to which LoopSide we are on  // TODO: This whole block needs to be moved up to the loop level
     144    34416411 :         if (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
     145             : 
     146             :             // Pass the loop information via the HVAC interface manager
     147    51635934 :             HVACInterfaceManager::UpdatePlantLoopInterface(state,
     148             :                                                            this->plantLoc,
     149    17211978 :                                                            thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumOut,
     150    17211978 :                                                            thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn,
     151             :                                                            ReSimOtherSideNeeded,
     152             :                                                            thisPlantLoop.CommonPipeType);
     153             : 
     154             :         } else { // LoopSide == LoopSideLocation::Supply
     155             : 
     156             :             // Update pressure drop reporting, calculate total loop pressure drop for use elsewhere
     157    17204433 :             PlantPressureSystem::SimPressureDropSystem(state, this->plantLoc.loopNum, FirstHVACIteration, DataPlant::PressureCall::Update);
     158             : 
     159             :             // Pass the loop information via the HVAC interface manager (only the flow)
     160    51613299 :             HVACInterfaceManager::UpdatePlantLoopInterface(state,
     161             :                                                            this->plantLoc,
     162    17204433 :                                                            thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut,
     163    17204433 :                                                            thisPlantLoop.LoopSide(DataPlant::LoopSideLocation::Demand).NodeNumIn,
     164             :                                                            ReSimOtherSideNeeded,
     165             :                                                            thisPlantLoop.CommonPipeType);
     166             : 
     167             :             // Update the loop outlet node conditions
     168    17204433 :             state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
     169    17204433 :                 .CheckLoopExitNode(state, FirstHVACIteration); // TODO: This is a loop level check, move out
     170             : 
     171    17204433 :             state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
     172    17204433 :                 .UpdateLoopSideReportVars(state, this->InitialDemandToLoopSetPointSAVED, this->LoadToLoopSetPointThatWasntMet);
     173             :         }
     174    34416411 :     }
     175             : 
     176    11558801 :     void HalfLoopData::ValidateFlowControlPaths(EnergyPlusData &state)
     177             :     {
     178             : 
     179             :         // FUNCTION INFORMATION:
     180             :         //       AUTHOR         Edwin Lee
     181             :         //       DATE WRITTEN   July 2010
     182             :         //       MODIFIED       na
     183             :         //       RE-ENGINEERED  na
     184             : 
     185             :         // PURPOSE OF THIS FUNCTION:
     186             :         // This routine will scan all the loop side paths and validate the component topology according
     187             :         //  to current topology rules and regulations.
     188             : 
     189             :         // METHODOLOGY EMPLOYED:
     190             :         // Scan this loop side and begin by scanning the first branch, then follow with the remainder of the flow paths
     191             :         //  - this would be from splitter outlet nodes all the way to the loop side outlet node.
     192             :         // The current rules are that "other types" of components (as defined below in the references) can be placed along each
     193             :         //  flow path as needed.  At this point, any number of "load-range based" components can be placed along the flow
     194             :         //  path.  After this, the user is allowed to place another set of any number of "other types" of components.
     195             :         // The key restriction is that an "other type" of component may not be sandwiched by "load-range based" components.
     196             :         // This is due to the load range based needing to be simulated all at once along each flow path.
     197             : 
     198             :         // REFERENCES:
     199             :         // "other types" of components: basically not load-range based heat transfer components.  This would include:
     200             :         //    - demand based components such as coils
     201             :         //    - component setpoint based operating components
     202             :         //    - heat exchanger components including waterside economizers
     203             :         // "load-range based" components are heat transfer components which are controlled based on a single load range.
     204             :         //    - currently only one load range based scheme is available at a given time, although other control types
     205             :         //      may be enabled, such as component setpoint.
     206             :         // Pumps are separate components since the pump heat is not accounted for in the flow path order.
     207             :         //  Improvements during the demand side rewrite has allowed pumps to be placed as -not- the first component on a branch
     208             :         //  Pumps can be placed anywhere, even between load-range based components, since they will not affect loop load
     209             : 
     210             :         // RETURN VALUE:
     211             :         // Returns a control validator flow structure, including a flag for successful or not, then if not successful
     212             :         //  the other values are filled in such as location on the loop where the error occurred and a message error description
     213             : 
     214             :         // FUNCTION PARAMETER DEFINITIONS:
     215    11558801 :         int constexpr Parallel(1);
     216    11558801 :         int constexpr Outlet(2);
     217             : 
     218             :         //~ Initialze
     219    11558801 :         bool EncounteredLRB = false;
     220    11558801 :         bool EncounteredNonLRBAfterLRB = false;
     221    11558801 :         int const NumParallelPaths = this->TotalBranches - 2;
     222             : 
     223             :         // We'll start by stepping through the first branch, which may be the only branch
     224             :         // If we find a load range based, then trip the flag and just keep moving
     225             :         // If we only have one branch and all is good, then RETURN early
     226             :         // If we have parallel branches, then start looping through each flow path to
     227             :         //  decide if it is a valid path.
     228             :         // If any one path is invalid then all is wrong
     229    11558801 :         int firstBranchIndex = 1;
     230    23241205 :         for (int CompIndex = 1; CompIndex <= this->Branch(firstBranchIndex).TotalComponents; ++CompIndex) {
     231             : 
     232    11682404 :             auto &this_component(this->Branch(firstBranchIndex).Comp(CompIndex));
     233             : 
     234             :             {
     235    11682404 :                 switch (this_component.CurOpSchemeType) {
     236        2464 :                 case OpScheme::HeatingRB:
     237             :                 case OpScheme::CoolingRB: { //~ load range based
     238        2464 :                     if (EncounteredNonLRBAfterLRB) {
     239             :                         // We must have already encountered a LRB, then a non-LRB, and now another LRB, this is bad
     240           0 :                         ShowSevereError(state, "Plant topology problem on \"" + this->loopSideDescription + "\"");
     241           0 :                         ShowContinueError(state, "PlaLoad range based components are separated by other control type components.");
     242           0 :                         ShowContinueError(state, "Load Range Based should be grouped together on each flow path.");
     243           0 :                         ShowFatalError(state, "Plant topology issue causes program termination");
     244             :                     } else {
     245        2464 :                         EncounteredLRB = true;
     246             :                     }
     247        2464 :                     break;
     248             :                 }
     249     5844357 :                 case DataPlant::OpScheme::Pump: { //~ pump
     250             :                     // For now this is just a placeholder, because I think pumps will be available anywhere,
     251             :                     //  and they won't affect the load distribution
     252     5844357 :                     break;
     253             :                 }
     254     5751137 :                 case DataPlant::OpScheme::NoControl: { //~ Such as pipes
     255             :                     // For now this is just a placeholder, because these components shouldn't cause a problem anywhere...
     256     5751137 :                     break;
     257             :                 }
     258           0 :                 case DataPlant::OpScheme::Invalid: { //~ Uninitialized, this should be a sufficient place to catch for this on branch 1
     259             :                     // throw fatal
     260           0 :                     ShowSevereError(state,
     261           0 :                                     "ValidateFlowControlPaths: Uninitialized operation scheme type for component Name: " + this_component.Name);
     262           0 :                     ShowFatalError(state, "ValidateFlowControlPaths: developer notice, Inlet path validation loop");
     263           0 :                     break;
     264             :                 }
     265       84446 :                 default: { //~ Other control type
     266       84446 :                     if (EncounteredLRB) {
     267           0 :                         EncounteredNonLRBAfterLRB = true;
     268             :                     } else {
     269             :                         // For now don't do anything, but we'll see...
     270             :                     }
     271             :                 }
     272             :                 }
     273             :             }
     274             :         }
     275             : 
     276             :         // Return early if we only needed to do the one branch
     277    11558801 :         if (NumParallelPaths <= 0) return;
     278             : 
     279             :         // Now, if we have multiple parallel branches, I think the easiest way is to go all the way from the inlet node
     280             :         //  of each parallel branch to the loop outlet node and check the flow path
     281             :         // This way we don't have to remember the conditions on each of the parallel branches when we would finally move
     282             :         //  to analyzing the outlet node when all done
     283             :         // This will reduce allocation on the heap because we will keep from storing that array
     284             :         // For each parallel path, we will need to check two branches: the parallel branch and the LoopSide outlet branch
     285    60705896 :         for (int PathCounter = 1; PathCounter <= NumParallelPaths; ++PathCounter) {
     286   147651891 :             for (int ParallelOrOutletIndex = Parallel; ParallelOrOutletIndex <= Outlet; ++ParallelOrOutletIndex) {
     287             :                 int BranchIndex;
     288    98434594 :                 if (ParallelOrOutletIndex == Parallel) {
     289             :                     // The branch index will be the current pathtype + 1 to add the inlet branch
     290    49217297 :                     BranchIndex = PathCounter + 1;
     291             :                 } else { // ParallelOrOutletIndex == Outlet
     292             :                     // The branch index will be the LoopSide outlet node
     293    49217297 :                     BranchIndex = this->TotalBranches;
     294             :                 }
     295             : 
     296             :                 // Now that we have the branch index, let's do the control type check over all the components
     297   197215374 :                 for (int CompIndex = 1; CompIndex <= this->Branch(BranchIndex).TotalComponents; ++CompIndex) {
     298             : 
     299    98780780 :                     auto &this_component(this->Branch(BranchIndex).Comp(CompIndex));
     300             : 
     301             :                     {
     302    98780780 :                         switch (this_component.CurOpSchemeType) {
     303     6216349 :                         case OpScheme::HeatingRB:
     304             :                         case OpScheme::CoolingRB: { //~ load range based
     305     6216349 :                             if (EncounteredNonLRBAfterLRB) {
     306             :                                 // We must have already encountered a LRB, then a non-LRB, and now another LRB, this is bad
     307           0 :                                 ShowSevereError(state, "Plant topology problem on \"" + this->loopSideDescription + "\"");
     308           0 :                                 ShowContinueError(state, "Load range based components are separated by other control type components.");
     309           0 :                                 ShowContinueError(state, "Load Range Based should be grouped together on each flow path.");
     310           0 :                                 ShowFatalError(state, "Plant topology issue causes program termination");
     311             :                             } else {
     312     6216349 :                                 EncounteredLRB = true;
     313             :                             }
     314     6216349 :                             break;
     315             :                         }
     316             : 
     317    60906141 :                         case DataPlant::OpScheme::NoControl: { //~ Such as pipes
     318             :                             // For now this is just a placeholder, because these components shouldn't cause a problem anywhere...
     319    60906141 :                             break;
     320             :                         }
     321       90306 :                         case DataPlant::OpScheme::Pump: { //~ pump
     322             :                             // For now this is just a placeholder, because I think pumps will be available anywhere,
     323             :                             //  and they won't affect the load distribution
     324       90306 :                             break;
     325             :                         }
     326           0 :                         case DataPlant::OpScheme::Invalid: { //~ Uninitialized, this should be sufficient place to
     327             :                                                              // catch for this on other branches
     328             :                             // throw fatal error
     329           0 :                             ShowSevereError(
     330           0 :                                 state, "ValidateFlowControlPaths: Uninitialized operation scheme type for component Name: " + this_component.Name);
     331           0 :                             ShowFatalError(state, "ValidateFlowControlPaths: developer notice, problem in Parallel path validation loop");
     332           0 :                             break;
     333             :                         }
     334    31567984 :                         default: { //~ Other control type
     335    31567984 :                             if (EncounteredLRB) {
     336           0 :                                 EncounteredNonLRBAfterLRB = true;
     337             :                             } else {
     338             :                                 // For now don't do anything, but we'll see...
     339             :                             }
     340             :                         }
     341             :                         }
     342             :                     }
     343             : 
     344             :                 } //~ CompIndex
     345             : 
     346             :             } //~ Parallel and Outlet Branches
     347             : 
     348             :         } //~ Parallel Paths
     349             :     }
     350             : 
     351   104695826 :     bool HalfLoopData::CheckPlantConvergence(bool const FirstHVACIteration)
     352             :     {
     353             : 
     354             :         // FUNCTION INFORMATION:
     355             :         //       AUTHOR         Edwin Lee
     356             :         //       DATE WRITTEN   Summer 2011
     357             :         //       MODIFIED       na
     358             :         //       RE-ENGINEERED  na
     359             : 
     360             :         // PURPOSE OF THIS FUNCTION:
     361             :         // This routine checks the history values in the convergence arrays of this loop/LoopSide combination
     362             : 
     363             :         // METHODOLOGY EMPLOYED:
     364             :         // On FirstHVAC, we are not converged yet, thus forcing at least two iterations
     365             :         // Calculate the average of each related variable history (generalized: could be any number of history terms)
     366             :         // If any of the history terms do not match this average, then at least one value is different, so not converged
     367             :         // Although this routine appears to check for convergence, it is also used to check for stuck (max iteration) conditions
     368             :         //  in cases where demand side (air loop, for example) equipment is "fighting" with the plant loop
     369             :         // The result of this routine can help the plant "lock-in" and take action to stop the iteration
     370             : 
     371             :         // Using/Aliasing
     372             :         using namespace DataPlant;
     373             :         using namespace DataLoopNode;
     374             : 
     375             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
     376             :         Real64 InletAvgTemp;
     377             :         Real64 InletAvgMdot;
     378             :         Real64 OutletAvgTemp;
     379             :         Real64 OutletAvgMdot;
     380             : 
     381   104695826 :         if (FirstHVACIteration) {
     382    46691124 :             return false;
     383             :         }
     384             : 
     385    58004702 :         InletAvgTemp = sum(this->InletNode.TemperatureHistory) / size(this->InletNode.TemperatureHistory);
     386    58004702 :         if (any_ne(this->InletNode.TemperatureHistory, InletAvgTemp)) {
     387    57758195 :             return false;
     388             :         }
     389             : 
     390      246507 :         InletAvgMdot = sum(this->InletNode.MassFlowRateHistory) / size(this->InletNode.MassFlowRateHistory);
     391      246507 :         if (any_ne(this->InletNode.MassFlowRateHistory, InletAvgMdot)) {
     392       77393 :             return false;
     393             :         }
     394             : 
     395      169114 :         OutletAvgTemp = sum(this->OutletNode.TemperatureHistory) / size(this->OutletNode.TemperatureHistory);
     396      169114 :         if (any_ne(this->OutletNode.TemperatureHistory, OutletAvgTemp)) {
     397       51969 :             return false;
     398             :         }
     399             : 
     400      117145 :         OutletAvgMdot = sum(this->OutletNode.MassFlowRateHistory) / size(this->OutletNode.MassFlowRateHistory);
     401      117145 :         if (any_ne(this->OutletNode.MassFlowRateHistory, OutletAvgMdot)) {
     402        5026 :             return false;
     403             :         }
     404             : 
     405             :         // If we made it this far, we're good!
     406      112119 :         return true;
     407             :     }
     408             : 
     409   104695826 :     void HalfLoopData::PushBranchFlowCharacteristics(EnergyPlusData &state,
     410             :                                                      int const BranchNum,
     411             :                                                      Real64 const ValueToPush,
     412             :                                                      bool const FirstHVACIteration // TRUE if First HVAC iteration of Time step
     413             :     )
     414             :     {
     415             : 
     416             :         // SUBROUTINE INFORMATION:
     417             :         //       AUTHOR         Edwin Lee
     418             :         //       DATE WRITTEN   September 2010
     419             :         //       MODIFIED       na
     420             :         //       RE-ENGINEERED  na
     421             : 
     422             :         // PURPOSE OF THIS SUBROUTINE:
     423             :         // This routine takes the flow resolved flow rate and pushes it
     424             :         //  down a branch.  In the process, if an externally connected
     425             :         //  component (air-water coil for example) is found to have a
     426             :         //  differing flow rate, the air sim flag is tripped to true, but
     427             :         //  the flow resolved flow rate is pushed down the loop to allow
     428             :         //  the plant to finish successfully.
     429             : 
     430             :         // METHODOLOGY EMPLOYED:
     431             :         // Push mass flow rate and max avail down each branch.  If the component
     432             :         //  is connected (or could be, for now) to an external loop such as
     433             :         //  an air loop, the current component outlet mass flow is checked
     434             :         //  vs the current resolved mass flow.  If the mass flow doesn't match,
     435             :         //  the air sim flag is tripped to true.
     436             : 
     437             :         // Currently this routine is only performed for starved branches, when
     438             :         //  the coil is requesting too much flow, more than the plant can provide.
     439             :         // If this were moved to every call type, including a minimum plant flow,
     440             :         //  you would need to provide a mass flow and min/max avail to push
     441             :         //  down the branch as well.
     442             : 
     443             :         // Using/Aliasing
     444             :         using namespace DataPlant; // Use the entire module to allow all TypeOf's, would be a huge ONLY list
     445             : 
     446             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     447             :         int CompCounter;
     448             :         int BranchInletNode;
     449             :         int ComponentInletNode;
     450             :         int ComponentOutletNode;
     451             :         DataPlant::PlantEquipmentType ComponentType;
     452             :         Real64 MassFlowRateFound;
     453             :         Real64 MassFlow;
     454             :         bool PlantIsRigid;
     455             : 
     456   104695826 :         auto &this_branch(this->Branch(BranchNum));
     457             : 
     458   104695826 :         BranchInletNode = this_branch.NodeNumIn;
     459             : 
     460             :         //~ Possible error handling if needed
     461   104695826 :         if (ValueToPush != state.dataLoopNodes->Node(BranchInletNode).MassFlowRate) {
     462             :             // Diagnostic problem, flow resolver isn't calling this routine properly
     463             :         }
     464             : 
     465             :         //~ This section would really be useful more later on if this routine has more logic regarding what to push down the branch
     466   104695826 :         MassFlow = ValueToPush;
     467             :         // MinAvail = ValueToPush
     468             :         // MaxAvail = ValueToPush
     469             : 
     470   104695826 :         PlantIsRigid = this->CheckPlantConvergence(FirstHVACIteration);
     471             : 
     472             :         //~ Loop across all component outlet nodes and update their mass flow and max avail
     473   209840465 :         for (CompCounter = 1; CompCounter <= this_branch.TotalComponents; ++CompCounter) {
     474             : 
     475   105144639 :             auto &this_comp(this_branch.Comp(CompCounter));
     476             : 
     477             :             //~ Pick up some values for convenience
     478   105144639 :             ComponentInletNode = this_comp.NodeNumIn;
     479   105144639 :             ComponentOutletNode = this_comp.NodeNumOut;
     480   105144639 :             MassFlowRateFound = state.dataLoopNodes->Node(ComponentOutletNode).MassFlowRate;
     481   105144639 :             ComponentType = this_comp.Type;
     482             : 
     483             :             //~ Push the values through
     484   105144639 :             state.dataLoopNodes->Node(ComponentOutletNode).MassFlowRate = MassFlow;
     485             : 
     486   105144639 :             if (PlantIsRigid) {
     487      112119 :                 state.dataLoopNodes->Node(ComponentInletNode).MassFlowRateMinAvail = MassFlow;
     488      112119 :                 state.dataLoopNodes->Node(ComponentInletNode).MassFlowRateMaxAvail = MassFlow;
     489      112119 :                 state.dataLoopNodes->Node(ComponentOutletNode).MassFlowRateMinAvail = MassFlow;
     490      112119 :                 state.dataLoopNodes->Node(ComponentOutletNode).MassFlowRateMaxAvail = MassFlow;
     491             :             }
     492             :             // Node(ComponentOutletNode)%MassFlowRateMinAvail = MinAvail
     493             :             // no this is 2-way valve which messes up flow options
     494             :             //      for demand components Node(ComponentOutletNode)%MassFlowRateMaxAvail = MaxAvail
     495             : 
     496             :             //~ If this value matches then we are good to move to the next component
     497   105144639 :             if (std::abs(MassFlow - MassFlowRateFound) < CriteriaDelta_MassFlowRate) continue;
     498             :             //~ Since there is a difference, we have to decide what to do based on the component type:
     499             :             //~  For plant connections, don't do anything, it SHOULD work itself out
     500             :             //~  For air connections, trip the LoopSide air flag
     501             :             //~  Similar for zone, none zone, and electric load center
     502             :             {
     503    11267659 :                 switch (ComponentType) {
     504             : 
     505             :                     // possibly air-connected components
     506      821016 :                 case DataPlant::PlantEquipmentType::CoilWaterCooling:
     507             :                 case DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling:
     508             :                 case DataPlant::PlantEquipmentType::CoilWaterSimpleHeating:
     509             :                 case DataPlant::PlantEquipmentType::CoilSteamAirHeating:
     510             :                 case DataPlant::PlantEquipmentType::CoilWAHPHeatingEquationFit:
     511             :                 case DataPlant::PlantEquipmentType::CoilWAHPCoolingEquationFit:
     512             :                 case DataPlant::PlantEquipmentType::CoilWAHPHeatingParamEst:
     513             :                 case DataPlant::PlantEquipmentType::CoilWAHPCoolingParamEst:
     514             :                 case DataPlant::PlantEquipmentType::CoilUserDefined:
     515             :                 case DataPlant::PlantEquipmentType::CoilVSWAHPCoolingEquationFit:
     516             :                 case DataPlant::PlantEquipmentType::CoilVSWAHPHeatingEquationFit:
     517             :                 case DataPlant::PlantEquipmentType::PackagedTESCoolingCoil: {
     518      821016 :                     this->SimAirLoopsNeeded = true;
     519             :                     // sometimes these coils are children in ZoneHVAC equipment
     520             :                     // PlantLoop(LoopNum)%LoopSide(LoopSideNum)%SimZoneEquipNeeded= .TRUE.
     521      821016 :                     break;
     522             :                 }
     523             : 
     524             :                     // zone connected components
     525       24275 :                 case DataPlant::PlantEquipmentType::CoolingPanel_Simple:
     526             :                 case DataPlant::PlantEquipmentType::Baseboard_Conv_Water:
     527             :                 case DataPlant::PlantEquipmentType::Baseboard_Rad_Conv_Steam:
     528             :                 case DataPlant::PlantEquipmentType::Baseboard_Rad_Conv_Water:
     529             :                 case DataPlant::PlantEquipmentType::LowTempRadiant_VarFlow:
     530             :                 case DataPlant::PlantEquipmentType::LowTempRadiant_ConstFlow:
     531             :                 case DataPlant::PlantEquipmentType::CooledBeamAirTerminal:
     532             :                 case DataPlant::PlantEquipmentType::ZoneHVACAirUserDefined:
     533             :                 case DataPlant::PlantEquipmentType::AirTerminalUserDefined:
     534             :                 case DataPlant::PlantEquipmentType::FourPipeBeamAirTerminal: {
     535       24275 :                     this->SimZoneEquipNeeded = true;
     536       24275 :                     break;
     537             :                 }
     538             : 
     539             :                 // electric center connected components
     540        5768 :                 case DataPlant::PlantEquipmentType::Generator_FCExhaust:
     541             :                 case DataPlant::PlantEquipmentType::Generator_FCStackCooler:
     542             :                 case DataPlant::PlantEquipmentType::Generator_MicroCHP:
     543             :                 case DataPlant::PlantEquipmentType::Generator_MicroTurbine:
     544             :                 case DataPlant::PlantEquipmentType::Generator_ICEngine:
     545             :                 case DataPlant::PlantEquipmentType::Generator_CTurbine: {
     546        5768 :                     this->SimElectLoadCentrNeeded = true;
     547        5768 :                     break;
     548             :                 }
     549             : 
     550    10416600 :                 default:
     551    10416600 :                     break;
     552             :                 }
     553             :             }
     554             :         }
     555   104695826 :     }
     556             : 
     557    34416411 :     void HalfLoopData::TurnOnAllLoopSideBranches()
     558             :     {
     559   179259700 :         for (int branchNum = 2; branchNum <= this->TotalBranches - 1; ++branchNum) {
     560   144843289 :             auto &branch = this->Branch(branchNum);
     561   144843289 :             branch.disableOverrideForCSBranchPumping = false;
     562             :         }
     563    34416411 :     }
     564             : 
     565    69003636 :     void HalfLoopData::SimulateAllLoopSideBranches(EnergyPlusData &state,
     566             :                                                    Real64 const ThisLoopSideFlow,
     567             :                                                    bool const FirstHVACIteration,
     568             :                                                    bool &LoopShutDownFlag)
     569             :     {
     570             : 
     571             :         // SUBROUTINE INFORMATION:
     572             :         //       AUTHOR         Edwin Lee
     573             :         //       DATE WRITTEN   July 2010
     574             :         //       MODIFIED       na
     575             :         //       RE-ENGINEERED  na
     576             : 
     577             :         // PURPOSE OF THIS SUBROUTINE:
     578             :         // This routine will step through all branch groups (single branch .OR. inlet/parallels/outlet)
     579             :         //  and call the branch group simulation routine.  This routine also calls to update the splitter
     580             :         //  and mixer.
     581             : 
     582             :         // METHODOLOGY EMPLOYED:
     583             :         // The number of branch groups is either 1 or 3.  1 would be a single branch half-loop.  3 would
     584             :         //  be the minimum for an inlet/parallels/outlet set.  The number of branch groups can then be
     585             :         //  calculated as #BrGrps = 1 + 2*L; where L is zero for single half loop and one for parallel-type set.
     586             :         //  This calculation can be reduced to the logical/integer conversion as shown in the code.
     587             :         // The simulation then steps through each branch group.  If there are parallel branches, the splitter is
     588             :         //  updated on flowlock=0 to pass information through, then after the parallel branches the mixer is always
     589             :         //  updated.  The outlet branch "group" is then simulated.
     590             : 
     591             :         // SUBROUTINE PARAMETER DEFINITIONS:
     592    69003636 :         int constexpr InletBranchOrOneBranchHalfLoop(1);
     593    69003636 :         int constexpr ParallelBranchSet(2);
     594    69003636 :         int constexpr OutletBranch(3);
     595             : 
     596    69003636 :         int NumBranchGroups = 1;
     597    69003636 :         if (this->TotalBranches > 1) {
     598    68684816 :             NumBranchGroups = 3;
     599             :         }
     600             : 
     601             :         // reset branch starting component index back to zero before each pass
     602   496869184 :         for (int BranchCounter = 1; BranchCounter <= this->TotalBranches; ++BranchCounter) {
     603   427865548 :             this->Branch(BranchCounter).lastComponentSimulated = 0;
     604             :         }
     605             : 
     606   275376904 :         for (int BranchGroup = 1; BranchGroup <= NumBranchGroups; ++BranchGroup) {
     607             : 
     608   206373268 :             if ((BranchGroup > 1) && (this->TotalBranches == 1)) break;
     609             : 
     610   206373268 :             switch (BranchGroup) {
     611    69003636 :             case InletBranchOrOneBranchHalfLoop:
     612    69003636 :                 this->SimulateLoopSideBranchGroup(state, 1, 1, ThisLoopSideFlow, FirstHVACIteration, LoopShutDownFlag);
     613    69003636 :                 break;
     614    68684816 :             case ParallelBranchSet:
     615    68684816 :                 this->UpdatePlantSplitter(state);
     616    68684816 :                 this->SimulateLoopSideBranchGroup(state, 2, this->TotalBranches - 1, ThisLoopSideFlow, FirstHVACIteration, LoopShutDownFlag);
     617    68684816 :                 this->UpdatePlantMixer(state);
     618    68684816 :                 break;
     619    68684816 :             case OutletBranch:
     620    68684816 :                 this->SimulateLoopSideBranchGroup(
     621             :                     state, this->TotalBranches, this->TotalBranches, ThisLoopSideFlow, FirstHVACIteration, LoopShutDownFlag);
     622    68684816 :                 break;
     623             :             }
     624             :         }
     625    69003636 :     }
     626             : 
     627    53185099 :     void HalfLoopData::AdjustPumpFlowRequestByEMSControls(int const BranchNum, int const CompNum, Real64 &FlowToRequest)
     628             :     {
     629             : 
     630             :         // SUBROUTINE INFORMATION:
     631             :         //       AUTHOR         Brent Griffith
     632             :         //       DATE WRITTEN   April 2012
     633             :         //       MODIFIED       na
     634             :         //       RE-ENGINEERED  na
     635             : 
     636             :         // PURPOSE OF THIS SUBROUTINE:
     637             :         // modify flow request to pump simulation if EMS is overriding pump component
     638             : 
     639             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     640    53185099 :         auto &this_branch(this->Branch(BranchNum));
     641    53185099 :         auto &this_comp(this_branch.Comp(CompNum));
     642             : 
     643    53185099 :         if ((this->EMSCtrl) && (this->EMSValue <= 0.0)) {
     644           0 :             FlowToRequest = 0.0;
     645           0 :             return;
     646             :         }
     647             : 
     648    53185099 :         if ((this_branch.EMSCtrlOverrideOn) && (this_branch.EMSCtrlOverrideValue <= 0.0)) {
     649           0 :             FlowToRequest = 0.0;
     650           0 :             return;
     651             :         }
     652             : 
     653    53185099 :         if (this_comp.EMSLoadOverrideOn) {
     654      333995 :             if (this_comp.EMSLoadOverrideValue == 0.0) {
     655      253367 :                 FlowToRequest = 0.0;
     656             :             }
     657             :         }
     658             :     }
     659             : 
     660       85407 :     void HalfLoopData::DisableAnyBranchPumpsConnectedToUnloadedEquipment()
     661             :     {
     662      330666 :         for (int branchNum = 2; branchNum <= this->TotalBranches - 1; ++branchNum) {
     663      245259 :             auto &branch = this->Branch(branchNum);
     664      245259 :             Real64 totalDispatchedLoadOnBranch = 0.0;
     665      661332 :             for (int compNum = 1; compNum <= branch.TotalComponents; ++compNum) {
     666      416073 :                 auto &component = branch.Comp(compNum);
     667      416073 :                 auto &t = component.Type;
     668      661332 :                 if (t == DataPlant::PlantEquipmentType::PumpConstantSpeed || t == DataPlant::PlantEquipmentType::PumpBankConstantSpeed ||
     669      490518 :                     t == DataPlant::PlantEquipmentType::PumpVariableSpeed || t == DataPlant::PlantEquipmentType::PumpBankVariableSpeed) {
     670             :                     // don't do anything
     671             :                 } else {
     672      245259 :                     totalDispatchedLoadOnBranch += component.MyLoad;
     673             :                 }
     674             :             }
     675      245259 :             if (std::abs(totalDispatchedLoadOnBranch) < 0.001) {
     676      191970 :                 branch.disableOverrideForCSBranchPumping = true;
     677             :             }
     678             :         }
     679       85407 :     }
     680             : 
     681    34501818 :     Real64 HalfLoopData::EvaluateLoopSetPointLoad(EnergyPlusData &state, int const FirstBranchNum, int const LastBranchNum, Real64 ThisLoopSideFlow)
     682             :     {
     683             : 
     684             :         // FUNCTION INFORMATION:
     685             :         //       AUTHOR         Edwin Lee
     686             :         //       DATE WRITTEN   August 2010
     687             :         //       MODIFIED       na
     688             :         //       RE-ENGINEERED  na
     689             : 
     690             :         // Return value
     691    34501818 :         Real64 LoadToLoopSetPoint = 0.0; // function result
     692             : 
     693             :         static constexpr std::string_view RoutineName("PlantLoopSolver::EvaluateLoopSetPointLoad");
     694             :         static constexpr std::string_view RoutineNameAlt("PlantSupplySide:EvaluateLoopSetPointLoad");
     695             : 
     696             :         //~ General variables
     697    34501818 :         Real64 SumMdotTimesTemp = 0.0;
     698    34501818 :         Real64 SumMdot = 0.0;
     699             : 
     700    34501818 :         auto &thisPlantLoop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     701             : 
     702             :         // We will place one specialized case in here for common pipe simulations.
     703             :         // If we are doing a common pipe simulation, and there is greater other-side flow than this side,
     704             :         //  then the "other side" demand needs to include getting the flow through the common pipe to the same setpoint
     705             :         //  as the flow going through the actual supply side
     706    34622297 :         if (this->hasConstSpeedBranchPumps && this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply &&
     707      120479 :             thisPlantLoop.CommonPipeType != DataPlant::CommonPipeType::No) {
     708       19955 :             const DataPlant::LoopSideLocation OtherSide = LoopSideOther[static_cast<int>(this->plantLoc.loopSideNum)];
     709       19955 :             const int otherSideOutletNodeNum = thisPlantLoop.LoopSide(OtherSide).NodeNumOut;
     710       19955 :             Real64 commonPipeFlow = state.dataLoopNodes->Node(otherSideOutletNodeNum).MassFlowRate - ThisLoopSideFlow;
     711       19955 :             Real64 otherSideExitingTemperature = state.dataLoopNodes->Node(otherSideOutletNodeNum).Temp;
     712       19955 :             SumMdotTimesTemp += otherSideExitingTemperature * commonPipeFlow;
     713       19955 :             SumMdot += commonPipeFlow;
     714             :         }
     715             : 
     716             :         // Sweep across flow paths in this group and calculate the deltaT and then the load
     717    34501818 :         int BranchIndex = 0; // ~ This is a 1 - n value within the current branch group
     718    69003636 :         for (int BranchCounter = FirstBranchNum; BranchCounter <= LastBranchNum; ++BranchCounter) {
     719             : 
     720    34501818 :             ++BranchIndex;
     721             : 
     722             :             //~ Always start from the last component we did the last time around + 1 and
     723             :             //~  try to make it all the way to the end of the loop
     724    34501818 :             int StartingComponent = this->Branch(BranchCounter).lastComponentSimulated + 1;
     725    34501818 :             int EnteringNodeNum = this->Branch(BranchCounter).Comp(StartingComponent).NodeNumIn;
     726             : 
     727    34501818 :             Real64 EnteringTemperature = state.dataLoopNodes->Node(EnteringNodeNum).Temp;
     728    34501818 :             Real64 MassFlowRate = state.dataLoopNodes->Node(EnteringNodeNum).MassFlowRate;
     729             : 
     730    34501818 :             SumMdotTimesTemp += EnteringTemperature * MassFlowRate;
     731    34501818 :             SumMdot += MassFlowRate;
     732             :         }
     733             : 
     734    34501818 :         if (SumMdot < DataBranchAirLoopPlant::MassFlowTolerance) {
     735    16240277 :             return 0.0;
     736             :         }
     737             : 
     738    18261541 :         Real64 WeightedInletTemp = SumMdotTimesTemp / SumMdot;
     739             : 
     740    18261541 :         if (thisPlantLoop.FluidType == DataLoopNode::NodeFluidType::Water) {
     741             : 
     742             :             Real64 Cp =
     743    18233741 :                 FluidProperties::GetSpecificHeatGlycol(state, thisPlantLoop.FluidName, WeightedInletTemp, thisPlantLoop.FluidIndex, RoutineName);
     744             : 
     745             :             {
     746             : 
     747    18233741 :                 if (thisPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     748             : 
     749             :                     // Pick up the loop setpoint temperature
     750    17892200 :                     Real64 LoopSetPointTemperature = this->TempSetPoint;
     751             :                     // Calculate the delta temperature
     752    17892200 :                     Real64 DeltaTemp = LoopSetPointTemperature - WeightedInletTemp;
     753             : 
     754             :                     // Calculate the demand on the loop
     755    17892200 :                     LoadToLoopSetPoint = SumMdot * Cp * DeltaTemp;
     756             : 
     757      341541 :                 } else if (thisPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
     758             : 
     759             :                     // Get the range of setpoints
     760      341541 :                     Real64 LoopSetPointTemperatureHi = state.dataLoopNodes->Node(thisPlantLoop.TempSetPointNodeNum).TempSetPointHi;
     761      341541 :                     Real64 LoopSetPointTemperatureLo = state.dataLoopNodes->Node(thisPlantLoop.TempSetPointNodeNum).TempSetPointLo;
     762             : 
     763             :                     // Calculate the demand on the loop
     764      341541 :                     if (SumMdot > 0.0) {
     765      341541 :                         Real64 LoadToHeatingSetPoint = SumMdot * Cp * (LoopSetPointTemperatureLo - WeightedInletTemp);
     766      341541 :                         Real64 LoadToCoolingSetPoint = SumMdot * Cp * (LoopSetPointTemperatureHi - WeightedInletTemp);
     767             :                         // Possible combinations:
     768             :                         // 1  LoadToHeatingSetPoint > 0 & LoadToCoolingSetPoint > 0 -->  Heating required
     769             :                         // 2  LoadToHeatingSetPoint < 0 & LoadToCoolingSetPoint < 0 -->  Cooling Required
     770             :                         // 3  LoadToHeatingSetPoint <=0 & LoadToCoolingSetPoint >=0 -->  Dead Band Operation - includes zero load cases
     771             :                         // 4  LoadToHeatingSetPoint  >  LoadToCoolingSetPoint       -->  Not Feasible if LoopSetPointHi >= LoopSetPointLo
     772             :                         // First trap bad set-points
     773      341541 :                         if (LoadToHeatingSetPoint > LoadToCoolingSetPoint) {
     774           0 :                             ShowSevereError(state,
     775             :                                             "Plant Loop: the Plant Loop Demand Calculation Scheme is set to DualSetPointDeadBand, but the "
     776             :                                             "heating-related low setpoint appears to be above the cooling-related high setpoint.");
     777           0 :                             ShowContinueError(state,
     778             :                                               "For example, if using SetpointManager:Scheduled:DualSetpoint, then check that the low setpoint is "
     779             :                                               "below the high setpoint.");
     780           0 :                             ShowContinueError(state, "Occurs in PlantLoop=" + thisPlantLoop.Name);
     781           0 :                             ShowContinueError(
     782             :                                 state,
     783           0 :                                 format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
     784           0 :                             ShowContinueError(state, format("Loop Heating Low Setpoint={:.2R}", LoopSetPointTemperatureLo));
     785           0 :                             ShowContinueError(state, format("Loop Cooling High Setpoint={:.2R}", LoopSetPointTemperatureHi));
     786             : 
     787           0 :                             ShowFatalError(state, "Program terminates due to above conditions.");
     788             :                         }
     789      341541 :                         if (LoadToHeatingSetPoint > 0.0 && LoadToCoolingSetPoint > 0.0) {
     790       88373 :                             LoadToLoopSetPoint = LoadToHeatingSetPoint;
     791      253168 :                         } else if (LoadToHeatingSetPoint < 0.0 && LoadToCoolingSetPoint < 0.0) {
     792      147174 :                             LoadToLoopSetPoint = LoadToCoolingSetPoint;
     793      105994 :                         } else if (LoadToHeatingSetPoint <= 0.0 && LoadToCoolingSetPoint >= 0.0) { // deadband includes zero loads
     794      105994 :                             LoadToLoopSetPoint = 0.0;
     795             :                         } else {
     796           0 :                             ShowSevereError(state,
     797             :                                             "DualSetPointWithDeadBand: Unanticipated combination of heating and cooling loads - report to EnergyPlus "
     798             :                                             "Development Team");
     799           0 :                             ShowContinueError(state, "occurs in PlantLoop=" + thisPlantLoop.Name);
     800           0 :                             ShowContinueError(
     801             :                                 state,
     802           0 :                                 format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
     803           0 :                             ShowContinueError(state, format("Loop Heating Setpoint={:.2R}", LoopSetPointTemperatureLo));
     804           0 :                             ShowContinueError(state, format("Loop Cooling Setpoint={:.2R}", LoopSetPointTemperatureHi));
     805           0 :                             ShowFatalError(state, "Program terminates due to above conditions.");
     806             :                         }
     807             :                     } else {
     808           0 :                         LoadToLoopSetPoint = 0.0;
     809             :                     }
     810             :                 }
     811             :             }
     812             : 
     813       27800 :         } else if (thisPlantLoop.FluidType == DataLoopNode::NodeFluidType::Steam) {
     814             : 
     815             :             Real64 Cp =
     816       27800 :                 FluidProperties::GetSpecificHeatGlycol(state, thisPlantLoop.FluidName, WeightedInletTemp, thisPlantLoop.FluidIndex, RoutineName);
     817             : 
     818             :             {
     819             : 
     820       27800 :                 if (thisPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     821             : 
     822             :                     // Pick up the loop setpoint temperature
     823       27800 :                     Real64 LoopSetPointTemperature = this->TempSetPoint;
     824             : 
     825             :                     // Calculate the delta temperature
     826       27800 :                     Real64 DeltaTemp = LoopSetPointTemperature - WeightedInletTemp;
     827             : 
     828             :                     Real64 EnthalpySteamSatVapor =
     829       27800 :                         FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, LoopSetPointTemperature, 1.0, this->refrigIndex, RoutineNameAlt);
     830             :                     Real64 EnthalpySteamSatLiquid =
     831       27800 :                         FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, LoopSetPointTemperature, 0.0, this->refrigIndex, RoutineNameAlt);
     832             : 
     833       27800 :                     Real64 LatentHeatSteam = EnthalpySteamSatVapor - EnthalpySteamSatLiquid;
     834             : 
     835             :                     // Calculate the demand on the loop
     836       27800 :                     LoadToLoopSetPoint = SumMdot * (Cp * DeltaTemp + LatentHeatSteam);
     837             :                 }
     838             :             }
     839             : 
     840             :         } else { // only have two types, water serves for glycol.
     841             :         }
     842             : 
     843             :         // Trim the demand to zero if it is very small
     844    18261541 :         if (std::abs(LoadToLoopSetPoint) < DataPlant::LoopDemandTol) LoadToLoopSetPoint = 0.0;
     845             : 
     846    18261541 :         return LoadToLoopSetPoint;
     847             :     }
     848             : 
     849    34501818 :     Real64 HalfLoopData::CalcOtherSideDemand(EnergyPlusData &state, Real64 ThisLoopSideFlow)
     850             :     {
     851             : 
     852             :         // FUNCTION INFORMATION:
     853             :         //       AUTHOR         Edwin Lee
     854             :         //       DATE WRITTEN   August 2010
     855             :         //       MODIFIED       na
     856             :         //       RE-ENGINEERED  na
     857             : 
     858             :         // PURPOSE OF THIS FUNCTION:
     859             :         // To evaluate the demand to hit the loop setpoint based on the loop side inlet conditions
     860             : 
     861             :         // METHODOLOGY EMPLOYED:
     862             :         // This routine will simply call the evaluate loop setpoint routine but call it from
     863             :         //  the very beginning of this loop side, so that it is basically for the entire loop side
     864             : 
     865             :         // FUNCTION PARAMETER DEFINITIONS:
     866    34501818 :         return this->EvaluateLoopSetPointLoad(state, 1, 1, ThisLoopSideFlow);
     867             :     }
     868             : 
     869    34501818 :     Real64 HalfLoopData::SetupLoopFlowRequest(EnergyPlusData &state, const LoopSideLocation OtherSide)
     870             :     {
     871             : 
     872             :         // FUNCTION INFORMATION:
     873             :         //       AUTHOR:          Dan Fisher, Edwin Lee
     874             :         //       DATE WRITTEN:    August 2010
     875             :         //       MODIFIED:        na
     876             :         //       RE-ENGINEERED:   na
     877             : 
     878             :         // PURPOSE OF THIS SUBROUTINE:
     879             :         // This routine sets up the flow request values and sums them up for each loop side
     880             :         // Then makes a decision on the desired loop flow based on loop configuration
     881             : 
     882             :         // METHODOLOGY EMPLOYED:
     883             :         // Scan through the components on this loop side, and look at the mass flow request
     884             :         //  values on components inlet node.
     885             :         // Check common pipe/pumping configuration for this loop side and the other loop side
     886             :         //  to determine what the LoopSide should flow
     887             : 
     888             :         //~ Initialize
     889    34501818 :         Real64 LoopFlow = 0.0; // Once all flow requests are evaluated, this is the desired flow on this side
     890             : 
     891             :         // reference
     892    34501818 :         auto &loop(state.dataPlnt->PlantLoop(this->plantLoc.loopNum));
     893             : 
     894             :         //~ First we need to set up the flow requests on each LoopSide
     895   103505454 :         for (DataPlant::LoopSideLocation LoopSideCounter : DataPlant::LoopSideKeys) {
     896             :             // Clear things out for this LoopSide
     897    69003636 :             Real64 InletBranchRequestNeedAndTurnOn = 0.0;
     898    69003636 :             Real64 InletBranchRequestNeedIfOn = 0.0;
     899    69003636 :             Real64 ParallelBranchRequestsNeedAndTurnOn(0.0);
     900    69003636 :             Real64 ParallelBranchRequestsNeedIfOn(0.0);
     901    69003636 :             Real64 OutletBranchRequestNeedAndTurnOn = 0.0;
     902    69003636 :             Real64 OutletBranchRequestNeedIfOn = 0.0;
     903             : 
     904             :             // reference
     905    69003636 :             auto &loop_side(loop.LoopSide(LoopSideCounter));
     906             : 
     907    69003636 :             loop_side.flowRequestNeedIfOn = 0.0;
     908    69003636 :             loop_side.flowRequestNeedAndTurnOn = 0.0;
     909    69003636 :             loop_side.flowRequestFinal = 0.0;
     910    69003636 :             loop_side.hasConstSpeedBranchPumps = false;
     911             : 
     912             :             // Now loop through all the branches on this LoopSide and get flow requests
     913    69003636 :             int const NumBranchesOnThisLoopSide = loop_side.TotalBranches;
     914    69003636 :             int ParallelBranchIndex = 0;
     915   496755139 :             for (int BranchCounter = 1; BranchCounter <= NumBranchesOnThisLoopSide; ++BranchCounter) {
     916   427751503 :                 Real64 ThisBranchFlowRequestNeedAndTurnOn = 0.0;
     917   427751503 :                 Real64 ThisBranchFlowRequestNeedIfOn = 0.0;
     918             : 
     919             :                 // reference
     920   427751503 :                 auto &branch(loop_side.Branch(BranchCounter));
     921             : 
     922   427751503 :                 if (BranchCounter > 1 && BranchCounter < NumBranchesOnThisLoopSide) ++ParallelBranchIndex;
     923             : 
     924   428135431 :                 if (branch.disableOverrideForCSBranchPumping) {
     925      383928 :                     branch.RequestedMassFlow = 0.0;
     926      383928 :                     continue;
     927             :                 }
     928             : 
     929   427367575 :                 int const NumCompsOnThisBranch = branch.TotalComponents;
     930   856768765 :                 for (int CompCounter = 1; CompCounter <= NumCompsOnThisBranch; ++CompCounter) {
     931             : 
     932             :                     // reference
     933   429401190 :                     auto &component(branch.Comp(CompCounter));
     934             : 
     935   429401190 :                     int NodeToCheckRequest = component.NodeNumIn;
     936   429401190 :                     LoopFlowStatus FlowPriorityStatus = component.FlowPriority;
     937             : 
     938             :                     // reference
     939   429401190 :                     auto &node_with_request(state.dataLoopNodes->Node(NodeToCheckRequest));
     940             : 
     941   429401190 :                     if (!DataPlant::PlantEquipmentTypeIsPump[static_cast<int>(component.Type)]) {
     942             : 
     943   394332586 :                         if (FlowPriorityStatus == DataPlant::LoopFlowStatus::Invalid) {
     944             :                             // do nothing
     945   394332586 :                         } else if (FlowPriorityStatus == DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn) {
     946   181870411 :                             ThisBranchFlowRequestNeedAndTurnOn = max(ThisBranchFlowRequestNeedAndTurnOn, node_with_request.MassFlowRateRequest);
     947   181870411 :                             ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, node_with_request.MassFlowRateRequest);
     948   212462175 :                         } else if (FlowPriorityStatus == DataPlant::LoopFlowStatus::NeedyIfLoopOn) {
     949    19879062 :                             ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, node_with_request.MassFlowRateRequest);
     950             :                         } else if (FlowPriorityStatus == DataPlant::LoopFlowStatus::TakesWhatGets) {
     951             :                             // do nothing
     952             :                         }
     953             :                     } else { // handle pumps differently
     954    69150695 :                         if ((BranchCounter == 1) && (LoopSideCounter == DataPlant::LoopSideLocation::Supply) &&
     955    34082091 :                             (loop.CommonPipeType == DataPlant::CommonPipeType::TwoWay)) {
     956             :                             // special primary side flow request for two way common pipe
     957      366366 :                             int const CompIndex = component.CompNum;
     958      366366 :                             switch (component.Type) {
     959             :                             // remove var speed pumps from this case statement if can set MassFlowRateRequest
     960      366366 :                             case DataPlant::PlantEquipmentType::PumpConstantSpeed:
     961             :                             case DataPlant::PlantEquipmentType::PumpVariableSpeed:
     962             :                             case DataPlant::PlantEquipmentType::PumpBankVariableSpeed:
     963      366366 :                                 if (CompIndex > 0) {
     964      366366 :                                     ThisBranchFlowRequestNeedIfOn =
     965      366366 :                                         max(ThisBranchFlowRequestNeedIfOn, state.dataPumps->PumpEquip(CompIndex).MassFlowRateMax);
     966             :                                 }
     967      366366 :                                 break;
     968           0 :                             case DataPlant::PlantEquipmentType::PumpBankConstantSpeed:
     969           0 :                                 if (CompIndex > 0) {
     970           0 :                                     ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn,
     971           0 :                                                                         state.dataPumps->PumpEquip(CompIndex).MassFlowRateMax /
     972           0 :                                                                             state.dataPumps->PumpEquip(CompIndex).NumPumpsInBank);
     973             :                                 }
     974           0 :                                 break;
     975           0 :                             default:
     976           0 :                                 ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, node_with_request.MassFlowRateRequest);
     977           0 :                                 break;
     978      366366 :                             }
     979             : 
     980    68417963 :                         } else if ((BranchCounter == 1) && (LoopSideCounter == DataPlant::LoopSideLocation::Supply) &&
     981    33715725 :                                    (loop.CommonPipeType == DataPlant::CommonPipeType::Single)) {
     982      131740 :                             int const CompIndex = component.CompNum;
     983      131740 :                             switch (component.Type) {
     984             :                             // remove var speed pumps from this case statement if can set MassFlowRateRequest
     985      131740 :                             case DataPlant::PlantEquipmentType::PumpConstantSpeed:
     986             :                             case DataPlant::PlantEquipmentType::PumpVariableSpeed:
     987             :                             case DataPlant::PlantEquipmentType::PumpBankVariableSpeed: {
     988      131740 :                                 if (CompIndex > 0) {
     989      131740 :                                     ThisBranchFlowRequestNeedIfOn =
     990      131740 :                                         max(ThisBranchFlowRequestNeedIfOn, state.dataPumps->PumpEquip(CompIndex).MassFlowRateMax);
     991             :                                 }
     992      131740 :                                 break;
     993             :                             }
     994           0 :                             case DataPlant::PlantEquipmentType::PumpBankConstantSpeed:
     995           0 :                                 if (CompIndex > 0) {
     996           0 :                                     ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn,
     997           0 :                                                                         state.dataPumps->PumpEquip(CompIndex).MassFlowRateMax /
     998           0 :                                                                             state.dataPumps->PumpEquip(CompIndex).NumPumpsInBank);
     999             :                                 }
    1000           0 :                                 break;
    1001           0 :                             default:
    1002           0 :                                 ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, node_with_request.MassFlowRateRequest);
    1003      131740 :                             }
    1004             :                         } else {
    1005    34570498 :                             int const CompIndex = component.CompNum;
    1006    34570498 :                             switch (component.Type) {
    1007     6222026 :                             case DataPlant::PlantEquipmentType::PumpConstantSpeed:
    1008     6222026 :                                 if (CompIndex > 0) {
    1009     6222026 :                                     auto &this_pump(state.dataPumps->PumpEquip(CompIndex));
    1010     6222026 :                                     if (ParallelBranchIndex >= 1) { // branch pump
    1011      277399 :                                         if (branch.max_abs_Comp_MyLoad() > DataHVACGlobals::SmallLoad) {
    1012      129539 :                                             ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax);
    1013      147860 :                                         } else if (loop.CommonPipeType != DataPlant::CommonPipeType::No) { // common pipe and constant branch pumps
    1014       18140 :                                             ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax);
    1015             :                                         }
    1016      277399 :                                         loop_side.hasConstSpeedBranchPumps = true;
    1017      277399 :                                         branch.HasConstantSpeedBranchPump = true;
    1018      277399 :                                         branch.ConstantSpeedBranchMassFlow = this_pump.MassFlowRateMax;
    1019             :                                     } else { // inlet pump
    1020     5944627 :                                         ThisBranchFlowRequestNeedIfOn = max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax);
    1021             :                                     }
    1022             :                                 }
    1023     6222026 :                                 break;
    1024       14592 :                             case DataPlant::PlantEquipmentType::PumpBankConstantSpeed:
    1025       14592 :                                 if (CompIndex > 0) {
    1026       14592 :                                     auto &this_pump(state.dataPumps->PumpEquip(CompIndex));
    1027       14592 :                                     if (ParallelBranchIndex >= 1) { // branch pump
    1028           0 :                                         if (branch.max_abs_Comp_MyLoad() > DataHVACGlobals::SmallLoad) {
    1029           0 :                                             ThisBranchFlowRequestNeedIfOn =
    1030           0 :                                                 max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax / this_pump.NumPumpsInBank);
    1031           0 :                                         } else if (loop.CommonPipeType != DataPlant::CommonPipeType::No) { // common pipe and constant branch pumps
    1032           0 :                                             ThisBranchFlowRequestNeedIfOn =
    1033           0 :                                                 max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax / this_pump.NumPumpsInBank);
    1034             :                                         }
    1035           0 :                                         loop_side.hasConstSpeedBranchPumps = true;
    1036           0 :                                         branch.HasConstantSpeedBranchPump = true;
    1037           0 :                                         branch.ConstantSpeedBranchMassFlow = this_pump.MassFlowRateMax / this_pump.NumPumpsInBank;
    1038             :                                     } else { // inlet pump
    1039       14592 :                                         ThisBranchFlowRequestNeedIfOn =
    1040       14592 :                                             max(ThisBranchFlowRequestNeedIfOn, this_pump.MassFlowRateMax / this_pump.NumPumpsInBank);
    1041             :                                     }
    1042             :                                 }
    1043       14592 :                                 break;
    1044             : 
    1045             :                                 // overwrite here for branch pumps
    1046    28333880 :                             case DataPlant::PlantEquipmentType::PumpVariableSpeed:
    1047             :                             case DataPlant::PlantEquipmentType::PumpBankVariableSpeed:
    1048             :                             case DataPlant::PlantEquipmentType::PumpCondensate:
    1049    28333880 :                                 if (component.CompNum > 0) {
    1050    28333880 :                                     auto &this_pump(state.dataPumps->PumpEquip(component.CompNum));
    1051    28333880 :                                     this_pump.LoopSolverOverwriteFlag = false;
    1052             :                                 }
    1053             :                             default:
    1054    28333880 :                                 break;
    1055             :                             }
    1056             :                         }
    1057             :                     }
    1058             :                 }
    1059   427367575 :                 if (BranchCounter == 1) { // inlet branch
    1060    69003636 :                     InletBranchRequestNeedAndTurnOn = ThisBranchFlowRequestNeedAndTurnOn;
    1061    69003636 :                     InletBranchRequestNeedIfOn = ThisBranchFlowRequestNeedIfOn;
    1062   358363939 :                 } else if (BranchCounter < NumBranchesOnThisLoopSide) { // branchcounter = 1 is already caught
    1063   289681895 :                     ParallelBranchRequestsNeedAndTurnOn += ThisBranchFlowRequestNeedAndTurnOn;
    1064   289681895 :                     ParallelBranchRequestsNeedIfOn += ThisBranchFlowRequestNeedIfOn;
    1065    68682044 :                 } else if (BranchCounter == NumBranchesOnThisLoopSide) { // outlet branch
    1066    68682044 :                     OutletBranchRequestNeedAndTurnOn = ThisBranchFlowRequestNeedAndTurnOn;
    1067    68682044 :                     OutletBranchRequestNeedIfOn = ThisBranchFlowRequestNeedIfOn;
    1068             :                 }
    1069             : 
    1070   427367575 :                 branch.RequestedMassFlow = max(ThisBranchFlowRequestNeedIfOn, ThisBranchFlowRequestNeedAndTurnOn);
    1071             :             }
    1072    69003636 :             loop_side.flowRequestNeedAndTurnOn =
    1073    69003636 :                 max(InletBranchRequestNeedAndTurnOn, ParallelBranchRequestsNeedAndTurnOn, OutletBranchRequestNeedAndTurnOn);
    1074    69003636 :             loop_side.flowRequestNeedIfOn = max(InletBranchRequestNeedIfOn, ParallelBranchRequestsNeedIfOn, OutletBranchRequestNeedIfOn);
    1075             :         }
    1076             : 
    1077    34501818 :         auto &this_loop_side(loop.LoopSide(this->plantLoc.loopSideNum));
    1078    34501818 :         auto &other_loop_side(loop.LoopSide(OtherSide));
    1079             : 
    1080             :         //~ Now that we have calculated each sides different status's requests, process to find final
    1081    34501818 :         if ((this_loop_side.flowRequestNeedAndTurnOn + other_loop_side.flowRequestNeedAndTurnOn) < DataBranchAirLoopPlant::MassFlowTolerance) {
    1082    16258311 :             this_loop_side.flowRequestFinal = 0.0;
    1083    16258311 :             other_loop_side.flowRequestFinal = 0.0;
    1084             :         } else { // some flow is needed and loop should try to run
    1085    18243507 :             this_loop_side.flowRequestFinal = max(this_loop_side.flowRequestNeedAndTurnOn, this_loop_side.flowRequestNeedIfOn);
    1086    18243507 :             other_loop_side.flowRequestFinal = max(other_loop_side.flowRequestNeedAndTurnOn, other_loop_side.flowRequestNeedIfOn);
    1087             :         }
    1088             :         // now store final flow requests on each loop side data structure
    1089    34501818 :         this_loop_side.FlowRequest = this_loop_side.flowRequestFinal;
    1090    34501818 :         other_loop_side.FlowRequest = other_loop_side.flowRequestFinal;
    1091             : 
    1092    34501818 :         if (loop.CommonPipeType == DataPlant::CommonPipeType::No) {
    1093             :             // we may or may not have a pump on this side, but the flow request is the larger of the two side's final
    1094    33970826 :             if ((!this_loop_side.hasConstSpeedBranchPumps) && (!other_loop_side.hasConstSpeedBranchPumps)) {
    1095    33844223 :                 LoopFlow = max(this_loop_side.flowRequestFinal, other_loop_side.flowRequestFinal);
    1096             :             } else { // account for stepped loop flow rates required of branch pumps
    1097             : 
    1098             :                 // rules for setting flow when there are constant speed branch pumps.
    1099             :                 // 1. Check if above routines already selected a loop flow rate based on the constant speed branches, if so then just use it
    1100      126603 :                 if (this_loop_side.hasConstSpeedBranchPumps && (this_loop_side.flowRequestFinal >= other_loop_side.flowRequestFinal)) {
    1101             :                     // okay, just use basic logic
    1102       67063 :                     LoopFlow = max(this_loop_side.flowRequestFinal, other_loop_side.flowRequestFinal);
    1103       59540 :                 } else if (other_loop_side.hasConstSpeedBranchPumps && (this_loop_side.flowRequestFinal <= other_loop_side.flowRequestFinal)) {
    1104             :                     // okay, just use basic logic
    1105       13455 :                     LoopFlow = max(this_loop_side.flowRequestFinal, other_loop_side.flowRequestFinal);
    1106             :                 } else { // not okay, we have a case that will likely need special correcting
    1107             :                     //  2. determine which loop side has the stepped data
    1108       46085 :                     DataPlant::LoopSideLocation LoopSideIndex = DataPlant::LoopSideLocation::Invalid;
    1109       46085 :                     if (this_loop_side.hasConstSpeedBranchPumps && (this_loop_side.flowRequestFinal < other_loop_side.flowRequestFinal)) {
    1110       33461 :                         LoopSideIndex = this->plantLoc.loopSideNum;
    1111       12624 :                     } else if (other_loop_side.hasConstSpeedBranchPumps && (other_loop_side.flowRequestFinal < this_loop_side.flowRequestFinal)) {
    1112       12624 :                         LoopSideIndex = OtherSide;
    1113             :                     }
    1114       46085 :                     auto &loop_side(loop.LoopSide(LoopSideIndex));
    1115             : 
    1116             :                     // 3. step through and find out needed information
    1117             :                     // 3a.  search the loop side with branch pumps and find the steps available with non-zero Myloads
    1118             :                     // 3b.  search the loop side with branch pumps and find the steps available with zero Myloads
    1119             :                     //                    LoadedConstantSpeedBranchFlowRateSteps = 0.0;
    1120       46085 :                     Real64 LoadedConstantSpeedBranchFlowRateSteps_sum = 0.0;
    1121       46085 :                     this_loop_side.noLoadConstantSpeedBranchFlowRateSteps = 0.0;
    1122       46085 :                     Real64 NoLoadConstantSpeedBranchFlowRateSteps_sum = 0.0;
    1123       46085 :                     int ParallelBranchIndex = 0;
    1124       46085 :                     int const NumBranchesOnThisLoopSide = loop_side.TotalBranches;
    1125       46085 :                     auto const &loop_branches(loop_side.Branch);
    1126      276510 :                     for (int BranchCounter = 1; BranchCounter <= NumBranchesOnThisLoopSide; ++BranchCounter) {
    1127      230425 :                         auto const &loop_branch(loop_branches(BranchCounter));
    1128      230425 :                         if (BranchCounter > 1 && BranchCounter < NumBranchesOnThisLoopSide) ++ParallelBranchIndex;
    1129      230425 :                         if (loop_branch.HasConstantSpeedBranchPump) {
    1130       92170 :                             auto const branch_mass_flow(loop_branch.ConstantSpeedBranchMassFlow);
    1131       92170 :                             if (loop_branch.max_abs_Comp_MyLoad() > DataHVACGlobals::SmallLoad) {
    1132       20132 :                                 LoadedConstantSpeedBranchFlowRateSteps_sum += branch_mass_flow;
    1133             :                             } else {
    1134       72038 :                                 this_loop_side.noLoadConstantSpeedBranchFlowRateSteps(ParallelBranchIndex) = branch_mass_flow;
    1135       72038 :                                 NoLoadConstantSpeedBranchFlowRateSteps_sum += branch_mass_flow;
    1136             :                             }
    1137             :                         }
    1138             :                     }
    1139             : 
    1140             :                     // 4. allocate which branches to use,
    1141       46085 :                     Real64 tmpLoopFlow = max(this_loop_side.flowRequestFinal, other_loop_side.flowRequestFinal);
    1142       46085 :                     Real64 MaxBranchPumpLoopSideFlow = LoadedConstantSpeedBranchFlowRateSteps_sum + NoLoadConstantSpeedBranchFlowRateSteps_sum;
    1143       46085 :                     tmpLoopFlow = min(tmpLoopFlow, MaxBranchPumpLoopSideFlow);
    1144             :                     //  4b. first use all the branches with non-zero MyLoad
    1145       46085 :                     if (tmpLoopFlow > LoadedConstantSpeedBranchFlowRateSteps_sum) {
    1146       46085 :                         Real64 AccumFlowSteps = LoadedConstantSpeedBranchFlowRateSteps_sum;
    1147       46085 :                         ParallelBranchIndex = 0;
    1148      138255 :                         for (int BranchCounter = 1; BranchCounter <= NumBranchesOnThisLoopSide; ++BranchCounter) {
    1149      184340 :                             if (BranchCounter > 1 && BranchCounter < NumBranchesOnThisLoopSide) {
    1150       92170 :                                 ++ParallelBranchIndex;
    1151             :                             } else {
    1152       46085 :                                 continue;
    1153             :                             }
    1154       92170 :                             auto const steps(this_loop_side.noLoadConstantSpeedBranchFlowRateSteps(ParallelBranchIndex));
    1155       92170 :                             if (steps > 0.0) { // add in branches with zero MyLoad  in branch input order until satisfied
    1156       72038 :                                 if (tmpLoopFlow > AccumFlowSteps) {
    1157       72038 :                                     if (tmpLoopFlow <= AccumFlowSteps + steps) { // found it set requests and exit
    1158       46085 :                                         tmpLoopFlow = AccumFlowSteps + steps;
    1159       46085 :                                         loop_side.Branch(BranchCounter).RequestedMassFlow = steps;
    1160       46085 :                                         LoopFlow = tmpLoopFlow;
    1161       46085 :                                         break;
    1162             :                                     } else {
    1163       25953 :                                         AccumFlowSteps += steps;
    1164       25953 :                                         loop_side.Branch(BranchCounter).RequestedMassFlow = steps;
    1165             :                                     }
    1166             :                                 }
    1167             :                             }
    1168             :                         }
    1169             :                     }
    1170             :                 }
    1171             :             }
    1172      530992 :         } else if (loop.CommonPipeType == DataPlant::CommonPipeType::TwoWay) {
    1173      390936 :             LoopFlow = this_loop_side.flowRequestFinal;
    1174      140056 :         } else if (loop.CommonPipeType == DataPlant::CommonPipeType::Single) {
    1175      140056 :             LoopFlow = this_loop_side.flowRequestFinal;
    1176             :         }
    1177             : 
    1178             :         // overrides the loop solver flow request to allow loop pump to turn off when not in use
    1179    34501818 :         if (this_loop_side.TotalPumps == 1) {
    1180    17371733 :             if (LoopFlow < DataConvergParams::PlantLowFlowRateToler) { // Update from dataconvergetols...
    1181    42268139 :                 for (int BranchCounter = 1; BranchCounter <= this_loop_side.TotalBranches; ++BranchCounter) {
    1182             :                     // reference
    1183    34284315 :                     auto &branch(this_loop_side.Branch(BranchCounter));
    1184    34284315 :                     int const NumCompsOnThisBranch = branch.TotalComponents;
    1185    68933173 :                     for (int CompCounter = 1; CompCounter <= NumCompsOnThisBranch; ++CompCounter) {
    1186    34648858 :                         auto const &component(branch.Comp(CompCounter));
    1187    34648858 :                         switch (component.Type) {
    1188     6806336 :                         case DataPlant::PlantEquipmentType::PumpVariableSpeed:
    1189             :                         case DataPlant::PlantEquipmentType::PumpBankVariableSpeed:
    1190             :                         case DataPlant::PlantEquipmentType::PumpCondensate:
    1191     6806336 :                             if (component.CompNum > 0) {
    1192     6806336 :                                 auto &this_pump(state.dataPumps->PumpEquip(component.CompNum));
    1193     6806336 :                                 this_pump.LoopSolverOverwriteFlag = true;
    1194             :                             }
    1195             :                         default:
    1196    34648858 :                             break;
    1197             :                         }
    1198             :                     }
    1199             :                 }
    1200             :             }
    1201             :         }
    1202             : 
    1203    34501818 :         return LoopFlow;
    1204             :     }
    1205             : 
    1206    34501818 :     void HalfLoopData::DoFlowAndLoadSolutionPass(EnergyPlusData &state, LoopSideLocation OtherSide, int ThisSideInletNode, bool FirstHVACIteration)
    1207             :     {
    1208             : 
    1209             :         // This is passed in-out deep down into the depths where the load op manager calls EMS and EMS can shut down pumps
    1210    34501818 :         bool LoopShutDownFlag = false;
    1211             : 
    1212             :         // First thing is to setup mass flow request information
    1213    34501818 :         Real64 ThisLoopSideFlowRequest = this->SetupLoopFlowRequest(state, OtherSide);
    1214             : 
    1215             :         // Now we know what the loop would "like" to run at, let's see the pump
    1216             :         // operation range (min/max avail) to see whether it is possible this time around
    1217    34501818 :         Real64 ThisLoopSideFlow = this->DetermineLoopSideFlowRate(state, ThisSideInletNode, ThisLoopSideFlowRequest);
    1218             : 
    1219   248434592 :         for (auto &branch : this->Branch) {
    1220   213932774 :             branch.lastComponentSimulated = 0;
    1221             :         }
    1222             : 
    1223             :         // We also need to establish a baseline "other-side-based" loop demand based on this possible flow rate
    1224    34501818 :         this->InitialDemandToLoopSetPoint = this->CalcOtherSideDemand(state, ThisLoopSideFlow);
    1225    34501818 :         this->UpdatedDemandToLoopSetPoint = this->InitialDemandToLoopSetPoint;
    1226    34501818 :         this->LoadToLoopSetPointThatWasntMet = 0.0;
    1227             : 
    1228             :         // We now have a loop side flow request, along with inlet min/max avails.
    1229             :         // We can now make a first pass through the component simulation, requesting flow as necessary.
    1230             :         // Normal "supply side" components will set a mass flow rate on their outlet node to request flow,
    1231             :         // while "Demand side" components will set a a mass flow request on their inlet node to request flow.
    1232    34501818 :         this->FlowLock = DataPlant::FlowLock::Unlocked;
    1233    34501818 :         this->SimulateAllLoopSideBranches(state, ThisLoopSideFlow, FirstHVACIteration, LoopShutDownFlag);
    1234             : 
    1235             :         // discussion/comments about loop solver/flow resolver interaction
    1236             :         // At this point, the components have been simulated.  They should have either:
    1237             :         //  - logged a massflowrequest
    1238             :         //  - or logged a MassFlowRate
    1239             :         // We need to decide what the components are going to do on FlowLock=0.
    1240             :         // If we want all control here at the solver level, the components just need to
    1241             :         //  log their MassFlowRate on their outlet nodes, or some other mechanism.
    1242             :         // Then the loop solver can scan the branch and get the max, and this will be the requested
    1243             :         //  flow rate for the branch.
    1244             :         // The loop solver will then set this as the branch outlet mass flow rate in preparation
    1245             :         //  for the flow resolver.
    1246             :         // The loop solver may need to do something to the inlet/outlet branch, but I'm not sure yet.
    1247             :         // The following comment block is what I had already thought of, and it may still make sense.
    1248             : 
    1249             :         // Now that all the flow requests have been logged, we need to prepare them for the
    1250             :         //  flow resolver.  This will just take the requests and determine the desired flow
    1251             :         //  request for that branch according to pump placement, pump type, and other component
    1252             :         //  conditions.  In many cases, this will just be to simply take the max request from
    1253             :         //  the branch, which will already be within pumping limits for that flow path.
    1254             :         // We can then call the flow resolver to lock down branch inlet flow rates.
    1255             : 
    1256             :         // The flow resolver takes information such as requested flows and min/max available flows and
    1257             :         //  sets the corrected flow on the inlet to each parallel branch
    1258    34501818 :         this->ResolveParallelFlows(state, ThisLoopSideFlow, FirstHVACIteration);
    1259             : 
    1260             :         // Re-Initialize variables for this next pass
    1261    34501818 :         this->InitialDemandToLoopSetPointSAVED = this->InitialDemandToLoopSetPoint;
    1262    34501818 :         this->CurrentAlterationsToDemand = 0.0;
    1263    34501818 :         this->UpdatedDemandToLoopSetPoint = this->InitialDemandToLoopSetPoint;
    1264             : 
    1265             :         // Now that flow rates have been resolved, we just need to set the flow lock status
    1266             :         //  flag, and resimulate.  During this simulation each component will still use the
    1267             :         //  SetFlowRequest routine, but this routine will also set the outlet flow rate
    1268             :         //  equal to the inlet flow rate, according to flowlock logic.
    1269    34501818 :         this->FlowLock = DataPlant::FlowLock::Locked;
    1270    34501818 :         this->SimulateAllLoopSideBranches(state, ThisLoopSideFlow, FirstHVACIteration, LoopShutDownFlag);
    1271    34501818 :     }
    1272             : 
    1273    34501818 :     void HalfLoopData::ResolveParallelFlows(EnergyPlusData &state,
    1274             :                                             Real64 const ThisLoopSideFlow, // [kg/s]  total flow to be split
    1275             :                                             bool const FirstHVACIteration  // TRUE if First HVAC iteration of Time step
    1276             :     )
    1277             :     {
    1278             : 
    1279             :         // SUBROUTINE INFORMATION:
    1280             :         //       AUTHOR         Brandon Anderson, Dan Fisher
    1281             :         //       DATE WRITTEN   October 1999
    1282             :         //       MODIFIED       May 2005 Sankaranarayanan K P, Rich Liesen
    1283             :         //       RE-ENGINEERED  Sept 2010 Dan Fisher, Brent Griffith for demand side update
    1284             : 
    1285             :         // PURPOSE OF THIS SUBROUTINE:
    1286             :         // This subroutine takes the overall loop side flow and distributes
    1287             :         // it among parallel branches. this is the main implementation of
    1288             :         // flow splitting for plant splitter/mixer
    1289             : 
    1290             :         // METHODOLOGY EMPLOYED:
    1291             :         // Flow through the branches is currently determined by
    1292             :         // the active component on the branch, as well as the
    1293             :         // order of the branches following the splitter.
    1294             :         // SimPlantEquipment is run first, and the active components
    1295             :         // request their flow.  These flows are compared and a simple
    1296             :         // algorithm balances flow in the branches.  The flow in these
    1297             :         // branches is then locked down, via MassFlowRateMaxAvail and MinAvail
    1298             :         // SimPlant Equipment is then run again in order to get correct
    1299             :         // properties.  Finally, Max/MinAvail are reset for the next time step.
    1300             : 
    1301             :         // Using/Aliasing
    1302             : 
    1303             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1304    34501818 :         int constexpr LoopSideSingleBranch(1); // For readability
    1305             : 
    1306             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1307             :         int NumActiveBranches;        // Active branch counter
    1308             :         Real64 ActiveFlowRate;        // The flow available when cycling through branches
    1309             :         Real64 PassiveFlowRate;       // The flow available when cycling through branches
    1310             :         Real64 FracFlow;              // The flow available when cycling through branches
    1311             :         Real64 ThisBranchRequestFrac; // The request ratio
    1312             :         Real64 totalMax;              // The flow available when cycling through branches
    1313             :         Real64 FlowRemaining;         // The flow available when cycling through branches
    1314             :         int OutletNum;                // Splitter outlet
    1315             :         int MixerBranchOut;
    1316             :         int SplitterBranchIn;  // As the name implies
    1317             :         int SplitterBranchOut; // As the name implies
    1318             :         int LastNodeOnBranch;  // intermediate value used for better readabilty
    1319             :         int FirstNodeOnBranch; // intermediate value used for better readabilty
    1320             :         int BranchNum;         // intermediate value used for better readabilty
    1321             :         int iBranch;           // DO loop counter for cycling through branches
    1322             :         int NumSplitOutlets;   // As the name implies
    1323             :         Real64 BranchFlowReq;
    1324             :         Real64 BranchMinAvail;
    1325             :         Real64 BranchMaxAvail;
    1326             :         Real64 ParallelBranchMaxAvail;
    1327             :         Real64 ParallelBranchMinAvail;
    1328             :         Real64 TotParallelBranchFlowReq;
    1329             :         int FirstNodeOnBranchIn;
    1330             :         int FirstNodeOnBranchOut;
    1331             :         Real64 StartingFlowRate;
    1332             :         Real64 ThisBranchRequest;
    1333             :         int CompCounter;
    1334             :         int CompInletNode;
    1335             :         int CompOutletNode;
    1336             : 
    1337             :         // If there is no splitter then there is no continuity to enforce.
    1338    34501818 :         if (!this->Splitter.Exists) {
    1339             : 
    1340             :             // If there's only one branch, then RETURN
    1341      159410 :             if (this->TotalBranches == 1) {
    1342             :                 // The branch should just try to meet the request previously calculated.  This should be good,
    1343             :                 // just need to make sure that during FlowUnlocked, no one constrained Min/Max farther.
    1344             :                 // This would have been propagated down the branch, so we can check the outlet node min/max avail for this.
    1345      159410 :                 auto &this_single_branch(this->Branch(LoopSideSingleBranch));
    1346      159410 :                 LastNodeOnBranch = this_single_branch.NodeNumOut;
    1347      159410 :                 FirstNodeOnBranch = this_single_branch.NodeNumIn;
    1348      159410 :                 BranchMinAvail = state.dataLoopNodes->Node(LastNodeOnBranch).MassFlowRateMinAvail;
    1349      159410 :                 BranchMaxAvail = state.dataLoopNodes->Node(LastNodeOnBranch).MassFlowRateMaxAvail;
    1350      159410 :                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = min(max(ThisLoopSideFlow, BranchMinAvail), BranchMaxAvail);
    1351             :                 // now with flow locked, this single branch will just ran at the specified flow rate, so we are done
    1352    30394338 :                 return;
    1353             :             } else {
    1354           0 :                 ShowSevereError(state, "Plant topology problem on \"" + this->loopSideDescription + "\"");
    1355           0 :                 ShowContinueError(state, "There are multiple branches, yet no splitter.  This is an invalid configuration.");
    1356           0 :                 ShowContinueError(state, "Add a set of connectors, use put components on a single branch.");
    1357           0 :                 ShowFatalError(state, "Invalid plant topology causes program termination.");
    1358           0 :                 return;
    1359             :             }
    1360             :         }
    1361             : 
    1362             :         // If a splitter/mixer combination exist on the loop
    1363    34342408 :         if (this->Splitter.Exists && this->Mixer.Exists) {
    1364             : 
    1365             :             // Zero out local variables
    1366    34342408 :             TotParallelBranchFlowReq = 0.0;
    1367    34342408 :             NumSplitOutlets = this->Splitter.TotalOutletNodes;
    1368    34342408 :             if (NumSplitOutlets < 1) {
    1369           0 :                 ShowSevereError(state, "Plant topology problem on \"" + this->loopSideDescription + "\"");
    1370           0 :                 ShowContinueError(state, "Diagnostic error in PlantLoopSolver::ResolveParallelFlows.");
    1371           0 :                 ShowContinueError(state, "Splitter improperly specified, no splitter outlets.");
    1372           0 :                 ShowFatalError(state, "Invalid plant topology causes program termination.");
    1373             :             }
    1374             : 
    1375    34342408 :             NumActiveBranches = 0;
    1376    34342408 :             ParallelBranchMaxAvail = 0.0;
    1377    34342408 :             ParallelBranchMinAvail = 0.0;
    1378   179430956 :             for (iBranch = 1; iBranch <= NumSplitOutlets; ++iBranch) {
    1379             : 
    1380   145088548 :                 BranchNum = this->Splitter.BranchNumOut(iBranch);
    1381   145088548 :                 auto &this_branch(this->Branch(BranchNum));
    1382   145088548 :                 SplitterBranchOut = this->Splitter.BranchNumOut(iBranch);
    1383   145088548 :                 auto &this_splitter_outlet_branch(this->Branch(SplitterBranchOut));
    1384   145088548 :                 LastNodeOnBranch = this_branch.NodeNumOut;
    1385   145088548 :                 FirstNodeOnBranch = this_branch.NodeNumIn;
    1386   145088548 :                 BranchFlowReq = this_branch.DetermineBranchFlowRequest(state);
    1387   145088548 :                 this_branch.RequestedMassFlow = BranchFlowReq; // store this for later use in logic for remaining flow allocations
    1388             :                 // now, if we are have branch pumps, here is the situation:
    1389             :                 // constant speed pumps lock in a flow request on the inlet node
    1390             :                 // variable speed pumps which have other components on the branch do not log a request themselves
    1391             :                 // the DetermineBranchFlowRequest routine only looks at the branch inlet node
    1392             :                 // for variable speed branch pumps then, this won't work because the branch will be requesting zero
    1393             :                 // so let's adjust for this here to make sure these branches get good representation
    1394             :                 // This comment above is not true, for series active branches, DetermineBranchFlowRequest does scan down the branch's
    1395             :                 // components already, no need to loop over components
    1396   145088548 :                 BranchMinAvail = state.dataLoopNodes->Node(LastNodeOnBranch).MassFlowRateMinAvail;
    1397   145088548 :                 BranchMaxAvail = state.dataLoopNodes->Node(LastNodeOnBranch).MassFlowRateMaxAvail;
    1398             :                 //            !sum the branch flow requests to a total parallel branch flow request
    1399   145088548 :                 bool activeBranch = this_splitter_outlet_branch.controlType == DataBranchAirLoopPlant::ControlType::Active;
    1400   145088548 :                 bool isSeriesActiveAndRequesting =
    1401   145088548 :                     (this_splitter_outlet_branch.controlType == DataBranchAirLoopPlant::ControlType::SeriesActive) && (BranchFlowReq > 0.0);
    1402   145088548 :                 if (activeBranch || isSeriesActiveAndRequesting) { // revised logic for series active
    1403   111441085 :                     TotParallelBranchFlowReq += BranchFlowReq;
    1404   111441085 :                     ++NumActiveBranches;
    1405             :                 }
    1406   145088548 :                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = BranchFlowReq;
    1407   145088548 :                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMinAvail = BranchMinAvail;
    1408   145088548 :                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail = BranchMaxAvail;
    1409   145088548 :                 ParallelBranchMaxAvail += BranchMaxAvail;
    1410   145088548 :                 ParallelBranchMinAvail += BranchMinAvail;
    1411             :             }
    1412             :             //            ! Find branch number and flow rates at splitter inlet
    1413    34342408 :             SplitterBranchIn = this->Splitter.BranchNumIn;
    1414    34342408 :             LastNodeOnBranch = this->Branch(SplitterBranchIn).NodeNumOut;
    1415    34342408 :             FirstNodeOnBranchIn = this->Branch(SplitterBranchIn).NodeNumIn;
    1416             :             //            ! Find branch number and flow rates at mixer outlet
    1417    34342408 :             MixerBranchOut = this->Mixer.BranchNumOut;
    1418    34342408 :             LastNodeOnBranch = this->Branch(MixerBranchOut).NodeNumOut;
    1419    34342408 :             FirstNodeOnBranchOut = this->Branch(MixerBranchOut).NodeNumIn;
    1420             : 
    1421    34342408 :             auto &first_branch_inlet_node(state.dataLoopNodes->Node(FirstNodeOnBranchIn));
    1422    34342408 :             auto &last_branch_inlet_node(state.dataLoopNodes->Node(FirstNodeOnBranchOut));
    1423             : 
    1424             :             // Reset branch inlet node flow rates for the first and last branch on loop
    1425    34342408 :             first_branch_inlet_node.MassFlowRate = ThisLoopSideFlow;
    1426    34342408 :             last_branch_inlet_node.MassFlowRate = ThisLoopSideFlow;
    1427             : 
    1428             :             // Reset branch inlet node Min/MaxAvails for the first and last branch on loop
    1429    34342408 :             first_branch_inlet_node.MassFlowRateMaxAvail = min(first_branch_inlet_node.MassFlowRateMaxAvail, ParallelBranchMaxAvail);
    1430    34342408 :             first_branch_inlet_node.MassFlowRateMaxAvail =
    1431    34342408 :                 min(first_branch_inlet_node.MassFlowRateMaxAvail, last_branch_inlet_node.MassFlowRateMaxAvail);
    1432    34342408 :             first_branch_inlet_node.MassFlowRateMinAvail = max(first_branch_inlet_node.MassFlowRateMinAvail, ParallelBranchMinAvail);
    1433    34342408 :             first_branch_inlet_node.MassFlowRateMinAvail =
    1434    34342408 :                 max(first_branch_inlet_node.MassFlowRateMinAvail, last_branch_inlet_node.MassFlowRateMinAvail);
    1435    34342408 :             last_branch_inlet_node.MassFlowRateMinAvail = first_branch_inlet_node.MassFlowRateMinAvail;
    1436    34342408 :             last_branch_inlet_node.MassFlowRateMaxAvail = first_branch_inlet_node.MassFlowRateMaxAvail;
    1437             : 
    1438             :             // Initialize the remaining flow variable
    1439    34342408 :             FlowRemaining = ThisLoopSideFlow;
    1440             : 
    1441             :             // Initialize flow on passive, bypass and uncontrolled parallel branches to zero.  For these branches
    1442             :             // MinAvail is not enforced
    1443   179430956 :             for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1444   145088548 :                 SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1445   145088548 :                 FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1446   179113841 :                 if (this->Branch(SplitterBranchOut).controlType != DataBranchAirLoopPlant::ControlType::Active &&
    1447    34025293 :                     this->Branch(SplitterBranchOut).controlType != DataBranchAirLoopPlant::ControlType::SeriesActive) {
    1448    33275151 :                     state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = 0.0;
    1449    66550302 :                     this->PushBranchFlowCharacteristics(
    1450    33275151 :                         state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1451             :                 }
    1452             :             }
    1453             : 
    1454             :             // IF SUFFICIENT FLOW TO MEET ALL PARALLEL BRANCH FLOW REQUESTS
    1455    34342408 :             if (FlowRemaining < DataBranchAirLoopPlant::MassFlowTolerance) { // no flow available at all for splitter
    1456    80648380 :                 for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1457    64465174 :                     SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1458   129318005 :                     for (CompCounter = 1; CompCounter <= this->Branch(SplitterBranchOut).TotalComponents; ++CompCounter) {
    1459             : 
    1460    64852831 :                         FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1461    64852831 :                         CompInletNode = this->Branch(SplitterBranchOut).Comp(CompCounter).NodeNumIn;
    1462    64852831 :                         CompOutletNode = this->Branch(SplitterBranchOut).Comp(CompCounter).NodeNumOut;
    1463    64852831 :                         state.dataLoopNodes->Node(CompInletNode).MassFlowRate = 0.0;
    1464    64852831 :                         state.dataLoopNodes->Node(CompInletNode).MassFlowRateMaxAvail = 0.0;
    1465    64852831 :                         state.dataLoopNodes->Node(CompOutletNode).MassFlowRate = 0.0;
    1466    64852831 :                         state.dataLoopNodes->Node(CompOutletNode).MassFlowRateMaxAvail = 0.0;
    1467             :                     }
    1468             :                 }
    1469    16183206 :                 return;
    1470    18159202 :             } else if (FlowRemaining >= TotParallelBranchFlowReq) {
    1471             : 
    1472             :                 // 1) Satisfy flow demand of ACTIVE splitter outlet branches
    1473    77294099 :                 for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1474    63401787 :                     SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1475    63401787 :                     FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1476    77163150 :                     if (this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Active ||
    1477    13761363 :                         this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::SeriesActive) {
    1478             :                         // branch flow is min of requested flow and remaining flow
    1479    49914704 :                         state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate =
    1480    49914704 :                             min(state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FlowRemaining);
    1481    49914704 :                         if (state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance)
    1482    11060970 :                             state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = 0.0;
    1483    99829408 :                         this->PushBranchFlowCharacteristics(
    1484    49914704 :                             state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1485    49914704 :                         FlowRemaining -= state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1486    49914704 :                         if (FlowRemaining < DataBranchAirLoopPlant::MassFlowTolerance) FlowRemaining = 0.0;
    1487             :                     }
    1488             :                 }
    1489             :                 // IF the active branches take the entire loop flow, return
    1490    13892312 :                 if (FlowRemaining == 0.0) return;
    1491             : 
    1492             :                 // 2) Distribute remaining flow to PASSIVE branches
    1493     3891633 :                 totalMax = 0.0;
    1494    23260575 :                 for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1495    19368942 :                     SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1496    19368942 :                     FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1497    19368942 :                     if (this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Passive) {
    1498             :                         // Calculate the total max available
    1499           0 :                         totalMax += state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail;
    1500             :                     }
    1501             :                 }
    1502             : 
    1503     3891633 :                 if (totalMax > 0) {
    1504           0 :                     for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1505           0 :                         SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1506           0 :                         FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1507           0 :                         if (this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Passive) {
    1508           0 :                             FracFlow = FlowRemaining / totalMax;
    1509           0 :                             if (FracFlow <= 1.0) { // the passive branches will take all the flow
    1510           0 :                                 PassiveFlowRate = FracFlow * state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail;
    1511             :                                 // Check against FlowRemaining
    1512           0 :                                 PassiveFlowRate = min(FlowRemaining, PassiveFlowRate);
    1513             :                                 // Allow FlowRequest to be increased to meet minimum on branch
    1514           0 :                                 PassiveFlowRate = max(PassiveFlowRate, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMinAvail);
    1515           0 :                                 FlowRemaining = max((FlowRemaining - PassiveFlowRate), 0.0);
    1516           0 :                                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = PassiveFlowRate;
    1517             :                             } else { // Each Branch receives maximum flow and BYPASS must be used
    1518           0 :                                 state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate =
    1519           0 :                                     min(state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail, FlowRemaining);
    1520           0 :                                 FlowRemaining -= state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1521             :                             }
    1522           0 :                             this->PushBranchFlowCharacteristics(
    1523           0 :                                 state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1524             :                         }
    1525             :                     }
    1526             :                 } // totalMax <=0 and flow should be assigned to active branches
    1527             :                 // IF the passive branches take the remaining loop flow, return
    1528     3891633 :                 if (FlowRemaining == 0.0) return;
    1529             : 
    1530             :                 // 3) Distribute remaining flow to the BYPASS
    1531    23260575 :                 for (OutletNum = 1; OutletNum <= this->Splitter.TotalOutletNodes; ++OutletNum) {
    1532    19368942 :                     SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1533    19368942 :                     FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1534    19368942 :                     if (this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Bypass) {
    1535     3752411 :                         state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate =
    1536     3752411 :                             min(FlowRemaining, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail);
    1537     7504822 :                         this->PushBranchFlowCharacteristics(
    1538     3752411 :                             state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1539     3752411 :                         FlowRemaining -= state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1540             :                     }
    1541             :                 }
    1542             :                 // IF the bypass take the remaining loop flow, return
    1543     3891633 :                 if (FlowRemaining == 0.0) return;
    1544             : 
    1545             :                 // 4) If PASSIVE branches and BYPASS are at max and there's still flow, distribute remaining flow to ACTIVE branches but only those
    1546             :                 // that had a non-zero flow request. Try to leave branches off that wanted to be off.
    1547      146015 :                 if (NumActiveBranches > 0) {
    1548      145993 :                     ActiveFlowRate = FlowRemaining / NumActiveBranches; // denominator now only includes active branches that wanted to be "on"
    1549      211030 :                     for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1550      195909 :                         SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1551      195909 :                         FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1552      195909 :                         bool branchIsActive = this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Active;
    1553             :                         bool branchIsSeriesActiveAndRequesting =
    1554      198656 :                             this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::SeriesActive &&
    1555      198656 :                             this->Branch(SplitterBranchOut).RequestedMassFlow > 0.0;
    1556      195909 :                         if (branchIsActive || branchIsSeriesActiveAndRequesting) { // only series active branches that want to be "on"
    1557             :                             // check Remaining flow (should be correct!)
    1558      194550 :                             ActiveFlowRate = min(ActiveFlowRate, FlowRemaining);
    1559             :                             // set the flow rate to the MIN((MassFlowRate+AvtiveFlowRate), MaxAvail)
    1560      194550 :                             StartingFlowRate = state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1561      194550 :                             state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate =
    1562      194550 :                                 min((state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate + ActiveFlowRate),
    1563      194550 :                                     state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail);
    1564      389100 :                             this->PushBranchFlowCharacteristics(
    1565      194550 :                                 state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1566             :                             // adjust the remaining flow
    1567      194550 :                             FlowRemaining -= (state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate - StartingFlowRate);
    1568             :                         }
    1569      195909 :                         if (FlowRemaining == 0) break;
    1570             :                     }
    1571             :                     // IF the active branches take the remaining loop flow, return
    1572      145993 :                     if (FlowRemaining == 0.0) return;
    1573             : 
    1574             :                     // 5)  Step 4) could have left ACTIVE branches < MaxAvail.  Check to makes sure all ACTIVE branches are at MaxAvail
    1575       57663 :                     for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1576       42542 :                         SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1577       42542 :                         FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1578       45740 :                         if (this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::Active ||
    1579        3198 :                             this->Branch(SplitterBranchOut).controlType == DataBranchAirLoopPlant::ControlType::SeriesActive) {
    1580       42079 :                             StartingFlowRate = state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1581       42079 :                             ActiveFlowRate =
    1582       42079 :                                 min(FlowRemaining, (state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRateMaxAvail - StartingFlowRate));
    1583       42079 :                             FlowRemaining -= ActiveFlowRate;
    1584       42079 :                             state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = StartingFlowRate + ActiveFlowRate;
    1585       84158 :                             this->PushBranchFlowCharacteristics(
    1586       42079 :                                 state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1587             :                         }
    1588             :                     }
    1589             :                 }
    1590             :                 // IF the active branches take the remaining loop flow, return
    1591       15143 :                 if (FlowRemaining == 0.0) return;
    1592             : 
    1593             :                 // 6) Adjust Inlet branch and outlet branch flow rates to match parallel branch rate
    1594        7953 :                 TotParallelBranchFlowReq = 0.0;
    1595       22582 :                 for (iBranch = 1; iBranch <= NumSplitOutlets; ++iBranch) {
    1596       14629 :                     BranchNum = this->Splitter.BranchNumOut(iBranch);
    1597       14629 :                     FirstNodeOnBranch = this->Branch(BranchNum).NodeNumIn;
    1598             :                     // calculate parallel branch flow rate
    1599       14629 :                     TotParallelBranchFlowReq += state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1600             :                 }
    1601             :                 // Reset the flow on the splitter inlet branch
    1602        7953 :                 SplitterBranchIn = this->Splitter.BranchNumIn;
    1603        7953 :                 FirstNodeOnBranchIn = this->Branch(SplitterBranchIn).NodeNumIn;
    1604        7953 :                 state.dataLoopNodes->Node(FirstNodeOnBranchIn).MassFlowRate = TotParallelBranchFlowReq;
    1605       15906 :                 this->PushBranchFlowCharacteristics(
    1606        7953 :                     state, SplitterBranchIn, state.dataLoopNodes->Node(FirstNodeOnBranchIn).MassFlowRate, FirstHVACIteration);
    1607             :                 // Reset the flow on the Mixer outlet branch
    1608        7953 :                 MixerBranchOut = this->Mixer.BranchNumOut;
    1609        7953 :                 FirstNodeOnBranchOut = this->Branch(MixerBranchOut).NodeNumIn;
    1610        7953 :                 state.dataLoopNodes->Node(FirstNodeOnBranchOut).MassFlowRate = TotParallelBranchFlowReq;
    1611       15906 :                 this->PushBranchFlowCharacteristics(
    1612        7953 :                     state, MixerBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranchOut).MassFlowRate, FirstHVACIteration);
    1613        7953 :                 return;
    1614             : 
    1615             :                 // IF INSUFFICIENT FLOW TO MEET ALL PARALLEL BRANCH FLOW REQUESTS
    1616     4266890 :             } else if (FlowRemaining < TotParallelBranchFlowReq) {
    1617             : 
    1618             :                 // 1) apportion flow based on requested fraction of total
    1619    21488477 :                 for (OutletNum = 1; OutletNum <= NumSplitOutlets; ++OutletNum) {
    1620             : 
    1621    17221587 :                     SplitterBranchOut = this->Splitter.BranchNumOut(OutletNum);
    1622    17221587 :                     ThisBranchRequest = this->Branch(SplitterBranchOut).DetermineBranchFlowRequest(state);
    1623    17221587 :                     FirstNodeOnBranch = this->Branch(SplitterBranchOut).NodeNumIn;
    1624    17221587 :                     auto &this_splitter_outlet_branch(this->Branch(SplitterBranchOut));
    1625             : 
    1626    21333656 :                     if ((this_splitter_outlet_branch.controlType == DataBranchAirLoopPlant::ControlType::Active) ||
    1627     4112069 :                         (this_splitter_outlet_branch.controlType == DataBranchAirLoopPlant::ControlType::SeriesActive)) {
    1628             : 
    1629             :                         // since we are calculating this fraction based on the total parallel request calculated above, we must mimic the logic to
    1630             :                         // make sure the math works every time that means we must make the variable speed pump correction here as well.
    1631    26592887 :                         for (CompCounter = 1; CompCounter <= this_splitter_outlet_branch.TotalComponents; ++CompCounter) {
    1632             : 
    1633    13358752 :                             auto &this_comp(this_splitter_outlet_branch.Comp(CompCounter));
    1634             : 
    1635             :                             // if this isn't a variable speed pump then just keep cycling
    1636    26715910 :                             if ((this_comp.Type != PlantEquipmentType::PumpVariableSpeed) &&
    1637    13357158 :                                 (this_comp.Type != PlantEquipmentType::PumpBankVariableSpeed)) {
    1638    13357158 :                                 continue;
    1639             :                             }
    1640             : 
    1641        1594 :                             CompInletNode = this_comp.NodeNumIn;
    1642        1594 :                             ThisBranchRequest = max(ThisBranchRequest, state.dataLoopNodes->Node(CompInletNode).MassFlowRateRequest);
    1643             :                         }
    1644             : 
    1645    13234135 :                         ThisBranchRequestFrac = ThisBranchRequest / TotParallelBranchFlowReq;
    1646             :                         //    FracFlow = state.dataLoopNodes->Node(FirstNodeOnBranch)%MassFlowRate/TotParallelBranchFlowReq
    1647             :                         //    state.dataLoopNodes->Node(FirstNodeOnBranch)%MassFlowRate = MIN((FracFlow *
    1648             :                         //    state.dataLoopNodes->Node(FirstNodeOnBranch)%MassFlowRate),FlowRemaining)
    1649    13234135 :                         state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate = ThisBranchRequestFrac * ThisLoopSideFlow;
    1650    26468270 :                         this->PushBranchFlowCharacteristics(
    1651    13234135 :                             state, SplitterBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate, FirstHVACIteration);
    1652    13234135 :                         FlowRemaining -= state.dataLoopNodes->Node(FirstNodeOnBranch).MassFlowRate;
    1653             :                     }
    1654             :                 }
    1655             : 
    1656             :                 // 1b) check if flow all apportioned
    1657     4266890 :                 if (FlowRemaining > DataBranchAirLoopPlant::MassFlowTolerance) {
    1658             :                     // Call fatal diagnostic error. !The math should work out!
    1659           0 :                     ShowSevereError(state, "ResolveParallelFlows: Dev note, failed to redistribute restricted flow");
    1660           0 :                     ShowContinueErrorTimeStamp(state, "");
    1661           0 :                     ShowContinueError(state, format("Loop side flow = {:.8R} (kg/s)", ThisLoopSideFlow));
    1662           0 :                     ShowContinueError(state, format("Flow Remaining = {:.8R} (kg/s)", FlowRemaining));
    1663           0 :                     ShowContinueError(state, format("Parallel Branch requests  = {:.8R} (kg/s)", TotParallelBranchFlowReq));
    1664             :                 }
    1665             : 
    1666             :                 // 2)  ! Reset the flow on the Mixer outlet branch
    1667     4266890 :                 MixerBranchOut = this->Mixer.BranchNumOut;
    1668     4266890 :                 FirstNodeOnBranchOut = this->Branch(MixerBranchOut).NodeNumIn;
    1669     4266890 :                 state.dataLoopNodes->Node(FirstNodeOnBranchOut).MassFlowRate = TotParallelBranchFlowReq;
    1670     8533780 :                 this->PushBranchFlowCharacteristics(
    1671     4266890 :                     state, MixerBranchOut, state.dataLoopNodes->Node(FirstNodeOnBranchOut).MassFlowRate, FirstHVACIteration);
    1672             : 
    1673             :             } // Total flow requested >= or < Total parallel request
    1674             : 
    1675             :         } // Splitter/Mixer exists
    1676             :     }
    1677             : 
    1678   206373268 :     void HalfLoopData::SimulateLoopSideBranchGroup(EnergyPlusData &state,
    1679             :                                                    int const FirstBranchNum,
    1680             :                                                    int const LastBranchNum,
    1681             :                                                    Real64 FlowRequest,
    1682             :                                                    bool const FirstHVACIteration,
    1683             :                                                    bool &LoopShutDownFlag)
    1684             :     {
    1685             : 
    1686             :         // SUBROUTINE INFORMATION:
    1687             :         //       AUTHOR         Edwin Lee
    1688             :         //       DATE WRITTEN   July 2010
    1689             :         //       MODIFIED       na
    1690             :         //       RE-ENGINEERED  na
    1691             : 
    1692             :         // PURPOSE OF THIS SUBROUTINE:
    1693             :         // This routine will manage the component simulation on a single set of parallel branches
    1694             :         // This routine also reverts to a single branch simulation if there isn't a set of parallel branches
    1695             : 
    1696             :         // METHODOLOGY EMPLOYED:
    1697             :         // Loop through all components, and simulate first the non-load range based on each branch.
    1698             :         // When a load-range based (LRB) is encountered, the simulation moves to the next branch to do non-LRB components.
    1699             :         // When all paths are exhausted the simulation begins simulating LRB components.  Before each comp, the load distribution
    1700             :         //  engine is called to handle the load distribution for this current pass.  If load is successfully distributed, this is
    1701             :         //  flagged, and not called again.  If load is not distributed (i.e. this component isn't ON right now), then the
    1702             :         //  load distribution engine will be called again before the next component.
    1703             :         // After all load distribution is done and those components are complete, the simulation moves back to do any
    1704             :         //  remaining components that may be downstream.
    1705             : 
    1706             :         //~ Flags
    1707             :         bool LoadDistributionWasPerformed;
    1708             : 
    1709             :         //~ General variables
    1710             :         Real64 LoadToLoopSetPoint;
    1711   206373268 :         PlantLocation PumpLocation;
    1712   206373268 :         LoadToLoopSetPoint = 0.0;
    1713             : 
    1714             :         // We now know what plant simulation region is available to us, let's simulate this group
    1715   206373268 :         bool EncounteredLRBObjDuringPass1(false);
    1716   634238816 :         for (int BranchCounter = FirstBranchNum; BranchCounter <= LastBranchNum; ++BranchCounter) {
    1717   427865548 :             auto &branch(this->Branch(BranchCounter));
    1718             : 
    1719             :             //~ Always start from the last component we did the last time around + 1 and
    1720             :             //~  try to make it all the way to the end of the loop
    1721   427865548 :             int const StartingComponent = branch.lastComponentSimulated + 1;
    1722   427865548 :             int const EndingComponent = branch.TotalComponents;
    1723   819774700 :             for (int CompCounter = StartingComponent; CompCounter <= EndingComponent; ++CompCounter) {
    1724             : 
    1725   429695648 :                 auto &this_comp(branch.Comp(CompCounter));
    1726   429695648 :                 PlantLocation this_plantLoc = {this->plantLoc.loopNum, this->plantLoc.loopSideNum, BranchCounter, CompCounter};
    1727   429695648 :                 auto const CurOpSchemeType(this_comp.CurOpSchemeType);
    1728             : 
    1729   429695648 :                 switch (CurOpSchemeType) {
    1730           0 :                 case DataPlant::OpScheme::WSEcon: //~ coils
    1731           0 :                     this_comp.MyLoad = UpdatedDemandToLoopSetPoint;
    1732           0 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1733           0 :                     break;
    1734    35455954 :                 case DataPlant::OpScheme::Pump: //~ pump
    1735    35455954 :                     if (this->BranchPumpsExist) {
    1736      712488 :                         SimulateSinglePump(state, this_comp.location, branch.RequestedMassFlow);
    1737             :                     } else {
    1738    34743466 :                         SimulateSinglePump(state, this_comp.location, FlowRequest);
    1739             :                     }
    1740    35455954 :                     break;
    1741     1168724 :                 case DataPlant::OpScheme::CompSetPtBased:
    1742     1168724 :                     PlantCondLoopOperation::ManagePlantLoadDistribution(state,
    1743             :                                                                         this_plantLoc,
    1744             :                                                                         LoadToLoopSetPoint,
    1745             :                                                                         LoadToLoopSetPointThatWasntMet,
    1746             :                                                                         FirstHVACIteration,
    1747             :                                                                         LoopShutDownFlag,
    1748             :                                                                         LoadDistributionWasPerformed);
    1749     1168724 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1750     1168724 :                     break;
    1751      322816 :                 case DataPlant::OpScheme::EMS:
    1752      322816 :                     if (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
    1753      322816 :                         int const curCompOpSchemePtr = this_comp.CurCompLevelOpNum;
    1754      322816 :                         int const OpSchemePtr = this_comp.OpScheme(curCompOpSchemePtr).OpSchemePtr;
    1755      322816 :                         state.dataPlnt->PlantLoop(this->plantLoc.loopNum).OpScheme(OpSchemePtr).EMSIntVarLoopDemandRate = InitialDemandToLoopSetPoint;
    1756             :                     }
    1757      322816 :                     PlantCondLoopOperation::ManagePlantLoadDistribution(state,
    1758             :                                                                         this_plantLoc,
    1759             :                                                                         UpdatedDemandToLoopSetPoint,
    1760             :                                                                         LoadToLoopSetPointThatWasntMet,
    1761             :                                                                         FirstHVACIteration,
    1762             :                                                                         LoopShutDownFlag,
    1763             :                                                                         LoadDistributionWasPerformed);
    1764      322816 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1765      322816 :                     break;
    1766    37786496 :                 case OpScheme::WetBulbRB:
    1767             :                 case OpScheme::DryBulbRB:
    1768             :                 case OpScheme::DewPointRB:
    1769             :                 case OpScheme::RelHumRB:
    1770             :                 case OpScheme::DryBulbTDB:
    1771             :                 case OpScheme::WetBulbTDB:
    1772             :                 case OpScheme::DewPointTDB:
    1773             :                 case OpScheme::HeatingRB:
    1774             :                 case OpScheme::CoolingRB: { //~ load range based
    1775    37786496 :                     EncounteredLRBObjDuringPass1 = true;
    1776    75572992 :                     goto components_end; // don't do any more components on this branch
    1777             :                     break;
    1778             :                 }
    1779   354961658 :                 default: // demand, etc.
    1780   354961658 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1781             :                 }
    1782             : 
    1783             :                 // Update loop demand as needed for changes this component may have made
    1784   391909152 :                 this->UpdateAnyLoopDemandAlterations(state, BranchCounter, CompCounter);
    1785             : 
    1786             :                 //~ If we didn't EXIT early, we must have simulated, so update array
    1787   391909152 :                 branch.lastComponentSimulated = CompCounter;
    1788             : 
    1789             :             } //~ CompCounter
    1790   817944600 :         components_end:;
    1791             : 
    1792   427865548 :             if (this->FlowLock == DataPlant::FlowLock::Locked) {
    1793   213932774 :                 PlantPressureSystem::SimPressureDropSystem(
    1794             :                     state, this->plantLoc.loopNum, FirstHVACIteration, DataPlant::PressureCall::Calc, this->plantLoc.loopSideNum, BranchCounter);
    1795             :             }
    1796             : 
    1797             :         } //~ BranchCounter
    1798             : 
    1799             :         // So now we have made one pass through all of the available components on these branches, skipping load based
    1800             :         // If we didn't encounter any load based objects during the first pass, then we must be done!
    1801   412746536 :         if (!EncounteredLRBObjDuringPass1) return;
    1802             : 
    1803             :         // If we have load based now, we should go ahead and distribute the load
    1804             :         // If not then this branch group is done, since flow path validation was previously done
    1805    33068324 :         LoadToLoopSetPoint = UpdatedDemandToLoopSetPoint;
    1806    33068324 :         LoadDistributionWasPerformed = false;
    1807             : 
    1808             :         // The way the load distribution is set up, I think I should call this for every load range based component
    1809             :         //  encountered until distribution is actually performed.  If we don't call for each component then we may
    1810             :         //  call for a component that is not on the current equip list and then nothing would come on.
    1811    33068324 :         bool EncounteredNonLBObjDuringPass2(false);
    1812   105706362 :         for (int BranchCounter = FirstBranchNum; BranchCounter <= LastBranchNum; ++BranchCounter) {
    1813    72638038 :             auto &branch(this->Branch(BranchCounter));
    1814             : 
    1815             :             //~ Always start from the last component we did the last time around + 1 and
    1816             :             //~  try to make it all the way to the end of the loop
    1817    72638038 :             int const StartingComponent = branch.lastComponentSimulated + 1;
    1818    72638038 :             int const EndingComponent = branch.TotalComponents;
    1819   111031134 :             for (int CompCounter = StartingComponent; CompCounter <= EndingComponent; ++CompCounter) {
    1820    38393096 :                 PlantLocation this_plantLoc = {this->plantLoc.loopNum, this->plantLoc.loopSideNum, BranchCounter, CompCounter};
    1821             : 
    1822    38393096 :                 auto const CurOpSchemeType(branch.Comp(CompCounter).CurOpSchemeType);
    1823             : 
    1824    38393096 :                 switch (CurOpSchemeType) {
    1825      127044 :                 case DataPlant::OpScheme::NoControl: //~ pipes, for example
    1826      127044 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1827      127044 :                     break;
    1828           0 :                 case DataPlant::OpScheme::Demand:
    1829             :                 case DataPlant::OpScheme::CompSetPtBased:
    1830             :                 case DataPlant::OpScheme::FreeRejection: //~ other control types
    1831           0 :                     EncounteredNonLBObjDuringPass2 = true;
    1832           0 :                     goto components2_end;       // don't do anymore components on this branch
    1833           0 :                 case DataPlant::OpScheme::Pump: //~ pump
    1834           0 :                     PumpLocation.loopNum = this->plantLoc.loopNum;
    1835           0 :                     PumpLocation.loopSideNum = this->plantLoc.loopSideNum;
    1836           0 :                     PumpLocation.branchNum = BranchCounter;
    1837           0 :                     PumpLocation.compNum = CompCounter;
    1838           0 :                     if (this->BranchPumpsExist) {
    1839           0 :                         SimulateSinglePump(state, PumpLocation, branch.RequestedMassFlow);
    1840             :                     } else {
    1841           0 :                         SimulateSinglePump(state, PumpLocation, FlowRequest);
    1842             :                     }
    1843           0 :                     break;
    1844    38266052 :                 case OpScheme::WetBulbRB:
    1845             :                 case OpScheme::DryBulbRB:
    1846             :                 case OpScheme::DewPointRB:
    1847             :                 case OpScheme::RelHumRB:
    1848             :                 case OpScheme::DryBulbTDB:
    1849             :                 case OpScheme::WetBulbTDB:
    1850             :                 case OpScheme::DewPointTDB:
    1851             :                 case OpScheme::HeatingRB:
    1852             :                 case OpScheme::CoolingRB: {              //~ load range based
    1853    38266052 :                     if (!LoadDistributionWasPerformed) { //~ Still need to distribute load among load range based components
    1854    36290292 :                         PlantCondLoopOperation::ManagePlantLoadDistribution(state,
    1855             :                                                                             this_plantLoc,
    1856             :                                                                             LoadToLoopSetPoint,
    1857             :                                                                             LoadToLoopSetPointThatWasntMet,
    1858             :                                                                             FirstHVACIteration,
    1859             :                                                                             LoopShutDownFlag,
    1860             :                                                                             LoadDistributionWasPerformed);
    1861             :                     }
    1862    38266052 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1863    38266052 :                     break;
    1864             :                 }
    1865           0 :                 default:
    1866           0 :                     break;
    1867             :                 }
    1868             : 
    1869             :                 //~ If we didn't EXIT early, we must have simulated, so update array
    1870    38393096 :                 branch.lastComponentSimulated = CompCounter;
    1871             : 
    1872             :             } //~ CompCounter
    1873    72638038 :         components2_end:;
    1874             : 
    1875             :             //~ If we are locked, go ahead and simulate the pressure components on this branch
    1876    72638038 :             if (this->FlowLock == DataPlant::FlowLock::Locked) {
    1877    36319019 :                 PlantPressureSystem::SimPressureDropSystem(
    1878             :                     state, this->plantLoc.loopNum, FirstHVACIteration, DataPlant::PressureCall::Calc, this->plantLoc.loopSideNum, BranchCounter);
    1879             :             }
    1880             : 
    1881             :         } //~ BranchCounter
    1882             : 
    1883             :         // So now we have made the load range based pass through all the components on each branch
    1884             :         // If we didn't see any other component types, then we are done, go away
    1885    33068324 :         if (!EncounteredNonLBObjDuringPass2) return;
    1886             : 
    1887             :         // If we did encounter other objects than we just need to go back through and simulate them
    1888           0 :         for (int BranchCounter = FirstBranchNum; BranchCounter <= LastBranchNum; ++BranchCounter) {
    1889           0 :             auto &branch(this->Branch(BranchCounter));
    1890             : 
    1891             :             //~ Always start from the last component we did the last time around + 1 and
    1892             :             //~  try to make it all the way to the end of the loop
    1893           0 :             int const StartingComponent = branch.lastComponentSimulated + 1;
    1894           0 :             int const EndingComponent = branch.TotalComponents;
    1895           0 :             for (int CompCounter = StartingComponent; CompCounter <= EndingComponent; ++CompCounter) {
    1896             : 
    1897           0 :                 auto const CurOpSchemeType(branch.Comp(CompCounter).CurOpSchemeType);
    1898             : 
    1899           0 :                 switch (CurOpSchemeType) {
    1900           0 :                 case DataPlant::OpScheme::Demand: //~ coils
    1901           0 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1902           0 :                     break;
    1903           0 :                 case DataPlant::OpScheme::Pump: //~ pump
    1904           0 :                     PumpLocation.loopNum = this->plantLoc.loopNum;
    1905           0 :                     PumpLocation.loopSideNum = this->plantLoc.loopSideNum;
    1906           0 :                     PumpLocation.branchNum = BranchCounter;
    1907           0 :                     PumpLocation.compNum = CompCounter;
    1908           0 :                     if (this->BranchPumpsExist) {
    1909           0 :                         SimulateSinglePump(state, PumpLocation, branch.RequestedMassFlow);
    1910             :                     } else {
    1911           0 :                         SimulateSinglePump(state, PumpLocation, FlowRequest);
    1912             :                     }
    1913           0 :                     break;
    1914           0 :                 case OpScheme::HeatingRB:
    1915             :                 case OpScheme::CoolingRB: { //~ load range based
    1916           0 :                     ShowFatalError(state, "Encountered Load Based Object after other components, invalid.");
    1917           0 :                     break;
    1918             :                 }
    1919           0 :                 default:
    1920             :                     //~ Typical control equipment
    1921           0 :                     branch.Comp(CompCounter).simulate(state, FirstHVACIteration);
    1922             :                 }
    1923             : 
    1924             :                 //~ If we didn't EXIT early, we must have simulated, so update array
    1925           0 :                 branch.lastComponentSimulated = CompCounter;
    1926             : 
    1927             :             } //~ CompCounter
    1928             : 
    1929           0 :             if (this->FlowLock == DataPlant::FlowLock::Locked) {
    1930           0 :                 PlantPressureSystem::SimPressureDropSystem(
    1931             :                     state, this->plantLoc.loopNum, FirstHVACIteration, DataPlant::PressureCall::Calc, this->plantLoc.loopSideNum, BranchCounter);
    1932             :             }
    1933             : 
    1934             :         } //~ BranchCounter
    1935             : 
    1936             :         // I suppose I could do a check on the last component simulated to make sure we actually exhausted all branches
    1937             :         // This would be the "THIRD" check on flow validation, but would be OK
    1938             :     }
    1939             : 
    1940   391909152 :     void HalfLoopData::UpdateAnyLoopDemandAlterations(EnergyPlusData &state, int const BranchNum, int const CompNum)
    1941             :     {
    1942             : 
    1943             :         // SUBROUTINE INFORMATION:
    1944             :         //       AUTHOR         Edwin Lee
    1945             :         //       DATE WRITTEN   August 2010
    1946             :         //       MODIFIED       na
    1947             :         //       RE-ENGINEERED  na
    1948             : 
    1949             :         // PURPOSE OF THIS SUBROUTINE:
    1950             :         // This routine will analyze the given component and determine if any
    1951             :         //  alterations need to be made to the current loop demand value.  If so,
    1952             :         //  it will make the changes to the module level loop demand variables.
    1953             : 
    1954             :         // METHODOLOGY EMPLOYED:
    1955             :         // Components will always supply a useful delta T, even if it happens to be zero
    1956             :         // For flow rate, make decisions based on the component's current operating scheme type:
    1957             :         //    Demand based: these components will have a flow request on their inlet node
    1958             :         //    Pump: these components will not be included, as they no longer include heat at the pump
    1959             :         //    component setpoint: these components will have a flow request
    1960             : 
    1961             :         //    on their outlet node corresponding to their calculated delta T
    1962             :         //    load range based: these components do not 'alter' the load, they reject the load
    1963             :         //    Therefore they are not included
    1964             : 
    1965             :         // Using/Aliasing
    1966             :         using FluidProperties::GetSpecificHeatGlycol;
    1967             : 
    1968             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1969             :         static constexpr std::string_view RoutineName("PlantLoopSolver::UpdateAnyLoopDemandAlterations");
    1970             : 
    1971             :         // Init to zero, so that if we don't find anything, we exit early
    1972   391909152 :         Real64 ComponentMassFlowRate(0.0);
    1973             : 
    1974   391909152 :         auto const &this_comp(this->Branch(BranchNum).Comp(CompNum));
    1975             : 
    1976             :         // Get information
    1977   391909152 :         int const InletNode(this_comp.NodeNumIn);
    1978   391909152 :         int const OutletNode(this_comp.NodeNumOut);
    1979             : 
    1980   391909152 :         if (this->FlowLock == DataPlant::FlowLock::Unlocked) {
    1981             : 
    1982   195954576 :             switch (this_comp.CurOpSchemeType) {
    1983           0 :             case OpScheme::HeatingRB:
    1984             :             case OpScheme::CoolingRB: { //~ load range based
    1985           0 :                 break;                  // Don't do anything for load based components
    1986             :             }
    1987             : 
    1988   195954576 :             default: {
    1989             :                 // pumps pipes, etc. will be lumped in here with other component types, but they will have no delta T anyway
    1990   195954576 :                 ComponentMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateRequest;
    1991             :                 // make sure components like economizers use the mass flow request
    1992   195954576 :                 break;
    1993             :             }
    1994             :             }
    1995             : 
    1996   195954576 :         } else if (this->FlowLock == DataPlant::FlowLock::Locked) {
    1997             : 
    1998             :             // For locked flow just use the mass flow rate
    1999             : 
    2000   195954576 :             switch (this_comp.CurOpSchemeType) {
    2001           0 :             case OpScheme::HeatingRB:
    2002             :             case OpScheme::CoolingRB: { //~ load range based
    2003           0 :                 break;                  // Don't do anything for load based components
    2004             :             }
    2005   195954576 :             default: {
    2006             :                 // pumps pipes, etc. will be lumped in here with other component types, but they will have no delta T anyway
    2007   195954576 :                 ComponentMassFlowRate = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    2008             :             }
    2009             :             }
    2010             : 
    2011             :         } else { // flow pump query? problem?
    2012             :         }
    2013             : 
    2014             :         // Leave early if there wasn't a mass flow rate or request
    2015   391909152 :         if (ComponentMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) return;
    2016             : 
    2017             :         // Get an average temperature for the property call
    2018   135605665 :         Real64 const InletTemp(state.dataLoopNodes->Node(InletNode).Temp);
    2019   135605665 :         Real64 const OutletTemp(state.dataLoopNodes->Node(OutletNode).Temp);
    2020   135605665 :         Real64 const AverageTemp((InletTemp + OutletTemp) / 2.0);
    2021   271211330 :         Real64 const ComponentCp(GetSpecificHeatGlycol(state,
    2022   135605665 :                                                        state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
    2023             :                                                        AverageTemp,
    2024   135605665 :                                                        state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
    2025   135605665 :                                                        RoutineName));
    2026             : 
    2027             :         // Calculate the load altered by this component
    2028   135605665 :         Real64 const LoadAlteration(ComponentMassFlowRate * ComponentCp * (OutletTemp - InletTemp));
    2029             : 
    2030             :         // Now alter the module level variables
    2031   135605665 :         this->CurrentAlterationsToDemand += LoadAlteration;
    2032   135605665 :         this->UpdatedDemandToLoopSetPoint = this->InitialDemandToLoopSetPoint - this->CurrentAlterationsToDemand;
    2033             :     }
    2034             : 
    2035    35455954 :     void HalfLoopData::SimulateSinglePump(EnergyPlusData &state, PlantLocation const SpecificPumpLocation, Real64 &SpecificPumpFlowRate)
    2036             :     {
    2037             : 
    2038             :         // SUBROUTINE INFORMATION:
    2039             :         //       AUTHOR         Edwin Lee
    2040             :         //       DATE WRITTEN   July 2010
    2041             :         //       MODIFIED       na
    2042             :         //       RE-ENGINEERED  na
    2043             : 
    2044    35455954 :         auto &loop(state.dataPlnt->PlantLoop(SpecificPumpLocation.loopNum));
    2045    35455954 :         auto &loop_side(loop.LoopSide(SpecificPumpLocation.loopSideNum));
    2046    35455954 :         auto &loop_side_branch(loop_side.Branch(SpecificPumpLocation.branchNum));
    2047    35455954 :         auto &comp(loop_side_branch.Comp(SpecificPumpLocation.compNum));
    2048    35455954 :         int const PumpIndex = comp.IndexInLoopSidePumps;
    2049    35455954 :         auto &pump(loop_side.Pumps(PumpIndex));
    2050             : 
    2051    35455954 :         this->AdjustPumpFlowRequestByEMSControls(SpecificPumpLocation.branchNum, SpecificPumpLocation.compNum, SpecificPumpFlowRate);
    2052             : 
    2053             :         // Call SimPumps, routine takes a flow request, and returns some info about the status of the pump
    2054             :         bool DummyThisPumpRunning;
    2055    70911908 :         Pumps::SimPumps(state,
    2056             :                         pump.PumpName,
    2057    35455954 :                         SpecificPumpLocation.loopNum,
    2058             :                         SpecificPumpFlowRate,
    2059             :                         DummyThisPumpRunning,
    2060             :                         loop_side_branch.PumpIndex,
    2061             :                         pump.PumpHeatToFluid);
    2062             : 
    2063             :         //~ Pull some state information from the pump outlet node
    2064    35455954 :         pump.CurrentMinAvail = state.dataLoopNodes->Node(pump.PumpOutletNode).MassFlowRateMinAvail;
    2065    35455954 :         pump.CurrentMaxAvail = state.dataLoopNodes->Node(pump.PumpOutletNode).MassFlowRateMaxAvail;
    2066             : 
    2067             :         //~ Update the LoopSide pump heat totality here
    2068    35455954 :         if (loop_side.TotalPumps > 0) {
    2069    35455954 :             loop_side.TotalPumpHeat = sum(loop_side.Pumps, &DataPlant::LoopSidePumpInformation::PumpHeatToFluid);
    2070             :         }
    2071    35455954 :     }
    2072             : 
    2073    17552151 :     void HalfLoopData::SimulateAllLoopSidePumps(EnergyPlusData &state,
    2074             :                                                 Optional<PlantLocation const> SpecificPumpLocation,
    2075             :                                                 Optional<Real64 const> SpecificPumpFlowRate)
    2076             :     {
    2077             : 
    2078             :         // SUBROUTINE INFORMATION:
    2079             :         //       AUTHOR         Edwin Lee
    2080             :         //       DATE WRITTEN   July 2010
    2081             :         //       MODIFIED       na
    2082             :         //       RE-ENGINEERED  na
    2083             : 
    2084             :         int PumpIndexStart;
    2085             :         int PumpIndexEnd;
    2086             :         int PumpLoopNum;
    2087             :         DataPlant::LoopSideLocation PumpLoopSideNum;
    2088             : 
    2089             :         // If we have a specific loop/side/br/comp, then find the index and only do that one, otherwise do all pumps on the loop side
    2090    17552151 :         if (present(SpecificPumpLocation)) {
    2091           0 :             PumpLoopNum = SpecificPumpLocation().loopNum;
    2092           0 :             PumpLoopSideNum = SpecificPumpLocation().loopSideNum;
    2093           0 :             int const PumpBranchNum = SpecificPumpLocation().branchNum;
    2094           0 :             int const PumpCompNum = SpecificPumpLocation().compNum;
    2095           0 :             PumpIndexStart =
    2096           0 :                 state.dataPlnt->PlantLoop(PumpLoopNum).LoopSide(PumpLoopSideNum).Branch(PumpBranchNum).Comp(PumpCompNum).IndexInLoopSidePumps;
    2097           0 :             PumpIndexEnd = PumpIndexStart;
    2098             :         } else {
    2099    17552151 :             PumpLoopNum = this->plantLoc.loopNum;
    2100    17552151 :             PumpLoopSideNum = this->plantLoc.loopSideNum;
    2101    17552151 :             PumpIndexStart = 1;
    2102    17552151 :             PumpIndexEnd = this->TotalPumps;
    2103             :         }
    2104             : 
    2105             :         // If we have a flow rate to hit, then go for it, otherwise, just operate in request mode with zero flow
    2106             :         Real64 FlowToRequest;
    2107    17552151 :         if (present(SpecificPumpFlowRate)) {
    2108           0 :             FlowToRequest = SpecificPumpFlowRate;
    2109             :         } else {
    2110    17552151 :             FlowToRequest = 0.0;
    2111             :         }
    2112             : 
    2113             :         //~ Now loop through all the pumps and simulate them, keeping track of their status
    2114    17552151 :         auto &loop_side(state.dataPlnt->PlantLoop(PumpLoopNum).LoopSide(PumpLoopSideNum));
    2115    17552151 :         auto &loop_side_branch(loop_side.Branch);
    2116    35281296 :         for (int PumpCounter = PumpIndexStart; PumpCounter <= PumpIndexEnd; ++PumpCounter) {
    2117             : 
    2118             :             //~ Set some variables
    2119    17729145 :             auto &pump(loop_side.Pumps(PumpCounter));
    2120    17729145 :             int const PumpBranchNum = pump.BranchNum;
    2121    17729145 :             int const PumpCompNum = pump.CompNum;
    2122    17729145 :             int const PumpOutletNode = pump.PumpOutletNode;
    2123             : 
    2124    17729145 :             this->AdjustPumpFlowRequestByEMSControls(PumpBranchNum, PumpCompNum, FlowToRequest);
    2125             : 
    2126             :             // Call SimPumps, routine takes a flow request, and returns some info about the status of the pump
    2127             :             bool DummyThisPumpRunning;
    2128    35458290 :             Pumps::SimPumps(state,
    2129             :                             pump.PumpName,
    2130             :                             PumpLoopNum,
    2131             :                             FlowToRequest,
    2132             :                             DummyThisPumpRunning,
    2133    17729145 :                             loop_side_branch(PumpBranchNum).PumpIndex,
    2134             :                             pump.PumpHeatToFluid);
    2135             : 
    2136             :             //~ Pull some state information from the pump outlet node
    2137    17729145 :             Real64 const ThisPumpMinAvail = state.dataLoopNodes->Node(PumpOutletNode).MassFlowRateMinAvail;
    2138    17729145 :             Real64 const ThisPumpMaxAvail = state.dataLoopNodes->Node(PumpOutletNode).MassFlowRateMaxAvail;
    2139             : 
    2140             :             //~ Now update the data structure
    2141    17729145 :             pump.CurrentMinAvail = ThisPumpMinAvail;
    2142    17729145 :             pump.CurrentMaxAvail = ThisPumpMaxAvail;
    2143             :         }
    2144             : 
    2145             :         //~ Update the LoopSide pump heat totality here
    2146    17552151 :         if (loop_side.TotalPumps > 0) {
    2147    17551015 :             loop_side.TotalPumpHeat = sum(loop_side.Pumps, &DataPlant::LoopSidePumpInformation::PumpHeatToFluid);
    2148             :         }
    2149    17552151 :     }
    2150             : 
    2151    34501818 :     Real64 HalfLoopData::DetermineLoopSideFlowRate(EnergyPlusData &state, int ThisSideInletNode, Real64 ThisSideLoopFlowRequest)
    2152             :     {
    2153    34501818 :         Real64 ThisLoopSideFlow = ThisSideLoopFlowRequest;
    2154    34501818 :         Real64 TotalPumpMinAvailFlow = 0.0;
    2155    34501818 :         Real64 TotalPumpMaxAvailFlow = 0.0;
    2156    34501818 :         if (allocated(this->Pumps)) {
    2157             : 
    2158             :             //~ Initialize pump values
    2159    35277832 :             for (auto &e : this->Pumps) {
    2160    17727977 :                 e.CurrentMinAvail = 0.0;
    2161    17727977 :                 e.CurrentMaxAvail = 0.0;
    2162             :             }
    2163    17549855 :             this->FlowLock = DataPlant::FlowLock::PumpQuery;
    2164             : 
    2165             :             //~ Simulate pumps
    2166    17549855 :             this->SimulateAllLoopSidePumps(state);
    2167             : 
    2168             :             //~ Calculate totals
    2169    35277832 :             for (auto const &e : this->Pumps) {
    2170    17727977 :                 TotalPumpMinAvailFlow += e.CurrentMinAvail;
    2171    17727977 :                 TotalPumpMaxAvailFlow += e.CurrentMaxAvail;
    2172             :             }
    2173             : 
    2174             :             // Use the pump min/max avail to attempt to constrain the loop side flow
    2175    17549855 :             ThisLoopSideFlow = PlantUtilities::BoundValueToWithinTwoValues(ThisLoopSideFlow, TotalPumpMinAvailFlow, TotalPumpMaxAvailFlow);
    2176             :         }
    2177             : 
    2178             :         // Now we check flow restriction from the other side, both min and max avail.
    2179             :         // Doing this last basically means it wins, so the pump should pull down to meet the flow restriction
    2180    34501818 :         ThisLoopSideFlow = PlantUtilities::BoundValueToNodeMinMaxAvail(state, ThisLoopSideFlow, ThisSideInletNode);
    2181             : 
    2182             :         // Final preparation of loop inlet min/max avail if pumps exist
    2183    34501818 :         if (allocated(this->Pumps)) {
    2184             :             // At this point, the pump limits should have been obeyed unless a flow restriction was encountered from the other side
    2185             :             // The pump may, however, have even tighter constraints than the other side
    2186             :             // At this point, the inlet node doesn't know anything about those limits
    2187             :             // Since we have already honored the other side flow restriction, try to honor the pump limits here
    2188    17549855 :             PlantUtilities::TightenNodeMinMaxAvails(state, ThisSideInletNode, TotalPumpMinAvailFlow, TotalPumpMaxAvailFlow);
    2189             :         }
    2190             : 
    2191             :         // Now reset the entering mass flow rate to the decided-upon flow rate
    2192    34501818 :         state.dataLoopNodes->Node(ThisSideInletNode).MassFlowRate = ThisLoopSideFlow;
    2193    34501818 :         return ThisLoopSideFlow;
    2194             :     }
    2195             : 
    2196    68684816 :     void HalfLoopData::UpdatePlantMixer(EnergyPlusData &state)
    2197             :     {
    2198             : 
    2199             :         // SUBROUTINE INFORMATION:
    2200             :         //       AUTHOR         Brandon Anderson, Dan Fisher
    2201             :         //       DATE WRITTEN   October 1999
    2202             :         //       MODIFIED       na
    2203             :         //       RE-ENGINEERED  na
    2204             : 
    2205             :         // PURPOSE OF THIS SUBROUTINE:
    2206             :         // calculate the outlet conditions at the mixer
    2207             :         // this is expected to only be called for loops with a mixer
    2208             : 
    2209             :         // Find mixer outlet node number
    2210    68684816 :         int const MixerOutletNode = this->Mixer.NodeNumOut;
    2211             : 
    2212             :         // Find corresponding splitter inlet node number--correspondence, but currently
    2213             :         //  hard code things to a single split/mix setting it to the mixer number
    2214    68684816 :         int const SplitterInNode = this->Splitter.NodeNumIn;
    2215             :         // Initialize Mixer outlet temp and mass flow rate
    2216    68684816 :         Real64 MixerOutletTemp = 0.0;
    2217    68684816 :         Real64 MixerOutletMassFlow = 0.0;
    2218    68684816 :         Real64 MixerOutletMassFlowMaxAvail = 0.0;
    2219    68684816 :         Real64 MixerOutletMassFlowMinAvail = 0.0;
    2220    68684816 :         Real64 MixerOutletPress = 0.0;
    2221    68684816 :         Real64 MixerOutletQuality = 0.0;
    2222             : 
    2223             :         // Calculate Mixer outlet mass flow rate
    2224   358861912 :         for (int InletNodeNum = 1; InletNodeNum <= this->Mixer.TotalInletNodes; ++InletNodeNum) {
    2225   290177096 :             int const MixerInletNode = this->Mixer.NodeNumIn(InletNodeNum);
    2226   290177096 :             MixerOutletMassFlow += state.dataLoopNodes->Node(MixerInletNode).MassFlowRate;
    2227             :         }
    2228             : 
    2229             :         // Calculate Mixer outlet temperature
    2230   233523266 :         for (int InletNodeNum = 1; InletNodeNum <= this->Mixer.TotalInletNodes; ++InletNodeNum) {
    2231   196675681 :             int const MixerInletNode = this->Mixer.NodeNumIn(InletNodeNum);
    2232   196675681 :             if (MixerOutletMassFlow > 0.0) {
    2233   164838450 :                 Real64 const MixerInletMassFlow = state.dataLoopNodes->Node(MixerInletNode).MassFlowRate;
    2234   164838450 :                 Real64 const MassFrac = MixerInletMassFlow / MixerOutletMassFlow;
    2235             :                 // mass flow weighted temp and enthalpy for each mixer inlet
    2236   164838450 :                 MixerOutletTemp += MassFrac * state.dataLoopNodes->Node(MixerInletNode).Temp;
    2237   164838450 :                 MixerOutletQuality += MassFrac * state.dataLoopNodes->Node(MixerInletNode).Quality;
    2238   164838450 :                 MixerOutletMassFlowMaxAvail += state.dataLoopNodes->Node(MixerInletNode).MassFlowRateMaxAvail;
    2239   164838450 :                 MixerOutletMassFlowMinAvail += state.dataLoopNodes->Node(MixerInletNode).MassFlowRateMinAvail;
    2240   164838450 :                 MixerOutletPress = max(MixerOutletPress, state.dataLoopNodes->Node(MixerInletNode).Press);
    2241             :             } else { // MixerOutletMassFlow <=0, then perform the 'no flow' update.
    2242    31837231 :                 MixerOutletTemp = state.dataLoopNodes->Node(SplitterInNode).Temp;
    2243    31837231 :                 MixerOutletQuality = state.dataLoopNodes->Node(SplitterInNode).Quality;
    2244    31837231 :                 MixerOutletMassFlowMaxAvail = state.dataLoopNodes->Node(SplitterInNode).MassFlowRateMaxAvail;
    2245    31837231 :                 MixerOutletMassFlowMinAvail = state.dataLoopNodes->Node(SplitterInNode).MassFlowRateMinAvail;
    2246    31837231 :                 MixerOutletPress = state.dataLoopNodes->Node(SplitterInNode).Press;
    2247    31837231 :                 break;
    2248             :             }
    2249             :         }
    2250             : 
    2251    68684816 :         state.dataLoopNodes->Node(MixerOutletNode).MassFlowRate = MixerOutletMassFlow;
    2252    68684816 :         state.dataLoopNodes->Node(MixerOutletNode).Temp = MixerOutletTemp;
    2253    68684816 :         if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).HasPressureComponents) {
    2254             :             // Don't update pressure, let pressure system handle this...
    2255             :         } else {
    2256             :             // Go ahead and update!
    2257    68642696 :             state.dataLoopNodes->Node(MixerOutletNode).Press = MixerOutletPress;
    2258             :         }
    2259    68684816 :         state.dataLoopNodes->Node(MixerOutletNode).Quality = MixerOutletQuality;
    2260             : 
    2261             :         // set max/min avails on mixer outlet to be consistent with the following rules
    2262             :         // 1.  limited by the max/min avails on splitter inlet
    2263             :         // 2.  limited by the sum of max/min avails for each branch's mixer inlet node
    2264             : 
    2265    68684816 :         state.dataLoopNodes->Node(MixerOutletNode).MassFlowRateMaxAvail =
    2266    68684816 :             min(MixerOutletMassFlowMaxAvail, state.dataLoopNodes->Node(SplitterInNode).MassFlowRateMaxAvail);
    2267    68684816 :         state.dataLoopNodes->Node(MixerOutletNode).MassFlowRateMinAvail =
    2268    68684816 :             max(MixerOutletMassFlowMinAvail, state.dataLoopNodes->Node(SplitterInNode).MassFlowRateMinAvail);
    2269    68684816 :     }
    2270             : 
    2271    68684816 :     void HalfLoopData::UpdatePlantSplitter(EnergyPlusData &state)
    2272             :     {
    2273             : 
    2274             :         // SUBROUTINE INFORMATION:
    2275             :         //       AUTHOR         Brandon Anderson, Dan Fisher
    2276             :         //       DATE WRITTEN   October 1999
    2277             :         //       MODIFIED       na
    2278             :         //       RE-ENGINEERED  na
    2279             : 
    2280             :         // PURPOSE OF THIS SUBROUTINE:
    2281             :         // Set the outlet conditions of the splitter
    2282             : 
    2283             :         // Update Temperatures across splitter
    2284    68684816 :         if (this->Splitter.Exists) {
    2285             : 
    2286             :             // Set branch number at splitter inlet
    2287    68684816 :             int const SplitterInletNode = this->Splitter.NodeNumIn;
    2288             : 
    2289             :             // Loop over outlet nodes
    2290   358861912 :             for (int CurNode = 1; CurNode <= this->Splitter.TotalOutletNodes; ++CurNode) {
    2291   290177096 :                 int const SplitterOutletNode = this->Splitter.NodeNumOut(CurNode);
    2292             : 
    2293             :                 // Inlet Temp equals exit Temp to all outlet branches
    2294   290177096 :                 state.dataLoopNodes->Node(SplitterOutletNode).Temp = state.dataLoopNodes->Node(SplitterInletNode).Temp;
    2295   290177096 :                 state.dataLoopNodes->Node(SplitterOutletNode).TempMin = state.dataLoopNodes->Node(SplitterInletNode).TempMin;
    2296   290177096 :                 state.dataLoopNodes->Node(SplitterOutletNode).TempMax = state.dataLoopNodes->Node(SplitterInletNode).TempMax;
    2297   290177096 :                 if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).HasPressureComponents) {
    2298             :                     // Don't update pressure, let pressure system handle this...
    2299             :                 } else {
    2300             :                     // Go ahead and update!
    2301   290123276 :                     state.dataLoopNodes->Node(SplitterOutletNode).Press = state.dataLoopNodes->Node(SplitterInletNode).Press;
    2302             :                 }
    2303   290177096 :                 state.dataLoopNodes->Node(SplitterOutletNode).Quality = state.dataLoopNodes->Node(SplitterInletNode).Quality;
    2304             : 
    2305             :                 // These two blocks and the following one which I added need to be cleaned up
    2306             :                 // I think we will always pass maxavail down the splitter, min avail is the issue.
    2307             :                 // Changed to include hardware max in next line
    2308   580354192 :                 state.dataLoopNodes->Node(SplitterOutletNode).MassFlowRateMaxAvail = min(
    2309   580354192 :                     state.dataLoopNodes->Node(SplitterInletNode).MassFlowRateMaxAvail, state.dataLoopNodes->Node(SplitterOutletNode).MassFlowRateMax);
    2310   290177096 :                 state.dataLoopNodes->Node(SplitterOutletNode).MassFlowRateMinAvail = 0.0;
    2311             : 
    2312             :                 // Not sure about passing min avail if it is nonzero.  I am testing a pump with nonzero
    2313             :                 // min flow rate, and it is causing problems because this routine passes zero down.  Perhaps if
    2314             :                 // it is a single parallel branch, we are safe to assume we need to just pass it down.
    2315             :                 // But need to test for multiple branches (or at least think about it), to see what we need to do...
    2316   290177096 :                 if (this->Splitter.TotalOutletNodes == 1) {
    2317     1622454 :                     state.dataLoopNodes->Node(SplitterOutletNode).MassFlowRateMinAvail =
    2318     1622454 :                         state.dataLoopNodes->Node(SplitterInletNode).MassFlowRateMinAvail;
    2319             :                 }
    2320             :             }
    2321             :         }
    2322    68684816 :     }
    2323             : 
    2324             : } // namespace DataPlant
    2325        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13