LCOV - code coverage report
Current view: top level - EnergyPlus - PlantCondLoopOperation.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 66.6 % 2226 1482
Test Date: 2025-06-03 15:18:44 Functions: 91.7 % 24 22

            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     38913632 : 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     38913632 :     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     38913632 :     if (LoopShutDownFlag) {
     150        16612 :         TurnOffLoopEquipment(state, plantLoc.loopNum);
     151        16612 :         return;
     152              :     }
     153              : 
     154              :     // Return if there are no loop operation schemes available
     155     38897020 :     if (!std::any_of(state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme.begin(),
     156     38897020 :                      state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme.end(),
     157     41716576 :                      [](DataPlant::OperationData const &e) { return e.Available; })) {
     158            0 :         return;
     159              :     }
     160              : 
     161              :     // set up references
     162     38897020 :     auto &loop_side = state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum);
     163     38897020 :     auto &this_component = loop_side.Branch(plantLoc.branchNum).Comp(plantLoc.compNum);
     164              : 
     165              :     // Implement EMS control commands
     166     38897020 :     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     38897020 :     CurCompLevelOpNum = this_component.CurCompLevelOpNum;
     171              :     // If no current operation scheme for component, RETURN
     172     38897020 :     if (CurCompLevelOpNum == 0) {
     173            0 :         return;
     174              :     }
     175              :     // set local variables from data structure
     176     38897020 :     NumEquipLists = this_component.OpScheme(CurCompLevelOpNum).NumEquipLists;
     177     38897020 :     CurSchemePtr = this_component.OpScheme(CurCompLevelOpNum).OpSchemePtr;
     178     38897020 :     DataPlant::OpScheme CurSchemeType = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).Type;
     179              : 
     180              :     // another reference
     181     38897020 :     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     38897020 :     switch (CurSchemeType) {
     185      1161430 :     case OpScheme::Uncontrolled:
     186              :     case OpScheme::CompSetPtBased: {
     187              :         // No RangeVariable specified for these types
     188      1161430 :         break;
     189              :     }
     190       322816 :     case OpScheme::EMS: {
     191       322816 :         InitLoadDistribution(state, FirstHVACIteration);
     192              :         // No RangeVariable specified for these types
     193       322816 :         break;
     194              :     }
     195     16060568 :     case OpScheme::HeatingRB: {
     196              :         // For zero demand, we need to clean things out before we leave
     197     16060568 :         if (LoopDemand < SmallLoad) {
     198      6826521 :             InitLoadDistribution(state, FirstHVACIteration);
     199      6826521 :             this_component.MyLoad = 0.0;
     200      6826521 :             this_component.ON = false;
     201      6826521 :             return;
     202              :         }
     203      9234047 :         RangeVariable = LoopDemand;
     204      9234047 :         break;
     205              :     }
     206     20894330 :     case OpScheme::CoolingRB: {
     207              :         // For zero demand, we need to clean things out before we leave
     208     20894330 :         if (LoopDemand > (-1.0 * SmallLoad)) {
     209     12344385 :             InitLoadDistribution(state, FirstHVACIteration);
     210     12344385 :             this_component.MyLoad = 0.0;
     211     12344385 :             this_component.ON = false;
     212     12344385 :             return;
     213              :         }
     214      8549945 :         RangeVariable = LoopDemand;
     215      8549945 :         break;
     216              :     }
     217        14544 :     case OpScheme::DryBulbRB: {
     218        14544 :         RangeVariable = state.dataEnvrn->OutDryBulbTemp;
     219        14544 :         break;
     220              :     }
     221        14544 :     case OpScheme::WetBulbRB: {
     222        14544 :         RangeVariable = state.dataEnvrn->OutWetBulbTemp;
     223        14544 :         break;
     224              :     }
     225        14544 :     case OpScheme::RelHumRB: {
     226        14544 :         RangeVariable = state.dataEnvrn->OutRelHum;
     227        14544 :         break;
     228              :     }
     229        14544 :     case OpScheme::DewPointRB: {
     230        14544 :         RangeVariable = state.dataEnvrn->OutDewPointTemp;
     231        14544 :         break;
     232              :     }
     233       399700 :     case OpScheme::DryBulbTDB:
     234              :     case OpScheme::WetBulbTDB:
     235              :     case OpScheme::DewPointTDB: {
     236       399700 :         RangeVariable = FindRangeVariable(state, plantLoc.loopNum, CurSchemePtr, CurSchemeType);
     237       399700 :         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     19726114 :     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      1161430 :     case OpScheme::CompSetPtBased: {
     255              :         // check for EMS Control
     256      1161430 :         TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     257      1161430 :         FindCompSPLoad(state, plantLoc, CurCompLevelOpNum);
     258      1161430 :         break;
     259              :     }
     260       322816 :     case OpScheme::EMS: {
     261       322816 :         TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     262       322816 :         DistributeUserDefinedPlantLoad(state, plantLoc, CurCompLevelOpNum, CurSchemePtr, LoopDemand, RemLoopDemand);
     263       322816 :         break;
     264              :     }
     265     18241868 :     default: { // it's a range based control type with multiple equipment lists
     266     18241868 :         int ListPtr = 0;
     267     18241868 :         int CurListNum = 0;
     268     18670298 :         for (int ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     269              :             // setpointers to 'PlantLoop()%OpScheme()...'structure
     270     18380056 :             ListPtr = this_component.OpScheme(CurCompLevelOpNum).EquipList(ListNum).ListPtr;
     271     18380056 :             RangeHiLimit = this_op_scheme.EquipList(ListPtr).RangeUpperLimit;
     272     18380056 :             RangeLoLimit = this_op_scheme.EquipList(ListPtr).RangeLowerLimit;
     273     18380056 :             if (CurSchemeType == OpScheme::HeatingRB || CurSchemeType == OpScheme::CoolingRB) {
     274              :                 // these limits are stored with absolute values, but the LoopDemand can be negative for cooling
     275     17892238 :                 TestRangeVariable = std::abs(RangeVariable);
     276              :             } else {
     277       487818 :                 TestRangeVariable = RangeVariable;
     278              :             }
     279              : 
     280              :             // trying to do something where the last stage still runs the equipment but at the hi limit.
     281              : 
     282     18380056 :             if (TestRangeVariable < RangeLoLimit || TestRangeVariable > RangeHiLimit) {
     283       464808 :                 if ((TestRangeVariable > RangeHiLimit) && (ListPtr == this_op_scheme.EquipListNumForLastStage)) {
     284              :                     // let this go thru, later AdjustChangeInLoadForLastStageUpperRangeLimit will cap dispatch to RangeHiLimit
     285        36378 :                     CurListNum = ListNum;
     286        36378 :                     break;
     287              :                 } else {
     288       428430 :                     continue;
     289              :                 }
     290              :             } else {
     291     17915248 :                 CurListNum = ListNum;
     292     17915248 :                 break;
     293              :             }
     294              :         }
     295              : 
     296     18241868 :         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     36154194 :             for (int ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     299     18202568 :                 if (ListNum == CurListNum) {
     300     17951626 :                     continue; // leave current one alone
     301              :                 }
     302       250942 :                 int NumCompsOnList = this_op_scheme.EquipList(ListNum).NumComps;
     303       582322 :                 for (int CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
     304       331380 :                     int EquipBranchNum = this_op_scheme.EquipList(ListNum).Comp(CompIndex).BranchNumPtr;
     305       331380 :                     int EquipCompNum = this_op_scheme.EquipList(ListNum).Comp(CompIndex).CompNumPtr;
     306       331380 :                     loop_side.Branch(EquipBranchNum).Comp(EquipCompNum).MyLoad = 0.0;
     307              :                 }
     308              :             }
     309     17951626 :             if (this_op_scheme.EquipList(ListPtr).NumComps > 0) {
     310     17951626 :                 TurnOnPlantLoopPipes(state, plantLoc.loopNum, plantLoc.loopSideNum);
     311     17951626 :                 DistributePlantLoad(state, plantLoc.loopNum, plantLoc.loopSideNum, CurSchemePtr, ListPtr, LoopDemand, RemLoopDemand);
     312     17951626 :                 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          462 : 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          462 :     std::string CurrentModuleObject; // for ease in renaming
     355          462 :     std::string PlantLoopObject;     // for ease in renaming
     356              :     bool ErrorsFound;                // Passed in from OpSchemeInput
     357              : 
     358          462 :     ErrorsFound = false;
     359              : 
     360          462 :     if (!allocated(state.dataPlnt->PlantLoop)) {
     361            0 :         GetInputOK = false;
     362            0 :         return;
     363              :     } else {
     364          462 :         GetInputOK = true;
     365              :     }
     366              : 
     367              :     // get number of operation schemes
     368          462 :     CurrentModuleObject = "PlantEquipmentOperationSchemes";
     369          462 :     NumPlantOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     370         1353 :     for (OpNum = 1; OpNum <= NumPlantOpSchemes; ++OpNum) {
     371         1782 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     372          891 :             state, CurrentModuleObject, OpNum, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     373          891 :         if (Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) {
     374            0 :             continue;
     375              :         }
     376              :     }
     377              : 
     378          462 :     CurrentModuleObject = "CondenserEquipmentOperationSchemes";
     379          462 :     NumCondOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     380          724 :     for (OpNum = 1; OpNum <= NumCondOpSchemes; ++OpNum) {
     381          524 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     382          262 :             state, CurrentModuleObject, OpNum, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     383          262 :         if (Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound)) {
     384            0 :             continue;
     385              :         }
     386              :     }
     387              : 
     388              :     // Load the Plant data structure
     389         1619 :     for (LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
     390         1157 :         std::string PlantOpSchemeName = state.dataPlnt->PlantLoop(LoopNum).OperationScheme;
     391         1157 :         if (LoopNum <= state.dataHVACGlobal->NumPlantLoops) {
     392          897 :             CurrentModuleObject = "PlantEquipmentOperationSchemes";
     393          897 :             PlantLoopObject = "PlantLoop";
     394              :         } else {
     395          260 :             CurrentModuleObject = "CondenserEquipmentOperationSchemes";
     396          260 :             PlantLoopObject = "CondenserLoop";
     397              :         }
     398         1157 :         OpNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, CurrentModuleObject, PlantOpSchemeName);
     399         1157 :         if (OpNum > 0) {
     400         2314 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     401              :                                                                      CurrentModuleObject,
     402              :                                                                      OpNum,
     403         1157 :                                                                      state.dataIPShortCut->cAlphaArgs,
     404              :                                                                      NumAlphas,
     405         1157 :                                                                      state.dataIPShortCut->rNumericArgs,
     406              :                                                                      NumNums,
     407              :                                                                      IOStat,
     408         1157 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     409         1157 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     410         1157 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     411         1157 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     412              : 
     413         1157 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     414              : 
     415         1157 :             state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes = (NumAlphas - 1) / 3;
     416         1157 :             if (state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes > 0) {
     417         1157 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme.clear();
     418         1157 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme.allocate(state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes);
     419         2438 :                 for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes; ++Num) {
     420         1281 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).TypeOf = state.dataIPShortCut->cAlphaArgs(Num * 3 - 1);
     421              : 
     422              :                     {
     423         1281 :                         std::string const &plantLoopOperation = state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).TypeOf;
     424         1281 :                         if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COOLINGLOAD") {
     425          699 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::CoolingRB;
     426          582 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:HEATINGLOAD") {
     427          501 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::HeatingRB;
     428           81 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COMPONENTSETPOINT") { //* Temp Based Control
     429           15 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::CompSetPtBased;
     430           66 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:CHILLERHEATERCHANGEOVER") {
     431           10 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::ChillerHeaterSupervisory;
     432           56 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") { //* Simple TES Control
     433            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type =
     434              :                                 OpScheme::CompSetPtBased; // set this to component based as it will be converted to this
     435           55 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:USERDEFINED") {
     436            6 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::EMS;
     437            6 :                             state.dataPlnt->AnyEMSPlantOpSchemesInModel = true;
     438           49 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULB") {
     439            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DryBulbRB;
     440           48 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULB") {
     441            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::WetBulbRB;
     442           47 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINT") {
     443            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DewPointRB;
     444           46 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORRELATIVEHUMIDITY") {
     445            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::RelHumRB;
     446           45 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULBDIFFERENCE") {
     447            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DryBulbTDB;
     448           44 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULBDIFFERENCE") {
     449            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::WetBulbTDB;
     450           43 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINTDIFFERENCE") {
     451            1 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Type = OpScheme::DewPointTDB;
     452           42 :                         } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:UNCONTROLLED") {
     453           42 :                             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         1281 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).Name = state.dataIPShortCut->cAlphaArgs(Num * 3);
     467              : 
     468         1281 :                     if ((state.dataPlnt->PlantLoop(LoopNum).OpScheme(Num).sched =
     469         2562 :                              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         1157 :     }
     491              : 
     492          462 :     if (ErrorsFound) {
     493            0 :         ShowFatalError(
     494            0 :             state, format("{}Errors found in getting input for PlantEquipmentOperationSchemes or CondenserEquipmentOperationSchemes", RoutineName));
     495              :     }
     496          462 : }
     497              : 
     498          462 : 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          462 :     std::string CurrentModuleObject; // for ease in renaming.
     552          462 :     std::unordered_map<std::string, std::string> UniqueNames;
     553              : 
     554          462 :     ErrorsFound = false;
     555              : 
     556              :     //**********VERIFY THE 'PLANTEQUIPMENTOPERATION:...' KEYWORDS**********
     557          462 :     CLRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:CoolingLoad");
     558          462 :     HLRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:HeatingLoad");
     559          462 :     DBRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDryBulb");
     560          462 :     WBRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorWetBulb");
     561          462 :     DPRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDewpoint");
     562          462 :     RHRBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorRelativeHumidity");
     563          462 :     CSPBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:ComponentSetpoint"); //* Temp Based Control
     564          462 :     NumUserDefOpSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:UserDefined");
     565          462 :     DBTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDryBulbDifference");
     566          462 :     WBTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorWetBulbDifference");
     567          462 :     DPTDBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:OutdoorDewpointDifference");
     568          462 :     TESSPBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:ThermalEnergyStorage");
     569          462 :     ACXSPBO = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:ChillerHeaterChangeover");
     570          462 :     NumSchemes = CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUserDefOpSchemes + TESSPBO + ACXSPBO;
     571          462 :     NumUncontrolledSchemes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentOperation:Uncontrolled");
     572          462 :     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          462 :     UniqueNames.reserve(static_cast<unsigned>(NumSchemes));
     578              : 
     579              :     // Check for existence of duplicates in keyword names
     580          462 :     Count = 0;
     581         1703 :     for (Num = 1; Num <= NumSchemes; ++Num) {
     582         1241 :         if (CLRBO > 0 && Num <= CLRBO) {
     583          708 :             CurrentModuleObject = "PlantEquipmentOperation:CoolingLoad";
     584          708 :             Count = Num;
     585          533 :         } else if (HLRBO > 0 && Num <= (CLRBO + HLRBO)) {
     586          501 :             CurrentModuleObject = "PlantEquipmentOperation:HeatingLoad";
     587          501 :             Count = Num - CLRBO;
     588           32 :         } else if (DBRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO)) {
     589            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulb";
     590            1 :             Count = Num - CLRBO - HLRBO;
     591           31 :         } else if (WBRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO)) {
     592            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulb";
     593            1 :             Count = Num - CLRBO - HLRBO - DBRBO;
     594           30 :         } else if (DPRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO)) {
     595            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewpoint";
     596            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO;
     597           29 :         } else if (RHRBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO)) {
     598            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorRelativeHumidity";
     599            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO;
     600           28 :         } else if (CSPBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO)) {
     601           15 :             CurrentModuleObject = "PlantEquipmentOperation:ComponentSetpoint";
     602           15 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO;
     603           13 :         } else if (DBTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO)) {
     604            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulbDifference";
     605            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO;
     606           12 :         } else if (WBTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO)) {
     607            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulbDifference";
     608            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO;
     609           11 :         } else if (DPTDBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO)) {
     610            1 :             CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewpointDifference";
     611            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO;
     612           10 :         } else if (NumUncontrolledSchemes > 0 &&
     613            1 :                    Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUncontrolledSchemes)) {
     614            1 :             CurrentModuleObject = "PlantEquipmentOperation:Uncontrolled";
     615            1 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO - DPTDBO;
     616            9 :         } else if (NumUserDefOpSchemes > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO +
     617            6 :                                                       NumUncontrolledSchemes + NumUserDefOpSchemes)) {
     618            6 :             CurrentModuleObject = "PlantEquipmentOperation:UserDefined";
     619            6 :             Count = Num - CLRBO - HLRBO - DBRBO - WBRBO - DPRBO - RHRBO - CSPBO - DBTDBO - WBTDBO - DPTDBO - NumUncontrolledSchemes;
     620            3 :         } else if (TESSPBO > 0 && Num <= (CLRBO + HLRBO + DBRBO + WBRBO + DPRBO + RHRBO + CSPBO + DBTDBO + WBTDBO + DPTDBO + NumUncontrolledSchemes +
     621            1 :                                           NumUserDefOpSchemes + TESSPBO)) {
     622            1 :             CurrentModuleObject = "PlantEquipmentOperation:ThermalEnergyStorage";
     623            1 :             Count =
     624            1 :                 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         2482 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     635         1241 :             state, CurrentModuleObject, Count, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     636         1241 :         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          462 :     PELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentList");
     643          462 :     CELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CondenserEquipmentList");
     644          462 :     NumSchemeLists = PELists + CELists;
     645          462 :     UniqueNames.clear();
     646          462 :     UniqueNames.reserve(NumSchemeLists);
     647          462 :     Count = 0;
     648         1967 :     for (Num = 1; Num <= NumSchemeLists; ++Num) {
     649         1505 :         if (Num <= PELists) {
     650         1234 :             CurrentModuleObject = "PlantEquipmentList";
     651         1234 :             Count = Num;
     652              :         } else {
     653          271 :             CurrentModuleObject = "CondenserEquipmentList";
     654          271 :             Count = Num - PELists;
     655              :         }
     656         3010 :         state.dataInputProcessing->inputProcessor->getObjectItem(
     657         1505 :             state, CurrentModuleObject, Count, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
     658         1505 :         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          462 :     NumSchemeLists += CSPBO + TESSPBO + NumUserDefOpSchemes;
     667         1619 :     for (LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
     668         2438 :         for (SchemeNum = 1; SchemeNum <= state.dataPlnt->PlantLoop(LoopNum).NumOpSchemes; ++SchemeNum) {
     669              : 
     670              :             {
     671         1281 :                 std::string const &plantLoopOperation = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).TypeOf;
     672              : 
     673         1281 :                 if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COOLINGLOAD") {
     674          699 :                     CurrentModuleObject = "PlantEquipmentOperation:CoolingLoad";
     675          699 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, CLRBO, LoopNum, SchemeNum, ErrorsFound);
     676              : 
     677          582 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:HEATINGLOAD") {
     678          501 :                     CurrentModuleObject = "PlantEquipmentOperation:HeatingLoad";
     679          501 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, HLRBO, LoopNum, SchemeNum, ErrorsFound);
     680              : 
     681           81 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:COMPONENTSETPOINT") { //* Temp Based Control
     682           15 :                     CurrentModuleObject = "PlantEquipmentOperation:ComponentSetPoint";
     683           15 :                     FindCompSPInput(state, CurrentModuleObject, CSPBO, LoopNum, SchemeNum, ErrorsFound);
     684              : 
     685           66 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:USERDEFINED") {
     686            6 :                     CurrentModuleObject = "PlantEquipmentOperation:UserDefined";
     687            6 :                     GetUserDefinedOpSchemeInput(state, CurrentModuleObject, NumUserDefOpSchemes, LoopNum, SchemeNum, ErrorsFound);
     688              : 
     689           60 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULB") {
     690            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulb";
     691            1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, DBRBO, LoopNum, SchemeNum, ErrorsFound);
     692              : 
     693           59 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULB") {
     694            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulb";
     695            1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, WBRBO, LoopNum, SchemeNum, ErrorsFound);
     696              : 
     697           58 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINT") {
     698            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewPoint";
     699            1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, DPRBO, LoopNum, SchemeNum, ErrorsFound);
     700              : 
     701           57 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORRELATIVEHUMIDITY") {
     702            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorrelativeHumidity";
     703            1 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, RHRBO, LoopNum, SchemeNum, ErrorsFound);
     704              : 
     705           56 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDRYBULBDIFFERENCE") {
     706            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDryBulbDifference";
     707            1 :                     FindDeltaTempRangeInput(state,
     708              :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorDrybulbDifference,
     709              :                                             DBTDBO,
     710              :                                             LoopNum,
     711              :                                             SchemeNum,
     712              :                                             ErrorsFound);
     713              : 
     714           55 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORWETBULBDIFFERENCE") {
     715            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorWetBulbDifference";
     716            1 :                     FindDeltaTempRangeInput(state,
     717              :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorWetbulbDifference,
     718              :                                             WBTDBO,
     719              :                                             LoopNum,
     720              :                                             SchemeNum,
     721              :                                             ErrorsFound);
     722              : 
     723           54 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:OUTDOORDEWPOINTDIFFERENCE") {
     724            1 :                     CurrentModuleObject = "PlantEquipmentOperation:OutdoorDewPointDifference";
     725            1 :                     FindDeltaTempRangeInput(state,
     726              :                                             DataLoopNode::ConnectionObjectType::PlantEquipmentOperationOutdoorDewpointDifference,
     727              :                                             DPTDBO,
     728              :                                             LoopNum,
     729              :                                             SchemeNum,
     730              :                                             ErrorsFound);
     731              : 
     732           53 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:UNCONTROLLED") {
     733           42 :                     CurrentModuleObject = "PlantEquipmentOperation:Uncontrolled";
     734           42 :                     FindRangeBasedOrUncontrolledInput(state, CurrentModuleObject, NumUncontrolledSchemes, LoopNum, SchemeNum, ErrorsFound);
     735              : 
     736           11 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") { //* Temp Based Control
     737            1 :                     CurrentModuleObject = "PlantEquipmentOperation:ThermalEnergyStorage";
     738            1 :                     FindCompSPInput(state, CurrentModuleObject, TESSPBO, LoopNum, SchemeNum, ErrorsFound);
     739              : 
     740           10 :                 } else if (plantLoopOperation == "PLANTEQUIPMENTOPERATION:CHILLERHEATERCHANGEOVER") {
     741           10 :                     CurrentModuleObject = "PlantEquipmentOperation:ChillerHeaterChangeover";
     742           10 :                     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         1281 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).TypeOf == "PLANTEQUIPMENTOPERATION:THERMALENERGYSTORAGE") {
     759            1 :                 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          462 :     if (ErrorsFound) {
     766            0 :         ShowFatalError(state, format("{}Errors found getting inputs. Previous error(s) cause program termination.", RoutineName));
     767              :     }
     768          462 : }
     769              : 
     770         1246 : 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         1246 :     Array1D_string AlphArray;      // Alpha input items for object
     803         1246 :     Array1D_string cAlphaFields;   // Alpha field names
     804         1246 :     Array1D_string cNumericFields; // Numeric field names
     805         1246 :     Array1D<Real64> NumArray;      // Numeric input items for object
     806         1246 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     807         1246 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     808         1246 :     int TotalArgs(0);              // Total number of alpha and numeric arguments (max) for a
     809              :     //   certain object in the input file
     810         1246 :     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         1246 :     SchemeNameFound = true;
     818              : 
     819              :     // Determine max number of alpha and numeric arguments for all objects being read, in order to allocate local arrays
     820         1246 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     821              : 
     822         1246 :     AlphArray.allocate(NumAlphas);
     823         1246 :     cAlphaFields.allocate(NumAlphas);
     824         1246 :     cNumericFields.allocate(NumNums);
     825         1246 :     NumArray.dimension(NumNums, 0.0);
     826         1246 :     lAlphaBlanks.dimension(NumAlphas, true);
     827         1246 :     lNumericBlanks.dimension(NumNums, true);
     828              : 
     829         1246 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
     830          991 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
     831          255 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
     832          255 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
     833              :     }
     834              : 
     835         1246 :     if (NumSchemes > 0) {
     836              :         int IOStat;
     837         1766 :         for (int Num = 1; Num <= NumSchemes; ++Num) {
     838         1766 :             state.dataInputProcessing->inputProcessor->getObjectItem(
     839              :                 state, CurrentModuleObject, Num, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
     840         1766 :             if (Util::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, AlphArray(1))) {
     841         1246 :                 break;
     842              :             }
     843          520 :             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         1246 :         if (SchemeNameFound) {
     855         1246 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = (NumAlphas - 1);
     856         1246 :             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         2492 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(
     862         1246 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists);
     863         1246 :                 int NumEquipLists = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists;
     864         1246 :                 if (NumNums <= 0) {          // Uncontrolled OpScheme type
     865           42 :                     ListNum = NumEquipLists; // NumEquipLists is always 1 for Uncontrolled OpScheme type
     866           42 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(2);
     867           42 :                     LoadEquipList(state, LoopNum, SchemeNum, ListNum, ErrorsFound);
     868              :                 } else { // Range based OpScheme type
     869         2563 :                     for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     870         1359 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit = NumArray(ListNum * 2 - 1);
     871         1359 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit = NumArray(ListNum * 2);
     872         1359 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(ListNum + 1);
     873         1359 :                         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         1359 :                             std::string const &plantLoopOperation =
     885              :                                 CurrentModuleObject; // different op schemes have different lower limit check values
     886              : 
     887         1359 :                             if (plantLoopOperation == "PlantEquipmentOperation:CoolingLoad" ||
     888         1367 :                                 plantLoopOperation == "PlantEquipmentOperation:HeatingLoad" ||
     889            8 :                                 plantLoopOperation == "PlantEquipmentOperation:OutdoorrelativeHumidity") {
     890              :                                 // these should not be less than zero
     891         1353 :                                 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            6 :                                 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         1359 :                         if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit >
     915         1359 :                             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         1359 :                         LoadEquipList(state, LoopNum, SchemeNum, ListNum, ErrorsFound);
     926              :                     }
     927              :                     // now run through lists again and check that range limits do not overlap each other
     928         2563 :                     for (ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
     929         1359 :                         OuterListNumLowerLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit;
     930         1359 :                         OuterListNumUpperLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit;
     931         3158 :                         for (int InnerListNum = 1; InnerListNum <= NumEquipLists; ++InnerListNum) {
     932         1799 :                             if (InnerListNum == ListNum) {
     933         1359 :                                 continue; // don't check against self.
     934              :                             }
     935          440 :                             InnerListNumLowerLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(InnerListNum).RangeLowerLimit;
     936          440 :                             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          440 :                             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          440 :                             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         1246 :     AlphArray.deallocate();
     989         1246 :     cAlphaFields.deallocate();
     990         1246 :     cNumericFields.deallocate();
     991         1246 :     NumArray.deallocate();
     992         1246 :     lAlphaBlanks.deallocate();
     993         1246 :     lNumericBlanks.deallocate();
     994         1246 : }
     995              : 
     996            3 : 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            3 :     Array1D_string AlphArray;      // Alpha input items for object
    1032            3 :     Array1D_string cAlphaFields;   // Alpha field names
    1033            3 :     Array1D_string cNumericFields; // Numeric field names
    1034            3 :     Array1D<Real64> NumArray;      // Numeric input items for object
    1035            3 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
    1036            3 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
    1037            3 :     int TotalArgs(0);              // Total number of alpha and numeric arguments (max) for a
    1038              :     //   certain object in the input file
    1039            3 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
    1040              : 
    1041            3 :     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            3 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cmoStr, TotalArgs, NumAlphas, NumNums);
    1045              : 
    1046            3 :     AlphArray.allocate(NumAlphas);
    1047            3 :     cAlphaFields.allocate(NumAlphas);
    1048            3 :     cNumericFields.allocate(NumNums);
    1049            3 :     NumArray.dimension(NumNums, 0.0);
    1050            3 :     lAlphaBlanks.dimension(NumAlphas, true);
    1051            3 :     lNumericBlanks.dimension(NumNums, true);
    1052              : 
    1053            3 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1054            0 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    1055            3 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    1056            3 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    1057              :     }
    1058              : 
    1059            3 :     if (NumSchemes > 0) {
    1060              :         int IOStat;
    1061            3 :         bool SchemeNameFound = true;
    1062              : 
    1063            3 :         for (int Num = 1; Num <= NumSchemes; ++Num) {
    1064            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state, cmoStr, Num, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    1065            3 :             if (Util::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, AlphArray(1))) {
    1066            3 :                 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            3 :         if (SchemeNameFound) {
    1080            3 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = (NumAlphas - 2);
    1081            3 :             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            6 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(
    1086            3 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists);
    1087            3 :                 int NumEquipLists = state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists;
    1088            3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ReferenceNodeName = AlphArray(2);
    1089            3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ReferenceNodeNumber =
    1090            6 :                     GetOnlySingleNode(state,
    1091            3 :                                       AlphArray(2),
    1092              :                                       ErrorsFound,
    1093              :                                       CurrentModuleObject,
    1094            3 :                                       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            9 :                 for (int ListNum = 1; ListNum <= NumEquipLists; ++ListNum) {
    1101            6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit = NumArray(ListNum * 2 - 1);
    1102            6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeUpperLimit = NumArray(ListNum * 2);
    1103            6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name = AlphArray(ListNum + 2);
    1104            6 :                     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).RangeLowerLimit >
    1105            6 :                         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            6 :                     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            3 :     AlphArray.deallocate();
    1129            3 :     cAlphaFields.deallocate();
    1130            3 :     cNumericFields.deallocate();
    1131            3 :     NumArray.deallocate();
    1132            3 :     lAlphaBlanks.deallocate();
    1133            3 :     lNumericBlanks.deallocate();
    1134            3 : }
    1135              : 
    1136         1407 : 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         1407 :     std::string CurrentModuleObject;
    1168              : 
    1169         1407 :     if (state.dataPlantCondLoopOp->LoadEquipListOneTimeFlag) {
    1170              :         // assemble mapping between list names and indices one time
    1171          462 :         int PELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PlantEquipmentList");
    1172          462 :         int CELists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CondenserEquipmentList");
    1173          462 :         state.dataPlantCondLoopOp->TotNumLists = PELists + CELists;
    1174          462 :         if (state.dataPlantCondLoopOp->TotNumLists > 0) {
    1175          462 :             state.dataPlantCondLoopOp->EquipListsNameList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1176          462 :             state.dataPlantCondLoopOp->EquipListsTypeList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1177          462 :             state.dataPlantCondLoopOp->EquipListsIndexList.allocate(state.dataPlantCondLoopOp->TotNumLists);
    1178              :             bool IsNotOK;
    1179              : 
    1180              :             // First load PlantEquipmentList info
    1181          462 :             if (PELists > 0) {
    1182          445 :                 CurrentModuleObject = "PlantEquipmentList";
    1183         1679 :                 for (Num = 1; Num <= PELists; ++Num) {
    1184         1234 :                     int iIndex = Num;
    1185         2468 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1186              :                                                                              CurrentModuleObject,
    1187              :                                                                              Num,
    1188         1234 :                                                                              state.dataIPShortCut->cAlphaArgs,
    1189              :                                                                              NumAlphas,
    1190         1234 :                                                                              state.dataIPShortCut->rNumericArgs,
    1191              :                                                                              NumNums,
    1192              :                                                                              IOStat,
    1193         1234 :                                                                              state.dataIPShortCut->lNumericFieldBlanks,
    1194         1234 :                                                                              state.dataIPShortCut->lAlphaFieldBlanks,
    1195         1234 :                                                                              state.dataIPShortCut->cAlphaFieldNames,
    1196         1234 :                                                                              state.dataIPShortCut->cNumericFieldNames);
    1197         1234 :                     state.dataPlantCondLoopOp->EquipListsNameList(iIndex) = state.dataIPShortCut->cAlphaArgs(1);
    1198         1234 :                     state.dataPlantCondLoopOp->EquipListsTypeList(iIndex) = LoopType::Plant;
    1199         1234 :                     state.dataPlantCondLoopOp->EquipListsIndexList(iIndex) = Num;
    1200         1234 :                     MachineNum = 2;
    1201         2710 :                     while (MachineNum <= NumAlphas) {
    1202         1476 :                         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         2952 :                             ValidateComponent(state,
    1224         1476 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum),
    1225         1476 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum + 1),
    1226              :                                               IsNotOK,
    1227              :                                               CurrentModuleObject);
    1228         1476 :                             if (IsNotOK) {
    1229            0 :                                 ShowContinueError(state, format("{}=\"{}\", Input Error.", CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1230            0 :                                 ErrorsFound = true;
    1231              :                             }
    1232              :                         }
    1233         1476 :                         MachineNum += 2;
    1234              :                     }
    1235              :                 }
    1236              :             }
    1237          462 :             if (CELists > 0) {
    1238          256 :                 CurrentModuleObject = "CondenserEquipmentList";
    1239          527 :                 for (Num = 1; Num <= CELists; ++Num) {
    1240          271 :                     int iIndex = Num + PELists;
    1241          542 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1242              :                                                                              CurrentModuleObject,
    1243              :                                                                              Num,
    1244          271 :                                                                              state.dataIPShortCut->cAlphaArgs,
    1245              :                                                                              NumAlphas,
    1246          271 :                                                                              state.dataIPShortCut->rNumericArgs,
    1247              :                                                                              NumNums,
    1248              :                                                                              IOStat,
    1249          271 :                                                                              state.dataIPShortCut->lNumericFieldBlanks,
    1250          271 :                                                                              state.dataIPShortCut->lAlphaFieldBlanks,
    1251          271 :                                                                              state.dataIPShortCut->cAlphaFieldNames,
    1252          271 :                                                                              state.dataIPShortCut->cNumericFieldNames);
    1253          271 :                     state.dataPlantCondLoopOp->EquipListsNameList(iIndex) = state.dataIPShortCut->cAlphaArgs(1);
    1254          271 :                     state.dataPlantCondLoopOp->EquipListsTypeList(iIndex) = LoopType::Condenser;
    1255          271 :                     state.dataPlantCondLoopOp->EquipListsIndexList(iIndex) = Num;
    1256          271 :                     MachineNum = 2;
    1257          567 :                     while (MachineNum <= NumAlphas) {
    1258          296 :                         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          592 :                             ValidateComponent(state,
    1280          296 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum),
    1281          296 :                                               state.dataIPShortCut->cAlphaArgs(MachineNum + 1),
    1282              :                                               IsNotOK,
    1283              :                                               CurrentModuleObject);
    1284          296 :                             if (IsNotOK) {
    1285            0 :                                 ShowContinueError(state, format("{}=\"{}\", Input Error.", CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1286            0 :                                 ErrorsFound = true;
    1287              :                             }
    1288              :                         }
    1289          296 :                         MachineNum += 2;
    1290              :                     }
    1291              :                 }
    1292              :             }
    1293              :         }
    1294          462 :         if (ErrorsFound) {
    1295            0 :             ShowFatalError(state, "LoadEquipList/GetEquipmentLists: Failed due to preceding errors.");
    1296              :         }
    1297          462 :         state.dataPlantCondLoopOp->LoadEquipListOneTimeFlag = false;
    1298              :     }
    1299              : 
    1300         1407 :     FoundIntendedList = false;
    1301              :     // find name in set of possible list
    1302         7441 :     for (Num = 1; Num <= state.dataPlantCondLoopOp->TotNumLists; ++Num) {
    1303         6034 :         if (Util::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Name,
    1304         6034 :                              state.dataPlantCondLoopOp->EquipListsNameList(Num))) {
    1305         1407 :             FoundIntendedList = true;
    1306              :             // get object item for real this time
    1307              :             {
    1308         1407 :                 if (state.dataPlantCondLoopOp->EquipListsTypeList(Num) == LoopType::Plant) {
    1309         1136 :                     CurrentModuleObject = "PlantEquipmentList";
    1310          271 :                 } else if (state.dataPlantCondLoopOp->EquipListsTypeList(Num) == LoopType::Condenser) {
    1311          271 :                     CurrentModuleObject = "CondenserEquipmentList";
    1312              :                 }
    1313              :             }
    1314         2814 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1315              :                                                                      CurrentModuleObject,
    1316         1407 :                                                                      state.dataPlantCondLoopOp->EquipListsIndexList(Num),
    1317         1407 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1318              :                                                                      NumAlphas,
    1319         1407 :                                                                      state.dataIPShortCut->rNumericArgs,
    1320              :                                                                      NumNums,
    1321              :                                                                      IOStat,
    1322         1407 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1323         1407 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1324         1407 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1325         1407 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1326         1407 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps = (NumAlphas - 1) / 2;
    1327         1407 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps > 0) {
    1328         2806 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp.allocate(
    1329         1403 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps);
    1330         3008 :                 for (MachineNum = 1; MachineNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).NumComps; ++MachineNum) {
    1331         1605 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp(MachineNum).TypeOf =
    1332         3210 :                         state.dataIPShortCut->cAlphaArgs(MachineNum * 2);
    1333         1605 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(ListNum).Comp(MachineNum).Name =
    1334         3210 :                         state.dataIPShortCut->cAlphaArgs(MachineNum * 2 + 1);
    1335              :                 } // MachineList
    1336              :             }
    1337              :         }
    1338              :     }
    1339              : 
    1340         1407 :     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         1407 : }
    1347              : 
    1348           16 : 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           16 :     Real64 CompFlowRate(0.0);
    1384           16 :     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           16 :     SchemeNameFound = true;
    1391              : 
    1392              :     DataLoopNode::ConnectionObjectType objType = static_cast<DataLoopNode::ConnectionObjectType>(
    1393           16 :         getEnumValue(BranchNodeConnections::ConnectionObjectTypeNamesUC, Util::makeUPPER(CurrentModuleObject)));
    1394              : 
    1395           16 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    1396           16 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    1397            0 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    1398            0 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    1399              :     }
    1400              : 
    1401           16 :     if (NumSchemes > 0) {
    1402              :         int NumAlphas;
    1403              :         int NumNums;
    1404              :         int IOStat;
    1405           16 :         for (int Num = 1; Num <= NumSchemes; ++Num) {
    1406           32 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    1407           16 :                 state, CurrentModuleObject, Num, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNums, IOStat);
    1408              : 
    1409           16 :             if (Util::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, state.dataIPShortCut->cAlphaArgs(1))) {
    1410           16 :                 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           16 :         if (SchemeNameFound) {
    1424              :             // why only one equip list assumed here? because component setpoint managers have their own lists contained.
    1425           16 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = 1;
    1426           16 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(1);
    1427           16 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps = (NumAlphas - 1) / 5;
    1428              : 
    1429           16 :             Sched::Schedule *chargeSched = nullptr;
    1430           16 :             Sched::Schedule *onPeakSched = nullptr;
    1431              : 
    1432           16 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    1433              : 
    1434           16 :             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           16 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps > 0) {
    1452           32 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp.allocate(
    1453           16 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps);
    1454              :                 int CompNumA;
    1455              :                 int CompNumN;
    1456           49 :                 for (int CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps; ++CompNum) {
    1457           33 :                     if (CurrentModuleObject == "PlantEquipmentOperation:ComponentSetPoint") {
    1458           31 :                         CompNumA = CompNum * 5;
    1459           31 :                         CompNumN = CompNum;
    1460            2 :                     } else if (CurrentModuleObject == "PlantEquipmentOperation:ThermalEnergyStorage") {
    1461            2 :                         CompNumA = CompNum * 5 + 2;
    1462            2 :                         CompNumN = CompNum + 2;
    1463              :                     }
    1464           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).TypeOf =
    1465           66 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 3);
    1466           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name =
    1467           66 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 2);
    1468           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeName =
    1469           66 :                         state.dataIPShortCut->cAlphaArgs(CompNumA - 1);
    1470           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeNum =
    1471           66 :                         GetOnlySingleNode(state,
    1472           33 :                                           state.dataIPShortCut->cAlphaArgs(CompNumA - 1),
    1473              :                                           ErrorsFound,
    1474              :                                           objType,
    1475           33 :                                           state.dataIPShortCut->cAlphaArgs(1),
    1476              :                                           DataLoopNode::NodeFluidType::Water,
    1477              :                                           DataLoopNode::ConnectionType::Sensor,
    1478              :                                           NodeInputManager::CompFluidStream::Primary,
    1479              :                                           ObjectIsNotParent);
    1480           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeName =
    1481           66 :                         state.dataIPShortCut->cAlphaArgs(CompNumA);
    1482           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum =
    1483           66 :                         GetOnlySingleNode(state,
    1484           33 :                                           state.dataIPShortCut->cAlphaArgs(CompNumA),
    1485              :                                           ErrorsFound,
    1486              :                                           objType,
    1487           33 :                                           state.dataIPShortCut->cAlphaArgs(1),
    1488              :                                           DataLoopNode::NodeFluidType::Water,
    1489              :                                           DataLoopNode::ConnectionType::Sensor,
    1490              :                                           NodeInputManager::CompFluidStream::Primary,
    1491              :                                           ObjectIsNotParent);
    1492           33 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointFlowRate =
    1493           33 :                         state.dataIPShortCut->rNumericArgs(CompNumN);
    1494              : 
    1495           33 :                     if (state.dataIPShortCut->rNumericArgs(CompNumN) == AutoSize) {
    1496           16 :                         int Num = 1;
    1497          916 :                         for (; Num <= state.dataSize->SaveNumPlantComps; ++Num) {
    1498          900 :                             int CompInNode = state.dataSize->CompDesWaterFlow(Num).SupNode;
    1499          900 :                             CompFlowRate = state.dataSize->CompDesWaterFlow(Num).DesVolFlowRate;
    1500          900 :                             if (CompInNode == state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).DemandNodeNum) {
    1501           16 :                                 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           64 :                         BaseSizer::reportSizerOutput(state,
    1507              :                                                      CurrentModuleObject,
    1508           16 :                                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name,
    1509           32 :                                                      format("Design Water Flow Rate [m3/s] Equipment # {}", Num),
    1510              :                                                      CompFlowRate);
    1511              :                     }
    1512              : 
    1513              :                     {
    1514           33 :                         std::string const &controlType = state.dataIPShortCut->cAlphaArgs(CompNumA + 1);
    1515           33 :                         if (controlType == "COOLING") {
    1516           18 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::CoolingOp;
    1517           15 :                         } else if (controlType == "HEATING") {
    1518            6 :                             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            6 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::HeatingOp;
    1527            9 :                         } else if (controlType == "DUAL") {
    1528            9 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType = CtrlType::DualOp;
    1529              :                         }
    1530              :                     }
    1531              : 
    1532           33 :                     if ((state.dataIPShortCut->cAlphaArgs(CompNumA + 1) != "COOLING") &&
    1533           33 :                         (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           33 :                     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            0 :                             ShowWarningError(state,
    1548            0 :                                              format("Equipment Operation Mode was reset to 'DUAL' for Component '{}' in {}='{}'.",
    1549            0 :                                                     state.dataIPShortCut->cAlphaArgs(CompNumA - 2),
    1550              :                                                     CurrentModuleObject,
    1551            0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    1552            0 :                             ShowContinueError(state,
    1553            0 :                                               format("Equipment Operation Mode can only be 'DUAL' for {} objects.",
    1554            0 :                                                      state.dataIPShortCut->cAlphaArgs(CompNumA - 3)));
    1555              : 
    1556            0 :                             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           33 :                     switch (state.dataPlnt->PlantLoop(LoopNum).LoopDemandCalcScheme) {
    1589           25 :                     case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1590           25 :                         if (state.dataLoopNodes
    1591           25 :                                 ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1592           25 :                                 .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           25 :                         break;
    1641              :                     }
    1642            8 :                     case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1643            8 :                         if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType == CtrlType::CoolingOp) {
    1644            4 :                             if (state.dataLoopNodes
    1645            4 :                                     ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1646            4 :                                     .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            4 :                         } else if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).CtrlType ==
    1697              :                                    CtrlType::HeatingOp) {
    1698            4 :                             if (state.dataLoopNodes
    1699            4 :                                     ->Node(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).SetPointNodeNum)
    1700            4 :                                     .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            8 :                         break;
    1813              :                     }
    1814            0 :                     default:
    1815            0 :                         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           16 : }
    1834              : 
    1835           10 : 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           10 :     if (NumSchemes > 0 && state.dataPlantCondLoopOp->LoadSupervisoryChillerHeaterOpScheme) {
    1843              : 
    1844            3 :         state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes.allocate(NumSchemes);
    1845            3 :         std::string heatingOnlyLoadOpName;
    1846            3 :         std::string coolingOnlyLoadOpName;
    1847            3 :         std::string simultHeatCoolHeatingOpName;
    1848            3 :         std::string simulHeatCoolCoolingOpName;
    1849            6 :         for (int Num = 1; Num <= NumSchemes; ++Num) {
    1850            3 :             auto &scheme = state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes(Num);
    1851            3 :             std::string cCurrentModuleObject("PlantEquipmentOperation:ChillerHeaterChangeover");
    1852            9 :             static const std::string routineName("GetChillerHeaterChangeoverOpSchemeInput: ");
    1853            3 :             auto const schemeInstances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
    1854            3 :             auto &ip = state.dataInputProcessing->inputProcessor;
    1855            3 :             if (schemeInstances != ip->epJSON.end()) {
    1856            3 :                 auto &instancesValue = schemeInstances.value();
    1857            6 :                 for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
    1858            3 :                     auto const &fields = instance.value();
    1859            3 :                     auto const &thisObjectName = Util::makeUPPER(instance.key());
    1860            3 :                     state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
    1861            3 :                     scheme.Name = thisObjectName;
    1862            3 :                     scheme.TypeOf = "PlantEquipmentOperation:ChillerHeaterChangeover";
    1863            3 :                     scheme.Type = OpScheme::ChillerHeaterSupervisory;
    1864            6 :                     scheme.Setpoint.PrimCW = fields.at("primary_cooling_plant_setpoint_temperature").get<Real64>();
    1865            3 :                     auto const secCWSP = fields.find("secondary_distribution_cooling_plant_setpoint_temperature");
    1866            3 :                     if (secCWSP != fields.end()) { // not required field
    1867            3 :                         scheme.Setpoint.SecCW = secCWSP.value().get<Real64>();
    1868              :                     }
    1869            6 :                     scheme.Setpoint.PrimHW_High = fields.at("primary_heating_plant_setpoint_at_outdoor_high_temperature").get<Real64>();
    1870            6 :                     scheme.TempReset.HighOutdoorTemp = fields.at("outdoor_high_temperature").get<Real64>();
    1871            6 :                     scheme.Setpoint.PrimHW_Low = fields.at("primary_heating_plant_setpoint_at_outdoor_low_temperature").get<Real64>();
    1872            6 :                     scheme.TempReset.LowOutdoorTemp = fields.at("outdoor_low_temperature").get<Real64>();
    1873            3 :                     auto const secHWSP = fields.find("secondary_distribution_heating_plant_setpoint_temperature");
    1874            3 :                     if (secHWSP != fields.end()) { // not required field
    1875            3 :                         scheme.Setpoint.SecHW = secHWSP.value().get<Real64>();
    1876              :                     }
    1877            3 :                     auto const boilerOffset = fields.find("boiler_setpoint_temperature_offset");
    1878            6 :                     (boilerOffset != fields.end()) ? (scheme.TempReset.BoilerTemperatureOffset = boilerOffset.value().get<Real64>())
    1879            3 :                                                    : (scheme.TempReset.BoilerTemperatureOffset = 0.5);
    1880            3 :                     auto const backUpLow_HWset = fields.find("primary_heating_plant_setpoint_at_backup_outdoor_low_temperature");
    1881            6 :                     (backUpLow_HWset != fields.end()) ? (scheme.Setpoint.PrimHW_BackupLow = backUpLow_HWset.value().get<Real64>())
    1882            3 :                                                       : (scheme.Setpoint.PrimHW_BackupLow = scheme.Setpoint.PrimHW_Low);
    1883            3 :                     auto const backUpLowTemp = fields.find("backup_outdoor_low_temperature");
    1884            6 :                     (backUpLowTemp != fields.end()) ? (scheme.TempReset.BackupLowOutdoorTemp = backUpLowTemp.value().get<Real64>())
    1885            3 :                                                     : (scheme.TempReset.BackupLowOutdoorTemp = scheme.TempReset.LowOutdoorTemp);
    1886            3 :                     auto const zoneNameList = fields.find("zone_load_polling_zonelist_name");
    1887            3 :                     if (zoneNameList != fields.end()) {
    1888            3 :                         scheme.ZoneListName = Util::makeUPPER(zoneNameList.value().get<std::string>());
    1889              :                     }
    1890            3 :                     auto const coolPlantEqOpCoolingLoad = fields.find("cooling_only_load_plant_equipment_operation_cooling_load_name");
    1891            3 :                     if (coolPlantEqOpCoolingLoad != fields.end()) {
    1892            3 :                         coolingOnlyLoadOpName = Util::makeUPPER(coolPlantEqOpCoolingLoad.value().get<std::string>());
    1893              :                     }
    1894            3 :                     auto const heatPlantEqOpHeatingLoad = fields.find("heating_only_load_plant_equipment_operation_heating_load_name");
    1895            3 :                     if (heatPlantEqOpHeatingLoad != fields.end()) {
    1896            3 :                         heatingOnlyLoadOpName = Util::makeUPPER(heatPlantEqOpHeatingLoad.value().get<std::string>());
    1897              :                     }
    1898            3 :                     auto const simulEqOpCoolingLoad = fields.find("simultaneous_cooling_and_heating_plant_equipment_operation_cooling_load_name");
    1899            3 :                     if (simulEqOpCoolingLoad != fields.end()) {
    1900            2 :                         simulHeatCoolCoolingOpName = Util::makeUPPER(simulEqOpCoolingLoad.value().get<std::string>());
    1901            2 :                         scheme.PlantOps.SimulHeatCoolCoolingOpInput = true;
    1902              :                     }
    1903            3 :                     auto const simulEqOpHeatingLoad = fields.find("simultaneous_cooling_and_heating_plant_equipment_operation_heating_load_name");
    1904            3 :                     if (simulEqOpHeatingLoad != fields.end()) {
    1905            2 :                         simultHeatCoolHeatingOpName = Util::makeUPPER(simulEqOpHeatingLoad.value().get<std::string>());
    1906            2 :                         scheme.PlantOps.SimultHeatCoolHeatingOpInput = true;
    1907              :                     }
    1908            3 :                     auto const dedicatedCWHPName = fields.find("dedicated_chilled_water_return_recovery_heat_pump_name");
    1909            3 :                     if (dedicatedCWHPName != fields.end()) {
    1910            1 :                         scheme.DedicatedHR_ChWRetControl_Name = Util::makeUPPER(dedicatedCWHPName.value().get<std::string>());
    1911            1 :                         scheme.PlantOps.DedicatedHR_ChWRetControl_Input = true;
    1912              :                     }
    1913            3 :                     auto const dedicatedHWHPName = fields.find("dedicated_hot_water_return_recovery_heat_pump_name");
    1914            3 :                     if (dedicatedHWHPName != fields.end()) {
    1915            1 :                         scheme.DedicatedHR_HWRetControl_Name = Util::makeUPPER(dedicatedHWHPName.value().get<std::string>());
    1916            1 :                         scheme.PlantOps.DedicatedHR_HWRetControl_Input = true;
    1917              :                     }
    1918            6 :                 }
    1919              :             }
    1920              : 
    1921              :             //  Load input instances from input processor
    1922            3 :             cCurrentModuleObject = "PlantEquipmentOperation:CoolingLoad";
    1923            3 :             auto const coolLoadInstances = ip->epJSON.find(cCurrentModuleObject);
    1924            3 :             auto &coolLoadInstancesValue = coolLoadInstances.value();
    1925              : 
    1926            3 :             cCurrentModuleObject = "PlantEquipmentOperation:HeatingLoad";
    1927            3 :             auto const heatLoadInstances = ip->epJSON.find(cCurrentModuleObject);
    1928            3 :             auto &heatLoadInstancesValue = heatLoadInstances.value();
    1929              : 
    1930            3 :             cCurrentModuleObject = "PlantEquipmentList";
    1931            3 :             auto const equipListInstances = ip->epJSON.find(cCurrentModuleObject);
    1932            3 :             auto const &equipListObjectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
    1933            3 :             auto &equipListInstancesValue = equipListInstances.value();
    1934              : 
    1935              :             // process cooling only mode equipment lists and ranges
    1936            8 :             for (auto instance = coolLoadInstancesValue.begin(); instance != coolLoadInstancesValue.end(); ++instance) {
    1937            5 :                 auto const &fields = instance.value();
    1938            5 :                 auto const &thisObjectName = Util::makeUPPER(instance.key());
    1939            5 :                 if (!Util::SameString(coolingOnlyLoadOpName, thisObjectName)) {
    1940            2 :                     continue;
    1941              :                 }
    1942              : 
    1943            3 :                 int numfields = fields.size();
    1944            3 :                 scheme.PlantOps.NumCoolingOnlyEquipLists = (numfields - 1) / 3; //  assume correctly formed field sets?
    1945            3 :                 scheme.CoolingOnlyEquipList.allocate(scheme.PlantOps.NumCoolingOnlyEquipLists);
    1946            9 :                 for (int listNum = 1; listNum <= scheme.PlantOps.NumCoolingOnlyEquipLists; ++listNum) {
    1947            6 :                     switch (listNum) {
    1948            3 :                     case 1: {
    1949            6 :                         scheme.CoolingOnlyEquipList(listNum).Name = Util::makeUPPER(fields.at("range_1_equipment_list_name").get<std::string>());
    1950            6 :                         scheme.CoolingOnlyEquipList(listNum).RangeLowerLimit = fields.at("load_range_1_lower_limit").get<Real64>();
    1951            3 :                         scheme.CoolingOnlyEquipList(listNum).RangeUpperLimit = fields.at("load_range_1_upper_limit").get<Real64>();
    1952            3 :                     } break;
    1953              : 
    1954            3 :                     case 2: {
    1955            6 :                         scheme.CoolingOnlyEquipList(listNum).Name = Util::makeUPPER(fields.at("range_2_equipment_list_name").get<std::string>());
    1956            6 :                         scheme.CoolingOnlyEquipList(listNum).RangeLowerLimit = fields.at("load_range_2_lower_limit").get<Real64>();
    1957            3 :                         scheme.CoolingOnlyEquipList(listNum).RangeUpperLimit = fields.at("load_range_2_upper_limit").get<Real64>();
    1958              : 
    1959            3 :                     } 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            8 :             }
    2003              : 
    2004            3 :             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            9 :             for (int listNum = 1; listNum <= scheme.PlantOps.NumCoolingOnlyEquipLists; ++listNum) {
    2014              : 
    2015           44 :                 for (auto instance = equipListInstancesValue.begin(); instance != equipListInstancesValue.end(); ++instance) {
    2016           38 :                     auto const &objectFields = instance.value();
    2017           38 :                     auto const &thisObjectName = Util::makeUPPER(instance.key());
    2018           38 :                     if (!Util::SameString(scheme.CoolingOnlyEquipList(listNum).Name, thisObjectName)) {
    2019           32 :                         continue;
    2020              :                     }
    2021              : 
    2022            6 :                     auto extensibles = objectFields.find("equipment");
    2023            6 :                     auto const &extensionSchemaProps = equipListObjectSchemaProps["equipment"]["items"]["properties"];
    2024            6 :                     if (extensibles != objectFields.end()) {
    2025            6 :                         auto extensiblesArray = extensibles.value();
    2026            6 :                         int numExtensibles = extensiblesArray.size();
    2027            6 :                         scheme.CoolingOnlyEquipList(listNum).NumComps = numExtensibles;
    2028            6 :                         scheme.CoolingOnlyEquipList(listNum).Comp.allocate(numExtensibles);
    2029            6 :                         int listItem = 0;
    2030           15 :                         for (nlohmann::json const &extensibleInstance : extensiblesArray) {
    2031            9 :                             ++listItem;
    2032            9 :                             scheme.CoolingOnlyEquipList(listNum).Comp(listItem).TypeOf =
    2033           27 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_object_type");
    2034            9 :                             scheme.CoolingOnlyEquipList(listNum).Comp(listItem).Name =
    2035           36 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_name");
    2036            6 :                         }
    2037            6 :                     }
    2038           44 :                 }
    2039              :             }
    2040              : 
    2041              :             // process heating only mode equipment lists and ranges
    2042           14 :             for (auto instance = heatLoadInstancesValue.begin(); instance != heatLoadInstancesValue.end(); ++instance) {
    2043           11 :                 auto const &fields = instance.value();
    2044           11 :                 auto const &thisObjectName = Util::makeUPPER(instance.key());
    2045           11 :                 if (!Util::SameString(heatingOnlyLoadOpName, thisObjectName)) {
    2046            8 :                     continue;
    2047              :                 }
    2048              : 
    2049            3 :                 int numfields = fields.size();
    2050            3 :                 scheme.PlantOps.NumHeatingOnlyEquipLists = (numfields - 1) / 3; //  assume correctly formed field sets?
    2051            3 :                 scheme.HeatingOnlyEquipList.allocate(scheme.PlantOps.NumHeatingOnlyEquipLists);
    2052            9 :                 for (int listNum = 1; listNum <= scheme.PlantOps.NumHeatingOnlyEquipLists; ++listNum) {
    2053            6 :                     switch (listNum) {
    2054            3 :                     case 1: {
    2055            6 :                         scheme.HeatingOnlyEquipList(listNum).Name = Util::makeUPPER(fields.at("range_1_equipment_list_name").get<std::string>());
    2056            6 :                         scheme.HeatingOnlyEquipList(listNum).RangeLowerLimit = fields.at("load_range_1_lower_limit").get<Real64>();
    2057            3 :                         scheme.HeatingOnlyEquipList(listNum).RangeUpperLimit = fields.at("load_range_1_upper_limit").get<Real64>();
    2058            3 :                     } break;
    2059              : 
    2060            3 :                     case 2: {
    2061            6 :                         scheme.HeatingOnlyEquipList(listNum).Name = Util::makeUPPER(fields.at("range_2_equipment_list_name").get<std::string>());
    2062            6 :                         scheme.HeatingOnlyEquipList(listNum).RangeLowerLimit = fields.at("load_range_2_lower_limit").get<Real64>();
    2063            3 :                         scheme.HeatingOnlyEquipList(listNum).RangeUpperLimit = fields.at("load_range_2_upper_limit").get<Real64>();
    2064              : 
    2065            3 :                     } 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           14 :             }
    2109              : 
    2110            3 :             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            9 :             for (int listNum = 1; listNum <= scheme.PlantOps.NumHeatingOnlyEquipLists; ++listNum) {
    2120              : 
    2121           44 :                 for (auto instance = equipListInstancesValue.begin(); instance != equipListInstancesValue.end(); ++instance) {
    2122           38 :                     auto const &objectFields = instance.value();
    2123           38 :                     auto const &thisObjectName = Util::makeUPPER(instance.key());
    2124           38 :                     if (!Util::SameString(scheme.HeatingOnlyEquipList(listNum).Name, thisObjectName)) {
    2125           32 :                         continue;
    2126              :                     }
    2127              : 
    2128            6 :                     auto extensibles = objectFields.find("equipment");
    2129            6 :                     auto const &extensionSchemaProps = equipListObjectSchemaProps["equipment"]["items"]["properties"];
    2130            6 :                     if (extensibles != objectFields.end()) {
    2131            6 :                         auto extensiblesArray = extensibles.value();
    2132            6 :                         int numExtensibles = extensiblesArray.size();
    2133            6 :                         scheme.HeatingOnlyEquipList(listNum).NumComps = numExtensibles;
    2134            6 :                         scheme.HeatingOnlyEquipList(listNum).Comp.allocate(numExtensibles);
    2135            6 :                         int listItem = 0;
    2136           15 :                         for (nlohmann::json const &extensibleInstance : extensiblesArray) {
    2137            9 :                             ++listItem;
    2138            9 :                             scheme.HeatingOnlyEquipList(listNum).Comp(listItem).TypeOf =
    2139           27 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_object_type");
    2140            9 :                             scheme.HeatingOnlyEquipList(listNum).Comp(listItem).Name =
    2141           36 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_name");
    2142            6 :                         }
    2143            6 :                     }
    2144           44 :                 }
    2145              :             }
    2146              : 
    2147              :             // process simulataneous heating and cooling mode cooling equipment lists and ranges
    2148              : 
    2149            8 :             for (auto instance = coolLoadInstancesValue.begin(); instance != coolLoadInstancesValue.end(); ++instance) {
    2150            5 :                 auto const &fields = instance.value();
    2151            5 :                 auto const &thisObjectName = Util::makeUPPER(instance.key());
    2152            5 :                 if (!Util::SameString(simulHeatCoolCoolingOpName, thisObjectName)) {
    2153            3 :                     continue;
    2154              :                 }
    2155              : 
    2156            2 :                 int numfields = fields.size();
    2157            2 :                 scheme.PlantOps.NumSimultHeatCoolCoolingEquipLists = (numfields - 1) / 3; //  assume correctly formed field sets?
    2158            2 :                 scheme.SimultHeatCoolCoolingEquipList.allocate(scheme.PlantOps.NumSimultHeatCoolCoolingEquipLists);
    2159            4 :                 for (int listNum = 1; listNum <= scheme.PlantOps.NumSimultHeatCoolCoolingEquipLists; ++listNum) {
    2160            2 :                     switch (listNum) {
    2161            2 :                     case 1: {
    2162            2 :                         scheme.SimultHeatCoolCoolingEquipList(listNum).Name =
    2163            6 :                             Util::makeUPPER(fields.at("range_1_equipment_list_name").get<std::string>());
    2164            4 :                         scheme.SimultHeatCoolCoolingEquipList(listNum).RangeLowerLimit = fields.at("load_range_1_lower_limit").get<Real64>();
    2165            2 :                         scheme.SimultHeatCoolCoolingEquipList(listNum).RangeUpperLimit = fields.at("load_range_1_upper_limit").get<Real64>();
    2166            2 :                     } 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            8 :             }
    2224              : 
    2225            3 :             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            5 :             for (int listNum = 1; listNum <= scheme.PlantOps.NumSimultHeatCoolCoolingEquipLists; ++listNum) {
    2235              : 
    2236           14 :                 for (auto instance = equipListInstancesValue.begin(); instance != equipListInstancesValue.end(); ++instance) {
    2237           12 :                     auto const &objectFields = instance.value();
    2238           12 :                     auto const &thisObjectName = Util::makeUPPER(instance.key());
    2239           12 :                     if (!Util::SameString(scheme.SimultHeatCoolCoolingEquipList(listNum).Name, thisObjectName)) {
    2240           10 :                         continue;
    2241              :                     }
    2242              : 
    2243            2 :                     auto extensibles = objectFields.find("equipment");
    2244            2 :                     auto const &extensionSchemaProps = equipListObjectSchemaProps["equipment"]["items"]["properties"];
    2245            2 :                     if (extensibles != objectFields.end()) {
    2246            2 :                         auto extensiblesArray = extensibles.value();
    2247            2 :                         int numExtensibles = extensiblesArray.size();
    2248            2 :                         scheme.SimultHeatCoolCoolingEquipList(listNum).NumComps = numExtensibles;
    2249            2 :                         scheme.SimultHeatCoolCoolingEquipList(listNum).Comp.allocate(numExtensibles);
    2250            2 :                         int listItem = 0;
    2251            4 :                         for (nlohmann::json const &extensibleInstance : extensiblesArray) {
    2252            2 :                             ++listItem;
    2253            2 :                             scheme.SimultHeatCoolCoolingEquipList(listNum).Comp(listItem).TypeOf =
    2254            6 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_object_type");
    2255            2 :                             scheme.SimultHeatCoolCoolingEquipList(listNum).Comp(listItem).Name =
    2256            8 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_name");
    2257            2 :                         }
    2258            2 :                     }
    2259           14 :                 }
    2260              :             }
    2261              : 
    2262              :             // process simultaneous heating and cooling mode heating equipment lists and ranges
    2263              : 
    2264           14 :             for (auto instance = heatLoadInstancesValue.begin(); instance != heatLoadInstancesValue.end(); ++instance) {
    2265           11 :                 auto const &fields = instance.value();
    2266           11 :                 auto const &thisObjectName = Util::makeUPPER(instance.key());
    2267           11 :                 if (!Util::SameString(simultHeatCoolHeatingOpName, thisObjectName)) {
    2268            9 :                     continue;
    2269              :                 }
    2270              : 
    2271            2 :                 int numfields = fields.size();
    2272            2 :                 scheme.PlantOps.NumSimultHeatCoolHeatingEquipLists = (numfields - 1) / 3; //  assume correctly formed field sets?
    2273            2 :                 scheme.SimultHeatCoolHeatingEquipList.allocate(scheme.PlantOps.NumSimultHeatCoolHeatingEquipLists);
    2274            4 :                 for (int listNum = 1; listNum <= scheme.PlantOps.NumSimultHeatCoolHeatingEquipLists; ++listNum) {
    2275            2 :                     switch (listNum) {
    2276            2 :                     case 1: {
    2277            2 :                         scheme.SimultHeatCoolHeatingEquipList(listNum).Name =
    2278            6 :                             Util::makeUPPER(fields.at("range_1_equipment_list_name").get<std::string>());
    2279            4 :                         scheme.SimultHeatCoolHeatingEquipList(listNum).RangeLowerLimit = fields.at("load_range_1_lower_limit").get<Real64>();
    2280            2 :                         scheme.SimultHeatCoolHeatingEquipList(listNum).RangeUpperLimit = fields.at("load_range_1_upper_limit").get<Real64>();
    2281            2 :                     } 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           14 :             }
    2339            3 :             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            3 :             cCurrentModuleObject = "PlantEquipmentList";
    2349              : 
    2350            5 :             for (int listNum = 1; listNum <= scheme.PlantOps.NumSimultHeatCoolHeatingEquipLists; ++listNum) {
    2351              : 
    2352            2 :                 auto const instances = ip->epJSON.find(cCurrentModuleObject);
    2353            2 :                 auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
    2354              : 
    2355            2 :                 auto &instancesValue = instances.value();
    2356           14 :                 for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
    2357           12 :                     auto const &objectFields = instance.value();
    2358           12 :                     auto const &thisObjectName = Util::makeUPPER(instance.key());
    2359           12 :                     if (!Util::SameString(scheme.SimultHeatCoolHeatingEquipList(listNum).Name, thisObjectName)) {
    2360           10 :                         continue;
    2361              :                     }
    2362              : 
    2363            2 :                     auto extensibles = objectFields.find("equipment");
    2364            2 :                     auto const &extensionSchemaProps = objectSchemaProps["equipment"]["items"]["properties"];
    2365            2 :                     if (extensibles != objectFields.end()) {
    2366            2 :                         auto extensiblesArray = extensibles.value();
    2367            2 :                         int numExtensibles = extensiblesArray.size();
    2368            2 :                         scheme.SimultHeatCoolHeatingEquipList(listNum).NumComps = numExtensibles;
    2369            2 :                         scheme.SimultHeatCoolHeatingEquipList(listNum).Comp.allocate(numExtensibles);
    2370            2 :                         int listItem = 0;
    2371            4 :                         for (nlohmann::json const &extensibleInstance : extensiblesArray) {
    2372            2 :                             ++listItem;
    2373            2 :                             scheme.SimultHeatCoolHeatingEquipList(listNum).Comp(listItem).TypeOf =
    2374            6 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_object_type");
    2375            2 :                             scheme.SimultHeatCoolHeatingEquipList(listNum).Comp(listItem).Name =
    2376            8 :                                 ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "equipment_name");
    2377            2 :                         }
    2378            2 :                     }
    2379           14 :                 }
    2380            2 :             }
    2381            3 :         }
    2382            3 :     }
    2383           10 :     state.dataPlantCondLoopOp->LoadSupervisoryChillerHeaterOpScheme = false;
    2384           10 : }
    2385              : 
    2386            6 : 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            6 :     std::string LoopOpSchemeObj; // Used to identify the object name for loop equipment operation scheme
    2410              : 
    2411            6 :     SchemeNameFound = true;
    2412              : 
    2413            6 :     if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Plant) {
    2414            4 :         LoopOpSchemeObj = "PlantEquipmentOperationSchemes";
    2415            2 :     } else if (state.dataPlnt->PlantLoop(LoopNum).TypeOfLoop == LoopType::Condenser) {
    2416            2 :         LoopOpSchemeObj = "CondenserEquipmentOperationSchemes";
    2417              :     }
    2418              : 
    2419            6 :     if (NumSchemes > 0) {
    2420              :         int NumAlphas, NumNums, Num, IOStat;
    2421              : 
    2422           12 :         for (Num = 1; Num <= NumSchemes; ++Num) {
    2423           24 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2424              :                                                                      CurrentModuleObject,
    2425              :                                                                      Num,
    2426           12 :                                                                      state.dataIPShortCut->cAlphaArgs,
    2427              :                                                                      NumAlphas,
    2428           12 :                                                                      state.dataIPShortCut->rNumericArgs,
    2429              :                                                                      NumNums,
    2430              :                                                                      IOStat,
    2431           12 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    2432           12 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    2433           12 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    2434           12 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    2435           12 :             if (Util::SameString(state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name, state.dataIPShortCut->cAlphaArgs(1))) {
    2436            6 :                 break; // found the correct one
    2437              :             }
    2438            6 :             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            6 :         if (SchemeNameFound) {
    2450            6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).NumEquipLists = 1;
    2451            6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList.allocate(1);
    2452              : 
    2453            6 :             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps = (NumAlphas - 3) / 2;
    2454            6 :             if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps > 0) {
    2455           12 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp.allocate(
    2456            6 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps);
    2457           14 :                 for (int CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).NumComps; ++CompNum) {
    2458            8 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).TypeOf =
    2459           16 :                         state.dataIPShortCut->cAlphaArgs(CompNum * 2 + 2);
    2460            8 :                     state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name =
    2461           16 :                         state.dataIPShortCut->cAlphaArgs(CompNum * 2 + 3);
    2462              : 
    2463              :                     // Setup EMS actuators for machines' MyLoad.
    2464           16 :                     SetupEMSActuator(
    2465              :                         state,
    2466              :                         "Plant Equipment Operation",
    2467           16 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + ':' +
    2468            8 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name,
    2469              :                         "Distributed Load Rate",
    2470              :                         "[W]",
    2471            8 :                         state.dataPlantCondLoopOp->lDummy,
    2472            8 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).EMSActuatorDispatchedLoadValue);
    2473              :                     // TODO: I think this should be a sensor really
    2474            8 :                     SetupEMSInternalVariable(
    2475              :                         state,
    2476              :                         "Component Remaining Current Demand Rate",
    2477           16 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name + ':' +
    2478            8 :                             state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).Name,
    2479              :                         "[W]",
    2480            8 :                         state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).EquipList(1).Comp(CompNum).EMSIntVarRemainingLoadValue);
    2481              :                 }
    2482              :             }
    2483            6 :             int StackMngrNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataRuntimeLang->EMSProgramCallManager);
    2484            6 :             if (StackMngrNum > 0) { // found it
    2485            3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).ErlSimProgramMngr = StackMngrNum;
    2486              :             } else {
    2487            3 :                 state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).simPluginLocation =
    2488            3 :                     state.dataPluginManager->pluginManager->getLocationOfUserDefinedPlugin(state, state.dataIPShortCut->cAlphaArgs(2));
    2489            3 :                 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            6 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    2497            1 :                 StackMngrNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataRuntimeLang->EMSProgramCallManager);
    2498            1 :                 if (StackMngrNum > 0) { // found it
    2499            1 :                     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            6 :             SetupEMSInternalVariable(state,
    2515              :                                      "Supply Side Current Demand Rate",
    2516            6 :                                      state.dataPlnt->PlantLoop(LoopNum).OpScheme(SchemeNum).Name,
    2517              :                                      "[W]",
    2518            6 :                                      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            6 : }
    2531              : 
    2532              : // End of GetInput subroutines for the Module
    2533              : //******************************************************************************
    2534              : 
    2535              : // Beginning Initialization Section of the Plant Loop Module
    2536              : //******************************************************************************
    2537              : 
    2538     31707366 : 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     31707366 :     PlantLocation plantLoc{};
    2558              : 
    2559              :     DataPlant::PlantEquipmentType Type;
    2560              : 
    2561              :     bool errFlag2;
    2562              :     Real64 HighestRange;
    2563              : 
    2564              :     // Object Data
    2565              : 
    2566     31707366 :     errFlag2 = false;
    2567              :     // Get Input
    2568     31707366 :     if (state.dataPlantCondLoopOp->GetPlantOpInput) {
    2569              :         bool GetInputOK; // successful Get Input
    2570          462 :         GetPlantOperationInput(state, GetInputOK);
    2571          462 :         if (GetInputOK) {
    2572          462 :             GetOperationSchemeInput(state);
    2573          462 :             state.dataPlantCondLoopOp->GetPlantOpInput = false;
    2574              :         } else {
    2575            0 :             return;
    2576              :         }
    2577              :     }
    2578              : 
    2579              :     // ONE TIME INITS
    2580     31707366 :     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         1619 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2588         1157 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2589         2438 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2590         1281 :                 auto &this_op_scheme = this_plant_loop.OpScheme(OpNum);
    2591         2710 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2592         1429 :                     auto &this_equip_list = this_op_scheme.EquipList(ListNum);
    2593         3075 :                     for (int EquipNum = 1, EquipNum_end = this_equip_list.NumComps; EquipNum <= EquipNum_end; ++EquipNum) {
    2594         1646 :                         auto &this_equip = this_equip_list.Comp(EquipNum);
    2595         1646 :                         Type = static_cast<DataPlant::PlantEquipmentType>(getEnumValue(PlantEquipTypeNamesUC, Util::makeUPPER(this_equip.TypeOf)));
    2596         1646 :                         bool errFlag1 = false;
    2597         1646 :                         PlantUtilities::ScanPlantLoopsForObject(state, this_equip.Name, Type, plantLoc, errFlag1, _, _, NumSearchResults, _, LoopNum);
    2598              : 
    2599         1646 :                         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         1646 :                         this_equip.LoopNumPtr = plantLoc.loopNum;
    2608         1646 :                         this_equip.LoopSideNumPtr = plantLoc.loopSideNum;
    2609         1646 :                         this_equip.BranchNumPtr = plantLoc.branchNum;
    2610         1646 :                         this_equip.CompNumPtr = plantLoc.compNum;
    2611              : 
    2612         1646 :                         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         1646 :                         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         1281 :                 if (this_op_scheme.Type == OpScheme::ChillerHeaterSupervisory) {
    2646              :                     // do one time set up for custom chillerheater controls
    2647           10 :                     bool found = false;
    2648           10 :                     for (auto &s : state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes) {
    2649           10 :                         if (s.Name == this_op_scheme.Name) {
    2650           10 :                             this_op_scheme.ChillerHeaterSupervisoryOperation = &s; // assign as pointer
    2651           10 :                             found = true;
    2652           10 :                             break;
    2653              :                         }
    2654              :                     }
    2655           10 :                     if (found) {
    2656           10 :                         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         1619 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2670         1157 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2671         2438 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2672         1281 :                 auto &this_op_scheme = this_plant_loop.OpScheme(OpNum);
    2673         2710 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2674         1429 :                     auto &this_equip_list = this_op_scheme.EquipList(ListNum);
    2675              :                     int thisSchemeNum;
    2676         3075 :                     for (int EquipNum = 1, EquipNum_end = this_equip_list.NumComps; EquipNum <= EquipNum_end; ++EquipNum) {
    2677         1646 :                         auto const &this_equip = this_equip_list.Comp(EquipNum);
    2678              :                         // dereference indices (stored in previous loop)
    2679         1646 :                         plantLoc.loopNum = this_equip.LoopNumPtr;
    2680         1646 :                         plantLoc.loopSideNum = this_equip.LoopSideNumPtr;
    2681         1646 :                         plantLoc.branchNum = this_equip.BranchNumPtr;
    2682         1646 :                         plantLoc.compNum = this_equip.CompNumPtr;
    2683         1646 :                         auto &dummy_loop_equip = DataPlant::CompData::getPlantComponent(state, plantLoc);
    2684              : 
    2685         1646 :                         if (dummy_loop_equip.NumOpSchemes == 0) {
    2686              :                             // first op scheme for this component, allocate OpScheme and its EquipList to size 1
    2687         1374 :                             dummy_loop_equip.OpScheme.allocate(1);
    2688         1374 :                             auto &dummy_op_scheme_1(dummy_loop_equip.OpScheme(1));
    2689         1374 :                             dummy_op_scheme_1.EquipList.allocate(1);
    2690         1374 :                             dummy_loop_equip.NumOpSchemes = 1;
    2691         1374 :                             dummy_op_scheme_1.NumEquipLists = 1;
    2692              :                             // store pointers
    2693         1374 :                             dummy_op_scheme_1.OpSchemePtr = OpNum;
    2694         1374 :                             dummy_op_scheme_1.EquipList(1).ListPtr = ListNum;
    2695         1374 :                             dummy_op_scheme_1.EquipList(1).CompPtr = EquipNum;
    2696              :                         } else { // already an op scheme
    2697          272 :                             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          272 :                             bool FoundSchemeMatch = false;
    2701          454 :                             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          272 :                                 if (OpNum != dummy_loop_equip.OpScheme(thisSchemeNum).OpSchemePtr) {
    2705          182 :                                     continue;
    2706              :                                 }
    2707           90 :                                 FoundSchemeMatch = true;
    2708           90 :                                 break;
    2709              :                             }
    2710          272 :                             if (FoundSchemeMatch) { // op scheme already exists, but need to add a list to the existing OpScheme
    2711           90 :                                 auto &this_op_schemeAdd = dummy_loop_equip.OpScheme(thisSchemeNum);
    2712           90 :                                 int NewNumEquipLists = this_op_schemeAdd.NumEquipLists + 1;
    2713           90 :                                 this_op_schemeAdd.EquipList.redimension(NewNumEquipLists);
    2714           90 :                                 this_op_schemeAdd.NumEquipLists = NewNumEquipLists;
    2715           90 :                                 this_op_schemeAdd.EquipList(NewNumEquipLists).ListPtr = ListNum;
    2716           90 :                                 this_op_schemeAdd.EquipList(NewNumEquipLists).CompPtr = EquipNum;
    2717              :                             } else { // !FoundSchemeMatch: Add new op scheme and a new list
    2718          182 :                                 int NewNumOpSchemes = OldNumOpSchemes + 1;
    2719          182 :                                 dummy_loop_equip.OpScheme.redimension(NewNumOpSchemes);
    2720          182 :                                 auto &new_op_scheme = dummy_loop_equip.OpScheme(NewNumOpSchemes);
    2721          182 :                                 new_op_scheme.EquipList.allocate(1);
    2722          182 :                                 dummy_loop_equip.NumOpSchemes = NewNumOpSchemes;
    2723          182 :                                 new_op_scheme.NumEquipLists = 1;
    2724          182 :                                 new_op_scheme.OpSchemePtr = OpNum;
    2725          182 :                                 new_op_scheme.EquipList(1).ListPtr = ListNum;
    2726          182 :                                 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         1619 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2737         1157 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2738         3471 :             for (DataPlant::LoopSideLocation LoopSideNum : DataPlant::LoopSideKeys) {
    2739         2314 :                 auto const &this_loop_side = this_plant_loop.LoopSide(LoopSideNum);
    2740        16262 :                 for (int BranchNum = 1, BranchNum_end = this_loop_side.TotalBranches; BranchNum <= BranchNum_end; ++BranchNum) {
    2741        13948 :                     auto const &this_branch = this_loop_side.Branch(BranchNum);
    2742        27982 :                     for (int CompNum = 1, CompNum_end = this_branch.TotalComponents; CompNum <= CompNum_end; ++CompNum) {
    2743        14034 :                         auto const &this_component = this_branch.Comp(CompNum);
    2744        14034 :                         if (allocated(this_component.OpScheme)) {
    2745         2946 :                             for (int Index = 1; Index <= this_component.NumOpSchemes; ++Index) {
    2746         1556 :                                 int OpSchemePtr = this_component.OpScheme(Index).OpSchemePtr;
    2747         1556 :                                 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         1556 :                                 DataPlant::OpScheme SchemeType{};
    2755         1556 :                                 if (Index == 1) {
    2756         1374 :                                     SchemeType = this_plant_loop.OpScheme(OpSchemePtr).Type;
    2757              :                                 } else {
    2758          182 :                                     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         1619 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2773         1157 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2774         2438 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2775         1281 :                 auto &this_op_scheme = this_plant_loop.OpScheme(OpNum);
    2776              :                 // skip non-load based op schemes
    2777         1281 :                 if ((this_op_scheme.Type != OpScheme::HeatingRB) && (this_op_scheme.Type != OpScheme::CoolingRB)) {
    2778           81 :                     continue;
    2779              :                 }
    2780         1200 :                 HighestRange = 0.0;
    2781         2551 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2782         1351 :                     HighestRange = max(HighestRange, this_op_scheme.EquipList(ListNum).RangeUpperLimit);
    2783              :                 } // List
    2784         2551 :                 for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2785         1351 :                     if (HighestRange == this_op_scheme.EquipList(ListNum).RangeUpperLimit) {
    2786         1200 :                         this_op_scheme.EquipListNumForLastStage = ListNum;
    2787              :                     }
    2788              :                 }
    2789              :             } // operation scheme
    2790              :         } // loop
    2791              : 
    2792          462 :         state.dataPlantCondLoopOp->InitLoadDistributionOneTimeFlag = false;
    2793              :     }
    2794              : 
    2795     31707366 :     if (state.dataPlnt->AnyEMSPlantOpSchemesInModel) { // Execute any Initialization EMS program calling managers for User-Defined operation.
    2796      1943560 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2797      1554848 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2798      3109696 :             for (int OpNum = 1, OpNum_end = this_plant_loop.NumOpSchemes; OpNum <= OpNum_end; ++OpNum) {
    2799      1554848 :                 auto &this_op_scheme = this_plant_loop.OpScheme(OpNum);
    2800      1554848 :                 if (this_op_scheme.Type == OpScheme::EMS) {
    2801      1166136 :                     if (state.dataGlobal->BeginEnvrnFlag && this_op_scheme.MyEnvrnFlag) {
    2802           30 :                         if (this_op_scheme.ErlInitProgramMngr > 0) {
    2803              :                             bool anyEMSRan;
    2804            5 :                             ManageEMS(state, EMSManager::EMSCallFrom::UserDefinedComponentModel, anyEMSRan, this_op_scheme.ErlInitProgramMngr);
    2805           25 :                         } else if (this_op_scheme.initPluginLocation > -1) {
    2806            0 :                             state.dataPluginManager->pluginManager->runSingleUserDefinedPlugin(state, this_op_scheme.initPluginLocation);
    2807              :                         }
    2808           30 :                         this_op_scheme.MyEnvrnFlag = false;
    2809              :                     }
    2810      1166136 :                     if (!state.dataGlobal->BeginEnvrnFlag) {
    2811      1157640 :                         this_op_scheme.MyEnvrnFlag = true;
    2812              :                     }
    2813              :                 }
    2814              :             } // operation scheme
    2815              :         } // loop
    2816              :     }
    2817              : 
    2818              :     // FIRST HVAC INITS
    2819     31707366 :     if (FirstHVACIteration) {
    2820     62830584 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2821     47485969 :             auto &this_plant_loop = state.dataPlnt->PlantLoop(LoopNum);
    2822    142457907 :             for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    2823     94971938 :                 auto &this_loop_side = this_plant_loop.LoopSide(LoopSideNum);
    2824    704396682 :                 for (int BranchNum = 1, BranchNum_end = this_loop_side.TotalBranches; BranchNum <= BranchNum_end; ++BranchNum) {
    2825    609424744 :                     auto &this_branch = this_loop_side.Branch(BranchNum);
    2826   1222439733 :                     for (int CompNum = 1, CompNum_end = this_branch.TotalComponents; CompNum <= CompNum_end; ++CompNum) {
    2827    613014989 :                         auto &this_component = this_branch.Comp(CompNum);
    2828              :                         // initalize components 'ON-AVAILABLE-NO LOAD-NO EMS CTRL'
    2829    613014989 :                         this_component.ON = true;
    2830    613014989 :                         this_component.Available = true;
    2831    613014989 :                         this_component.MyLoad = 0.0;
    2832    613014989 :                         this_component.EMSLoadOverrideOn = false;
    2833              :                         // Zero out the old curOpSchemePtr so that we don't get 'carry-over' when we update schedules
    2834    613014989 :                         if (this_component.CurOpSchemeType != OpScheme::Demand && this_component.CurOpSchemeType != OpScheme::Pump &&
    2835    297778291 :                             this_component.CurOpSchemeType != OpScheme::WSEcon && this_component.CurOpSchemeType != OpScheme::NoControl) {
    2836     57240202 :                             this_component.CurOpSchemeType = OpScheme::NoControl;
    2837              :                         }
    2838    613014989 :                         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     15448091 :         for (DataPlant::ChillerHeaterSupervisoryOperationData &supervisor : state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes) {
    2845       103476 :             supervisor.needsSimulation = true;
    2846              :         }
    2847              :         // Update the OpScheme schedules
    2848     62830584 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2849     47485969 :             auto &this_loop = state.dataPlnt->PlantLoop(LoopNum);
    2850    100707202 :             for (int OpNum = 1; OpNum <= this_loop.NumOpSchemes; ++OpNum) {
    2851     53221233 :                 auto &this_op_scheme = this_loop.OpScheme(OpNum);
    2852              : 
    2853     53221233 :                 if (this_op_scheme.Type == OpScheme::ChillerHeaterSupervisory) {
    2854       326200 :                     if (this_op_scheme.ChillerHeaterSupervisoryOperation != nullptr &&
    2855       326200 :                         this_op_scheme.ChillerHeaterSupervisoryOperation->needsSimulation) {
    2856       103476 :                         this_op_scheme.ChillerHeaterSupervisoryOperation->EvaluateChillerHeaterChangeoverOpScheme(state);
    2857       103476 :                         this_op_scheme.ChillerHeaterSupervisoryOperation->needsSimulation = false;
    2858              :                     }
    2859       326200 :                     continue;
    2860              :                 }
    2861              : 
    2862     52895033 :                 if (this_op_scheme.sched->getCurrentVal() > 0.0) {
    2863     47212599 :                     this_op_scheme.Available = true;
    2864     98199522 :                     for (int ListNum = 1, ListNum_end = this_op_scheme.NumEquipLists; ListNum <= ListNum_end; ++ListNum) {
    2865     50986923 :                         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    110029131 :                         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     59042208 :                             auto const &this_list_component = this_equip_list.Comp(CompNum);
    2873              : 
    2874              :                             // then look up the component topological position from this structure
    2875     59042208 :                             int LoopPtr = this_list_component.LoopNumPtr;
    2876     59042208 :                             LoopSidePtr = this_list_component.LoopSideNumPtr;
    2877     59042208 :                             int BranchPtr = this_list_component.BranchNumPtr;
    2878     59042208 :                             int CompPtr = this_list_component.CompNumPtr;
    2879              : 
    2880              :                             // then set up a reference to the component on the plant data structure
    2881     59042208 :                             auto &this_loop_component = state.dataPlnt->PlantLoop(LoopPtr).LoopSide(LoopSidePtr).Branch(BranchPtr).Comp(CompPtr);
    2882              : 
    2883     59042208 :                             if (this_loop_component.CurOpSchemeType != OpScheme::Pump) {
    2884     59042208 :                                 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    127157392 :                             for (int CompOpNum = 1; CompOpNum <= this_loop_component.NumOpSchemes; ++CompOpNum) {
    2894     68115184 :                                 if (this_loop_component.OpScheme(CompOpNum).OpSchemePtr == OpNum) {
    2895     59042208 :                                     this_loop_component.CurCompLevelOpNum = CompOpNum;
    2896              :                                 }
    2897              :                             }
    2898              :                         }
    2899              :                     }
    2900              :                 } else {
    2901      5682434 :                     this_op_scheme.Available = false;
    2902              :                 }
    2903              :             }
    2904              :         }
    2905              :     } else { // call supervisory scheme every iteration
    2906     16362751 :         if (!state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes.empty()) {
    2907              :             // set sim flag so each supervisor is only simulated once in the plant loop below
    2908       449016 :             for (DataPlant::ChillerHeaterSupervisoryOperationData &supervisor : state.dataPlantCondLoopOp->ChillerHeaterSupervisoryOperationSchemes) {
    2909       224508 :                 supervisor.needsSimulation = true;
    2910              :             }
    2911      1220381 :             for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    2912       995873 :                 auto &this_loop = state.dataPlnt->PlantLoop(LoopNum);
    2913      1991746 :                 for (int OpNum = 1; OpNum <= this_loop.NumOpSchemes; ++OpNum) {
    2914       995873 :                     auto &this_op_scheme = this_loop.OpScheme(OpNum);
    2915       995873 :                     if (this_op_scheme.Type == OpScheme::ChillerHeaterSupervisory) {
    2916       644698 :                         if (this_op_scheme.ChillerHeaterSupervisoryOperation != nullptr &&
    2917       644698 :                             this_op_scheme.ChillerHeaterSupervisoryOperation->needsSimulation) {
    2918       224508 :                             this_op_scheme.ChillerHeaterSupervisoryOperation->EvaluateChillerHeaterChangeoverOpScheme(state);
    2919       224508 :                             this_op_scheme.ChillerHeaterSupervisoryOperation->needsSimulation = false;
    2920              :                         }
    2921       644698 :                         continue;
    2922              :                     }
    2923              :                 }
    2924              :             }
    2925              :         }
    2926              :     }
    2927              : 
    2928     31707366 :     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     17951626 : 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     17951626 :     auto &this_loop = state.dataPlnt->PlantLoop(LoopNum);
    2997     17951626 :     auto &this_loopside = this_loop.LoopSide(LoopSideNum);
    2998     17951626 :     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            0 :         LoadPLRPoint(Real64 capacity, Real64 plr) : plant_capacity_to_this_point(capacity), largest_min_plr_to_this_point(plr)
    3005              :         {
    3006            0 :         }
    3007              :     };
    3008     17951626 :     std::vector<LoadPLRPoint> accrued_load_plr_values;
    3009              : 
    3010              :     // load local variables
    3011     17951626 :     NumCompsOnList = this_equiplist.NumComps;
    3012              : 
    3013              :     // Allocate array once
    3014     17951626 :     accrued_load_plr_values.reserve(NumCompsOnList);
    3015     17951626 :     RemLoopDemand = LoopDemand;
    3016     17951626 :     if (NumCompsOnList <= 0) {
    3017            0 :         return;
    3018              :     }
    3019              : 
    3020     17951626 :     if (std::abs(RemLoopDemand) < SmallLoad) {
    3021              :         // no load to distribute
    3022              :     } else {
    3023              : 
    3024              :         // OPTIMAL DISTRIBUTION SCHEME
    3025     17837058 :         int numAvail = 0;
    3026     17837058 :         switch (this_loop.LoadDistribution) {
    3027      9810720 :         case DataPlant::LoadingScheme::Optimal:
    3028              :             // step 1: load all machines to optimal PLR
    3029     20182900 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3030              : 
    3031              :                 // look up topology from the equipment list
    3032     10372180 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3033     10372180 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3034              : 
    3035              :                 // create a reference to the component itself
    3036     10372180 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3037              : 
    3038     10372180 :                 if (!this_component.Available) {
    3039            3 :                     continue;
    3040              :                 }
    3041     10372177 :                 ++numAvail;
    3042              : 
    3043     10372177 :                 if (this_component.OptLoad > 0.0) {
    3044     10278973 :                     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        93204 :                     ChangeInLoad = std::abs(RemLoopDemand);
    3048              :                 }
    3049              : 
    3050     10372177 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    3051              : 
    3052     10372177 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3053              : 
    3054     10372177 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3055              : 
    3056     10372177 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    3057     10372177 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    3058              : 
    3059     10372177 :                 RemLoopDemand -= this_component.MyLoad;
    3060     10372177 :                 if (std::abs(RemLoopDemand) < SmallLoad) {
    3061      9725562 :                     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      9810720 :             if (numAvail > 0 && std::abs(RemLoopDemand) > SmallLoad) {
    3067       553607 :                 DivideLoad = std::abs(RemLoopDemand) / numAvail;
    3068      1143869 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3069              : 
    3070       590262 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3071       590262 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3072              : 
    3073              :                     // create a reference to the component itself
    3074       590262 :                     auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3075              : 
    3076       590262 :                     if (!this_component.Available) {
    3077            1 :                         continue;
    3078              :                     }
    3079              : 
    3080       590261 :                     NewLoad = this_component.MyLoad;
    3081       590261 :                     NewLoad = min(this_component.MaxLoad, std::abs(NewLoad) + DivideLoad);
    3082       590261 :                     ChangeInLoad = NewLoad - std::abs(this_component.MyLoad);
    3083       590261 :                     this_component.MyLoad = sign(NewLoad, RemLoopDemand);
    3084       590261 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3085       590261 :                     if (std::abs(RemLoopDemand) < SmallLoad) {
    3086       201255 :                         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      9810720 :             if (numAvail > 0 && std::abs(RemLoopDemand) > SmallLoad) {
    3094       738553 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3095              : 
    3096       386201 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3097       386201 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3098              : 
    3099              :                     // create a reference to the component itself
    3100       386201 :                     auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3101              : 
    3102       386201 :                     if (!this_component.Available) {
    3103            1 :                         continue;
    3104              :                     }
    3105       386200 :                     DivideLoad = this_component.MaxLoad - std::abs(this_component.MyLoad);
    3106       386200 :                     ChangeInLoad = min(std::abs(RemLoopDemand), DivideLoad);
    3107       386200 :                     this_component.MyLoad += sign(ChangeInLoad, RemLoopDemand);
    3108       386200 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3109       386200 :                     if (std::abs(RemLoopDemand) < SmallLoad) {
    3110         4155 :                         RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't
    3111              :                     }
    3112              :                     // reset
    3113              :                 }
    3114              :             }
    3115              : 
    3116      9810720 :             break;
    3117              : 
    3118              :         // SEQUENTIALLOAD DISTRIBUTION SCHEME
    3119      7447368 :         case DataPlant::LoadingScheme::Sequential:
    3120              : 
    3121              :             // step 1: Load machines in list order
    3122     15237152 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3123              : 
    3124      7789784 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3125      7789784 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3126              : 
    3127              :                 // create a reference to the component itself
    3128      7789784 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3129              : 
    3130      7789784 :                 if (!this_component.Available) {
    3131            0 :                     continue;
    3132              :                 }
    3133              : 
    3134      7789784 :                 if (this_component.MaxLoad > 0.0) { // apply known limit
    3135      7757226 :                     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        32558 :                     ChangeInLoad = std::abs(RemLoopDemand);
    3139              :                 }
    3140              : 
    3141      7789784 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    3142              : 
    3143      7789784 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3144              : 
    3145      7789784 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3146              : 
    3147      7789784 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    3148      7789784 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    3149      7789784 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3150      7789784 :                 if (std::abs(RemLoopDemand) < SmallLoad) {
    3151      6624793 :                     RemLoopDemand = 0.0; // CR8631 don't just exit or %MyLoad on second device isn't reset
    3152              :                 }
    3153              :             }
    3154              : 
    3155      7447368 :             break;
    3156              : 
    3157              :         // UNIFORMLOAD DISTRIBUTION SCHEME
    3158       578970 :         case DataPlant::LoadingScheme::Uniform:
    3159              : 
    3160              :             // step 1: distribute load equally to all available machines
    3161       578970 :             numAvail = 0;
    3162      1651326 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3163              : 
    3164      1072356 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3165      1072356 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3166              : 
    3167              :                 // create a reference to the component itself
    3168      1072356 :                 auto const &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3169              : 
    3170      1072356 :                 if (this_component.Available) {
    3171      1072352 :                     ++numAvail;
    3172              :                 }
    3173              :             }
    3174       578970 :             if (numAvail > 0) {
    3175       578968 :                 UniformLoad = std::abs(RemLoopDemand) / numAvail;
    3176              :             } else {
    3177            2 :                 UniformLoad = 0.0;
    3178              :             }
    3179      1651326 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3180              : 
    3181      1072356 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3182      1072356 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3183              : 
    3184              :                 // create a reference to the component itself
    3185      1072356 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3186              : 
    3187      1072356 :                 if (!this_component.Available) {
    3188            4 :                     continue;
    3189              :                 }
    3190      1072352 :                 if (this_component.MaxLoad > 0.0) {
    3191      1072352 :                     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      1072352 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    3198              : 
    3199      1072352 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3200              : 
    3201      1072352 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3202      1072352 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    3203      1072352 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    3204      1072352 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3205      1072352 :                 if (std::abs(RemLoopDemand) < SmallLoad) {
    3206       450735 :                     RemLoopDemand = 0.0;
    3207              :                 }
    3208              :             }
    3209              : 
    3210              :             // step 2: If RemLoopDemand is not zero, then distribute remainder sequentially.
    3211       578970 :             if (std::abs(RemLoopDemand) > SmallLoad) {
    3212       345711 :                 for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3213              : 
    3214       217476 :                     BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3215       217476 :                     CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3216              : 
    3217              :                     // create a reference to the component itself
    3218       217476 :                     auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3219              : 
    3220       217476 :                     if (!this_component.Available) {
    3221            4 :                         continue;
    3222              :                     }
    3223       217472 :                     ChangeInLoad = min(this_component.MaxLoad - std::abs(this_component.MyLoad), std::abs(RemLoopDemand));
    3224       217472 :                     ChangeInLoad = max(0.0, ChangeInLoad);
    3225       217472 :                     this_component.MyLoad += sign(ChangeInLoad, RemLoopDemand);
    3226       217472 :                     RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3227       217472 :                     if (std::abs(RemLoopDemand) < SmallLoad) {
    3228        46161 :                         RemLoopDemand = 0.0;
    3229              :                     }
    3230              :                 }
    3231              :             }
    3232              : 
    3233       578970 :             break;
    3234              : 
    3235              :         // UNIFORMPLR LOAD DISTRIBUTION SCHEME
    3236            0 :         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            0 :             PlantCapacity = 0.0;
    3240            0 :             PlantPLR = 0.0;
    3241            0 :             MinCompPLR = 0.0;
    3242            0 :             LargestMinCompPLR = 0.0;
    3243              : 
    3244              :             // Determine PlantCapacity and LargestMinCompPLR
    3245            0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3246              : 
    3247            0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3248            0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3249              : 
    3250              :                 // create a reference to the component itself
    3251            0 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3252              : 
    3253            0 :                 if (!this_component.Available) {
    3254            0 :                     continue;
    3255              :                 }
    3256              : 
    3257            0 :                 PlantCapacity += this_component.MaxLoad;
    3258              : 
    3259            0 :                 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            0 :                     MinCompPLR = this_component.MinLoad / this_component.MaxLoad;
    3265              :                 }
    3266              : 
    3267              :                 // Set LargestMinCompPLR to largest MinCompPLR
    3268            0 :                 LargestMinCompPLR = max(LargestMinCompPLR, MinCompPLR);
    3269              : 
    3270              :                 // Update the array
    3271            0 :                 accrued_load_plr_values.push_back(LoadPLRPoint(PlantCapacity, LargestMinCompPLR));
    3272              :             }
    3273              : 
    3274              :             // work backwards from full capacity down to 1 unit on
    3275            0 :             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            0 :                 if (i == 0) {
    3279            0 :                     PlantCapacity = accrued_load_plr_values[i].plant_capacity_to_this_point;
    3280            0 :                     LargestMinCompPLR = accrued_load_plr_values[i].largest_min_plr_to_this_point;
    3281            0 :                     break;
    3282              : 
    3283              :                     // if the capacity is greater than the demand, just store the latest values and continue
    3284            0 :                 } else if (std::abs(RemLoopDemand) <
    3285            0 :                            (accrued_load_plr_values[i].largest_min_plr_to_this_point * accrued_load_plr_values[i].plant_capacity_to_this_point)) {
    3286            0 :                     PlantCapacity = accrued_load_plr_values[i].plant_capacity_to_this_point;
    3287            0 :                     LargestMinCompPLR = accrued_load_plr_values[i].largest_min_plr_to_this_point;
    3288            0 :                     continue;
    3289              : 
    3290              :                     // if the capacity is less than the demand, accept the last values from the previous iteration and exit
    3291              :                 } else {
    3292            0 :                     break;
    3293              :                 }
    3294              :             }
    3295              : 
    3296              :             // Determine PLR for uniform PLR loading of all equipment
    3297            0 :             if (PlantCapacity > 0.0) {
    3298            0 :                 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            0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3305              : 
    3306            0 :                 CompLoad = 0.0;
    3307              : 
    3308            0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3309            0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3310              : 
    3311              :                 // create a reference to the component itself
    3312            0 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3313              : 
    3314            0 :                 if (!this_component.Available) {
    3315            0 :                     continue;
    3316              :                 }
    3317              : 
    3318            0 :                 CompLoad = PlantPLR * this_component.MaxLoad;
    3319              : 
    3320            0 :                 if (this_component.MaxLoad > 0.0) {
    3321            0 :                     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            0 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    3328              : 
    3329            0 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3330              : 
    3331            0 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3332              : 
    3333            0 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    3334              : 
    3335            0 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    3336              : 
    3337            0 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3338              : 
    3339            0 :                 if (std::abs(RemLoopDemand) < SmallLoad) {
    3340            0 :                     RemLoopDemand = 0.0;
    3341              :                 }
    3342              :             }
    3343              : 
    3344            0 :             break;
    3345              : 
    3346              :         // SEQUENTIALUNIFORMPLR LOAD DISTRIBUTION SCHEME
    3347            0 :         case DataPlant::LoadingScheme::SequentialUniformPLR:
    3348              : 
    3349            0 :             PlantCapacity = 0.0;
    3350            0 :             PlantPLR = 0.0;
    3351            0 :             MinCompPLR = 0.0;
    3352            0 :             LargestMinCompPLR = 0.0;
    3353              : 
    3354              :             // Determine PlantCapacity and LargestMinCompPLR
    3355            0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3356              : 
    3357            0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3358            0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3359              : 
    3360              :                 // create a reference to the component itself
    3361            0 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3362              : 
    3363            0 :                 if (!this_component.Available) {
    3364            0 :                     continue;
    3365              :                 }
    3366              : 
    3367            0 :                 PlantCapacity += this_component.MaxLoad;
    3368              : 
    3369            0 :                 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            0 :                     MinCompPLR = this_component.MinLoad / this_component.MaxLoad;
    3375              :                 }
    3376              : 
    3377              :                 // Set LargestMinCompPLR to largest MinCompPLR
    3378            0 :                 if (MinCompPLR > LargestMinCompPLR) {
    3379            0 :                     LargestMinCompPLR = MinCompPLR;
    3380              :                 }
    3381              : 
    3382            0 :                 if (std::abs(RemLoopDemand) <= PlantCapacity) {
    3383            0 :                     break;
    3384              :                 }
    3385              :             }
    3386              : 
    3387              :             // Determine PLR for uniform PLR loading of all equipment
    3388            0 :             if (PlantCapacity > 0.0) {
    3389            0 :                 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            0 :             for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3396              : 
    3397            0 :                 CompLoad = 0.0;
    3398              : 
    3399            0 :                 BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3400            0 :                 CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3401              : 
    3402              :                 // create a reference to the component itself
    3403            0 :                 auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3404              : 
    3405            0 :                 if (!this_component.Available) {
    3406            0 :                     continue;
    3407              :                 }
    3408              : 
    3409            0 :                 CompLoad = PlantPLR * this_component.MaxLoad;
    3410              : 
    3411            0 :                 if (this_component.MaxLoad > 0.0) {
    3412            0 :                     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            0 :                 AdjustChangeInLoadForLastStageUpperRangeLimit(state, LoopNum, CurSchemePtr, ListPtr, ChangeInLoad);
    3419              : 
    3420            0 :                 AdjustChangeInLoadByEMSControls(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3421              : 
    3422            0 :                 AdjustChangeInLoadByHowServed(state, {LoopNum, LoopSideNum, BranchNum, CompNum}, ChangeInLoad);
    3423              : 
    3424            0 :                 ChangeInLoad = max(0.0, ChangeInLoad);
    3425              : 
    3426            0 :                 this_component.MyLoad = sign(ChangeInLoad, RemLoopDemand);
    3427              : 
    3428            0 :                 RemLoopDemand -= sign(ChangeInLoad, RemLoopDemand);
    3429              : 
    3430            0 :                 if (std::abs(RemLoopDemand) < SmallLoad) {
    3431            0 :                     RemLoopDemand = 0.0;
    3432              :                 }
    3433              :             }
    3434            0 :             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     37409482 :     for (CompIndex = 1; CompIndex <= NumCompsOnList; ++CompIndex) {
    3443              : 
    3444     19457856 :         BranchNum = this_equiplist.Comp(CompIndex).BranchNumPtr;
    3445     19457856 :         CompNum = this_equiplist.Comp(CompIndex).CompNumPtr;
    3446              : 
    3447              :         // create a reference to the component itself
    3448     19457856 :         auto &this_component = this_loopside.Branch(BranchNum).Comp(CompNum);
    3449              : 
    3450     19457856 :         if (std::abs(this_component.MyLoad) < SmallLoad) {
    3451       893368 :             this_component.ON = false;
    3452              :         } else {
    3453     18564488 :             this_component.ON = true;
    3454              :         }
    3455              :     }
    3456     17951626 : }
    3457              : 
    3458     19234313 : 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     19234313 :     if (state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurOpSchemePtr).EquipListNumForLastStage == CurEquipListPtr) { // at final last stage
    3500              : 
    3501     18652819 :         RangeHiLimit = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurOpSchemePtr).EquipList(CurEquipListPtr).RangeUpperLimit;
    3502     18652819 :         ChangeInLoad = min(ChangeInLoad, RangeHiLimit);
    3503              :     }
    3504     19234313 : }
    3505              : 
    3506     19234313 : 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     19234313 :     Real64 CurMassFlowRate(0.0);
    3530     19234313 :     Real64 ToutLowLimit(0.0);
    3531     19234313 :     Real64 ToutHiLimit(0.0);
    3532     19234313 :     Real64 TinLowLimit(0.0);
    3533     19234313 :     Real64 Tinlet(0.0);
    3534     19234313 :     Real64 Tsensor(0.0);
    3535     19234313 :     Real64 CurSpecHeat(0.0);
    3536     19234313 :     Real64 QdotTmp(0.0);
    3537     19234313 :     int ControlNodeNum(0);
    3538              : 
    3539     19234313 :     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     19234313 :     switch (this_component.HowLoadServed) {
    3545              : 
    3546              :     // Chillers
    3547      4932226 :     case DataPlant::HowMet::ByNominalCapLowOutLimit: { // chillers with lower limit on outlet temperature
    3548              : 
    3549              :         //- Retrieve data from the plant loop data structure
    3550      4932226 :         CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
    3551      4932226 :         ToutLowLimit = this_component.MinOutletTemp;
    3552      4932226 :         Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
    3553      4932226 :         CurSpecHeat = state.dataPlnt->PlantLoop(plantLoc.loopNum).glycol->getSpecificHeat(state, Tinlet, RoutineName);
    3554      4932226 :         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      4932226 :         if (CurMassFlowRate > 0.0) {
    3558      4800472 :             ChangeInLoad = min(ChangeInLoad, QdotTmp);
    3559              :         }
    3560              : 
    3561      4932226 :         break;
    3562              :     }
    3563        45881 :     case DataPlant::HowMet::ByNominalCapFreeCoolCntrl: {
    3564              :         // for chillers with free cooling shutdown (HeatExchanger:Hydronic currently)
    3565              :         // determine if free cooling controls shut off chiller
    3566        45881 :         TinLowLimit = this_component.FreeCoolCntrlMinCntrlTemp;
    3567        45881 :         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        45881 :         case DataPlant::FreeCoolControlMode::Loop: {
    3577        45881 :             ControlNodeNum = this_component.FreeCoolCntrlNodeNum;
    3578        45881 :             if (ControlNodeNum > 0) {
    3579        45881 :                 Tsensor = state.dataLoopNodes->Node(ControlNodeNum).TempLastTimestep; // use lagged value for stability
    3580              :             } else {
    3581            0 :                 Tsensor = 23.0;
    3582              :             }
    3583        45881 :             break;
    3584              :         }
    3585            0 :         default:
    3586            0 :             break;
    3587              :         }
    3588              : 
    3589        45881 :         if (Tsensor < TinLowLimit) { // turn off chiller to initiate free cooling
    3590            1 :             ChangeInLoad = 0.0;
    3591            1 :             this_component.Available = false;
    3592            1 :             this_component.FreeCoolCntrlShutDown = true;
    3593              :         } else {
    3594        45880 :             this_component.Available = true;
    3595        45880 :             this_component.FreeCoolCntrlShutDown = false;
    3596              :         }
    3597              : 
    3598        45881 :         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      4823850 :     case DataPlant::HowMet::ByNominalCapHiOutLimit: { // boilers with upper limit on outlet temperature
    3650              :         //- Retrieve data from the plant loop data structure
    3651      4823850 :         CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
    3652      4823850 :         ToutHiLimit = this_component.MaxOutletTemp;
    3653      4823850 :         Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
    3654      4823850 :         CurSpecHeat = state.dataPlnt->PlantLoop(plantLoc.loopNum).glycol->getSpecificHeat(state, Tinlet, RoutineName);
    3655      4823850 :         QdotTmp = CurMassFlowRate * CurSpecHeat * (ToutHiLimit - Tinlet);
    3656              : 
    3657      4823850 :         if (CurMassFlowRate > 0.0) {
    3658      4760007 :             ChangeInLoad = min(ChangeInLoad, QdotTmp);
    3659              :         }
    3660              : 
    3661      4823850 :         break;
    3662              :     }
    3663      4607773 :     case DataPlant::HowMet::PassiveCap: { // need to estimate current capacity if more or less passive devices ??
    3664              : 
    3665      4607773 :         break;
    3666              :     }
    3667      4824583 :     default:
    3668      4824583 :         break;
    3669              :     }
    3670     19234313 : }
    3671              : 
    3672      1161430 : 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      1161430 :     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      1161430 :     auto &this_component = CompData::getPlantComponent(state, plantLoc);
    3718              : 
    3719              :     // find the pointer to the 'PlantLoop()%OpScheme()'...data structure
    3720      1161430 :     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      1161430 :     OpSchemePtr = this_component.OpScheme(OpNum).OpSchemePtr;
    3726      1161430 :     ListPtr = this_component.OpScheme(OpNum).EquipList(1).ListPtr;
    3727      1161430 :     CompPtr = this_component.OpScheme(OpNum).EquipList(1).CompPtr;
    3728              : 
    3729              :     // load local variables from the data structures
    3730      1161430 :     CompMinLoad = this_component.MinLoad;
    3731      1161430 :     CompMaxLoad = this_component.getDynamicMaxCapacity(state);
    3732      1161430 :     CompOptLoad = this_component.OptLoad;
    3733      1161430 :     DemandNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).DemandNodeNum;
    3734      1161430 :     SetPtNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).SetPointNodeNum;
    3735      1161430 :     TempIn = state.dataLoopNodes->Node(DemandNode).Temp;
    3736      1161430 :     rho = state.dataPlnt->PlantLoop(plantLoc.loopNum).glycol->getDensity(state, TempIn, RoutineName);
    3737              : 
    3738      1161430 :     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      1161430 :     ActualMdot = state.dataLoopNodes->Node(DemandNode).MassFlowRate;
    3741      1161430 :     CurSpecHeat = state.dataPlnt->PlantLoop(plantLoc.loopNum).glycol->getSpecificHeat(state, TempIn, RoutineName);
    3742      1161430 :     if ((ActualMdot > 0.0) && (ActualMdot != DemandMdot)) {
    3743       729160 :         DemandMdot = ActualMdot;
    3744              :     }
    3745              : 
    3746      1161430 :     switch (state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopDemandCalcScheme) {
    3747       956790 :     case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    3748       956790 :         TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPoint;
    3749       956790 :         break;
    3750              :     }
    3751       204640 :     case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    3752       204640 :         if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::CoolingOp) {
    3753       102320 :             TempSetPt = state.dataLoopNodes->Node(SetPtNode).TempSetPointHi;
    3754       102320 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType ==
    3755              :                    CtrlType::HeatingOp) {
    3756       102320 :             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       204640 :         break;
    3771              :     }
    3772            0 :     default:
    3773            0 :         assert(false);
    3774              :         break;
    3775              :     }
    3776              : 
    3777      1161430 :     if (TempSetPt == SensedNodeFlagValue) {
    3778          120 :         this_component.ON = false;
    3779          120 :         this_component.MyLoad = 0.0;
    3780          120 :         this_component.EquipDemand = 0.0;
    3781              :     } else {
    3782              : 
    3783      1161310 :         CompDemand = (DemandMdot * CurSpecHeat * (TempSetPt - TempIn));
    3784              : 
    3785      1161310 :         if (std::abs(CompDemand) < LoopDemandTol) {
    3786       137101 :             CompDemand = 0.0;
    3787              :         }
    3788      1161310 :         this_component.EquipDemand = CompDemand;
    3789              : 
    3790              :         // set MyLoad and runflag
    3791      1161310 :         if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::CoolingOp) {
    3792       652408 :             if (CompDemand < (-LoopDemandTol)) {
    3793       454298 :                 this_component.ON = true;
    3794       454298 :                 this_component.MyLoad = CompDemand;
    3795              :             } else {
    3796       198110 :                 this_component.ON = false;
    3797       198110 :                 this_component.MyLoad = 0.0;
    3798              :             }
    3799       508902 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType ==
    3800              :                    CtrlType::HeatingOp) {
    3801       133274 :             if (CompDemand > LoopDemandTol) {
    3802         7887 :                 this_component.ON = true;
    3803         7887 :                 this_component.MyLoad = CompDemand;
    3804              :             } else {
    3805       125387 :                 this_component.ON = false;
    3806       125387 :                 this_component.MyLoad = 0.0;
    3807              :             }
    3808       375628 :         } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).CtrlType == CtrlType::DualOp) {
    3809       375628 :             if (CompDemand > LoopDemandTol || CompDemand < (-LoopDemandTol)) {
    3810       305203 :                 this_component.ON = true;
    3811       305203 :                 this_component.MyLoad = CompDemand;
    3812              :             } else {
    3813        70425 :                 this_component.ON = false;
    3814        70425 :                 this_component.MyLoad = 0.0;
    3815              :             }
    3816              :         }
    3817              : 
    3818              :         // Check bounds on MyLoad
    3819      1161310 :         if (std::abs(this_component.MyLoad) > CompMaxLoad) {
    3820       530923 :             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      1161310 :         if (std::abs(this_component.MyLoad) < CompMinLoad) {
    3826        80008 :             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      1161430 : }
    3833              : 
    3834       322816 : 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       322816 :     auto &this_component = CompData::getPlantComponent(state, plantLoc);
    3876              : 
    3877              :     // ListPtr = PlantLoop(LoopNum)%LoopSide(LoopSideNum)%Branch(BranchNum)%Comp(CompNum)%OpScheme(CurCompLevelOpNum)%EquipList(1)%ListPtr
    3878       322816 :     CompPtr = this_component.OpScheme(CurCompLevelOpNum).EquipList(1).CompPtr;
    3879              : 
    3880              :     // fill internal variable
    3881       322816 :     state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSIntVarRemainingLoadValue = LoopDemand;
    3882              : 
    3883              :     // Call EMS program(s)
    3884       322816 :     if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).ErlSimProgramMngr > 0) {
    3885              :         bool anyEMSRan;
    3886       161408 :         ManageEMS(state,
    3887              :                   EMSManager::EMSCallFrom::UserDefinedComponentModel,
    3888              :                   anyEMSRan,
    3889       161408 :                   state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).ErlSimProgramMngr);
    3890       161408 :     } else if (state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).simPluginLocation > -1) {
    3891       161408 :         state.dataPluginManager->pluginManager->runSingleUserDefinedPlugin(
    3892       161408 :             state, state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).simPluginLocation);
    3893              :     }
    3894              : 
    3895              :     // move actuated value to MyLoad
    3896              : 
    3897       322816 :     this_component.MyLoad =
    3898       322816 :         state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSActuatorDispatchedLoadValue;
    3899       322816 :     this_component.EquipDemand =
    3900       322816 :         state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(CurSchemePtr).EquipList(1).Comp(CompPtr).EMSActuatorDispatchedLoadValue;
    3901       322816 :     if (std::abs(this_component.MyLoad) > LoopDemandTol) {
    3902       125424 :         this_component.ON = true;
    3903              : 
    3904              :     } else {
    3905       197392 :         this_component.ON = false;
    3906              :     }
    3907       322816 : }
    3908              : 
    3909              : // End Load Calculation/Distribution Section of the Plant Loop Module
    3910              : //******************************************************************************
    3911              : 
    3912              : //********************************
    3913              : 
    3914       399700 : 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       399700 :     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       399700 :     switch (CurSchemeType) {
    3949        14584 :     case OpScheme::DryBulbTDB: { // drybulb temp based controls
    3950        14584 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3951        14584 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3952        14584 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutDryBulbTemp;
    3953        14584 :         break;
    3954              :     }
    3955       370572 :     case OpScheme::WetBulbTDB: { // wetbulb temp based controls
    3956       370572 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3957       370572 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3958       370572 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutWetBulbTemp;
    3959       370572 :         break;
    3960              :     }
    3961        14544 :     case OpScheme::DewPointTDB: { // dewpoint temp based controls
    3962        14544 :         ReferenceNodeNum = state.dataPlnt->PlantLoop(LoopNum).OpScheme(CurSchemePtr).ReferenceNodeNumber;
    3963        14544 :         NodeTemperature = state.dataLoopNodes->Node(ReferenceNodeNum).Temp;
    3964        14544 :         FindRangeVariable = NodeTemperature - state.dataEnvrn->OutDewPointTemp;
    3965        14544 :         break;
    3966              :     }
    3967            0 :     default: {
    3968            0 :         assert(false);
    3969              :         break;
    3970              :     }
    3971              :     } // OperationScheme
    3972              : 
    3973       399700 :     return FindRangeVariable;
    3974              : }
    3975              : 
    3976              : //********************************
    3977              : 
    3978              : // Begin Plant Loop ON/OFF Utility Subroutines
    3979              : //******************************************************************************
    3980              : 
    3981     19435872 : 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     99614407 :     for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++Num) {
    4013    162702066 :         for (MachineOnLoopNum = 1; MachineOnLoopNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).TotalComponents;
    4014              :              ++MachineOnLoopNum) {
    4015     82523531 :             switch (state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnLoopNum).Type) {
    4016     38077699 :             case DataPlant::PlantEquipmentType::Pipe:
    4017              :             case DataPlant::PlantEquipmentType::PipeInterior:
    4018              :             case DataPlant::PlantEquipmentType::PipeExterior:
    4019              :             case DataPlant::PlantEquipmentType::PipeUnderground: {
    4020     38077699 :                 state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnLoopNum).ON = true;
    4021     38077699 :                 break;
    4022              :             }
    4023     44445832 :             default:
    4024     44445832 :                 break; // Don't do anything
    4025              :             }
    4026              :         }
    4027              :     }
    4028     19435872 : }
    4029              : 
    4030        33224 : 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        99672 :     for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    4060       332240 :         for (Num = 1; Num <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++Num) {
    4061       531584 :             for (MachineOnBranch = 1; MachineOnBranch <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).TotalComponents;
    4062              :                  ++MachineOnBranch) {
    4063              :                 // Sankar Non Integrated Economizer
    4064       265792 :                 if (!DataPlant::PlantEquipmentTypeIsPump[static_cast<int>(
    4065       265792 :                         state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).Type)]) {
    4066       232568 :                     state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).ON = false;
    4067       232568 :                     state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(Num).Comp(MachineOnBranch).MyLoad = 0.0;
    4068              :                 }
    4069              :             }
    4070              :         }
    4071              :     }
    4072        33224 : }
    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           76 : 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          203 :     for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    4141          127 :         std::string ActuatorName = "Plant Loop Overall";
    4142          127 :         std::string UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    4143          127 :         std::string ActuatorType = "On/Off Supervisory";
    4144          127 :         SetupEMSActuator(state,
    4145              :                          ActuatorName,
    4146              :                          UniqueIDName,
    4147              :                          ActuatorType,
    4148              :                          Units,
    4149          127 :                          state.dataPlnt->PlantLoop(LoopNum).EMSCtrl,
    4150          127 :                          state.dataPlnt->PlantLoop(LoopNum).EMSValue);
    4151              : 
    4152          127 :         ActuatorName = "Supply Side Half Loop";
    4153          127 :         UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    4154          127 :         ActuatorType = "On/Off Supervisory";
    4155          127 :         SetupEMSActuator(state,
    4156              :                          ActuatorName,
    4157              :                          UniqueIDName,
    4158              :                          ActuatorType,
    4159              :                          Units,
    4160          127 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Supply).EMSCtrl,
    4161          127 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Supply).EMSValue);
    4162              : 
    4163          127 :         ActuatorName = "Demand Side Half Loop";
    4164          127 :         UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).Name;
    4165          127 :         ActuatorType = "On/Off Supervisory";
    4166          127 :         SetupEMSActuator(state,
    4167              :                          ActuatorName,
    4168              :                          UniqueIDName,
    4169              :                          ActuatorType,
    4170              :                          Units,
    4171          127 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Demand).EMSCtrl,
    4172          127 :                          state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideLocation::Demand).EMSValue);
    4173              : 
    4174          381 :         for (DataPlant::LoopSideLocation LoopSideNum : LoopSideKeys) {
    4175         3032 :             for (int BranchNum = 1; BranchNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).TotalBranches; ++BranchNum) {
    4176         2778 :                 if (LoopSideNum == LoopSideLocation::Supply) {
    4177          524 :                     ActuatorName = "Supply Side Branch";
    4178          524 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Name;
    4179          524 :                     ActuatorType = "On/Off Supervisory";
    4180          524 :                     SetupEMSActuator(state,
    4181              :                                      ActuatorName,
    4182              :                                      UniqueIDName,
    4183              :                                      ActuatorType,
    4184              :                                      Units,
    4185          524 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideOn,
    4186          524 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideValue);
    4187         2254 :                 } else if (LoopSideNum == LoopSideLocation::Demand) {
    4188         2254 :                     ActuatorName = "Demand Side Branch";
    4189         2254 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Name;
    4190         2254 :                     ActuatorType = "On/Off Supervisory";
    4191         2254 :                     SetupEMSActuator(state,
    4192              :                                      ActuatorName,
    4193              :                                      UniqueIDName,
    4194              :                                      ActuatorType,
    4195              :                                      Units,
    4196         2254 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideOn,
    4197         2254 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).EMSCtrlOverrideValue);
    4198              :                 }
    4199         5573 :                 for (int CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).TotalComponents;
    4200              :                      ++CompNum) {
    4201         5590 :                     ActuatorName = format("Plant Component {}",
    4202              :                                           PlantEquipTypeNames[static_cast<int>(
    4203         5590 :                                               state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).Type)]);
    4204         2795 :                     UniqueIDName = state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).Name;
    4205         2795 :                     ActuatorType = "On/Off Supervisory";
    4206         2795 :                     SetupEMSActuator(state,
    4207              :                                      ActuatorName,
    4208              :                                      UniqueIDName,
    4209              :                                      ActuatorType,
    4210              :                                      "[fraction]",
    4211         2795 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).EMSLoadOverrideOn,
    4212         2795 :                                      state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).EMSLoadOverrideValue);
    4213              :                 }
    4214              :             }
    4215              :         }
    4216          127 :     }
    4217           76 : }
    4218              : 
    4219     38897020 : 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     38897020 :     auto &this_loop = state.dataPlnt->PlantLoop(plantLoc.loopNum);
    4268     38897020 :     auto &this_loopside = this_loop.LoopSide(plantLoc.loopSideNum);
    4269     38897020 :     auto &this_comp = this_loopside.Branch(plantLoc.branchNum).Comp(plantLoc.compNum);
    4270              : 
    4271              :     // Loop Control
    4272     38897020 :     if (this_loop.EMSCtrl) {
    4273        16612 :         if (this_loop.EMSValue <= 0.0) {
    4274        16612 :             LoopShutDownFlag = true;
    4275        16612 :             TurnOffLoopEquipment(state, plantLoc.loopNum);
    4276       136404 :             return;
    4277              :         } else {
    4278            0 :             LoopShutDownFlag = false;
    4279              :         }
    4280              :     } else {
    4281     38880408 :         LoopShutDownFlag = false;
    4282              :     }
    4283              : 
    4284              :     // Half-loop control
    4285     38880408 :     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     38880408 :     if (this_comp.EMSLoadOverrideOn) {
    4295              :         // EMSValue <= 0 turn component OFF
    4296       119792 :         if (this_comp.EMSLoadOverrideValue <= 0.0) {
    4297       119792 :             this_comp.ON = false;
    4298       119792 :             this_comp.Available = false;
    4299       119792 :             this_comp.MyLoad = 0.0;
    4300       119792 :             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     19234313 : 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     19234313 :     auto &this_loopside = state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum);
    4383     19234313 :     auto &this_branch = this_loopside.Branch(plantLoc.branchNum);
    4384     19234313 :     auto const &this_comp = this_branch.Comp(plantLoc.compNum);
    4385              : 
    4386     19234313 :     if ((this_loopside.EMSCtrl) && (this_loopside.EMSValue <= 0.0)) {
    4387            0 :         ChangeInLoad = 0.0;
    4388            0 :         return;
    4389              :     }
    4390              : 
    4391     19234313 :     if ((this_branch.EMSCtrlOverrideOn) && (this_branch.EMSCtrlOverrideValue <= 0.0)) {
    4392            0 :         ChangeInLoad = 0.0;
    4393            0 :         return;
    4394              :     }
    4395              : 
    4396     19234313 :     if (this_comp.EMSLoadOverrideOn) {
    4397        52224 :         if (this_comp.EMSLoadOverrideValue == 0.0) {
    4398          672 :             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