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