Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Fmath.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Data/EnergyPlusData.hh>
53 : #include <EnergyPlus/DataEnvironment.hh>
54 : #include <EnergyPlus/DataHeatBalFanSys.hh>
55 : #include <EnergyPlus/DataHeatBalance.hh>
56 : #include <EnergyPlus/DataIPShortCuts.hh>
57 : #include <EnergyPlus/DataZoneControls.hh>
58 : #include <EnergyPlus/DemandManager.hh>
59 : #include <EnergyPlus/GlobalNames.hh>
60 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
61 : #include <EnergyPlus/InternalHeatGains.hh>
62 : #include <EnergyPlus/MixedAir.hh>
63 : #include <EnergyPlus/OutputProcessor.hh>
64 : #include <EnergyPlus/ScheduleManager.hh>
65 : #include <EnergyPlus/SimulationManager.hh>
66 : #include <EnergyPlus/UtilityRoutines.hh>
67 :
68 : namespace EnergyPlus::DemandManager {
69 :
70 : // MODULE INFORMATION:
71 : // AUTHOR Peter Graham Ellis
72 : // DATE WRITTEN July 2005
73 : // MODIFIED Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
74 : // RE-ENGINEERED na
75 :
76 : // PURPOSE OF THIS MODULE:
77 : // This module provides controls for demand limiting various loads.
78 :
79 : // METHODOLOGY EMPLOYED:
80 : // ManageDemand is called from within the ManageHVAC routine after the first pass through SimHVAC, but
81 : // _before_ any variables are reported or histories are updated. If the metered demand is above the
82 : // limit action is taken using the various demand managers to reduce loads. Exterior energy use, zone
83 : // heat balance, and HVAC system are then resimulated as necessary. It is possible to iterate several
84 : // times through ManageDemand before the final demand managers are established and the timestep can be
85 : // completed.
86 :
87 : constexpr std::array<std::string_view, static_cast<int>(ManagerType::Num)> ManagerNamesUC{"DEMANDMANAGER:EXTERIORLIGHTS",
88 : "DEMANDMANAGER:LIGHTS",
89 : "DEMANDMANAGER:ELECTRICEQUIPMENT",
90 : "DEMANDMANAGER:THERMOSTATS",
91 : "DEMANDMANAGER:VENTILATION"};
92 : constexpr std::array<std::string_view, static_cast<int>(ManagePriorityType::Num)> ManagePriorityNamesUC{"SEQUENTIAL", "OPTIMAL", "ALL"};
93 : constexpr std::array<std::string_view, static_cast<int>(ManagerLimit::Num)> ManagerLimitNamesUC{"OFF", "FIXED", "VARIABLE", "REDUCTIONRATIO"};
94 : constexpr std::array<std::string_view, static_cast<int>(ManagerLimit::Num)> ManagerLimitVentNamesUC{"OFF", "FIXEDRATE", "VARIABLE", "REDUCTIONRATIO"};
95 : constexpr std::array<std::string_view, static_cast<int>(ManagerSelection::Num)> ManagerSelectionNamesUC{"ALL", "ROTATEMANY", "ROTATEONE"};
96 :
97 1989307 : void ManageDemand(EnergyPlusData &state)
98 : {
99 :
100 : // SUBROUTINE INFORMATION:
101 : // AUTHOR Peter Graham Ellis
102 : // DATE WRITTEN July 2005
103 :
104 : // Locals
105 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
106 :
107 1989307 : if (state.dataDemandManager->GetInput && !state.dataGlobal->DoingSizing) {
108 0 : GetDemandManagerInput(state);
109 0 : GetDemandManagerListInput(state);
110 0 : state.dataDemandManager->GetInput = false;
111 : }
112 :
113 1989307 : if (state.dataDemandManager->NumDemandManagerList > 0) {
114 :
115 8064 : if (state.dataGlobal->WarmupFlag) {
116 6912 : state.dataDemandManager->BeginDemandSim = true;
117 6912 : if (state.dataDemandManager->ClearHistory) {
118 : // Clear historical variables
119 24 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
120 12 : state.dataDemandManager->DemandManagerList(ListNum).History = 0.0;
121 12 : state.dataDemandManager->DemandManagerList(ListNum).MeterDemand = 0.0;
122 12 : state.dataDemandManager->DemandManagerList(ListNum).AverageDemand = 0.0;
123 12 : state.dataDemandManager->DemandManagerList(ListNum).PeakDemand = 0.0;
124 12 : state.dataDemandManager->DemandManagerList(ListNum).ScheduledLimit = 0.0;
125 12 : state.dataDemandManager->DemandManagerList(ListNum).DemandLimit = 0.0;
126 12 : state.dataDemandManager->DemandManagerList(ListNum).AvoidedDemand = 0.0;
127 12 : state.dataDemandManager->DemandManagerList(ListNum).OverLimit = 0.0;
128 12 : state.dataDemandManager->DemandManagerList(ListNum).OverLimitDuration = 0.0;
129 : } // ListNum
130 :
131 : // Clear demand manager variables
132 84 : for (auto &e : state.dataDemandManager->DemandMgr) {
133 72 : e.Active = false;
134 72 : e.ElapsedTime = 0;
135 72 : e.ElapsedRotationTime = 0;
136 72 : e.RotatedLoadNum = 0;
137 : }
138 : }
139 6912 : state.dataDemandManager->ClearHistory = false;
140 : }
141 :
142 8064 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing) {
143 :
144 1152 : if (state.dataDemandManager->BeginDemandSim) {
145 12 : state.dataDemandManager->BeginDemandSim = false;
146 12 : state.dataDemandManager->ClearHistory = true;
147 : }
148 :
149 1152 : state.dataDemandManager->DemandManagerExtIterations = 0;
150 1152 : state.dataDemandManager->DemandManagerHBIterations = 0;
151 1152 : state.dataDemandManager->DemandManagerHVACIterations = 0;
152 :
153 1152 : state.dataDemandManager->firstTime = true;
154 1152 : state.dataDemandManager->ResimExt = false;
155 1152 : state.dataDemandManager->ResimHB = false;
156 1152 : state.dataDemandManager->ResimHVAC = false;
157 :
158 3791 : while (state.dataDemandManager->firstTime || state.dataDemandManager->ResimExt || state.dataDemandManager->ResimHB ||
159 1194 : state.dataDemandManager->ResimHVAC) {
160 1445 : state.dataDemandManager->firstTime = false;
161 :
162 1445 : Resimulate(state, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
163 1445 : state.dataDemandManager->ResimExt = false;
164 1445 : state.dataDemandManager->ResimHB = false;
165 1445 : state.dataDemandManager->ResimHVAC = false;
166 :
167 1445 : SurveyDemandManagers(state); // Determines which Demand Managers can reduce demand
168 :
169 2890 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
170 1445 : SimulateDemandManagerList(
171 1445 : state, ListNum, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
172 : } // ListNum
173 :
174 1445 : ActivateDemandManagers(state); // Sets limits on loads
175 :
176 1445 : if (state.dataDemandManager->DemandManagerExtIterations + state.dataDemandManager->DemandManagerHBIterations +
177 1445 : state.dataDemandManager->DemandManagerHVACIterations >
178 : 500) {
179 : // This error can only happen if there is a bug in the code
180 0 : ShowFatalError(state, "Too many DemandManager iterations. (>500)");
181 0 : break;
182 : }
183 : }
184 :
185 2304 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
186 1152 : ReportDemandManagerList(state, ListNum);
187 : } // ListNum
188 : }
189 : }
190 1989307 : }
191 :
192 1445 : void SimulateDemandManagerList(EnergyPlusData &state,
193 : int const ListNum,
194 : bool &ResimExt, // Flag to resimulate the exterior energy use simulation
195 : bool &ResimHB, // Flag to resimulate the heat balance simulation (including HVAC)
196 : bool &ResimHVAC // Flag to resimulate the HVAC simulation
197 : )
198 : {
199 :
200 : // SUBROUTINE INFORMATION:
201 : // AUTHOR Peter Graham Ellis
202 : // DATE WRITTEN July 2005
203 : // MODIFIED Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
204 :
205 : // Using/Aliasing
206 1445 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
207 :
208 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
209 : bool OnPeak;
210 :
211 1445 : auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
212 :
213 1445 : demandManagerList.ScheduledLimit = demandManagerList.limitSched->getCurrentVal();
214 1445 : demandManagerList.DemandLimit = demandManagerList.ScheduledLimit * demandManagerList.SafetyFraction;
215 :
216 1445 : demandManagerList.MeterDemand =
217 1445 : GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::Zone) / state.dataGlobal->TimeStepZoneSec +
218 1445 : GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::System) / TimeStepSysSec;
219 :
220 : // Calculate average demand over the averaging window including the current timestep meter demand
221 : Real64 AverageDemand =
222 1445 : demandManagerList.AverageDemand + (demandManagerList.MeterDemand - demandManagerList.History(1)) / demandManagerList.AveragingWindow;
223 :
224 1445 : OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
225 :
226 1445 : if (OnPeak) {
227 1445 : Real64 OverLimit = AverageDemand - demandManagerList.DemandLimit;
228 :
229 1445 : if (OverLimit > 0.0) {
230 :
231 329 : switch (demandManagerList.ManagerPriority) {
232 329 : case ManagePriorityType::Sequential: { // Activate first Demand Manager that can reduce demand
233 :
234 999 : for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
235 963 : auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
236 :
237 963 : if (demandMgr.CanReduceDemand) {
238 293 : demandMgr.Activate = true;
239 :
240 293 : switch (demandMgr.Type) {
241 55 : case ManagerType::ExtLights: {
242 55 : ResimExt = true;
243 55 : } break;
244 196 : case ManagerType::Lights:
245 : case ManagerType::ElecEquip: {
246 196 : ResimHB = true;
247 196 : ResimHVAC = true;
248 196 : } break;
249 42 : case ManagerType::Thermostats:
250 : case ManagerType::Ventilation: {
251 42 : ResimHVAC = true;
252 42 : } break;
253 0 : default:
254 0 : break;
255 : }
256 :
257 293 : break; // Leave the loop
258 : }
259 : } // MgrNum
260 :
261 329 : } break;
262 0 : case ManagePriorityType::Optimal: {
263 : // Not yet implemented
264 :
265 0 : } break;
266 0 : case ManagePriorityType::All: { // Activate ALL Demand Managers that can reduce demand
267 :
268 0 : for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
269 0 : auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
270 :
271 0 : if (demandMgr.CanReduceDemand) {
272 0 : demandMgr.Activate = true;
273 :
274 0 : switch (demandMgr.Type) {
275 0 : case ManagerType::ExtLights: {
276 0 : ResimExt = true;
277 0 : } break;
278 0 : case ManagerType::Lights:
279 : case ManagerType::ElecEquip: {
280 0 : ResimHB = true;
281 0 : ResimHVAC = true;
282 0 : } break;
283 0 : case ManagerType::Thermostats:
284 : case ManagerType::Ventilation: {
285 0 : ResimHVAC = true;
286 0 : } break;
287 0 : default:
288 0 : break;
289 : }
290 : }
291 : } // MgrNum
292 0 : } break;
293 0 : default:
294 0 : break;
295 : }
296 : }
297 : }
298 1445 : }
299 :
300 800 : void GetDemandManagerListInput(EnergyPlusData &state)
301 : {
302 :
303 : // SUBROUTINE INFORMATION:
304 : // AUTHOR Peter Graham Ellis
305 : // DATE WRITTEN July 2005
306 : // MODIFIED Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
307 :
308 : // PURPOSE OF THIS SUBROUTINE:
309 : // Gets the DEMAND MANAGER LIST input from the input file.
310 :
311 : // METHODOLOGY EMPLOYED:
312 : // Standard EnergyPlus methodology.
313 :
314 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
315 :
316 : static constexpr std::string_view routineName = "GetDemandManagerListInput";
317 800 : constexpr std::string_view cCurrentModuleObject = "DemandManagerAssignmentList";
318 :
319 800 : auto &s_ipsc = state.dataIPShortCut;
320 800 : auto const &s_ip = state.dataInputProcessing->inputProcessor;
321 :
322 800 : state.dataDemandManager->NumDemandManagerList = s_ip->getNumObjectsFound(state, cCurrentModuleObject);
323 :
324 800 : if (state.dataDemandManager->NumDemandManagerList > 0) {
325 : int NumAlphas; // Number of elements in the alpha array
326 : int NumNums; // Number of elements in the numeric array
327 : int IOStat; // IO Status when calling get input subroutine
328 6 : bool ErrorsFound = false;
329 :
330 6 : state.dataDemandManager->DemandManagerList.allocate(state.dataDemandManager->NumDemandManagerList);
331 :
332 12 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
333 :
334 6 : auto &thisDemandMgrList = state.dataDemandManager->DemandManagerList(ListNum);
335 :
336 18 : s_ip->getObjectItem(state,
337 : cCurrentModuleObject,
338 : ListNum,
339 6 : s_ipsc->cAlphaArgs,
340 : NumAlphas,
341 6 : s_ipsc->rNumericArgs,
342 : NumNums,
343 : IOStat,
344 : _,
345 6 : s_ipsc->lAlphaFieldBlanks,
346 6 : s_ipsc->cAlphaFieldNames,
347 6 : s_ipsc->cNumericFieldNames);
348 :
349 6 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
350 :
351 6 : thisDemandMgrList.Name = s_ipsc->cAlphaArgs(1);
352 :
353 6 : thisDemandMgrList.Meter = GetMeterIndex(state, s_ipsc->cAlphaArgs(2));
354 :
355 6 : if (thisDemandMgrList.Meter == -1) {
356 0 : ShowSevereError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
357 0 : ShowContinueError(state, format("Entered in {} = {}", cCurrentModuleObject, thisDemandMgrList.Name));
358 0 : ErrorsFound = true;
359 :
360 6 : } else if ((state.dataOutputProcessor->meters[thisDemandMgrList.Meter]->resource == Constant::eResource::Electricity) ||
361 0 : (state.dataOutputProcessor->meters[thisDemandMgrList.Meter]->resource == Constant::eResource::ElectricityNet)) {
362 : } else {
363 0 : ShowSevereError(state,
364 0 : format("{} = \"{}\" invalid value {} = \"{}\".",
365 : cCurrentModuleObject,
366 0 : thisDemandMgrList.Name,
367 0 : s_ipsc->cAlphaFieldNames(2),
368 0 : s_ipsc->cAlphaArgs(2)));
369 0 : ShowContinueError(state, "Only Electricity and ElectricityNet meters are currently allowed.");
370 0 : ErrorsFound = true;
371 : }
372 :
373 : // Further checking for conflicting DEMAND MANAGER LISTs
374 :
375 6 : if (s_ipsc->lAlphaFieldBlanks(3)) {
376 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
377 0 : ErrorsFound = true;
378 6 : } else if ((thisDemandMgrList.limitSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
379 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
380 0 : ErrorsFound = true;
381 : }
382 :
383 6 : thisDemandMgrList.SafetyFraction = s_ipsc->rNumericArgs(1);
384 :
385 6 : if (s_ipsc->lAlphaFieldBlanks(4)) {
386 0 : } else if ((thisDemandMgrList.billingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
387 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
388 0 : ErrorsFound = true;
389 : }
390 :
391 6 : if (s_ipsc->lAlphaFieldBlanks(5)) {
392 0 : } else if ((thisDemandMgrList.peakSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
393 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
394 0 : ErrorsFound = true;
395 : }
396 :
397 6 : thisDemandMgrList.AveragingWindow = max(int(s_ipsc->rNumericArgs(2) / state.dataGlobal->MinutesInTimeStep), 1);
398 : // Round to nearest timestep
399 : // Can make this fancier to include windows that do not fit the timesteps
400 6 : thisDemandMgrList.History.allocate(thisDemandMgrList.AveragingWindow);
401 6 : thisDemandMgrList.History = 0.0;
402 :
403 : // Validate Demand Manager Priority
404 6 : thisDemandMgrList.ManagerPriority =
405 6 : static_cast<ManagePriorityType>(getEnumValue(ManagePriorityNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(6))));
406 6 : ErrorsFound = ErrorsFound || (thisDemandMgrList.ManagerPriority == ManagePriorityType::Invalid);
407 :
408 : // Get DEMAND MANAGER Type and Name pairs
409 6 : thisDemandMgrList.NumOfManager = int((NumAlphas - 6) / 2.0);
410 :
411 6 : if (thisDemandMgrList.NumOfManager > 0) {
412 6 : thisDemandMgrList.Manager.allocate(thisDemandMgrList.NumOfManager);
413 42 : for (int MgrNum = 1; MgrNum <= thisDemandMgrList.NumOfManager; ++MgrNum) {
414 :
415 36 : auto &thisManager = thisDemandMgrList.Manager(MgrNum);
416 : // Validate DEMAND MANAGER Type
417 36 : ManagerType MgrType = static_cast<ManagerType>(getEnumValue(ManagerNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(MgrNum * 2 + 5))));
418 36 : if (MgrType != ManagerType::Invalid) {
419 36 : thisManager = Util::FindItemInList(s_ipsc->cAlphaArgs(MgrNum * 2 + 6), state.dataDemandManager->DemandMgr);
420 36 : if (thisManager == 0) {
421 0 : ShowSevereError(state,
422 0 : format("{} = \"{}\" invalid {} = \"{}\" not found.",
423 : cCurrentModuleObject,
424 0 : thisDemandMgrList.Name,
425 0 : s_ipsc->cAlphaFieldNames(MgrNum * 2 + 6),
426 0 : s_ipsc->cAlphaArgs(MgrNum * 2 + 6)));
427 0 : ErrorsFound = true;
428 : }
429 : } else {
430 0 : ShowSevereError(state,
431 0 : format("{} = \"{}\" invalid value {} = \"{}\".",
432 : cCurrentModuleObject,
433 0 : thisDemandMgrList.Name,
434 0 : s_ipsc->cAlphaFieldNames(MgrNum * 2 + 5),
435 0 : s_ipsc->cAlphaArgs(MgrNum * 2 + 5)));
436 0 : ErrorsFound = true;
437 : }
438 :
439 : // Check that each is not already referenced using %DemandManagerList field
440 :
441 : } // MgrNum
442 : }
443 :
444 : // Setup report variables
445 12 : SetupOutputVariable(state,
446 : "Demand Manager Meter Demand Power",
447 : Constant::Units::W,
448 6 : thisDemandMgrList.MeterDemand,
449 : OutputProcessor::TimeStepType::Zone,
450 : OutputProcessor::StoreType::Average,
451 6 : thisDemandMgrList.Name);
452 :
453 12 : SetupOutputVariable(state,
454 : "Demand Manager Average Demand Power",
455 : Constant::Units::W,
456 6 : thisDemandMgrList.AverageDemand,
457 : OutputProcessor::TimeStepType::Zone,
458 : OutputProcessor::StoreType::Average,
459 6 : thisDemandMgrList.Name);
460 :
461 12 : SetupOutputVariable(state,
462 : "Demand Manager Peak Demand Power",
463 : Constant::Units::W,
464 6 : thisDemandMgrList.PeakDemand,
465 : OutputProcessor::TimeStepType::Zone,
466 : OutputProcessor::StoreType::Average,
467 6 : thisDemandMgrList.Name);
468 :
469 12 : SetupOutputVariable(state,
470 : "Demand Manager Scheduled Limit Power",
471 : Constant::Units::W,
472 6 : thisDemandMgrList.ScheduledLimit,
473 : OutputProcessor::TimeStepType::Zone,
474 : OutputProcessor::StoreType::Average,
475 6 : thisDemandMgrList.Name);
476 :
477 12 : SetupOutputVariable(state,
478 : "Demand Manager Demand Limit Power",
479 : Constant::Units::W,
480 6 : thisDemandMgrList.DemandLimit,
481 : OutputProcessor::TimeStepType::Zone,
482 : OutputProcessor::StoreType::Average,
483 6 : thisDemandMgrList.Name);
484 :
485 12 : SetupOutputVariable(state,
486 : "Demand Manager Over Limit Power",
487 : Constant::Units::W,
488 6 : thisDemandMgrList.OverLimit,
489 : OutputProcessor::TimeStepType::Zone,
490 : OutputProcessor::StoreType::Average,
491 6 : thisDemandMgrList.Name);
492 :
493 12 : SetupOutputVariable(state,
494 : "Demand Manager Over Limit Time",
495 : Constant::Units::hr,
496 6 : thisDemandMgrList.OverLimitDuration,
497 : OutputProcessor::TimeStepType::Zone,
498 : OutputProcessor::StoreType::Sum,
499 6 : thisDemandMgrList.Name);
500 :
501 6 : if (ErrorsFound) {
502 0 : ShowFatalError(state, format("Errors found in processing input for {}.", cCurrentModuleObject));
503 : }
504 :
505 : } // ListNum
506 :
507 : // Iteration diagnostic reporting for all DEMAND MANAGER LISTs
508 18 : SetupOutputVariable(state,
509 : "Demand Manager Exterior Energy Iteration Count",
510 : Constant::Units::None,
511 6 : state.dataDemandManager->DemandManagerExtIterations,
512 : OutputProcessor::TimeStepType::Zone,
513 : OutputProcessor::StoreType::Sum,
514 : "ManageDemand");
515 :
516 18 : SetupOutputVariable(state,
517 : "Demand Manager Heat Balance Iteration Count",
518 : Constant::Units::None,
519 6 : state.dataDemandManager->DemandManagerHBIterations,
520 : OutputProcessor::TimeStepType::Zone,
521 : OutputProcessor::StoreType::Sum,
522 : "ManageDemand");
523 :
524 18 : SetupOutputVariable(state,
525 : "Demand Manager HVAC Iteration Count",
526 : Constant::Units::None,
527 6 : state.dataDemandManager->DemandManagerHVACIterations,
528 : OutputProcessor::TimeStepType::Zone,
529 : OutputProcessor::StoreType::Sum,
530 : "ManageDemand");
531 : }
532 800 : }
533 :
534 800 : void GetDemandManagerInput(EnergyPlusData &state)
535 : {
536 :
537 : // SUBROUTINE INFORMATION:
538 : // AUTHOR Peter Graham Ellis
539 : // DATE WRITTEN July 2005
540 : // MODIFIED MODIFIED Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
541 :
542 : // PURPOSE OF THIS SUBROUTINE:
543 : // Gets the DEMAND MANAGER input from the input file.
544 :
545 : static constexpr std::string_view routineName = "GetDemandManagerInput";
546 :
547 800 : auto &s_ipsc = state.dataIPShortCut;
548 800 : auto const &s_ip = state.dataInputProcessing->inputProcessor;
549 :
550 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
551 : int NumAlphas; // Number of elements in the alpha array
552 : int NumNums; // Number of elements in the numeric array
553 : int NumParams; // Number of arguments total in an ObjectDef
554 800 : Array1D_string AlphArray; // Character string data
555 800 : Array1D<Real64> NumArray; // Numeric data
556 800 : bool ErrorsFound(false);
557 :
558 800 : int MaxAlphas = 0;
559 800 : int MaxNums = 0;
560 800 : std::string CurrentModuleObject = "DemandManager:ExteriorLights";
561 800 : int NumDemandMgrExtLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
562 800 : if (NumDemandMgrExtLights > 0) {
563 5 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
564 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
565 5 : MaxNums = max(MaxNums, NumNums);
566 : }
567 800 : CurrentModuleObject = "DemandManager:Lights";
568 800 : int NumDemandMgrLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
569 800 : if (NumDemandMgrLights > 0) {
570 6 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
571 6 : MaxAlphas = max(MaxAlphas, NumAlphas);
572 6 : MaxNums = max(MaxNums, NumNums);
573 : }
574 800 : CurrentModuleObject = "DemandManager:ElectricEquipment";
575 800 : int NumDemandMgrElecEquip = s_ip->getNumObjectsFound(state, CurrentModuleObject);
576 800 : if (NumDemandMgrElecEquip > 0) {
577 5 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
578 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
579 5 : MaxNums = max(MaxNums, NumNums);
580 : }
581 800 : CurrentModuleObject = "DemandManager:Thermostats";
582 800 : int NumDemandMgrThermostats = s_ip->getNumObjectsFound(state, CurrentModuleObject);
583 800 : if (NumDemandMgrThermostats > 0) {
584 5 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
585 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
586 5 : MaxNums = max(MaxNums, NumNums);
587 : }
588 800 : CurrentModuleObject = "DemandManager:Ventilation";
589 800 : int NumDemandMgrVentilation = s_ip->getNumObjectsFound(state, CurrentModuleObject);
590 800 : if (NumDemandMgrVentilation > 0) {
591 5 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
592 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
593 5 : MaxNums = max(MaxNums, NumNums);
594 : }
595 :
596 1600 : state.dataDemandManager->NumDemandMgr =
597 800 : NumDemandMgrExtLights + NumDemandMgrLights + NumDemandMgrElecEquip + NumDemandMgrThermostats + NumDemandMgrVentilation;
598 :
599 800 : auto &DemandMgr(state.dataDemandManager->DemandMgr);
600 :
601 800 : if (state.dataDemandManager->NumDemandMgr > 0) {
602 6 : AlphArray.dimension(MaxAlphas, std::string());
603 6 : NumArray.dimension(MaxNums, 0.0);
604 : int IOStat; // IO Status when calling get input subroutine
605 :
606 6 : DemandMgr.allocate(state.dataDemandManager->NumDemandMgr);
607 6 : state.dataDemandManager->UniqueDemandMgrNames.reserve(state.dataDemandManager->NumDemandMgr);
608 :
609 : // Get input for DemandManager:ExteriorLights
610 6 : int StartIndex = 1;
611 6 : int EndIndex = NumDemandMgrExtLights;
612 :
613 6 : CurrentModuleObject = "DemandManager:ExteriorLights";
614 :
615 11 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
616 5 : auto &demandMgr = DemandMgr(MgrNum);
617 :
618 15 : s_ip->getObjectItem(state,
619 : CurrentModuleObject,
620 5 : MgrNum - StartIndex + 1,
621 : AlphArray,
622 : NumAlphas,
623 : NumArray,
624 : NumNums,
625 : IOStat,
626 : _,
627 5 : s_ipsc->lAlphaFieldBlanks,
628 5 : s_ipsc->cAlphaFieldNames,
629 5 : s_ipsc->cNumericFieldNames);
630 :
631 5 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
632 :
633 5 : GlobalNames::VerifyUniqueInterObjectName(
634 10 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
635 5 : demandMgr.Name = AlphArray(1);
636 :
637 5 : demandMgr.Type = ManagerType::ExtLights;
638 :
639 5 : if (s_ipsc->lAlphaFieldBlanks(2)) {
640 5 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
641 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
642 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
643 0 : ErrorsFound = true;
644 : }
645 :
646 : // Validate Limiting Control
647 5 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
648 5 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
649 :
650 5 : if (NumArray(1) == 0.0) {
651 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
652 : } else {
653 5 : demandMgr.LimitDuration = NumArray(1);
654 : }
655 :
656 5 : demandMgr.LowerLimit = NumArray(2);
657 :
658 : // Validate Selection Control
659 5 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
660 5 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
661 :
662 5 : if (NumArray(4) == 0.0) {
663 5 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
664 : } else {
665 0 : demandMgr.RotationDuration = NumArray(4);
666 : }
667 :
668 5 : demandMgr.NumOfLoads = NumAlphas - 4;
669 :
670 5 : if (demandMgr.NumOfLoads > 0) {
671 5 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
672 :
673 10 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
674 5 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataExteriorEnergyUse->ExteriorLights);
675 :
676 5 : if (LoadPtr > 0) {
677 5 : demandMgr.Load(LoadNum) = LoadPtr;
678 :
679 : } else {
680 0 : ShowSevereError(state,
681 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
682 : CurrentModuleObject,
683 0 : s_ipsc->cAlphaArgs(1),
684 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
685 : AlphArray(LoadNum + 4)));
686 0 : ErrorsFound = true;
687 : }
688 : } // LoadNum
689 : } else {
690 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
691 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
692 0 : ErrorsFound = true;
693 : }
694 :
695 : } // MgrNum
696 :
697 : // Get input for DemandManager:Lights
698 6 : StartIndex = EndIndex + 1;
699 6 : EndIndex += NumDemandMgrLights;
700 :
701 6 : CurrentModuleObject = "DemandManager:Lights";
702 :
703 12 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
704 6 : auto &demandMgr = DemandMgr(MgrNum);
705 :
706 18 : s_ip->getObjectItem(state,
707 : CurrentModuleObject,
708 6 : MgrNum - StartIndex + 1,
709 : AlphArray,
710 : NumAlphas,
711 : NumArray,
712 : NumNums,
713 : IOStat,
714 : _,
715 6 : s_ipsc->lAlphaFieldBlanks,
716 6 : s_ipsc->cAlphaFieldNames,
717 6 : s_ipsc->cNumericFieldNames);
718 :
719 6 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
720 6 : GlobalNames::VerifyUniqueInterObjectName(
721 12 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
722 6 : demandMgr.Name = AlphArray(1);
723 :
724 6 : demandMgr.Type = ManagerType::Lights;
725 :
726 6 : if (s_ipsc->lAlphaFieldBlanks(2)) {
727 6 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
728 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
729 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
730 0 : ErrorsFound = true;
731 : }
732 :
733 : // Validate Limiting Control
734 6 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
735 6 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
736 :
737 6 : if (NumArray(1) == 0.0) {
738 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
739 : } else {
740 6 : demandMgr.LimitDuration = NumArray(1);
741 : }
742 :
743 6 : demandMgr.LowerLimit = NumArray(2);
744 :
745 : // Validate Selection Control
746 6 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
747 6 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
748 :
749 6 : if (NumArray(4) == 0.0) {
750 6 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
751 : } else {
752 0 : demandMgr.RotationDuration = NumArray(4);
753 : }
754 :
755 : // Count actual pointers to controlled zones
756 6 : demandMgr.NumOfLoads = 0;
757 12 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
758 6 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->lightsObjects);
759 6 : if (LoadPtr > 0) {
760 6 : demandMgr.NumOfLoads += state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces;
761 : } else {
762 0 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->Lights);
763 0 : if (LoadPtr > 0) {
764 0 : ++demandMgr.NumOfLoads;
765 : } else {
766 0 : ShowSevereError(state,
767 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
768 : CurrentModuleObject,
769 0 : s_ipsc->cAlphaArgs(1),
770 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
771 : AlphArray(LoadNum + 4)));
772 0 : ErrorsFound = true;
773 : }
774 : }
775 : }
776 :
777 : // demandMgr%NumOfLoads = NumAlphas - 4
778 :
779 6 : if (demandMgr.NumOfLoads > 0) {
780 6 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
781 6 : int LoadNum = 0;
782 12 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
783 6 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->lightsObjects);
784 6 : if (LoadPtr > 0) {
785 36 : for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces; ++Item1) {
786 30 : ++LoadNum;
787 30 : demandMgr.Load(LoadNum) = state.dataInternalHeatGains->lightsObjects(LoadPtr).spaceStartPtr + Item1 - 1;
788 : }
789 : } else {
790 0 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->Lights);
791 0 : if (LoadPtr > 0) {
792 0 : ++LoadNum;
793 0 : demandMgr.Load(LoadNum) = LoadPtr;
794 : }
795 : }
796 : } // LoadNum
797 : } else {
798 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
799 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
800 0 : ErrorsFound = true;
801 : }
802 :
803 : } // MgrNum
804 :
805 : // Get input for DemandManager:ElectricEquipment
806 6 : StartIndex = EndIndex + 1;
807 6 : EndIndex += NumDemandMgrElecEquip;
808 :
809 6 : CurrentModuleObject = "DemandManager:ElectricEquipment";
810 :
811 21 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
812 15 : auto &demandMgr = DemandMgr(MgrNum);
813 :
814 45 : s_ip->getObjectItem(state,
815 : CurrentModuleObject,
816 15 : MgrNum - StartIndex + 1,
817 : AlphArray,
818 : NumAlphas,
819 : NumArray,
820 : NumNums,
821 : IOStat,
822 : _,
823 15 : s_ipsc->lAlphaFieldBlanks,
824 15 : s_ipsc->cAlphaFieldNames,
825 15 : s_ipsc->cNumericFieldNames);
826 :
827 15 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
828 15 : GlobalNames::VerifyUniqueInterObjectName(
829 30 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
830 :
831 15 : demandMgr.Name = AlphArray(1);
832 :
833 15 : demandMgr.Type = ManagerType::ElecEquip;
834 :
835 15 : if (s_ipsc->lAlphaFieldBlanks(2)) {
836 15 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
837 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
838 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
839 0 : ErrorsFound = true;
840 : }
841 :
842 : // Validate Limiting Control
843 15 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
844 15 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
845 :
846 15 : if (NumArray(1) == 0.0) {
847 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
848 : } else {
849 15 : demandMgr.LimitDuration = NumArray(1);
850 : }
851 :
852 15 : demandMgr.LowerLimit = NumArray(2);
853 :
854 : // Validate Selection Control
855 15 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
856 15 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
857 :
858 15 : if (NumArray(4) == 0.0) {
859 15 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
860 : } else {
861 0 : demandMgr.RotationDuration = NumArray(4);
862 : }
863 :
864 : // Count actual pointers to controlled zones
865 15 : demandMgr.NumOfLoads = 0;
866 30 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
867 15 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->zoneElectricObjects);
868 15 : if (LoadPtr > 0) {
869 0 : demandMgr.NumOfLoads += state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces;
870 : } else {
871 15 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->ZoneElectric);
872 15 : if (LoadPtr > 0) {
873 15 : ++demandMgr.NumOfLoads;
874 : } else {
875 0 : ShowSevereError(state,
876 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
877 : CurrentModuleObject,
878 0 : s_ipsc->cAlphaArgs(1),
879 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
880 : AlphArray(LoadNum + 4)));
881 0 : ErrorsFound = true;
882 : }
883 : }
884 : }
885 :
886 : // demandMgr%NumOfLoads = NumAlphas - 4
887 :
888 15 : if (demandMgr.NumOfLoads > 0) {
889 15 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
890 15 : int LoadNum = 0;
891 30 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
892 15 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->zoneElectricObjects);
893 15 : if (LoadPtr > 0) {
894 0 : for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces; ++Item1) {
895 0 : ++LoadNum;
896 0 : demandMgr.Load(LoadNum) = state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).spaceStartPtr + Item1 - 1;
897 : }
898 : } else {
899 15 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->ZoneElectric);
900 15 : if (LoadPtr > 0) {
901 15 : ++LoadNum;
902 15 : demandMgr.Load(LoadNum) = LoadPtr;
903 : }
904 : }
905 : } // LoadNum
906 : } else {
907 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
908 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
909 0 : ErrorsFound = true;
910 : }
911 :
912 : } // MgrNum
913 :
914 : // Get input for DemandManager:Thermostats
915 6 : StartIndex = EndIndex + 1;
916 6 : EndIndex += NumDemandMgrThermostats;
917 :
918 6 : CurrentModuleObject = "DemandManager:Thermostats";
919 :
920 11 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
921 5 : auto &demandMgr = DemandMgr(MgrNum);
922 :
923 15 : s_ip->getObjectItem(state,
924 : CurrentModuleObject,
925 5 : MgrNum - StartIndex + 1,
926 : AlphArray,
927 : NumAlphas,
928 : NumArray,
929 : NumNums,
930 : IOStat,
931 : _,
932 5 : s_ipsc->lAlphaFieldBlanks,
933 5 : s_ipsc->cAlphaFieldNames,
934 5 : s_ipsc->cNumericFieldNames);
935 :
936 5 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
937 :
938 5 : GlobalNames::VerifyUniqueInterObjectName(
939 10 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
940 5 : demandMgr.Name = AlphArray(1);
941 :
942 5 : demandMgr.Type = ManagerType::Thermostats;
943 :
944 5 : if (s_ipsc->lAlphaFieldBlanks(2)) {
945 5 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
946 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
947 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
948 0 : ErrorsFound = true;
949 : }
950 :
951 : // Validate Limiting Control
952 5 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
953 5 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
954 :
955 5 : if (NumArray(1) == 0.0) {
956 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
957 : } else {
958 5 : demandMgr.LimitDuration = NumArray(1);
959 : }
960 :
961 5 : demandMgr.LowerLimit = NumArray(2);
962 5 : demandMgr.UpperLimit = NumArray(3);
963 :
964 5 : if (demandMgr.LowerLimit > demandMgr.UpperLimit) {
965 0 : ShowSevereError(state, format("Invalid input for {} = {}", CurrentModuleObject, AlphArray(1)));
966 0 : ShowContinueError(
967 : state,
968 0 : format("{} [{:.2R}] > {} [{:.2R}]", s_ipsc->cNumericFieldNames(2), NumArray(2), s_ipsc->cNumericFieldNames(3), NumArray(3)));
969 0 : ShowContinueError(state, format("{} cannot be greater than {}", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3)));
970 0 : ErrorsFound = true;
971 : }
972 :
973 : // Validate Selection Control
974 5 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
975 5 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
976 :
977 5 : if (NumArray(5) == 0.0) {
978 5 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
979 : } else {
980 0 : demandMgr.RotationDuration = NumArray(5);
981 : }
982 :
983 : // Count actual pointers to controlled zones
984 5 : demandMgr.NumOfLoads = 0;
985 10 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
986 5 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TStatObjects);
987 5 : if (LoadPtr > 0) {
988 5 : demandMgr.NumOfLoads += state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones;
989 : } else {
990 0 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TempControlledZone);
991 0 : if (LoadPtr > 0) {
992 0 : ++demandMgr.NumOfLoads;
993 : } else {
994 0 : ShowSevereError(state,
995 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
996 : CurrentModuleObject,
997 0 : s_ipsc->cAlphaArgs(1),
998 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
999 : AlphArray(LoadNum + 4)));
1000 0 : ErrorsFound = true;
1001 : }
1002 : }
1003 : }
1004 :
1005 5 : if (demandMgr.NumOfLoads > 0) {
1006 5 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
1007 5 : int LoadNum = 0;
1008 10 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
1009 5 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TStatObjects);
1010 5 : if (LoadPtr > 0) {
1011 30 : for (int Item1 = 1; Item1 <= state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones; ++Item1) {
1012 25 : ++LoadNum;
1013 25 : demandMgr.Load(LoadNum) = state.dataZoneCtrls->TStatObjects(LoadPtr).TempControlledZoneStartPtr + Item1 - 1;
1014 : }
1015 : } else {
1016 0 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TempControlledZone);
1017 0 : if (LoadPtr > 0) {
1018 0 : ++LoadNum;
1019 0 : demandMgr.Load(LoadNum) = LoadPtr;
1020 : }
1021 : }
1022 : } // LoadNum
1023 : } else {
1024 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1025 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
1026 0 : ErrorsFound = true;
1027 : }
1028 : } // MgrNum
1029 :
1030 : // Get input for DemandManager:Ventilation
1031 6 : StartIndex = EndIndex + 1;
1032 6 : EndIndex += NumDemandMgrVentilation;
1033 :
1034 6 : CurrentModuleObject = "DemandManager:Ventilation";
1035 :
1036 11 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
1037 5 : auto &demandMgr = DemandMgr(MgrNum);
1038 :
1039 15 : s_ip->getObjectItem(state,
1040 : CurrentModuleObject,
1041 5 : MgrNum - StartIndex + 1,
1042 : AlphArray,
1043 : NumAlphas,
1044 : NumArray,
1045 : NumNums,
1046 : IOStat,
1047 : _,
1048 5 : s_ipsc->lAlphaFieldBlanks,
1049 5 : s_ipsc->cAlphaFieldNames,
1050 5 : s_ipsc->cNumericFieldNames);
1051 :
1052 5 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
1053 5 : GlobalNames::VerifyUniqueInterObjectName(
1054 10 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
1055 5 : demandMgr.Name = AlphArray(1);
1056 :
1057 5 : demandMgr.Type = ManagerType::Ventilation;
1058 :
1059 5 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1060 5 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
1061 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
1062 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
1063 0 : ErrorsFound = true;
1064 : }
1065 :
1066 : // Validate Limiting Control
1067 5 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitVentNamesUC, Util::makeUPPER(AlphArray(3))));
1068 5 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
1069 :
1070 5 : demandMgr.LimitDuration = (NumArray(1) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(1);
1071 :
1072 5 : if (demandMgr.LimitControl == ManagerLimit::Fixed) {
1073 2 : demandMgr.FixedRate = NumArray(2);
1074 : }
1075 5 : if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
1076 3 : demandMgr.ReductionRatio = NumArray(3);
1077 : }
1078 :
1079 5 : demandMgr.LowerLimit = NumArray(4);
1080 :
1081 : // Validate Selection Control
1082 5 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
1083 5 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
1084 :
1085 5 : demandMgr.RotationDuration = (NumArray(5) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(5);
1086 :
1087 : // Count number of string fields for loading Controller:OutdoorAir names. This number must be increased in case if
1088 : // new string field is added or decreased if string fields are removed.
1089 5 : int AlphaShift = 4;
1090 :
1091 : // Count actual pointers to air controllers
1092 5 : demandMgr.NumOfLoads = 0;
1093 10 : for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
1094 5 : int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
1095 5 : if (LoadPtr > 0) {
1096 5 : ++demandMgr.NumOfLoads;
1097 : } else {
1098 0 : ShowSevereError(state,
1099 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1100 : CurrentModuleObject,
1101 0 : s_ipsc->cAlphaArgs(1),
1102 0 : s_ipsc->cAlphaFieldNames(LoadNum + AlphaShift),
1103 : AlphArray(LoadNum + AlphaShift)));
1104 0 : ErrorsFound = true;
1105 : }
1106 : }
1107 :
1108 5 : if (demandMgr.NumOfLoads > 0) {
1109 5 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
1110 10 : for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
1111 5 : int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
1112 5 : if (LoadPtr > 0) {
1113 5 : demandMgr.Load(LoadNum) = LoadPtr;
1114 : }
1115 : }
1116 : } else {
1117 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1118 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
1119 0 : ErrorsFound = true;
1120 : }
1121 : } // MgrNum
1122 :
1123 6 : AlphArray.deallocate();
1124 6 : NumArray.deallocate();
1125 : }
1126 :
1127 800 : if (ErrorsFound) {
1128 0 : ShowFatalError(state, "Errors found in processing input for demand managers. Preceding condition causes termination.");
1129 : }
1130 800 : }
1131 :
1132 1445 : void SurveyDemandManagers(EnergyPlusData &state)
1133 : {
1134 :
1135 : // SUBROUTINE INFORMATION:
1136 : // AUTHOR Peter Graham Ellis
1137 : // DATE WRITTEN July 2005
1138 :
1139 : // PURPOSE OF THIS SUBROUTINE:
1140 : // Checks to see if any demand managers can reduce the load
1141 :
1142 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1143 : bool CanReduceDemand;
1144 :
1145 10260 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1146 :
1147 8815 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1148 :
1149 8815 : demandMgr.CanReduceDemand = false;
1150 :
1151 8815 : if (!demandMgr.Available) {
1152 0 : continue;
1153 : }
1154 8815 : if (demandMgr.LimitControl == ManagerLimit::Off) {
1155 0 : continue;
1156 : }
1157 :
1158 8815 : if (demandMgr.Active) {
1159 1788 : continue; // This works for FIXED control action, but not VARIABLE
1160 : }
1161 : // VARIABLE control could actually reduce demand farther, even if active already
1162 :
1163 11467 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1164 10579 : int LoadPtr = demandMgr.Load(LoadNum);
1165 :
1166 : // Check if this load can reduce demand
1167 : // Assume FIXED control action for now, needs more sophisticated check for VARIABLE control
1168 10579 : LoadInterface(state, DemandAction::CheckCanReduce, MgrNum, LoadPtr, CanReduceDemand);
1169 :
1170 10579 : if (CanReduceDemand) {
1171 6139 : demandMgr.CanReduceDemand = true;
1172 6139 : break; // If any one load can reduce demand, then the whole demand manager can reduce demand
1173 : }
1174 :
1175 : } // LoadNum
1176 :
1177 : } // MgrNum
1178 1445 : }
1179 :
1180 1445 : void ActivateDemandManagers(EnergyPlusData &state)
1181 : {
1182 :
1183 : // SUBROUTINE INFORMATION:
1184 : // AUTHOR Peter Graham Ellis
1185 : // DATE WRITTEN July 2005
1186 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1187 : int LoadPtr;
1188 :
1189 10260 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1190 :
1191 8815 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1192 :
1193 8815 : if (demandMgr.Activate) {
1194 : bool CanReduceDemand;
1195 293 : demandMgr.Activate = false;
1196 293 : demandMgr.Active = true;
1197 :
1198 293 : switch (demandMgr.SelectionControl) {
1199 293 : case ManagerSelection::All: {
1200 : // Turn ON limiting on all loads
1201 790 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1202 497 : LoadPtr = demandMgr.Load(LoadNum);
1203 497 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1204 : } // LoadNum
1205 :
1206 293 : } break;
1207 0 : case ManagerSelection::Many: { // All loads are limited except for one
1208 0 : if (demandMgr.NumOfLoads > 1) {
1209 :
1210 : // Turn ON limiting on all loads
1211 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1212 0 : LoadPtr = demandMgr.Load(LoadNum);
1213 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1214 : } // LoadNum
1215 :
1216 : // Set next rotated load (from last time it was active)
1217 0 : int RotatedLoadNum = demandMgr.RotatedLoadNum;
1218 0 : ++RotatedLoadNum;
1219 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) {
1220 0 : RotatedLoadNum = 1;
1221 : }
1222 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1223 :
1224 : // Turn OFF limiting for the new rotated load
1225 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1226 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1227 : } else {
1228 : // Turn ON limiting for the one and only load
1229 0 : LoadPtr = demandMgr.Load(1);
1230 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1231 : }
1232 :
1233 0 : } break;
1234 0 : case ManagerSelection::One: { // Only one load is limited
1235 0 : if (demandMgr.NumOfLoads > 1) {
1236 : // Turn OFF limiting on all loads
1237 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1238 0 : LoadPtr = demandMgr.Load(LoadNum);
1239 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1240 : } // LoadNum
1241 :
1242 : // Set next rotated load (from last time it was active)
1243 0 : int RotatedLoadNum = demandMgr.RotatedLoadNum;
1244 0 : ++RotatedLoadNum;
1245 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) {
1246 0 : RotatedLoadNum = 1;
1247 : }
1248 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1249 :
1250 : // Turn ON limiting for the new rotated load
1251 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1252 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1253 : } else {
1254 : // Turn ON limiting for the one and only load
1255 0 : LoadPtr = demandMgr.Load(1);
1256 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1257 : }
1258 0 : } break;
1259 0 : default:
1260 0 : break;
1261 : }
1262 : }
1263 :
1264 : } // MgrNum
1265 1445 : }
1266 :
1267 2828212 : void UpdateDemandManagers(EnergyPlusData &state)
1268 : {
1269 :
1270 : // SUBROUTINE INFORMATION:
1271 : // AUTHOR Peter Graham Ellis
1272 : // DATE WRITTEN July 2005
1273 :
1274 : // PURPOSE OF THIS SUBROUTINE:
1275 : // Expires limits and rotates loads after specified time duration.
1276 : // It updates availability flags, expires managers that ended in the last timestep, etc.
1277 :
1278 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1279 : int LoadPtr;
1280 : bool CanReduceDemand;
1281 : int RotatedLoadNum;
1282 :
1283 2876596 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1284 :
1285 48384 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1286 :
1287 : // Check availability
1288 48384 : bool Available = demandMgr.availSched->getCurrentVal() > 0.0;
1289 :
1290 48384 : demandMgr.Available = Available;
1291 :
1292 : // Update demand manager status
1293 48384 : if (Available) {
1294 :
1295 48384 : if (demandMgr.Active) {
1296 :
1297 1172 : demandMgr.ElapsedTime += state.dataGlobal->MinutesInTimeStep;
1298 :
1299 : // Check for expiring limit duration
1300 1172 : if (demandMgr.ElapsedTime >= demandMgr.LimitDuration) {
1301 293 : demandMgr.ElapsedTime = 0;
1302 293 : demandMgr.ElapsedRotationTime = 0;
1303 293 : demandMgr.Active = false;
1304 :
1305 : // Demand Manager is not available, remove demand limits from all loads
1306 790 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1307 497 : LoadPtr = demandMgr.Load(LoadNum);
1308 497 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1309 : } // LoadNum
1310 :
1311 : } else {
1312 :
1313 879 : switch (demandMgr.SelectionControl) {
1314 879 : case ManagerSelection::All: {
1315 : // Do nothing; limits remain on all loads
1316 :
1317 879 : } break;
1318 0 : case ManagerSelection::Many: { // All loads are limited except for one
1319 0 : demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
1320 :
1321 0 : if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
1322 0 : demandMgr.ElapsedRotationTime = 0;
1323 :
1324 0 : if (demandMgr.NumOfLoads > 1) {
1325 : // Turn ON limiting for the old rotated load
1326 0 : RotatedLoadNum = demandMgr.RotatedLoadNum;
1327 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1328 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1329 :
1330 : // Set next rotated load
1331 0 : ++RotatedLoadNum;
1332 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) {
1333 0 : RotatedLoadNum = 1;
1334 : }
1335 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1336 :
1337 : // Turn OFF limiting for the new rotated load
1338 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1339 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1340 : }
1341 : }
1342 :
1343 0 : } break;
1344 0 : case ManagerSelection::One: { // Only one load is limited
1345 0 : demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
1346 :
1347 0 : if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
1348 0 : demandMgr.ElapsedRotationTime = 0;
1349 :
1350 0 : if (demandMgr.NumOfLoads > 1) {
1351 : // Turn OFF limiting for the old rotated load
1352 0 : RotatedLoadNum = demandMgr.RotatedLoadNum;
1353 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1354 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1355 :
1356 : // Set next rotated load
1357 0 : ++RotatedLoadNum;
1358 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) {
1359 0 : RotatedLoadNum = 1;
1360 : }
1361 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1362 :
1363 : // Turn ON limiting for the new rotated load
1364 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1365 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1366 : }
1367 : }
1368 0 : } break;
1369 0 : default:
1370 0 : break;
1371 : }
1372 : }
1373 : }
1374 :
1375 : } else { // Demand Manager is not available
1376 0 : demandMgr.Active = false;
1377 :
1378 : // Demand Manager is not available, remove demand limits from all loads
1379 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1380 0 : LoadPtr = demandMgr.Load(LoadNum);
1381 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1382 : } // LoadNum
1383 : }
1384 :
1385 : } // MgrNum
1386 2828212 : }
1387 :
1388 1152 : void ReportDemandManagerList(EnergyPlusData &state, int const ListNum)
1389 : {
1390 :
1391 : // SUBROUTINE INFORMATION:
1392 : // AUTHOR Peter Graham Ellis
1393 : // DATE WRITTEN July 2005
1394 :
1395 : // PURPOSE OF THIS SUBROUTINE:
1396 : // Calculates report variables.
1397 :
1398 : // METHODOLOGY EMPLOYED:
1399 : // Standard EnergyPlus methodology.
1400 :
1401 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1402 : int AveragingWindow;
1403 : bool OnPeak;
1404 : Real64 OverLimit;
1405 :
1406 1152 : auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
1407 :
1408 1152 : Real64 BillingPeriod = (demandManagerList.billingSched == nullptr) ? state.dataEnvrn->Month : demandManagerList.billingSched->getCurrentVal();
1409 :
1410 1152 : if (demandManagerList.BillingPeriod != BillingPeriod) {
1411 : // Reset variables for new billing period
1412 : // demandManagerList%History = 0.0 ! Don't reset--continue from previous billing period
1413 : // demandManagerList%AverageDemand = 0.0 ! Don't reset--continue from previous billing period
1414 12 : demandManagerList.PeakDemand = 0.0;
1415 12 : demandManagerList.OverLimitDuration = 0.0;
1416 :
1417 12 : demandManagerList.BillingPeriod = BillingPeriod;
1418 : }
1419 :
1420 : // Add new timestep to demand history and subtract oldest timestep
1421 1152 : AveragingWindow = demandManagerList.AveragingWindow;
1422 1152 : demandManagerList.AverageDemand += (demandManagerList.MeterDemand - demandManagerList.History(1)) / AveragingWindow;
1423 :
1424 : // Update demand history
1425 1152 : for (int Item = 1; Item <= AveragingWindow - 1; ++Item) {
1426 0 : demandManagerList.History(Item) = demandManagerList.History(Item + 1);
1427 : }
1428 1152 : demandManagerList.History(AveragingWindow) = demandManagerList.MeterDemand;
1429 :
1430 1152 : OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
1431 :
1432 1152 : if (OnPeak) {
1433 1152 : demandManagerList.PeakDemand = max(demandManagerList.AverageDemand, demandManagerList.PeakDemand);
1434 :
1435 1152 : OverLimit = demandManagerList.AverageDemand - demandManagerList.ScheduledLimit;
1436 1152 : if (OverLimit > 0.0) {
1437 36 : demandManagerList.OverLimit = OverLimit;
1438 36 : demandManagerList.OverLimitDuration += (state.dataGlobal->MinutesInTimeStep / 60.0);
1439 : } else {
1440 1116 : demandManagerList.OverLimit = 0.0;
1441 : }
1442 :
1443 : } else {
1444 0 : demandManagerList.OverLimit = 0.0;
1445 : }
1446 1152 : }
1447 :
1448 11573 : void LoadInterface(EnergyPlusData &state, DemandAction const Action, int const MgrNum, int const LoadPtr, bool &CanReduceDemand)
1449 : {
1450 :
1451 : // SUBROUTINE INFORMATION:
1452 : // AUTHOR Peter Graham Ellis
1453 : // DATE WRITTEN August 2005
1454 :
1455 : // PURPOSE OF THIS SUBROUTINE:
1456 : // Provides a universal interface to handle all communication with the various load objects.
1457 : // Demand managers for new types of loads can be easily added with a new CASE statement in this subroutine
1458 : // and new GetInput code.
1459 :
1460 11573 : auto const &s_dhbf = state.dataHeatBalFanSys;
1461 11573 : auto const &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1462 :
1463 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1464 : Real64 LowestPower;
1465 :
1466 11573 : CanReduceDemand = false;
1467 :
1468 11573 : switch (demandMgr.Type) {
1469 938 : case ManagerType::ExtLights: {
1470 938 : LowestPower = state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1471 938 : if (Action == DemandAction::CheckCanReduce) {
1472 828 : if (state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).Power > LowestPower) {
1473 828 : CanReduceDemand = true;
1474 : }
1475 110 : } else if (Action == DemandAction::SetLimit) {
1476 55 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = true;
1477 55 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DemandLimit = LowestPower;
1478 55 : } else if (Action == DemandAction::ClearLimit) {
1479 55 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = false;
1480 : }
1481 938 : } break;
1482 :
1483 5294 : case ManagerType::Lights: {
1484 5294 : LowestPower = state.dataHeatBal->Lights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1485 5294 : if (Action == DemandAction::CheckCanReduce) {
1486 4784 : if (state.dataHeatBal->Lights(LoadPtr).Power > LowestPower) {
1487 344 : CanReduceDemand = true;
1488 : }
1489 510 : } else if (Action == DemandAction::SetLimit) {
1490 255 : state.dataHeatBal->Lights(LoadPtr).ManageDemand = true;
1491 255 : state.dataHeatBal->Lights(LoadPtr).DemandLimit = LowestPower;
1492 255 : } else if (Action == DemandAction::ClearLimit) {
1493 255 : state.dataHeatBal->Lights(LoadPtr).ManageDemand = false;
1494 : }
1495 5294 : } break;
1496 :
1497 3131 : case ManagerType::ElecEquip: {
1498 3131 : LowestPower = state.dataHeatBal->ZoneElectric(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1499 3131 : if (Action == DemandAction::CheckCanReduce) {
1500 2841 : if (state.dataHeatBal->ZoneElectric(LoadPtr).Power > LowestPower) {
1501 2841 : CanReduceDemand = true;
1502 : }
1503 290 : } else if (Action == DemandAction::SetLimit) {
1504 145 : state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = true;
1505 145 : state.dataHeatBal->ZoneElectric(LoadPtr).DemandLimit = LowestPower;
1506 145 : } else if (Action == DemandAction::ClearLimit) {
1507 145 : state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = false;
1508 : }
1509 3131 : } break;
1510 :
1511 1233 : case ManagerType::Thermostats: {
1512 1233 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(LoadPtr);
1513 1233 : auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(tempZone.ActualZoneNum);
1514 1233 : if (Action == DemandAction::CheckCanReduce) {
1515 1233 : if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit) {
1516 1233 : CanReduceDemand = true; // Heating | Cooling
1517 : }
1518 0 : } else if (Action == DemandAction::SetLimit) {
1519 0 : tempZone.ManageDemand = true;
1520 0 : tempZone.HeatingResetLimit = demandMgr.LowerLimit;
1521 0 : tempZone.CoolingResetLimit = demandMgr.UpperLimit;
1522 0 : } else if (Action == DemandAction::ClearLimit) {
1523 0 : tempZone.ManageDemand = false;
1524 : }
1525 1233 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
1526 0 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(LoadPtr);
1527 0 : if (state.dataHeatBalFanSys->ComfortControlType(comfortZone.ActualZoneNum) != HVAC::SetptType::Uncontrolled) {
1528 0 : auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(comfortZone.ActualZoneNum);
1529 0 : if (Action == DemandAction::CheckCanReduce) {
1530 0 : if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit) {
1531 0 : CanReduceDemand = true; // Heating
1532 : }
1533 0 : } else if (Action == DemandAction::SetLimit) {
1534 0 : comfortZone.ManageDemand = true;
1535 0 : comfortZone.HeatingResetLimit = demandMgr.LowerLimit;
1536 0 : comfortZone.CoolingResetLimit = demandMgr.UpperLimit;
1537 0 : } else if (Action == DemandAction::ClearLimit) {
1538 0 : comfortZone.ManageDemand = false;
1539 : }
1540 : }
1541 : }
1542 1233 : } break;
1543 :
1544 977 : case ManagerType::Ventilation: {
1545 977 : Real64 FlowRate(0);
1546 977 : FlowRate = MixedAir::OAGetFlowRate(state, LoadPtr);
1547 977 : if (Action == DemandAction::CheckCanReduce) {
1548 893 : CanReduceDemand = true;
1549 84 : } else if (Action == DemandAction::SetLimit) {
1550 42 : MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, true);
1551 42 : if (demandMgr.LimitControl == ManagerLimit::Fixed) {
1552 22 : MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, demandMgr.FixedRate);
1553 20 : } else if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
1554 20 : Real64 DemandRate(0);
1555 20 : DemandRate = FlowRate * demandMgr.ReductionRatio;
1556 20 : MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, DemandRate);
1557 : }
1558 42 : } else if (Action == DemandAction::ClearLimit) {
1559 42 : MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, false);
1560 : }
1561 977 : } break;
1562 0 : default:
1563 0 : break;
1564 : }
1565 11573 : }
1566 :
1567 800 : void InitDemandManagers(EnergyPlusData &state)
1568 : {
1569 :
1570 : // SUBROUTINE INFORMATION:
1571 : // AUTHOR Linda Lawrie
1572 : // DATE WRITTEN September 2010
1573 :
1574 : // PURPOSE OF THIS SUBROUTINE:
1575 : // Provide external call to get Demand manager input after
1576 : // appropriate initializations.
1577 :
1578 800 : if (state.dataDemandManager->GetInput) {
1579 800 : GetDemandManagerInput(state);
1580 800 : GetDemandManagerListInput(state);
1581 800 : state.dataDemandManager->GetInput = false;
1582 : }
1583 800 : }
1584 :
1585 : } // namespace EnergyPlus::DemandManager
|