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 : // C++ Headers
49 : #include <map>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/string.functions.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/CommandLineInterface.hh>
56 : #include <EnergyPlus/Data/EnergyPlusData.hh>
57 : #include <EnergyPlus/DataEnvironment.hh>
58 : #include <EnergyPlus/DataStringGlobals.hh>
59 : #include <EnergyPlus/DataSystemVariables.hh>
60 : #include <EnergyPlus/EMSManager.hh>
61 : #include <EnergyPlus/FileSystem.hh>
62 : #include <EnergyPlus/General.hh>
63 : // #include <EnergyPlus/GlobalNames.hh>
64 : #include <EnergyPlus/InputProcessing/CsvParser.hh>
65 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
66 : #include <EnergyPlus/OutputProcessor.hh>
67 : #include <EnergyPlus/ScheduleManager.hh>
68 : #include <EnergyPlus/StringUtilities.hh>
69 : #include <EnergyPlus/UtilityRoutines.hh>
70 : #include <EnergyPlus/WeatherManager.hh>
71 :
72 : namespace EnergyPlus {
73 :
74 : namespace Sched {
75 : // Module containing the Schedule Manager routines
76 :
77 : // MODULE INFORMATION:
78 : // AUTHOR Linda K. Lawrie
79 : // DATE WRITTEN September 1997
80 : // MODIFIED January 2003 -- added sub-hourly schedule possibility (and interval scheduling)
81 : // J. Glazer January 2005 -- added Schedule:File
82 : // Michael Wetter February 2010 -- added Schedule for external Interface
83 : // L Lawrie - October 2012 - added sub-hourly option for Schedule:File
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // To provide the capabilities of getting the schedule data from the input,
87 : // validating it, and storing it in such a manner that the schedule manager
88 : // can provide the scheduling value needs for the simulation.
89 :
90 : // REFERENCES:
91 : // Proposal for Schedule Manager in EnergyPlus (Rick Strand)
92 :
93 : // MODULE PARAMETER DEFINITIONS
94 17647 : int GetScheduleTypeNum(EnergyPlusData &state, std::string const &name)
95 : {
96 17647 : auto const &s_sched = state.dataSched;
97 45536 : for (int i = 0; i < (int)s_sched->scheduleTypes.size(); ++i) {
98 45524 : if (s_sched->scheduleTypes[i]->Name == name) {
99 17635 : return i;
100 : }
101 : }
102 12 : return SchedNum_Invalid;
103 : }
104 :
105 26722 : Real64 ScheduleBase::getMinVal(EnergyPlusData &state)
106 : {
107 26722 : if (!isMinMaxSet) {
108 2 : setMinMaxVals(state);
109 : }
110 26722 : return minVal;
111 : }
112 :
113 26495 : Real64 ScheduleBase::getMaxVal(EnergyPlusData &state)
114 : {
115 26495 : if (!isMinMaxSet) {
116 461 : setMinMaxVals(state);
117 : }
118 26495 : return maxVal;
119 : }
120 :
121 : // Day types are 1-based for EMS and output and other uses, so add a dummy
122 : constexpr std::array<std::string_view, (int)DayType::Num> dayTypeNames = {"Unused",
123 : "Sunday",
124 : "Monday",
125 : "Tuesday",
126 : "Wednesday",
127 : "Thursday",
128 : "Friday",
129 : "Saturday",
130 : "Holiday",
131 : "SummerDesignDay",
132 : "WinterDesignDay",
133 : "CustomDay1",
134 : "CustomDay2"};
135 :
136 : constexpr std::array<std::string_view, (int)DayType::Num> dayTypeNamesUC = {"UNUSED",
137 : "SUNDAY",
138 : "MONDAY",
139 : "TUESDAY",
140 : "WEDNESDAY",
141 : "THURSDAY",
142 : "FRIDAY",
143 : "SATURDAY",
144 : "HOLIDAY",
145 : "SUMMERDESIGNDAY",
146 : "WINTERDESIGNDAY",
147 : "CUSTOMDAY1",
148 : "CUSTOMDAY2"};
149 :
150 : static constexpr std::array<std::string_view, (int)LimitUnits::Num> limitUnitNamesUC = {"DIMENSIONLESS",
151 : "TEMPERATURE",
152 : "DELTATEMPERATURE",
153 : "PRECIPITATIONRATE",
154 : "ANGLE",
155 : "CONVECTIONCOEFFICIENT",
156 : "ACTIVITYLEVEL",
157 : "VELOCITY",
158 : "CAPACITY",
159 : "POWER",
160 : "AVAILABILITY",
161 : "PERCENT",
162 : "CONTROL",
163 : "MODE"};
164 :
165 : constexpr std::array<std::string_view, (int)ReportLevel::Num> reportLevelNames = {"Hourly", "Timestep"};
166 : constexpr std::array<std::string_view, (int)ReportLevel::Num> reportLevelNamesUC = {"HOURLY", "TIMESTEP"};
167 : constexpr std::array<std::string_view, (int)Interpolation::Num> interpolationNames = {"No", "Average", "Linear"};
168 : constexpr std::array<std::string_view, (int)Interpolation::Num> interpolationNamesUC = {"NO", "AVERAGE", "LINEAR"};
169 :
170 532 : bool DaySchedule::checkValsForLimitViolations(EnergyPlusData &state) const
171 : {
172 532 : auto &s_sched = state.dataSched;
173 :
174 532 : if (this->schedTypeNum == SchedNum_Invalid) {
175 0 : return false;
176 : }
177 532 : auto *schedType = s_sched->scheduleTypes[this->schedTypeNum];
178 532 : if (!schedType->isLimited) {
179 58 : return false;
180 : }
181 :
182 45642 : for (int i = 0; i < Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour; ++i) {
183 45168 : if (this->tsVals[i] < schedType->minVal || this->tsVals[i] > schedType->maxVal) {
184 0 : return true;
185 : }
186 : }
187 :
188 474 : return false;
189 : } // ScheduleDay::checkValsForLimitViolations()
190 :
191 532 : bool DaySchedule::checkValsForBadIntegers(EnergyPlusData &state) const
192 : {
193 532 : auto &s_sched = state.dataSched;
194 532 : if (this->schedTypeNum == SchedNum_Invalid) {
195 0 : return false;
196 : }
197 532 : auto *schedType = s_sched->scheduleTypes[this->schedTypeNum];
198 532 : if (schedType->isReal) {
199 505 : return false;
200 : }
201 : // Make sure each is integer
202 3195 : for (int i = 0; i < Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour; ++i) {
203 3168 : if (this->tsVals[i] != int(this->tsVals[i])) {
204 0 : return true;
205 : }
206 : }
207 27 : return false;
208 : } // ScheduleDay::checkValsForBadIntegers()
209 :
210 79686 : void DaySchedule::populateFromMinuteVals(EnergyPlusData &state, std::array<Real64, Constant::iMinutesInDay> const &minuteVals)
211 : {
212 79686 : auto &s_glob = state.dataGlobal;
213 79686 : if (this->interpolation == Interpolation::Average) {
214 6200 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
215 5952 : int begMin = 0;
216 5952 : int endMin = s_glob->MinutesInTimeStep - 1;
217 37200 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
218 31248 : Real64 accum = 0.0;
219 388368 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
220 357120 : accum += minuteVals[hr * Constant::iMinutesInHour + iMin];
221 : }
222 31248 : this->tsVals[hr * s_glob->TimeStepsInHour + ts] = accum / double(s_glob->MinutesInTimeStep);
223 31248 : this->sumTsVals += this->tsVals[hr * s_glob->TimeStepsInHour + ts];
224 31248 : begMin = endMin + 1;
225 31248 : endMin += s_glob->MinutesInTimeStep;
226 : }
227 : }
228 : } else {
229 1985950 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
230 1906512 : int endMinute = s_glob->MinutesInTimeStep - 1;
231 11262720 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
232 9356208 : this->tsVals[hr * s_glob->TimeStepsInHour + ts] = minuteVals[hr * Constant::iMinutesInHour + endMinute];
233 9356208 : this->sumTsVals += this->tsVals[hr * s_glob->TimeStepsInHour + ts];
234 9356208 : endMinute += s_glob->MinutesInTimeStep;
235 : }
236 : }
237 : }
238 79686 : } // ScheduleDay::populateFromHrMinVals()
239 :
240 1867 : ScheduleConstant *AddScheduleConstant(EnergyPlusData &state, std::string const &name, Real64 value)
241 : {
242 1867 : auto const &s_sched = state.dataSched;
243 1867 : auto const &s_glob = state.dataGlobal;
244 :
245 1867 : auto *sched = new ScheduleConstant;
246 1867 : sched->Name = name;
247 1867 : sched->type = SchedType::Constant;
248 1867 : sched->Num = (int)s_sched->schedules.size();
249 1867 : sched->currentVal = value;
250 : // When InitConstantScheduleData is called, TimeStepsInHour is 0, so we ensure 24
251 1867 : sched->tsVals.assign(Constant::iHoursInDay * max(1, s_glob->TimeStepsInHour), value);
252 :
253 1867 : s_sched->schedules.push_back(sched);
254 1867 : s_sched->scheduleMap.insert_or_assign(std::move(Util::makeUPPER(sched->Name)), sched->Num);
255 :
256 1867 : return sched;
257 : } // AddScheduleConstant()
258 :
259 16997 : ScheduleDetailed *AddScheduleDetailed(EnergyPlusData &state, std::string const &name)
260 : {
261 16997 : auto const &s_sched = state.dataSched;
262 :
263 16997 : auto *sched = new ScheduleDetailed;
264 16997 : sched->Name = name;
265 :
266 16997 : sched->Num = (int)s_sched->schedules.size();
267 16997 : s_sched->schedules.push_back(sched);
268 16997 : s_sched->scheduleMap.insert_or_assign(std::move(Util::makeUPPER(sched->Name)), sched->Num);
269 :
270 16997 : sched->type = SchedType::Year;
271 16997 : return sched;
272 : } // AddScheduleDetailed()
273 :
274 125121 : DaySchedule *AddDaySchedule(EnergyPlusData &state, std::string const &name)
275 : {
276 125121 : auto &s_glob = state.dataGlobal;
277 125121 : auto &s_sched = state.dataSched;
278 :
279 125121 : auto *daySched = new DaySchedule;
280 125121 : daySched->Name = name;
281 :
282 125121 : daySched->Num = (int)s_sched->daySchedules.size();
283 125121 : s_sched->daySchedules.push_back(daySched);
284 125121 : s_sched->dayScheduleMap.insert_or_assign(std::move(Util::makeUPPER(daySched->Name)), daySched->Num);
285 :
286 125121 : daySched->tsVals.resize(Constant::iHoursInDay * s_glob->TimeStepsInHour);
287 :
288 125121 : return daySched;
289 : } // AddDaySchedule()
290 :
291 113310 : WeekSchedule *AddWeekSchedule(EnergyPlusData &state, std::string const &name)
292 : {
293 113310 : auto const &s_sched = state.dataSched;
294 :
295 113310 : auto *weekSched = new WeekSchedule;
296 113310 : weekSched->Name = name;
297 :
298 113310 : weekSched->Num = (int)s_sched->weekSchedules.size();
299 113310 : s_sched->weekSchedules.push_back(weekSched);
300 113310 : s_sched->weekScheduleMap.insert_or_assign(std::move(Util::makeUPPER(weekSched->Name)), weekSched->Num);
301 :
302 113310 : return weekSched;
303 : } // AddWeekSchedule()
304 :
305 801 : void InitConstantScheduleData(EnergyPlusData &state)
306 : {
307 : // Create ScheduleAlwaysOn and ScheduleAlwaysOff
308 : // Create constant schedules
309 801 : auto *schedOff = AddScheduleConstant(state, "Constant-0.0", 0.0);
310 801 : assert(schedOff->Num == SchedNum_AlwaysOff);
311 801 : schedOff->isUsed = true; // Suppress unused warnings
312 :
313 801 : auto *schedOn = AddScheduleConstant(state, "Constant-1.0", 1.0);
314 801 : assert(schedOn->Num == SchedNum_AlwaysOn);
315 801 : schedOn->isUsed = true; // Suppress unused warnings
316 801 : }
317 :
318 801 : void ProcessScheduleInput(EnergyPlusData &state)
319 : {
320 : // SUBROUTINE INFORMATION:
321 : // AUTHOR Linda K. Lawrie
322 : // DATE WRITTEN September 1997
323 : // MODIFIED Rui Zhang February 2010
324 :
325 : // PURPOSE OF THIS SUBROUTINE:
326 : // This subroutine processes the schedules input for EnergyPlus.
327 :
328 : // METHODOLOGY EMPLOYED:
329 : // Uses the standard get routines in the InputProcessor.
330 :
331 : // Using/Aliasing
332 : using DataStringGlobals::CharComma;
333 : using DataStringGlobals::CharSemicolon;
334 : using DataStringGlobals::CharSpace;
335 : using DataStringGlobals::CharTab;
336 : using DataSystemVariables::CheckForActualFilePath;
337 : using General::ProcessDateString;
338 :
339 : // Locals
340 : // SUBROUTINE PARAMETER DEFINITIONS:
341 801 : constexpr std::string_view routineName = "ProcessScheduleInput";
342 :
343 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
344 :
345 801 : Array1D_string Alphas;
346 801 : Array1D_string cAlphaFields;
347 801 : Array1D_string cNumericFields;
348 801 : Array1D<Real64> Numbers;
349 801 : Array1D_bool lAlphaBlanks;
350 801 : Array1D_bool lNumericBlanks;
351 : int NumAlphas;
352 : int NumNumbers;
353 : int Status;
354 :
355 : int EndMonth;
356 : int EndDay;
357 : int StartPointer;
358 : int EndPointer;
359 : int NumPointer;
360 801 : bool ErrorsFound(false);
361 : bool NumErrorFlag;
362 :
363 801 : std::string CFld; // Character field for error message
364 : // CHARACTER(len=20) CFld1 ! Character field for error message
365 :
366 : std::array<Real64, Constant::iMinutesInDay> minuteVals;
367 : std::array<bool, Constant::iMinutesInDay> setMinuteVals;
368 :
369 : int NumFields;
370 : // LOGICAL RptSchedule
371 :
372 : int RptLevel;
373 : int MinutesPerItem;
374 : int NumExpectedItems;
375 : std::array<bool, (int)DayType::Num> allDays;
376 : std::array<bool, (int)DayType::Num> theseDays;
377 : bool ErrorHere;
378 : int SchNum;
379 : int WkCount;
380 : int DyCount;
381 : int NumField;
382 : int Count;
383 : Weather::DateType PDateType;
384 : int PWeekDay;
385 : int ThruField;
386 : int UntilFld;
387 : int xxcount;
388 : // REAL(r64) tempval
389 801 : std::string CurrentThrough;
390 801 : std::string LastFor;
391 801 : std::string errmsg;
392 : // for SCHEDULE:FILE
393 : int rowCnt;
394 :
395 801 : std::string subString;
396 : int MaxNums1;
397 : char ColumnSep;
398 : bool FileIntervalInterpolated;
399 : int rowLimitCount;
400 : int skiprowCount;
401 : int curcolCount;
402 801 : int numerrors = 0;
403 :
404 801 : auto const &s_glob = state.dataGlobal;
405 801 : auto const &s_ip = state.dataInputProcessing->inputProcessor;
406 801 : auto const &s_sched = state.dataSched;
407 :
408 801 : if (s_sched->ScheduleInputProcessed) {
409 0 : return;
410 : }
411 :
412 801 : s_sched->ScheduleInputProcessed = true;
413 :
414 801 : int MaxNums = 1; // Need at least 1 number because it's used as a local variable in the Schedule Types loop
415 801 : int MaxAlps = 0;
416 :
417 801 : std::string CurrentModuleObject = "ScheduleTypeLimits";
418 801 : int NumScheduleTypes = s_ip->getNumObjectsFound(state, CurrentModuleObject);
419 801 : if (NumScheduleTypes > 0) {
420 799 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
421 799 : MaxNums = max(MaxNums, NumNumbers);
422 799 : MaxAlps = max(MaxAlps, NumAlphas);
423 : }
424 801 : CurrentModuleObject = "Schedule:Day:Hourly";
425 801 : int NumHrDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
426 801 : if (NumHrDaySchedules > 0) {
427 17 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
428 17 : MaxNums = max(MaxNums, NumNumbers);
429 17 : MaxAlps = max(MaxAlps, NumAlphas);
430 : }
431 801 : CurrentModuleObject = "Schedule:Day:Interval";
432 801 : int NumIntDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
433 801 : if (NumIntDaySchedules > 0) {
434 9 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
435 9 : MaxNums = max(MaxNums, NumNumbers);
436 9 : MaxAlps = max(MaxAlps, NumAlphas);
437 : }
438 801 : CurrentModuleObject = "Schedule:Day:List";
439 801 : int NumLstDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
440 801 : if (NumLstDaySchedules > 0) {
441 1 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
442 1 : MaxNums = max(MaxNums, NumNumbers);
443 1 : MaxAlps = max(MaxAlps, NumAlphas);
444 : }
445 801 : CurrentModuleObject = "Schedule:Week:Daily";
446 801 : int NumRegWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
447 801 : if (NumRegWeekSchedules > 0) {
448 19 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
449 19 : MaxNums = max(MaxNums, NumNumbers);
450 19 : MaxAlps = max(MaxAlps, NumAlphas);
451 : }
452 801 : CurrentModuleObject = "Schedule:Week:Compact";
453 801 : int NumCptWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
454 801 : if (NumCptWeekSchedules > 0) {
455 4 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
456 4 : MaxNums = max(MaxNums, NumNumbers);
457 4 : MaxAlps = max(MaxAlps, NumAlphas);
458 : }
459 801 : CurrentModuleObject = "Schedule:Year";
460 801 : int NumRegSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
461 801 : if (NumRegSchedules > 0) {
462 23 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
463 23 : MaxNums = max(MaxNums, NumNumbers);
464 23 : MaxAlps = max(MaxAlps, NumAlphas);
465 : }
466 801 : CurrentModuleObject = "Schedule:Compact";
467 801 : int NumCptSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
468 801 : if (NumCptSchedules > 0) {
469 771 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
470 771 : MaxNums = max(MaxNums, NumNumbers);
471 771 : MaxAlps = max(MaxAlps, NumAlphas + 1);
472 : }
473 801 : CurrentModuleObject = "Schedule:File";
474 801 : int NumCommaFileSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
475 801 : if (NumCommaFileSchedules > 0) {
476 8 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
477 8 : MaxNums = max(MaxNums, NumNumbers);
478 8 : MaxAlps = max(MaxAlps, NumAlphas);
479 : }
480 :
481 801 : CurrentModuleObject = "Schedule:Constant";
482 801 : int NumConstantSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
483 801 : if (NumConstantSchedules > 0) {
484 95 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
485 95 : MaxNums = max(MaxNums, NumNumbers);
486 95 : MaxAlps = max(MaxAlps, NumAlphas);
487 : }
488 801 : CurrentModuleObject = "ExternalInterface:Schedule";
489 801 : int NumExternalInterfaceSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
490 : // added for FMI
491 801 : if (NumExternalInterfaceSchedules > 0) {
492 0 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
493 0 : MaxNums = max(MaxNums, NumNumbers);
494 0 : MaxAlps = max(MaxAlps, NumAlphas + 1);
495 : }
496 : // added for FMU Import
497 801 : CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
498 801 : int NumExternalInterfaceFunctionalMockupUnitImportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
499 801 : if (NumExternalInterfaceFunctionalMockupUnitImportSchedules > 0) {
500 1 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
501 1 : MaxNums = max(MaxNums, NumNumbers);
502 1 : MaxAlps = max(MaxAlps, NumAlphas + 1);
503 : }
504 : // added for FMU Export
505 801 : CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule";
506 801 : int NumExternalInterfaceFunctionalMockupUnitExportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
507 801 : if (NumExternalInterfaceFunctionalMockupUnitExportSchedules > 0) {
508 0 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
509 0 : MaxNums = max(MaxNums, NumNumbers);
510 0 : MaxAlps = max(MaxAlps, NumAlphas + 1);
511 : }
512 801 : CurrentModuleObject = "Output:Schedules";
513 801 : s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
514 801 : MaxNums = max(MaxNums, NumNumbers);
515 801 : MaxAlps = max(MaxAlps, NumAlphas);
516 :
517 801 : Alphas.allocate(MaxAlps); // Maximum Alphas possible
518 801 : cAlphaFields.allocate(MaxAlps);
519 801 : cNumericFields.allocate(MaxNums);
520 801 : Numbers.dimension(MaxNums, 0.0); // Maximum Numbers possible
521 801 : lAlphaBlanks.dimension(MaxAlps, true);
522 801 : lNumericBlanks.dimension(MaxNums, true);
523 :
524 : // Prescan to determine extra day and week schedules due to compact schedule input
525 801 : CurrentModuleObject = "Schedule:Compact";
526 801 : MaxNums1 = 0;
527 :
528 17373 : for (int LoopIndex = 1; LoopIndex <= NumCptSchedules; ++LoopIndex) {
529 16572 : s_ip->getObjectItem(state, CurrentModuleObject, LoopIndex, Alphas, NumAlphas, Numbers, NumNumbers, Status);
530 : // # 'THROUGH" => Number of additional week schedules
531 : // # 'FOR' => Number of additional day schedules
532 234890 : for (Count = 3; Count <= NumAlphas; ++Count) {
533 218318 : if (has_prefix(Alphas(Count), "UNTIL")) {
534 80036 : ++MaxNums1;
535 : }
536 : }
537 : }
538 801 : if (MaxNums1 > MaxNums) {
539 750 : MaxNums = MaxNums1;
540 750 : cNumericFields.deallocate();
541 750 : Numbers.deallocate();
542 750 : lNumericBlanks.deallocate();
543 750 : cNumericFields.allocate(MaxNums);
544 750 : Numbers.dimension(MaxNums, 0.0); // Maximum Numbers possible
545 750 : lNumericBlanks.dimension(MaxNums, true);
546 : }
547 :
548 : // add week and day schedules for each FILE:COMMA schedule
549 :
550 801 : CurrentModuleObject = "Schedule:File:Shading";
551 801 : int NumCommaFileShading = s_ip->getNumObjectsFound(state, CurrentModuleObject);
552 801 : NumAlphas = 0;
553 801 : NumNumbers = 0;
554 801 : if (NumCommaFileShading > 1) {
555 0 : ShowWarningError(state, format("{}: More than 1 occurrence of this object found, only first will be used.", CurrentModuleObject));
556 : }
557 :
558 801 : std::map<fs::path, nlohmann::json>::iterator schedule_file_shading_result;
559 801 : if (NumCommaFileShading != 0) {
560 1 : s_ip->getObjectItem(state,
561 : CurrentModuleObject,
562 : 1,
563 : Alphas,
564 : NumAlphas,
565 : Numbers,
566 : NumNumbers,
567 : Status,
568 : lNumericBlanks,
569 : lAlphaBlanks,
570 : cAlphaFields,
571 : cNumericFields);
572 1 : std::string ShadingSunlitFracFileName = Alphas(1);
573 :
574 1 : std::string contextString = CurrentModuleObject + ", " + cAlphaFields(1) + ": ";
575 1 : state.files.TempFullFilePath.filePath = CheckForActualFilePath(state, ShadingSunlitFracFileName, contextString);
576 :
577 1 : if (state.files.TempFullFilePath.filePath.empty()) {
578 0 : ShowFatalError(state, "Program terminates due to previous condition.");
579 : }
580 :
581 1 : if (state.dataEnvrn->CurrentYearIsLeapYear) {
582 0 : rowLimitCount = 366 * Constant::iHoursInDay * s_glob->TimeStepsInHour;
583 : } else {
584 1 : rowLimitCount = 365 * Constant::iHoursInDay * s_glob->TimeStepsInHour;
585 : }
586 1 : ColumnSep = CharComma;
587 :
588 1 : schedule_file_shading_result = s_sched->UniqueProcessedExternalFiles.find(state.files.TempFullFilePath.filePath);
589 1 : if (schedule_file_shading_result == s_sched->UniqueProcessedExternalFiles.end()) {
590 :
591 1 : FileSystem::FileTypes const ext = FileSystem::getFileType(state.files.TempFullFilePath.filePath);
592 1 : if (FileSystem::is_flat_file_type(ext)) {
593 1 : auto const schedule_data = FileSystem::readFile(state.files.TempFullFilePath.filePath);
594 1 : CsvParser csvParser;
595 1 : skiprowCount = 1; // make sure to parse header row only for Schedule:File:Shading
596 1 : auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
597 1 : csvParser.decode(schedule_data, ColumnSep, skiprowCount));
598 1 : if (csvParser.hasErrors()) {
599 0 : for (const auto &[error, isContinued] : csvParser.errors()) {
600 0 : if (isContinued) {
601 0 : ShowContinueError(state, error);
602 : } else {
603 0 : ShowSevereError(state, error);
604 : }
605 0 : }
606 0 : ShowContinueError(state, fmt::format("Error Occurred in {}", state.files.TempFullFilePath.filePath));
607 0 : ShowFatalError(state, "Program terminates due to previous condition.");
608 : }
609 1 : schedule_file_shading_result = it.first;
610 1 : } else if (FileSystem::is_all_json_type(ext)) {
611 0 : auto schedule_data = FileSystem::readJSON(state.files.TempFullFilePath.filePath);
612 : auto it = // (AUTO_OK_ITER)
613 0 : s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath, std::move(schedule_data));
614 0 : schedule_file_shading_result = it.first;
615 0 : } else {
616 0 : ShowSevereError(state,
617 0 : fmt::format(R"({}: {}="{}", {}="{}" has an unknown file extension and cannot be read by this program.)",
618 : routineName,
619 : CurrentModuleObject,
620 : Alphas(1),
621 : cAlphaFields(3),
622 : Alphas(3)));
623 0 : ShowFatalError(state, "Program terminates due to previous condition.");
624 : }
625 : }
626 :
627 1 : auto const &column_json = schedule_file_shading_result->second["values"].at(0); // assume there is at least 1 column
628 1 : rowCnt = column_json.size();
629 : int NumCSVAllColumnsSchedules =
630 1 : schedule_file_shading_result->second["header"].get<std::set<std::string>>().size() - 1; // -1 to account for timestamp column
631 :
632 1 : if (schedule_file_shading_result->second["header"].back().get<std::string>() == "()") {
633 0 : ShowWarningError(state,
634 0 : format("{}: {}=\"{}\" Removing last column of the CSV since it has '()' for the surface name.",
635 : routineName,
636 : CurrentModuleObject,
637 : Alphas(1)));
638 0 : ShowContinueError(state, "This was a problem in E+ 22.2.0 and below, consider removing it from the file to suppress this warning.");
639 0 : schedule_file_shading_result->second["header"].erase(NumCSVAllColumnsSchedules);
640 0 : assert(schedule_file_shading_result->second["header"].size() == schedule_file_shading_result->second["values"].size());
641 0 : --NumCSVAllColumnsSchedules;
642 : }
643 :
644 1 : if (rowCnt != rowLimitCount) {
645 0 : if (rowCnt < rowLimitCount) {
646 0 : ShowSevereError(state, format("{}: {}=\"{}\" {} data values read.", routineName, CurrentModuleObject, Alphas(1), rowCnt));
647 0 : } else if (rowCnt > rowLimitCount) {
648 0 : ShowSevereError(state, format("{}: {}=\"{}\" too many data values read.", routineName, CurrentModuleObject, Alphas(1)));
649 : }
650 0 : ShowContinueError(
651 : state,
652 0 : format("Number of rows in the shading file must be a full year multiplied by the simulation TimeStep: {}.", rowLimitCount));
653 0 : ShowFatalError(state, "Program terminates due to previous condition.");
654 : }
655 :
656 : // schedule values have been filled into the CSVAllColumnNameAndValues map.
657 1 : s_sched->ScheduleFileShadingProcessed = true;
658 :
659 1 : if (numerrors > 0) {
660 0 : ShowWarningError(
661 : state,
662 0 : format(
663 : "{}:{}=\"{}\" {} records had errors - these values are set to 0.", routineName, CurrentModuleObject, Alphas(1), numerrors));
664 : }
665 1 : }
666 :
667 : //! Most initializations in the schedule data structures are taken care of in
668 : //! the definitions (see above)
669 :
670 1602 : print(state.files.audit.ensure_open(state, "ProcessScheduleInput", state.files.outputControl.audit),
671 : "{}\n",
672 : " Processing Schedule Input -- Start");
673 :
674 : //!! Get Schedule Types
675 :
676 801 : CurrentModuleObject = "ScheduleTypeLimits";
677 5080 : for (int Loop = 1; Loop <= NumScheduleTypes; ++Loop) {
678 4279 : s_ip->getObjectItem(state,
679 : CurrentModuleObject,
680 : Loop,
681 : Alphas,
682 : NumAlphas,
683 : Numbers,
684 : NumNumbers,
685 : Status,
686 : lNumericBlanks,
687 : lAlphaBlanks,
688 : cAlphaFields,
689 : cNumericFields);
690 :
691 4279 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
692 :
693 4279 : if (s_sched->scheduleTypeMap.find(Alphas(1)) != s_sched->scheduleTypeMap.end()) {
694 0 : ShowSevereDuplicateName(state, eoh);
695 0 : ErrorsFound = true;
696 0 : continue;
697 : }
698 :
699 4279 : auto *schedType = new ScheduleType;
700 4279 : schedType->Name = Alphas(1);
701 :
702 4279 : schedType->Num = (int)s_sched->scheduleTypes.size();
703 4279 : s_sched->scheduleTypes.push_back(schedType);
704 4279 : s_sched->scheduleTypeMap.insert_or_assign(schedType->Name, schedType->Num);
705 :
706 4279 : schedType->isLimited = !lNumericBlanks(1) && !lNumericBlanks(2);
707 :
708 4279 : if (!lNumericBlanks(1)) {
709 3293 : schedType->minVal = Numbers(1);
710 : }
711 4279 : if (!lNumericBlanks(2)) {
712 3284 : schedType->maxVal = Numbers(2);
713 : }
714 :
715 4279 : if (schedType->isLimited) {
716 3284 : if (Alphas(2) == "DISCRETE" || Alphas(2) == "INTEGER") {
717 1436 : schedType->isReal = false;
718 1848 : } else if (Alphas(2) == "CONTINUOUS" || Alphas(2) == "REAL") {
719 1848 : schedType->isReal = true;
720 : } else {
721 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(2), Alphas(2));
722 0 : ErrorsFound = true;
723 : }
724 : }
725 :
726 4279 : if (NumAlphas >= 3 && !lAlphaBlanks(3)) {
727 591 : schedType->limitUnits = static_cast<LimitUnits>(getEnumValue(limitUnitNamesUC, Alphas(3)));
728 591 : if (schedType->limitUnits == LimitUnits::Invalid) {
729 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(3), Alphas(3));
730 0 : ErrorsFound = true;
731 : }
732 : }
733 :
734 4279 : if (schedType->isLimited && schedType->minVal > schedType->maxVal) {
735 0 : if (schedType->isReal) {
736 0 : ShowSevereCustom(
737 0 : state, eoh, format("{} [{:.2R}] > {} [{:.2R}].", cNumericFields(1), schedType->minVal, cNumericFields(2), schedType->maxVal));
738 : } else {
739 0 : ShowSevereCustom(
740 0 : state, eoh, format("{} [{:.0R}] > {} [{:.0R}].", cNumericFields(1), schedType->minVal, cNumericFields(2), schedType->maxVal));
741 : }
742 0 : ShowContinueError(state, " Other warning/severes about schedule values may appear.");
743 : }
744 : } // for (Loop)
745 :
746 : //!! Get Day Schedules (all types)
747 :
748 : //!!=> Get "DAYSCHEDULE" (Hourly)
749 :
750 801 : Count = 0;
751 801 : CurrentModuleObject = "Schedule:Day:Hourly";
752 974 : for (int Loop = 1; Loop <= NumHrDaySchedules; ++Loop) {
753 173 : s_ip->getObjectItem(state,
754 : CurrentModuleObject,
755 : Loop,
756 : Alphas,
757 : NumAlphas,
758 : Numbers,
759 : NumNumbers,
760 : Status,
761 : lNumericBlanks,
762 : lAlphaBlanks,
763 : cAlphaFields,
764 : cNumericFields);
765 :
766 173 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
767 :
768 173 : if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
769 0 : ShowSevereDuplicateName(state, eoh);
770 0 : ErrorsFound = true;
771 0 : continue;
772 : }
773 :
774 173 : auto *daySched = AddDaySchedule(state, Alphas(1));
775 :
776 : // Validate ScheduleType
777 173 : if (lAlphaBlanks(2)) {
778 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
779 0 : ShowContinueError(state, "Schedule will not be validated.");
780 173 : } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
781 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
782 0 : ShowContinueError(state, "Schedule will not be validated.");
783 : }
784 :
785 173 : daySched->interpolation = Interpolation::No;
786 :
787 4325 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
788 28104 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
789 23952 : daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = Numbers(hr + 1);
790 23952 : daySched->sumTsVals += daySched->tsVals[hr * s_glob->TimeStepsInHour + ts];
791 : }
792 : }
793 :
794 173 : if (daySched->checkValsForLimitViolations(state)) {
795 0 : ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
796 : }
797 :
798 173 : if (daySched->checkValsForBadIntegers(state)) {
799 0 : ShowWarningCustom(state, eoh, format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2)));
800 : }
801 :
802 : } // for (Loop)
803 :
804 : //!! Get "DaySchedule:Interval"
805 :
806 801 : CurrentModuleObject = "Schedule:Day:Interval";
807 1154 : for (int Loop = 1; Loop <= NumIntDaySchedules; ++Loop) {
808 353 : s_ip->getObjectItem(state,
809 : CurrentModuleObject,
810 : Loop,
811 : Alphas,
812 : NumAlphas,
813 : Numbers,
814 : NumNumbers,
815 : Status,
816 : lNumericBlanks,
817 : lAlphaBlanks,
818 : cAlphaFields,
819 : cNumericFields);
820 :
821 353 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
822 :
823 353 : if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
824 0 : ShowSevereDuplicateName(state, eoh);
825 0 : ErrorsFound = true;
826 0 : continue;
827 : }
828 :
829 353 : auto *daySched = AddDaySchedule(state, Alphas(1));
830 :
831 : // Validate ScheduleType
832 353 : if (lAlphaBlanks(2)) {
833 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
834 0 : ShowContinueError(state, "Schedule will not be validated.");
835 353 : } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
836 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
837 0 : ShowContinueError(state, "Schedule will not be validated.");
838 : }
839 :
840 353 : NumFields = NumAlphas - 3;
841 : // check to see if numfield=0
842 353 : if (NumFields == 0) {
843 0 : ShowSevereCustom(state,
844 : eoh,
845 0 : format("Insufficient data entered for a full schedule day."
846 : "Number of interval fields == [{}].",
847 : NumFields));
848 0 : ErrorsFound = true;
849 : }
850 :
851 : // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
852 353 : daySched->interpolation = static_cast<Interpolation>(getEnumValue(interpolationNamesUC, Alphas(3)));
853 353 : if (daySched->interpolation == Interpolation::Invalid) {
854 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(3), Alphas(3));
855 0 : ErrorsFound = true;
856 : }
857 :
858 353 : ProcessIntervalFields(state,
859 1412 : Alphas({4, _}),
860 : Numbers,
861 : NumFields,
862 : NumNumbers,
863 : minuteVals,
864 : setMinuteVals,
865 : ErrorsFound,
866 353 : Alphas(1),
867 : CurrentModuleObject,
868 : daySched->interpolation);
869 :
870 : // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule()
871 353 : daySched->populateFromMinuteVals(state, minuteVals);
872 :
873 353 : if (daySched->checkValsForLimitViolations(state)) {
874 0 : ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
875 : }
876 :
877 353 : if (daySched->checkValsForBadIntegers(state)) {
878 0 : ShowWarningCustom(state, eoh, format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2)));
879 : }
880 : }
881 :
882 : //!! Get "DaySchedule:List"
883 :
884 801 : CurrentModuleObject = "Schedule:Day:List";
885 807 : for (int Loop = 1; Loop <= NumLstDaySchedules; ++Loop) {
886 6 : s_ip->getObjectItem(state,
887 : CurrentModuleObject,
888 : Loop,
889 : Alphas,
890 : NumAlphas,
891 : Numbers,
892 : NumNumbers,
893 : Status,
894 : lNumericBlanks,
895 : lAlphaBlanks,
896 : cAlphaFields,
897 : cNumericFields);
898 :
899 6 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
900 :
901 6 : if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
902 0 : ShowSevereDuplicateName(state, eoh);
903 0 : ErrorsFound = true;
904 0 : continue;
905 : }
906 :
907 6 : auto *daySched = AddDaySchedule(state, Alphas(1));
908 :
909 : // Validate ScheduleType
910 6 : if (lAlphaBlanks(2)) {
911 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
912 0 : ShowContinueError(state, "Schedule will not be validated.");
913 6 : } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
914 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
915 0 : ShowContinueError(state, "Schedule will not be validated.");
916 : }
917 :
918 : // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
919 6 : daySched->interpolation = static_cast<Interpolation>(getEnumValue(interpolationNamesUC, Alphas(3)));
920 :
921 : // check to see if there are any fields
922 6 : if (Numbers(1) <= 0.0) {
923 0 : ShowSevereCustom(state,
924 : eoh,
925 0 : format("Insufficient data entered for a full schedule day."
926 : "...Minutes per Item field = [{}].",
927 : Numbers(1)));
928 0 : ErrorsFound = true;
929 0 : continue;
930 : }
931 6 : if (NumNumbers < 25) {
932 0 : ShowSevereCustom(state,
933 : eoh,
934 0 : format("Insufficient data entered for a full schedule day."
935 : "...Minutes per Item field = [{}] and only [{}] to apply to list fields.",
936 : Numbers(1),
937 0 : NumNumbers - 1));
938 0 : ErrorsFound = true;
939 0 : continue;
940 : }
941 :
942 6 : MinutesPerItem = int(Numbers(1));
943 6 : NumExpectedItems = 1440 / MinutesPerItem;
944 6 : if ((NumNumbers - 1) != NumExpectedItems) {
945 0 : ShowSevereCustom(state,
946 : eoh,
947 0 : format("Number of Entered Items={} not equal number of expected items={}"
948 : "based on {}={}",
949 0 : NumNumbers - 1,
950 : NumExpectedItems,
951 : cNumericFields(1),
952 : MinutesPerItem));
953 0 : ErrorsFound = true;
954 0 : continue;
955 : }
956 :
957 6 : if (mod(Constant::iMinutesInHour, MinutesPerItem) != 0) {
958 0 : ShowSevereCustom(state, eoh, format("{}={} not evenly divisible into 60", cNumericFields(1), MinutesPerItem));
959 0 : ErrorsFound = true;
960 0 : continue;
961 : }
962 :
963 : // Number of numbers in the Numbers list okay to process
964 6 : int hr = 0;
965 6 : int begMin = 0;
966 6 : int endMin = MinutesPerItem - 1;
967 438 : for (int NumFields = 2; NumFields <= NumNumbers; ++NumFields) {
968 9072 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
969 8640 : minuteVals[hr * Constant::iMinutesInHour + iMin] = Numbers(NumFields);
970 : }
971 432 : begMin = endMin + 1;
972 432 : endMin += MinutesPerItem;
973 432 : if (endMin >= Constant::iMinutesInHour) {
974 144 : endMin = MinutesPerItem - 1;
975 144 : begMin = 0;
976 144 : ++hr;
977 : }
978 : }
979 :
980 : // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule()
981 6 : daySched->populateFromMinuteVals(state, minuteVals);
982 :
983 6 : if (daySched->checkValsForLimitViolations(state)) {
984 0 : ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
985 : }
986 :
987 6 : if (daySched->checkValsForBadIntegers(state)) {
988 0 : ShowWarningCustom(state, eoh, format("One or more values are not integer for {}={}", cAlphaFields(2), Alphas(2)));
989 : }
990 : }
991 :
992 : //!! Get Week Schedules - regular
993 :
994 801 : CurrentModuleObject = "Schedule:Week:Daily";
995 1148 : for (int Loop = 1; Loop <= NumRegWeekSchedules; ++Loop) {
996 347 : s_ip->getObjectItem(state,
997 : CurrentModuleObject,
998 : Loop,
999 : Alphas,
1000 : NumAlphas,
1001 : Numbers,
1002 : NumNumbers,
1003 : Status,
1004 : lNumericBlanks,
1005 : lAlphaBlanks,
1006 : cAlphaFields,
1007 : cNumericFields);
1008 :
1009 347 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1010 :
1011 347 : if (s_sched->weekScheduleMap.find(Alphas(1)) != s_sched->weekScheduleMap.end()) {
1012 0 : ShowSevereDuplicateName(state, eoh);
1013 0 : ErrorsFound = true;
1014 0 : continue;
1015 : }
1016 :
1017 347 : auto *weekSched = AddWeekSchedule(state, Alphas(1));
1018 :
1019 : // Rest of Alphas are processed into schedule nums
1020 4511 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
1021 4164 : if ((weekSched->dayScheds[iDayType] = GetDaySchedule(state, Alphas(iDayType + 1))) == nullptr) {
1022 0 : ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(iDayType + 1), Alphas(iDayType + 1));
1023 0 : ErrorsFound = true;
1024 : }
1025 : } // for (iDayType)
1026 : }
1027 :
1028 : //!! Get Week Schedules - compact
1029 801 : Count = NumRegWeekSchedules;
1030 801 : CurrentModuleObject = "Schedule:Week:Compact";
1031 853 : for (int Loop = 1; Loop <= NumCptWeekSchedules; ++Loop) {
1032 52 : s_ip->getObjectItem(state,
1033 : CurrentModuleObject,
1034 : Loop,
1035 : Alphas,
1036 : NumAlphas,
1037 : Numbers,
1038 : NumNumbers,
1039 : Status,
1040 : lNumericBlanks,
1041 : lAlphaBlanks,
1042 : cAlphaFields,
1043 : cNumericFields);
1044 :
1045 52 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1046 :
1047 52 : if (s_sched->weekScheduleMap.find(Alphas(1)) != s_sched->weekScheduleMap.end()) {
1048 0 : ShowSevereDuplicateName(state, eoh);
1049 0 : ErrorsFound = true;
1050 0 : continue;
1051 : }
1052 :
1053 52 : auto *weekSched = AddWeekSchedule(state, Alphas(1));
1054 :
1055 52 : std::fill(allDays.begin(), allDays.end(), false);
1056 : // Rest of Alphas are processed into schedule indices
1057 140 : for (int idx = 2; idx <= NumAlphas; idx += 2) {
1058 88 : auto *daySched = GetDaySchedule(state, Alphas(idx + 1));
1059 88 : if (daySched == nullptr) {
1060 0 : ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(idx + 1), Alphas(idx + 1));
1061 0 : ShowContinueError(state, format("ref: {} \"{}\"", cAlphaFields(idx), Alphas(idx)));
1062 0 : ErrorsFound = true;
1063 : } else {
1064 88 : std::fill(theseDays.begin(), theseDays.end(), false);
1065 88 : ErrorHere = false;
1066 88 : ProcessForDayTypes(state, Alphas(idx), theseDays, allDays, ErrorHere);
1067 88 : if (ErrorHere) {
1068 0 : ShowContinueError(state, format("{}: {}=\"{}", routineName, CurrentModuleObject, Alphas(1)));
1069 0 : ErrorsFound = true;
1070 : } else {
1071 1144 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
1072 1056 : if (theseDays[iDayType]) {
1073 624 : weekSched->dayScheds[iDayType] = daySched;
1074 : }
1075 : }
1076 : }
1077 : }
1078 : }
1079 :
1080 : // Have processed all named days, check to make sure all given
1081 676 : for (int iDayType = iDayType_Sun; iDayType < (int)DayType::Num; ++iDayType) {
1082 624 : if (allDays[iDayType] == true) {
1083 624 : continue;
1084 : }
1085 0 : ShowSevereError(state, format("{}: {}=\"{}\", Missing some day assignments", routineName, CurrentModuleObject, Alphas(1)));
1086 0 : ErrorsFound = true;
1087 0 : break;
1088 : }
1089 : }
1090 801 : NumRegWeekSchedules = Count;
1091 :
1092 : //!! Get Schedules (all types)
1093 :
1094 : //!! Get Regular Schedules
1095 :
1096 801 : CurrentModuleObject = "Schedule:Year";
1097 978 : for (int Loop = 1; Loop <= NumRegSchedules; ++Loop) {
1098 177 : s_ip->getObjectItem(state,
1099 : CurrentModuleObject,
1100 : Loop,
1101 : Alphas,
1102 : NumAlphas,
1103 : Numbers,
1104 : NumNumbers,
1105 : Status,
1106 : lNumericBlanks,
1107 : lAlphaBlanks,
1108 : cAlphaFields,
1109 : cNumericFields);
1110 :
1111 177 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1112 :
1113 177 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1114 0 : ShowSevereDuplicateName(state, eoh);
1115 0 : ErrorsFound = true;
1116 0 : continue;
1117 : }
1118 :
1119 177 : auto *sched = AddScheduleDetailed(state, Alphas(1));
1120 :
1121 : // Validate ScheduleType
1122 177 : if (lAlphaBlanks(2)) {
1123 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1124 0 : ShowContinueError(state, "Schedule will not be validated.");
1125 177 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1126 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1127 0 : ShowContinueError(state, "Schedule will not be validated.");
1128 : }
1129 :
1130 177 : int NumPointer = 0;
1131 :
1132 : std::array<int, 367> daysInYear;
1133 177 : std::fill(daysInYear.begin(), daysInYear.end(), 0);
1134 :
1135 : // Rest of Alphas (Weekschedules) are processed into Pointers
1136 583 : for (int idx = 3; idx <= NumAlphas; ++idx) {
1137 406 : auto *weekSched = GetWeekSchedule(state, Alphas(idx));
1138 406 : if (weekSched == nullptr) {
1139 0 : ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(idx), Alphas(idx));
1140 0 : ErrorsFound = true;
1141 0 : continue;
1142 : }
1143 :
1144 : // Process for month, day
1145 406 : int StartMonth = int(Numbers(NumPointer + 1));
1146 406 : int StartDay = int(Numbers(NumPointer + 2));
1147 406 : int EndMonth = int(Numbers(NumPointer + 3));
1148 406 : int EndDay = int(Numbers(NumPointer + 4));
1149 406 : NumPointer += 4;
1150 406 : int StartPointer = General::OrdinalDay(StartMonth, StartDay, 1);
1151 406 : int EndPointer = General::OrdinalDay(EndMonth, EndDay, 1);
1152 406 : if (StartPointer <= EndPointer) {
1153 65188 : for (int Count = StartPointer; Count <= EndPointer; ++Count) {
1154 64782 : ++daysInYear[Count];
1155 64782 : sched->weekScheds[Count] = weekSched;
1156 : }
1157 : } else {
1158 0 : for (int Count = StartPointer; Count <= 366; ++Count) {
1159 0 : ++daysInYear[Count];
1160 0 : sched->weekScheds[Count] = weekSched;
1161 : }
1162 0 : for (int Count = 1; Count <= EndPointer; ++Count) {
1163 0 : ++daysInYear[Count];
1164 0 : sched->weekScheds[Count] = weekSched;
1165 : }
1166 : }
1167 : }
1168 :
1169 : // Perform Error checks on this item
1170 : // Do special test for Feb 29. Make equal to Feb 28.
1171 177 : if (daysInYear[60] == 0) {
1172 0 : daysInYear[60] = daysInYear[59];
1173 0 : sched->weekScheds[60] = sched->weekScheds[59];
1174 : }
1175 :
1176 64959 : for (int iDay = 1; iDay <= 366; ++iDay) {
1177 64782 : if (daysInYear[iDay] == 0) {
1178 0 : ShowSevereCustomAudit(state, eoh, "has missing days in its schedule pointers");
1179 0 : ErrorsFound = true;
1180 0 : break;
1181 64782 : } else if (daysInYear[iDay] > 1) {
1182 0 : ShowSevereCustomAudit(state, eoh, "has overlapping days in its schedule pointers");
1183 0 : ErrorsFound = true;
1184 0 : break;
1185 : }
1186 : }
1187 :
1188 : // What does it mean to actuate a schedule?
1189 177 : if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
1190 70 : SetupEMSActuator(state, "Schedule:Year", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
1191 : }
1192 : }
1193 :
1194 : //!! Get Compact Schedules
1195 : // SCHEDULE:COMPACT,
1196 : // \memo Irregular object. Does not follow the usual definition for fields. Fields A3... are:
1197 : // \memo Through: Date
1198 : // \memo For: Applicable days (ref: Weekschedule:Compact)
1199 : // \memo Interpolate: Yes/No (ref: Dayschedule:interval) -- optional, if not used will be "No"
1200 : // \memo Until: <Time> (ref: Dayschedule:Interval)
1201 : // \memo <numeric value>
1202 : // \memo words "Through","For","Interpolate","Until" must be included.
1203 : // A1 , \field Name
1204 : // \required-field
1205 : // \type alpha
1206 : // \reference ScheduleNames
1207 : // A2 , \field ScheduleType
1208 : // \type object-list
1209 : // \object-list ScheduleTypeNames
1210 : // A3 , \field Complex Field #1
1211 : // A4 , \field Complex Field #2
1212 : // A5 , \field Complex Field #3
1213 :
1214 801 : SchNum = NumRegSchedules;
1215 801 : CurrentModuleObject = "Schedule:Compact";
1216 17373 : for (int Loop = 1; Loop <= NumCptSchedules; ++Loop) {
1217 16572 : s_ip->getObjectItem(state,
1218 : CurrentModuleObject,
1219 : Loop,
1220 : Alphas,
1221 : NumAlphas,
1222 : Numbers,
1223 : NumNumbers,
1224 : Status,
1225 : lNumericBlanks,
1226 : lAlphaBlanks,
1227 : cAlphaFields,
1228 : cNumericFields);
1229 :
1230 16572 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1231 :
1232 16572 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1233 0 : ShowSevereDuplicateName(state, eoh);
1234 0 : ErrorsFound = true;
1235 0 : continue;
1236 : }
1237 :
1238 16572 : auto *sched = AddScheduleDetailed(state, Alphas(1));
1239 16572 : sched->type = SchedType::Compact;
1240 :
1241 : // Validate ScheduleType
1242 16572 : if (lAlphaBlanks(2)) {
1243 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1244 0 : ShowContinueError(state, "Schedule will not be validated.");
1245 16572 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1246 10 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1247 30 : ShowContinueError(state, "Schedule will not be validated.");
1248 : }
1249 :
1250 16572 : NumPointer = 0;
1251 :
1252 : std::array<int, 367> daysInYear;
1253 16572 : std::fill(daysInYear.begin() + 1, daysInYear.end(), 0);
1254 : // Process the "complex" fields -- so named because they are not a 1:1 correspondence
1255 : // as other objects are
1256 16572 : NumField = 3;
1257 16572 : StartPointer = 1;
1258 16572 : WkCount = 0;
1259 16572 : DyCount = 0;
1260 16572 : bool FullYearSet = false;
1261 39691 : while (NumField < NumAlphas) {
1262 : // Process "Through"
1263 23119 : if (!has_prefix(Alphas(NumField), "THROUGH:") && !has_prefix(Alphas(NumField), "THROUGH")) {
1264 0 : ShowSevereCustom(state, eoh, format("Expecting \"Through:\" date, instead found entry={}", Alphas(NumField)));
1265 0 : ErrorsFound = true;
1266 0 : goto Through_exit;
1267 : }
1268 :
1269 23119 : int sPos = (Alphas(NumField)[7] == ':') ? 8 : 7;
1270 23119 : Alphas(NumField).erase(0, sPos);
1271 23119 : strip(Alphas(NumField));
1272 :
1273 23119 : CurrentThrough = Alphas(NumField);
1274 23119 : ErrorHere = false;
1275 23119 : ProcessDateString(state, Alphas(NumField), EndMonth, EndDay, PWeekDay, PDateType, ErrorHere);
1276 23119 : if (PDateType == Weather::DateType::NthDayInMonth || PDateType == Weather::DateType::LastDayInMonth) {
1277 0 : ShowSevereCustom(state, eoh, format("Invalid \"Through:\" date, found entry={}", Alphas(NumField)));
1278 0 : ErrorsFound = true;
1279 0 : goto Through_exit;
1280 : }
1281 :
1282 23119 : if (ErrorHere) {
1283 0 : ShowSevereCustom(state, eoh, "Invalid \"Through:\" date");
1284 0 : ErrorsFound = true;
1285 0 : goto Through_exit;
1286 : }
1287 :
1288 23119 : EndPointer = General::OrdinalDay(EndMonth, EndDay, 1);
1289 23119 : if (EndPointer == 366) {
1290 16572 : if (FullYearSet) {
1291 0 : ShowSevereCustom(
1292 0 : state, eoh, format("New \"Through\" entry when \"full year\" already set \"Through\" field={}", CurrentThrough));
1293 0 : ErrorsFound = true;
1294 : }
1295 16572 : FullYearSet = true;
1296 : }
1297 :
1298 23119 : ++WkCount;
1299 :
1300 23119 : auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", Alphas(1), WkCount));
1301 23119 : weekSched->isUsed = true;
1302 :
1303 6088471 : for (int iDay = StartPointer; iDay <= EndPointer; ++iDay) {
1304 6065352 : sched->weekScheds[iDay] = weekSched;
1305 6065352 : ++daysInYear[iDay];
1306 : }
1307 :
1308 23119 : StartPointer = EndPointer + 1;
1309 23119 : ThruField = NumField;
1310 23119 : std::fill(allDays.begin(), allDays.end(), false);
1311 23119 : ++NumField;
1312 :
1313 57916 : while (NumField < NumAlphas) { // Continues until next "Through"
1314 41344 : if (has_prefix(Alphas(NumField), "THROUGH")) {
1315 6547 : goto For_exit;
1316 : }
1317 : // "For" must be next, adds to "# Day Schedules"
1318 34797 : if (!has_prefix(Alphas(NumField), "FOR")) {
1319 0 : ShowSevereCustom(state, eoh, format("Looking for \"For\" field, found={}", Alphas(NumField)));
1320 0 : ErrorsFound = true;
1321 0 : goto Through_exit;
1322 : }
1323 :
1324 34797 : ++DyCount;
1325 :
1326 34797 : auto *daySched = AddDaySchedule(state, format("{}_dy_{}", Alphas(1), DyCount));
1327 :
1328 34797 : daySched->schedTypeNum = sched->schedTypeNum;
1329 34797 : daySched->isUsed = true;
1330 :
1331 34797 : std::fill(theseDays.begin(), theseDays.end(), false);
1332 34797 : ErrorHere = false;
1333 34797 : LastFor = Alphas(NumField);
1334 34797 : ProcessForDayTypes(state, Alphas(NumField), theseDays, allDays, ErrorHere);
1335 34797 : if (ErrorHere) {
1336 0 : ShowContinueError(state, format("ref {}=\"{}\"", CurrentModuleObject, Alphas(1)));
1337 0 : ShowContinueError(state, format("ref Through field={}", Alphas(ThruField)));
1338 0 : ErrorsFound = true;
1339 : } else {
1340 452361 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
1341 417564 : if (theseDays[iDayType]) {
1342 277428 : weekSched->dayScheds[iDayType] = daySched;
1343 : }
1344 : }
1345 : }
1346 :
1347 : // Check for "Interpolate"
1348 34797 : ++NumField;
1349 34797 : if (has_prefix(Alphas(NumField), "INTERPOLATE") || !has_prefix(Alphas(NumField), "UNTIL")) {
1350 330 : if (has(Alphas(NumField), "NO")) {
1351 88 : daySched->interpolation = Interpolation::No;
1352 242 : } else if (has(Alphas(NumField), "AVERAGE")) {
1353 242 : daySched->interpolation = Interpolation::Average;
1354 0 : } else if (has(Alphas(NumField), "LINEAR")) {
1355 0 : daySched->interpolation = Interpolation::Linear;
1356 : } else {
1357 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(NumField), Alphas(NumField));
1358 0 : ErrorsFound = true;
1359 : }
1360 330 : ++NumField;
1361 : }
1362 :
1363 34797 : NumNumbers = 0;
1364 34797 : xxcount = 0;
1365 34797 : UntilFld = NumField;
1366 : while (true) {
1367 98261 : if (has_prefix(Alphas(NumField), "FOR")) {
1368 11678 : break;
1369 : }
1370 86583 : if (has_prefix(Alphas(NumField), "THROUGH")) {
1371 6547 : break;
1372 : }
1373 80036 : if (has_prefix(Alphas(NumField), "UNTIL")) {
1374 : // Process Until/Value pairs for later processing by other routine.
1375 80036 : ++NumField;
1376 80036 : ++xxcount;
1377 80036 : ++NumNumbers;
1378 80036 : Numbers(NumNumbers) = Util::ProcessNumber(Alphas(NumField), ErrorHere);
1379 80036 : if (ErrorHere) {
1380 0 : ShowSevereCustom(
1381 0 : state, eoh, format("Until field=[{}] has illegal value field=[{}].", Alphas(NumField - 1), Alphas(NumField)));
1382 0 : ErrorsFound = true;
1383 : }
1384 80036 : ++NumField;
1385 80036 : Alphas(UntilFld + xxcount) = Alphas(NumField); // In case next is "until"
1386 : } else {
1387 0 : ShowSevereCustom(state, eoh, format("Looking for \"Until\" field, found={}", Alphas(NumField)));
1388 0 : ErrorsFound = true;
1389 0 : goto Through_exit;
1390 : }
1391 80036 : if (Alphas(NumField).empty()) {
1392 16572 : break;
1393 : }
1394 : }
1395 :
1396 : // Process Untils, Numbers
1397 34797 : if (NumNumbers > 0) {
1398 34797 : NumFields = NumNumbers;
1399 34797 : ErrorHere = false;
1400 34797 : ProcessIntervalFields(state,
1401 139188 : Alphas({UntilFld, _}),
1402 : Numbers,
1403 : NumFields,
1404 : NumNumbers,
1405 : minuteVals,
1406 : setMinuteVals,
1407 : ErrorHere,
1408 34797 : daySched->Name,
1409 69594 : CurrentModuleObject + " DaySchedule Fields",
1410 : daySched->interpolation);
1411 : // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
1412 34797 : if (ErrorHere) {
1413 0 : ShowContinueError(state, format("ref {}=\"{}\"", CurrentModuleObject, Alphas(1)));
1414 0 : ErrorsFound = true;
1415 : }
1416 :
1417 34797 : daySched->populateFromMinuteVals(state, minuteVals);
1418 : }
1419 : }
1420 :
1421 16572 : For_exit:;
1422 300547 : for (int iDayType = iDayType_Sun; iDayType < (int)DayType::Num; ++iDayType) {
1423 277428 : if (allDays[iDayType] == true) {
1424 277428 : continue;
1425 : }
1426 :
1427 0 : ShowWarningCustom(state, eoh, format("has missing day types in Through={}", CurrentThrough));
1428 0 : ShowContinueError(state, format("Last \"For\" field={}", LastFor));
1429 0 : std::string errmsg = "Missing day types=,";
1430 0 : for (int kDayType = iDayType_Sun; kDayType < (int)DayType::Num; ++kDayType) {
1431 0 : if (allDays[kDayType]) {
1432 0 : continue;
1433 : }
1434 0 : errmsg.erase(errmsg.length() - 1);
1435 0 : errmsg = format("{} \"{}\",-", errmsg, dayTypeNames[kDayType]);
1436 : }
1437 0 : errmsg.erase(errmsg.length() - 2);
1438 0 : ShowContinueError(state, errmsg);
1439 0 : ShowContinueError(state, "Missing day types will have 0.0 as Schedule Values");
1440 0 : break;
1441 0 : }
1442 : }
1443 :
1444 16572 : Through_exit:;
1445 16572 : if (daysInYear[60] == 0) {
1446 0 : daysInYear[60] = daysInYear[59];
1447 0 : sched->weekScheds[60] = sched->weekScheds[59];
1448 : }
1449 :
1450 16572 : if (std::find(daysInYear.begin() + 1, daysInYear.end(), 0) != daysInYear.end()) {
1451 0 : ShowSevereCustomAudit(state, eoh, "has missing days in its schedule pointers");
1452 0 : ErrorsFound = true;
1453 : }
1454 6081924 : if (std::find_if(daysInYear.begin() + 1, daysInYear.end(), [](int i) { return i > 1; }) != daysInYear.end()) {
1455 0 : ShowSevereCustomAudit(state, eoh, "has overlapping days in its schedule pointers");
1456 0 : ErrorsFound = true;
1457 : }
1458 :
1459 16572 : if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
1460 3860 : SetupEMSActuator(state, "Schedule:Compact", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
1461 : }
1462 : }
1463 :
1464 : // Schedule:File,
1465 : // \min-fields 5
1466 : // \memo A Schedule:File points to a text computer file that has 8760-8784 hours of data.
1467 : // A1 , \field Name
1468 : // \required-field
1469 : // \type alpha
1470 : // \reference ScheduleNames
1471 : // A2 , \field Schedule Type Limits Name
1472 : // \type object-list
1473 : // \object-list ScheduleTypeLimitsNames
1474 : // A3 , \field File Name
1475 : // \required-field
1476 : // \retaincase
1477 : // N1 , \field Column Number
1478 : // \required-field
1479 : // \type integer
1480 : // \minimum 1
1481 : // N2 , \field Rows to Skip at Top
1482 : // \required-field
1483 : // \type integer
1484 : // \minimum 0
1485 : // N3 , \field Number of Hours of Data
1486 : // \note 8760 hours does not account for leap years, 8784 does.
1487 : // \note should be either 8760 or 8784
1488 : // \default 8760
1489 : // \minimum 8760
1490 : // \maximum 8784
1491 : // A4 , \field Column Separator
1492 : // \type choice
1493 : // \key Comma
1494 : // \key Tab
1495 : // \key Space
1496 : // \key Semicolon
1497 : // \default Comma
1498 : // A5 , \field Interpolate to Timestep
1499 : // \note when the interval does not match the user specified timestep a "Yes" choice will average between the intervals request (to
1500 : // \note timestep resolution. a "No" choice will use the interval value at the simulation timestep without regard to if it matches
1501 : // \note the boundary or not.
1502 : // \type choice
1503 : // \key Yes
1504 : // \key No
1505 : // \default No
1506 : // N4 ; \field Minutes per Item
1507 : // \note Must be evenly divisible into 60
1508 : // \type integer
1509 : // \minimum 1
1510 : // \maximum 60
1511 :
1512 : // continue adding to SchNum,AddWeekSch,AddDaySch
1513 :
1514 801 : CurrentModuleObject = "Schedule:File";
1515 934 : for (int Loop = 1; Loop <= NumCommaFileSchedules; ++Loop) {
1516 133 : s_ip->getObjectItem(state,
1517 : CurrentModuleObject,
1518 : Loop,
1519 : Alphas,
1520 : NumAlphas,
1521 : Numbers,
1522 : NumNumbers,
1523 : Status,
1524 : lNumericBlanks,
1525 : lAlphaBlanks,
1526 : cAlphaFields,
1527 : cNumericFields);
1528 :
1529 133 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1530 :
1531 133 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1532 0 : ShowSevereDuplicateName(state, eoh);
1533 0 : ErrorsFound = true;
1534 0 : continue;
1535 : }
1536 :
1537 133 : auto *sched = AddScheduleDetailed(state, Alphas(1));
1538 133 : sched->type = SchedType::File;
1539 :
1540 : // Validate ScheduleType
1541 133 : if (lAlphaBlanks(2)) {
1542 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1543 0 : ShowContinueError(state, "Schedule will not be validated.");
1544 133 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1545 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1546 0 : ShowContinueError(state, "Schedule will not be validated.");
1547 : }
1548 :
1549 : // Numbers(1) - which column
1550 133 : curcolCount = Numbers(1);
1551 : // Numbers(2) - number of rows to skip
1552 133 : skiprowCount = Numbers(2);
1553 133 : if (Numbers(3) == 0) {
1554 0 : Numbers(3) = 8760.0;
1555 : }
1556 133 : if (Numbers(3) != 8760 && Numbers(3) != 8784) {
1557 0 : ShowSevereCustom(
1558 : state,
1559 : eoh,
1560 0 : format("{} must = 8760 or 8784 (for a leap year). Value = {:.0T}, Schedule not processed.", cNumericFields(3), Numbers(3)));
1561 0 : ErrorsFound = true;
1562 0 : continue;
1563 : }
1564 :
1565 133 : if (lAlphaBlanks(4) || Util::SameString(Alphas(4), "comma")) {
1566 133 : ColumnSep = CharComma;
1567 133 : Alphas(4) = "comma";
1568 0 : } else if (Util::SameString(Alphas(4), "semicolon")) {
1569 0 : ColumnSep = CharSemicolon;
1570 0 : } else if (Util::SameString(Alphas(4), "tab")) {
1571 0 : ColumnSep = CharTab;
1572 0 : } else if (Util::SameString(Alphas(4), "space")) {
1573 0 : ColumnSep = CharSpace;
1574 : } else {
1575 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(4), Alphas(4), "..must be Comma, Semicolon, Tab, or Space.");
1576 0 : ErrorsFound = true;
1577 0 : continue;
1578 : }
1579 :
1580 : // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
1581 133 : Interpolation interp = Interpolation::No;
1582 :
1583 133 : if (!lAlphaBlanks(5)) {
1584 4 : if (BooleanSwitch bs = getYesNoValue(Alphas(5)); bs != BooleanSwitch::Invalid) {
1585 4 : interp = static_cast<bool>(bs) ? Interpolation::Average : Interpolation::Linear;
1586 : } else {
1587 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(5), Alphas(5));
1588 0 : ErrorsFound = true;
1589 : }
1590 : }
1591 :
1592 133 : sched->UseDaylightSaving = true;
1593 133 : if ((Alphas(6)) == "NO") {
1594 2 : sched->UseDaylightSaving = false;
1595 : }
1596 :
1597 : // is it a sub-hourly schedule or not?
1598 133 : int MinutesPerItem = Constant::iMinutesInHour;
1599 133 : if (NumNumbers > 3) {
1600 133 : MinutesPerItem = int(Numbers(4));
1601 : // int NumExpectedItems = 1440 / MinutesPerItem;
1602 133 : if (mod(Constant::iMinutesInHour, MinutesPerItem) != 0) {
1603 0 : ShowSevereCustom(
1604 0 : state, eoh, format("Requested {} field value ({}) not evenly divisible into 60", cNumericFields(4), MinutesPerItem));
1605 0 : ErrorsFound = true;
1606 0 : continue;
1607 : }
1608 : }
1609 :
1610 133 : int numHourlyValues = Numbers(3);
1611 133 : int rowLimitCount = (Numbers(3) * Constant::rMinutesInHour) / MinutesPerItem;
1612 133 : int hrLimitCount = Constant::iMinutesInHour / MinutesPerItem;
1613 :
1614 133 : std::string contextString = format("{}=\"{}\", {}: ", CurrentModuleObject, Alphas(1), cAlphaFields(3));
1615 :
1616 133 : state.files.TempFullFilePath.filePath = CheckForActualFilePath(state, Alphas(3), contextString);
1617 : // Setup file reading parameters
1618 133 : if (state.files.TempFullFilePath.filePath.empty()) {
1619 0 : ErrorsFound = true;
1620 : } else {
1621 133 : auto result = s_sched->UniqueProcessedExternalFiles.find(state.files.TempFullFilePath.filePath);
1622 133 : if (result == s_sched->UniqueProcessedExternalFiles.end()) {
1623 9 : FileSystem::FileTypes const ext = FileSystem::getFileType(state.files.TempFullFilePath.filePath);
1624 9 : if (FileSystem::is_flat_file_type(ext)) {
1625 9 : auto const schedule_data = FileSystem::readFile(state.files.TempFullFilePath.filePath);
1626 9 : CsvParser csvParser;
1627 9 : auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
1628 9 : csvParser.decode(schedule_data, ColumnSep, skiprowCount));
1629 9 : if (csvParser.hasErrors()) {
1630 0 : for (const auto &[error, isContinued] : csvParser.errors()) {
1631 0 : if (isContinued) {
1632 0 : ShowContinueError(state, error);
1633 : } else {
1634 0 : ShowSevereError(state, error);
1635 : }
1636 0 : }
1637 0 : ShowContinueError(state, fmt::format("Error Occurred in {}", state.files.TempFullFilePath.filePath));
1638 0 : ShowFatalError(state, "Program terminates due to previous condition.");
1639 : }
1640 9 : result = it.first;
1641 9 : } else if (FileSystem::is_all_json_type(ext)) {
1642 0 : auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
1643 0 : FileSystem::readJSON(state.files.TempFullFilePath.filePath));
1644 0 : result = it.first;
1645 0 : } else {
1646 0 : ShowSevereCustom(
1647 : state,
1648 : eoh,
1649 0 : format("{} = {} has an unknown file extension and cannot be read by this program.", cAlphaFields(3), Alphas(3)));
1650 0 : ShowFatalError(state, "Program terminates due to previous condition.");
1651 : }
1652 : }
1653 :
1654 133 : auto const &column_json = result->second["values"][curcolCount - 1];
1655 133 : rowCnt = column_json.size();
1656 133 : auto const column_values = column_json.get<std::vector<Real64>>(); // (AUTO_OK_OBJ)
1657 :
1658 : // schedule values have been filled into the hourlyFileValues array.
1659 :
1660 133 : if (numerrors > 0) {
1661 0 : ShowWarningCustom(state,
1662 : eoh,
1663 0 : format("{} records had errors - these values are set to 0."
1664 : "Use Output:Diagnostics,DisplayExtraWarnings; to see individual records in error.",
1665 : numerrors));
1666 : }
1667 :
1668 133 : if (rowCnt < rowLimitCount) {
1669 0 : ShowWarningCustom(state,
1670 : eoh,
1671 0 : format("less than {} hourly values read from file."
1672 : "..Number read={}.",
1673 : numHourlyValues,
1674 0 : (rowCnt * Constant::iMinutesInHour) / MinutesPerItem));
1675 : }
1676 :
1677 : // process the data into the normal schedule data structures
1678 : // note -- schedules are ALWAYS 366 days so some special measures have to be done at 29 Feb "day of year" (60)
1679 133 : int iDay = 0;
1680 133 : int hDay = 0;
1681 133 : int ifld = 0;
1682 : while (true) {
1683 : // create string of which day of year
1684 48678 : ++iDay;
1685 48678 : ++hDay;
1686 48678 : if (iDay > 366) {
1687 133 : break;
1688 : }
1689 : // increment both since a week schedule is being defined for each day so that a day is valid
1690 : // no matter what the day type that is used in a design day.
1691 :
1692 : // define day schedule
1693 48545 : auto *daySched = AddDaySchedule(state, format("{}_dy_{}", Alphas(1), iDay));
1694 48545 : daySched->schedTypeNum = sched->schedTypeNum;
1695 :
1696 : // define week schedule
1697 48545 : auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", Alphas(1), iDay));
1698 :
1699 : // for all day types point the week schedule to the newly defined day schedule
1700 631085 : for (int kDayType = 1; kDayType < (int)DayType::Num; ++kDayType) {
1701 582540 : weekSched->dayScheds[kDayType] = daySched;
1702 : }
1703 :
1704 : // schedule is pointing to the week schedule
1705 48545 : sched->weekScheds[iDay] = weekSched;
1706 :
1707 48545 : if (MinutesPerItem == Constant::iMinutesInHour) {
1708 100375 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
1709 96360 : Real64 curHrVal = column_values[ifld]; // hourlyFileValues((hDay - 1) * 24 + jHour)
1710 96360 : ++ifld;
1711 481800 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
1712 385440 : daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = curHrVal;
1713 385440 : daySched->sumTsVals += daySched->tsVals[hr * s_glob->TimeStepsInHour + ts];
1714 : }
1715 : }
1716 : } else { // Minutes Per Item < 60
1717 1113250 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
1718 1068720 : int endMin = MinutesPerItem - 1;
1719 1068720 : int begMin = 0;
1720 5694000 : for (int NumFields = 1; NumFields <= hrLimitCount; ++NumFields) {
1721 68748480 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
1722 64123200 : minuteVals[hr * Constant::iMinutesInHour + iMin] = column_values[ifld];
1723 : }
1724 :
1725 4625280 : ++ifld;
1726 4625280 : begMin = endMin + 1;
1727 4625280 : endMin += MinutesPerItem;
1728 : }
1729 : }
1730 :
1731 44530 : daySched->interpolation = interp;
1732 44530 : daySched->populateFromMinuteVals(state, minuteVals);
1733 : }
1734 48545 : if (iDay == 59 && rowCnt < 8784 * hrLimitCount) { // 28 Feb
1735 : // Dup 28 Feb to 29 Feb (60)
1736 133 : ++iDay;
1737 133 : sched->weekScheds[iDay] = sched->weekScheds[iDay - 1];
1738 : }
1739 48545 : }
1740 133 : }
1741 :
1742 133 : if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
1743 0 : SetupEMSActuator(state, "Schedule:File", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
1744 : }
1745 133 : }
1746 :
1747 801 : if (NumCommaFileShading != 0) {
1748 1 : auto const &values_json = schedule_file_shading_result->second["values"];
1749 1 : auto const headers = schedule_file_shading_result->second["header"].get<std::vector<std::string>>(); // (AUTO_OK_OBJ)
1750 1 : auto const headers_set = schedule_file_shading_result->second["header"].get<std::set<std::string>>(); // (AUTO_OK_OBJ)
1751 :
1752 115 : for (auto const &header : headers_set) {
1753 114 : size_t column = 0;
1754 114 : auto column_it = std::find(headers.begin(), headers.end(), header);
1755 114 : if (column_it != headers.end()) {
1756 228 : column = std::distance(headers.begin(), column_it);
1757 : }
1758 114 : if (column == 0) {
1759 1 : continue; // Skip timestamp column and any duplicate column, which will be 0 as well since it won't be found.
1760 : }
1761 113 : auto const column_values = values_json.at(column).get<std::vector<Real64>>(); // (AUTO_OK_OBJ)
1762 :
1763 113 : std::string curName = format("{}_shading", header);
1764 113 : std::string curNameUC = Util::makeUPPER(curName);
1765 :
1766 113 : if (s_sched->scheduleMap.find(curNameUC) != s_sched->scheduleMap.end()) {
1767 0 : ShowSevereError(state, format("Duplicate schedule name {}", curName));
1768 0 : ErrorsFound = true;
1769 0 : continue;
1770 : }
1771 :
1772 113 : auto *schedShading = AddScheduleDetailed(state, curName);
1773 113 : schedShading->type = SchedType::File;
1774 :
1775 113 : int iDay = 0;
1776 113 : int ifld = 0;
1777 : while (true) {
1778 : // create string of which day of year
1779 41358 : ++iDay;
1780 41358 : if (iDay > 366) {
1781 113 : break;
1782 : }
1783 :
1784 : // day schedule
1785 41245 : auto *daySched = AddDaySchedule(state, format("{}_dy_{}", curName, iDay));
1786 41245 : daySched->schedTypeNum = schedShading->schedTypeNum;
1787 :
1788 : // define week schedule
1789 41245 : auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", curName, iDay));
1790 :
1791 : // for all day types point the week schedule to the newly defined day schedule
1792 536185 : for (int kDayType = 1; kDayType < (int)DayType::Num; ++kDayType) {
1793 494940 : weekSched->dayScheds[kDayType] = daySched;
1794 : }
1795 :
1796 : // schedule is pointing to the week schedule
1797 41245 : schedShading->weekScheds[iDay] = weekSched;
1798 :
1799 1031125 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
1800 4949400 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
1801 3959520 : daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = column_values[ifld];
1802 3959520 : ++ifld;
1803 : }
1804 : }
1805 :
1806 41245 : if (iDay == 59 && !state.dataEnvrn->CurrentYearIsLeapYear) { // 28 Feb
1807 : // Dup 28 Feb to 29 Feb (60)
1808 113 : ++iDay;
1809 113 : schedShading->weekScheds[iDay] = schedShading->weekScheds[iDay - 1];
1810 : }
1811 41245 : }
1812 115 : }
1813 1 : }
1814 :
1815 : // Constant Schedules
1816 801 : CurrentModuleObject = "Schedule:Constant";
1817 1066 : for (int Loop = 1; Loop <= NumConstantSchedules; ++Loop) {
1818 265 : s_ip->getObjectItem(state,
1819 : CurrentModuleObject,
1820 : Loop,
1821 : Alphas,
1822 : NumAlphas,
1823 : Numbers,
1824 : NumNumbers,
1825 : Status,
1826 : lNumericBlanks,
1827 : lAlphaBlanks,
1828 : cAlphaFields,
1829 : cNumericFields);
1830 :
1831 265 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1832 :
1833 265 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1834 0 : ShowSevereDuplicateName(state, eoh);
1835 0 : ErrorsFound = true;
1836 0 : continue;
1837 : }
1838 :
1839 265 : auto *sched = AddScheduleConstant(state, Alphas(1), Numbers(1));
1840 :
1841 : // Validate ScheduleType
1842 265 : if (lAlphaBlanks(2)) { // No warning here for constant schedules
1843 34 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1844 102 : ShowContinueError(state, "Schedule will not be validated.");
1845 231 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1846 2 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1847 6 : ShowContinueError(state, "Schedule will not be validated.");
1848 : }
1849 :
1850 265 : if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
1851 94 : SetupEMSActuator(state, "Schedule:Constant", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
1852 : }
1853 : }
1854 : // When InitConstantScheduleData is called, TimeStepsInHour is 0, so we delay it here
1855 801 : static_cast<ScheduleConstant *>(s_sched->schedules[SchedNum_AlwaysOff])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 0.0);
1856 801 : static_cast<ScheduleConstant *>(s_sched->schedules[SchedNum_AlwaysOn])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 1.0);
1857 :
1858 801 : CurrentModuleObject = "ExternalInterface:Schedule";
1859 801 : for (int Loop = 1; Loop <= NumExternalInterfaceSchedules; ++Loop) {
1860 0 : s_ip->getObjectItem(state,
1861 : CurrentModuleObject,
1862 : Loop,
1863 : Alphas,
1864 : NumAlphas,
1865 : Numbers,
1866 : NumNumbers,
1867 : Status,
1868 : lNumericBlanks,
1869 : lAlphaBlanks,
1870 : cAlphaFields,
1871 : cNumericFields);
1872 :
1873 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1874 :
1875 0 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1876 0 : ShowSevereDuplicateName(state, eoh);
1877 0 : ErrorsFound = true;
1878 0 : continue;
1879 : }
1880 :
1881 0 : auto *sched = AddScheduleDetailed(state, Alphas(1));
1882 0 : sched->type = SchedType::External;
1883 :
1884 : // Validate ScheduleType
1885 0 : if (lAlphaBlanks(2)) {
1886 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1887 0 : ShowContinueError(state, "Schedule will not be validated.");
1888 0 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1889 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1890 0 : ShowContinueError(state, "Schedule will not be validated.");
1891 : }
1892 :
1893 : // TODO: I'm not sure this Jazz is necessary
1894 : // Add day schedule
1895 0 : auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
1896 0 : daySched->isUsed = true;
1897 0 : daySched->schedTypeNum = sched->schedTypeNum;
1898 :
1899 : // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
1900 : // It will be overwritten during run time stepping after the warm up period
1901 0 : if (NumNumbers < 1) {
1902 0 : ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
1903 0 : NumErrorFlag = true;
1904 : }
1905 0 : ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
1906 :
1907 0 : auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
1908 0 : weekSched->isUsed = true;
1909 0 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
1910 0 : weekSched->dayScheds[iDayType] = daySched;
1911 : }
1912 :
1913 0 : for (int iDay = 1; iDay <= 366; ++iDay) {
1914 0 : sched->weekScheds[iDay] = weekSched;
1915 : }
1916 : } // for (Loop)
1917 :
1918 : // added for FMU Import
1919 801 : CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
1920 803 : for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitImportSchedules; ++Loop) {
1921 2 : s_ip->getObjectItem(state,
1922 : CurrentModuleObject,
1923 : Loop,
1924 : Alphas,
1925 : NumAlphas,
1926 : Numbers,
1927 : NumNumbers,
1928 : Status,
1929 : lNumericBlanks,
1930 : lAlphaBlanks,
1931 : cAlphaFields,
1932 : cNumericFields);
1933 :
1934 2 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1935 :
1936 2 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
1937 0 : ShowSevereDuplicateName(state, eoh);
1938 0 : if (NumExternalInterfaceSchedules >= 1) {
1939 0 : ShowContinueError(
1940 : state,
1941 0 : format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule."
1942 : "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)",
1943 : cAlphaFields(1)));
1944 : }
1945 0 : ErrorsFound = true;
1946 0 : continue;
1947 : }
1948 :
1949 2 : auto *sched = AddScheduleDetailed(state, Alphas(1));
1950 2 : sched->type = SchedType::External;
1951 :
1952 : // Validate ScheduleType
1953 2 : if (lAlphaBlanks(2)) {
1954 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
1955 0 : ShowContinueError(state, "Schedule will not be validated.");
1956 2 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
1957 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1958 0 : ShowContinueError(state, "Schedule will not be validated.");
1959 : }
1960 :
1961 : // TODO: I'm not sure this Jazz is necessary
1962 : // Add day schedule
1963 2 : auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
1964 2 : daySched->isUsed = true;
1965 2 : daySched->schedTypeNum = sched->schedTypeNum;
1966 :
1967 : // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
1968 : // It will be overwritten during run time stepping after the warm up period
1969 2 : if (NumNumbers < 1) {
1970 0 : ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
1971 0 : NumErrorFlag = true;
1972 : }
1973 2 : ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
1974 :
1975 2 : auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
1976 2 : weekSched->isUsed = true;
1977 26 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
1978 24 : weekSched->dayScheds[iDayType] = daySched;
1979 : }
1980 :
1981 734 : for (int iDay = 1; iDay <= 366; ++iDay) {
1982 732 : sched->weekScheds[iDay] = weekSched;
1983 : }
1984 : }
1985 :
1986 : // added for FMU Export
1987 801 : CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule";
1988 801 : for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitExportSchedules; ++Loop) {
1989 0 : s_ip->getObjectItem(state,
1990 : CurrentModuleObject,
1991 : Loop,
1992 : Alphas,
1993 : NumAlphas,
1994 : Numbers,
1995 : NumNumbers,
1996 : Status,
1997 : lNumericBlanks,
1998 : lAlphaBlanks,
1999 : cAlphaFields,
2000 : cNumericFields);
2001 :
2002 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
2003 :
2004 0 : if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
2005 0 : ShowSevereDuplicateName(state, eoh);
2006 0 : if (NumExternalInterfaceSchedules >= 1) {
2007 0 : ShowContinueError(
2008 : state,
2009 0 : format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule."
2010 : "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)",
2011 : cAlphaFields(1)));
2012 : }
2013 0 : ErrorsFound = true;
2014 0 : continue;
2015 : }
2016 :
2017 0 : auto *sched = AddScheduleDetailed(state, Alphas(1));
2018 0 : sched->type = SchedType::External;
2019 :
2020 : // Validate ScheduleType
2021 0 : if (lAlphaBlanks(2)) {
2022 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(2));
2023 0 : ShowContinueError(state, "Schedule will not be validated.");
2024 0 : } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
2025 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
2026 0 : ShowContinueError(state, "Schedule will not be validated.");
2027 : }
2028 :
2029 : // TODO: I'm not sure this Jazz is necessary
2030 : // Add day schedule
2031 0 : auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
2032 0 : daySched->isUsed = true;
2033 0 : daySched->schedTypeNum = sched->schedTypeNum;
2034 :
2035 : // Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
2036 : // It will be overwritten during run time stepping after the warm up period
2037 0 : if (NumNumbers < 1) {
2038 0 : ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
2039 0 : NumErrorFlag = true;
2040 : }
2041 0 : ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
2042 :
2043 0 : auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
2044 0 : weekSched->isUsed = true;
2045 0 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
2046 0 : weekSched->dayScheds[iDayType] = daySched;
2047 : }
2048 :
2049 0 : std::fill(sched->weekScheds.begin() + 1, sched->weekScheds.end(), weekSched);
2050 : } // for (Loop)
2051 :
2052 : // Validate by ScheduleLimitsType
2053 19665 : for (auto *sched : s_sched->schedules) {
2054 :
2055 18864 : if (sched->schedTypeNum == SchedNum_Invalid) {
2056 1761 : continue;
2057 : }
2058 :
2059 17103 : auto const *schedType = s_sched->scheduleTypes[sched->schedTypeNum];
2060 17103 : if (!schedType->isLimited) {
2061 3546 : continue;
2062 : }
2063 :
2064 13557 : if (!sched->checkMinMaxVals(state, Clusive::In, schedType->minVal, Clusive::In, schedType->maxVal)) {
2065 0 : ErrorObjectHeader eoh{routineName, "Schedule", sched->Name};
2066 0 : ShowSevereBadMinMax(state, eoh, "", "", Clusive::In, schedType->minVal, Clusive::In, schedType->maxVal);
2067 0 : ErrorsFound = true;
2068 : }
2069 801 : }
2070 :
2071 801 : if (ErrorsFound) {
2072 0 : ShowFatalError(state, format("{}: Preceding Errors cause termination.", routineName));
2073 : }
2074 :
2075 801 : if (s_sched->scheduleTypes.size() + s_sched->daySchedules.size() + s_sched->weekSchedules.size() + s_sched->schedules.size() > 0) {
2076 801 : CurrentModuleObject = "Output:Schedules";
2077 801 : NumFields = s_ip->getNumObjectsFound(state, CurrentModuleObject);
2078 :
2079 : // RptSchedule=.FALSE.
2080 801 : RptLevel = 1;
2081 824 : for (int Count = 1; Count <= NumFields; ++Count) {
2082 23 : s_ip->getObjectItem(state, CurrentModuleObject, Count, Alphas, NumAlphas, Numbers, NumNumbers, Status);
2083 :
2084 23 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
2085 :
2086 : // IDD only allows Hourly or Timestep as valid values on the required field, anything else should be an error in the input processor
2087 23 : ReportLevel reportLevel = static_cast<ReportLevel>(getEnumValue(reportLevelNamesUC, Alphas(1)));
2088 23 : if (reportLevel == ReportLevel::Invalid) {
2089 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(1), Alphas(1), "HOURLY report will be done");
2090 0 : reportLevel = ReportLevel::Hourly;
2091 : }
2092 23 : ReportScheduleDetails(state, reportLevel);
2093 : }
2094 : }
2095 :
2096 801 : Alphas.deallocate();
2097 801 : cAlphaFields.deallocate();
2098 801 : cNumericFields.deallocate();
2099 801 : Numbers.deallocate();
2100 801 : lAlphaBlanks.deallocate();
2101 801 : lNumericBlanks.deallocate();
2102 :
2103 801 : print(state.files.audit, "{}\n", " Processing Schedule Input -- Complete");
2104 35951 : } // ProcessScheduleInput()
2105 :
2106 23 : void ReportScheduleDetails(EnergyPlusData &state,
2107 : ReportLevel const LevelOfDetail) // =1: hourly; =2: timestep; = 3: make IDF excerpt
2108 : {
2109 : // SUBROUTINE INFORMATION:
2110 : // AUTHOR Linda K. Lawrie
2111 : // DATE WRITTEN January 2003
2112 : // MODIFIED February 2008 - add IDF outputs (compact schedules)
2113 :
2114 : // PURPOSE OF THIS SUBROUTINE:
2115 : // This subroutine puts the details of the Schedules on the .eio file (Inits file).
2116 :
2117 : // SUBROUTINE PARAMETER DEFINITIONS:
2118 23 : constexpr std::array<std::string_view, 12> Months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
2119 23 : constexpr std::array<std::string_view, 25> HrField = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
2120 : "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24"};
2121 :
2122 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2123 : int NumF;
2124 : int PMon;
2125 : int PDay;
2126 23 : Array1D_string ShowMinute;
2127 23 : Array1D_string TimeHHMM;
2128 23 : std::string NoAverageLinear;
2129 23 : std::string YesNo2;
2130 23 : std::string Num1;
2131 23 : std::string Num2;
2132 23 : Array2D_string RoundTSValue;
2133 23 : std::string_view constexpr SchDFmtdata{",{}"};
2134 :
2135 23 : auto const &s_glob = state.dataGlobal;
2136 23 : auto const &s_sched = state.dataSched;
2137 :
2138 23 : ShowMinute.allocate(s_glob->TimeStepsInHour);
2139 23 : TimeHHMM.allocate(s_glob->TimeStepsInHour * Constant::iHoursInDay);
2140 23 : RoundTSValue.allocate(s_glob->TimeStepsInHour, Constant::iHoursInDay);
2141 23 : ShowMinute = std::string{};
2142 23 : TimeHHMM = std::string{};
2143 23 : RoundTSValue = std::string{};
2144 :
2145 23 : int CurMinute = s_glob->MinutesInTimeStep;
2146 128 : for (int Count = 1; Count <= s_glob->TimeStepsInHour - 1; ++Count) {
2147 105 : ShowMinute(Count) = format("{:02}", CurMinute);
2148 105 : CurMinute += s_glob->MinutesInTimeStep;
2149 : }
2150 23 : ShowMinute(s_glob->TimeStepsInHour) = "00";
2151 :
2152 23 : switch (LevelOfDetail) {
2153 23 : case ReportLevel::Hourly:
2154 : case ReportLevel::TimeStep: {
2155 23 : NumF = 1;
2156 575 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
2157 552 : if (LevelOfDetail == ReportLevel::TimeStep) {
2158 2784 : for (int ts = 1; ts <= s_glob->TimeStepsInHour - 1; ++ts) {
2159 2304 : TimeHHMM(NumF) = format("{}:{}", HrField[hr], ShowMinute(ts));
2160 2304 : ++NumF;
2161 : }
2162 : }
2163 552 : TimeHHMM(NumF) = format("{}:{}", HrField[hr + 1], ShowMinute(s_glob->TimeStepsInHour));
2164 552 : ++NumF;
2165 : }
2166 23 : --NumF;
2167 :
2168 : // SchTFmt Schedule Types Header
2169 : {
2170 23 : std::string_view constexpr SchTFmt0("! Schedule Details Report={} =====================\n");
2171 23 : std::string_view constexpr SchDFmt{",{}"};
2172 23 : print(state.files.eio, SchTFmt0, reportLevelNames[(int)LevelOfDetail]);
2173 :
2174 23 : std::string_view constexpr SchTFmt("! <ScheduleType>,Name,Limited? {Yes/No},Minimum,Maximum,Continuous? {Yes/No - Discrete}");
2175 23 : print(state.files.eio, "{}\n", SchTFmt);
2176 23 : std::string_view constexpr SchDFmt0("! <DaySchedule>,Name,ScheduleType,Interpolated {Yes/No},Time (HH:MM) =>");
2177 23 : print(state.files.eio, "{}", SchDFmt0);
2178 2879 : for (int Count = 1; Count <= NumF; ++Count) {
2179 2856 : print(state.files.eio, SchDFmt, TimeHHMM(Count));
2180 : }
2181 23 : print(state.files.eio, "\n");
2182 : // SchWFmt Header (WeekSchedule)
2183 23 : std::string SchWFmt("! <WeekSchedule>,Name");
2184 299 : for (int Count = 1; Count < (int)DayType::Num; ++Count) {
2185 276 : SchWFmt = format("{},{}", SchWFmt, dayTypeNames[Count]);
2186 : }
2187 23 : print(state.files.eio, "{}\n", SchWFmt);
2188 23 : std::string_view constexpr SchSFmt("! <Schedule>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31");
2189 23 : print(state.files.eio, "{}\n", SchSFmt);
2190 23 : }
2191 :
2192 164 : for (auto const *schedType : s_sched->scheduleTypes) {
2193 141 : if (schedType->isLimited) {
2194 103 : NoAverageLinear = "Average";
2195 103 : Num1 = format("{:.2R}", schedType->minVal);
2196 103 : strip(Num1);
2197 103 : Num2 = format("{:.2R}", schedType->maxVal);
2198 103 : strip(Num2);
2199 103 : if (schedType->isReal) {
2200 66 : YesNo2 = "Yes";
2201 : } else {
2202 37 : YesNo2 = "No";
2203 37 : Num1 = fmt::to_string((int)schedType->minVal);
2204 37 : Num2 = fmt::to_string((int)schedType->maxVal);
2205 : }
2206 : } else {
2207 38 : NoAverageLinear = "No";
2208 38 : Num1 = "N/A";
2209 38 : Num2 = "N/A";
2210 38 : YesNo2 = "N/A";
2211 : }
2212 141 : std::string_view constexpr SchTFmtdata("ScheduleTypeLimits,{},{},{},{},{}\n");
2213 141 : print(state.files.eio, SchTFmtdata, schedType->Name, NoAverageLinear, Num1, Num2, YesNo2);
2214 23 : }
2215 :
2216 944 : for (auto *daySched : s_sched->daySchedules) {
2217 :
2218 921 : NoAverageLinear = interpolationNames[(int)daySched->interpolation];
2219 23025 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
2220 152760 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
2221 130656 : RoundTSValue(ts + 1, hr + 1) = format("{:.2R}", daySched->tsVals[hr * s_glob->TimeStepsInHour + ts]);
2222 : }
2223 : }
2224 921 : std::string_view constexpr SchDFmtdata0("DaySchedule,{},{},{},{}");
2225 921 : print(state.files.eio,
2226 : SchDFmtdata0,
2227 921 : daySched->Name,
2228 1842 : (daySched->schedTypeNum == SchedNum_Invalid) ? "" : s_sched->scheduleTypes[daySched->schedTypeNum]->Name,
2229 : NoAverageLinear,
2230 : "Values:");
2231 :
2232 921 : switch (LevelOfDetail) {
2233 23 : case ReportLevel::Hourly: {
2234 575 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
2235 552 : print(state.files.eio, SchDFmtdata, RoundTSValue(s_glob->TimeStepsInHour, hr + 1));
2236 : }
2237 23 : } break;
2238 :
2239 898 : case ReportLevel::TimeStep: {
2240 22450 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
2241 150000 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
2242 128448 : print(state.files.eio, SchDFmtdata, RoundTSValue(ts + 1, hr + 1));
2243 : }
2244 : }
2245 898 : } break;
2246 0 : default:
2247 0 : assert(false);
2248 : }
2249 921 : print(state.files.eio, "\n");
2250 23 : }
2251 :
2252 672 : for (auto *weekSched : s_sched->weekSchedules) {
2253 :
2254 649 : std::string_view constexpr SchWFmtdata("Schedule:Week:Daily,{}");
2255 649 : print(state.files.eio, SchWFmtdata, weekSched->Name);
2256 :
2257 8437 : for (int NumF = 1; NumF < (int)DayType::Num; ++NumF) {
2258 7788 : print(state.files.eio, ",{}", weekSched->dayScheds[NumF]->Name);
2259 : }
2260 649 : print(state.files.eio, "\n");
2261 23 : }
2262 :
2263 712 : for (auto *sched : s_sched->schedules) {
2264 :
2265 689 : if (sched->type == SchedType::Constant) {
2266 48 : continue;
2267 : }
2268 :
2269 641 : auto *schedDetailed = dynamic_cast<ScheduleDetailed *>(sched);
2270 641 : assert(schedDetailed != nullptr);
2271 :
2272 641 : int NumF = 1;
2273 641 : print(state.files.eio,
2274 : "Schedule,{},{}",
2275 641 : schedDetailed->Name,
2276 1282 : (sched->schedTypeNum == SchedNum_Invalid) ? "" : s_sched->scheduleTypes[sched->schedTypeNum]->Name);
2277 :
2278 1290 : while (NumF <= 366) {
2279 :
2280 649 : auto *weekSched = schedDetailed->weekScheds[NumF];
2281 649 : std::string_view constexpr ThruFmt(",Through {} {:02},{}");
2282 234614 : while (schedDetailed->weekScheds[NumF] == weekSched && NumF <= 366) {
2283 234606 : if (NumF == 366) {
2284 641 : General::InvOrdinalDay(NumF, PMon, PDay, 1);
2285 641 : print(state.files.eio, ThruFmt, Months[PMon - 1], PDay, weekSched->Name);
2286 : }
2287 234606 : ++NumF;
2288 234606 : if (NumF > 366) {
2289 641 : break; // compound If might have a problem unless this included.
2290 : }
2291 : }
2292 649 : if (NumF <= 366) {
2293 8 : General::InvOrdinalDay(NumF - 1, PMon, PDay, 1);
2294 8 : print(state.files.eio, ThruFmt, Months[PMon - 1], PDay, weekSched->Name);
2295 : }
2296 : }
2297 641 : print(state.files.eio, "\n");
2298 23 : }
2299 23 : } break;
2300 :
2301 0 : default:
2302 0 : break;
2303 : }
2304 :
2305 : // So this section of the code was not accessible. The input processor would never have let anything but hourly or timestep on the object
2306 : // This code is obviously not covered by any of our integration or unit tests.
2307 : // for (Count = 1; Count <= s_sched->NumSchedules; ++Count) {
2308 : // print(state.files.debug, "\n");
2309 : // print(state.files.debug, " Schedule:Compact,\n");
2310 : // print(state.files.debug, " {}, !- Name\n", s_sched->Schedule(Count).Name);
2311 : // print(state.files.debug,
2312 : // " {}, !- ScheduleTypeLimits\n",
2313 : // s_sched->ScheduleType(s_sched->Schedule(Count).ScheduleTypePtr).Name);
2314 : // NumF = 1;
2315 : // while (NumF <= 366) {
2316 : // TS = s_sched->Schedule(Count).WeekSchedulePointer(NumF);
2317 : // while (s_sched->Schedule(Count).WeekSchedulePointer(NumF) == TS && NumF <= 366) {
2318 : // if (NumF == 366) {
2319 : // General::InvOrdinalDay(NumF, PMon, PDay, 1);
2320 : // print(state.files.debug, " Through: {}/{},\n", PMon, PDay);
2321 : // iDayP = 0;
2322 : // for (DT = 2; DT <= 6; ++DT) {
2323 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2324 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2325 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2326 : // if (iDay != iDayP) {
2327 : // for (Hr = 1; Hr <= 24; ++Hr) {
2328 : // print(state.files.debug,
2329 : // " Until: {}:{},{:.2R},\n",
2330 : // Hr,
2331 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2332 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2333 : // }
2334 : // } else {
2335 : // print(state.files.debug, " Same as previous\n");
2336 : // }
2337 : // iDayP = iDay;
2338 : // }
2339 : // DT = 1;
2340 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2341 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2342 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2343 : // if (iDay != iDayP) {
2344 : // for (Hr = 1; Hr <= 24; ++Hr) {
2345 : // print(state.files.debug,
2346 : // " Until: {}:{},{:.2R},\n",
2347 : // Hr,
2348 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2349 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2350 : // }
2351 : // } else {
2352 : // print(state.files.debug, " Same as previous\n");
2353 : // }
2354 : // iDayP = iDay;
2355 : // for (DT = 7; DT <= MaxDayTypes; ++DT) {
2356 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2357 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2358 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2359 : // if (iDay != iDayP) {
2360 : // for (Hr = 1; Hr <= 24; ++Hr) {
2361 : // print(state.files.debug,
2362 : // " Until: {}:{},{:.2R},\n",
2363 : // Hr,
2364 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2365 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2366 : // }
2367 : // } else {
2368 : // print(state.files.debug, " Same as previous\n");
2369 : // }
2370 : // iDayP = iDay;
2371 : // }
2372 : // }
2373 : // ++NumF;
2374 : // if (NumF > 366) break; // compound If might have a problem unless this included.
2375 : // }
2376 : // if (NumF <= 366) {
2377 : // General::InvOrdinalDay(NumF - 1, PMon, PDay, 1);
2378 : // print(state.files.debug, " Through: {}/{},\n", PMon, PDay);
2379 : // iDayP = 0;
2380 : // for (DT = 2; DT <= 6; ++DT) {
2381 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2382 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2383 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2384 : // if (iDay != iDayP) {
2385 : // for (Hr = 1; Hr <= 24; ++Hr) {
2386 : // print(state.files.debug,
2387 : // " Until: {}:{},{:.2R},\n",
2388 : // Hr,
2389 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2390 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2391 : // }
2392 : // } else {
2393 : // print(state.files.debug, " Same as previous\n");
2394 : // }
2395 : // iDayP = iDay;
2396 : // }
2397 : // DT = 1;
2398 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2399 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2400 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2401 : // if (iDay != iDayP) {
2402 : // for (Hr = 1; Hr <= 24; ++Hr) {
2403 : // print(state.files.debug,
2404 : // " Until: {}:{},{:.2R},\n",
2405 : // Hr,
2406 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2407 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2408 : // }
2409 : // } else {
2410 : // print(state.files.debug, " Same as previous\n");
2411 : // }
2412 : // iDayP = iDay;
2413 : // for (DT = 7; DT <= MaxDayTypes; ++DT) {
2414 : // print(state.files.debug, " For: {},\n", ValidDayTypes(DT));
2415 : // iWeek = s_sched->Schedule(Count).WeekSchedulePointer(NumF - 1);
2416 : // iDay = s_sched->WeekSchedule(iWeek).DaySchedulePointer(DT);
2417 : // if (iDay != iDayP) {
2418 : // for (Hr = 1; Hr <= 24; ++Hr) {
2419 : // print(state.files.debug,
2420 : // " Until: {}:{},{:.2R},\n",
2421 : // Hr,
2422 : // ShowMinute(s_glob->NumOfTimeStepInHour),
2423 : // s_sched->DaySchedule(iDay).TSValue(s_glob->NumOfTimeStepInHour, Hr));
2424 : // }
2425 : // } else {
2426 : // print(state.files.debug, " Same as previous\n");
2427 : // }
2428 : // iDayP = iDay;
2429 : // }
2430 : // }
2431 : // }
2432 : // }
2433 :
2434 23 : ShowMinute.deallocate();
2435 23 : TimeHHMM.deallocate();
2436 23 : RoundTSValue.deallocate();
2437 23 : } // ReportScheduleDetails()
2438 :
2439 0 : Real64 GetCurrentScheduleValue(EnergyPlusData const &state, int const schedNum)
2440 : {
2441 : // Wrapper for method
2442 0 : return state.dataSched->schedules[schedNum]->getCurrentVal();
2443 : }
2444 :
2445 5753551 : void UpdateScheduleVals(EnergyPlusData &state)
2446 : {
2447 : // SUBROUTINE INFORMATION:
2448 : // AUTHOR Linda Lawrie
2449 : // DATE WRITTEN August 2011; adapted from Autodesk (time reduction)
2450 :
2451 : // PURPOSE OF THIS SUBROUTINE:
2452 : // This routine calculates all the scheduled values as a time reduction measure and
2453 : // stores them in the CurrentValue item of the schedule data structure.
2454 :
2455 : // METHODOLOGY EMPLOYED:
2456 : // Use internal Schedule data structure to calculate current value. Note that missing values in
2457 :
2458 5753551 : auto const &s_sched = state.dataSched;
2459 5753551 : auto const &s_glob = state.dataGlobal;
2460 :
2461 148780373 : for (auto *sched : s_sched->schedules) {
2462 143026822 : if (sched->EMSActuatedOn) {
2463 185990 : sched->currentVal = sched->EMSVal;
2464 : } else {
2465 142840832 : sched->currentVal = sched->getHrTsVal(state, s_glob->HourOfDay, s_glob->TimeStep);
2466 : }
2467 5753551 : }
2468 5753551 : }
2469 :
2470 133585508 : Real64 ScheduleDetailed::getHrTsVal(EnergyPlusData &state,
2471 : int hr,
2472 : int ts // Negative => unspecified
2473 : ) const
2474 : {
2475 : // FUNCTION INFORMATION:
2476 : // AUTHOR Linda K. Lawrie
2477 : // DATE WRITTEN January 2003
2478 : // PURPOSE OF THIS FUNCTION:
2479 : // This function provides a method to look up schedule values for any hour, timestep, day
2480 : // of the year (rather than just the "current time").
2481 133585508 : auto const &s_glob = state.dataGlobal;
2482 :
2483 133585508 : if (this->EMSActuatedOn) {
2484 0 : return this->EMSVal;
2485 : }
2486 :
2487 : // so, current date, but maybe TimeStep added
2488 :
2489 : // Hourly Value
2490 133585508 : if (hr > Constant::iHoursInDay) {
2491 0 : ShowFatalError(state, format("LookUpScheduleValue called with thisHour={}", hr));
2492 : }
2493 :
2494 133585508 : int thisHr = hr + state.dataEnvrn->DSTIndicator * this->UseDaylightSaving;
2495 :
2496 133585508 : int thisDayOfYear = state.dataEnvrn->DayOfYear_Schedule;
2497 133585508 : int thisDayOfWeek = state.dataEnvrn->DayOfWeek;
2498 133585508 : int thisHolidayNum = state.dataEnvrn->HolidayIndex;
2499 133585508 : if (thisHr > Constant::iHoursInDay) { // In case HourOfDay is 24 and DSTIndicator is 1, you're actually the next day
2500 51146 : thisDayOfYear += 1;
2501 51146 : thisHr -= Constant::iHoursInDay;
2502 51146 : thisDayOfWeek = state.dataEnvrn->DayOfWeekTomorrow;
2503 51146 : thisHolidayNum = state.dataEnvrn->HolidayIndexTomorrow;
2504 : }
2505 :
2506 : // In the case where DST is applied on 12/31 at 24:00, which is the case for a Southern Hemisphere location for eg
2507 : // (DayOfYear_Schedule is a bit weird, ScheduleManager always assumes LeapYear)
2508 133585508 : if (thisDayOfYear == 367) {
2509 0 : thisDayOfYear = 1;
2510 : }
2511 :
2512 133585508 : auto const *weekSched = this->weekScheds[thisDayOfYear];
2513 133585508 : auto const *daySched = (thisHolidayNum > 0) ? weekSched->dayScheds[thisHolidayNum] : weekSched->dayScheds[thisDayOfWeek];
2514 133585508 : if (daySched == nullptr) {
2515 : // We already warned in ProcessScheduleInput that there were missing days: Missing day types will have 0.0 as Schedule Values
2516 0 : return 0.0;
2517 : }
2518 :
2519 : // If Unspecified or equal to zero, use NumOfTimeStepInHour, otherwise use supplied
2520 133585508 : if (ts <= 0) {
2521 1159867 : ts = s_glob->TimeStepsInHour;
2522 : }
2523 :
2524 133585508 : return daySched->tsVals[(thisHr - 1) * s_glob->TimeStepsInHour + (ts - 1)];
2525 : } // ScheduleDetailed::getHrTsVal()
2526 :
2527 13288746 : Real64 ScheduleConstant::getHrTsVal([[maybe_unused]] EnergyPlusData &state, [[maybe_unused]] int hr, [[maybe_unused]] int ts) const
2528 : {
2529 : // cf #10962 - We can't use currentValue as it could be overwritten by the EMS Sensor
2530 13288746 : return this->tsVals.front();
2531 : } // ScheduleConstant::getHrTsVal()
2532 :
2533 22539 : Sched::Schedule *GetScheduleAlwaysOn(EnergyPlusData &state)
2534 : {
2535 22539 : return state.dataSched->schedules[SchedNum_AlwaysOn];
2536 : }
2537 :
2538 16 : Sched::Schedule *GetScheduleAlwaysOff(EnergyPlusData &state)
2539 : {
2540 16 : return state.dataSched->schedules[SchedNum_AlwaysOff];
2541 : }
2542 :
2543 130092 : Sched::Schedule *GetSchedule(EnergyPlusData &state, std::string const &name)
2544 : {
2545 : // FUNCTION INFORMATION:
2546 : // AUTHOR Linda K. Lawrie
2547 : // DATE WRITTEN September 1997
2548 :
2549 : // PURPOSE OF THIS FUNCTION:
2550 : // This function returns the internal pointer to Schedule "ScheduleName".
2551 130092 : auto const &s_sched = state.dataSched;
2552 :
2553 130092 : auto found = s_sched->scheduleMap.find(name);
2554 130092 : if (found == s_sched->scheduleMap.end()) {
2555 58719 : return nullptr;
2556 : }
2557 :
2558 71373 : int schedNum = found->second;
2559 :
2560 71373 : auto *sched = s_sched->schedules[schedNum];
2561 :
2562 71373 : if (!sched->isUsed) {
2563 16406 : sched->isUsed = true;
2564 :
2565 16406 : if (sched->type != SchedType::Constant) {
2566 :
2567 16181 : auto *schedDetailed = dynamic_cast<ScheduleDetailed *>(sched);
2568 16181 : assert(schedDetailed != nullptr);
2569 :
2570 16181 : schedDetailed->isUsed = true;
2571 5938427 : for (int iWeek = 1; iWeek <= 366; ++iWeek) {
2572 5922246 : if (auto *weekSched = schedDetailed->weekScheds[iWeek]; weekSched != nullptr) {
2573 5922246 : if (weekSched->isUsed) {
2574 5873701 : continue;
2575 : }
2576 :
2577 48545 : weekSched->isUsed = true;
2578 631085 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
2579 582540 : auto *daySched = weekSched->dayScheds[iDayType];
2580 582540 : daySched->isUsed = true;
2581 : }
2582 : }
2583 : }
2584 : }
2585 : }
2586 71373 : return sched;
2587 130092 : } // GetSchedule()
2588 :
2589 2 : int GetScheduleNum(EnergyPlusData &state, std::string const &name)
2590 : {
2591 2 : auto *sched = GetSchedule(state, name);
2592 2 : return (sched == nullptr) ? -1 : sched->Num;
2593 : }
2594 :
2595 406 : Sched::WeekSchedule *GetWeekSchedule(EnergyPlusData &state, std::string const &name)
2596 : {
2597 406 : auto const &s_sched = state.dataSched;
2598 :
2599 406 : auto found = s_sched->weekScheduleMap.find(name);
2600 406 : if (found == s_sched->weekScheduleMap.end()) {
2601 0 : return nullptr;
2602 : }
2603 :
2604 406 : int weekSchedNum = found->second;
2605 :
2606 406 : auto *weekSched = s_sched->weekSchedules[weekSchedNum];
2607 :
2608 406 : if (!weekSched->isUsed) {
2609 399 : weekSched->isUsed = true;
2610 5187 : for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
2611 4788 : auto *daySched = weekSched->dayScheds[iDayType];
2612 4788 : if (daySched == nullptr) {
2613 0 : continue;
2614 : }
2615 4788 : daySched->isUsed = true;
2616 : }
2617 : }
2618 406 : return weekSched;
2619 406 : } // GetWeekSchedule()
2620 :
2621 0 : int GetWeekScheduleNum(EnergyPlusData &state, std::string const &name)
2622 : {
2623 0 : auto *weekSched = GetWeekSchedule(state, name);
2624 0 : return (weekSched == nullptr) ? -1 : weekSched->Num;
2625 : }
2626 :
2627 4271 : Sched::DaySchedule *GetDaySchedule(EnergyPlusData &state, std::string const &name)
2628 : {
2629 : // FUNCTION INFORMATION:
2630 : // AUTHOR Linda K. Lawrie
2631 : // DATE WRITTEN September 1997
2632 :
2633 : // PURPOSE OF THIS FUNCTION:
2634 : // This function returns the internal pointer to Schedule "ScheduleName".
2635 4271 : auto const &s_sched = state.dataSched;
2636 :
2637 4271 : auto found = s_sched->dayScheduleMap.find(name);
2638 4271 : if (found == s_sched->dayScheduleMap.end()) {
2639 0 : return nullptr;
2640 : }
2641 :
2642 4271 : int daySchedNum = found->second;
2643 :
2644 4271 : auto *daySched = s_sched->daySchedules[daySchedNum];
2645 :
2646 4271 : daySched->isUsed = true;
2647 :
2648 4271 : return daySched;
2649 4271 : } // GetDaySchedule()
2650 :
2651 0 : int GetDayScheduleNum(EnergyPlusData &state, std::string const &name)
2652 : {
2653 0 : auto *daySched = GetDaySchedule(state, name);
2654 0 : return (daySched == nullptr) ? -1 : daySched->Num;
2655 : }
2656 :
2657 470 : void ScheduleConstant::setMinMaxVals([[maybe_unused]] EnergyPlusData &state)
2658 : {
2659 470 : assert(!isMinMaxSet);
2660 470 : minVal = maxVal = currentVal;
2661 470 : isMinMaxSet = true;
2662 470 : }
2663 :
2664 0 : std::vector<Real64> const &ScheduleConstant::getDayVals(EnergyPlusData &state, [[maybe_unused]] int jDay, [[maybe_unused]] int dayofWeek)
2665 : {
2666 0 : assert((int)tsVals.size() == Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour);
2667 0 : return this->tsVals;
2668 : } // ScheduleConstant::getDayVals()
2669 :
2670 33269 : std::vector<Real64> const &ScheduleDetailed::getDayVals(EnergyPlusData &state, int jDay, int dayOfWeek)
2671 : {
2672 : // PURPOSE OF THIS SUBROUTINE:
2673 : // This subroutine returns an entire day's worth of schedule values.
2674 33269 : auto const &s_env = state.dataEnvrn;
2675 :
2676 : // Determine which Week Schedule is used
2677 33269 : auto const *weekSched = this->weekScheds[(jDay == -1) ? state.dataEnvrn->DayOfYear_Schedule : jDay];
2678 :
2679 33269 : DaySchedule *daySched = nullptr;
2680 : // Now, which day?
2681 33269 : if (dayOfWeek == -1) {
2682 28227 : daySched = weekSched->dayScheds[(s_env->HolidayIndex > 0) ? s_env->HolidayIndex : s_env->DayOfWeek];
2683 5042 : } else if (dayOfWeek <= 7 && s_env->HolidayIndex > 0) {
2684 5042 : daySched = weekSched->dayScheds[s_env->HolidayIndex];
2685 : } else {
2686 0 : daySched = weekSched->dayScheds[dayOfWeek];
2687 : }
2688 :
2689 33269 : return daySched->getDayVals(state);
2690 : } // ScheduleDetailed::getDayVals()
2691 :
2692 73538 : void ExternalInterfaceSetSchedule(EnergyPlusData &state,
2693 : int schedNum,
2694 : Real64 value // The new value for the schedule
2695 : )
2696 : {
2697 : // FUNCTION INFORMATION:
2698 : // AUTHOR Michael Wetter
2699 : // DATE WRITTEN February 2010
2700 :
2701 : // PURPOSE OF THIS SUBROUTINE:
2702 : // This subroutine sets all values of the schedule referenced by 'ScheduleIndex'
2703 : // to the value specified by 'Value'. The subroutine is used by the ExternalInterface to
2704 : // write real-time data into a schedule so that EnergyPlus modules can use
2705 : // real-time data by referencing a schedule. This allows overwriting setpoint
2706 : // for supervisory controls or internal gains obtained from real-time occupancy
2707 : // measurements.
2708 73538 : auto const &s_glob = state.dataGlobal;
2709 73538 : auto const &s_sched = state.dataSched;
2710 73538 : auto *daySched = s_sched->daySchedules[schedNum];
2711 :
2712 1838450 : for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
2713 8824560 : for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
2714 7059648 : daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = value;
2715 : }
2716 : }
2717 73538 : } // ExternalInterfaceSetSchedule()
2718 :
2719 35150 : void ProcessIntervalFields(EnergyPlusData &state,
2720 : Array1S_string const Untils,
2721 : Array1S<Real64> const Numbers,
2722 : int const NumUntils,
2723 : int const NumNumbers,
2724 : std::array<Real64, Constant::iMinutesInDay> &minuteVals,
2725 : std::array<bool, Constant::iMinutesInDay> &setMinuteVals,
2726 : bool &ErrorsFound,
2727 : std::string const &DayScheduleName, // Name (used for errors)
2728 : std::string const &ErrContext, // Context (used for errors)
2729 : Interpolation interpolation // enumeration on how to interpolate values in schedule
2730 : )
2731 : {
2732 : // SUBROUTINE INFORMATION:
2733 : // AUTHOR <author>
2734 : // DATE WRITTEN <date_written>
2735 :
2736 : // PURPOSE OF THIS SUBROUTINE:
2737 : // This subroutine processes the "interval" fields with/without optional "until" in front of
2738 : // time (hh:mm).
2739 :
2740 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2741 : int HHField;
2742 : int MMField;
2743 :
2744 35150 : int begHr = 0; // starting hour
2745 35150 : int begMin = 0; // starting minute
2746 35150 : int endHr = -1; // ending hour
2747 35150 : int endMin = -1; // ending minute
2748 : std::string::size_type sFld;
2749 :
2750 : int totalMinutes;
2751 : Real64 incrementPerMinute;
2752 : Real64 curValue;
2753 :
2754 35150 : std::fill(minuteVals.begin(), minuteVals.end(), 0.0);
2755 35150 : std::fill(setMinuteVals.begin(), setMinuteVals.end(), false);
2756 :
2757 35150 : sFld = 0;
2758 :
2759 35150 : Real64 StartValue = 0;
2760 35150 : Real64 EndValue = 0;
2761 :
2762 35150 : if (NumUntils != NumNumbers) {
2763 0 : ShowSevereError(state,
2764 0 : format("ProcessScheduleInput: ProcessIntervalFields, number of Time fields does not match number of value fields, {}={}",
2765 : ErrContext,
2766 : DayScheduleName));
2767 0 : ErrorsFound = true;
2768 0 : return;
2769 : }
2770 :
2771 120169 : for (int Count = 1; Count <= NumUntils; ++Count) {
2772 85019 : std::string const &until = Untils(Count);
2773 85019 : int Pos = index(until, "UNTIL");
2774 85019 : if (Pos == 0) {
2775 80258 : if (until[5] == ':') {
2776 80236 : sFld = 6;
2777 : } else {
2778 22 : sFld = 5;
2779 : }
2780 80258 : DecodeHHMMField(state, until.substr(sFld), HHField, MMField, ErrorsFound, DayScheduleName, until, interpolation);
2781 4761 : } else if (Pos == (int)std::string::npos) {
2782 4761 : DecodeHHMMField(state, until, HHField, MMField, ErrorsFound, DayScheduleName, until, interpolation);
2783 : } else { // Until found but wasn't first field
2784 0 : ShowSevereError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", until));
2785 0 : ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
2786 0 : ErrorsFound = true;
2787 0 : continue;
2788 : }
2789 : // Field decoded
2790 85019 : if (HHField < 0 || HHField > Constant::iHoursInDay || MMField < 0 || MMField > Constant::iMinutesInHour) {
2791 0 : ShowSevereError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", until));
2792 0 : ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
2793 0 : ErrorsFound = true;
2794 0 : continue;
2795 : }
2796 85019 : if (HHField == Constant::iHoursInDay && MMField > 0 && MMField < Constant::iMinutesInHour) {
2797 0 : ShowWarningError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", Untils(Count)));
2798 0 : ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
2799 0 : ShowContinueError(state, "Terminating the field at 24:00");
2800 0 : MMField = 0;
2801 : }
2802 :
2803 : // Fill in values
2804 85019 : if (MMField == 0) {
2805 84175 : endHr = HHField - 1;
2806 84175 : endMin = Constant::iMinutesInHour - 1;
2807 844 : } else if (MMField < Constant::iMinutesInHour) {
2808 844 : endHr = HHField;
2809 844 : endMin = MMField - 1;
2810 : }
2811 :
2812 85019 : if (interpolation == Interpolation::Linear) {
2813 0 : totalMinutes = (endHr - begHr) * Constant::iMinutesInHour + (endMin - begMin) + 1;
2814 0 : if (totalMinutes == 0) {
2815 0 : totalMinutes = 1; // protect future division
2816 : }
2817 0 : if (Count == 1) {
2818 0 : StartValue = Numbers(Count); // assume first period is flat
2819 0 : EndValue = Numbers(Count);
2820 : } else {
2821 0 : StartValue = EndValue;
2822 0 : EndValue = Numbers(Count);
2823 : }
2824 0 : incrementPerMinute = (EndValue - StartValue) / totalMinutes;
2825 0 : curValue = StartValue + incrementPerMinute;
2826 : }
2827 :
2828 85019 : if (begHr > endHr) {
2829 8 : if (begHr == endHr + 1 && begMin == 0 && endMin == Constant::iMinutesInHour - 1) {
2830 16 : ShowWarningError(state,
2831 16 : format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, zero time interval detected, {}={}",
2832 : ErrContext,
2833 : DayScheduleName));
2834 : } else {
2835 0 : ShowSevereError(state,
2836 0 : format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, overlapping times detected, {}={}",
2837 : ErrContext,
2838 : DayScheduleName));
2839 0 : ErrorsFound = true;
2840 : }
2841 :
2842 85011 : } else if (begHr == endHr) {
2843 1545749 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
2844 1519888 : if (setMinuteVals[begHr * Constant::iMinutesInHour + iMin] == true) {
2845 0 : ShowSevereError(
2846 : state,
2847 0 : format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, overlapping times detected, {}={}",
2848 : ErrContext,
2849 : DayScheduleName));
2850 0 : ErrorsFound = true;
2851 0 : goto UntilLoop_exit;
2852 : }
2853 : }
2854 :
2855 25861 : if (interpolation == Interpolation::Linear) {
2856 0 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
2857 0 : minuteVals[begHr * Constant::iMinutesInHour + iMin] = curValue;
2858 0 : curValue += incrementPerMinute;
2859 0 : setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
2860 : }
2861 : } else {
2862 1545749 : for (int iMin = begMin; iMin <= endMin; ++iMin) {
2863 1519888 : minuteVals[begHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
2864 1519888 : setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
2865 : }
2866 : }
2867 :
2868 25861 : begMin = endMin + 1;
2869 25861 : if (begMin >= Constant::iMinutesInHour) {
2870 25169 : ++begHr;
2871 25169 : begMin = 0;
2872 : }
2873 :
2874 : } else { // begHr < endHr
2875 59150 : if (interpolation == Interpolation::Linear) {
2876 0 : for (int iMin = begMin; iMin <= Constant::iMinutesInHour - 1; ++iMin) { // for portion of starting hour
2877 0 : minuteVals[begHr * Constant::iMinutesInHour + iMin] = curValue;
2878 0 : curValue += incrementPerMinute;
2879 0 : setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
2880 : }
2881 :
2882 0 : for (int iHr = begHr + 1; iHr <= endHr - 1; ++iHr) { // for intermediate hours
2883 0 : for (int iMin = 0; iMin <= Constant::iMinutesInHour - 1; ++iMin) {
2884 0 : minuteVals[iHr * Constant::iMinutesInHour + iMin] = curValue;
2885 0 : curValue += incrementPerMinute;
2886 0 : setMinuteVals[iHr * Constant::iMinutesInHour + iMin] = true;
2887 : }
2888 : }
2889 :
2890 0 : for (int iMin = 0; iMin <= endMin; ++iMin) { // for ending hour
2891 0 : minuteVals[endHr * Constant::iMinutesInHour + iMin] = curValue;
2892 0 : curValue += incrementPerMinute;
2893 0 : setMinuteVals[endHr * Constant::iMinutesInHour + iMin] = true;
2894 : }
2895 :
2896 : } else { // either no interpolation or "average" interpolation (average just is when the interval does not match the timestep)
2897 : // Fill values for first hour (which may not start at minute 0)
2898 : // For std::fill the end marker has to be 1 past the last position you want to fill
2899 3653318 : for (int iMin = begMin; iMin <= Constant::iMinutesInHour; ++iMin) {
2900 3594168 : minuteVals[begHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
2901 3594168 : setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
2902 : }
2903 :
2904 : // Fill values for middle hours (which start at minute 0 and end in minute 59)
2905 59150 : if ((begHr + 1) <= (endHr - 1)) {
2906 754563 : for (int iHr = begHr + 1; iHr <= endHr - 1; ++iHr) {
2907 42717263 : for (int iMin = 0; iMin <= Constant::iMinutesInHour - 1; ++iMin) {
2908 42016980 : minuteVals[iHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
2909 42016980 : setMinuteVals[iHr * Constant::iMinutesInHour + iMin] = true;
2910 : }
2911 : }
2912 : }
2913 :
2914 : // Fill values for last hour (which starts at minute 0 but may end on minute that isn't 59)
2915 3603264 : for (int iMin = 0; iMin <= endMin; ++iMin) {
2916 3544114 : minuteVals[endHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
2917 3544114 : setMinuteVals[endHr * Constant::iMinutesInHour + iMin] = true;
2918 : }
2919 : }
2920 :
2921 59150 : begHr = endHr;
2922 59150 : begMin = endMin + 1;
2923 59150 : if (begMin >= Constant::iMinutesInHour) {
2924 58998 : ++begHr;
2925 58998 : begMin = 0;
2926 : }
2927 : }
2928 : }
2929 35150 : UntilLoop_exit:;
2930 :
2931 50651150 : for (int iMin = 0; iMin < Constant::iMinutesInDay; ++iMin) {
2932 50616000 : if (setMinuteVals[iMin] == false) {
2933 0 : ShowSevereError(state,
2934 0 : format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, incomplete day detected, {}={}",
2935 : ErrContext,
2936 : DayScheduleName));
2937 0 : ErrorsFound = true;
2938 : }
2939 : }
2940 : }
2941 :
2942 85019 : void DecodeHHMMField(EnergyPlusData &state,
2943 : std::string const &FieldValue, // Input field value
2944 : int &RetHH, // Returned "hour"
2945 : int &RetMM, // Returned "minute"
2946 : bool &ErrorsFound, // True if errors found in this field
2947 : std::string const &DayScheduleName, // originating day schedule name
2948 : std::string const &FullFieldValue, // Full Input field value
2949 : Interpolation interpolation // enumeration on how to interpolate values in schedule
2950 : )
2951 : {
2952 : // SUBROUTINE INFORMATION:
2953 : // AUTHOR Linda K Lawrie
2954 : // DATE WRITTEN January 2003
2955 :
2956 : // PURPOSE OF THIS SUBROUTINE:
2957 :
2958 : // This subroutine decodes a hhmm date field input as part of the "until" time in a schedule
2959 : // representation.
2960 :
2961 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2962 : Real64 rRetHH; // real Returned "hour"
2963 85019 : std::string hHour;
2964 85019 : std::string mMinute;
2965 :
2966 85019 : std::string String = stripped(FieldValue);
2967 85019 : std::string::size_type const Pos = index(String, ':');
2968 85019 : bool nonIntegral = false;
2969 :
2970 85019 : auto const &s_glob = state.dataGlobal;
2971 85019 : if (Pos == std::string::npos) {
2972 0 : ShowSevereError(state,
2973 0 : format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (no : separator in hh:mm)={}",
2974 0 : stripped(FullFieldValue)));
2975 0 : ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
2976 0 : ErrorsFound = true;
2977 0 : return;
2978 85019 : } else if (Pos == 0) {
2979 0 : RetHH = 0;
2980 : } else {
2981 85019 : bool error = false;
2982 85019 : Real64 rRetHH = Util::ProcessNumber(String.substr(0, Pos), error);
2983 85019 : RetHH = int(rRetHH);
2984 85019 : if (double(RetHH) != rRetHH || error || rRetHH < 0.0) {
2985 0 : if (double(RetHH) != rRetHH && rRetHH >= 0.0) {
2986 0 : ShowWarningError(state,
2987 0 : format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (non-integer numeric in HH)={}",
2988 0 : stripped(FullFieldValue)));
2989 0 : ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
2990 0 : nonIntegral = true;
2991 : } else {
2992 0 : ShowSevereError(state,
2993 0 : format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (invalid numeric in HH)={}",
2994 0 : stripped(FullFieldValue)));
2995 0 : ShowContinueError(
2996 0 : state, format("Field values must be integer and represent hours:minutes. Occurred in Day Schedule={}", DayScheduleName));
2997 0 : ErrorsFound = true;
2998 0 : return;
2999 : }
3000 : }
3001 : }
3002 :
3003 85019 : String.erase(0, Pos + 1);
3004 85019 : bool error = false;
3005 85019 : Real64 rRetMM = Util::ProcessNumber(String, error);
3006 85019 : RetMM = int(rRetMM);
3007 85019 : if (double(RetMM) != rRetMM || error || rRetMM < 0.0) {
3008 0 : if (double(RetMM) != rRetMM && rRetMM >= 0.0) {
3009 0 : ShowWarningError(state,
3010 0 : format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (non-integer numeric in MM)={}",
3011 0 : stripped(FullFieldValue)));
3012 0 : ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
3013 0 : nonIntegral = true;
3014 : } else {
3015 0 : ShowSevereError(state,
3016 0 : format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (invalid numeric in MM)={}",
3017 0 : stripped(FullFieldValue)));
3018 0 : ShowContinueError(state,
3019 0 : format("Field values must be integer and represent hours:minutes. Occurred in Day Schedule={}", DayScheduleName));
3020 0 : ErrorsFound = true;
3021 0 : return;
3022 : }
3023 : }
3024 :
3025 85019 : if (nonIntegral) {
3026 0 : std::string hHour; // these haven't been initialized?
3027 0 : std::string mMinute;
3028 0 : ShowContinueError(state, format("Until value to be used will be: {:2.2F}:{:2.2F}", hHour, mMinute));
3029 0 : }
3030 85019 : if (interpolation == Interpolation::No) {
3031 83697 : if (!isMinuteMultipleOfTimestep(RetMM, s_glob->MinutesInTimeStep)) {
3032 82 : ShowWarningError(
3033 : state,
3034 82 : format(
3035 : "ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field value is not a multiple of the minutes for each timestep: {}",
3036 82 : stripped(FullFieldValue)));
3037 41 : ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
3038 : }
3039 : }
3040 85019 : }
3041 :
3042 83697 : bool isMinuteMultipleOfTimestep(int minute, int numMinutesPerTimestep)
3043 : {
3044 83697 : if (minute != 0) {
3045 252 : return (minute % numMinutesPerTimestep == 0);
3046 : } else {
3047 83445 : return true;
3048 : }
3049 : }
3050 :
3051 34885 : void ProcessForDayTypes(EnergyPlusData &state,
3052 : std::string const &ForDayField, // Field containing the "FOR:..."
3053 : std::array<bool, (int)DayType::Num> &these, // Array to contain returned "true" days
3054 : std::array<bool, (int)DayType::Num> &already, // Array of days already done
3055 : bool &ErrorsFound // Will be true if error found.
3056 : )
3057 : {
3058 : // SUBROUTINE INFORMATION:
3059 : // AUTHOR Linda K. Lawrie
3060 : // DATE WRITTEN February 2003
3061 :
3062 : // PURPOSE OF THIS SUBROUTINE:
3063 : // This subroutine processes a field "For: day types" and returns
3064 : // those day types (can be multiple) from field.
3065 : // Argument array dimensioning
3066 :
3067 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3068 34885 : bool OneValid = false;
3069 34885 : bool DupAssignment = false;
3070 :
3071 : // Just test for specific days
3072 34885 : if (has(ForDayField, "WEEKDAY")) {
3073 4894 : these[iDayType_Mon] = these[iDayType_Tue] = these[iDayType_Wed] = these[iDayType_Thu] = these[iDayType_Fri] = true;
3074 4894 : if (already[iDayType_Mon] || already[iDayType_Tue] || already[iDayType_Wed] || already[iDayType_Thu] || already[iDayType_Fri]) {
3075 0 : DupAssignment = true;
3076 : }
3077 4894 : already[iDayType_Mon] = already[iDayType_Tue] = already[iDayType_Wed] = already[iDayType_Thu] = already[iDayType_Fri] = true;
3078 4894 : OneValid = true;
3079 : }
3080 34885 : if (has(ForDayField, "MONDAY")) { // Should this be an else-if
3081 106 : these[iDayType_Mon] = true;
3082 106 : if (already[iDayType_Mon]) {
3083 0 : DupAssignment = true;
3084 : } else {
3085 106 : already[iDayType_Mon] = true;
3086 : }
3087 106 : OneValid = true;
3088 : }
3089 34885 : if (has(ForDayField, "TUESDAY")) {
3090 144 : these[iDayType_Tue] = true;
3091 144 : if (already[iDayType_Tue]) {
3092 0 : DupAssignment = true;
3093 : } else {
3094 144 : already[iDayType_Tue] = true;
3095 : }
3096 144 : OneValid = true;
3097 : }
3098 34885 : if (has(ForDayField, "WEDNESDAY")) {
3099 88 : these[iDayType_Wed] = true;
3100 88 : if (already[iDayType_Wed]) {
3101 0 : DupAssignment = true;
3102 : } else {
3103 88 : already[iDayType_Wed] = true;
3104 : }
3105 88 : OneValid = true;
3106 : }
3107 34885 : if (has(ForDayField, "THURSDAY")) {
3108 88 : these[iDayType_Thu] = true;
3109 88 : if (already[iDayType_Thu]) {
3110 0 : DupAssignment = true;
3111 : } else {
3112 88 : already[iDayType_Thu] = true;
3113 : }
3114 88 : OneValid = true;
3115 : }
3116 34885 : if (has(ForDayField, "FRIDAY")) {
3117 126 : these[iDayType_Fri] = true;
3118 126 : if (already[iDayType_Fri]) {
3119 0 : DupAssignment = true;
3120 : } else {
3121 126 : already[iDayType_Fri] = true;
3122 : }
3123 126 : OneValid = true;
3124 : }
3125 34885 : if (has(ForDayField, "WEEKEND")) {
3126 2061 : these[iDayType_Sun] = these[iDayType_Sat] = true;
3127 2061 : if (already[iDayType_Sun] || already[iDayType_Sat]) {
3128 0 : DupAssignment = true;
3129 : }
3130 2061 : already[iDayType_Sun] = already[iDayType_Sat] = true;
3131 2061 : OneValid = true;
3132 : }
3133 :
3134 34885 : if (has(ForDayField, "SATURDAY")) {
3135 1715 : these[iDayType_Sat] = true;
3136 1715 : if (already[iDayType_Sat]) {
3137 0 : DupAssignment = true;
3138 : } else {
3139 1715 : already[iDayType_Sat] = true;
3140 : }
3141 1715 : OneValid = true;
3142 : }
3143 34885 : if (has(ForDayField, "SUNDAY")) {
3144 1204 : these[iDayType_Sun] = true;
3145 1204 : if (already[iDayType_Sun]) {
3146 0 : DupAssignment = true;
3147 : } else {
3148 1204 : already[iDayType_Sun] = true;
3149 : }
3150 1204 : OneValid = true;
3151 : }
3152 34885 : if (has(ForDayField, "CUSTOMDAY1")) {
3153 1770 : these[iDayType_Cus1] = true;
3154 1770 : if (already[iDayType_Cus1]) {
3155 0 : DupAssignment = true;
3156 : } else {
3157 1770 : already[iDayType_Cus1] = true;
3158 : }
3159 1770 : OneValid = true;
3160 : }
3161 34885 : if (has(ForDayField, "CUSTOMDAY2")) {
3162 1752 : these[iDayType_Cus2] = true;
3163 1752 : if (already[iDayType_Cus2]) {
3164 0 : DupAssignment = true;
3165 : } else {
3166 1752 : already[iDayType_Cus2] = true;
3167 : }
3168 1752 : OneValid = true;
3169 : }
3170 34885 : if (has(ForDayField, "ALLDAY")) {
3171 247450 : for (int iDay = 0; iDay < (int)DayType::Num; ++iDay) {
3172 229775 : these[iDay] = true;
3173 229775 : if (already[iDay]) {
3174 0 : DupAssignment = true;
3175 : } else {
3176 229775 : already[iDay] = true;
3177 : }
3178 : }
3179 17675 : OneValid = true;
3180 : }
3181 34885 : if (has(ForDayField, "HOLIDAY")) {
3182 3232 : these[iDayType_Hol] = true;
3183 3232 : if (already[iDayType_Hol]) {
3184 0 : DupAssignment = true;
3185 : } else {
3186 3232 : already[iDayType_Hol] = true;
3187 : }
3188 3232 : OneValid = true;
3189 : }
3190 34885 : if (has(ForDayField, "SUMMER")) {
3191 4834 : these[iDayType_SumDes] = true;
3192 4834 : if (already[iDayType_SumDes]) {
3193 0 : DupAssignment = true;
3194 : } else {
3195 4834 : already[iDayType_SumDes] = true;
3196 : }
3197 4834 : OneValid = true;
3198 : }
3199 34885 : if (has(ForDayField, "WINTER")) {
3200 4546 : these[iDayType_WinDes] = true;
3201 4546 : if (already[iDayType_WinDes]) {
3202 0 : DupAssignment = true;
3203 : } else {
3204 4546 : already[iDayType_WinDes] = true;
3205 : }
3206 4546 : OneValid = true;
3207 : }
3208 34885 : if (has(ForDayField, "ALLOTHERDAY")) {
3209 53326 : for (int iDay = 0; iDay < (int)DayType::Num; ++iDay) {
3210 49517 : if (!already[iDay]) {
3211 21562 : these[iDay] = already[iDay] = true;
3212 : }
3213 : }
3214 3809 : OneValid = true;
3215 : }
3216 :
3217 34885 : if (DupAssignment) {
3218 0 : ShowSevereError(state, format("ProcessForDayTypes: Duplicate assignment attempted in \"for\" days field={}", ForDayField));
3219 0 : ErrorsFound = true;
3220 : }
3221 34885 : if (!OneValid) {
3222 0 : ShowSevereError(state, format("ProcessForDayTypes: No valid day assignments found in \"for\" days field={}", ForDayField));
3223 0 : ErrorsFound = true;
3224 : }
3225 34885 : } // ProcessScheduleInput()
3226 :
3227 74023 : void DaySchedule::setMinMaxVals([[maybe_unused]] EnergyPlusData &state)
3228 : {
3229 74023 : assert(!this->isMinMaxSet);
3230 :
3231 74023 : auto const &s_glob = state.dataGlobal;
3232 :
3233 74023 : this->minVal = this->maxVal = this->tsVals[0];
3234 8603887 : for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
3235 8529864 : Real64 value = this->tsVals[i];
3236 8529864 : if (value < this->minVal) {
3237 11692 : this->minVal = value;
3238 8518172 : } else if (value > this->maxVal) {
3239 257804 : this->maxVal = value;
3240 : }
3241 : }
3242 :
3243 74023 : this->isMinMaxSet = true;
3244 74023 : }
3245 :
3246 62365 : void WeekSchedule::setMinMaxVals(EnergyPlusData &state)
3247 : {
3248 62365 : assert(!this->isMinMaxSet);
3249 :
3250 62365 : auto *daySched1 = this->dayScheds[1];
3251 62365 : if (!daySched1->isMinMaxSet) {
3252 62171 : daySched1->setMinMaxVals(state);
3253 : }
3254 :
3255 62365 : this->minVal = daySched1->minVal;
3256 62365 : this->maxVal = daySched1->maxVal;
3257 :
3258 62365 : auto *daySchedPrev = daySched1;
3259 748380 : for (int iDay = 2; iDay < (int)DayType::Num; ++iDay) {
3260 686015 : auto *daySched = this->dayScheds[iDay];
3261 686015 : if (daySched == daySchedPrev) {
3262 661041 : continue;
3263 : }
3264 :
3265 24974 : if (!daySched->isMinMaxSet) {
3266 11838 : daySched->setMinMaxVals(state);
3267 : }
3268 24974 : if (daySched->minVal < this->minVal) {
3269 1805 : this->minVal = daySched->minVal;
3270 : }
3271 24974 : if (daySched->maxVal > this->maxVal) {
3272 4526 : this->maxVal = daySched->maxVal;
3273 : }
3274 24974 : daySchedPrev = daySched;
3275 : }
3276 :
3277 62365 : this->isMinMaxSet = true;
3278 62365 : } // ScheduleWeek::setMinMaxVals()
3279 :
3280 16088 : void ScheduleDetailed::setMinMaxVals(EnergyPlusData &state)
3281 : {
3282 16088 : assert(!this->isMinMaxSet);
3283 :
3284 16088 : auto *weekSched1 = this->weekScheds[1];
3285 16088 : if (!weekSched1->isMinMaxSet) {
3286 16084 : weekSched1->setMinMaxVals(state);
3287 : }
3288 :
3289 16088 : this->minVal = weekSched1->minVal;
3290 16088 : this->maxVal = weekSched1->maxVal;
3291 :
3292 16088 : auto *weekSchedPrev = weekSched1;
3293 :
3294 5888208 : for (int iWeek = 2; iWeek <= 366; ++iWeek) {
3295 5872120 : auto *weekSched = this->weekScheds[iWeek];
3296 5872120 : if (iWeek == 366 && weekSched == nullptr) {
3297 0 : continue;
3298 : }
3299 5872120 : if (weekSched == weekSchedPrev) {
3300 5825836 : continue;
3301 : }
3302 46284 : if (!weekSched->isMinMaxSet) {
3303 46281 : weekSched->setMinMaxVals(state);
3304 : }
3305 :
3306 46284 : if (weekSched->minVal < this->minVal) {
3307 1139 : this->minVal = weekSched->minVal;
3308 : }
3309 46284 : if (weekSched->maxVal > this->maxVal) {
3310 2719 : this->maxVal = weekSched->maxVal;
3311 : }
3312 46284 : weekSchedPrev = weekSched;
3313 : }
3314 :
3315 16088 : this->isMinMaxSet = true;
3316 16088 : }
3317 :
3318 0 : bool CheckScheduleValueMin(EnergyPlusData &state,
3319 : int const schedNum, // Which Schedule being tested
3320 : Clusive clu,
3321 : Real64 const min // Minimum desired value
3322 : )
3323 : {
3324 : // FUNCTION INFORMATION:
3325 : // AUTHOR Linda K. Lawrie
3326 : // DATE WRITTEN February 2003
3327 :
3328 : // PURPOSE OF THIS FUNCTION:
3329 : // This function checks the indicated schedule values for validity.
3330 :
3331 : // METHODOLOGY EMPLOYED:
3332 : // Schedule data structure stores this on first validity check. If there, then is returned else
3333 : // looks up minimum and maximum values for the schedule and then sets result of function based on
3334 : // requested minimum/maximum checks.
3335 :
3336 0 : return state.dataSched->schedules[schedNum]->checkMinVal(state, clu, min);
3337 : }
3338 :
3339 22815 : bool ScheduleBase::checkMinVal(EnergyPlusData &state, Clusive clu, Real64 min)
3340 : {
3341 22815 : if (!this->isMinMaxSet) { // Set Minimum/Maximums for this schedule
3342 1937 : this->setMinMaxVals(state);
3343 : }
3344 :
3345 : // Min/max for schedule has been set. Test.
3346 22815 : return (clu == Clusive::In) ? (FLT_EPSILON >= min - this->minVal) : (this->minVal > min);
3347 : } // ScheduleDetailed::checkMinVal()
3348 :
3349 2670 : bool ScheduleBase::checkMaxVal(EnergyPlusData &state, Clusive cluMax, Real64 const max)
3350 : {
3351 2670 : if (!this->isMinMaxSet) {
3352 0 : this->setMinMaxVals(state);
3353 : }
3354 :
3355 2670 : return (cluMax == Clusive::Ex) ? (this->maxVal < max) : (this->maxVal - max <= FLT_EPSILON);
3356 : }
3357 :
3358 28102 : bool ScheduleBase::checkMinMaxVals(EnergyPlusData &state,
3359 : Clusive cluMin, // Minimum indicator ('>', '>=')
3360 : Real64 const min, // Minimum desired value
3361 : Clusive cluMax, // Maximum indicator ('<', ',=')
3362 : Real64 const max) // Maximum desired value
3363 : {
3364 : // FUNCTION INFORMATION:
3365 : // AUTHOR Linda K. Lawrie
3366 : // DATE WRITTEN February 2003
3367 :
3368 : // PURPOSE OF THIS FUNCTION:
3369 : // This function checks the indicated schedule values for validity.
3370 :
3371 : // METHODOLOGY EMPLOYED:
3372 : // Schedule data structure stores this on first validity check. If there, then is returned else
3373 : // looks up minimum and maximum values for the schedule and then sets result of function based on
3374 : // requested minimum/maximum checks.
3375 :
3376 28102 : if (!this->isMinMaxSet) {
3377 14172 : this->setMinMaxVals(state);
3378 : }
3379 :
3380 28102 : bool minOk = (cluMin == Clusive::Ex) ? (this->minVal > min) : (FLT_EPSILON >= min - this->minVal);
3381 28102 : bool maxOk = (cluMax == Clusive::Ex) ? (this->maxVal < max) : (this->maxVal - max <= FLT_EPSILON);
3382 :
3383 28102 : return (minOk && maxOk);
3384 : } // ScheduleBase::checkMinMaxVals()
3385 :
3386 0 : bool CheckScheduleValueMinMax(EnergyPlusData &state,
3387 : int const schedNum, // Which Schedule being tested
3388 : Clusive cluMin, // Minimum indicator ('>', '>=')
3389 : Real64 const min, // Minimum desired value
3390 : Clusive cluMax, // Maximum indicator ('<', ',=')
3391 : Real64 const max // Maximum desired value
3392 : )
3393 : {
3394 : // Wrapper for method
3395 0 : return state.dataSched->schedules[schedNum]->checkMinMaxVals(state, cluMin, min, cluMax, max);
3396 : } // CheckScheduleValueMinMax()
3397 :
3398 59 : bool ScheduleConstant::hasVal([[maybe_unused]] EnergyPlusData &state, Real64 const value) const
3399 : {
3400 59 : return value == this->currentVal;
3401 : } // ScheduleConstant::hasVal()
3402 :
3403 11758 : bool ScheduleDetailed::hasVal(EnergyPlusData &state, Real64 const value) const
3404 : {
3405 11758 : auto const &s_sched = state.dataSched;
3406 11758 : auto const &s_glob = state.dataGlobal;
3407 :
3408 : // These arrays make sure you don't check the same day or week schedule twice
3409 11758 : std::vector<bool> weekSchedChecked;
3410 11758 : weekSchedChecked.resize(s_sched->weekSchedules.size());
3411 11758 : std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
3412 :
3413 11758 : std::vector<bool> daySchedChecked;
3414 11758 : daySchedChecked.resize(s_sched->daySchedules.size());
3415 11758 : std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
3416 :
3417 4172080 : for (int iWeek = 1; iWeek <= 366; ++iWeek) {
3418 4160713 : auto const *weekSched = this->weekScheds[iWeek];
3419 4160713 : if (weekSchedChecked[weekSched->Num]) {
3420 4147041 : continue;
3421 : }
3422 :
3423 173046 : for (int iDay = 1; iDay < (int)DayType::Num; ++iDay) {
3424 159765 : auto const *daySched = weekSched->dayScheds[iDay];
3425 159765 : if (daySchedChecked[daySched->Num]) {
3426 144403 : continue;
3427 : }
3428 :
3429 1928210 : for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
3430 1913239 : if (daySched->tsVals[i] == value) {
3431 391 : return true;
3432 : }
3433 : }
3434 14971 : daySchedChecked[daySched->Num] = true;
3435 : }
3436 13281 : weekSchedChecked[weekSched->Num] = true;
3437 : }
3438 :
3439 11367 : return false;
3440 11758 : } // ScheduleDetailed::hasVal()
3441 :
3442 0 : bool CheckScheduleValue(EnergyPlusData &state,
3443 : int const schedNum, // Which Schedule being tested
3444 : Real64 const value // Actual desired value
3445 : )
3446 : {
3447 : // Method wrapper
3448 0 : return state.dataSched->schedules[schedNum]->hasVal(state, value);
3449 : }
3450 :
3451 0 : bool CheckDayScheduleMinValues(EnergyPlusData &state,
3452 : int const schedNum, // Which Day Schedule being tested
3453 : Clusive cluMin,
3454 : Real64 const min)
3455 : {
3456 : // Method wrapper
3457 0 : return state.dataSched->daySchedules[schedNum]->checkMinVal(state, cluMin, min);
3458 : } // CheckDayScheduleMinValues()
3459 :
3460 0 : bool ScheduleConstant::hasFractionalVal([[maybe_unused]] EnergyPlusData &state) const
3461 : {
3462 0 : return (this->currentVal > 0.0) && (this->currentVal < 1.0);
3463 : } // ScheduleYear::hasFractionalVal()
3464 :
3465 160 : bool ScheduleDetailed::hasFractionalVal(EnergyPlusData &state) const
3466 : {
3467 160 : auto const &s_sched = state.dataSched;
3468 160 : auto const &s_glob = state.dataGlobal;
3469 :
3470 : // These arrays make sure you don't check the same day or week schedule twice
3471 160 : std::vector<bool> weekSchedChecked;
3472 160 : weekSchedChecked.resize(s_sched->weekSchedules.size());
3473 160 : std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
3474 :
3475 160 : std::vector<bool> daySchedChecked;
3476 160 : daySchedChecked.resize(s_sched->daySchedules.size());
3477 160 : std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
3478 :
3479 58720 : for (int iWeek = 1; iWeek <= 366; ++iWeek) {
3480 58560 : auto const *weekSched = this->weekScheds[iWeek];
3481 58560 : if (weekSchedChecked[weekSched->Num]) {
3482 58350 : continue;
3483 : }
3484 :
3485 2730 : for (int iDay = 1; iDay < (int)DayType::Num; ++iDay) {
3486 2520 : auto const *daySched = weekSched->dayScheds[iDay];
3487 2520 : if (daySchedChecked[daySched->Num]) {
3488 2188 : continue;
3489 : }
3490 :
3491 38060 : for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
3492 37728 : if (daySched->tsVals[i] > 0.0 && daySched->tsVals[i] < 1.0) {
3493 0 : return true;
3494 : }
3495 : }
3496 332 : daySchedChecked[daySched->Num] = true;
3497 : }
3498 210 : weekSchedChecked[weekSched->Num] = true;
3499 : }
3500 :
3501 160 : return false;
3502 160 : } // ScheduleDetailed::hasFractionalVal()
3503 :
3504 332 : std::pair<Real64, Real64> ScheduleConstant::getMinMaxValsByDayType([[maybe_unused]] EnergyPlusData &state,
3505 : [[maybe_unused]] DayTypeGroup const days)
3506 : {
3507 332 : return std::make_pair(this->currentVal, this->currentVal);
3508 : } // ScheduleConstant::getMinMaxValsByDayType()
3509 :
3510 53628 : std::pair<Real64, Real64> ScheduleDetailed::getMinMaxValsByDayType(EnergyPlusData &state, DayTypeGroup const days)
3511 : {
3512 : // J. Glazer - March 2024
3513 : // finds the minimum and maximum for a specific set of day types for a given schedule
3514 53628 : constexpr std::array<std::array<bool, (int)DayType::Num>, (int)DayTypeGroup::Num> dayTypeFilters = {{
3515 : // Unused Sun Mon Tues Wed Thur Fri Sat Hol Summer Winter Cust1 Cust2
3516 : {false, false, true, true, true, true, true, false, false, false, false, false, false}, // Weekday
3517 : {false, true, false, false, false, false, false, true, true, false, false, false, false}, // WeekendHoliday
3518 : {false, false, false, false, false, false, false, false, false, true, false, false, false}, // SummerDesign
3519 : {false, false, false, false, false, false, false, false, false, false, true, false, false} // WinterDesign
3520 : }};
3521 :
3522 53628 : auto const &s_sched = state.dataSched;
3523 :
3524 53628 : if (!this->isMinMaxSet) {
3525 0 : this->setMinMaxVals(state);
3526 : }
3527 :
3528 53628 : if (!this->MaxMinByDayTypeSet[(int)days]) {
3529 :
3530 9568 : bool firstSet = true;
3531 9568 : std::array<bool, (int)DayType::Num> const &dayTypeFilter = dayTypeFilters[(int)days];
3532 :
3533 : // These arrays make sure you don't check the same day or week schedule twice
3534 9568 : std::vector<bool> weekSchedChecked;
3535 9568 : weekSchedChecked.resize(s_sched->weekSchedules.size());
3536 9568 : std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
3537 :
3538 9568 : std::vector<bool> daySchedChecked;
3539 9568 : daySchedChecked.resize(s_sched->daySchedules.size());
3540 9568 : std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
3541 :
3542 9568 : this->MinByDayType[(int)days] = this->MaxByDayType[(int)days] = 0.0;
3543 :
3544 3511456 : for (int iDay = 1; iDay <= 366; ++iDay) {
3545 3501888 : auto const *weekSched = this->weekScheds[iDay];
3546 3501888 : if (weekSchedChecked[weekSched->Num]) {
3547 3488104 : continue;
3548 : }
3549 :
3550 179192 : for (int jDayType = 1; jDayType < (int)DayType::Num; ++jDayType) {
3551 165408 : if (!dayTypeFilter[jDayType]) {
3552 130948 : continue;
3553 : }
3554 :
3555 34460 : auto *daySched = weekSched->dayScheds[jDayType];
3556 34460 : if (daySchedChecked[daySched->Num]) {
3557 20437 : continue;
3558 : }
3559 :
3560 14023 : if (!daySched->isMinMaxSet) {
3561 0 : daySched->setMinMaxVals(state);
3562 : }
3563 :
3564 14023 : if (firstSet) {
3565 9568 : this->MinByDayType[(int)days] = daySched->minVal;
3566 9568 : this->MaxByDayType[(int)days] = daySched->maxVal;
3567 9568 : firstSet = false;
3568 : } else {
3569 4455 : this->MinByDayType[(int)days] = min(this->MinByDayType[(int)days], daySched->minVal);
3570 4455 : this->MaxByDayType[(int)days] = max(this->MaxByDayType[(int)days], daySched->maxVal);
3571 : }
3572 :
3573 14023 : daySchedChecked[daySched->Num] = true;
3574 : }
3575 13784 : weekSchedChecked[weekSched->Num] = true;
3576 : }
3577 9568 : this->MaxMinByDayTypeSet[(int)days] = true;
3578 9568 : }
3579 107256 : return std::make_pair(this->MinByDayType[(int)days], this->MaxByDayType[(int)days]);
3580 : } // ScheduleDetailed::getMinMaxValsByDayType()
3581 :
3582 2828211 : void ReportScheduleVals(EnergyPlusData &state)
3583 : {
3584 : // SUBROUTINE INFORMATION:
3585 : // AUTHOR Linda Lawrie
3586 : // DATE WRITTEN February 2004
3587 :
3588 : // PURPOSE OF THIS SUBROUTINE:
3589 : // This subroutine puts the proper current schedule values into the "reporting"
3590 : // slot for later reporting.
3591 2828211 : auto const &s_sched = state.dataSched;
3592 :
3593 2828211 : if (s_sched->DoScheduleReportingSetup) { // CurrentModuleObject='Any Schedule'
3594 19665 : for (auto *sched : s_sched->schedules) {
3595 : // No variables for the built-in AlwaysOn and AlwaysOff schedules
3596 18864 : if (sched->Num == SchedNum_AlwaysOff || sched->Num == SchedNum_AlwaysOn) {
3597 1602 : continue;
3598 : }
3599 :
3600 : // Set Up Reporting
3601 34524 : SetupOutputVariable(state,
3602 : "Schedule Value",
3603 : Constant::Units::None,
3604 17262 : sched->currentVal,
3605 : OutputProcessor::TimeStepType::Zone,
3606 : OutputProcessor::StoreType::Average,
3607 17262 : sched->Name);
3608 801 : }
3609 801 : s_sched->DoScheduleReportingSetup = false;
3610 : }
3611 :
3612 2828211 : UpdateScheduleVals(state);
3613 2828211 : }
3614 :
3615 799 : void ReportOrphanSchedules(EnergyPlusData &state)
3616 : {
3617 : // SUBROUTINE INFORMATION:
3618 : // AUTHOR Linda Lawrie
3619 : // DATE WRITTEN April 2008
3620 :
3621 : // PURPOSE OF THIS SUBROUTINE:
3622 : // In response to CR7498, report orphan (unused) schedule items.
3623 :
3624 799 : bool NeedOrphanMessage = true;
3625 799 : bool NeedUseMessage = false;
3626 799 : int NumCount = 0;
3627 :
3628 799 : auto const &s_sched = state.dataSched;
3629 799 : auto const &s_glob = state.dataGlobal;
3630 :
3631 19583 : for (auto const *sched : s_sched->schedules) {
3632 18784 : if (sched->isUsed) {
3633 17960 : continue;
3634 : }
3635 824 : if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
3636 2 : ShowWarningError(state, "The following schedule names are \"Unused Schedules\". These schedules are in the idf");
3637 2 : ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
3638 1 : NeedOrphanMessage = false;
3639 : }
3640 824 : if (s_glob->DisplayUnusedSchedules) {
3641 1 : ShowMessage(state, format("Schedule:Year or Schedule:Compact or Schedule:File or Schedule:Constant={}", sched->Name));
3642 : } else {
3643 823 : ++NumCount;
3644 : }
3645 799 : }
3646 :
3647 799 : if (NumCount > 0) {
3648 102 : ShowMessage(state, format("There are {} unused schedules in input.", NumCount));
3649 102 : NeedUseMessage = true;
3650 : }
3651 :
3652 799 : NeedOrphanMessage = true;
3653 799 : NumCount = 0;
3654 :
3655 114025 : for (auto *weekSched : s_sched->weekSchedules) {
3656 113226 : if (weekSched->isUsed) {
3657 71981 : continue;
3658 : }
3659 41245 : if (weekSched->Name.empty()) {
3660 0 : continue;
3661 : }
3662 41245 : if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
3663 0 : ShowWarningError(state, "The following week schedule names are \"Unused Schedules\". These schedules are in the idf");
3664 0 : ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
3665 0 : NeedOrphanMessage = false;
3666 : }
3667 41245 : if (s_glob->DisplayUnusedSchedules) {
3668 0 : ShowMessage(state, format("Schedule:Week:Daily or Schedule:Week:Compact={}", weekSched->Name));
3669 : } else {
3670 41245 : ++NumCount;
3671 : }
3672 799 : }
3673 :
3674 799 : if (NumCount > 0) {
3675 2 : ShowMessage(state, fmt::format("There are {} unused week schedules in input.", NumCount));
3676 1 : NeedUseMessage = true;
3677 : }
3678 :
3679 799 : NeedOrphanMessage = true;
3680 799 : NumCount = 0;
3681 :
3682 125762 : for (auto *daySched : s_sched->daySchedules) {
3683 124963 : if (daySched->isUsed) {
3684 83708 : continue;
3685 : }
3686 41255 : if (daySched->Name.empty()) {
3687 0 : continue;
3688 : }
3689 41255 : if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
3690 0 : ShowWarningError(state, "The following day schedule names are \"Unused Schedules\". These schedules are in the idf");
3691 0 : ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
3692 0 : NeedOrphanMessage = false;
3693 : }
3694 :
3695 41255 : if (s_glob->DisplayUnusedSchedules) {
3696 0 : ShowMessage(state, format("Schedule:Day:Hourly or Schedule:Day:Interval or Schedule:Day:List={}", daySched->Name));
3697 : } else {
3698 41255 : ++NumCount;
3699 : }
3700 799 : }
3701 :
3702 799 : if (NumCount > 0) {
3703 6 : ShowMessage(state, format("There are {} unused day schedules in input.", NumCount));
3704 6 : NeedUseMessage = true;
3705 : }
3706 :
3707 799 : if (NeedUseMessage) {
3708 309 : ShowMessage(state, "Use Output:Diagnostics,DisplayUnusedSchedules; to see them.");
3709 : }
3710 799 : } // ReportOrphanSchedules()
3711 :
3712 : // returns the annual full load hours for a schedule - essentially the sum of the hourly values
3713 44 : Real64 ScheduleConstant::getAnnualHoursFullLoad([[maybe_unused]] EnergyPlusData &state,
3714 : int const StartDayOfWeek, // Day of week for start of year
3715 : bool const isLeapYear // true if it is a leap year containing February 29
3716 : )
3717 : {
3718 44 : if (StartDayOfWeek < iDayType_Sun || StartDayOfWeek > iDayType_Sat) {
3719 0 : return 0.0; // Assert this instead?
3720 : }
3721 :
3722 44 : int DaysInYear = (isLeapYear) ? 366 : 365;
3723 44 : return DaysInYear * Constant::iHoursInDay * this->currentVal;
3724 : }
3725 :
3726 : // returns the annual full load hours for a schedule - essentially the sum of the hourly values
3727 11363 : Real64 ScheduleDetailed::getAnnualHoursFullLoad(EnergyPlusData &state,
3728 : int const StartDayOfWeek, // Day of week for start of year
3729 : bool const isLeapYear // true if it is a leap year containing February 29
3730 : )
3731 : {
3732 : // J. Glazer - July 2017
3733 : // adapted from Linda K. Lawrie original code for ScheduleAverageHoursPerWeek()
3734 11363 : auto const &s_glob = state.dataGlobal;
3735 :
3736 11363 : int DaysInYear = (isLeapYear) ? 366 : 365;
3737 :
3738 11363 : int DayT = StartDayOfWeek;
3739 11363 : Real64 TotalHours = 0.0;
3740 :
3741 11363 : if (DayT < iDayType_Sun || DayT > iDayType_Sat) {
3742 0 : return TotalHours;
3743 : }
3744 :
3745 4158874 : for (int iDay = 1; iDay <= DaysInYear; ++iDay) {
3746 4147511 : auto const *weekSched = this->weekScheds[iDay];
3747 4147511 : auto const *daySched = weekSched->dayScheds[DayT];
3748 :
3749 4147511 : TotalHours += daySched->sumTsVals / double(s_glob->TimeStepsInHour);
3750 4147511 : ++DayT;
3751 4147511 : if (DayT > iDayType_Sat) {
3752 590892 : DayT = iDayType_Sun;
3753 : }
3754 : }
3755 :
3756 11363 : return TotalHours;
3757 : }
3758 :
3759 : // returns the average number of hours per week based on the schedule index provided
3760 4482 : Real64 Schedule::getAverageWeeklyHoursFullLoad(EnergyPlusData &state,
3761 : int const StartDayOfWeek, // Day of week for start of year
3762 : bool const isLeapYear // true if it is a leap year containing February 29
3763 : )
3764 : {
3765 : // FUNCTION INFORMATION:
3766 : // AUTHOR Linda K. Lawrie
3767 : // DATE WRITTEN August 2006
3768 : // MODIFIED September 2012; Glazer - CR8849
3769 :
3770 : // PURPOSE OF THIS FUNCTION:
3771 : // This function returns the "average" hours per week for a schedule over
3772 : // the entire year.
3773 :
3774 4482 : Real64 WeeksInYear = (isLeapYear) ? (366.0 / 7.0) : (365.0 / 7.0);
3775 4482 : return this->getAnnualHoursFullLoad(state, StartDayOfWeek, isLeapYear) / WeeksInYear;
3776 : }
3777 :
3778 : // returns the annual hours greater than 1% for a schedule - essentially the number of hours with any operation
3779 6884 : Real64 ScheduleDetailed::getAnnualHoursGreaterThan1Percent(EnergyPlusData &state,
3780 : int const StartDayOfWeek, // Day of week for start of year
3781 : bool const isItLeapYear // true if it is a leap year containing February 29
3782 : )
3783 : {
3784 : // J. Glazer - July 2017
3785 : // adapted from Linda K. Lawrie original code for ScheduleAverageHoursPerWeek()
3786 6884 : auto const &s_glob = state.dataGlobal;
3787 :
3788 6884 : int DaysInYear = (isItLeapYear) ? 366 : 365;
3789 :
3790 6884 : int DayT = StartDayOfWeek;
3791 6884 : Real64 TotalHours = 0.0;
3792 :
3793 6884 : if (DayT < iDayType_Sun || DayT > iDayType_Sat) {
3794 0 : return TotalHours;
3795 : }
3796 :
3797 2519555 : for (int iDay = 1; iDay <= DaysInYear; ++iDay) {
3798 2512671 : auto const *weekSched = this->weekScheds[iDay];
3799 2512671 : auto const *daySched = weekSched->dayScheds[DayT];
3800 307475607 : for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
3801 304962936 : if (daySched->tsVals[i] > 0.0) {
3802 224264355 : TotalHours += s_glob->TimeStepZone;
3803 : }
3804 : }
3805 :
3806 2512671 : ++DayT;
3807 2512671 : if (DayT > iDayType_Sat) {
3808 357979 : DayT = iDayType_Sun;
3809 : }
3810 : }
3811 :
3812 6884 : return TotalHours;
3813 : } // ScheduleDetailed::getAnnualHoursGreaterThan1Percent()
3814 :
3815 : // returns the annual hours greater than 1% for a schedule - essentially the number of hours with any operation
3816 41 : Real64 ScheduleConstant::getAnnualHoursGreaterThan1Percent([[maybe_unused]] EnergyPlusData &state,
3817 : int const StartDayOfWeek, // Day of week for start of year
3818 : bool const isItLeapYear // true if it is a leap year containing February 29
3819 : )
3820 : {
3821 41 : int DaysInYear = (isItLeapYear) ? 366 : 365;
3822 :
3823 41 : if (StartDayOfWeek < iDayType_Sun || StartDayOfWeek > iDayType_Sat) {
3824 0 : return 0.0; // Assert this instead?
3825 : }
3826 :
3827 41 : return (this->currentVal > 0.0) ? (Constant::rHoursInDay * DaysInYear) : 0;
3828 : } // ScheduleConstant::getHoursGreaterThan1Percent()
3829 :
3830 : // returns the temperature value from a schedule at a certain time for the first day of the week in either January or July
3831 : std::tuple<Real64, int, std::string>
3832 3736 : ScheduleDetailed::getValAndCountOnDay(EnergyPlusData &state, bool const isSummer, DayType const dayOfWeek, int const hourOfDay)
3833 : {
3834 : // J.Glazer - Aug 2017
3835 :
3836 3736 : auto const &s_glob = state.dataGlobal;
3837 :
3838 : // determine month to use based on hemiphere and season
3839 : int month;
3840 3736 : if (isSummer) {
3841 1850 : month = (state.dataEnvrn->Latitude > 0.) ? 7 : 1;
3842 : } else {
3843 1886 : month = (state.dataEnvrn->Latitude > 0.) ? 1 : 7;
3844 : }
3845 :
3846 3736 : std::string monthName = (month == 1) ? "January" : "July";
3847 :
3848 3736 : int jdateSelect = General::nthDayOfWeekOfMonth(state, (int)dayOfWeek, 1, month);
3849 :
3850 : // determine number of days in year
3851 3736 : int DaysInYear = (state.dataEnvrn->CurrentYearIsLeapYear) ? 366 : 365;
3852 :
3853 : // should adjust date if lands on a holiday but for now assume that it does not
3854 :
3855 : // adjust time of day for daylight savings time
3856 3736 : int hourSelect = hourOfDay + state.dataWeather->DSTIndex(jdateSelect);
3857 :
3858 : // get the value at the selected time
3859 3736 : int constexpr firstTimeStep = 1;
3860 3736 : auto const *weekSched = this->weekScheds[jdateSelect];
3861 3736 : auto const *daySched = weekSched->dayScheds[(int)dayOfWeek];
3862 :
3863 3736 : Real64 value = daySched->tsVals[(hourSelect - 1) * state.dataGlobal->TimeStepsInHour + (firstTimeStep - 1)];
3864 3736 : int countOfSame = 0;
3865 :
3866 : // count the number of times with that same value
3867 1367384 : for (int jdateOfYear = 1; jdateOfYear <= DaysInYear; ++jdateOfYear) {
3868 1363648 : auto const *wSched = this->weekScheds[jdateOfYear];
3869 1363648 : if (wSched == weekSched) { // if same week schedule can short circuit rest of testing and increment counter
3870 1350820 : ++countOfSame;
3871 1350820 : continue;
3872 : }
3873 :
3874 12828 : auto const *dSched = wSched->dayScheds[(int)dayOfWeek];
3875 12828 : if (dSched == daySched) { // if same day schedule can short circuit rest of testing and increment counter
3876 12 : ++countOfSame;
3877 12 : continue;
3878 : }
3879 :
3880 12816 : if (dSched->tsVals[(hourSelect - 1) * s_glob->TimeStepsInHour + (firstTimeStep - 1)] == value) {
3881 6250 : ++countOfSame;
3882 : }
3883 : }
3884 :
3885 7472 : return std::make_tuple(value, countOfSame, monthName);
3886 3736 : } // ScheduleDetailed::getValAndCountOnDay()
3887 :
3888 : // returns the temperature value from a schedule at a certain time for the first day of the week in either January or July
3889 18 : std::tuple<Real64, int, std::string> ScheduleConstant::getValAndCountOnDay(EnergyPlusData &state,
3890 : bool const isSummer,
3891 : [[maybe_unused]] DayType const dayOfWeek,
3892 : [[maybe_unused]] int const hourOfDay)
3893 : {
3894 : // determine month to use based on hemiphere and season
3895 : int month;
3896 18 : if (isSummer) {
3897 10 : month = (state.dataEnvrn->Latitude > 0.) ? 7 : 1;
3898 : } else {
3899 8 : month = (state.dataEnvrn->Latitude > 0.) ? 1 : 7;
3900 : }
3901 :
3902 18 : std::string monthName = (month == 1) ? "January" : "July";
3903 18 : int DaysInYear = (state.dataEnvrn->CurrentYearIsLeapYear) ? 366 : 365;
3904 36 : return std::make_tuple(this->currentVal, DaysInYear, monthName);
3905 18 : } // ScheduleConstant::getValAndCountOnDay()
3906 :
3907 0 : void ShowSevereBadMin(EnergyPlusData &state,
3908 : ErrorObjectHeader const &eoh,
3909 : std::string_view fieldName,
3910 : std::string_view fieldVal,
3911 : Clusive cluMin,
3912 : Real64 minVal,
3913 : std::string_view msg)
3914 : {
3915 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
3916 0 : ShowContinueError(
3917 0 : state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMin == Clusive::In ? "<" : "<=", minVal));
3918 0 : if (!msg.empty()) {
3919 0 : ShowContinueError(state, format("{}", msg));
3920 : }
3921 0 : }
3922 :
3923 0 : void ShowSevereBadMax(EnergyPlusData &state,
3924 : ErrorObjectHeader const &eoh,
3925 : std::string_view fieldName,
3926 : std::string_view fieldVal,
3927 : Clusive cluMax,
3928 : Real64 maxVal,
3929 : std::string_view msg)
3930 : {
3931 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
3932 0 : ShowContinueError(
3933 0 : state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMax == Clusive::In ? ">" : ">=", maxVal));
3934 0 : if (!msg.empty()) {
3935 0 : ShowContinueError(state, format("{}", msg));
3936 : }
3937 0 : }
3938 :
3939 0 : void ShowSevereBadMinMax(EnergyPlusData &state,
3940 : ErrorObjectHeader const &eoh,
3941 : std::string_view fieldName,
3942 : std::string_view fieldVal,
3943 : Clusive cluMin,
3944 : Real64 minVal,
3945 : Clusive cluMax,
3946 : Real64 maxVal,
3947 : std::string_view msg)
3948 : {
3949 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
3950 0 : ShowContinueError(state,
3951 0 : format("{} = {}, schedule contains values that are {} {} and/or {} {}",
3952 : fieldName,
3953 : fieldVal,
3954 0 : cluMin == Clusive::In ? "<" : "<=",
3955 : minVal,
3956 0 : cluMax == Clusive::In ? ">" : ">=",
3957 : maxVal));
3958 0 : if (!msg.empty()) {
3959 0 : ShowContinueError(state, format("{}", msg));
3960 : }
3961 0 : }
3962 :
3963 0 : void ShowWarningBadMin(EnergyPlusData &state,
3964 : ErrorObjectHeader const &eoh,
3965 : std::string_view fieldName,
3966 : std::string_view fieldVal,
3967 : Clusive cluMin,
3968 : Real64 minVal,
3969 : std::string_view msg)
3970 : {
3971 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
3972 0 : ShowContinueError(
3973 0 : state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMin == Clusive::In ? "<" : "<=", minVal));
3974 0 : if (!msg.empty()) {
3975 0 : ShowContinueError(state, format("{}", msg));
3976 : }
3977 0 : }
3978 :
3979 0 : void ShowWarningBadMax(EnergyPlusData &state,
3980 : ErrorObjectHeader const &eoh,
3981 : std::string_view fieldName,
3982 : std::string_view fieldVal,
3983 : Clusive cluMax,
3984 : Real64 maxVal,
3985 : std::string_view msg)
3986 : {
3987 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
3988 0 : ShowContinueError(
3989 0 : state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMax == Clusive::In ? ">" : ">=", maxVal));
3990 0 : if (!msg.empty()) {
3991 0 : ShowContinueError(state, format("{}", msg));
3992 : }
3993 0 : }
3994 :
3995 0 : void ShowWarningBadMinMax(EnergyPlusData &state,
3996 : ErrorObjectHeader const &eoh,
3997 : std::string_view fieldName,
3998 : std::string_view fieldVal,
3999 : Clusive cluMin,
4000 : Real64 minVal,
4001 : Clusive cluMax,
4002 : Real64 maxVal,
4003 : std::string_view msg)
4004 : {
4005 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
4006 0 : ShowContinueError(state,
4007 0 : format("{} = {}, schedule contains values that are {} {} and/or {} {}",
4008 : fieldName,
4009 : fieldVal,
4010 0 : cluMin == Clusive::In ? "<" : "<=",
4011 : minVal,
4012 0 : cluMax == Clusive::In ? ">" : ">=",
4013 : maxVal));
4014 0 : if (!msg.empty()) {
4015 0 : ShowContinueError(state, format("{}", msg));
4016 : }
4017 0 : }
4018 :
4019 : } // namespace Sched
4020 :
4021 : } // namespace EnergyPlus
|