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