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