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