LCOV - code coverage report
Current view: top level - EnergyPlus - PlantCondLoopOperation.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1183 1735 68.2 %
Date: 2023-01-17 19:17:23 Functions: 23 25 92.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <algorithm>
      50             : #include <cassert>
      51             : #include <cmath>
      52             : #include <vector>
      53             : 
      54             : // ObjexxFCL Headers
      55             : #include <ObjexxFCL/Array.functions.hh>
      56             : #include <ObjexxFCL/Array1D.hh>
      57             : #include <ObjexxFCL/Fmath.hh>
      58             : 
      59             : // EnergyPlus Headers
      60             : #include <EnergyPlus/Autosizing/Base.hh>
      61             : #include <EnergyPlus/BranchNodeConnections.hh>
      62             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      63             : #include <EnergyPlus/DataEnvironment.hh>
      64             : #include <EnergyPlus/DataHVACGlobals.hh>
      65             : #include <EnergyPlus/DataIPShortCuts.hh>
      66             : #include <EnergyPlus/DataRuntimeLanguage.hh>
      67             : #include <EnergyPlus/DataSizing.hh>
      68             : #include <EnergyPlus/EMSManager.hh>
      69             : #include <EnergyPlus/FluidProperties.hh>
      70             : #include <EnergyPlus/General.hh>
      71             : #include <EnergyPlus/GeneralRoutines.hh>
      72             : #include <EnergyPlus/GlobalNames.hh>
      73             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74             : #include <EnergyPlus/NodeInputManager.hh>
      75             : #include <EnergyPlus/Plant/DataPlant.hh>
      76             : #include <EnergyPlus/PlantCondLoopOperation.hh>
      77             : #include <EnergyPlus/PlantUtilities.hh>
      78             : #include <EnergyPlus/PluginManager.hh>
      79             : #include <EnergyPlus/ScheduleManager.hh>
      80             : #include <EnergyPlus/SetPointManager.hh>
      81             : #include <EnergyPlus/UtilityRoutines.hh>
      82             : 
      83             : namespace EnergyPlus::PlantCondLoopOperation {
      84             : 
      85             : // MODIFIED       LKL Sep 03: adding integer/pointers for various parts of operation schemes
      86             : // MODIFIED       DEF JUL 10: complete re-write to support new Plant manager
      87             : 
      88             : // PURPOSE OF THIS MODULE: This module assigns loads to the equipment on
      89             : // the plant and condenser loops that will operate
      90             : // for a given timestep.
      91             : 
      92             : // METHODOLOGY EMPLOYED:  The main driver, "ManagePlantLoadDistribution",
      93             : // gets 'Plant Operation scheme' and 'Plant Equipment List' input.  Pointers are
      94             : // set up in the PlantLoop data structure to allow components to directly access the
      95             : // operation schemes and plant lists that the component shows up on.
      96             : // ManagePlantLoadDistribution is called one time for each component on the loop.
      97             : // It finds the operation scheme and equipment list associated with the component
      98             : // and calculates the component load.  If the component is part of a 'load range'
      99             : // based scheme, it also assigns a component load to each of the components on the
     100             : // equipment list.
     101             : 
     102             : // Using/Aliasing
     103             : using namespace DataPlant;
     104             : using DataHVACGlobals::SmallLoad;
     105             : using FluidProperties::GetSpecificHeatGlycol;
     106             : 
     107    37781832 : void ManagePlantLoadDistribution(EnergyPlusData &state,
     108             :                                  PlantLocation const &plantLoc, // PlantLoop data structure Location struct
     109             :                                  Real64 &LoopDemand,
     110             :                                  Real64 &RemLoopDemand,
     111             :                                  bool const FirstHVACIteration,
     112             :                                  bool &LoopShutDownFlag, // EMS flag to tell loop solver to shut down pumps
     113             :                                  bool &LoadDistributionWasPerformed)
     114             : {
     115             :     // SUBROUTINE INFORMATION:
     116             :     //       AUTHOR:          Dan Fisher
     117             :     //       DATE WRITTEN:    April 1999
     118             :     //       REVISED:         March 2001
     119             :     //                        July 2001, Rick Strand (revision of pump and loop control code)
     120             :     //                        July 2010, Dan Fisher, complete rewrite to component based control
     121             : 
     122             :     // PURPOSE OF THIS SUBROUTINE:
     123             :     // ManageLoopOperation is the driver routine
     124             :     // for plant equipment selection.  It calls the general "Get-
     125             :     // Input" routines, initializes the loop pointers, then calls the
     126             :     // appropriate type of control algorithm (setpoint, load range based,
     127             :     // or uncontrolled) for the component
     128             : 
     129             :     int ListNum;    // DO loop index in PlantLoop()%LoopSide()%Branch()%Comp()%OpScheme()%EquipList(ListNum)
     130             :     int CurListNum; // Current list...= ListNum,  used for error checking only
     131             :     // Indices in PlantLoop.LoopSide.Branch.Comp data structure
     132             :     int CurCompLevelOpNum; // This is set by the init routine at each FirstHVACIteration.
     133             :     // It tells which scheme for this component is currently scheduled
     134             :     // and is used to avoid a 'schedule search' on each call
     135             :     // It is used as the OpScheme index in PlantLoop.LoopSide.Branch.Comp.OpScheme(CurCompLevelOpNum)
     136             :     // Value of pointers held in PlantLoop.LoopSide.Branch.Comp() data structure
     137             :     // Used as indices in PlantLoop.OpScheme() data structure
     138             :     int CurSchemePtr; // set by PlantLoop.LoopSide.Branch.Comp.OpScheme.OpSchemePtr
     139             :     // used to locate data in PL()%OpScheme(CurSchemePtr)
     140             :     int ListPtr; // !set by PL()%LoopSide()%Branch()%Comp()%OpScheme(CurCompLevelOpNum)%EquipList(CurListNum)ListPtr
     141             :     // used to locate data in PL()%OpScheme(CurSchemePtr)%EquipList(ListPtr)
     142             :     // Local values from the PlantLoop()%OpScheme() data structure
     143    37781832 :     Real64 RangeVariable(0.0); // holds the 'loop demand', wetbulb temp, etc.
     144             :     Real64 TestRangeVariable;  // abs of RangeVariable for logic tests etc.
     145             :     Real64 RangeHiLimit;       // upper limit of the range variable
     146             :     Real64 RangeLoLimit;       // lower limit of the range variable
     147             :     // Local values from the PlantLoop()%LoopSide()%Branch()%Comp() data structure
     148             :     int NumEquipLists; // number of equipment lists
     149             :     // Error control flags
     150             :     int NumCompsOnList;
     151             :     int CompIndex;
     152             :     int EquipBranchNum;
     153             :     int EquipCompNum;
     154             : 
     155             :     // Shut down equipment and return if so instructed by LoopShutDownFlag
     156    37781832 :     if (LoopShutDownFlag) {
     157        8356 :         TurnOffLoopEquipment(state, plantLoc.loopNum);
     158        8356 :         return;
     159             :     }
     160             : 
     161             :     // Return if there are no loop operation schemes available
     162    37773476 :     if (!std::any_of(state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme.begin(),
     163    37773476 :                      state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme.end(),
     164    40501796 :                      [](DataPlant::OperationData const &e) { return e.Available; }))
     165           0 :         return;
     166             : 
     167             :     // set up references
     168    37773476 :     auto &loop_side(state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum));
     169    37773476 :     auto &this_component(loop_side.Branch(plantLoc.branchNum).Comp(plantLoc.compNum));
     170             : 
     171             :     // Implement EMS control commands
     172    37773476 :     ActivateEMSControls(state, plantLoc, LoopShutDownFlag);
     173             : 
     174             :     // Schedules are checked and CurOpScheme updated on FirstHVACIteration in InitLoadDistribution
     175             :     // Here we just load CurOpScheme to a local variable
     176    37773476 :     CurCompLevelOpNum = this_component.CurCompLevelOpNum;
     177             :     // If no current operation scheme for component, RETURN
     178    37773476 :     if (CurCompLevelOpNum == 0) return;
     179             :     // set local variables from data structure
     180    37773476 :     NumEquipLists = this_component.OpScheme(CurCompLevelOpNum).NumEquipLists;
     181    37773476 :     CurSchemePtr = this_component.OpScheme(CurCompLevelOpNum).OpSchemePtr;
     182    37773476 :     DataPlant::OpScheme CurSchemeType = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).Type;
     183             : 
     184             :     // another reference
     185    37773476 :     auto &this_op_scheme(state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr));
     186             : 
     187             :     // Load the 'range variable' according to the type of control scheme specified
     188    37773476 :     switch (CurSchemeType) {
     189     1168724 :     case OpScheme::Uncontrolled:
     190             :     case OpScheme::CompSetPtBased: {
     191             :         // No RangeVariable specified for these types
     192     1168724 :         break;
     193             :     }
     194      322816 :     case OpScheme::EMS: {
     195      322816 :         InitLoadDistribution(state, FirstHVACIteration);
     196             :         // No RangeVariable specified for these types
     197      322816 :         break;
     198             :     }
     199    15440274 :     case OpScheme::HeatingRB: {
     200             :         // For zero demand, we need to clean things out before we leave
     201    15440274 :         if (LoopDemand < SmallLoad) {
     202     6611662 :             InitLoadDistribution(state, FirstHVACIteration);
     203     6611662 :             this_component.MyLoad = 0.0;
     204     6611662 :             this_component.ON = false;
     205     6611662 :             return;
     206             :         }
     207     8828612 :         RangeVariable = LoopDemand;
     208     8828612 :         break;
     209             :     }
     210    20370246 :     case OpScheme::CoolingRB: {
     211             :         // For zero demand, we need to clean things out before we leave
     212    20370246 :         if (LoopDemand > (-1.0 * SmallLoad)) {
     213    12151568 :             InitLoadDistribution(state, FirstHVACIteration);
     214    12151568 :             this_component.MyLoad = 0.0;
     215    12151568 :             this_component.ON = false;
     216    12151568 :             return;
     217             :         }
     218     8218678 :         RangeVariable = LoopDemand;
     219     8218678 :         break;
     220             :     }
     221       14616 :     case OpScheme::DryBulbRB: {
     222       14616 :         RangeVariable = state.dataEnvrn->OutDryBulbTemp;
     223       14616 :         break;
     224             :     }
     225       14616 :     case OpScheme::WetBulbRB: {
     226       14616 :         RangeVariable = state.dataEnvrn->OutWetBulbTemp;
     227       14616 :         break;
     228             :     }
     229       14616 :     case OpScheme::RelHumRB: {
     230       14616 :         RangeVariable = state.dataEnvrn->OutRelHum;
     231       14616 :         break;
     232             :     }
     233       14616 :     case OpScheme::DewPointRB: {
     234       14616 :         RangeVariable = state.dataEnvrn->OutDewPointTemp;
     235       14616 :         break;
     236             :     }
     237      412952 :     case OpScheme::DryBulbTDB:
     238             :     case OpScheme::WetBulbTDB:
     239             :     case OpScheme::DewPointTDB: {
     240      412952 :         RangeVariable = FindRangeVariable(state, plantLoc.loopNum, CurSchemePtr, CurSchemeType);
     241      412952 :         break;
     242             :     }
     243           0 :     default: {
     244             :         // No controls specified.  This is a fatal error
     245           0 :         ShowFatalError(state,
     246           0 :                        "Invalid Operation Scheme Type Requested=" + state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).TypeOf +
     247             :                            ", in ManagePlantLoadDistribution");
     248             :     }
     249             :     }
     250             : 
     251    19010246 :     switch (CurSchemeType) {
     252           0 :     case OpScheme::Uncontrolled: {
     253             :         //!***what else do we do with 'uncontrolled' equipment?
     254             :         // There's an equipment list...but I think the idea is to just
     255             :         // Set one component to run in an 'uncontrolled' way (whatever that means!)
     256           0 :         break;
     257             :     }
     258     1168724 :     case OpScheme::CompSetPtBased: {
     259             :         // check for EMS Control
     260     1168724 :         TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     261     1168724 :         FindCompSPLoad(state, plantLoc, CurCompLevelOpNum);
     262     1168724 :         break;
     263             :     }
     264      322816 :     case OpScheme::EMS: {
     265      322816 :         TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     266      322816 :         DistributeUserDefinedPlantLoad(state, plantLoc, CurCompLevelOpNum, CurSchemePtr, LoopDemand, RemLoopDemand);
     267      322816 :         break;
     268             :     }
     269    17518706 :     default: { // it's a range based control type with multiple equipment lists
     270    17518706 :         CurListNum = 0;
     271    17957344 :         for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     272             :             // setpointers to 'PlantLoop()%OpScheme()...'structure
     273    17655012 :             ListPtr = this_component.OpScheme(CurCompLevelOpNum).EquipList(ListNum).ListPtr;
     274    17655012 :             RangeHiLimit = this_op_scheme.EquipList(ListPtr).RangeUpperLimit;
     275    17655012 :             RangeLoLimit = this_op_scheme.EquipList(ListPtr).RangeLowerLimit;
     276    17655012 :             if (CurSchemeType == OpScheme::HeatingRB || CurSchemeType == OpScheme::CoolingRB) {
     277             :                 // these limits are stored with absolute values, but the LoopDemand can be negative for cooling
     278    17155510 :                 TestRangeVariable = std::abs(RangeVariable);
     279             :             } else {
     280      499502 :                 TestRangeVariable = RangeVariable;
     281             :             }
     282             : 
     283             :             // trying to do something where the last stage still runs the equipment but at the hi limit.
     284             : 
     285    17655012 :             if (TestRangeVariable < RangeLoLimit || TestRangeVariable > RangeHiLimit) {
     286      913284 :                 if ((TestRangeVariable > RangeHiLimit) && (ListPtr == this_op_scheme.EquipListNumForLastStage)) {
     287             :                     // let this go thru, later AdjustChangeInLoadForLastStageUpperRangeLimit will cap dispatch to RangeHiLimit
     288       36008 :                     CurListNum = ListNum;
     289       36008 :                     break;
     290             :                 } else {
     291      438638 :                     continue;
     292             :                 }
     293             :             } else {
     294    17180366 :                 CurListNum = ListNum;
     295    17180366 :                 break;
     296             :             }
     297             :         }
     298             : 
     299    17518706 :         if (CurListNum > 0) {
     300             :             // there could be equipment on another list that needs to be nulled out, it may have a load from earlier iteration
     301    34682354 :             for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     302    17465980 :                 if (ListNum == CurListNum) continue; // leave current one alone
     303      249606 :                 NumCompsOnList = this_op_scheme.EquipList(ListNum).NumComps;
     304      581628 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
     305      332022 :                     EquipBranchNum = this_op_scheme.EquipList(ListNum).Comp(CompIndex).BranchNumPtr;
     306      332022 :                     EquipCompNum = this_op_scheme.EquipList(ListNum).Comp(CompIndex).CompNumPtr;
     307      332022 :                     loop_side.Branch(EquipBranchNum).Comp(EquipCompNum).MyLoad = 0.0;
     308             :                 }
     309             :             }
     310    17216374 :             if (this_op_scheme.EquipList(ListPtr).NumComps > 0) {
     311    17216374 :                 TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     312    17216374 :                 DistributePlantLoad(state, plantLoc.loopNum, plantLoc.loopSideNum, CurSchemePtr, ListPtr, LoopDemand, RemLoopDemand);
     313    17216374 :                 LoadDistributionWasPerformed = true;
     314             :             }
     315             :         }
     316             : 
     317             :     } // End of range based schemes
     318             :     }
     319             : }
     320             : 
     321             : // Beginning of GetInput subroutines for the Module
     322             : //******************************************************************************
     323             : 
     324         442 : void GetPlantOperationInput(EnergyPlusData &state, bool &GetInputOK)
     325             : {
     326             : 
     327             :     // SUBROUTINE INFORMATION:
     328             :     //       AUTHOR         Dan Fisher
     329             :     //       DATE WRITTEN   October 1998
     330             :     //       MODIFIED       July 2010, Dan Fisher, restructure input data
     331             :     //       RE-ENGINEERED  na
     332             : 
     333             :     // PURPOSE OF THIS SUBROUTINE: This subroutine reads the primary plant loop
     334             :     // operation schemes from the input file
     335             : 
     336             :     // METHODOLOGY EMPLOYED: calls the Input Processor to retrieve data from input file.
     337             :     // The format of the Energy+.idd (the EnergyPlus input data dictionary) for the
     338             :     // following keywords is reflected exactly in this subroutine:
     339             :     //    PlantEquipmentOperationSchemes
     340             :     //    CondenserEquipmentOperationSchemes
     341             : 
     342             :     // Using/Aliasing
     343             :     using ScheduleManager::GetScheduleIndex;
     344             : 
     345             :     // SUBROUTINE PARAMETER DEFINITIONS:
     346             :     static constexpr std::string_view RoutineName("GetPlantOperationInput: "); // include trailing blank space
     347             : 
     348             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     349             :     int LoopNum;           // Loop counter (Plant or Cond)
     350             :     int OpNum;             // Scheme counter
     351             :     int Num;               // Item counter
     352             :     int NumPlantOpSchemes; // Total Number of PlantEquipmentOperationSchemes
     353             :     int NumCondOpSchemes;  // Total Number of CondenserEquipmentOperationSchemes
     354             :     int NumAlphas;         // Number of alpha items in the input object
     355             :     int NumNums;           // Number of numeric items in the input object
     356             :     int IOStat;
     357         884 :     std::string PlantOpSchemeName;   // Name of the plant or condenser operating scheme
     358         884 :     std::string CurrentModuleObject; // for ease in renaming
     359         884 :     std::string PlantLoopObject;     // for ease in renaming
     360             :     bool ErrorsFound;                // Passed in from OpSchemeInput
     361             : 
     362         442 :     ErrorsFound = false;
     363             : 
     364         442 :     if (!allocated(state.dataPlnt->PlantLoop)) {
     365           0 :         GetInputOK = false;
     366           0 :         return;
     367             :     } else {
     368         442 :         GetInputOK = true;
     369             :     }
     370             : 
     371             :     // get number of operation schemes
     372         442 :     CurrentModuleObject = "PlantEquipmentOperationSchemes";
     373         442 :     NumPlantOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     374        1288 :     for (OpNum = 1; OpNum <= NumPlantOpSchemes; ++OpNum) {
     375        2538 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     376        1692 :             state, CurrentModuleObject, OpNum, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     377         846 :         if (UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) continue;
     378             :     }
     379             : 
     380         442 :     CurrentModuleObject = "CondenserEquipmentOperationSchemes";
     381         442 :     NumCondOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     382         699 :     for (OpNum = 1; OpNum <= NumCondOpSchemes; ++OpNum) {
     383         771 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     384         514 :             state, CurrentModuleObject, OpNum, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     385         257 :         if (UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) continue;
     386             :     }
     387             : 
     388             :     // Load the Plant data structure
     389        1549 :     for (LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
     390        1107 :         PlantOpSchemeName = state.dataPlnt->PlantLoop(LoopNum).OperationScheme;
     391        1107 :         if (LoopNum <= state.dataHVACGlobal->NumPlantLoops) {
     392         852 :             CurrentModuleObject = "PlantEquipmentOperationSchemes";
     393         852 :             PlantLoopObject = "PlantLoop";
     394             :         } else {
     395         255 :             CurrentModuleObject = "CondenserEquipmentOperationSchemes";
     396         255 :             PlantLoopObject = "CondenserLoop";
     397             :         }
     398        1107 :         OpNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, CurrentModuleObject, PlantOpSchemeName);
     399        1107 :         if (OpNum > 0) {
     400        7749 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     401             :                                                                      CurrentModuleObject,
     402             :                                                                      OpNum,
     403        1107 :                                                                      state.dataIPShortCut->cAlphaArgs,
     404             :                                                                      NumAlphas,
     405        1107 :                                                                      state.dataIPShortCut->rNumericArgs,
     406             :                                                                      NumNums,
     407             :                                                                      IOStat,
     408        1107 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     409        1107 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     410        1107 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     411        1107 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     412        1107 :             state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes = (NumAlphas - 1) / 3;
     413        1107 :             if (state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes > 0) {
     414        1107 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme.allocate(state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes);
     415        2335 :                 for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes; ++Num) {
     416        1228 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).TypeOf = state.dataIPShortCut->cAlphaArgs(Num * 3 - 1);
     417             : 
     418             :                     {
     419        2456 :                         auto const plantLoopOperation(state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).TypeOf);
     420             : 
     421        1228 :                         if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COOLINGLOAD") {
     422         682 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::CoolingRB;
     423         546 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:HEATINGLOAD") {
     424         477 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::HeatingRB;
     425          69 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COMPONENTSETPOINT") { //* Temp Based Control
     426          14 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::CompSetPtBased;
     427          55 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") { //* Simple TES Control
     428           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type =
     429             :                                 OpScheme::CompSetPtBased; // set this to component based as it will be converted to this
     430          54 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:USERDEFINED") {
     431           6 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::EMS;
     432           6 :                             state.dataPlnt->AnyEMSPlantOpSchemesInModel = true;
     433          48 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULB") {
     434           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DryBulbRB;
     435          47 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULB") {
     436           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::WetBulbRB;
     437          46 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINT") {
     438           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DewPointRB;
     439          45 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORRELATIVEHUMIDITY") {
     440           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::RelHumRB;
     441          44 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULBDIFFERENCE") {
     442           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DryBulbTDB;
     443          43 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULBDIFFERENCE") {
     444           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::WetBulbTDB;
     445          42 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINTDIFFERENCE") {
     446           1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DewPointTDB;
     447          41 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:UNCONTROLLED") {
     448          41 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::Uncontrolled;
     449             :                         } else { // invalid op scheme type for plant loop
     450           0 :                             ShowSevereError(state,
     451           0 :                                             std::string{RoutineName} + "Invalid " + state.dataIPShortCut->cAlphaFieldNames(Num * 3 - 1) + '=' +
     452           0 :                                                 state.dataIPShortCut->cAlphaArgs(Num * 3 - 1) + ", entered in " + CurrentModuleObject + '=' +
     453           0 :                                                 state.dataIPShortCut->cAlphaArgs(1));
     454           0 :                             ErrorsFound = true;
     455             :                         }
     456             :                     }
     457             : 
     458        1228 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Name = state.dataIPShortCut->cAlphaArgs(Num * 3);
     459        1228 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Sched = state.dataIPShortCut->cAlphaArgs(Num * 3 + 1);
     460        1228 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).SchedPtr =
     461        1228 :                         GetScheduleIndex(state, state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Sched);
     462        1228 :                     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).SchedPtr == 0) {
     463           0 :                         ShowSevereError(state,
     464           0 :                                         std::string{RoutineName} + "Invalid " + state.dataIPShortCut->cAlphaFieldNames(Num * 3 + 1) + " = \"" +
     465           0 :                                             state.dataIPShortCut->cAlphaArgs(Num * 3 + 1) + "\", entered in " + CurrentModuleObject + "= \"" +
     466           0 :                                             state.dataIPShortCut->cAlphaArgs(1) + "\".");
     467           0 :                         ErrorsFound = true;
     468             :                     }
     469             :                 }
     470             :             } else {
     471           0 :                 ShowSevereError(state,
     472           0 :                                 CurrentModuleObject + " = \"" + state.dataIPShortCut->cAlphaArgs(1) + "\", requires at least " +
     473           0 :                                     state.dataIPShortCut->cAlphaFieldNames(2) + ", " + state.dataIPShortCut->cAlphaFieldNames(3) + " and " +
     474           0 :                                     state.dataIPShortCut->cAlphaFieldNames(4) + " to be specified.");
     475           0 :                 ErrorsFound = true;
     476             :             }
     477             :         } else {
     478           0 :             ShowSevereError(state, std::string{RoutineName} + PlantLoopObject + '=' + state.dataPlnt->PlantLoop(LoopNum).Name + " is expecting");
     479           0 :             ShowContinueError(state, CurrentModuleObject + '=' + PlantOpSchemeName + ", but not found.");
     480           0 :             ErrorsFound = true;
     481             :         }
     482             :     }
     483             : 
     484         442 :     if (ErrorsFound) {
     485           0 :         ShowFatalError(state,
     486           0 :                        std::string{RoutineName} +
     487             :                            "Errors found in getting input for PlantEquipmentOperationSchemes or CondenserEquipmentOperationSchemes");
     488             :     }
     489             : }
     490             : 
     491         442 : void GetOperationSchemeInput(EnergyPlusData &state)
     492             : {
     493             : 
     494             :     // SUBROUTINE INFORMATION:
     495             :     //       AUTHOR         Dan Fisher
     496             :     //       DATE WRITTEN   October 1998
     497             :     //       MODIFIED       August 2001, LKL -- Validations
     498             :     //       RE-ENGINEERED  July 2010, Dan Fisher, restructure input data
     499             : 
     500             :     // PURPOSE OF THIS SUBROUTINE:
     501             :     // This subroutine reads the primary plant loop
     502             :     // operation schemes from the input file
     503             : 
     504             :     // METHODOLOGY EMPLOYED:
     505             :     // calls the Input Processor to retrieve data from input file.
     506             :     // The format of the Energy+.idd (the EnergyPlus input data dictionary) for the
     507             :     // following keywords is reflected exactly in this subroutine:
     508             :     //    PlantEquipmentOperation:*
     509             : 
     510             :     // Using/Aliasing
     511             :     using namespace DataLoopNode;
     512             :     using namespace DataSizing;
     513             : 
     514             :     // SUBROUTINE PARAMETER DEFINITIONS:
     515             :     static constexpr std::string_view RoutineName("GetOperationSchemeInput: "); // include trailing blank space
     516             : 
     517             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     518             :     int SchemeNum;
     519             :     int Num;
     520             :     int NumAlphas;
     521             :     int NumNums;
     522             :     int IOStat;
     523             :     bool ErrorsFound;           // May be set here and passed on
     524             :     int CLRBO;                  // Number ofCooling Load Range Based Operation Inputs
     525             :     int HLRBO;                  // Number ofHeating Load Range Based Operation Inputs
     526             :     int DBRBO;                  // Number ofDry Bulb Temperature Range Based Operation Inputs
     527             :     int WBRBO;                  // Number ofWet Bulb Temperature Range Based Operation Inputs
     528             :     int DPRBO;                  // Number ofDewPoint Temperature Range Based Operation Inputs
     529             :     int RHRBO;                  // Number ofRelative Humidity Range Based Operation Inputs
     530             :     int CSPBO;                  // Number of Component SetPoint Based Operation Inputs
     531             :     int DBTDBO;                 // Number ofDry Bulb Temperature Range Based Operation Inputs
     532             :     int WBTDBO;                 // Number ofWet Bulb Temperature Range Based Operation Inputs
     533             :     int DPTDBO;                 // Number ofDewPoint Temperature Range Based Operation Inputs
     534             :     int TESSPBO;                // Number of Thermal Energy Storage Setpoint Based Operation Inputs
     535             :     int NumSchemes;             // Number of Condenser equipment lists
     536             :     int NumUncontrolledSchemes; // Number of Condenser equipment lists
     537             :     int NumUserDefOpSchemes;    // number of user defined EMS op schemes
     538             :     int CELists;                // Number of Condenser equipment lists
     539             :     int PELists;                // Number of Plant equipment lists
     540             :     int Count;                  // Loop counter
     541             :     int NumSchemeLists;
     542             :     int LoopNum;
     543         884 :     std::string CurrentModuleObject; // for ease in renaming.
     544         884 :     std::unordered_map<std::string, std::string> UniqueNames;
     545             : 
     546         442 :     ErrorsFound = false;
     547             : 
     548             :     //**********VERIFY THE 'PLANTEQUIPMENTOPERATION:...' KEYWORDS**********
     549         442 :     CLRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:CoolingLoad");
     550         442 :     HLRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:HeatingLoad");
     551         442 :     DBRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDryBulb");
     552         442 :     WBRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorWetBulb");
     553         442 :     DPRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDewpoint");
     554         442 :     RHRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorRelativeHumidity");
     555         442 :     CSPBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:ComponentSetpoint"); //* Temp Based Control
     556         442 :     NumUserDefOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:UserDefined");
     557         442 :     DBTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDryBulbDifference");
     558         442 :     WBTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorWetBulbDifference");
     559         442 :     DPTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDewpointDifference");
     560         442 :     TESSPBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:ThermalEnergyStorage");
     561         442 :     NumSchemes = CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUserDefOpSchemes + TESSPBO;
     562         442 :     NumUncontrolledSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:Uncontrolled");
     563         442 :     if ((NumSchemes + NumUncontrolledSchemes) <= 0) {
     564           0 :         ShowFatalError(state, "No PlantEquipmentOperation:* objects specified. Stop simulation.");
     565             :     }
     566             : 
     567             :     // test for blank or duplicates -- this section just determines if there are any duplicate operation scheme names
     568         442 :     UniqueNames.reserve(static_cast<unsigned>(NumSchemes));
     569             : 
     570             :     // Check for existence of duplicates in keyword names
     571         442 :     Count = 0;
     572        1626 :     for (Num = 1; Num <= NumSchemes; ++Num) {
     573        1184 :         if (CLRBO > 0 && Num <= CLRBO) {
     574         686 :             CurrentModuleObject = "PlantEquipmentOperation:CoolingLoad";
     575         686 :             Count = Num;
     576         498 :         } else if (HLRBO > 0 && Num <= (CLRBO + HLRBO)) {
     577         470 :             CurrentModuleObject = "PlantEquipmentOperation:HeatingLoad";
     578         470 :             Count = Num - CLRBO;
     579          28 :         } else if (DBRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO)) {
     580           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulb";
     581           1 :             Count = Num - CLRBO - HLRBO;
     582          27 :         } else if (WBRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO)) {
     583           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulb";
     584           1 :             Count = Num - CLRBO - HLRBO - DBRBO;
     585          26 :         } else if (DPRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO)) {
     586           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewpoint";
     587           1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO;
     588          25 :         } else if (RHRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO)) {
     589           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorRelativeHumidity";
     590           1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO;
     591          24 :         } else if (CSPBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO)) {
     592          14 :             CurrentModuleObject = "PlantEquipmentOperation:ComponentSetpoint";
     593          14 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO;
     594          10 :         } else if (DBTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO)) {
     595           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulbDifference";
     596           1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO;
     597           9 :         } else if (WBTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO)) {
     598           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulbDifference";
     599           1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO;
     600           8 :         } else if (DPTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO)) {
     601           1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewpointDifference";
     602           1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO;
     603           7 :         } else if (NumUncontrolledSchemes > 0 &&
     604           0 :                    Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUncontrolledSchemes)) {
     605           0 :             CurrentModuleObject = "PlantEquipmentOperation:Uncontrolled";
     606           0 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO - DPTDBO;
     607          13 :         } else if (NumUserDefOpSchemes > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO +
     608           6 :                                                       NumUncontrolledSchemes + NumUserDefOpSchemes)) {
     609           6 :             CurrentModuleObject = "PlantEquipmentOperation:UserDefined";
     610           6 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO - DPTDBO - NumUncontrolledSchemes;
     611           2 :         } else if (TESSPBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUncontrolledSchemes +
     612           1 :                                           NumUserDefOpSchemes + TESSPBO)) {
     613           1 :             CurrentModuleObject = "PlantEquipmentOperation:ThermalEnergyStorage";
     614           1 :             Count =
     615           1 :                 Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO - DPTDBO - NumUncontrolledSchemes - NumUserDefOpSchemes;
     616             :         } else {
     617           0 :             ShowFatalError(state, "Error in control scheme identification");
     618             :         }
     619             : 
     620        3552 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     621        2368 :             state, CurrentModuleObject, Count, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     622        1184 :         if (GlobalNames::VerifyUniqueInterObjectName(state, UniqueNames, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) {
     623           0 :             continue;
     624             :         }
     625             :     }
     626             : 
     627             :     //**********VERIFY THE 'PlantEquipmentList' AND 'CondenserEquipmentList' KEYWORDS*********
     628         442 :     PELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentList");
     629         442 :     CELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CondenserEquipmentList");
     630         442 :     NumSchemeLists = PELists + CELists;
     631         442 :     UniqueNames.clear();
     632         442 :     UniqueNames.reserve(NumSchemeLists);
     633         442 :     Count = 0;
     634        1889 :     for (Num = 1; Num <= NumSchemeLists; ++Num) {
     635        1447 :         if (Num <= PELists) {
     636        1181 :             CurrentModuleObject = "PlantEquipmentList";
     637        1181 :             Count = Num;
     638             :         } else {
     639         266 :             CurrentModuleObject = "CondenserEquipmentList";
     640         266 :             Count = Num - PELists;
     641             :         }
     642        4341 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     643        2894 :             state, CurrentModuleObject, Count, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     644        1447 :         if (GlobalNames::VerifyUniqueInterObjectName(state, UniqueNames, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) {
     645           0 :             continue;
     646             :         }
     647             :     }
     648             : 
     649             :     //**********GET INPUT AND LOAD PLANT DATA STRUCTURE*********
     650             : 
     651             :     // extend number of equipment lists to include one for each CSPBO
     652         442 :     NumSchemeLists += CSPBO + TESSPBO + NumUserDefOpSchemes;
     653        1549 :     for (LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
     654        2335 :         for (SchemeNum = 1; SchemeNum <= state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes; ++SchemeNum) {
     655             : 
     656             :             {
     657        2456 :                 auto const plantLoopOperation(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).TypeOf);
     658             : 
     659        1228 :                 if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COOLINGLOAD") {
     660         682 :                     CurrentModuleObject = "PlantEquipmentOperation:CoolingLoad";
     661         682 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, CLRBO, LoopNum, SchemeNum, ErrorsFound);
     662             : 
     663         546 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:HEATINGLOAD") {
     664         477 :                     CurrentModuleObject = "PlantEquipmentOperation:HeatingLoad";
     665         477 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, HLRBO, LoopNum, SchemeNum, ErrorsFound);
     666             : 
     667          69 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COMPONENTSETPOINT") { //* Temp Based Control
     668          14 :                     CurrentModuleObject = "PlantEquipmentOperation:ComponentSetPoint";
     669          14 :                     FindCompSPInput(state, CurrentModuleObject, CSPBO, LoopNum, SchemeNum, ErrorsFound);
     670             : 
     671          55 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:USERDEFINED") {
     672           6 :                     CurrentModuleObject = "PlantEquipmentOperation:UserDefined";
     673           6 :                     GetUserDefinedOpSchemeInput(state, CurrentModuleObject, NumUserDefOpSchemes, LoopNum, SchemeNum, ErrorsFound);
     674             : 
     675          49 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULB") {
     676           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulb";
     677           1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, DBRBO, LoopNum, SchemeNum, ErrorsFound);
     678             : 
     679          48 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULB") {
     680           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulb";
     681           1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, WBRBO, LoopNum, SchemeNum, ErrorsFound);
     682             : 
     683          47 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINT") {
     684           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewPoint";
     685           1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, DPRBO, LoopNum, SchemeNum, ErrorsFound);
     686             : 
     687          46 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORRELATIVEHUMIDITY") {
     688           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorrelativeHumidity";
     689           1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, RHRBO, LoopNum, SchemeNum, ErrorsFound);
     690             : 
     691          45 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULBDIFFERENCE") {
     692           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulbDifference";
     693           1 :                     FindDeltaTempRangeInput(state,
     694             :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorDrybulbDifference,
     695             :                                             DBTDBO,
     696             :                                             LoopNum,
     697             :                                             SchemeNum,
     698             :                                             ErrorsFound);
     699             : 
     700          44 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULBDIFFERENCE") {
     701           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulbDifference";
     702           1 :                     FindDeltaTempRangeInput(state,
     703             :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorWetbulbDifference,
     704             :                                             WBTDBO,
     705             :                                             LoopNum,
     706             :                                             SchemeNum,
     707             :                                             ErrorsFound);
     708             : 
     709          43 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINTDIFFERENCE") {
     710           1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewPointDifference";
     711           1 :                     FindDeltaTempRangeInput(state,
     712             :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorDewpointDifference,
     713             :                                             DPTDBO,
     714             :                                             LoopNum,
     715             :                                             SchemeNum,
     716             :                                             ErrorsFound);
     717             : 
     718          42 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:UNCONTROLLED") {
     719          41 :                     CurrentModuleObject = "PlantEquipmentOperation:Uncontrolled";
     720          41 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, NumUncontrolledSchemes, LoopNum, SchemeNum, ErrorsFound);
     721             : 
     722           1 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") { //* Temp Based Control
     723           1 :                     CurrentModuleObject = "PlantEquipmentOperation:ThermalEnergyStorage";
     724           1 :                     FindCompSPInput(state, CurrentModuleObject, TESSPBO, LoopNum, SchemeNum, ErrorsFound);
     725             : 
     726             :                 } else { // invalid op scheme type for plant loop
     727             :                     // Seems like the alpha args below is incorrect....
     728           0 :                     ShowSevereError(state,
     729           0 :                                     "Invalid operation scheme type = \"" + state.dataIPShortCut->cAlphaArgs(Num * 3 - 1) + "\", entered in " +
     730           0 :                                         CurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
     731           0 :                     ErrorsFound = true;
     732             :                 }
     733             :             }
     734             : 
     735             :             // At this point, switch the thermal energy storage controls to setpoint based controls as all of the
     736             :             // internally generated setpoints and schedules have been generated and this can now be handled like
     737             :             // the long form setpoint based control.
     738        1228 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).TypeOf == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") {
     739           1 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).TypeOf = "PLANTEQUIPMENTOPERATION:COMPONENTSETPOINT";
     740             :             }
     741             :         }
     742             :     }
     743             : 
     744             :     // Validate that component names/types in each list correspond to a valid component in input file
     745         442 :     if (ErrorsFound) {
     746           0 :         ShowFatalError(state, std::string{RoutineName} + "Errors found getting inputs. Previous error(s) cause program termination.");
     747             :     }
     748         442 : }
     749             : 
     750        1204 : void FindRangeBasedOrUncontrolledInput(EnergyPlusData &state,
     751             :                                        std::string &CurrentModuleObject, // for ease in renaming
     752             :                                        int const NumSchemes,             // May be set here and passed on
     753             :                                        int const LoopNum,                // May be set here and passed on
     754             :                                        int const SchemeNum,              // May be set here and passed on
     755             :                                        bool &ErrorsFound                 // May be set here and passed on
     756             : )
     757             : {
     758             :     // SUBROUTINE INFORMATION:
     759             :     //       AUTHOR         Dan Fisher
     760             :     //       DATE WRITTEN   July 2010
     761             :     //       MODIFIED       Chandan Sharma, August 2010
     762             :     //       RE-ENGINEERED  na
     763             : 
     764             :     // PURPOSE OF THIS SUBROUTINE:
     765             :     // Load range based or uncontrolled input into PLANTLOOP data structure
     766             : 
     767             :     // METHODOLOGY EMPLOYED:
     768             :     // calls the Input Processor to retrieve data from input file.
     769             :     // The format of the Energy+.idd (the EnergyPlus input data dictionary) for the
     770             :     // following keywords is reflected exactly in this subroutine:
     771             :     //       PlantEquipmentOperation:CoolingLoad
     772             :     //       PlantEquipmentOperation:HeatingLoad
     773             :     //       PlantEquipmentOperation:OutdoorDryBulb
     774             :     //       PlantEquipmentOperation:OutdoorWetBulb
     775             :     //       PlantEquipmentOperation:OutdoorDewPoint
     776             :     //       PlantEquipmentOperation:OutdoorRelativeHumidity
     777             :     //       PlantEquipmentOperation:Uncontrolled
     778             : 
     779             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     780             :     int NumAlphas;
     781             :     int NumNums;
     782             :     int IOStat;
     783        2408 :     Array1D_string AlphArray;      // Alpha input items for object
     784        2408 :     Array1D_string cAlphaFields;   // Alpha field names
     785        2408 :     Array1D_string cNumericFields; // Numeric field names
     786        2408 :     Array1D<Real64> NumArray;      // Numeric input items for object
     787        2408 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     788        2408 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     789        1204 :     int TotalArgs(0);              // Total number of alpha and numeric arguments (max) for a
     790             :     //   certain object in the input file
     791             :     int Num;
     792             :     int NumEquipLists;
     793             :     int ListNum;
     794        2408 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
     795             :     bool SchemeNameFound;        // Set to FALSE if a match of OpScheme object and OpScheme name is not found
     796             :     int InnerListNum;            // inner loop list number
     797             :     Real64 OuterListNumLowerLimit;
     798             :     Real64 OuterListNumUpperLimit;
     799             :     Real64 InnerListNumLowerLimit;
     800             :     Real64 InnerListNumUpperLimit;
     801             : 
     802        1204 :     SchemeNameFound = true;
     803             : 
     804             :     // Determine max number of alpha and numeric arguments for all objects being read, in order to allocate local arrays
     805        1204 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     806             : 
     807        1204 :     AlphArray.allocate(NumAlphas);
     808        1204 :     cAlphaFields.allocate(NumAlphas);
     809        1204 :     cNumericFields.allocate(NumNums);
     810        1204 :     NumArray.dimension(NumNums, 0.0);
     811        1204 :     lAlphaBlanks.dimension(NumAlphas, true);
     812        1204 :     lNumericBlanks.dimension(NumNums, true);
     813             : 
     814        1204 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
     815         954 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
     816         250 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
     817         250 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
     818             :     }
     819             : 
     820        1204 :     if (NumSchemes > 0) {
     821        1702 :         for (Num = 1; Num <= NumSchemes; ++Num) {
     822        1702 :             state.dataInputProcessing->inputProcessor->getObjectItem(
     823             :                 state, CurrentModuleObject, Num, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
     824        1702 :             if (UtilityRoutines::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, AlphArray(1))) break;
     825         498 :             if (Num == NumSchemes) {
     826           0 :                 ShowSevereError(state,
     827           0 :                                 LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " +
     828           0 :                                     CurrentModuleObject + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     829           0 :                 ErrorsFound = true;
     830           0 :                 SchemeNameFound = false;
     831             :             }
     832             :         }
     833        1204 :         if (SchemeNameFound) {
     834        1204 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = (NumAlphas - 1);
     835        1204 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists <= 0) {
     836           0 :                 ShowSevereError(state, CurrentModuleObject + " = \"" + AlphArray(1) + "\", specified without equipment list.");
     837           0 :                 ErrorsFound = true;
     838             :             } else {
     839        2408 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(
     840        2408 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists);
     841        1204 :                 NumEquipLists = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists;
     842        1204 :                 if (NumNums <= 0) {          // Uncontrolled OpScheme type
     843          41 :                     ListNum = NumEquipLists; // NumEquipLists is always 1 for Uncontrolled OpScheme type
     844          41 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(2);
     845          41 :                     LoadEquipList(state, LoopNum, SchemeNum, ListNum, ErrorsFound);
     846             :                 } else { // Range based OpScheme type
     847        2481 :                     for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     848        1318 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit = NumArray(ListNum * 2 - 1);
     849        1318 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit = NumArray(ListNum * 2);
     850        1318 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(ListNum + 1);
     851        1318 :                         if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit < 0.0) {
     852           0 :                             ShowSevereError(state,
     853           0 :                                             LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     854           0 :                                                 "\", found a negative value for an upper limit in " + CurrentModuleObject + " = \"" +
     855           0 :                                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     856           0 :                             ErrorsFound = true;
     857             :                         }
     858             : 
     859             :                         {
     860        1318 :                             auto const &plantLoopOperation(CurrentModuleObject); // different op schemes have different lower limit check values
     861             : 
     862        3126 :                             if (plantLoopOperation == "PlantEquipmentOperation:CoolingLoad" ||
     863        1326 :                                 plantLoopOperation == "PlantEquipmentOperation:HeatingLoad" ||
     864           8 :                                 plantLoopOperation == "PlantEquipmentOperation:OutdoorrelativeHumidity") {
     865             :                                 // these should not be less than zero
     866        1312 :                                 if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit < 0.0) {
     867           0 :                                     ShowSevereError(state,
     868           0 :                                                     LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     869           0 :                                                         "\", found a negative value for a lower limit in " + CurrentModuleObject + " = \"" +
     870           0 :                                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     871           0 :                                     ErrorsFound = true;
     872             :                                 }
     873             :                             } else {
     874             :                                 // others should not be less than -70
     875           6 :                                 if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit < -70.0) {
     876           0 :                                     ShowSevereError(state,
     877           0 :                                                     LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     878           0 :                                                         "\", found too low of a value for a lower limit in " + CurrentModuleObject + " = \"" +
     879           0 :                                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     880           0 :                                     ErrorsFound = true;
     881             :                                 }
     882             :                             }
     883             :                         }
     884             : 
     885        2636 :                         if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit >
     886        1318 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit) {
     887           0 :                             ShowSevereError(state,
     888           0 :                                             LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     889           0 :                                                 "\", found a lower limit that is higher than an upper limit in " + CurrentModuleObject + " = \"" +
     890           0 :                                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     891           0 :                             ErrorsFound = true;
     892             :                         }
     893             : 
     894        1318 :                         LoadEquipList(state, LoopNum, SchemeNum, ListNum, ErrorsFound);
     895             :                     }
     896             :                     // now run through lists again and check that range limits do not overlap each other
     897        2481 :                     for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     898        1318 :                         OuterListNumLowerLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit;
     899        1318 :                         OuterListNumUpperLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit;
     900        3076 :                         for (InnerListNum = 1; InnerListNum <= NumEquipLists; ++InnerListNum) {
     901        1758 :                             if (InnerListNum == ListNum) continue; // don't check against self.
     902         440 :                             InnerListNumLowerLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(InnerListNum).RangeLowerLimit;
     903         440 :                             InnerListNumUpperLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(InnerListNum).RangeUpperLimit;
     904             :                             // Check if inner list has a lower limit that is between an outer's lower and upper limit
     905         440 :                             if (InnerListNumLowerLimit > OuterListNumLowerLimit && InnerListNumLowerLimit < OuterListNumUpperLimit) {
     906           0 :                                 ShowWarningError(state,
     907           0 :                                                  LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     908           0 :                                                      "\", detected overlapping ranges in " + CurrentModuleObject + " = \"" +
     909           0 :                                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     910           0 :                                 ShowContinueError(state,
     911           0 :                                                   format("Range # {} Lower limit = {:.1R} lies within the Range # {} ({:.1R} to {:.1R}).",
     912             :                                                          InnerListNum,
     913             :                                                          InnerListNumLowerLimit,
     914             :                                                          ListNum,
     915             :                                                          OuterListNumLowerLimit,
     916           0 :                                                          OuterListNumUpperLimit));
     917           0 :                                 ShowContinueError(state,
     918             :                                                   "Check that input for load range limit values do not overlap, and the simulation continues...");
     919             :                             }
     920             :                             // Check if inner list has an upper limit that is between an outer's lower and upper limit
     921         440 :                             if (InnerListNumUpperLimit > OuterListNumLowerLimit && InnerListNumUpperLimit < OuterListNumUpperLimit) {
     922           0 :                                 ShowWarningError(state,
     923           0 :                                                  LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
     924           0 :                                                      "\", detected overlapping ranges in " + CurrentModuleObject + " = \"" +
     925           0 :                                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     926           0 :                                 ShowContinueError(state,
     927           0 :                                                   format("Range # {} Upper limit = {:.1R} lies within Range # {} ({:.1R} to {:.1R}).",
     928             :                                                          InnerListNum,
     929             :                                                          InnerListNumUpperLimit,
     930             :                                                          ListNum,
     931             :                                                          OuterListNumLowerLimit,
     932           0 :                                                          OuterListNumUpperLimit));
     933           0 :                                 ShowContinueError(state,
     934             :                                                   "Check that input for load range limit values do not overlap, and the simulation continues...");
     935             :                             }
     936             :                         }
     937             :                     }
     938             :                 }
     939             :             }
     940             :         }
     941             :     } else {
     942           0 :         ShowSevereError(state,
     943           0 :                         LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " + CurrentModuleObject +
     944           0 :                             " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
     945           0 :         ErrorsFound = true;
     946             :     }
     947             : 
     948        1204 :     AlphArray.deallocate();
     949        1204 :     cAlphaFields.deallocate();
     950        1204 :     cNumericFields.deallocate();
     951        1204 :     NumArray.deallocate();
     952        1204 :     lAlphaBlanks.deallocate();
     953        1204 :     lNumericBlanks.deallocate();
     954        1204 : }
     955             : 
     956           3 : void FindDeltaTempRangeInput(EnergyPlusData &state,
     957             :                              DataLoopNode::ConnectionObjectType const CurrentModuleObject, // for ease in renaming
     958             :                              int const NumSchemes,                                         // May be set here and passed on
     959             :                              int const LoopNum,                                            // May be set here and passed on
     960             :                              int const SchemeNum,                                          // May be set here and passed on
     961             :                              bool &ErrorsFound                                             // May be set here and passed on
     962             : )
     963             : {
     964             :     // SUBROUTINE INFORMATION:
     965             :     //       AUTHOR         Chandan Sharma
     966             :     //       DATE WRITTEN   August 2010
     967             :     //       MODIFIED       na
     968             :     //       RE-ENGINEERED  na
     969             : 
     970             :     // PURPOSE OF THIS SUBROUTINE:
     971             :     // Load range based input into PLANTLOOP data structure
     972             : 
     973             :     // METHODOLOGY EMPLOYED:
     974             :     // calls the Input Processor to retrieve data from input file.
     975             :     // The format of the Energy+.idd (the EnergyPlus input data dictionary) for the
     976             :     // following keywords is reflected exactly in this subroutine:
     977             :     //       PlantEquipmentOperation:OutdoorDryBulbDifference
     978             :     //       PlantEquipmentOperation:OutdoorWetBulbDifference
     979             :     //       PlantEquipmentOperation:OutdoorDewPointDifference
     980             : 
     981             :     // REFERENCES:
     982             :     // Based on subroutine FindRangeBasedOrUncontrolledInput from Dan Fisher, July 2010
     983             : 
     984             :     // Using/Aliasing
     985             :     using NodeInputManager::GetOnlySingleNode;
     986             :     using namespace DataLoopNode;
     987             : 
     988             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     989             :     int NumAlphas;
     990             :     int NumNums;
     991             :     int IOStat;
     992           6 :     Array1D_string AlphArray;      // Alpha input items for object
     993           6 :     Array1D_string cAlphaFields;   // Alpha field names
     994           6 :     Array1D_string cNumericFields; // Numeric field names
     995           6 :     Array1D<Real64> NumArray;      // Numeric input items for object
     996           6 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     997           6 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     998           3 :     int TotalArgs(0);              // Total number of alpha and numeric arguments (max) for a
     999             :     //   certain object in the input file
    1000             :     int Num;
    1001             :     int NumEquipLists;
    1002             :     int ListNum;
    1003           6 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
    1004             :     bool SchemeNameFound;        // Set to FALSE if a match of OpScheme object and OpScheme name is not found
    1005             : 
    1006           3 :     SchemeNameFound = true;
    1007             : 
    1008           6 :     auto cmoStr = std::string(BranchNodeConnections::ConnectionObjectTypeNamesUC[static_cast<int>(CurrentModuleObject)]);
    1009             : 
    1010             :     // Determine max number of alpha and numeric arguments for all objects being read, in order to allocate local arrays
    1011           3 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cmoStr, TotalArgs, NumAlphas, NumNums);
    1012             : 
    1013           3 :     AlphArray.allocate(NumAlphas);
    1014           3 :     cAlphaFields.allocate(NumAlphas);
    1015           3 :     cNumericFields.allocate(NumNums);
    1016           3 :     NumArray.dimension(NumNums, 0.0);
    1017           3 :     lAlphaBlanks.dimension(NumAlphas, true);
    1018           3 :     lNumericBlanks.dimension(NumNums, true);
    1019             : 
    1020           3 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1021           0 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    1022           3 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    1023           3 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    1024             :     }
    1025             : 
    1026           3 :     if (NumSchemes > 0) {
    1027           3 :         for (Num = 1; Num <= NumSchemes; ++Num) {
    1028           3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state, cmoStr, Num, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    1029           3 :             if (UtilityRoutines::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, AlphArray(1))) break;
    1030           0 :             if (Num == NumSchemes) {
    1031           0 :                 ShowSevereError(state,
    1032           0 :                                 LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " + cmoStr +
    1033           0 :                                     " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1034           0 :                 ErrorsFound = true;
    1035           0 :                 SchemeNameFound = false;
    1036             :             }
    1037             :         }
    1038           3 :         if (SchemeNameFound) {
    1039           3 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = (NumAlphas - 2);
    1040           3 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists <= 0) {
    1041           0 :                 ShowSevereError(state, cmoStr + " = \"" + AlphArray(1) + "\", specified without equipment list.");
    1042           0 :                 ErrorsFound = true;
    1043             :             } else {
    1044           6 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(
    1045           6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists);
    1046           3 :                 NumEquipLists = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists;
    1047           3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ReferenceNodeName = AlphArray(2);
    1048           3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ReferenceNodeNumber =
    1049           6 :                     GetOnlySingleNode(state,
    1050           3 :                                       AlphArray(2),
    1051             :                                       ErrorsFound,
    1052             :                                       CurrentModuleObject,
    1053           3 :                                       AlphArray(1),
    1054             :                                       DataLoopNode::NodeFluidType::Water,
    1055             :                                       DataLoopNode::ConnectionType::Sensor,
    1056             :                                       NodeInputManager::CompFluidStream::Primary,
    1057           3 :                                       ObjectIsNotParent);
    1058             :                 // For DO Loop below -- Check for lower limit > upper limit.(invalid)
    1059           9 :                 for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
    1060           6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit = NumArray(ListNum * 2 - 1);
    1061           6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit = NumArray(ListNum * 2);
    1062           6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(ListNum + 2);
    1063          12 :                     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit >
    1064           6 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit) {
    1065           0 :                         ShowSevereError(state,
    1066           0 :                                         LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme +
    1067           0 :                                             "\", found a lower limit that is higher than an upper limit in " + cmoStr + " = \"" +
    1068           0 :                                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1069           0 :                         ErrorsFound = true;
    1070             :                     }
    1071           6 :                     LoadEquipList(state, LoopNum, SchemeNum, ListNum, ErrorsFound);
    1072             :                 }
    1073             :             }
    1074             :         }
    1075             :     } else {
    1076           0 :         ShowSevereError(state,
    1077           0 :                         LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " + cmoStr + " = \"" +
    1078           0 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1079           0 :         ErrorsFound = true;
    1080             :     }
    1081             : 
    1082           3 :     AlphArray.deallocate();
    1083           3 :     cAlphaFields.deallocate();
    1084           3 :     cNumericFields.deallocate();
    1085           3 :     NumArray.deallocate();
    1086           3 :     lAlphaBlanks.deallocate();
    1087           3 :     lNumericBlanks.deallocate();
    1088           3 : }
    1089             : 
    1090        1365 : void LoadEquipList(EnergyPlusData &state,
    1091             :                    int const LoopNum,   // May be set here and passed on
    1092             :                    int const SchemeNum, // May be set here and passed on
    1093             :                    int const ListNum,   // May be set here and passed on
    1094             :                    bool &ErrorsFound    // May be set here and passed on
    1095             : )
    1096             : {
    1097             :     // SUBROUTINE INFORMATION:
    1098             :     //       AUTHOR         Dan Fisher
    1099             :     //       DATE WRITTEN   July 2010
    1100             :     //       MODIFIED       B. Griffith Sept 2011, major rewrite
    1101             :     //                      allow mixing list types across plant types, store info first time
    1102             :     //       RE-ENGINEERED  na
    1103             : 
    1104             :     // PURPOSE OF THIS SUBROUTINE:
    1105             :     // Load delta range based input into PLANTLOOP data structure
    1106             : 
    1107             :     // METHODOLOGY EMPLOYED:
    1108             :     // calls the Input Processor to retrieve data from input file.
    1109             : 
    1110             :     // Using/Aliasing
    1111             : 
    1112             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1113             : 
    1114             :     bool FoundIntendedList;
    1115             :     int Num;
    1116             :     int MachineNum;
    1117             :     int PELists;
    1118             :     int CELists;
    1119             :     //  INTEGER :: NumLists
    1120             :     int NumAlphas;
    1121             :     int NumNums;
    1122             :     int IOStat;
    1123             :     bool IsNotOK;
    1124        2730 :     std::string CurrentModuleObject;
    1125             :     int iIndex;
    1126             :     bool firstblank;
    1127             : 
    1128        1365 :     if (state.dataPlantCondLoopOp->LoadEquipListOneTimeFlag) {
    1129             :         // assemble mapping between list names and indices one time
    1130         442 :         PELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentList");
    1131         442 :         CELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CondenserEquipmentList");
    1132         442 :         state.dataPlantCondLoopOp->TotNumLists = PELists + CELists;
    1133         442 :         if (state.dataPlantCondLoopOp->TotNumLists > 0) {
    1134         442 :             state.dataPlantCondLoopOp->EquipListsNameList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1135         442 :             state.dataPlantCondLoopOp->EquipListsTypeList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1136         442 :             state.dataPlantCondLoopOp->EquipListsIndexList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1137             : 
    1138             :             // First load PlantEquipmentList info
    1139         442 :             if (PELists > 0) {
    1140         426 :                 CurrentModuleObject = "PlantEquipmentList";
    1141        1607 :                 for (Num = 1; Num <= PELists; ++Num) {
    1142        1181 :                     iIndex = Num;
    1143        8267 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1144             :                                                                              CurrentModuleObject,
    1145             :                                                                              Num,
    1146        1181 :                                                                              state.dataIPShortCut->cAlphaArgs,
    1147             :                                                                              NumAlphas,
    1148        1181 :                                                                              state.dataIPShortCut->rNumericArgs,
    1149             :                                                                              NumNums,
    1150             :                                                                              IOStat,
    1151        1181 :                                                                              state.dataIPShortCut->lNumericFieldBlanks,
    1152        1181 :                                                                              state.dataIPShortCut->lAlphaFieldBlanks,
    1153        1181 :                                                                              state.dataIPShortCut->cAlphaFieldNames,
    1154        1181 :                                                                              state.dataIPShortCut->cNumericFieldNames);
    1155        1181 :                     state.dataPlantCondLoopOp->EquipListsNameList(iIndex) = state.dataIPShortCut->cAlphaArgs(1);
    1156        1181 :                     state.dataPlantCondLoopOp->EquipListsTypeList(iIndex) = LoopType::Plant;
    1157        1181 :                     state.dataPlantCondLoopOp->EquipListsIndexList(iIndex) = Num;
    1158        1181 :                     MachineNum = 2;
    1159        4013 :                     while (MachineNum <= NumAlphas) {
    1160        1416 :                         firstblank = false;
    1161        1416 :                         if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum) || state.dataIPShortCut->lAlphaFieldBlanks(MachineNum + 1)) {
    1162           0 :                             if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum)) {
    1163           0 :                                 ShowSevereError(state,
    1164           0 :                                                 CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
    1165             :                                                     "\", invalid component specification.");
    1166           0 :                                 ShowContinueError(state, state.dataIPShortCut->cAlphaFieldNames(MachineNum) + " is blank.");
    1167           0 :                                 firstblank = true;
    1168           0 :                                 ErrorsFound = true;
    1169             :                             }
    1170           0 :                             if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum + 1)) {
    1171           0 :                                 if (!firstblank) {
    1172           0 :                                     ShowSevereError(state,
    1173           0 :                                                     CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
    1174             :                                                         "\", invalid component specification.");
    1175             :                                 }
    1176           0 :                                 ShowContinueError(state, state.dataIPShortCut->cAlphaFieldNames(MachineNum + 1) + " is blank.");
    1177           0 :                                 ErrorsFound = true;
    1178             :                             }
    1179             :                         } else {
    1180        1416 :                             ValidateComponent(state,
    1181        1416 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum),
    1182        1416 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum + 1),
    1183             :                                               IsNotOK,
    1184             :                                               CurrentModuleObject);
    1185        1416 :                             if (IsNotOK) {
    1186           0 :                                 ShowContinueError(state, CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", Input Error.");
    1187           0 :                                 ErrorsFound = true;
    1188             :                             }
    1189             :                         }
    1190        1416 :                         MachineNum += 2;
    1191             :                     }
    1192             :                 }
    1193             :             }
    1194         442 :             if (CELists > 0) {
    1195         252 :                 CurrentModuleObject = "CondenserEquipmentList";
    1196         518 :                 for (Num = 1; Num <= CELists; ++Num) {
    1197         266 :                     iIndex = Num + PELists;
    1198        1862 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1199             :                                                                              CurrentModuleObject,
    1200             :                                                                              Num,
    1201         266 :                                                                              state.dataIPShortCut->cAlphaArgs,
    1202             :                                                                              NumAlphas,
    1203         266 :                                                                              state.dataIPShortCut->rNumericArgs,
    1204             :                                                                              NumNums,
    1205             :                                                                              IOStat,
    1206         266 :                                                                              state.dataIPShortCut->lNumericFieldBlanks,
    1207         266 :                                                                              state.dataIPShortCut->lAlphaFieldBlanks,
    1208         266 :                                                                              state.dataIPShortCut->cAlphaFieldNames,
    1209         266 :                                                                              state.dataIPShortCut->cNumericFieldNames);
    1210         266 :                     state.dataPlantCondLoopOp->EquipListsNameList(iIndex) = state.dataIPShortCut->cAlphaArgs(1);
    1211         266 :                     state.dataPlantCondLoopOp->EquipListsTypeList(iIndex) = LoopType::Condenser;
    1212         266 :                     state.dataPlantCondLoopOp->EquipListsIndexList(iIndex) = Num;
    1213         266 :                     MachineNum = 2;
    1214         846 :                     while (MachineNum <= NumAlphas) {
    1215         290 :                         firstblank = false;
    1216         290 :                         if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum) || state.dataIPShortCut->lAlphaFieldBlanks(MachineNum + 1)) {
    1217           0 :                             if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum)) {
    1218           0 :                                 ShowSevereError(state,
    1219           0 :                                                 CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
    1220             :                                                     "\", invalid component specification.");
    1221           0 :                                 ShowContinueError(state, state.dataIPShortCut->cAlphaFieldNames(MachineNum) + " is blank.");
    1222           0 :                                 firstblank = true;
    1223           0 :                                 ErrorsFound = true;
    1224             :                             }
    1225           0 :                             if (state.dataIPShortCut->lAlphaFieldBlanks(MachineNum + 1)) {
    1226           0 :                                 if (!firstblank) {
    1227           0 :                                     ShowSevereError(state,
    1228           0 :                                                     CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
    1229             :                                                         "\", invalid component specification.");
    1230             :                                 }
    1231           0 :                                 ShowContinueError(state, state.dataIPShortCut->cAlphaFieldNames(MachineNum + 1) + " is blank.");
    1232           0 :                                 ErrorsFound = true;
    1233             :                             }
    1234             :                         } else {
    1235         290 :                             ValidateComponent(state,
    1236         290 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum),
    1237         290 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum + 1),
    1238             :                                               IsNotOK,
    1239             :                                               CurrentModuleObject);
    1240         290 :                             if (IsNotOK) {
    1241           0 :                                 ShowContinueError(state, CurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", Input Error.");
    1242           0 :                                 ErrorsFound = true;
    1243             :                             }
    1244             :                         }
    1245         290 :                         MachineNum += 2;
    1246             :                     }
    1247             :                 }
    1248             :             }
    1249             :         }
    1250         442 :         if (ErrorsFound) {
    1251           0 :             ShowFatalError(state, "LoadEquipList/GetEquipmentLists: Failed due to preceding errors.");
    1252             :         }
    1253         442 :         state.dataPlantCondLoopOp->LoadEquipListOneTimeFlag = false;
    1254             :     }
    1255             : 
    1256        1365 :     FoundIntendedList = false;
    1257             :     // find name in set of possible list
    1258        7249 :     for (Num = 1; Num <= state.dataPlantCondLoopOp->TotNumLists; ++Num) {
    1259        5884 :         if (UtilityRoutines::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name,
    1260        5884 :                                         state.dataPlantCondLoopOp->EquipListsNameList(Num))) {
    1261        1365 :             FoundIntendedList = true;
    1262             :             // get object item for real this time
    1263             :             {
    1264        1365 :                 if (state.dataPlantCondLoopOp->EquipListsTypeList(Num) == LoopType::Plant) {
    1265        1099 :                     CurrentModuleObject = "PlantEquipmentList";
    1266         266 :                 } else if (state.dataPlantCondLoopOp->EquipListsTypeList(Num) == LoopType::Condenser) {
    1267         266 :                     CurrentModuleObject = "CondenserEquipmentList";
    1268             :                 }
    1269             :             }
    1270       10920 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1271             :                                                                      CurrentModuleObject,
    1272        1365 :                                                                      state.dataPlantCondLoopOp->EquipListsIndexList(Num),
    1273        1365 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1274             :                                                                      NumAlphas,
    1275        1365 :                                                                      state.dataIPShortCut->rNumericArgs,
    1276             :                                                                      NumNums,
    1277             :                                                                      IOStat,
    1278        1365 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1279        1365 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1280        1365 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1281        1365 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1282        1365 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps = (NumAlphas - 1) / 2;
    1283        1365 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps > 0) {
    1284        2722 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp.allocate(
    1285        2722 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps);
    1286        2922 :                 for (MachineNum = 1; MachineNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps; ++MachineNum) {
    1287        3122 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp(MachineNum).TypeOf =
    1288        3122 :                         state.dataIPShortCut->cAlphaArgs(MachineNum * 2);
    1289        3122 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp(MachineNum).Name =
    1290        3122 :                         state.dataIPShortCut->cAlphaArgs(MachineNum * 2 + 1);
    1291             :                 } // MachineList
    1292             :             }
    1293             :         }
    1294             :     }
    1295             : 
    1296        1365 :     if (!FoundIntendedList) {
    1297           0 :         ShowSevereError(state,
    1298           0 :                         "LoadEquipList: Failed to find PlantEquipmentList or CondenserEquipmentList object named = " +
    1299           0 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name);
    1300           0 :         ErrorsFound = true;
    1301             :     }
    1302        1365 : }
    1303             : 
    1304          15 : void FindCompSPInput(EnergyPlusData &state,
    1305             :                      std::string &CurrentModuleObject, // for ease in renaming
    1306             :                      int const NumSchemes,             // May be set here and passed on
    1307             :                      int const LoopNum,                // May be set here and passed on
    1308             :                      int const SchemeNum,              // May be set here and passed on
    1309             :                      bool &ErrorsFound                 // May be set here and passed on
    1310             : )
    1311             : {
    1312             :     // SUBROUTINE INFORMATION:
    1313             :     //       AUTHOR         Dan Fisher
    1314             :     //       DATE WRITTEN   July 2010
    1315             :     //       MODIFIED       B. Griffith, check setpoint nodes have setpoint managers on EMS on them.
    1316             :     //                      Rick Strand, Aug 2014, added simple thermal energy storage controls
    1317             :     //       RE-ENGINEERED  na
    1318             : 
    1319             :     // PURPOSE OF THIS SUBROUTINE:
    1320             :     // Load component setpoint based input into PLANTLOOP data structure
    1321             : 
    1322             :     // METHODOLOGY EMPLOYED:
    1323             :     // calls the Input Processor to retrieve data from input file.
    1324             :     // The format of the Energy+.idd (the EnergyPlus input data dictionary) for the
    1325             :     // following keywords is reflected exactly in this subroutine:
    1326             :     //    PlantEquipmentOperation:ComponentSetPoint
    1327             :     //    PlantEquipmentOperation:ThermalEnergyStorage
    1328             : 
    1329             :     // Using/Aliasing
    1330             :     using namespace DataLoopNode;
    1331             :     using NodeInputManager::GetOnlySingleNode;
    1332             :     using namespace DataSizing;
    1333             :     using EMSManager::CheckIfNodeSetPointManagedByEMS;
    1334             :     using ScheduleManager::GetScheduleIndex;
    1335             :     using SetPointManager::SetUpNewScheduledTESSetPtMgr;
    1336             : 
    1337             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1338             :     int NumAlphas;
    1339             :     int NumNums;
    1340             :     int CompNum;
    1341             :     int CompInNode;
    1342             :     int IOStat;
    1343          15 :     Real64 CompFlowRate(0.0);
    1344          30 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
    1345             :     bool SchemeNameFound;        // Set to FALSE if a match of OpScheme object and OpScheme name is not found
    1346             :     bool NodeEMSSetPointMissing;
    1347          30 :     std::string OnPeakSchedName;
    1348             :     int OnPeakSchedPtr;
    1349          30 :     std::string ChargeSchedName;
    1350             :     int ChargeSchedPtr;
    1351             :     Real64 NonChargCHWTemp;
    1352             :     Real64 OffPeakCHWTemp;
    1353             :     int CompNumA;
    1354             :     int CompNumN;
    1355             :     CtrlType CompOpType; // 1=cooling, 2=dual(or other)
    1356             : 
    1357          15 :     SchemeNameFound = true;
    1358             : 
    1359          30 :     auto objType = (DataLoopNode::ConnectionObjectType)getEnumerationValue(BranchNodeConnections::ConnectionObjectTypeNamesUC,
    1360          45 :                                                                            UtilityRoutines::MakeUPPERCase(CurrentModuleObject));
    1361             : 
    1362          15 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1363          15 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    1364           0 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    1365           0 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    1366             :     }
    1367             : 
    1368          15 :     if (NumSchemes > 0) {
    1369          15 :         for (int Num = 1; Num <= NumSchemes; ++Num) {
    1370          45 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    1371          30 :                 state, CurrentModuleObject, Num, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
    1372          15 :             if (UtilityRoutines::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, state.dataIPShortCut->cAlphaArgs(1))) break;
    1373           0 :             if (Num == NumSchemes) {
    1374           0 :                 ShowSevereError(state,
    1375           0 :                                 LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " +
    1376           0 :                                     CurrentModuleObject + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1377           0 :                 ErrorsFound = true;
    1378           0 :                 SchemeNameFound = false;
    1379             :             }
    1380             :         }
    1381          15 :         if (SchemeNameFound) {
    1382             :             // why only one equip list assumed here? because component setpoint managers have their own lists contained.
    1383          15 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = 1;
    1384          15 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(1);
    1385          15 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps = (NumAlphas - 1) / 5;
    1386             : 
    1387          15 :             if (CurrentModuleObject == "PlantEquipmentOperation:ThermalEnergyStorage") {
    1388             :                 // Read all of the additional parameters for ice storage control scheme and error check various parameters
    1389           1 :                 OnPeakSchedName = state.dataIPShortCut->cAlphaArgs(2);
    1390           1 :                 OnPeakSchedPtr = GetScheduleIndex(state, OnPeakSchedName);
    1391           1 :                 if (OnPeakSchedPtr == 0) {
    1392           0 :                     ShowSevereError(state,
    1393           0 :                                     "Could not find On Peak Schedule " + OnPeakSchedName + " in " + CurrentModuleObject +
    1394           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1395           0 :                     ErrorsFound = true;
    1396             :                 }
    1397           1 :                 ChargeSchedName = state.dataIPShortCut->cAlphaArgs(3);
    1398           1 :                 ChargeSchedPtr = GetScheduleIndex(state, ChargeSchedName);
    1399           1 :                 if (ChargeSchedPtr == 0) {
    1400           0 :                     ShowSevereError(state,
    1401           0 :                                     "Could not find Charging Availability Schedule " + ChargeSchedName + " in " + CurrentModuleObject +
    1402           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1403           0 :                     ErrorsFound = true;
    1404             :                 }
    1405           1 :                 NonChargCHWTemp = state.dataIPShortCut->rNumericArgs(1);
    1406           1 :                 OffPeakCHWTemp = state.dataIPShortCut->rNumericArgs(2);
    1407             :             }
    1408             : 
    1409          15 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps > 0) {
    1410          30 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp.allocate(
    1411          30 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps);
    1412          47 :                 for (CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps; ++CompNum) {
    1413          32 :                     if (CurrentModuleObject == "PlantEquipmentOperation:ComponentSetPoint") {
    1414          30 :                         CompNumA = CompNum * 5;
    1415          30 :                         CompNumN = CompNum;
    1416           2 :                     } else if (CurrentModuleObject == "PlantEquipmentOperation:ThermalEnergyStorage") {
    1417           2 :                         CompNumA = CompNum * 5 + 2;
    1418           2 :                         CompNumN = CompNum + 2;
    1419             :                     }
    1420          64 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).TypeOf =
    1421          64 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 3);
    1422          64 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name =
    1423          64 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 2);
    1424          64 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeName =
    1425          64 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 1);
    1426          32 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeNum =
    1427          64 :                         GetOnlySingleNode(state,
    1428          32 :                                           state.dataIPShortCut->cAlphaArgs(CompNumA - 1),
    1429             :                                           ErrorsFound,
    1430             :                                           objType,
    1431          32 :                                           state.dataIPShortCut->cAlphaArgs(1),
    1432             :                                           DataLoopNode::NodeFluidType::Water,
    1433             :                                           DataLoopNode::ConnectionType::Sensor,
    1434             :                                           NodeInputManager::CompFluidStream::Primary,
    1435          32 :                                           ObjectIsNotParent);
    1436          64 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName =
    1437          64 :                         state.dataIPShortCut->cAlphaArgs(CompNumA);
    1438          32 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum =
    1439          64 :                         GetOnlySingleNode(state,
    1440          32 :                                           state.dataIPShortCut->cAlphaArgs(CompNumA),
    1441             :                                           ErrorsFound,
    1442             :                                           objType,
    1443          32 :                                           state.dataIPShortCut->cAlphaArgs(1),
    1444             :                                           DataLoopNode::NodeFluidType::Water,
    1445             :                                           DataLoopNode::ConnectionType::Sensor,
    1446             :                                           NodeInputManager::CompFluidStream::Primary,
    1447          32 :                                           ObjectIsNotParent);
    1448          32 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointFlowRate =
    1449          32 :                         state.dataIPShortCut->rNumericArgs(CompNumN);
    1450             : 
    1451          32 :                     if (state.dataIPShortCut->rNumericArgs(CompNumN) == AutoSize) {
    1452          15 :                         int Num = 1;
    1453         945 :                         for (; Num <= state.dataSize->SaveNumPlantComps; ++Num) {
    1454         465 :                             CompInNode = state.dataSize->CompDesWaterFlow(Num).SupNode;
    1455         465 :                             CompFlowRate = state.dataSize->CompDesWaterFlow(Num).DesVolFlowRate;
    1456         465 :                             if (CompInNode == state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeNum) {
    1457          15 :                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointFlowRate = CompFlowRate;
    1458             :                             } else {
    1459             :                                 // call error...Demand node must be component inlet node for autosizing
    1460             :                             }
    1461             :                         }
    1462          60 :                         BaseSizer::reportSizerOutput(state,
    1463             :                                                      CurrentModuleObject,
    1464          15 :                                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name,
    1465          30 :                                                      format("Design Water Flow Rate [m3/s] Equipment # {}", Num),
    1466             :                                                      CompFlowRate);
    1467             :                     }
    1468             : 
    1469             :                     {
    1470          64 :                         auto const controlType(state.dataIPShortCut->cAlphaArgs(CompNumA + 1));
    1471          32 :                         if (controlType == "COOLING") {
    1472          18 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::CoolingOp;
    1473          14 :                         } else if (controlType == "HEATING") {
    1474           5 :                             if (CurrentModuleObject == "PlantEquipmentOperation:ThermalEnergyStorage") {
    1475           0 :                                 ShowSevereError(state,
    1476           0 :                                                 "Equipment Operation Mode cannot be HEATING for any equipment found in " +
    1477           0 :                                                     state.dataIPShortCut->cAlphaArgs(1) + " in thermal energy storage control");
    1478           0 :                                 ErrorsFound = true;
    1479             :                             }
    1480           5 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::HeatingOp;
    1481           9 :                         } else if (controlType == "DUAL") {
    1482           9 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::DualOp;
    1483             :                         }
    1484             :                     }
    1485             : 
    1486          78 :                     if ((state.dataIPShortCut->cAlphaArgs(CompNumA + 1) != "COOLING") &&
    1487          41 :                         (state.dataIPShortCut->cAlphaArgs(CompNumA + 1) != "HEATING") && (state.dataIPShortCut->cAlphaArgs(CompNumA + 1) != "DUAL")) {
    1488           0 :                         ShowSevereError(state,
    1489           0 :                                         "Equipment Operation Mode should be either HEATING or COOLING or DUAL mode, for " + CurrentModuleObject +
    1490           0 :                                             '=' + state.dataIPShortCut->cAlphaArgs(1));
    1491             :                     }
    1492             : 
    1493          32 :                     if (CurrentModuleObject == "PlantEquipmentOperation:ThermalEnergyStorage") {
    1494             : 
    1495             :                         // Special case for ThermalStorage:Ice:XXXX objects which can only be dual (cf #6958)
    1496           6 :                         if (((state.dataIPShortCut->cAlphaArgs(CompNumA - 3) == "THERMALSTORAGE:ICE:SIMPLE") ||
    1497           3 :                              (state.dataIPShortCut->cAlphaArgs(CompNumA - 3) == "THERMALSTORAGE:ICE:DETAILED")) &&
    1498           1 :                             (state.dataIPShortCut->cAlphaArgs(CompNumA + 1) != "DUAL")) {
    1499             : 
    1500           0 :                             ShowWarningError(state,
    1501           0 :                                              "Equipment Operation Mode was reset to 'DUAL' for Component '" +
    1502           0 :                                                  state.dataIPShortCut->cAlphaArgs(CompNumA - 2) + "' in " + CurrentModuleObject + "='" +
    1503           0 :                                                  state.dataIPShortCut->cAlphaArgs(1) + "'.");
    1504           0 :                             ShowContinueError(state,
    1505           0 :                                               "Equipment Operation Mode can only be 'DUAL' for " + state.dataIPShortCut->cAlphaArgs(CompNumA - 3) +
    1506             :                                                   " objects.");
    1507             : 
    1508           0 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::DualOp;
    1509             :                         }
    1510             : 
    1511             :                         // This block forces CompOpType to be either Cooling if explicitly provided, all other cases = Dual
    1512           2 :                         switch (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType) {
    1513           1 :                         case CtrlType::DualOp:
    1514           1 :                             CompOpType = CtrlType::CoolingOp;
    1515           1 :                             break;
    1516           1 :                         case CtrlType::CoolingOp:
    1517           1 :                             CompOpType = CtrlType::HeatingOp;
    1518           1 :                             break;
    1519           0 :                         case CtrlType::HeatingOp:
    1520           0 :                             CompOpType = CtrlType::CoolingOp;
    1521           0 :                             break;
    1522           0 :                         default:
    1523           0 :                             assert(false);
    1524             :                         }
    1525             : 
    1526             :                         // for each component, a new scheduled setpoint manager needs to be defined to internally generate the more
    1527             :                         // detailed input that is necessary to get thermal energy storage to work from the simpler input.
    1528           2 :                         SetUpNewScheduledTESSetPtMgr(
    1529             :                             state,
    1530             :                             OnPeakSchedPtr,
    1531             :                             ChargeSchedPtr,
    1532             :                             NonChargCHWTemp,
    1533             :                             OffPeakCHWTemp,
    1534             :                             CompOpType,
    1535           2 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum);
    1536             :                     }
    1537             : 
    1538             :                     // check that setpoint node has valid setpoint managers or EMS
    1539             : 
    1540          32 :                     switch (state.dataPlnt->PlantLoop(LoopNum).LoopDemandCalcScheme) {
    1541          24 :                     case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1542          24 :                         if (state.dataLoopNodes
    1543          24 :                                 ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1544          24 :                                 .TempSetPoint == SensedNodeFlagValue) {
    1545           0 :                             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1546           0 :                                 ShowSevereError(state,
    1547           0 :                                                 "Missing temperature setpoint for " + CurrentModuleObject + " named " +
    1548           0 :                                                     state.dataIPShortCut->cAlphaArgs(1));
    1549           0 :                                 ShowContinueError(
    1550             :                                     state,
    1551           0 :                                     "A temperature setpoint is needed at the node named " +
    1552           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1553           0 :                                 if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1554           0 :                                     ShowContinueError(state,
    1555           0 :                                                       "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1556             :                                                           "\", Plant Loop Demand Calculation Scheme=SingleSetpoint");
    1557           0 :                                 } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1558             :                                            LoopType::Condenser) { // not applicable to Condenser loops
    1559             :                                 }
    1560           0 :                                 ShowContinueError(state, " Use a setpoint manager to place a single temperature setpoint on the node");
    1561           0 :                                 ErrorsFound = true;
    1562             :                             } else {
    1563             :                                 // need call to EMS to check node
    1564           0 :                                 NodeEMSSetPointMissing = false;
    1565           0 :                                 CheckIfNodeSetPointManagedByEMS(
    1566             :                                     state,
    1567           0 :                                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum,
    1568             :                                     EMSManager::SPControlType::TemperatureSetPoint,
    1569             :                                     NodeEMSSetPointMissing);
    1570           0 :                                 if (NodeEMSSetPointMissing) {
    1571           0 :                                     ShowSevereError(state,
    1572           0 :                                                     "Missing temperature setpoint for " + CurrentModuleObject + " named " +
    1573           0 :                                                         state.dataIPShortCut->cAlphaArgs(1));
    1574           0 :                                     ShowContinueError(
    1575             :                                         state,
    1576           0 :                                         "A temperature setpoint is needed at the node named " +
    1577           0 :                                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1578           0 :                                     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1579           0 :                                         ShowContinueError(state,
    1580           0 :                                                           "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1581             :                                                               "\", Plant Loop Demand Calculation Scheme=SingleSetpoint");
    1582           0 :                                     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1583             :                                                LoopType::Condenser) { // not applicable to Condenser loops
    1584             :                                     }
    1585           0 :                                     ShowContinueError(state,
    1586             :                                                       " Use a setpoint manager or EMS actuator to place a single temperature setpoint on node");
    1587           0 :                                     ErrorsFound = true;
    1588             :                                 }
    1589             :                             }
    1590             :                         }
    1591          24 :                         break;
    1592             :                     }
    1593           8 :                     case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1594           8 :                         if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType == CtrlType::CoolingOp) {
    1595           4 :                             if (state.dataLoopNodes
    1596           4 :                                     ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1597           4 :                                     .TempSetPointHi == SensedNodeFlagValue) {
    1598           0 :                                 if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1599           0 :                                     ShowSevereError(state,
    1600           0 :                                                     "Missing temperature high setpoint for " + CurrentModuleObject + " named " +
    1601           0 :                                                         state.dataIPShortCut->cAlphaArgs(1));
    1602           0 :                                     ShowContinueError(
    1603             :                                         state,
    1604           0 :                                         "A temperature high setpoint is needed at the node named " +
    1605           0 :                                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1606           0 :                                     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1607           0 :                                         ShowContinueError(state,
    1608           0 :                                                           "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1609             :                                                               "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1610           0 :                                     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1611             :                                                LoopType::Condenser) { // not applicable to Condenser loops
    1612             :                                     }
    1613           0 :                                     ShowContinueError(state, " Use a setpoint manager to place a dual temperature setpoint on the node");
    1614           0 :                                     ErrorsFound = true;
    1615             :                                 } else {
    1616             :                                     // need call to EMS to check node
    1617           0 :                                     NodeEMSSetPointMissing = false;
    1618           0 :                                     CheckIfNodeSetPointManagedByEMS(
    1619             :                                         state,
    1620           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum,
    1621             :                                         EMSManager::SPControlType::TemperatureMaxSetPoint,
    1622             :                                         NodeEMSSetPointMissing);
    1623           0 :                                     if (NodeEMSSetPointMissing) {
    1624           0 :                                         ShowSevereError(state,
    1625           0 :                                                         "Missing high temperature setpoint for " + CurrentModuleObject + " named " +
    1626           0 :                                                             state.dataIPShortCut->cAlphaArgs(1));
    1627           0 :                                         ShowContinueError(
    1628             :                                             state,
    1629           0 :                                             "A high temperature setpoint is needed at the node named " +
    1630           0 :                                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1631           0 :                                         if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1632           0 :                                             ShowContinueError(state,
    1633           0 :                                                               "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1634             :                                                                   "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1635           0 :                                         } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1636             :                                                    LoopType::Condenser) { // not applicable to Condenser loops
    1637             :                                         }
    1638           0 :                                         ShowContinueError(
    1639             :                                             state, " Use a setpoint manager or EMS actuator to place a dual or high temperature setpoint on node");
    1640           0 :                                         ErrorsFound = true;
    1641             :                                     }
    1642             :                                 }
    1643             :                             }
    1644           4 :                         } else if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType ==
    1645             :                                    CtrlType::HeatingOp) {
    1646           4 :                             if (state.dataLoopNodes
    1647           4 :                                     ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1648           4 :                                     .TempSetPointLo == SensedNodeFlagValue) {
    1649           0 :                                 if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1650           0 :                                     ShowSevereError(state,
    1651           0 :                                                     "Missing temperature low setpoint for " + CurrentModuleObject + " named " +
    1652           0 :                                                         state.dataIPShortCut->cAlphaArgs(1));
    1653           0 :                                     ShowContinueError(
    1654             :                                         state,
    1655           0 :                                         "A temperature low setpoint is needed at the node named " +
    1656           0 :                                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1657           0 :                                     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1658           0 :                                         ShowContinueError(state,
    1659           0 :                                                           "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1660             :                                                               "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1661           0 :                                     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1662             :                                                LoopType::Condenser) { // not applicable to Condenser loops
    1663             :                                     }
    1664           0 :                                     ShowContinueError(state, " Use a setpoint manager to place a dual temperature setpoint on the node");
    1665           0 :                                     ErrorsFound = true;
    1666             :                                 } else {
    1667             :                                     // need call to EMS to check node
    1668           0 :                                     NodeEMSSetPointMissing = false;
    1669           0 :                                     CheckIfNodeSetPointManagedByEMS(
    1670             :                                         state,
    1671           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum,
    1672             :                                         EMSManager::SPControlType::TemperatureMinSetPoint,
    1673             :                                         NodeEMSSetPointMissing);
    1674           0 :                                     CheckIfNodeSetPointManagedByEMS(
    1675             :                                         state,
    1676           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum,
    1677             :                                         EMSManager::SPControlType::TemperatureMaxSetPoint,
    1678             :                                         NodeEMSSetPointMissing);
    1679           0 :                                     if (NodeEMSSetPointMissing) {
    1680           0 :                                         ShowSevereError(state,
    1681           0 :                                                         "Missing low temperature setpoint for " + CurrentModuleObject + " named " +
    1682           0 :                                                             state.dataIPShortCut->cAlphaArgs(1));
    1683           0 :                                         ShowContinueError(
    1684             :                                             state,
    1685           0 :                                             "A low temperature setpoint is needed at the node named " +
    1686           0 :                                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1687           0 :                                         if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1688           0 :                                             ShowContinueError(state,
    1689           0 :                                                               "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1690             :                                                                   "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1691           0 :                                         } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1692             :                                                    LoopType::Condenser) { // not applicable to Condenser loops
    1693             :                                         }
    1694           0 :                                         ShowContinueError(
    1695             :                                             state, " Use a setpoint manager or EMS actuator to place a dual or low temperature setpoint on node");
    1696           0 :                                         ErrorsFound = true;
    1697             :                                     }
    1698             :                                 }
    1699             :                             }
    1700           0 :                         } else if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType == CtrlType::DualOp) {
    1701           0 :                             if ((state.dataLoopNodes
    1702           0 :                                      ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1703           0 :                                      .TempSetPointHi == SensedNodeFlagValue) ||
    1704             :                                 (state.dataLoopNodes
    1705           0 :                                      ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1706           0 :                                      .TempSetPointLo == SensedNodeFlagValue)) {
    1707           0 :                                 if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1708           0 :                                     ShowSevereError(state,
    1709           0 :                                                     "Missing temperature dual setpoints for " + CurrentModuleObject + " named " +
    1710           0 :                                                         state.dataIPShortCut->cAlphaArgs(1));
    1711           0 :                                     ShowContinueError(
    1712             :                                         state,
    1713           0 :                                         "A dual temperaturesetpoint is needed at the node named " +
    1714           0 :                                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1715           0 :                                     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1716           0 :                                         ShowContinueError(state,
    1717           0 :                                                           "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1718             :                                                               "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1719           0 :                                     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1720             :                                                LoopType::Condenser) { // not applicable to Condenser loops
    1721             :                                     }
    1722           0 :                                     ShowContinueError(state, " Use a setpoint manager to place a dual temperature setpoint on the node");
    1723           0 :                                     ErrorsFound = true;
    1724             :                                 } else {
    1725             :                                     // need call to EMS to check node
    1726           0 :                                     NodeEMSSetPointMissing = false;
    1727           0 :                                     CheckIfNodeSetPointManagedByEMS(
    1728             :                                         state,
    1729           0 :                                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum,
    1730             :                                         EMSManager::SPControlType::TemperatureMinSetPoint,
    1731             :                                         NodeEMSSetPointMissing);
    1732           0 :                                     if (NodeEMSSetPointMissing) {
    1733           0 :                                         ShowSevereError(state,
    1734           0 :                                                         "Missing dual temperature setpoint for " + CurrentModuleObject + " named " +
    1735           0 :                                                             state.dataIPShortCut->cAlphaArgs(1));
    1736           0 :                                         ShowContinueError(
    1737             :                                             state,
    1738           0 :                                             "A dual temperature setpoint is needed at the node named " +
    1739           0 :                                                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName);
    1740           0 :                                         if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1741           0 :                                             ShowContinueError(state,
    1742           0 :                                                               "PlantLoop=\"" + state.dataPlnt->PlantLoop(LoopNum).Name +
    1743             :                                                                   "\", Plant Loop Demand Calculation Scheme=DualSetpointDeadband");
    1744           0 :                                         } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop ==
    1745             :                                                    LoopType::Condenser) { // not applicable to Condenser loops
    1746             :                                         }
    1747           0 :                                         ShowContinueError(state,
    1748             :                                                           " Use a setpoint manager or EMS actuator to place a dual temperature setpoint on node");
    1749           0 :                                         ErrorsFound = true;
    1750             :                                     }
    1751             :                                 }
    1752             :                             }
    1753             :                         }
    1754           8 :                         break;
    1755             :                     }
    1756           0 :                     default:
    1757           0 :                         break;
    1758             :                     }
    1759             :                 }
    1760             :             } else {
    1761           0 :                 ShowSevereError(state, CurrentModuleObject + " = \"" + state.dataIPShortCut->cAlphaArgs(1) + "\", specified without any machines.");
    1762           0 :                 ErrorsFound = true;
    1763             :             }
    1764             :         }
    1765             :     } else {
    1766           0 :         ShowSevereError(state,
    1767           0 :                         LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " + CurrentModuleObject +
    1768           0 :                             " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1769           0 :         ErrorsFound = true;
    1770             :     }
    1771          15 : }
    1772             : 
    1773           6 : void GetUserDefinedOpSchemeInput(EnergyPlusData &state,
    1774             :                                  std::string &CurrentModuleObject, // for ease in renaming
    1775             :                                  int const NumSchemes,             // May be set here and passed on
    1776             :                                  int const LoopNum,                // May be set here and passed on
    1777             :                                  int const SchemeNum,              // May be set here and passed on
    1778             :                                  bool &ErrorsFound                 // May be set here and passed on
    1779             : )
    1780             : {
    1781             : 
    1782             :     // SUBROUTINE INFORMATION:
    1783             :     //       AUTHOR         <author>
    1784             :     //       DATE WRITTEN   <date_written>
    1785             :     //       MODIFIED       na
    1786             :     //       RE-ENGINEERED  na
    1787             : 
    1788             :     // PURPOSE OF THIS SUBROUTINE:
    1789             :     // <description>
    1790             : 
    1791             :     // Using/Aliasing
    1792             :     using namespace DataPlant;
    1793             : 
    1794             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1795             :     int NumAlphas;
    1796             :     int NumNums;
    1797             :     int Num;
    1798             :     int CompNum;
    1799             :     int IOStat;
    1800             :     bool SchemeNameFound;        // Set to FALSE if a match of OpScheme object and OpScheme name is not found
    1801          12 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
    1802             :     int StackMngrNum;            // local temporary for Erl program calling manager index
    1803             : 
    1804           6 :     SchemeNameFound = true;
    1805             : 
    1806           6 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1807           4 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    1808           2 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    1809           2 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    1810             :     }
    1811             : 
    1812           6 :     if (NumSchemes > 0) {
    1813             : 
    1814          12 :         for (Num = 1; Num <= NumSchemes; ++Num) {
    1815          84 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1816             :                                                                      CurrentModuleObject,
    1817             :                                                                      Num,
    1818          12 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1819             :                                                                      NumAlphas,
    1820          12 :                                                                      state.dataIPShortCut->rNumericArgs,
    1821             :                                                                      NumNums,
    1822             :                                                                      IOStat,
    1823          12 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1824          12 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1825          12 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1826          12 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1827          12 :             if (UtilityRoutines::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, state.dataIPShortCut->cAlphaArgs(1)))
    1828           6 :                 break;               // found the correct one
    1829           6 :             if (Num == NumSchemes) { // did not find it
    1830           0 :                 ShowSevereError(state,
    1831           0 :                                 LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " +
    1832           0 :                                     CurrentModuleObject + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1833           0 :                 ErrorsFound = true;
    1834           0 :                 SchemeNameFound = false;
    1835             :             }
    1836             :         }
    1837           6 :         if (SchemeNameFound) {
    1838           6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = 1;
    1839           6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(1);
    1840             : 
    1841           6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps = (NumAlphas - 3) / 2;
    1842           6 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps > 0) {
    1843          12 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp.allocate(
    1844          12 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps);
    1845          14 :                 for (CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps; ++CompNum) {
    1846          16 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).TypeOf =
    1847          16 :                         state.dataIPShortCut->cAlphaArgs(CompNum * 2 + 2);
    1848          16 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name =
    1849          16 :                         state.dataIPShortCut->cAlphaArgs(CompNum * 2 + 3);
    1850             : 
    1851             :                     // Setup EMS actuators for machines' MyLoad.
    1852          40 :                     SetupEMSActuator(
    1853             :                         state,
    1854             :                         "Plant Equipment Operation",
    1855          16 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + ':' +
    1856           8 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name,
    1857             :                         "Distributed Load Rate",
    1858             :                         "[W]",
    1859           8 :                         state.dataPlantCondLoopOp->lDummy,
    1860          24 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).EMSActuatorDispatchedLoadValue);
    1861             :                     // TODO: I think this should be a sensor really
    1862          32 :                     SetupEMSInternalVariable(
    1863             :                         state,
    1864             :                         "Component Remaining Current Demand Rate",
    1865          16 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + ':' +
    1866           8 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name,
    1867             :                         "[W]",
    1868          24 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).EMSIntVarRemainingLoadValue);
    1869             :                 }
    1870             :             }
    1871           6 :             StackMngrNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataRuntimeLang->EMSProgramCallManager);
    1872           6 :             if (StackMngrNum > 0) { // found it
    1873           3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ErlSimProgramMngr = StackMngrNum;
    1874             :             } else {
    1875           3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).simPluginLocation =
    1876           3 :                     state.dataPluginManager->pluginManager->getLocationOfUserDefinedPlugin(state, state.dataIPShortCut->cAlphaArgs(2));
    1877           3 :                 if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).simPluginLocation == -1) {
    1878           0 :                     ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
    1879           0 :                     ShowContinueError(state, "Entered in " + CurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
    1880           0 :                     ShowContinueError(state, "Not found as either an EMS Program Manager or a Python Plugin instance.");
    1881           0 :                     ErrorsFound = true;
    1882             :                 }
    1883             :             }
    1884           6 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    1885           1 :                 StackMngrNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataRuntimeLang->EMSProgramCallManager);
    1886           1 :                 if (StackMngrNum > 0) { // found it
    1887           1 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ErlInitProgramMngr = StackMngrNum;
    1888             :                 } else {
    1889           0 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).initPluginLocation =
    1890           0 :                         state.dataPluginManager->pluginManager->getLocationOfUserDefinedPlugin(state, state.dataIPShortCut->cAlphaArgs(3));
    1891           0 :                     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).initPluginLocation == -1) {
    1892           0 :                         ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + '=' + state.dataIPShortCut->cAlphaArgs(3));
    1893           0 :                         ShowContinueError(state, "Entered in " + CurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
    1894           0 :                         ShowContinueError(state, "Not found as either an EMS Program Manager or a Python Plugin instance.");
    1895           0 :                         ErrorsFound = true;
    1896             :                     }
    1897             :                 }
    1898             :             }
    1899             : 
    1900             :             // setup internal variable for Supply Side Current Demand Rate [W]
    1901          18 :             SetupEMSInternalVariable(state,
    1902             :                                      "Supply Side Current Demand Rate",
    1903           6 :                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name,
    1904             :                                      "[W]",
    1905          18 :                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EMSIntVarLoopDemandRate);
    1906             :         }
    1907             : 
    1908             :     } else {
    1909           0 :         ShowSevereError(state,
    1910           0 :                         LoopOpSchemeObj + " = \"" + state.dataPlnt->PlantLoop(LoopNum).OperationScheme + "\", could not find " + CurrentModuleObject +
    1911           0 :                             " = \"" + state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + "\".");
    1912           0 :         ErrorsFound = true;
    1913             :     }
    1914           6 : }
    1915             : 
    1916             : // End of GetInput subroutines for the Module
    1917             : //******************************************************************************
    1918             : 
    1919             : // Beginning Initialization Section of the Plant Loop Module
    1920             : //******************************************************************************
    1921             : 
    1922    30644847 : void InitLoadDistribution(EnergyPlusData &state, bool const FirstHVACIteration)
    1923             : {
    1924             :     // SUBROUTINE INFORMATION:
    1925             :     //       AUTHOR:          Dan Fisher
    1926             :     //       DATE WRITTEN:    July 2010
    1927             :     //       REVISED:
    1928             : 
    1929             :     // PURPOSE OF THIS SUBROUTINE:
    1930             :     // This subroutine scans equipment lists and matches a particular
    1931             :     // plant component with a component on the list.  Pointers to the
    1932             :     // operation scheme and equipment list are saved on the plant data
    1933             :     // structure to facilitate a new load management routine that calls
    1934             :     // ManageLoadDistribution for every component.
    1935             : 
    1936             :     // Using/Aliasing
    1937             :     using EMSManager::ManageEMS;
    1938             :     using ScheduleManager::GetCurrentScheduleValue;
    1939             :     using ScheduleManager::GetScheduleIndex;
    1940             : 
    1941             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1942             :     int LoopPtr;
    1943             :     DataPlant::LoopSideLocation LoopSidePtr;
    1944             :     int BranchPtr;
    1945             :     int CompPtr;
    1946    30644847 :     PlantLocation plantLoc{};
    1947             :     int Index;
    1948             :     int OpSchemePtr;
    1949             :     int thisSchemeNum;
    1950             : 
    1951             :     bool FoundScheme;
    1952             :     bool FoundSchemeMatch;
    1953             :     //  LOGICAL, SAVE                     :: FirstHVACInitsDone = .FALSE.
    1954             :     //  LOGICAL, SAVE                     :: MyEnvrnFlag = .TRUE.
    1955             :     DataPlant::PlantEquipmentType Type;
    1956             :     int CompOpNum;
    1957             :     int OldNumOpSchemes;
    1958             :     int NewNumEquipLists;
    1959             :     int NewNumOpSchemes;
    1960             :     int NumSearchResults;
    1961             :     bool GetInputOK; // successful Get Input
    1962             : 
    1963             :     bool errFlag1;
    1964             :     bool errFlag2;
    1965             :     Real64 HighestRange;
    1966             : 
    1967             :     // Object Data
    1968             : 
    1969    30644847 :     errFlag2 = false;
    1970             :     // Get Input
    1971    30644847 :     if (state.dataPlantCondLoopOp->GetPlantOpInput) {
    1972         442 :         GetPlantOperationInput(state, GetInputOK);
    1973         442 :         if (GetInputOK) {
    1974         442 :             GetOperationSchemeInput(state);
    1975         442 :             state.dataPlantCondLoopOp->GetPlantOpInput = false;
    1976             :         } else {
    1977           0 :             return;
    1978             :         }
    1979             :     }
    1980             : 
    1981             :     // ONE TIME INITS
    1982    30644847 :     if (state.dataPlantCondLoopOp->InitLoadDistributionOneTimeFlag) {
    1983             :         // Set up 'component' to 'op scheme' pointers in Plant data structure
    1984             :         // We're looking for matches between a component on a PlantLoop.OpScheme.List()
    1985             :         // and the same component in the PlantLoop.LoopSide.Branch.Comp() data structure
    1986             : 
    1987             :         // first loop over main operation scheme data and finish filling out indexes to plant topology for the components in the lists
    1988        1549 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    1989        1107 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    1990        2335 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    1991        1228 :                 auto &this_op_scheme(this_plant_loop.OpScheme(OpNum));
    1992        2614 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    1993        1386 :                     auto &this_equip_list(this_op_scheme.EquipList(ListNum));
    1994        2987 :                     for (int EquipNum = 1, EquipNum_end = this_equip_list.NumComps; EquipNum <= EquipNum_end; ++EquipNum) {
    1995        1601 :                         auto &this_equip(this_equip_list.Comp(EquipNum));
    1996        1601 :                         Type = static_cast<DataPlant::PlantEquipmentType>(
    1997        3202 :                             getEnumerationValue(PlantEquipTypeNamesUC, UtilityRoutines::MakeUPPERCase(this_equip.TypeOf)));
    1998        1601 :                         errFlag1 = false;
    1999        1601 :                         PlantUtilities::ScanPlantLoopsForObject(state, this_equip.Name, Type, plantLoc, errFlag1, _, _, NumSearchResults, _, LoopNum);
    2000             : 
    2001        1601 :                         if (errFlag1) {
    2002           0 :                             ShowSevereError(state, "InitLoadDistribution: Equipment specified for operation scheme not found on correct loop");
    2003           0 :                             ShowContinueError(state, "Operation Scheme name = " + this_op_scheme.Name);
    2004           0 :                             ShowContinueError(state, "Loop name = " + this_plant_loop.Name);
    2005           0 :                             ShowContinueError(state, "Component name = " + this_equip.Name);
    2006           0 :                             ShowFatalError(state, "InitLoadDistribution: Simulation terminated because of error in operation scheme.");
    2007             :                         }
    2008             : 
    2009        1601 :                         this_equip.LoopNumPtr = plantLoc.loopNum;
    2010        1601 :                         this_equip.LoopSideNumPtr = plantLoc.loopSideNum;
    2011        1601 :                         this_equip.BranchNumPtr = plantLoc.branchNum;
    2012        1601 :                         this_equip.CompNumPtr = plantLoc.compNum;
    2013             : 
    2014        1601 :                         if (ValidLoopEquipTypes[static_cast<int>(Type)] == LoopType::Plant && this_plant_loop.TypeOfLoop == LoopType::Condenser) {
    2015           0 :                             ShowSevereError(state,
    2016           0 :                                             "InitLoadDistribution: CondenserLoop=\"" + this_plant_loop.Name + "\", Operation Scheme=\"" +
    2017           0 :                                                 this_plant_loop.OperationScheme + "\",");
    2018           0 :                             ShowContinueError(state,
    2019           0 :                                               "Scheme type=" + this_op_scheme.TypeOf + ", Name=\"" + this_op_scheme.Name +
    2020             :                                                   "\" includes equipment that is not valid on a Condenser Loop");
    2021           0 :                             ShowContinueError(state,
    2022           0 :                                               format("Component {} not allowed as supply equipment on this type of loop.",
    2023           0 :                                                      PlantEquipTypeNames[static_cast<int>(Type)]));
    2024           0 :                             ShowContinueError(state, "Component name = " + this_equip.Name);
    2025           0 :                             errFlag2 = true;
    2026             :                         }
    2027        1601 :                         if (ValidLoopEquipTypes[static_cast<int>(Type)] == LoopType::Condenser && this_plant_loop.TypeOfLoop == LoopType::Plant) {
    2028           0 :                             ShowSevereError(state,
    2029           0 :                                             "InitLoadDistribution: PlantLoop=\"" + this_plant_loop.Name + "\", Operation Scheme=\"" +
    2030           0 :                                                 this_plant_loop.OperationScheme + "\",");
    2031           0 :                             ShowContinueError(state,
    2032           0 :                                               "Scheme type=" + this_op_scheme.TypeOf + ", Name=\"" + this_op_scheme.Name +
    2033             :                                                   "\" includes equipment that is not valid on a Plant Loop");
    2034           0 :                             ShowContinueError(state,
    2035           0 :                                               format("Component {} not allowed as supply equipment on this type of loop.",
    2036           0 :                                                      PlantEquipTypeNames[static_cast<int>(Type)]));
    2037           0 :                             ShowContinueError(state, "Component name = " + this_equip.Name);
    2038           0 :                             errFlag2 = true;
    2039             :                         }
    2040             : 
    2041             :                     } // Equipment on List
    2042             :                 }     // List
    2043             :             }         // operation scheme
    2044             :         }             // loop
    2045             : 
    2046             :         // second loop, fill op schemes info at each component.
    2047        1549 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2048        1107 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    2049        2335 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2050        1228 :                 auto &this_op_scheme(this_plant_loop.OpScheme(OpNum));
    2051        2614 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2052        1386 :                     auto &this_equip_list(this_op_scheme.EquipList(ListNum));
    2053        2987 :                     for (int EquipNum = 1, EquipNum_end = this_equip_list.NumComps; EquipNum <= EquipNum_end; ++EquipNum) {
    2054        1601 :                         auto &this_equip(this_equip_list.Comp(EquipNum));
    2055             :                         // dereference indices (stored in previous loop)
    2056        1601 :                         plantLoc.loopNum = this_equip.LoopNumPtr;
    2057        1601 :                         plantLoc.loopSideNum = this_equip.LoopSideNumPtr;
    2058        1601 :                         plantLoc.branchNum = this_equip.BranchNumPtr;
    2059        1601 :                         plantLoc.compNum = this_equip.CompNumPtr;
    2060        1601 :                         auto &dummy_loop_equip(DataPlant::CompData::getPlantComponent(state, plantLoc));
    2061             : 
    2062        1601 :                         if (dummy_loop_equip.NumOpSchemes == 0) {
    2063             :                             // first op scheme for this component, allocate OpScheme and its EquipList to size 1
    2064        1331 :                             dummy_loop_equip.OpScheme.allocate(1);
    2065        1331 :                             auto &dummy_op_scheme_1(dummy_loop_equip.OpScheme(1));
    2066        1331 :                             dummy_op_scheme_1.EquipList.allocate(1);
    2067        1331 :                             dummy_loop_equip.NumOpSchemes = 1;
    2068        1331 :                             dummy_op_scheme_1.NumEquipLists = 1;
    2069             :                             // store pointers
    2070        1331 :                             dummy_op_scheme_1.OpSchemePtr = OpNum;
    2071        1331 :                             dummy_op_scheme_1.EquipList(1).ListPtr = ListNum;
    2072        1331 :                             dummy_op_scheme_1.EquipList(1).CompPtr = EquipNum;
    2073         270 :                         } else if (dummy_loop_equip.NumOpSchemes > 0) { // already an op scheme
    2074         270 :                             OldNumOpSchemes = dummy_loop_equip.NumOpSchemes;
    2075             : 
    2076             :                             // could be new list on existing scheme or new scheme with new list.  Check and see
    2077         270 :                             FoundSchemeMatch = false;
    2078         450 :                             for (thisSchemeNum = 1; thisSchemeNum <= OldNumOpSchemes; ++thisSchemeNum) { // Loop index used below
    2079             :                                 // compare the OpScheme index, 'opnum', in the PlantLoop()%OpScheme()data structure
    2080             :                                 // with the OpSchemePtr in the PlantLoop()%LoopSide()%Branch()%Comp() data structure.
    2081         270 :                                 if (OpNum != dummy_loop_equip.OpScheme(thisSchemeNum).OpSchemePtr) continue;
    2082          90 :                                 FoundSchemeMatch = true;
    2083          90 :                                 break;
    2084             :                             }
    2085         270 :                             if (FoundSchemeMatch) { // op scheme already exists, but need to add a list to the existing OpScheme
    2086          90 :                                 auto &this_op_scheme(dummy_loop_equip.OpScheme(thisSchemeNum));
    2087          90 :                                 NewNumEquipLists = this_op_scheme.NumEquipLists + 1;
    2088          90 :                                 this_op_scheme.EquipList.redimension(NewNumEquipLists);
    2089          90 :                                 this_op_scheme.NumEquipLists = NewNumEquipLists;
    2090          90 :                                 this_op_scheme.EquipList(NewNumEquipLists).ListPtr = ListNum;
    2091          90 :                                 this_op_scheme.EquipList(NewNumEquipLists).CompPtr = EquipNum;
    2092             :                             } else { // !FoundSchemeMatch: Add new op scheme and a new list
    2093         180 :                                 NewNumOpSchemes = OldNumOpSchemes + 1;
    2094         180 :                                 dummy_loop_equip.OpScheme.redimension(NewNumOpSchemes);
    2095         180 :                                 auto &new_op_scheme(dummy_loop_equip.OpScheme(NewNumOpSchemes));
    2096         180 :                                 new_op_scheme.EquipList.allocate(1);
    2097         180 :                                 dummy_loop_equip.NumOpSchemes = NewNumOpSchemes;
    2098         180 :                                 new_op_scheme.NumEquipLists = 1;
    2099         180 :                                 new_op_scheme.OpSchemePtr = OpNum;
    2100         180 :                                 new_op_scheme.EquipList(1).ListPtr = ListNum;
    2101         180 :                                 new_op_scheme.EquipList(1).CompPtr = EquipNum;
    2102             :                             }
    2103             :                         }
    2104             : 
    2105             :                     } // Equipment on List
    2106             :                 }     // List
    2107             :             }         // operation scheme
    2108             :         }             // loop
    2109             : 
    2110             :         // check the pointers to see if a single component is attached to more than one type of control scheme
    2111        1549 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2112        1107 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    2113        3321 :             for (DataPlant::LoopSideLocation LoopSideNum : DataPlant::LoopSideKeys) {
    2114        2214 :                 auto const &this_loop_side(this_plant_loop.LoopSide(LoopSideNum));
    2115       15076 :                 for (int BranchNum = 1, BranchNum_end = this_loop_side.TotalBranches; BranchNum <= BranchNum_end; ++BranchNum) {
    2116       12862 :                     auto const &this_branch(this_loop_side.Branch(BranchNum));
    2117       25797 :                     for (int CompNum = 1, CompNum_end = this_branch.TotalComponents; CompNum <= CompNum_end; ++CompNum) {
    2118       12935 :                         auto const &this_component(this_branch.Comp(CompNum));
    2119       12935 :                         if (allocated(this_component.OpScheme)) {
    2120        2842 :                             for (Index = 1; Index <= this_component.NumOpSchemes; ++Index) {
    2121        1511 :                                 OpSchemePtr = this_component.OpScheme(Index).OpSchemePtr;
    2122        1511 :                                 if (OpSchemePtr == 0) {
    2123           0 :                                     ShowSevereError(state,
    2124           0 :                                                     "InitLoadDistribution: no operation scheme index found for component on PlantLoop=" +
    2125             :                                                         this_plant_loop.Name);
    2126           0 :                                     ShowContinueError(state, "Component name = " + this_component.Name);
    2127           0 :                                     errFlag2 = true;
    2128             :                                 }
    2129        1511 :                                 DataPlant::OpScheme SchemeType{};
    2130        1511 :                                 if (Index == 1) {
    2131        1331 :                                     SchemeType = this_plant_loop.OpScheme(OpSchemePtr).Type;
    2132             :                                 } else {
    2133         180 :                                     if (SchemeType != this_plant_loop.OpScheme(OpSchemePtr).Type) {
    2134             :                                         // CALL FATAL ERROR 'component may not be specified on two types of operation schemes
    2135             :                                         // Cannot different op schemes be in effect at different times?
    2136             :                                         //  I thought this would be allowed??
    2137             :                                     }
    2138             :                                 }
    2139             :                             }
    2140             :                         }
    2141             :                     }
    2142             :                 }
    2143             :             }
    2144             :         }
    2145             : 
    2146             :         // fill out information on which equipment list is the "last" meaning it has the highest upper limit for load range
    2147        1549 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2148        1107 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    2149        2335 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2150        1228 :                 auto &this_op_scheme(this_plant_loop.OpScheme(OpNum));
    2151             :                 // skip non-load based op schemes
    2152        1228 :                 if ((this_op_scheme.Type != OpScheme::HeatingRB) && (this_op_scheme.Type != OpScheme::CoolingRB)) continue;
    2153        1159 :                 HighestRange = 0.0;
    2154        2469 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2155        1310 :                     HighestRange = max(HighestRange, this_op_scheme.EquipList(ListNum).RangeUpperLimit);
    2156             :                 } // List
    2157        2469 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2158        1310 :                     if (HighestRange == this_op_scheme.EquipList(ListNum).RangeUpperLimit) {
    2159        1159 :                         this_op_scheme.EquipListNumForLastStage = ListNum;
    2160             :                     }
    2161             :                 }
    2162             :             } // operation scheme
    2163             :         }     // loop
    2164             : 
    2165         442 :         state.dataPlantCondLoopOp->InitLoadDistributionOneTimeFlag = false;
    2166             :     }
    2167             : 
    2168    30644847 :     if (state.dataPlnt->AnyEMSPlantOpSchemesInModel) { // Execute any Initialization EMS program calling managers for User-Defined operation.
    2169     1943560 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2170     1554848 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    2171     3109696 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2172     1554848 :                 auto &this_op_scheme(this_plant_loop.OpScheme(OpNum));
    2173     1554848 :                 if (this_op_scheme.Type == OpScheme::EMS) {
    2174     1166136 :                     if (state.dataGlobal->BeginEnvrnFlag && this_op_scheme.MyEnvrnFlag) {
    2175          30 :                         if (this_op_scheme.ErlInitProgramMngr > 0) {
    2176             :                             bool anyEMSRan;
    2177           5 :                             ManageEMS(state, EMSManager::EMSCallFrom::UserDefinedComponentModel, anyEMSRan, this_op_scheme.ErlInitProgramMngr);
    2178          25 :                         } else if (this_op_scheme.initPluginLocation > -1) {
    2179           0 :                             state.dataPluginManager->pluginManager->runSingleUserDefinedPlugin(state, this_op_scheme.initPluginLocation);
    2180             :                         }
    2181          30 :                         this_op_scheme.MyEnvrnFlag = false;
    2182             :                     }
    2183     1166136 :                     if (!state.dataGlobal->BeginEnvrnFlag) this_op_scheme.MyEnvrnFlag = true;
    2184             :                 }
    2185             :             } // operation scheme
    2186             :         }     // loop
    2187             :     }
    2188             : 
    2189             :     // FIRST HVAC INITS
    2190    30644847 :     if (FirstHVACIteration) {
    2191    60849779 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2192    46005606 :             auto &this_plant_loop(state.dataPlnt->PlantLoop(LoopNum));
    2193   138016818 :             for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    2194    92011212 :                 auto &this_loop_side(this_plant_loop.LoopSide(LoopSideNum));
    2195   643138527 :                 for (int BranchNum = 1, BranchNum_end = this_loop_side.TotalBranches; BranchNum <= BranchNum_end; ++BranchNum) {
    2196   551127315 :                     auto &this_branch(this_loop_side.Branch(BranchNum));
    2197  1105095826 :                     for (int CompNum = 1, CompNum_end = this_branch.TotalComponents; CompNum <= CompNum_end; ++CompNum) {
    2198   553968511 :                         auto &this_component(this_branch.Comp(CompNum));
    2199             :                         // initalize components 'ON-AVAILABLE-NO LOAD-NO EMS CTRL'
    2200   553968511 :                         this_component.ON = true;
    2201   553968511 :                         this_component.Available = true;
    2202   553968511 :                         this_component.MyLoad = 0.0;
    2203   553968511 :                         this_component.EMSLoadOverrideOn = false;
    2204             :                         // Zero out the old curOpSchemePtr so that we don't get 'carry-over' when we update schedules
    2205   842534428 :                         if (this_component.CurOpSchemeType != OpScheme::Demand && this_component.CurOpSchemeType != OpScheme::Pump &&
    2206   577131834 :                             this_component.CurOpSchemeType != OpScheme::WSEcon && this_component.CurOpSchemeType != OpScheme::NoControl) {
    2207    55825694 :                             this_component.CurOpSchemeType = OpScheme::NoControl;
    2208             :                         }
    2209   553968511 :                         this_component.CurCompLevelOpNum = 0;
    2210             :                     }
    2211             :                 }
    2212             :             }
    2213             :         }
    2214             :         // Update the OpScheme schedules
    2215    60849779 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2216    46005606 :             FoundScheme = false;
    2217    46005606 :             auto &this_loop(state.dataPlnt->PlantLoop(LoopNum));
    2218    97452834 :             for (int OpNum = 1; OpNum <= this_loop.NumOpSchemes; ++OpNum) {
    2219    51447228 :                 auto &this_op_scheme(this_loop.OpScheme(OpNum));
    2220    51447228 :                 if (GetCurrentScheduleValue(state, this_op_scheme.SchedPtr) > 0.0) {
    2221    46036986 :                     this_op_scheme.Available = true;
    2222    46036986 :                     FoundScheme = true;
    2223    96001558 :                     for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2224    49964572 :                         auto &this_equip_list(this_op_scheme.EquipList(ListNum));
    2225             :                         // The component loop loads the pointers from the OpScheme data structure
    2226             :                         // If the component happens to be active in more than schedule, the *LAST*
    2227             :                         // schedule found will be activated
    2228   107890559 :                         for (int CompNum = 1; CompNum <= this_equip_list.NumComps; ++CompNum) {
    2229             : 
    2230             :                             // set up a reference to the component instance on the list data structure
    2231    57925987 :                             auto const &this_list_component(this_equip_list.Comp(CompNum));
    2232             : 
    2233             :                             // then look up the component topological position from this structure
    2234    57925987 :                             LoopPtr = this_list_component.LoopNumPtr;
    2235    57925987 :                             LoopSidePtr = this_list_component.LoopSideNumPtr;
    2236    57925987 :                             BranchPtr = this_list_component.BranchNumPtr;
    2237    57925987 :                             CompPtr = this_list_component.CompNumPtr;
    2238             : 
    2239             :                             // then set up a reference to the component on the plant data structure
    2240    57925987 :                             auto &this_loop_component(state.dataPlnt->PlantLoop(LoopPtr).LoopSide(LoopSidePtr).Branch(BranchPtr).Comp(CompPtr));
    2241             : 
    2242    57925987 :                             if (this_loop_component.CurOpSchemeType != OpScheme::Pump) {
    2243    57925987 :                                 this_loop_component.CurOpSchemeType = this_op_scheme.Type;
    2244             :                             } else {
    2245           0 :                                 ShowSevereError(state,
    2246             :                                                 "Invalid [pump] component found on equipment list.  Pumps are not allowed on equipment lists.");
    2247           0 :                                 ShowContinueError(state, "Problem component name = " + this_op_scheme.EquipList(ListNum).Comp(CompNum).Name);
    2248           0 :                                 ShowContinueError(state, "Remove pump component and place other plant equipment on the list to correct.");
    2249           0 :                                 errFlag2 = true;
    2250             :                             }
    2251             : 
    2252   124749880 :                             for (CompOpNum = 1; CompOpNum <= this_loop_component.NumOpSchemes; ++CompOpNum) {
    2253    66823893 :                                 if (this_loop_component.OpScheme(CompOpNum).OpSchemePtr == OpNum) {
    2254    57925987 :                                     this_loop_component.CurCompLevelOpNum = CompOpNum;
    2255             :                                 }
    2256             :                             }
    2257             :                         }
    2258             :                     }
    2259             :                 } else {
    2260     5410242 :                     this_op_scheme.Available = false;
    2261             :                 }
    2262             :             }
    2263             :             //    IF(.NOT. foundscheme)THEN
    2264             :             //      !'call warning 'no current control scheme specified.  Loop Equipment will be shut down'
    2265             :             //    ENDIF
    2266             :         }
    2267             :     }
    2268             : 
    2269    30644847 :     if (errFlag2) {
    2270           0 :         ShowFatalError(state, "InitLoadDistribution: Fatal error caused by previous severe error(s).");
    2271             :     }
    2272             : }
    2273             : 
    2274             : // End Initialization Section of the Plant Loop Module
    2275             : //******************************************************************************
    2276             : 
    2277             : // Begin Load Calculation/Distribution Section of the Plant Loop Module
    2278             : //******************************************************************************
    2279             : 
    2280    17216374 : void DistributePlantLoad(EnergyPlusData &state,
    2281             :                          int const LoopNum,
    2282             :                          const LoopSideLocation LoopSideNum,
    2283             :                          int const CurSchemePtr, // use as index in PlantLoop()OpScheme() data structure
    2284             :                          int const ListPtr,      // use as index in PlantLoop()OpScheme() data structure
    2285             :                          Real64 const LoopDemand,
    2286             :                          Real64 &RemLoopDemand)
    2287             : {
    2288             : 
    2289             :     // SUBROUTINE INFORMATION:
    2290             :     //       AUTHOR         Dan Fisher
    2291             :     //       DATE WRITTEN   July 1998
    2292             :     //       MODIFIED       na
    2293             :     //       RE-ENGINEERED  July 2010
    2294             :     //                      Sept 2010 B. Griffith, retain actual sign of load values
    2295             :     //                        July 2014 M. Mitchell, added SequentialUniformPLR and UniformPLR schemes
    2296             : 
    2297             :     // PURPOSE OF THIS SUBROUTINE: This subroutine distributes the load
    2298             :     // to plant equipment according to one of two distribution schemes:
    2299             :     //     OPTIMAL    = 1
    2300             :     //     SEQUENTIALLOAD = 2
    2301             :     //     UNIFORMLOAD  = 3
    2302             :     //     UNIFORMPLR = 4
    2303             :     //     SEQUENTIALUNIFORMPLR = 5
    2304             :     // METHODOLOGY EMPLOYED:
    2305             :     // na
    2306             :     // REFERENCES:
    2307             :     // na
    2308             :     // Using/Aliasing
    2309             :     using namespace DataLoopNode;
    2310             : 
    2311             :     // Locals
    2312             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    2313             : 
    2314             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2315             :     // na
    2316             :     // INTERFACE BLOCK SPECIFICATIONS
    2317             :     // na
    2318             :     // DERIVED TYPE DEFINITIONS
    2319             :     // na
    2320             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2321             :     Real64 ChangeInLoad;
    2322             :     Real64 DivideLoad;
    2323             :     Real64 UniformLoad;
    2324             :     Real64 NewLoad;
    2325             :     Real64 PlantCapacity;
    2326             :     Real64 MinCompPLR;
    2327             :     Real64 LargestMinCompPLR;
    2328             :     Real64 PlantPLR;
    2329             :     Real64 CompLoad;
    2330             : 
    2331             :     int BranchNum;
    2332             :     int CompNum;
    2333             :     int CompIndex;
    2334             :     int NumCompsOnList;
    2335             : 
    2336             :     // start with some references
    2337    17216374 :     auto &this_loop(state.dataPlnt->PlantLoop(LoopNum));
    2338    17216374 :     auto &this_loopside(this_loop.LoopSide(LoopSideNum));
    2339    17216374 :     auto &this_equiplist(this_loop.OpScheme(CurSchemePtr).EquipList(ListPtr));
    2340             : 
    2341             :     struct LoadPLRPoint
    2342             :     {
    2343             :         Real64 plant_capacity_to_this_point;
    2344             :         Real64 largest_min_plr_to_this_point;
    2345           0 :         LoadPLRPoint(Real64 capacity, Real64 plr)
    2346           0 :         {
    2347           0 :             plant_capacity_to_this_point = capacity;
    2348           0 :             largest_min_plr_to_this_point = plr;
    2349           0 :         }
    2350             :     };
    2351    34432748 :     std::vector<LoadPLRPoint> accrued_load_plr_values;
    2352             : 
    2353             :     // load local variables
    2354    17216374 :     NumCompsOnList = this_equiplist.NumComps;
    2355    17216374 :     int numAvail = 0;
    2356             : 
    2357             :     // Allocate array once
    2358    17216374 :     accrued_load_plr_values.reserve(NumCompsOnList);
    2359    17216374 :     RemLoopDemand = LoopDemand;
    2360    17216374 :     if (NumCompsOnList <= 0) return;
    2361             : 
    2362    17216374 :     if (std::abs(RemLoopDemand) < SmallLoad) {
    2363             :         // no load to distribute
    2364             :     } else {
    2365             : 
    2366             :         // OPTIMAL DISTRIBUTION SCHEME
    2367    17099118 :         switch (this_loop.LoadDistribution) {
    2368     9145664 :         case DataPlant::LoadingScheme::Optimal:
    2369             :             // step 1: load all machines to optimal PLR
    2370     9145664 :             numAvail = 0;
    2371    18831266 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2372             : 
    2373             :                 // look up topology from the equipment list
    2374     9685602 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2375     9685602 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2376             : 
    2377             :                 // create a reference to the component itself
    2378     9685602 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2379             : 
    2380     9685602 :                 if (!this_component.Available) continue;
    2381     9685599 :                 ++numAvail;
    2382             : 
    2383     9685599 :                 if (this_component.OptLoad > 0.0) {
    2384     9588279 :                     ChangeInLoad = min(this_component.OptLoad, std::abs(RemLoopDemand));
    2385             :                 } else {
    2386             :                     // this is for some components like cooling towers don't have well defined OptLoad
    2387       97320 :                     ChangeInLoad = std::abs(RemLoopDemand);
    2388             :                 }
    2389             : 
    2390     9685599 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    2391             : 
    2392     9685599 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2393             : 
    2394     9685599 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2395             : 
    2396     9685599 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    2397     9685599 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    2398             : 
    2399     9685599 :                 RemLoopDemand -= this_component.MyLoad;
    2400     9685599 :                 if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't reset
    2401     9145664 :             }
    2402             : 
    2403             :             // step 2: Evenly distribute remaining loop demand
    2404     9145664 :             if (numAvail > 0 && std::abs(RemLoopDemand) > SmallLoad) {
    2405      474281 :                 DivideLoad = std::abs(RemLoopDemand) / numAvail;
    2406      982161 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2407             : 
    2408      507880 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2409      507880 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2410             : 
    2411             :                     // create a reference to the component itself
    2412      507880 :                     auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2413             : 
    2414      507880 :                     if (!this_component.Available) continue;
    2415             : 
    2416      507879 :                     NewLoad = this_component.MyLoad;
    2417      507879 :                     NewLoad = min(this_component.MaxLoad, std::abs(NewLoad) + DivideLoad);
    2418      507879 :                     ChangeInLoad = NewLoad - std::abs(this_component.MyLoad);
    2419      507879 :                     this_component.MyLoad = sign(NewLoad, RemLoopDemand);
    2420      507879 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2421      507879 :                     if (std::abs(RemLoopDemand) < SmallLoad)
    2422      168946 :                         RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't
    2423             :                                              // reset
    2424             :                 }
    2425             :             }
    2426             : 
    2427             :             // step 3: If RemLoopDemand is still greater than zero, look for any machine
    2428     9145664 :             if (numAvail > 0 && std::abs(RemLoopDemand) > SmallLoad) {
    2429      641479 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2430             : 
    2431      336140 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2432      336140 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2433             : 
    2434             :                     // create a reference to the component itself
    2435      336140 :                     auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2436             : 
    2437      336140 :                     if (!this_component.Available) continue;
    2438      336139 :                     DivideLoad = this_component.MaxLoad - std::abs(this_component.MyLoad);
    2439      336139 :                     ChangeInLoad = min(std::abs(RemLoopDemand), DivideLoad);
    2440      336139 :                     this_component.MyLoad += sign(ChangeInLoad, RemLoopDemand);
    2441      336139 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2442      336139 :                     if (std::abs(RemLoopDemand) < SmallLoad)
    2443        3829 :                         RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't
    2444             :                                              // reset
    2445             :                 }
    2446             :             }
    2447             : 
    2448     9145664 :             break;
    2449             : 
    2450             :         // SEQUENTIALLOAD DISTRIBUTION SCHEME
    2451     7374346 :         case DataPlant::LoadingScheme::Sequential:
    2452             : 
    2453             :             // step 1: Load machines in list order
    2454    14983820 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2455             : 
    2456     7609474 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2457     7609474 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2458             : 
    2459             :                 // create a reference to the component itself
    2460     7609474 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2461             : 
    2462     7609474 :                 if (!this_component.Available) continue;
    2463             : 
    2464     7609474 :                 if (this_component.MaxLoad > 0.0) { // apply known limit
    2465     7576678 :                     ChangeInLoad = min(this_component.MaxLoad, std::abs(RemLoopDemand));
    2466             :                 } else {
    2467             :                     // this is for some components like cooling towers don't have well defined MaxLoad
    2468       32796 :                     ChangeInLoad = std::abs(RemLoopDemand);
    2469             :                 }
    2470             : 
    2471     7609474 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    2472             : 
    2473     7609474 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2474             : 
    2475     7609474 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2476             : 
    2477     7609474 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    2478     7609474 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    2479     7609474 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2480     7609474 :                 if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't reset
    2481     7374346 :             }
    2482             : 
    2483     7374346 :             break;
    2484             : 
    2485             :         // UNIFORMLOAD DISTRIBUTION SCHEME
    2486      579108 :         case DataPlant::LoadingScheme::Uniform:
    2487             : 
    2488             :             // step 1: distribute load equally to all available machines
    2489      579108 :             numAvail = 0;
    2490     1651690 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2491             : 
    2492     1072582 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2493     1072582 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2494             : 
    2495             :                 // create a reference to the component itself
    2496     1072582 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2497             : 
    2498     1072582 :                 if (this_component.Available) ++numAvail;
    2499      579108 :             }
    2500      579108 :             if (numAvail > 0) {
    2501      579106 :                 UniformLoad = std::abs(RemLoopDemand) / numAvail;
    2502             :             } else {
    2503           2 :                 UniformLoad = 0.0;
    2504             :             }
    2505     1651690 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2506             : 
    2507     1072582 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2508     1072582 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2509             : 
    2510             :                 // create a reference to the component itself
    2511     1072582 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2512             : 
    2513     1072582 :                 if (!this_component.Available) continue;
    2514     1072578 :                 if (this_component.MaxLoad > 0.0) {
    2515     1072578 :                     ChangeInLoad = min(this_component.MaxLoad, UniformLoad);
    2516             :                 } else {
    2517             :                     // this is for some components like cooling towers don't have well defined MaxLoad
    2518           0 :                     ChangeInLoad = std::abs(RemLoopDemand);
    2519             :                 }
    2520             : 
    2521     1072578 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    2522             : 
    2523     1072578 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2524             : 
    2525     1072578 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2526     1072578 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    2527     1072578 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    2528     1072578 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2529     1072578 :                 if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0;
    2530      579108 :             }
    2531             : 
    2532             :             // step 2: If RemLoopDemand is not zero, then distribute remainder sequentially.
    2533      579108 :             if (std::abs(RemLoopDemand) > SmallLoad) {
    2534      345799 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2535             : 
    2536      217520 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2537      217520 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2538             : 
    2539             :                     // create a reference to the component itself
    2540      217520 :                     auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2541             : 
    2542      217520 :                     if (!this_component.Available) continue;
    2543      217516 :                     ChangeInLoad = min(this_component.MaxLoad - std::abs(this_component.MyLoad), std::abs(RemLoopDemand));
    2544      217516 :                     ChangeInLoad = max(0.0, ChangeInLoad);
    2545      217516 :                     this_component.MyLoad += sign(ChangeInLoad, RemLoopDemand);
    2546      217516 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2547      217516 :                     if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0;
    2548             :                 }
    2549             :             }
    2550             : 
    2551      579108 :             break;
    2552             : 
    2553             :         // UNIFORMPLR LOAD DISTRIBUTION SCHEME
    2554           0 :         case DataPlant::LoadingScheme::UniformPLR:
    2555             :             // Get total plant capacity and remove last component from list if load is less
    2556             :             // than plant capacity at min PLR
    2557           0 :             PlantCapacity = 0.0;
    2558           0 :             PlantPLR = 0.0;
    2559           0 :             MinCompPLR = 0.0;
    2560           0 :             LargestMinCompPLR = 0.0;
    2561             : 
    2562             :             // Determine PlantCapacity and LargestMinCompPLR
    2563           0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2564             : 
    2565           0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2566           0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2567             : 
    2568             :                 // create a reference to the component itself
    2569           0 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2570             : 
    2571           0 :                 if (!this_component.Available) continue;
    2572             : 
    2573           0 :                 PlantCapacity += this_component.MaxLoad;
    2574             : 
    2575           0 :                 if (this_component.MaxLoad < SmallLoad) {
    2576           0 :                     ShowWarningMessage(state, "Plant component " + this_component.Name + " has zero available capacity. Check component controls.");
    2577           0 :                     MinCompPLR = 0.0;
    2578             :                 } else {
    2579           0 :                     MinCompPLR = this_component.MinLoad / this_component.MaxLoad;
    2580             :                 }
    2581             : 
    2582             :                 // Set LargestMinCompPLR to largest MinCompPLR
    2583           0 :                 LargestMinCompPLR = max(LargestMinCompPLR, MinCompPLR);
    2584             : 
    2585             :                 // Update the array
    2586           0 :                 accrued_load_plr_values.push_back(LoadPLRPoint(PlantCapacity, LargestMinCompPLR));
    2587           0 :             }
    2588             : 
    2589             :             // work backwards from full capacity down to 1 unit on
    2590           0 :             for (int i = accrued_load_plr_values.size() - 1; i >= 0; --i) {
    2591             : 
    2592             :                 // if i == 0 then we need to take that as the resulting value
    2593           0 :                 if (i == 0) {
    2594           0 :                     PlantCapacity = accrued_load_plr_values[i].plant_capacity_to_this_point;
    2595           0 :                     LargestMinCompPLR = accrued_load_plr_values[i].largest_min_plr_to_this_point;
    2596           0 :                     break;
    2597             : 
    2598             :                     // if the capacity is greater than the demand, just store the latest values and continue
    2599           0 :                 } else if (std::abs(RemLoopDemand) <
    2600           0 :                            (accrued_load_plr_values[i].largest_min_plr_to_this_point * accrued_load_plr_values[i].plant_capacity_to_this_point)) {
    2601           0 :                     PlantCapacity = accrued_load_plr_values[i].plant_capacity_to_this_point;
    2602           0 :                     LargestMinCompPLR = accrued_load_plr_values[i].largest_min_plr_to_this_point;
    2603           0 :                     continue;
    2604             : 
    2605             :                     // if the capacity is less than the demand, accept the last values from the previous iteration and exit
    2606             :                 } else {
    2607           0 :                     break;
    2608             :                 }
    2609           0 :             }
    2610             : 
    2611             :             // Determine PLR for uniform PLR loading of all equipment
    2612           0 :             if (PlantCapacity > 0.0) {
    2613           0 :                 PlantPLR = min(1.0, std::abs(RemLoopDemand) / PlantCapacity);
    2614             :             } else {
    2615           0 :                 ShowWarningError(state, "Zero available plant capacity for Plant Loop = " + state.dataPlnt->PlantLoop(LoopNum).Name);
    2616             :             }
    2617             : 
    2618             :             // Distribute load to each machine
    2619           0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2620             : 
    2621           0 :                 CompLoad = 0.0;
    2622             : 
    2623           0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2624           0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2625             : 
    2626             :                 // create a reference to the component itself
    2627           0 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2628             : 
    2629           0 :                 if (!this_component.Available) continue;
    2630             : 
    2631           0 :                 CompLoad = PlantPLR * this_component.MaxLoad;
    2632             : 
    2633           0 :                 if (this_component.MaxLoad > 0.0) {
    2634           0 :                     ChangeInLoad = min(std::abs(RemLoopDemand), CompLoad);
    2635             :                 } else {
    2636             :                     // this is for some components like cooling towers don't have well defined MaxLoad
    2637           0 :                     ChangeInLoad = std::abs(RemLoopDemand);
    2638             :                 }
    2639             : 
    2640           0 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    2641             : 
    2642           0 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2643             : 
    2644           0 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2645             : 
    2646           0 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    2647             : 
    2648           0 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    2649             : 
    2650           0 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2651             : 
    2652           0 :                 if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0;
    2653           0 :             }
    2654             : 
    2655           0 :             break;
    2656             : 
    2657             :         // SEQUENTIALUNIFORMPLR LOAD DISTRIBUTION SCHEME
    2658           0 :         case DataPlant::LoadingScheme::SequentialUniformPLR:
    2659             : 
    2660           0 :             PlantCapacity = 0.0;
    2661           0 :             PlantPLR = 0.0;
    2662           0 :             MinCompPLR = 0.0;
    2663           0 :             LargestMinCompPLR = 0.0;
    2664             : 
    2665             :             // Determine PlantCapacity and LargestMinCompPLR
    2666           0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2667             : 
    2668           0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2669           0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2670             : 
    2671             :                 // create a reference to the component itself
    2672           0 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2673             : 
    2674           0 :                 if (!this_component.Available) continue;
    2675             : 
    2676           0 :                 PlantCapacity += this_component.MaxLoad;
    2677             : 
    2678           0 :                 if (this_component.MaxLoad < SmallLoad) {
    2679           0 :                     ShowWarningMessage(state, "Plant component " + this_component.Name + " has zero available capacity. Check component controls.");
    2680           0 :                     MinCompPLR = 0.0;
    2681             :                 } else {
    2682           0 :                     MinCompPLR = this_component.MinLoad / this_component.MaxLoad;
    2683             :                 }
    2684             : 
    2685             :                 // Set LargestMinCompPLR to largest MinCompPLR
    2686           0 :                 if (MinCompPLR > LargestMinCompPLR) LargestMinCompPLR = MinCompPLR;
    2687             : 
    2688           0 :                 if (std::abs(RemLoopDemand) <= PlantCapacity) {
    2689           0 :                     break;
    2690             :                 }
    2691           0 :             }
    2692             : 
    2693             :             // Determine PLR for uniform PLR loading of all equipment
    2694           0 :             if (PlantCapacity > 0.0) {
    2695           0 :                 PlantPLR = min(1.0, std::abs(RemLoopDemand) / PlantCapacity);
    2696             :             } else {
    2697           0 :                 ShowWarningError(state, "Zero available plant capacity for Plant Loop = " + state.dataPlnt->PlantLoop(LoopNum).Name);
    2698             :             }
    2699             : 
    2700             :             // Distribute load to each machine
    2701           0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2702             : 
    2703           0 :                 CompLoad = 0.0;
    2704             : 
    2705           0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2706           0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2707             : 
    2708             :                 // create a reference to the component itself
    2709           0 :                 auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2710             : 
    2711           0 :                 if (!this_component.Available) continue;
    2712             : 
    2713           0 :                 CompLoad = PlantPLR * this_component.MaxLoad;
    2714             : 
    2715           0 :                 if (this_component.MaxLoad > 0.0) {
    2716           0 :                     ChangeInLoad = min(std::abs(RemLoopDemand), CompLoad);
    2717             :                 } else {
    2718             :                     // this is for some components like cooling towers don't have well defined MaxLoad
    2719           0 :                     ChangeInLoad = std::abs(RemLoopDemand);
    2720             :                 }
    2721             : 
    2722           0 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    2723             : 
    2724           0 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2725             : 
    2726           0 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    2727             : 
    2728           0 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    2729             : 
    2730           0 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    2731             : 
    2732           0 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    2733             : 
    2734           0 :                 if (std::abs(RemLoopDemand) < SmallLoad) RemLoopDemand = 0.0;
    2735           0 :             }
    2736           0 :             break;
    2737           0 :         default:
    2738           0 :             assert(false);
    2739             :         }
    2740             : 
    2741             :     } // load is small check
    2742             : 
    2743             :     // now update On flags according to result for MyLoad
    2744    35812944 :     for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    2745             : 
    2746    18596570 :         BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    2747    18596570 :         CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    2748             : 
    2749             :         // create a reference to the component itself
    2750    18596570 :         auto &this_component(this_loopside.Branch(BranchNum).Comp(CompNum));
    2751             : 
    2752    18596570 :         if (std::abs(this_component.MyLoad) < SmallLoad) {
    2753      833095 :             this_component.ON = false;
    2754             :         } else {
    2755    17763475 :             this_component.ON = true;
    2756             :         }
    2757             :     }
    2758             : }
    2759             : 
    2760    18367651 : void AdjustChangeInLoadForLastStageUpperRangeLimit(EnergyPlusData &state,
    2761             :                                                    int const LoopNum,         // component topology
    2762             :                                                    int const CurOpSchemePtr,  // current active operation scheme
    2763             :                                                    int const CurEquipListPtr, // current equipment list
    2764             :                                                    Real64 &ChangeInLoad       // positive magnitude of load change
    2765             : )
    2766             : {
    2767             : 
    2768             :     // SUBROUTINE INFORMATION:
    2769             :     //       AUTHOR         B. Griffith
    2770             :     //       DATE WRITTEN   May 2012
    2771             :     //       MODIFIED       na
    2772             :     //       RE-ENGINEERED  na
    2773             : 
    2774             :     // PURPOSE OF THIS SUBROUTINE:
    2775             :     // if this is the last stage for a load based operation, then limit load to upper range
    2776             : 
    2777             :     // METHODOLOGY EMPLOYED:
    2778             :     // <description>
    2779             : 
    2780             :     // REFERENCES:
    2781             :     // na
    2782             : 
    2783             :     // USE STATEMENTS:
    2784             :     // na
    2785             : 
    2786             :     // Locals
    2787             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    2788             : 
    2789             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2790             :     // na
    2791             : 
    2792             :     // INTERFACE BLOCK SPECIFICATIONS:
    2793             :     // na
    2794             : 
    2795             :     // DERIVED TYPE DEFINITIONS:
    2796             :     // na
    2797             : 
    2798             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2799             :     Real64 RangeHiLimit;
    2800             : 
    2801    18367651 :     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurOpSchemePtr).EquipListNumForLastStage == CurEquipListPtr) { // at final last stage
    2802             : 
    2803    17784239 :         RangeHiLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurOpSchemePtr).EquipList(CurEquipListPtr).RangeUpperLimit;
    2804    17784239 :         ChangeInLoad = min(ChangeInLoad, RangeHiLimit);
    2805             :     }
    2806    18367651 : }
    2807             : 
    2808    18367651 : void AdjustChangeInLoadByHowServed(EnergyPlusData &state,
    2809             :                                    PlantLocation const &plantLoc, // component topology
    2810             :                                    Real64 &ChangeInLoad           // positive magnitude of load change
    2811             : )
    2812             : {
    2813             : 
    2814             :     // SUBROUTINE INFORMATION:
    2815             :     //       AUTHOR         B. Griffith
    2816             :     //       DATE WRITTEN   Nov 2011
    2817             :     //       MODIFIED       March 2012, B. Griffith add controls for free cooling heat exchanger overrides of chillers
    2818             :     //       RE-ENGINEERED  na
    2819             : 
    2820             :     // PURPOSE OF THIS SUBROUTINE:
    2821             :     // central place to apply limits to machine load dispatch based on how the machine serves loads
    2822             : 
    2823             :     // METHODOLOGY EMPLOYED:
    2824             :     // Components are machines on plant equipment operation lists.  Need to make adjustments to the
    2825             :     // load dispatch to account for limits and floating capacities.
    2826             : 
    2827             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2828             :     static constexpr std::string_view RoutineName("PlantCondLoopOperation:DistributePlantLoad");
    2829             : 
    2830             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2831    18367651 :     Real64 CurMassFlowRate(0.0);
    2832    18367651 :     Real64 ToutLowLimit(0.0);
    2833    18367651 :     Real64 ToutHiLimit(0.0);
    2834    18367651 :     Real64 TinLowLimit(0.0);
    2835    18367651 :     Real64 Tinlet(0.0);
    2836    18367651 :     Real64 Tsensor(0.0);
    2837    18367651 :     Real64 CurSpecHeat(0.0);
    2838    18367651 :     Real64 QdotTmp(0.0);
    2839    18367651 :     int ControlNodeNum(0);
    2840             : 
    2841    18367651 :     auto &this_component(CompData::getPlantComponent(state, plantLoc));
    2842             : 
    2843             :     // start of bad band-aid, need a general and comprehensive approach for determining current capacity of all kinds of equipment
    2844             :     // Need to truncate the load down in case outlet temperature will hit a lower/upper limit
    2845             : 
    2846    18367651 :     switch (this_component.HowLoadServed) {
    2847             : 
    2848             :     // Chillers
    2849     4842548 :     case DataPlant::HowMet::ByNominalCapLowOutLimit: { // chillers with lower limit on outlet temperature
    2850             : 
    2851             :         //- Retrieve data from the plant loop data structure
    2852     4842548 :         CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
    2853     4842548 :         ToutLowLimit = this_component.MinOutletTemp;
    2854     4842548 :         Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
    2855     9685096 :         CurSpecHeat = GetSpecificHeatGlycol(state,
    2856     4842548 :                                             state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidName,
    2857             :                                             Tinlet,
    2858     4842548 :                                             state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidIndex,
    2859             :                                             RoutineName);
    2860     4842548 :         QdotTmp = CurMassFlowRate * CurSpecHeat * (Tinlet - ToutLowLimit);
    2861             : 
    2862             :         //        !- Don't correct if Q is zero, as this could indicate a component which this hasn't been implemented or not yet turned on
    2863     4842548 :         if (CurMassFlowRate > 0.0) {
    2864     4742362 :             ChangeInLoad = min(ChangeInLoad, QdotTmp);
    2865             :         }
    2866             : 
    2867     4842548 :         break;
    2868             :     }
    2869       46041 :     case DataPlant::HowMet::ByNominalCapFreeCoolCntrl: {
    2870             :         // for chillers with free cooling shutdown (HeatExchanger:Hydronic currently)
    2871             :         // determine if free cooling controls shut off chiller
    2872       46041 :         TinLowLimit = this_component.FreeCoolCntrlMinCntrlTemp;
    2873       46041 :         switch (this_component.FreeCoolCntrlMode) {
    2874           0 :         case DataPlant::FreeCoolControlMode::WetBulb: {
    2875           0 :             Tsensor = state.dataEnvrn->OutWetBulbTemp;
    2876           0 :             break;
    2877             :         }
    2878           0 :         case DataPlant::FreeCoolControlMode::DryBulb: {
    2879           0 :             Tsensor = state.dataEnvrn->OutDryBulbTemp;
    2880           0 :             break;
    2881             :         }
    2882       46041 :         case DataPlant::FreeCoolControlMode::Loop: {
    2883       46041 :             ControlNodeNum = this_component.FreeCoolCntrlNodeNum;
    2884       46041 :             if (ControlNodeNum > 0) {
    2885       46041 :                 Tsensor = state.dataLoopNodes->Node(ControlNodeNum).TempLastTimestep; // use lagged value for stability
    2886             :             } else {
    2887           0 :                 Tsensor = 23.0;
    2888             :             }
    2889       46041 :             break;
    2890             :         }
    2891           0 :         default:
    2892           0 :             break;
    2893             :         }
    2894             : 
    2895       46041 :         if (Tsensor < TinLowLimit) { // turn off chiller to initiate free cooling
    2896           1 :             ChangeInLoad = 0.0;
    2897           1 :             this_component.Available = false;
    2898           1 :             this_component.FreeCoolCntrlShutDown = true;
    2899             :         } else {
    2900       46040 :             this_component.Available = true;
    2901       46040 :             this_component.FreeCoolCntrlShutDown = false;
    2902             :         }
    2903             : 
    2904       46041 :         break;
    2905             :     }
    2906           0 :     case DataPlant::HowMet::ByNominalCapLowOutLimitFreeCoolCntrl: {
    2907             :         // for chillers with free cooling shutdown (HeatExchanger:Hydronic currently)
    2908             :         // determine if free cooling controls shut off chiller
    2909           0 :         TinLowLimit = this_component.FreeCoolCntrlMinCntrlTemp;
    2910           0 :         switch (this_component.FreeCoolCntrlMode) {
    2911           0 :         case DataPlant::FreeCoolControlMode::WetBulb: {
    2912           0 :             Tsensor = state.dataEnvrn->OutWetBulbTemp;
    2913           0 :             break;
    2914             :         }
    2915           0 :         case DataPlant::FreeCoolControlMode::DryBulb: {
    2916           0 :             Tsensor = state.dataEnvrn->OutDryBulbTemp;
    2917           0 :             break;
    2918             :         }
    2919           0 :         case DataPlant::FreeCoolControlMode::Loop: {
    2920           0 :             ControlNodeNum = this_component.FreeCoolCntrlNodeNum;
    2921           0 :             if (ControlNodeNum > 0) {
    2922           0 :                 Tsensor = state.dataLoopNodes->Node(ControlNodeNum).TempLastTimestep; // use lagged value for stability
    2923             :             } else {
    2924           0 :                 Tsensor = 23.0;
    2925             :             }
    2926           0 :             break;
    2927             :         }
    2928           0 :         default:
    2929           0 :             break;
    2930             :         }
    2931             : 
    2932           0 :         if (Tsensor < TinLowLimit) { // turn off chiller to initiate free cooling
    2933           0 :             ChangeInLoad = 0.0;
    2934           0 :             this_component.Available = false;
    2935           0 :             this_component.FreeCoolCntrlShutDown = true;
    2936             :         } else {
    2937             :             //- Retrieve data from the plant loop data structure
    2938           0 :             this_component.Available = true;
    2939           0 :             this_component.FreeCoolCntrlShutDown = false;
    2940           0 :             CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
    2941           0 :             ToutLowLimit = this_component.MinOutletTemp;
    2942           0 :             Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
    2943           0 :             CurSpecHeat = GetSpecificHeatGlycol(state,
    2944           0 :                                                 state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidName,
    2945             :                                                 Tinlet,
    2946           0 :                                                 state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidIndex,
    2947             :                                                 RoutineName);
    2948           0 :             QdotTmp = CurMassFlowRate * CurSpecHeat * (Tinlet - ToutLowLimit);
    2949             : 
    2950             :             //        !- Don't correct if Q is zero, as this could indicate a component which this hasn't been implemented or not yet turned
    2951             :             //        on
    2952           0 :             if (CurMassFlowRate > 0.0) {
    2953           0 :                 ChangeInLoad = min(ChangeInLoad, QdotTmp);
    2954             :             }
    2955             :         }
    2956             : 
    2957           0 :         break;
    2958             :     }
    2959     4574794 :     case DataPlant::HowMet::ByNominalCapHiOutLimit: { // boilers with upper limit on outlet temperature
    2960             :         //- Retrieve data from the plant loop data structure
    2961     4574794 :         CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
    2962     4574794 :         ToutHiLimit = this_component.MaxOutletTemp;
    2963     4574794 :         Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
    2964     9149588 :         CurSpecHeat = GetSpecificHeatGlycol(state,
    2965     4574794 :                                             state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidName,
    2966             :                                             Tinlet,
    2967     4574794 :                                             state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidIndex,
    2968             :                                             RoutineName);
    2969     4574794 :         QdotTmp = CurMassFlowRate * CurSpecHeat * (ToutHiLimit - Tinlet);
    2970             : 
    2971     4574794 :         if (CurMassFlowRate > 0.0) {
    2972     4513476 :             ChangeInLoad = min(ChangeInLoad, QdotTmp);
    2973             :         }
    2974             : 
    2975     4574794 :         break;
    2976             :     }
    2977     4420272 :     case DataPlant::HowMet::PassiveCap: { // need to estimate current capacity if more or less passive devices ??
    2978             : 
    2979     4420272 :         break;
    2980             :     }
    2981     4483996 :     default:
    2982     4483996 :         break;
    2983             :     }
    2984    18367651 : }
    2985             : 
    2986     1168724 : void FindCompSPLoad(EnergyPlusData &state,
    2987             :                     PlantLocation const &plantLoc,
    2988             :                     int const OpNum // index for Plant()%LoopSide()%Branch()%Comp()%OpScheme()
    2989             : )
    2990             : {
    2991             : 
    2992             :     // SUBROUTINE INFORMATION:
    2993             :     //       AUTHOR         Sankaranarayanan K P
    2994             :     //       DATE WRITTEN   Jan 2005
    2995             :     //       MODIFIED       na
    2996             :     //       RE-ENGINEERED  Dan Fisher July 2010
    2997             : 
    2998             :     // PURPOSE OF THIS SUBROUTINE:
    2999             :     // To calculate the load on a component controlled by
    3000             :     // Component SetPoint based scheme.
    3001             : 
    3002             :     // Using/Aliasing
    3003             :     using DataLoopNode::SensedNodeFlagValue;
    3004             :     using FluidProperties::GetDensityGlycol;
    3005             : 
    3006             :     // Locals
    3007             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3008             : 
    3009             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3010             :     static constexpr std::string_view RoutineName("FindCompSPLoad");
    3011             : 
    3012             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3013             :     Real64 CompDemand;
    3014             :     Real64 DemandMdot;
    3015             :     Real64 ActualMdot;
    3016             :     Real64 TempIn;
    3017             :     Real64 CurSpecHeat;
    3018     1168724 :     Real64 TempSetPt(0.0);
    3019             :     Real64 CompMinLoad;
    3020             :     Real64 CompMaxLoad;
    3021             :     Real64 CompOptLoad;
    3022             :     int DemandNode;
    3023             :     int CompPtr;
    3024             :     int OpSchemePtr;
    3025             :     int ListPtr;
    3026             :     int SetPtNode;
    3027             :     int NumEquipLists;
    3028             :     Real64 rho;
    3029             :     Real64 CurrentDemandForCoolingOp;
    3030             :     Real64 CurrentDemandForHeatingOp;
    3031             : 
    3032     1168724 :     auto &this_component(CompData::getPlantComponent(state, plantLoc));
    3033             : 
    3034             :     // find the pointer to the 'PlantLoop()%OpScheme()'...data structure
    3035     1168724 :     NumEquipLists = this_component.OpScheme(OpNum).NumEquipLists;
    3036             :     if (NumEquipLists != 1) {
    3037             :         // CALL Severe error) there should be exactly one list associated with component setpoint scheme
    3038             :     }
    3039             : 
    3040     1168724 :     OpSchemePtr = this_component.OpScheme(OpNum).OpSchemePtr;
    3041     1168724 :     ListPtr = this_component.OpScheme(OpNum).EquipList(1).ListPtr;
    3042     1168724 :     CompPtr = this_component.OpScheme(OpNum).EquipList(1).CompPtr;
    3043             : 
    3044             :     // load local variables from the data structures
    3045     1168724 :     CompMinLoad = this_component.MinLoad;
    3046     1168724 :     CompMaxLoad = this_component.MaxLoad;
    3047     1168724 :     CompOptLoad = this_component.OptLoad;
    3048     1168724 :     DemandNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).DemandNodeNum;
    3049     1168724 :     SetPtNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).SetPointNodeNum;
    3050     1168724 :     TempIn = state.dataLoopNodes->Node(DemandNode).Temp;
    3051     2337448 :     rho = GetDensityGlycol(
    3052     2337448 :         state, state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidName, TempIn, state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidIndex, RoutineName);
    3053             : 
    3054     1168724 :     DemandMdot = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).SetPointFlowRate * rho;
    3055             :     // DemandMDot is a constant design flow rate, next based on actual current flow rate for accurate current demand?
    3056     1168724 :     ActualMdot = state.dataLoopNodes->Node(DemandNode).MassFlowRate;
    3057     2337448 :     CurSpecHeat = GetSpecificHeatGlycol(
    3058     2337448 :         state, state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidName, TempIn, state.dataPlnt->PlantLoop(plantLoc.loopNum).FluidIndex, RoutineName);
    3059     1168724 :     if ((ActualMdot > 0.0) && (ActualMdot != DemandMdot)) {
    3060      800638 :         DemandMdot = ActualMdot;
    3061             :     }
    3062             : 
    3063     1168724 :     switch (state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopDemandCalcScheme) {
    3064      939508 :     case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    3065      939508 :         TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPoint;
    3066      939508 :         break;
    3067             :     }
    3068      229216 :     case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    3069      229216 :         if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::CoolingOp) {
    3070      114608 :             TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPointHi;
    3071      114608 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType ==
    3072             :                    CtrlType::HeatingOp) {
    3073      114608 :             TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPointLo;
    3074           0 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::DualOp) {
    3075           0 :             CurrentDemandForCoolingOp = DemandMdot * CurSpecHeat * (state.dataLoopNodes->Node(SetPtNode).TempSetPointHi - TempIn);
    3076           0 :             CurrentDemandForHeatingOp = DemandMdot * CurSpecHeat * (state.dataLoopNodes->Node(SetPtNode).TempSetPointLo - TempIn);
    3077           0 :             if ((CurrentDemandForCoolingOp < 0.0) && (CurrentDemandForHeatingOp <= 0.0)) { // cooling
    3078           0 :                 TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPointHi;
    3079           0 :             } else if ((CurrentDemandForCoolingOp >= 0.0) && (CurrentDemandForHeatingOp > 0.0)) { // heating
    3080           0 :                 TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPointLo;
    3081             :             } else { // deadband
    3082           0 :                 TempSetPt = TempIn;
    3083             :             }
    3084             :         } else {
    3085           0 :             assert(false);
    3086             :         }
    3087      229216 :         break;
    3088             :     }
    3089           0 :     default:
    3090           0 :         assert(false);
    3091             :         break;
    3092             :     }
    3093             : 
    3094     1168724 :     if (TempSetPt == SensedNodeFlagValue) {
    3095         120 :         this_component.ON = false;
    3096         120 :         this_component.MyLoad = 0.0;
    3097         120 :         this_component.EquipDemand = 0.0;
    3098             :     } else {
    3099             : 
    3100     1168604 :         CompDemand = (DemandMdot * CurSpecHeat * (TempSetPt - TempIn));
    3101             : 
    3102     1168604 :         if (std::abs(CompDemand) < LoopDemandTol) CompDemand = 0.0;
    3103     1168604 :         this_component.EquipDemand = CompDemand;
    3104             : 
    3105             :         // set MyLoad and runflag
    3106     1168604 :         if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::CoolingOp) {
    3107      669176 :             if (CompDemand < (-LoopDemandTol)) {
    3108      462876 :                 this_component.ON = true;
    3109      462876 :                 this_component.MyLoad = CompDemand;
    3110             :             } else {
    3111      206300 :                 this_component.ON = false;
    3112      206300 :                 this_component.MyLoad = 0.0;
    3113             :             }
    3114      499428 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType ==
    3115             :                    CtrlType::HeatingOp) {
    3116      120740 :             if (CompDemand > LoopDemandTol) {
    3117        1832 :                 this_component.ON = true;
    3118        1832 :                 this_component.MyLoad = CompDemand;
    3119             :             } else {
    3120      118908 :                 this_component.ON = false;
    3121      118908 :                 this_component.MyLoad = 0.0;
    3122             :             }
    3123      378688 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::DualOp) {
    3124      378688 :             if (CompDemand > LoopDemandTol || CompDemand < (-LoopDemandTol)) {
    3125      236228 :                 this_component.ON = true;
    3126      236228 :                 this_component.MyLoad = CompDemand;
    3127             :             } else {
    3128      142460 :                 this_component.ON = false;
    3129      142460 :                 this_component.MyLoad = 0.0;
    3130             :             }
    3131             :         }
    3132             : 
    3133             :         // Check bounds on MyLoad
    3134     1168604 :         if (std::abs(this_component.MyLoad) > CompMaxLoad) {
    3135      458362 :             this_component.MyLoad = sign(CompMaxLoad, this_component.MyLoad);
    3136             :         }
    3137             :         //   PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%MyLoad = &
    3138             :         //   MIN(PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%MyLoad,CompMaxLoad)
    3139             : 
    3140     1168604 :         if (std::abs(this_component.MyLoad) < CompMinLoad) {
    3141       85848 :             this_component.MyLoad = sign(CompMinLoad, this_component.MyLoad);
    3142             :         }
    3143             :         //   PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%MyLoad = &
    3144             :         //   MAX(PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%MyLoad,CompMinLoad)
    3145             : 
    3146             :     } // valid setpoint (TempSetPt /= SensedNodeFlagValue)
    3147     1168724 : }
    3148             : 
    3149      322816 : void DistributeUserDefinedPlantLoad(EnergyPlusData &state,
    3150             :                                     PlantLocation const &plantLoc,
    3151             :                                     int const CurCompLevelOpNum, // index for Plant()%LoopSide()%Branch()%Comp()%OpScheme()
    3152             :                                     int const CurSchemePtr,
    3153             :                                     Real64 const LoopDemand,
    3154             :                                     [[maybe_unused]] Real64 &RemLoopDemand)
    3155             : {
    3156             : 
    3157             :     // SUBROUTINE INFORMATION:
    3158             :     //       AUTHOR         B. Griffith
    3159             :     //       DATE WRITTEN   August 2013
    3160             :     //       MODIFIED       na
    3161             :     //       RE-ENGINEERED  na
    3162             : 
    3163             :     // PURPOSE OF THIS SUBROUTINE:
    3164             :     // <description>
    3165             : 
    3166             :     // METHODOLOGY EMPLOYED:
    3167             :     // <description>
    3168             : 
    3169             :     // REFERENCES:
    3170             :     // na
    3171             : 
    3172             :     // Using/Aliasing
    3173             :     using EMSManager::ManageEMS;
    3174             : 
    3175             :     // Locals
    3176             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3177             : 
    3178             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3179             :     // na
    3180             : 
    3181             :     // INTERFACE BLOCK SPECIFICATIONS:
    3182             :     // na
    3183             : 
    3184             :     // DERIVED TYPE DEFINITIONS:
    3185             :     // na
    3186             : 
    3187             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3188             :     int CompPtr;
    3189             : 
    3190      322816 :     auto &this_component(CompData::getPlantComponent(state, plantLoc));
    3191             : 
    3192             :     // ListPtr = PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%OpScheme(CurCompLevelOpNum)%EquipList(1)%ListPtr
    3193      322816 :     CompPtr = this_component.OpScheme(CurCompLevelOpNum).EquipList(1).CompPtr;
    3194             : 
    3195             :     // fill internal variable
    3196      322816 :     state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSIntVarRemainingLoadValue = LoopDemand;
    3197             : 
    3198             :     // Call EMS program(s)
    3199      322816 :     if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).ErlSimProgramMngr > 0) {
    3200             :         bool anyEMSRan;
    3201      161408 :         ManageEMS(state,
    3202             :                   EMSManager::EMSCallFrom::UserDefinedComponentModel,
    3203             :                   anyEMSRan,
    3204      161408 :                   state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).ErlSimProgramMngr);
    3205      161408 :     } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).simPluginLocation > -1) {
    3206      161408 :         state.dataPluginManager->pluginManager->runSingleUserDefinedPlugin(
    3207      161408 :             state, state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).simPluginLocation);
    3208             :     }
    3209             : 
    3210             :     // move actuated value to MyLoad
    3211             : 
    3212      322816 :     this_component.MyLoad =
    3213      322816 :         state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSActuatorDispatchedLoadValue;
    3214      322816 :     this_component.EquipDemand =
    3215      322816 :         state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSActuatorDispatchedLoadValue;
    3216      322816 :     if (std::abs(this_component.MyLoad) > LoopDemandTol) {
    3217      125424 :         this_component.ON = true;
    3218             : 
    3219             :     } else {
    3220      197392 :         this_component.ON = false;
    3221             :     }
    3222      322816 : }
    3223             : 
    3224             : // End Load Calculation/Distribution Section of the Plant Loop Module
    3225             : //******************************************************************************
    3226             : 
    3227             : //********************************
    3228             : 
    3229      412952 : Real64 FindRangeVariable(EnergyPlusData &state,
    3230             :                          int const LoopNum,                // PlantLoop data structure loop counter
    3231             :                          int const CurSchemePtr,           // set by PL()%LoopSide()%Branch()%Comp()%OpScheme()%OpSchemePtr
    3232             :                          DataPlant::OpScheme CurSchemeType // identifier set in PlantData
    3233             : )
    3234             : {
    3235             : 
    3236             :     // SUBROUTINE INFORMATION:
    3237             :     //       AUTHOR         Sankaranarayanan K P
    3238             :     //       DATE WRITTEN   Jan 2004
    3239             :     //       MODIFIED       Chandan Sharma, August 2010
    3240             :     //       RE-ENGINEERED  na
    3241             : 
    3242             :     // Using/Aliasing
    3243             :     using namespace DataLoopNode;
    3244             :     // Return value
    3245      412952 :     Real64 FindRangeVariable(0.0);
    3246             : 
    3247             :     // Locals
    3248             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3249             :     // used to locate data in PL()%OpScheme(CurSchemePtr)
    3250             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3251             :     // na
    3252             : 
    3253             :     // INTERFACE BLOCK SPECIFICATIONS
    3254             :     // na
    3255             : 
    3256             :     // DERIVED TYPE DEFINITIONS
    3257             :     // na
    3258             : 
    3259             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3260             :     int ReferenceNodeNum;
    3261             :     Real64 NodeTemperature;
    3262             : 
    3263      412952 :     switch (CurSchemeType) {
    3264       16348 :     case OpScheme::DryBulbTDB: { // drybulb temp based controls
    3265       16348 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3266       16348 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3267       16348 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutDryBulbTemp;
    3268       16348 :         break;
    3269             :     }
    3270      381988 :     case OpScheme::WetBulbTDB: { // wetbulb temp based controls
    3271      381988 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3272      381988 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3273      381988 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutWetBulbTemp;
    3274      381988 :         break;
    3275             :     }
    3276       14616 :     case OpScheme::DewPointTDB: { // dewpoint temp based controls
    3277       14616 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3278       14616 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3279       14616 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutDewPointTemp;
    3280       14616 :         break;
    3281             :     }
    3282           0 :     default: {
    3283           0 :         assert(false);
    3284             :         break;
    3285             :     }
    3286             :     } // OperationScheme
    3287             : 
    3288      412952 :     return FindRangeVariable;
    3289             : }
    3290             : 
    3291             : //********************************
    3292             : 
    3293             : // Begin Plant Loop ON/OFF Utility Subroutines
    3294             : //******************************************************************************
    3295             : 
    3296    18707914 : void TurnOnPlantLoopPipes(EnergyPlusData &state, int const LoopNum, const LoopSideLocation LoopSideNum)
    3297             : {
    3298             :     // SUBROUTINE INFORMATION:
    3299             :     //       AUTHOR         Dan Fisher
    3300             :     //       DATE WRITTEN   July 1998
    3301             :     //       MODIFIED       na
    3302             :     //       RE-ENGINEERED  na
    3303             : 
    3304             :     // PURPOSE OF THIS SUBROUTINE: This subroutine sets a logical flag
    3305             :     // for the loop circulation pump to TRUE.
    3306             : 
    3307             :     // METHODOLOGY EMPLOYED:
    3308             :     // na
    3309             :     // REFERENCES:
    3310             :     // na
    3311             :     // USE STATEMENTS:
    3312             :     // na
    3313             : 
    3314             :     // Locals
    3315             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3316             : 
    3317             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3318             :     // na
    3319             :     // INTERFACE BLOCK SPECIFICATIONS
    3320             :     // na
    3321             :     // DERIVED TYPE DEFINITIONS
    3322             :     // na
    3323             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3324             :     int MachineOnLoopNum;
    3325             :     int Num;
    3326             : 
    3327    96007262 :     for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++Num) {
    3328   156579602 :         for (MachineOnLoopNum = 1; MachineOnLoopNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).TotalComponents;
    3329             :              ++MachineOnLoopNum) {
    3330    79280254 :             switch (state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnLoopNum).Type) {
    3331    36573374 :             case DataPlant::PlantEquipmentType::Pipe:
    3332             :             case DataPlant::PlantEquipmentType::PipeInterior:
    3333             :             case DataPlant::PlantEquipmentType::PipeExterior:
    3334             :             case DataPlant::PlantEquipmentType::PipeUnderground: {
    3335    36573374 :                 state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnLoopNum).ON = true;
    3336    36573374 :                 break;
    3337             :             }
    3338    42706880 :             default:
    3339    42706880 :                 break; // Don't do anything
    3340             :             }
    3341             :         }
    3342             :     }
    3343    18707914 : }
    3344             : 
    3345       16712 : void TurnOffLoopEquipment(EnergyPlusData &state, int const LoopNum)
    3346             : {
    3347             :     // SUBROUTINE INFORMATION:
    3348             :     //       AUTHOR         D.E. Fisher
    3349             :     //       DATE WRITTEN   July 1998
    3350             :     //       MODIFIED       D.E. Fisher, Aug. 2010
    3351             :     //       RE-ENGINEERED
    3352             : 
    3353             :     // PURPOSE OF THIS SUBROUTINE:
    3354             :     // METHODOLOGY EMPLOYED:
    3355             :     // na
    3356             :     // REFERENCES:
    3357             :     // na
    3358             :     // USE STATEMENTS:
    3359             :     // na
    3360             : 
    3361             :     // Locals
    3362             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3363             : 
    3364             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3365             :     // na
    3366             :     // INTERFACE BLOCK SPECIFICATIONS
    3367             :     // na
    3368             :     // DERIVED TYPE DEFINITIONS
    3369             :     // na
    3370             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3371             :     int MachineOnBranch;
    3372             :     int Num;
    3373             : 
    3374       50136 :     for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    3375      167120 :         for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++Num) {
    3376      267392 :             for (MachineOnBranch = 1; MachineOnBranch <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).TotalComponents;
    3377             :                  ++MachineOnBranch) {
    3378             :                 // Sankar Non Integrated Economizer
    3379      133696 :                 if (!DataPlant::PlantEquipmentTypeIsPump[static_cast<int>(
    3380      133696 :                         state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).Type)]) {
    3381      116984 :                     state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).ON = false;
    3382      116984 :                     state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).MyLoad = 0.0;
    3383             :                 }
    3384             :             }
    3385             :         }
    3386             :     }
    3387       16712 : }
    3388             : 
    3389           0 : void TurnOffLoopSideEquipment(EnergyPlusData &state, int const LoopNum, const LoopSideLocation LoopSideNum)
    3390             : {
    3391             :     // SUBROUTINE INFORMATION:
    3392             :     //       AUTHOR         D.E. Fisher
    3393             :     //       DATE WRITTEN   July 1998
    3394             :     //       MODIFIED       D.E. Fisher, Aug. 2010
    3395             :     //       RE-ENGINEERED
    3396             : 
    3397             :     // PURPOSE OF THIS SUBROUTINE:
    3398             :     // METHODOLOGY EMPLOYED:
    3399             :     // na
    3400             :     // REFERENCES:
    3401             :     // na
    3402             :     // USE STATEMENTS:
    3403             :     // na
    3404             : 
    3405             :     // Locals
    3406             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3407             : 
    3408             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3409             :     // na
    3410             :     // INTERFACE BLOCK SPECIFICATIONS
    3411             :     // na
    3412             :     // DERIVED TYPE DEFINITIONS
    3413             :     // na
    3414             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3415             :     int MachineOnBranch;
    3416             :     int Num;
    3417             : 
    3418           0 :     for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++Num) {
    3419           0 :         for (MachineOnBranch = 1; MachineOnBranch <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).TotalComponents;
    3420             :              ++MachineOnBranch) {
    3421             :             // Sankar Non Integrated Economizer
    3422           0 :             if (!DataPlant::PlantEquipmentTypeIsPump[static_cast<int>(
    3423           0 :                     state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).Type)]) {
    3424           0 :                 state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).ON = false;
    3425           0 :                 state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).MyLoad = 0.0;
    3426             :             }
    3427             :         }
    3428             :     }
    3429           0 : }
    3430             : 
    3431             : // End Plant Loop ON/OFF Utility Subroutines
    3432             : //******************************************************************************
    3433             : 
    3434             : // Begin Plant EMS Control Routines
    3435             : //******************************************************************************
    3436             : 
    3437          71 : void SetupPlantEMSActuators(EnergyPlusData &state)
    3438             : {
    3439             : 
    3440             :     // SUBROUTINE INFORMATION:
    3441             :     //       AUTHOR         D.E. Fisher
    3442             :     //       DATE WRITTEN   Feb 2007
    3443             :     //       MODIFIED       B. Griffith August 2009, D. Fisher, Aug. 2010
    3444             :     //       RE-ENGINEERED  na
    3445             : 
    3446             :     // PURPOSE OF THIS SUBROUTINE:
    3447             :     // This subroutine loads the plant EMS actuators
    3448             : 
    3449             :     // METHODOLOGY EMPLOYED:
    3450             :     // Call the setupAcuator routine
    3451             : 
    3452             :     // Locals
    3453         142 :     std::string ActuatorType;
    3454         142 :     std::string ActuatorName;
    3455         142 :     std::string UniqueIDName;
    3456             :     static constexpr std::string_view Units("[on/off]");
    3457             :     // INTEGER                      :: NumAct
    3458             :     int LoopNum;
    3459             :     int BranchNum;
    3460             :     int CompNum;
    3461             : 
    3462         187 :     for (LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    3463         116 :         ActuatorName = "Plant Loop Overall";
    3464         116 :         UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    3465         116 :         ActuatorType = "On/Off Supervisory";
    3466         232 :         SetupEMSActuator(state,
    3467             :                          ActuatorName,
    3468             :                          UniqueIDName,
    3469             :                          ActuatorType,
    3470             :                          Units,
    3471         116 :                          state.dataPlnt->PlantLoop(LoopNum).EMSCtrl,
    3472         116 :                          state.dataPlnt->PlantLoop(LoopNum).EMSValue);
    3473             : 
    3474         116 :         ActuatorName = "Supply Side Half Loop";
    3475         116 :         UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    3476         116 :         ActuatorType = "On/Off Supervisory";
    3477         232 :         SetupEMSActuator(state,
    3478             :                          ActuatorName,
    3479             :                          UniqueIDName,
    3480             :                          ActuatorType,
    3481             :                          Units,
    3482         116 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Supply).EMSCtrl,
    3483         116 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Supply).EMSValue);
    3484             : 
    3485         116 :         ActuatorName = "Demand Side Half Loop";
    3486         116 :         UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    3487         116 :         ActuatorType = "On/Off Supervisory";
    3488         232 :         SetupEMSActuator(state,
    3489             :                          ActuatorName,
    3490             :                          UniqueIDName,
    3491             :                          ActuatorType,
    3492             :                          Units,
    3493         116 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Demand).EMSCtrl,
    3494         116 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Demand).EMSValue);
    3495             : 
    3496         348 :         for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    3497        2493 :             for (BranchNum = 1; BranchNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++BranchNum) {
    3498        2261 :                 if (LoopSideNum == LoopSideLocation::Supply) {
    3499         480 :                     ActuatorName = "Supply Side Branch";
    3500         480 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Name;
    3501         480 :                     ActuatorType = "On/Off Supervisory";
    3502         960 :                     SetupEMSActuator(state,
    3503             :                                      ActuatorName,
    3504             :                                      UniqueIDName,
    3505             :                                      ActuatorType,
    3506             :                                      Units,
    3507         480 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideOn,
    3508         480 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideValue);
    3509        1781 :                 } else if (LoopSideNum == LoopSideLocation::Demand) {
    3510        1781 :                     ActuatorName = "Demand Side Branch";
    3511        1781 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Name;
    3512        1781 :                     ActuatorType = "On/Off Supervisory";
    3513        3562 :                     SetupEMSActuator(state,
    3514             :                                      ActuatorName,
    3515             :                                      UniqueIDName,
    3516             :                                      ActuatorType,
    3517             :                                      Units,
    3518        1781 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideOn,
    3519        1781 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideValue);
    3520             :                 }
    3521        4537 :                 for (CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).TotalComponents; ++CompNum) {
    3522        2276 :                     ActuatorName = format("Plant Component {}",
    3523             :                                           PlantEquipTypeNames[static_cast<int>(
    3524        2276 :                                               state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).Type)]);
    3525        2276 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).Name;
    3526        2276 :                     ActuatorType = "On/Off Supervisory";
    3527        6828 :                     SetupEMSActuator(state,
    3528             :                                      ActuatorName,
    3529             :                                      UniqueIDName,
    3530             :                                      ActuatorType,
    3531             :                                      "[fraction]",
    3532        2276 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).EMSLoadOverrideOn,
    3533        4552 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).EMSLoadOverrideValue);
    3534             :                 }
    3535             :             }
    3536             :         }
    3537             :     }
    3538          71 : }
    3539             : 
    3540    37773476 : void ActivateEMSControls(EnergyPlusData &state, PlantLocation const &plantLoc, bool &LoopShutDownFlag)
    3541             : {
    3542             : 
    3543             :     // SUBROUTINE INFORMATION:
    3544             :     //       AUTHOR         D.E. Fisher
    3545             :     //       DATE WRITTEN   Feb 2007
    3546             :     //       MODIFIED
    3547             :     //       RE-ENGINEERED  na
    3548             : 
    3549             :     // PURPOSE OF THIS SUBROUTINE:
    3550             :     // This subroutine loads the plant EMS actuators
    3551             : 
    3552             :     // METHODOLOGY EMPLOYED: The EMS flags are evaluated in hierarchical order:
    3553             :     //     LOOP flags override branch and component flags
    3554             :     //     BRANCH flags override component flags
    3555             :     // If the loop flag (EMSCtrl) is true, then
    3556             :     //     IF EMSValue <= 0, shut down the entire loop including the pumps
    3557             :     //     IF EMSValue > 0, no action
    3558             :     // If the LoopSide flag (EMSCtrl) is true, then:
    3559             :     //     IF EMSValue <=0, shut down all components on the LoopSide except the pumps
    3560             :     //     IF EMSValue > 0, no action
    3561             :     // If a component flag (EMSCtrl) is true, then:
    3562             :     //     EMSValue <=0, shut down the component
    3563             :     //     EMSValue > 0, calc. component load: MyLoad=MIN(MaxCompLoad,MaxCompLoad*EMSValue)
    3564             : 
    3565             :     // REFERENCES:
    3566             :     // na
    3567             : 
    3568             :     // Using/Aliasing
    3569             :     using namespace DataLoopNode;
    3570             : 
    3571             :     // SUBROUTINE ARGUMENT DEFINITIONS
    3572             : 
    3573             :     // Locals
    3574             :     // SUBROUTINE PARAMETER DEFINITIONS
    3575             :     static constexpr std::string_view RoutineName("ActivateEMSControls");
    3576             : 
    3577             :     // SUBROUTINE VARIABLE DEFINITIONS
    3578             :     Real64 CurMassFlowRate;
    3579             :     Real64 ToutLowLimit;
    3580             :     Real64 Tinlet;
    3581             :     Real64 CurSpecHeat;
    3582             :     Real64 QTemporary;
    3583             :     // unused REAL(r64)                  :: ChangeInLoad
    3584             : 
    3585             :     // MODULE VARIABLE DECLARATIONS:
    3586             : 
    3587             :     // set up some nice references to avoid lookups
    3588    37773476 :     auto &this_loop(state.dataPlnt->PlantLoop(plantLoc.loopNum));
    3589    37773476 :     auto &this_loopside(this_loop.LoopSide(plantLoc.loopSideNum));
    3590    37773476 :     auto &this_comp(this_loopside.Branch(plantLoc.branchNum).Comp(plantLoc.compNum));
    3591             : 
    3592             :     // Loop Control
    3593    37773476 :     if (this_loop.EMSCtrl) {
    3594        8356 :         if (this_loop.EMSValue <= 0.0) {
    3595        8356 :             LoopShutDownFlag = true;
    3596        8356 :             TurnOffLoopEquipment(state, plantLoc.loopNum);
    3597      161728 :             return;
    3598             :         } else {
    3599           0 :             LoopShutDownFlag = false;
    3600             :         }
    3601             :     } else {
    3602    37765120 :         LoopShutDownFlag = false;
    3603             :     }
    3604             : 
    3605             :     // Half-loop control
    3606    37765120 :     if (this_loopside.EMSCtrl) {
    3607           0 :         if (this_loopside.EMSValue <= 0.0) {
    3608           0 :             TurnOffLoopSideEquipment(state, plantLoc.loopNum, plantLoc.loopSideNum);
    3609           0 :             return;
    3610             :         } else {
    3611             :             // do nothing:  can't turn all LoopSide equip. ON with loop switch
    3612             :         }
    3613             :     }
    3614             : 
    3615    37765120 :     if (this_comp.EMSLoadOverrideOn) {
    3616             :         // EMSValue <= 0 turn component OFF
    3617      145016 :         if (this_comp.EMSLoadOverrideValue <= 0.0) {
    3618      145016 :             this_comp.ON = false;
    3619      145016 :             this_comp.Available = false;
    3620      145016 :             this_comp.MyLoad = 0.0;
    3621      145016 :             return;
    3622             :         } else {
    3623             :             // EMSValue > 0 Set Component Load and Turn component ON
    3624           0 :             this_comp.ON = true;
    3625           0 :             this_comp.Available = false;
    3626           0 :             this_comp.MyLoad = min(this_comp.MaxLoad, (this_comp.MaxLoad * this_comp.EMSLoadOverrideValue));
    3627             : 
    3628             :             // Check lower/upper temperature limit for chillers
    3629           0 :             switch (this_comp.Type) {
    3630             : 
    3631           0 :             case DataPlant::PlantEquipmentType::Chiller_ElectricEIR:
    3632             :             case DataPlant::PlantEquipmentType::Chiller_Electric:
    3633             :             case DataPlant::PlantEquipmentType::Chiller_ElectricReformEIR: {
    3634             : 
    3635             :                 //- Retrieve data from the plant loop data structure
    3636           0 :                 CurMassFlowRate = state.dataLoopNodes->Node(this_comp.NodeNumIn).MassFlowRate;
    3637           0 :                 ToutLowLimit = this_comp.MinOutletTemp;
    3638           0 :                 Tinlet = state.dataLoopNodes->Node(this_comp.NodeNumIn).Temp;
    3639           0 :                 CurSpecHeat = GetSpecificHeatGlycol(state, this_loop.FluidName, Tinlet, this_loop.FluidIndex, RoutineName);
    3640           0 :                 QTemporary = CurMassFlowRate * CurSpecHeat * (Tinlet - ToutLowLimit);
    3641             : 
    3642             :                 //- Don't correct if Q is zero, as this could indicate a component which this hasn't been implemented
    3643           0 :                 if (QTemporary > 0.0) {
    3644           0 :                     if (std::abs(this_comp.MyLoad) > this_comp.MaxLoad) {
    3645           0 :                         this_comp.MyLoad = sign(this_comp.MaxLoad, this_comp.MyLoad);
    3646             :                     }
    3647           0 :                     if (std::abs(this_comp.MyLoad) > QTemporary) {
    3648           0 :                         this_comp.MyLoad = sign(QTemporary, this_comp.MyLoad);
    3649             :                     }
    3650             :                 }
    3651           0 :                 break;
    3652             :             }
    3653           0 :             default:
    3654           0 :                 break; // Nothing Changes for now, could add in case statements for boilers, which would use upper limit temp check
    3655             :             }
    3656           0 :             return;
    3657             :         } // EMSValue <=> 0
    3658             :     }     // EMSFlag
    3659             : }
    3660             : 
    3661    18367651 : void AdjustChangeInLoadByEMSControls(EnergyPlusData &state,
    3662             :                                      PlantLocation const &plantLoc,
    3663             :                                      Real64 &ChangeInLoad // positive magnitude of load change
    3664             : )
    3665             : {
    3666             : 
    3667             :     // SUBROUTINE INFORMATION:
    3668             :     //       AUTHOR         B. Griffith
    3669             :     //       DATE WRITTEN   April 2012
    3670             :     //       MODIFIED       na
    3671             :     //       RE-ENGINEERED  na
    3672             : 
    3673             :     // PURPOSE OF THIS SUBROUTINE:
    3674             :     // modify load dispatch if EMS controls are in place for a specific component
    3675             : 
    3676             :     // METHODOLOGY EMPLOYED:
    3677             :     // Check if Loop Side is shutdown
    3678             :     //  then check if branch is shutdown
    3679             :     // then  check if component is overridden and use the value if it is.
    3680             :     // take ABS() of EMS value to ensure sign is correct.
    3681             : 
    3682             :     // REFERENCES:
    3683             :     // na
    3684             : 
    3685             :     // USE STATEMENTS:
    3686             :     // na
    3687             : 
    3688             :     // Locals
    3689             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3690             : 
    3691             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3692             :     // na
    3693             : 
    3694             :     // INTERFACE BLOCK SPECIFICATIONS:
    3695             :     // na
    3696             : 
    3697             :     // DERIVED TYPE DEFINITIONS:
    3698             :     // na
    3699             : 
    3700             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3701             : 
    3702             :     // set up some nice references to avoid lookups
    3703    18367651 :     auto &this_loopside(state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum));
    3704    18367651 :     auto &this_branch(this_loopside.Branch(plantLoc.branchNum));
    3705    18367651 :     auto &this_comp(this_branch.Comp(plantLoc.compNum));
    3706             : 
    3707    18367651 :     if ((this_loopside.EMSCtrl) && (this_loopside.EMSValue <= 0.0)) {
    3708           0 :         ChangeInLoad = 0.0;
    3709           0 :         return;
    3710             :     }
    3711             : 
    3712    18367651 :     if ((this_branch.EMSCtrlOverrideOn) && (this_branch.EMSCtrlOverrideValue <= 0.0)) {
    3713           0 :         ChangeInLoad = 0.0;
    3714           0 :         return;
    3715             :     }
    3716             : 
    3717    18367651 :     if (this_comp.EMSLoadOverrideOn) {
    3718       52228 :         if (this_comp.EMSLoadOverrideValue == 0.0) {
    3719         672 :             ChangeInLoad = 0.0;
    3720             :         }
    3721             :     }
    3722             : }
    3723             : 
    3724             : //*END PLANT EMS CONTROL ROUTINES!
    3725             : //******************************************************************************
    3726             : 
    3727        2313 : } // namespace EnergyPlus::PlantCondLoopOperation

Generated by: LCOV version 1.13