LCOV - code coverage report
Current view: top level - EnergyPlus - PlantCondLoopOperation.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 55.5 % 2182 1211
Test Date: 2025-05-22 16:09:37 Functions: 79.2 % 24 19

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

Generated by: LCOV version 2.0-1