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