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 164434 : 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 164434 : if (state.dataDemandManager->GetInput && !state.dataGlobal->DoingSizing) {
108 0 : GetDemandManagerInput(state);
109 0 : GetDemandManagerListInput(state);
110 0 : state.dataDemandManager->GetInput = false;
111 : }
112 :
113 164434 : if (state.dataDemandManager->NumDemandManagerList > 0) {
114 :
115 0 : if (state.dataGlobal->WarmupFlag) {
116 0 : state.dataDemandManager->BeginDemandSim = true;
117 0 : if (state.dataDemandManager->ClearHistory) {
118 : // Clear historical variables
119 0 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
120 0 : state.dataDemandManager->DemandManagerList(ListNum).History = 0.0;
121 0 : state.dataDemandManager->DemandManagerList(ListNum).MeterDemand = 0.0;
122 0 : state.dataDemandManager->DemandManagerList(ListNum).AverageDemand = 0.0;
123 0 : state.dataDemandManager->DemandManagerList(ListNum).PeakDemand = 0.0;
124 0 : state.dataDemandManager->DemandManagerList(ListNum).ScheduledLimit = 0.0;
125 0 : state.dataDemandManager->DemandManagerList(ListNum).DemandLimit = 0.0;
126 0 : state.dataDemandManager->DemandManagerList(ListNum).AvoidedDemand = 0.0;
127 0 : state.dataDemandManager->DemandManagerList(ListNum).OverLimit = 0.0;
128 0 : state.dataDemandManager->DemandManagerList(ListNum).OverLimitDuration = 0.0;
129 : } // ListNum
130 :
131 : // Clear demand manager variables
132 0 : for (auto &e : state.dataDemandManager->DemandMgr) {
133 0 : e.Active = false;
134 0 : e.ElapsedTime = 0;
135 0 : e.ElapsedRotationTime = 0;
136 0 : e.RotatedLoadNum = 0;
137 : }
138 : }
139 0 : state.dataDemandManager->ClearHistory = false;
140 : }
141 :
142 0 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing) {
143 :
144 0 : if (state.dataDemandManager->BeginDemandSim) {
145 0 : state.dataDemandManager->BeginDemandSim = false;
146 0 : state.dataDemandManager->ClearHistory = true;
147 : }
148 :
149 0 : state.dataDemandManager->DemandManagerExtIterations = 0;
150 0 : state.dataDemandManager->DemandManagerHBIterations = 0;
151 0 : state.dataDemandManager->DemandManagerHVACIterations = 0;
152 :
153 0 : state.dataDemandManager->firstTime = true;
154 0 : state.dataDemandManager->ResimExt = false;
155 0 : state.dataDemandManager->ResimHB = false;
156 0 : state.dataDemandManager->ResimHVAC = false;
157 :
158 0 : while (state.dataDemandManager->firstTime || state.dataDemandManager->ResimExt || state.dataDemandManager->ResimHB ||
159 0 : state.dataDemandManager->ResimHVAC) {
160 0 : state.dataDemandManager->firstTime = false;
161 :
162 0 : Resimulate(state, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
163 0 : state.dataDemandManager->ResimExt = false;
164 0 : state.dataDemandManager->ResimHB = false;
165 0 : state.dataDemandManager->ResimHVAC = false;
166 :
167 0 : SurveyDemandManagers(state); // Determines which Demand Managers can reduce demand
168 :
169 0 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
170 0 : SimulateDemandManagerList(
171 0 : state, ListNum, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
172 : } // ListNum
173 :
174 0 : ActivateDemandManagers(state); // Sets limits on loads
175 :
176 0 : if (state.dataDemandManager->DemandManagerExtIterations + state.dataDemandManager->DemandManagerHBIterations +
177 0 : 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 0 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
186 0 : ReportDemandManagerList(state, ListNum);
187 : } // ListNum
188 : }
189 : }
190 164434 : }
191 :
192 0 : 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 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
207 :
208 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
209 : bool OnPeak;
210 :
211 0 : auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
212 :
213 0 : demandManagerList.ScheduledLimit = demandManagerList.limitSched->getCurrentVal();
214 0 : demandManagerList.DemandLimit = demandManagerList.ScheduledLimit * demandManagerList.SafetyFraction;
215 :
216 0 : demandManagerList.MeterDemand =
217 0 : GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::Zone) / state.dataGlobal->TimeStepZoneSec +
218 0 : 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 0 : demandManagerList.AverageDemand + (demandManagerList.MeterDemand - demandManagerList.History(1)) / demandManagerList.AveragingWindow;
223 :
224 0 : OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
225 :
226 0 : if (OnPeak) {
227 0 : Real64 OverLimit = AverageDemand - demandManagerList.DemandLimit;
228 :
229 0 : if (OverLimit > 0.0) {
230 :
231 0 : switch (demandManagerList.ManagerPriority) {
232 0 : case ManagePriorityType::Sequential: { // Activate first Demand Manager that can reduce demand
233 :
234 0 : for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
235 0 : auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
236 :
237 0 : if (demandMgr.CanReduceDemand) {
238 0 : demandMgr.Activate = true;
239 :
240 0 : switch (demandMgr.Type) {
241 0 : case ManagerType::ExtLights: {
242 0 : ResimExt = true;
243 0 : } break;
244 0 : case ManagerType::Lights:
245 : case ManagerType::ElecEquip: {
246 0 : ResimHB = true;
247 0 : ResimHVAC = true;
248 0 : } break;
249 0 : case ManagerType::Thermostats:
250 : case ManagerType::Ventilation: {
251 0 : ResimHVAC = true;
252 0 : } break;
253 0 : default:
254 0 : break;
255 : }
256 :
257 0 : break; // Leave the loop
258 : }
259 : } // MgrNum
260 :
261 0 : } 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 0 : }
299 :
300 74 : 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 74 : constexpr std::string_view cCurrentModuleObject = "DemandManagerAssignmentList";
318 :
319 74 : auto &s_ipsc = state.dataIPShortCut;
320 74 : auto const &s_ip = state.dataInputProcessing->inputProcessor;
321 :
322 74 : state.dataDemandManager->NumDemandManagerList = s_ip->getNumObjectsFound(state, cCurrentModuleObject);
323 :
324 74 : 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 1 : bool ErrorsFound = false;
329 :
330 1 : state.dataDemandManager->DemandManagerList.allocate(state.dataDemandManager->NumDemandManagerList);
331 :
332 1 : for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
333 :
334 1 : auto &thisDemandMgrList = state.dataDemandManager->DemandManagerList(ListNum);
335 :
336 3 : s_ip->getObjectItem(state,
337 : cCurrentModuleObject,
338 : ListNum,
339 1 : s_ipsc->cAlphaArgs,
340 : NumAlphas,
341 1 : s_ipsc->rNumericArgs,
342 : NumNums,
343 : IOStat,
344 : _,
345 1 : s_ipsc->lAlphaFieldBlanks,
346 1 : s_ipsc->cAlphaFieldNames,
347 1 : s_ipsc->cNumericFieldNames);
348 :
349 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
350 :
351 1 : thisDemandMgrList.Name = s_ipsc->cAlphaArgs(1);
352 :
353 1 : thisDemandMgrList.Meter = GetMeterIndex(state, s_ipsc->cAlphaArgs(2));
354 :
355 1 : 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 1 : } 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 1 : if (s_ipsc->lAlphaFieldBlanks(3)) {
376 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
377 0 : ErrorsFound = true;
378 1 : } 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 1 : thisDemandMgrList.SafetyFraction = s_ipsc->rNumericArgs(1);
384 :
385 1 : 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 1 : 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 1 : 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 1 : thisDemandMgrList.History.allocate(thisDemandMgrList.AveragingWindow);
401 1 : thisDemandMgrList.History = 0.0;
402 :
403 : // Validate Demand Manager Priority
404 1 : thisDemandMgrList.ManagerPriority =
405 1 : static_cast<ManagePriorityType>(getEnumValue(ManagePriorityNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(6))));
406 1 : ErrorsFound = ErrorsFound || (thisDemandMgrList.ManagerPriority == ManagePriorityType::Invalid);
407 :
408 : // Get DEMAND MANAGER Type and Name pairs
409 1 : thisDemandMgrList.NumOfManager = int((NumAlphas - 6) / 2.0);
410 :
411 1 : if (thisDemandMgrList.NumOfManager > 0) {
412 1 : thisDemandMgrList.Manager.allocate(thisDemandMgrList.NumOfManager);
413 2 : for (int MgrNum = 1; MgrNum <= thisDemandMgrList.NumOfManager; ++MgrNum) {
414 :
415 1 : auto &thisManager = thisDemandMgrList.Manager(MgrNum);
416 : // Validate DEMAND MANAGER Type
417 1 : ManagerType MgrType = static_cast<ManagerType>(getEnumValue(ManagerNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(MgrNum * 2 + 5))));
418 1 : if (MgrType != ManagerType::Invalid) {
419 1 : thisManager = Util::FindItemInList(s_ipsc->cAlphaArgs(MgrNum * 2 + 6), state.dataDemandManager->DemandMgr);
420 1 : if (thisManager == 0) {
421 2 : ShowSevereError(state,
422 2 : format("{} = \"{}\" invalid {} = \"{}\" not found.",
423 : cCurrentModuleObject,
424 1 : thisDemandMgrList.Name,
425 1 : s_ipsc->cAlphaFieldNames(MgrNum * 2 + 6),
426 1 : s_ipsc->cAlphaArgs(MgrNum * 2 + 6)));
427 1 : 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 2 : SetupOutputVariable(state,
446 : "Demand Manager Meter Demand Power",
447 : Constant::Units::W,
448 1 : thisDemandMgrList.MeterDemand,
449 : OutputProcessor::TimeStepType::Zone,
450 : OutputProcessor::StoreType::Average,
451 1 : thisDemandMgrList.Name);
452 :
453 2 : SetupOutputVariable(state,
454 : "Demand Manager Average Demand Power",
455 : Constant::Units::W,
456 1 : thisDemandMgrList.AverageDemand,
457 : OutputProcessor::TimeStepType::Zone,
458 : OutputProcessor::StoreType::Average,
459 1 : thisDemandMgrList.Name);
460 :
461 2 : SetupOutputVariable(state,
462 : "Demand Manager Peak Demand Power",
463 : Constant::Units::W,
464 1 : thisDemandMgrList.PeakDemand,
465 : OutputProcessor::TimeStepType::Zone,
466 : OutputProcessor::StoreType::Average,
467 1 : thisDemandMgrList.Name);
468 :
469 2 : SetupOutputVariable(state,
470 : "Demand Manager Scheduled Limit Power",
471 : Constant::Units::W,
472 1 : thisDemandMgrList.ScheduledLimit,
473 : OutputProcessor::TimeStepType::Zone,
474 : OutputProcessor::StoreType::Average,
475 1 : thisDemandMgrList.Name);
476 :
477 2 : SetupOutputVariable(state,
478 : "Demand Manager Demand Limit Power",
479 : Constant::Units::W,
480 1 : thisDemandMgrList.DemandLimit,
481 : OutputProcessor::TimeStepType::Zone,
482 : OutputProcessor::StoreType::Average,
483 1 : thisDemandMgrList.Name);
484 :
485 2 : SetupOutputVariable(state,
486 : "Demand Manager Over Limit Power",
487 : Constant::Units::W,
488 1 : thisDemandMgrList.OverLimit,
489 : OutputProcessor::TimeStepType::Zone,
490 : OutputProcessor::StoreType::Average,
491 1 : thisDemandMgrList.Name);
492 :
493 2 : SetupOutputVariable(state,
494 : "Demand Manager Over Limit Time",
495 : Constant::Units::hr,
496 1 : thisDemandMgrList.OverLimitDuration,
497 : OutputProcessor::TimeStepType::Zone,
498 : OutputProcessor::StoreType::Sum,
499 1 : thisDemandMgrList.Name);
500 :
501 1 : if (ErrorsFound) {
502 2 : 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 0 : SetupOutputVariable(state,
509 : "Demand Manager Exterior Energy Iteration Count",
510 : Constant::Units::None,
511 0 : state.dataDemandManager->DemandManagerExtIterations,
512 : OutputProcessor::TimeStepType::Zone,
513 : OutputProcessor::StoreType::Sum,
514 : "ManageDemand");
515 :
516 0 : SetupOutputVariable(state,
517 : "Demand Manager Heat Balance Iteration Count",
518 : Constant::Units::None,
519 0 : state.dataDemandManager->DemandManagerHBIterations,
520 : OutputProcessor::TimeStepType::Zone,
521 : OutputProcessor::StoreType::Sum,
522 : "ManageDemand");
523 :
524 0 : SetupOutputVariable(state,
525 : "Demand Manager HVAC Iteration Count",
526 : Constant::Units::None,
527 0 : state.dataDemandManager->DemandManagerHVACIterations,
528 : OutputProcessor::TimeStepType::Zone,
529 : OutputProcessor::StoreType::Sum,
530 : "ManageDemand");
531 : }
532 73 : }
533 :
534 75 : 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 75 : auto &s_ipsc = state.dataIPShortCut;
548 75 : 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 75 : Array1D_string AlphArray; // Character string data
555 75 : Array1D<Real64> NumArray; // Numeric data
556 75 : bool ErrorsFound(false);
557 :
558 75 : int MaxAlphas = 0;
559 75 : int MaxNums = 0;
560 75 : std::string CurrentModuleObject = "DemandManager:ExteriorLights";
561 75 : int NumDemandMgrExtLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
562 75 : if (NumDemandMgrExtLights > 0) {
563 1 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
564 1 : MaxAlphas = max(MaxAlphas, NumAlphas);
565 1 : MaxNums = max(MaxNums, NumNums);
566 : }
567 75 : CurrentModuleObject = "DemandManager:Lights";
568 75 : int NumDemandMgrLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
569 75 : if (NumDemandMgrLights > 0) {
570 0 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
571 0 : MaxAlphas = max(MaxAlphas, NumAlphas);
572 0 : MaxNums = max(MaxNums, NumNums);
573 : }
574 75 : CurrentModuleObject = "DemandManager:ElectricEquipment";
575 75 : int NumDemandMgrElecEquip = s_ip->getNumObjectsFound(state, CurrentModuleObject);
576 75 : if (NumDemandMgrElecEquip > 0) {
577 0 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
578 0 : MaxAlphas = max(MaxAlphas, NumAlphas);
579 0 : MaxNums = max(MaxNums, NumNums);
580 : }
581 75 : CurrentModuleObject = "DemandManager:Thermostats";
582 75 : int NumDemandMgrThermostats = s_ip->getNumObjectsFound(state, CurrentModuleObject);
583 75 : if (NumDemandMgrThermostats > 0) {
584 0 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
585 0 : MaxAlphas = max(MaxAlphas, NumAlphas);
586 0 : MaxNums = max(MaxNums, NumNums);
587 : }
588 75 : CurrentModuleObject = "DemandManager:Ventilation";
589 75 : int NumDemandMgrVentilation = s_ip->getNumObjectsFound(state, CurrentModuleObject);
590 75 : if (NumDemandMgrVentilation > 0) {
591 1 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
592 1 : MaxAlphas = max(MaxAlphas, NumAlphas);
593 1 : MaxNums = max(MaxNums, NumNums);
594 : }
595 :
596 150 : state.dataDemandManager->NumDemandMgr =
597 75 : NumDemandMgrExtLights + NumDemandMgrLights + NumDemandMgrElecEquip + NumDemandMgrThermostats + NumDemandMgrVentilation;
598 :
599 75 : auto &DemandMgr(state.dataDemandManager->DemandMgr);
600 :
601 75 : if (state.dataDemandManager->NumDemandMgr > 0) {
602 2 : AlphArray.dimension(MaxAlphas, std::string());
603 2 : NumArray.dimension(MaxNums, 0.0);
604 : int IOStat; // IO Status when calling get input subroutine
605 :
606 2 : DemandMgr.allocate(state.dataDemandManager->NumDemandMgr);
607 2 : state.dataDemandManager->UniqueDemandMgrNames.reserve(state.dataDemandManager->NumDemandMgr);
608 :
609 : // Get input for DemandManager:ExteriorLights
610 2 : int StartIndex = 1;
611 2 : int EndIndex = NumDemandMgrExtLights;
612 :
613 2 : CurrentModuleObject = "DemandManager:ExteriorLights";
614 :
615 3 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
616 1 : auto &demandMgr = DemandMgr(MgrNum);
617 :
618 3 : s_ip->getObjectItem(state,
619 : CurrentModuleObject,
620 1 : MgrNum - StartIndex + 1,
621 : AlphArray,
622 : NumAlphas,
623 : NumArray,
624 : NumNums,
625 : IOStat,
626 : _,
627 1 : s_ipsc->lAlphaFieldBlanks,
628 1 : s_ipsc->cAlphaFieldNames,
629 1 : s_ipsc->cNumericFieldNames);
630 :
631 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
632 :
633 1 : GlobalNames::VerifyUniqueInterObjectName(
634 2 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
635 1 : demandMgr.Name = AlphArray(1);
636 :
637 1 : demandMgr.Type = ManagerType::ExtLights;
638 :
639 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
640 1 : 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 1 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
648 1 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
649 :
650 1 : if (NumArray(1) == 0.0)
651 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
652 : else
653 1 : demandMgr.LimitDuration = NumArray(1);
654 :
655 1 : demandMgr.LowerLimit = NumArray(2);
656 :
657 : // Validate Selection Control
658 1 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
659 1 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
660 :
661 1 : if (NumArray(4) == 0.0)
662 1 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
663 : else
664 0 : demandMgr.RotationDuration = NumArray(4);
665 :
666 1 : demandMgr.NumOfLoads = NumAlphas - 4;
667 :
668 1 : if (demandMgr.NumOfLoads > 0) {
669 1 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
670 :
671 2 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
672 1 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataExteriorEnergyUse->ExteriorLights);
673 :
674 1 : if (LoadPtr > 0) {
675 1 : demandMgr.Load(LoadNum) = LoadPtr;
676 :
677 : } else {
678 0 : ShowSevereError(state,
679 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
680 : CurrentModuleObject,
681 0 : s_ipsc->cAlphaArgs(1),
682 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
683 : AlphArray(LoadNum + 4)));
684 0 : ErrorsFound = true;
685 : }
686 : } // LoadNum
687 : } else {
688 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
689 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
690 0 : ErrorsFound = true;
691 : }
692 :
693 : } // MgrNum
694 :
695 : // Get input for DemandManager:Lights
696 2 : StartIndex = EndIndex + 1;
697 2 : EndIndex += NumDemandMgrLights;
698 :
699 2 : CurrentModuleObject = "DemandManager:Lights";
700 :
701 2 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
702 0 : auto &demandMgr = DemandMgr(MgrNum);
703 :
704 0 : s_ip->getObjectItem(state,
705 : CurrentModuleObject,
706 0 : MgrNum - StartIndex + 1,
707 : AlphArray,
708 : NumAlphas,
709 : NumArray,
710 : NumNums,
711 : IOStat,
712 : _,
713 0 : s_ipsc->lAlphaFieldBlanks,
714 0 : s_ipsc->cAlphaFieldNames,
715 0 : s_ipsc->cNumericFieldNames);
716 :
717 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
718 0 : GlobalNames::VerifyUniqueInterObjectName(
719 0 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
720 0 : demandMgr.Name = AlphArray(1);
721 :
722 0 : demandMgr.Type = ManagerType::Lights;
723 :
724 0 : if (s_ipsc->lAlphaFieldBlanks(2)) {
725 0 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
726 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
727 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
728 0 : ErrorsFound = true;
729 : }
730 :
731 : // Validate Limiting Control
732 0 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
733 0 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
734 :
735 0 : if (NumArray(1) == 0.0)
736 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
737 : else
738 0 : demandMgr.LimitDuration = NumArray(1);
739 :
740 0 : demandMgr.LowerLimit = NumArray(2);
741 :
742 : // Validate Selection Control
743 0 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
744 0 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
745 :
746 0 : if (NumArray(4) == 0.0)
747 0 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
748 : else
749 0 : demandMgr.RotationDuration = NumArray(4);
750 :
751 : // Count actual pointers to controlled zones
752 0 : demandMgr.NumOfLoads = 0;
753 0 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
754 0 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->lightsObjects);
755 0 : if (LoadPtr > 0) {
756 0 : demandMgr.NumOfLoads += state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces;
757 : } else {
758 0 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->Lights);
759 0 : if (LoadPtr > 0) {
760 0 : ++demandMgr.NumOfLoads;
761 : } else {
762 0 : ShowSevereError(state,
763 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
764 : CurrentModuleObject,
765 0 : s_ipsc->cAlphaArgs(1),
766 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
767 : AlphArray(LoadNum + 4)));
768 0 : ErrorsFound = true;
769 : }
770 : }
771 : }
772 :
773 : // demandMgr%NumOfLoads = NumAlphas - 4
774 :
775 0 : if (demandMgr.NumOfLoads > 0) {
776 0 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
777 0 : int LoadNum = 0;
778 0 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
779 0 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->lightsObjects);
780 0 : if (LoadPtr > 0) {
781 0 : for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces; ++Item1) {
782 0 : ++LoadNum;
783 0 : demandMgr.Load(LoadNum) = state.dataInternalHeatGains->lightsObjects(LoadPtr).spaceStartPtr + Item1 - 1;
784 : }
785 : } else {
786 0 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->Lights);
787 0 : if (LoadPtr > 0) {
788 0 : ++LoadNum;
789 0 : demandMgr.Load(LoadNum) = LoadPtr;
790 : }
791 : }
792 : } // LoadNum
793 : } else {
794 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
795 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
796 0 : ErrorsFound = true;
797 : }
798 :
799 : } // MgrNum
800 :
801 : // Get input for DemandManager:ElectricEquipment
802 2 : StartIndex = EndIndex + 1;
803 2 : EndIndex += NumDemandMgrElecEquip;
804 :
805 2 : CurrentModuleObject = "DemandManager:ElectricEquipment";
806 :
807 2 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
808 0 : auto &demandMgr = DemandMgr(MgrNum);
809 :
810 0 : s_ip->getObjectItem(state,
811 : CurrentModuleObject,
812 0 : MgrNum - StartIndex + 1,
813 : AlphArray,
814 : NumAlphas,
815 : NumArray,
816 : NumNums,
817 : IOStat,
818 : _,
819 0 : s_ipsc->lAlphaFieldBlanks,
820 0 : s_ipsc->cAlphaFieldNames,
821 0 : s_ipsc->cNumericFieldNames);
822 :
823 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
824 0 : GlobalNames::VerifyUniqueInterObjectName(
825 0 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
826 :
827 0 : demandMgr.Name = AlphArray(1);
828 :
829 0 : demandMgr.Type = ManagerType::ElecEquip;
830 :
831 0 : if (s_ipsc->lAlphaFieldBlanks(2)) {
832 0 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
833 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
834 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
835 0 : ErrorsFound = true;
836 : }
837 :
838 : // Validate Limiting Control
839 0 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
840 0 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
841 :
842 0 : if (NumArray(1) == 0.0)
843 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
844 : else
845 0 : demandMgr.LimitDuration = NumArray(1);
846 :
847 0 : demandMgr.LowerLimit = NumArray(2);
848 :
849 : // Validate Selection Control
850 0 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
851 0 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
852 :
853 0 : if (NumArray(4) == 0.0)
854 0 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
855 : else
856 0 : demandMgr.RotationDuration = NumArray(4);
857 :
858 : // Count actual pointers to controlled zones
859 0 : demandMgr.NumOfLoads = 0;
860 0 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
861 0 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->zoneElectricObjects);
862 0 : if (LoadPtr > 0) {
863 0 : demandMgr.NumOfLoads += state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces;
864 : } else {
865 0 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->ZoneElectric);
866 0 : if (LoadPtr > 0) {
867 0 : ++demandMgr.NumOfLoads;
868 : } else {
869 0 : ShowSevereError(state,
870 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
871 : CurrentModuleObject,
872 0 : s_ipsc->cAlphaArgs(1),
873 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
874 : AlphArray(LoadNum + 4)));
875 0 : ErrorsFound = true;
876 : }
877 : }
878 : }
879 :
880 : // demandMgr%NumOfLoads = NumAlphas - 4
881 :
882 0 : if (demandMgr.NumOfLoads > 0) {
883 0 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
884 0 : int LoadNum = 0;
885 0 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
886 0 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->zoneElectricObjects);
887 0 : if (LoadPtr > 0) {
888 0 : for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces; ++Item1) {
889 0 : ++LoadNum;
890 0 : demandMgr.Load(LoadNum) = state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).spaceStartPtr + Item1 - 1;
891 : }
892 : } else {
893 0 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->ZoneElectric);
894 0 : if (LoadPtr > 0) {
895 0 : ++LoadNum;
896 0 : demandMgr.Load(LoadNum) = LoadPtr;
897 : }
898 : }
899 : } // LoadNum
900 : } else {
901 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
902 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
903 0 : ErrorsFound = true;
904 : }
905 :
906 : } // MgrNum
907 :
908 : // Get input for DemandManager:Thermostats
909 2 : StartIndex = EndIndex + 1;
910 2 : EndIndex += NumDemandMgrThermostats;
911 :
912 2 : CurrentModuleObject = "DemandManager:Thermostats";
913 :
914 2 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
915 0 : auto &demandMgr = DemandMgr(MgrNum);
916 :
917 0 : s_ip->getObjectItem(state,
918 : CurrentModuleObject,
919 0 : MgrNum - StartIndex + 1,
920 : AlphArray,
921 : NumAlphas,
922 : NumArray,
923 : NumNums,
924 : IOStat,
925 : _,
926 0 : s_ipsc->lAlphaFieldBlanks,
927 0 : s_ipsc->cAlphaFieldNames,
928 0 : s_ipsc->cNumericFieldNames);
929 :
930 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
931 :
932 0 : GlobalNames::VerifyUniqueInterObjectName(
933 0 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
934 0 : demandMgr.Name = AlphArray(1);
935 :
936 0 : demandMgr.Type = ManagerType::Thermostats;
937 :
938 0 : if (s_ipsc->lAlphaFieldBlanks(2)) {
939 0 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
940 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
941 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
942 0 : ErrorsFound = true;
943 : }
944 :
945 : // Validate Limiting Control
946 0 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
947 0 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
948 :
949 0 : if (NumArray(1) == 0.0)
950 0 : demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
951 : else
952 0 : demandMgr.LimitDuration = NumArray(1);
953 :
954 0 : demandMgr.LowerLimit = NumArray(2);
955 0 : demandMgr.UpperLimit = NumArray(3);
956 :
957 0 : if (demandMgr.LowerLimit > demandMgr.UpperLimit) {
958 0 : ShowSevereError(state, format("Invalid input for {} = {}", CurrentModuleObject, AlphArray(1)));
959 0 : ShowContinueError(
960 : state,
961 0 : format("{} [{:.2R}] > {} [{:.2R}]", s_ipsc->cNumericFieldNames(2), NumArray(2), s_ipsc->cNumericFieldNames(3), NumArray(3)));
962 0 : ShowContinueError(state, format("{} cannot be greater than {}", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3)));
963 0 : ErrorsFound = true;
964 : }
965 :
966 : // Validate Selection Control
967 0 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
968 0 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
969 :
970 0 : if (NumArray(5) == 0.0)
971 0 : demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
972 : else
973 0 : demandMgr.RotationDuration = NumArray(5);
974 :
975 : // Count actual pointers to controlled zones
976 0 : demandMgr.NumOfLoads = 0;
977 0 : for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
978 0 : int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TStatObjects);
979 0 : if (LoadPtr > 0) {
980 0 : demandMgr.NumOfLoads += state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones;
981 : } else {
982 0 : LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TempControlledZone);
983 0 : if (LoadPtr > 0) {
984 0 : ++demandMgr.NumOfLoads;
985 : } else {
986 0 : ShowSevereError(state,
987 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
988 : CurrentModuleObject,
989 0 : s_ipsc->cAlphaArgs(1),
990 0 : s_ipsc->cAlphaFieldNames(LoadNum + 4),
991 : AlphArray(LoadNum + 4)));
992 0 : ErrorsFound = true;
993 : }
994 : }
995 : }
996 :
997 0 : if (demandMgr.NumOfLoads > 0) {
998 0 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
999 0 : int LoadNum = 0;
1000 0 : for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
1001 0 : int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TStatObjects);
1002 0 : if (LoadPtr > 0) {
1003 0 : for (int Item1 = 1; Item1 <= state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones; ++Item1) {
1004 0 : ++LoadNum;
1005 0 : demandMgr.Load(LoadNum) = state.dataZoneCtrls->TStatObjects(LoadPtr).TempControlledZoneStartPtr + Item1 - 1;
1006 : }
1007 : } else {
1008 0 : LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TempControlledZone);
1009 0 : if (LoadPtr > 0) {
1010 0 : ++LoadNum;
1011 0 : demandMgr.Load(LoadNum) = LoadPtr;
1012 : }
1013 : }
1014 : } // LoadNum
1015 : } else {
1016 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1017 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
1018 0 : ErrorsFound = true;
1019 : }
1020 : } // MgrNum
1021 :
1022 : // Get input for DemandManager:Ventilation
1023 2 : StartIndex = EndIndex + 1;
1024 2 : EndIndex += NumDemandMgrVentilation;
1025 :
1026 2 : CurrentModuleObject = "DemandManager:Ventilation";
1027 :
1028 3 : for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
1029 1 : auto &demandMgr = DemandMgr(MgrNum);
1030 :
1031 3 : s_ip->getObjectItem(state,
1032 : CurrentModuleObject,
1033 1 : MgrNum - StartIndex + 1,
1034 : AlphArray,
1035 : NumAlphas,
1036 : NumArray,
1037 : NumNums,
1038 : IOStat,
1039 : _,
1040 1 : s_ipsc->lAlphaFieldBlanks,
1041 1 : s_ipsc->cAlphaFieldNames,
1042 1 : s_ipsc->cNumericFieldNames);
1043 :
1044 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
1045 1 : GlobalNames::VerifyUniqueInterObjectName(
1046 2 : state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
1047 1 : demandMgr.Name = AlphArray(1);
1048 :
1049 1 : demandMgr.Type = ManagerType::Ventilation;
1050 :
1051 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1052 1 : demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
1053 0 : } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
1054 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
1055 0 : ErrorsFound = true;
1056 : }
1057 :
1058 : // Validate Limiting Control
1059 1 : demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitVentNamesUC, Util::makeUPPER(AlphArray(3))));
1060 1 : ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
1061 :
1062 1 : demandMgr.LimitDuration = (NumArray(1) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(1);
1063 :
1064 1 : if (demandMgr.LimitControl == ManagerLimit::Fixed) demandMgr.FixedRate = NumArray(2);
1065 1 : if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) demandMgr.ReductionRatio = NumArray(3);
1066 :
1067 1 : demandMgr.LowerLimit = NumArray(4);
1068 :
1069 : // Validate Selection Control
1070 1 : demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
1071 1 : ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
1072 :
1073 1 : demandMgr.RotationDuration = (NumArray(5) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(5);
1074 :
1075 : // Count number of string fields for loading Controller:OutdoorAir names. This number must be increased in case if
1076 : // new string field is added or decreased if string fields are removed.
1077 1 : int AlphaShift = 4;
1078 :
1079 : // Count actual pointers to air controllers
1080 1 : demandMgr.NumOfLoads = 0;
1081 2 : for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
1082 1 : int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
1083 1 : if (LoadPtr > 0) {
1084 1 : ++demandMgr.NumOfLoads;
1085 : } else {
1086 0 : ShowSevereError(state,
1087 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1088 : CurrentModuleObject,
1089 0 : s_ipsc->cAlphaArgs(1),
1090 0 : s_ipsc->cAlphaFieldNames(LoadNum + AlphaShift),
1091 : AlphArray(LoadNum + AlphaShift)));
1092 0 : ErrorsFound = true;
1093 : }
1094 : }
1095 :
1096 1 : if (demandMgr.NumOfLoads > 0) {
1097 1 : demandMgr.Load.allocate(demandMgr.NumOfLoads);
1098 2 : for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
1099 1 : int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
1100 1 : if (LoadPtr > 0) {
1101 1 : demandMgr.Load(LoadNum) = LoadPtr;
1102 : }
1103 : }
1104 : } else {
1105 0 : ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1106 0 : ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
1107 0 : ErrorsFound = true;
1108 : }
1109 : } // MgrNum
1110 :
1111 2 : AlphArray.deallocate();
1112 2 : NumArray.deallocate();
1113 : }
1114 :
1115 75 : if (ErrorsFound) {
1116 0 : ShowFatalError(state, "Errors found in processing input for demand managers. Preceding condition causes termination.");
1117 : }
1118 75 : }
1119 :
1120 0 : void SurveyDemandManagers(EnergyPlusData &state)
1121 : {
1122 :
1123 : // SUBROUTINE INFORMATION:
1124 : // AUTHOR Peter Graham Ellis
1125 : // DATE WRITTEN July 2005
1126 :
1127 : // PURPOSE OF THIS SUBROUTINE:
1128 : // Checks to see if any demand managers can reduce the load
1129 :
1130 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1131 : bool CanReduceDemand;
1132 :
1133 0 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1134 :
1135 0 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1136 :
1137 0 : demandMgr.CanReduceDemand = false;
1138 :
1139 0 : if (!demandMgr.Available) continue;
1140 0 : if (demandMgr.LimitControl == ManagerLimit::Off) continue;
1141 :
1142 0 : if (demandMgr.Active) continue; // This works for FIXED control action, but not VARIABLE
1143 : // VARIABLE control could actually reduce demand farther, even if active already
1144 :
1145 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1146 0 : int LoadPtr = demandMgr.Load(LoadNum);
1147 :
1148 : // Check if this load can reduce demand
1149 : // Assume FIXED control action for now, needs more sophisticated check for VARIABLE control
1150 0 : LoadInterface(state, DemandAction::CheckCanReduce, MgrNum, LoadPtr, CanReduceDemand);
1151 :
1152 0 : if (CanReduceDemand) {
1153 0 : demandMgr.CanReduceDemand = true;
1154 0 : break; // If any one load can reduce demand, then the whole demand manager can reduce demand
1155 : }
1156 :
1157 : } // LoadNum
1158 :
1159 : } // MgrNum
1160 0 : }
1161 :
1162 0 : void ActivateDemandManagers(EnergyPlusData &state)
1163 : {
1164 :
1165 : // SUBROUTINE INFORMATION:
1166 : // AUTHOR Peter Graham Ellis
1167 : // DATE WRITTEN July 2005
1168 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1169 : int LoadPtr;
1170 :
1171 0 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1172 :
1173 0 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1174 :
1175 0 : if (demandMgr.Activate) {
1176 : bool CanReduceDemand;
1177 0 : demandMgr.Activate = false;
1178 0 : demandMgr.Active = true;
1179 :
1180 0 : switch (demandMgr.SelectionControl) {
1181 0 : case ManagerSelection::All: {
1182 : // Turn ON limiting on all loads
1183 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1184 0 : LoadPtr = demandMgr.Load(LoadNum);
1185 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1186 : } // LoadNum
1187 :
1188 0 : } break;
1189 0 : case ManagerSelection::Many: { // All loads are limited except for one
1190 0 : if (demandMgr.NumOfLoads > 1) {
1191 :
1192 : // Turn ON limiting on all loads
1193 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1194 0 : LoadPtr = demandMgr.Load(LoadNum);
1195 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1196 : } // LoadNum
1197 :
1198 : // Set next rotated load (from last time it was active)
1199 0 : int RotatedLoadNum = demandMgr.RotatedLoadNum;
1200 0 : ++RotatedLoadNum;
1201 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
1202 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1203 :
1204 : // Turn OFF limiting for the new rotated load
1205 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1206 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1207 : } else {
1208 : // Turn ON limiting for the one and only load
1209 0 : LoadPtr = demandMgr.Load(1);
1210 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1211 : }
1212 :
1213 0 : } break;
1214 0 : case ManagerSelection::One: { // Only one load is limited
1215 0 : if (demandMgr.NumOfLoads > 1) {
1216 : // Turn OFF limiting on all loads
1217 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1218 0 : LoadPtr = demandMgr.Load(LoadNum);
1219 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1220 : } // LoadNum
1221 :
1222 : // Set next rotated load (from last time it was active)
1223 0 : int RotatedLoadNum = demandMgr.RotatedLoadNum;
1224 0 : ++RotatedLoadNum;
1225 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
1226 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1227 :
1228 : // Turn ON limiting for the new rotated load
1229 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1230 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1231 : } else {
1232 : // Turn ON limiting for the one and only load
1233 0 : LoadPtr = demandMgr.Load(1);
1234 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1235 : }
1236 0 : } break;
1237 0 : default:
1238 0 : break;
1239 : }
1240 : }
1241 :
1242 : } // MgrNum
1243 0 : }
1244 :
1245 248592 : void UpdateDemandManagers(EnergyPlusData &state)
1246 : {
1247 :
1248 : // SUBROUTINE INFORMATION:
1249 : // AUTHOR Peter Graham Ellis
1250 : // DATE WRITTEN July 2005
1251 :
1252 : // PURPOSE OF THIS SUBROUTINE:
1253 : // Expires limits and rotates loads after specified time duration.
1254 : // It updates availability flags, expires managers that ended in the last timestep, etc.
1255 :
1256 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1257 : int LoadPtr;
1258 : bool CanReduceDemand;
1259 : int RotatedLoadNum;
1260 :
1261 248592 : for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
1262 :
1263 0 : auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1264 :
1265 : // Check availability
1266 0 : bool Available = demandMgr.availSched->getCurrentVal() > 0.0;
1267 :
1268 0 : demandMgr.Available = Available;
1269 :
1270 : // Update demand manager status
1271 0 : if (Available) {
1272 :
1273 0 : if (demandMgr.Active) {
1274 :
1275 0 : demandMgr.ElapsedTime += state.dataGlobal->MinutesInTimeStep;
1276 :
1277 : // Check for expiring limit duration
1278 0 : if (demandMgr.ElapsedTime >= demandMgr.LimitDuration) {
1279 0 : demandMgr.ElapsedTime = 0;
1280 0 : demandMgr.ElapsedRotationTime = 0;
1281 0 : demandMgr.Active = false;
1282 :
1283 : // Demand Manager is not available, remove demand limits from all loads
1284 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1285 0 : LoadPtr = demandMgr.Load(LoadNum);
1286 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1287 : } // LoadNum
1288 :
1289 : } else {
1290 :
1291 0 : switch (demandMgr.SelectionControl) {
1292 0 : case ManagerSelection::All: {
1293 : // Do nothing; limits remain on all loads
1294 :
1295 0 : } break;
1296 0 : case ManagerSelection::Many: { // All loads are limited except for one
1297 0 : demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
1298 :
1299 0 : if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
1300 0 : demandMgr.ElapsedRotationTime = 0;
1301 :
1302 0 : if (demandMgr.NumOfLoads > 1) {
1303 : // Turn ON limiting for the old rotated load
1304 0 : RotatedLoadNum = demandMgr.RotatedLoadNum;
1305 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1306 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1307 :
1308 : // Set next rotated load
1309 0 : ++RotatedLoadNum;
1310 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
1311 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1312 :
1313 : // Turn OFF limiting for the new rotated load
1314 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1315 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1316 : }
1317 : }
1318 :
1319 0 : } break;
1320 0 : case ManagerSelection::One: { // Only one load is limited
1321 0 : demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
1322 :
1323 0 : if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
1324 0 : demandMgr.ElapsedRotationTime = 0;
1325 :
1326 0 : if (demandMgr.NumOfLoads > 1) {
1327 : // Turn OFF limiting for the old rotated load
1328 0 : RotatedLoadNum = demandMgr.RotatedLoadNum;
1329 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1330 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1331 :
1332 : // Set next rotated load
1333 0 : ++RotatedLoadNum;
1334 0 : if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
1335 0 : demandMgr.RotatedLoadNum = RotatedLoadNum;
1336 :
1337 : // Turn ON limiting for the new rotated load
1338 0 : LoadPtr = demandMgr.Load(RotatedLoadNum);
1339 0 : LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
1340 : }
1341 : }
1342 0 : } break;
1343 0 : default:
1344 0 : break;
1345 : }
1346 : }
1347 : }
1348 :
1349 : } else { // Demand Manager is not available
1350 0 : demandMgr.Active = false;
1351 :
1352 : // Demand Manager is not available, remove demand limits from all loads
1353 0 : for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
1354 0 : LoadPtr = demandMgr.Load(LoadNum);
1355 0 : LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
1356 : } // LoadNum
1357 : }
1358 :
1359 : } // MgrNum
1360 248592 : }
1361 :
1362 0 : void ReportDemandManagerList(EnergyPlusData &state, int const ListNum)
1363 : {
1364 :
1365 : // SUBROUTINE INFORMATION:
1366 : // AUTHOR Peter Graham Ellis
1367 : // DATE WRITTEN July 2005
1368 :
1369 : // PURPOSE OF THIS SUBROUTINE:
1370 : // Calculates report variables.
1371 :
1372 : // METHODOLOGY EMPLOYED:
1373 : // Standard EnergyPlus methodology.
1374 :
1375 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1376 : int AveragingWindow;
1377 : bool OnPeak;
1378 : Real64 OverLimit;
1379 :
1380 0 : auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
1381 :
1382 0 : Real64 BillingPeriod = (demandManagerList.billingSched == nullptr) ? state.dataEnvrn->Month : demandManagerList.billingSched->getCurrentVal();
1383 :
1384 0 : if (demandManagerList.BillingPeriod != BillingPeriod) {
1385 : // Reset variables for new billing period
1386 : // demandManagerList%History = 0.0 ! Don't reset--continue from previous billing period
1387 : // demandManagerList%AverageDemand = 0.0 ! Don't reset--continue from previous billing period
1388 0 : demandManagerList.PeakDemand = 0.0;
1389 0 : demandManagerList.OverLimitDuration = 0.0;
1390 :
1391 0 : demandManagerList.BillingPeriod = BillingPeriod;
1392 : }
1393 :
1394 : // Add new timestep to demand history and subtract oldest timestep
1395 0 : AveragingWindow = demandManagerList.AveragingWindow;
1396 0 : demandManagerList.AverageDemand += (demandManagerList.MeterDemand - demandManagerList.History(1)) / AveragingWindow;
1397 :
1398 : // Update demand history
1399 0 : for (int Item = 1; Item <= AveragingWindow - 1; ++Item) {
1400 0 : demandManagerList.History(Item) = demandManagerList.History(Item + 1);
1401 : }
1402 0 : demandManagerList.History(AveragingWindow) = demandManagerList.MeterDemand;
1403 :
1404 0 : OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
1405 :
1406 0 : if (OnPeak) {
1407 0 : demandManagerList.PeakDemand = max(demandManagerList.AverageDemand, demandManagerList.PeakDemand);
1408 :
1409 0 : OverLimit = demandManagerList.AverageDemand - demandManagerList.ScheduledLimit;
1410 0 : if (OverLimit > 0.0) {
1411 0 : demandManagerList.OverLimit = OverLimit;
1412 0 : demandManagerList.OverLimitDuration += (state.dataGlobal->MinutesInTimeStep / 60.0);
1413 : } else {
1414 0 : demandManagerList.OverLimit = 0.0;
1415 : }
1416 :
1417 : } else {
1418 0 : demandManagerList.OverLimit = 0.0;
1419 : }
1420 0 : }
1421 :
1422 0 : void LoadInterface(EnergyPlusData &state, DemandAction const Action, int const MgrNum, int const LoadPtr, bool &CanReduceDemand)
1423 : {
1424 :
1425 : // SUBROUTINE INFORMATION:
1426 : // AUTHOR Peter Graham Ellis
1427 : // DATE WRITTEN August 2005
1428 :
1429 : // PURPOSE OF THIS SUBROUTINE:
1430 : // Provides a universal interface to handle all communication with the various load objects.
1431 : // Demand managers for new types of loads can be easily added with a new CASE statement in this subroutine
1432 : // and new GetInput code.
1433 :
1434 0 : auto const &s_dhbf = state.dataHeatBalFanSys;
1435 0 : auto const &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
1436 :
1437 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1438 : Real64 LowestPower;
1439 :
1440 0 : CanReduceDemand = false;
1441 :
1442 0 : switch (demandMgr.Type) {
1443 0 : case ManagerType::ExtLights: {
1444 0 : LowestPower = state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1445 0 : if (Action == DemandAction::CheckCanReduce) {
1446 0 : if (state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).Power > LowestPower) CanReduceDemand = true;
1447 0 : } else if (Action == DemandAction::SetLimit) {
1448 0 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = true;
1449 0 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DemandLimit = LowestPower;
1450 0 : } else if (Action == DemandAction::ClearLimit) {
1451 0 : state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = false;
1452 : }
1453 0 : } break;
1454 :
1455 0 : case ManagerType::Lights: {
1456 0 : LowestPower = state.dataHeatBal->Lights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1457 0 : if (Action == DemandAction::CheckCanReduce) {
1458 0 : if (state.dataHeatBal->Lights(LoadPtr).Power > LowestPower) CanReduceDemand = true;
1459 0 : } else if (Action == DemandAction::SetLimit) {
1460 0 : state.dataHeatBal->Lights(LoadPtr).ManageDemand = true;
1461 0 : state.dataHeatBal->Lights(LoadPtr).DemandLimit = LowestPower;
1462 0 : } else if (Action == DemandAction::ClearLimit) {
1463 0 : state.dataHeatBal->Lights(LoadPtr).ManageDemand = false;
1464 : }
1465 0 : } break;
1466 :
1467 0 : case ManagerType::ElecEquip: {
1468 0 : LowestPower = state.dataHeatBal->ZoneElectric(LoadPtr).DesignLevel * demandMgr.LowerLimit;
1469 0 : if (Action == DemandAction::CheckCanReduce) {
1470 0 : if (state.dataHeatBal->ZoneElectric(LoadPtr).Power > LowestPower) CanReduceDemand = true;
1471 0 : } else if (Action == DemandAction::SetLimit) {
1472 0 : state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = true;
1473 0 : state.dataHeatBal->ZoneElectric(LoadPtr).DemandLimit = LowestPower;
1474 0 : } else if (Action == DemandAction::ClearLimit) {
1475 0 : state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = false;
1476 : }
1477 0 : } break;
1478 :
1479 0 : case ManagerType::Thermostats: {
1480 0 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(LoadPtr);
1481 0 : auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(tempZone.ActualZoneNum);
1482 0 : if (Action == DemandAction::CheckCanReduce) {
1483 0 : if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit)
1484 0 : CanReduceDemand = true; // Heating | Cooling
1485 0 : } else if (Action == DemandAction::SetLimit) {
1486 0 : tempZone.ManageDemand = true;
1487 0 : tempZone.HeatingResetLimit = demandMgr.LowerLimit;
1488 0 : tempZone.CoolingResetLimit = demandMgr.UpperLimit;
1489 0 : } else if (Action == DemandAction::ClearLimit) {
1490 0 : tempZone.ManageDemand = false;
1491 : }
1492 0 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
1493 0 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(LoadPtr);
1494 0 : if (state.dataHeatBalFanSys->ComfortControlType(comfortZone.ActualZoneNum) != HVAC::SetptType::Uncontrolled) {
1495 0 : auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(comfortZone.ActualZoneNum);
1496 0 : if (Action == DemandAction::CheckCanReduce) {
1497 0 : if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit)
1498 0 : CanReduceDemand = true; // Heating
1499 0 : } else if (Action == DemandAction::SetLimit) {
1500 0 : comfortZone.ManageDemand = true;
1501 0 : comfortZone.HeatingResetLimit = demandMgr.LowerLimit;
1502 0 : comfortZone.CoolingResetLimit = demandMgr.UpperLimit;
1503 0 : } else if (Action == DemandAction::ClearLimit) {
1504 0 : comfortZone.ManageDemand = false;
1505 : }
1506 : }
1507 : }
1508 0 : } break;
1509 :
1510 0 : case ManagerType::Ventilation: {
1511 0 : Real64 FlowRate(0);
1512 0 : FlowRate = MixedAir::OAGetFlowRate(state, LoadPtr);
1513 0 : if (Action == DemandAction::CheckCanReduce) {
1514 0 : CanReduceDemand = true;
1515 0 : } else if (Action == DemandAction::SetLimit) {
1516 0 : MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, true);
1517 0 : if (demandMgr.LimitControl == ManagerLimit::Fixed) {
1518 0 : MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, demandMgr.FixedRate);
1519 0 : } else if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
1520 0 : Real64 DemandRate(0);
1521 0 : DemandRate = FlowRate * demandMgr.ReductionRatio;
1522 0 : MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, DemandRate);
1523 : }
1524 0 : } else if (Action == DemandAction::ClearLimit) {
1525 0 : MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, false);
1526 : }
1527 0 : } break;
1528 0 : default:
1529 0 : break;
1530 : }
1531 0 : }
1532 :
1533 73 : void InitDemandManagers(EnergyPlusData &state)
1534 : {
1535 :
1536 : // SUBROUTINE INFORMATION:
1537 : // AUTHOR Linda Lawrie
1538 : // DATE WRITTEN September 2010
1539 :
1540 : // PURPOSE OF THIS SUBROUTINE:
1541 : // Provide external call to get Demand manager input after
1542 : // appropriate initializations.
1543 :
1544 73 : if (state.dataDemandManager->GetInput) {
1545 73 : GetDemandManagerInput(state);
1546 73 : GetDemandManagerListInput(state);
1547 73 : state.dataDemandManager->GetInput = false;
1548 : }
1549 73 : }
1550 :
1551 : } // namespace EnergyPlus::DemandManager
|