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

Generated by: LCOV version 2.0-1