Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 : #include <cstdlib>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Fmath.hh>
55 : #include <ObjexxFCL/string.functions.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataIPShortCuts.hh>
62 : #include <EnergyPlus/DataRuntimeLanguage.hh>
63 : #include <EnergyPlus/DataSurfaces.hh>
64 : #include <EnergyPlus/General.hh>
65 : #include <EnergyPlus/HVACSystemRootFindingAlgorithm.hh>
66 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
67 : #include <EnergyPlus/UtilityRoutines.hh>
68 : #include <EnergyPlus/WeatherManager.hh>
69 :
70 : #if defined(_WIN32) && _MSC_VER < 1900
71 : #define snprintf _snprintf
72 : #endif
73 :
74 : namespace EnergyPlus::General {
75 :
76 : // Module containing routines for general use
77 :
78 : // MODULE INFORMATION:
79 : // AUTHOR Fred Buhl, Linda Lawrie
80 : // DATE WRITTEN December 2001
81 :
82 : // PURPOSE OF THIS MODULE:
83 : // contains routines (most likely numeric) that may be needed in several parts
84 : // of EnergyPlus
85 :
86 : // MODULE PARAMETER DEFINITIONS
87 : static constexpr std::string_view BlankString;
88 :
89 : enum class ReportType
90 : {
91 : Invalid = -1,
92 : DXF,
93 : DXFWireFrame,
94 : VRML,
95 : Num
96 : };
97 :
98 : constexpr std::array<std::string_view, static_cast<int>(ReportType::Num)> ReportTypeNamesUC{"DXF", "DXF:WIREFRAME", "VRML"};
99 :
100 : enum class AvailRpt
101 : {
102 : Invalid = -1,
103 : None,
104 : NotByUniqueKeyNames,
105 : Verbose,
106 : Num
107 : };
108 :
109 : constexpr std::array<std::string_view, static_cast<int>(AvailRpt::Num)> AvailRptNamesUC{"NONE", "NOTBYUNIQUEKEYNAMES", "VERBOSE"};
110 :
111 : enum class ERLdebugOutputLevel
112 : {
113 : Invalid = -1,
114 : None,
115 : ErrorsOnly,
116 : Verbose,
117 : Num
118 : };
119 :
120 : constexpr std::array<std::string_view, static_cast<int>(ERLdebugOutputLevel::Num)> ERLdebugOutputLevelNamesUC{"NONE", "ERRORSONLY", "VERBOSE"};
121 :
122 : enum class ReportName
123 : {
124 : Invalid = -1,
125 : Constructions,
126 : Viewfactorinfo,
127 : Variabledictionary,
128 : Surfaces,
129 : Energymanagementsystem,
130 : Num
131 : };
132 :
133 : constexpr std::array<std::string_view, static_cast<int>(ReportName::Num)> ReportNamesUC{
134 : "CONSTRUCTIONS", "VIEWFACTORINFO", "VARIABLEDICTIONARY", "SURFACES", "ENERGYMANAGEMENTSYSTEM"};
135 :
136 : enum class RptKey
137 : {
138 : Invalid = -1,
139 : Costinfo,
140 : DXF,
141 : DXFwireframe,
142 : VRML,
143 : Vertices,
144 : Details,
145 : DetailsWithVertices,
146 : Lines,
147 : Num
148 : };
149 :
150 : constexpr std::array<std::string_view, static_cast<int>(RptKey::Num)> RptKeyNamesUC{
151 : "COSTINFO", "DXF", "DXF:WIREFRAME", "VRML", "VERTICES", "DETAILS", "DETAILSWITHVERTICES", "LINES"};
152 :
153 : // A second version that does not require a payload -- use lambdas
154 15416255 : void SolveRoot(const EnergyPlusData &state,
155 : Real64 Eps, // required absolute accuracy
156 : int MaxIte, // maximum number of allowed iterations
157 : int &Flag, // integer storing exit status
158 : Real64 &XRes, // value of x that solves f(x,Par) = 0
159 : const std::function<Real64(Real64)> &f,
160 : Real64 X_0, // 1st bound of interval that contains the solution
161 : Real64 X_1) // 2nd bound of interval that contains the solution
162 : {
163 : // SUBROUTINE INFORMATION:
164 : // AUTHOR Michael Wetter
165 : // DATE WRITTEN March 1999
166 : // MODIFIED Fred Buhl November 2000, R. Raustad October 2006 - made subroutine RECURSIVE
167 : // L. Gu, May 2017 - allow both Bisection and RegulaFalsi
168 :
169 : // PURPOSE OF THIS SUBROUTINE:
170 : // Find the value of x between x0 and x1 such that f(x,Par)
171 : // is equal to zero.
172 :
173 : // METHODOLOGY EMPLOYED:
174 : // Uses the Regula Falsi (false position) method (similar to secant method)
175 :
176 : // REFERENCES:
177 : // See Press et al., Numerical Recipes in Fortran, Cambridge University Press,
178 : // 2nd edition, 1992. Page 347 ff.
179 :
180 : // SUBROUTINE ARGUMENT DEFINITIONS:
181 : // = -2: f(x0) and f(x1) have the same sign
182 : // = -1: no convergence
183 : // > 0: number of iterations performed
184 :
185 15416255 : Real64 constexpr SMALL(1.e-10);
186 15416255 : Real64 X0 = X_0; // present 1st bound
187 15416255 : Real64 X1 = X_1; // present 2nd bound
188 15416255 : Real64 XTemp = X0; // new estimate
189 15416255 : int NIte = 0; // number of interations
190 15416255 : int AltIte = 0; // an accounter used for Alternation choice
191 :
192 15416255 : Real64 Y0 = f(X0); // f at X0
193 15416255 : Real64 Y1 = f(X1); // f at X1
194 : // check initial values
195 15416255 : if (Y0 * Y1 > 0) {
196 415371 : Flag = -2;
197 415371 : XRes = X0;
198 415371 : return;
199 : }
200 15000884 : XRes = XTemp;
201 :
202 : while (true) {
203 :
204 31704654 : Real64 DY = Y0 - Y1;
205 31704654 : if (std::abs(DY) < SMALL) DY = SMALL;
206 31704654 : if (std::abs(X1 - X0) < SMALL) {
207 7988 : break;
208 : }
209 : // new estimation
210 31696666 : switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolver) {
211 31691160 : case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
212 31691160 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
213 31691160 : break;
214 : }
215 0 : case HVACSystemRootSolverAlgorithm::Bisection: {
216 0 : XTemp = (X1 + X0) / 2.0;
217 0 : break;
218 : }
219 5506 : case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
220 5506 : if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
221 71 : XTemp = (X1 + X0) / 2.0;
222 : } else {
223 5435 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
224 : }
225 5506 : break;
226 : }
227 0 : case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
228 0 : if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
229 0 : XTemp = (X1 + X0) / 2.0;
230 : } else {
231 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
232 : }
233 0 : break;
234 : }
235 0 : case HVACSystemRootSolverAlgorithm::Alternation: {
236 0 : if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
237 0 : XTemp = (X1 + X0) / 2.0;
238 0 : if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) AltIte = 0;
239 : } else {
240 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
241 : }
242 0 : break;
243 : }
244 0 : default: {
245 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
246 : }
247 : }
248 :
249 31696666 : Real64 const YTemp = f(XTemp);
250 :
251 31696666 : ++NIte;
252 31696666 : ++AltIte;
253 :
254 : // check convergence
255 31696666 : if (std::abs(YTemp) < Eps) {
256 14992699 : Flag = NIte;
257 14992699 : XRes = XTemp;
258 14992699 : return;
259 : };
260 :
261 : // OK, so we didn't converge, lets check max iterations to see if we should break early
262 16703967 : if (NIte > MaxIte) break;
263 :
264 : // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
265 : // and reassign values (only if further iteration required)
266 16703770 : if (Y0 < 0.0) {
267 14590139 : if (YTemp < 0.0) {
268 6734606 : X0 = XTemp;
269 6734606 : Y0 = YTemp;
270 : } else {
271 7855533 : X1 = XTemp;
272 7855533 : Y1 = YTemp;
273 : }
274 : } else {
275 2113631 : if (YTemp < 0.0) {
276 1304396 : X1 = XTemp;
277 1304396 : Y1 = YTemp;
278 : } else {
279 809235 : X0 = XTemp;
280 809235 : Y0 = YTemp;
281 : }
282 : } // ( Y0 < 0 )
283 16703770 : } // Cont
284 :
285 : // if we make it here we haven't converged, so just set the flag and leave
286 8185 : Flag = -1;
287 8185 : XRes = XTemp;
288 : }
289 :
290 203538 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
291 : {
292 203538 : if (NumItemsInAvg <= 1) return; // no need to average/smooth
293 :
294 201330 : Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
295 :
296 24631794 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
297 24430464 : TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
298 24430464 : DataIn(i) = 0.0;
299 : }
300 :
301 24631794 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
302 231344640 : for (int j = 1; j <= NumItemsInAvg; ++j) {
303 206914176 : DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
304 : }
305 24430464 : DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
306 : }
307 201330 : }
308 :
309 35705 : void ProcessDateString(EnergyPlusData &state,
310 : std::string const &String,
311 : int &PMonth,
312 : int &PDay,
313 : int &PWeekDay,
314 : Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
315 : bool &ErrorsFound,
316 : ObjexxFCL::Optional_int PYear)
317 : {
318 :
319 : // SUBROUTINE INFORMATION:
320 : // AUTHOR Linda Lawrie
321 : // DATE WRITTEN December 1999
322 :
323 : // PURPOSE OF THIS SUBROUTINE:
324 : // This subroutine will process a date from a string and determine
325 : // the proper month and day for that date string.
326 :
327 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
328 : bool errFlag;
329 :
330 35705 : int FstNum = int(Util::ProcessNumber(String, errFlag));
331 35705 : DateType = Weather::DateType::Invalid;
332 35705 : if (!errFlag) {
333 : // Entered single number, do inverse JDay
334 1574 : if (FstNum == 0) {
335 1574 : PMonth = 0;
336 1574 : PDay = 0;
337 1574 : DateType = Weather::DateType::MonthDay;
338 0 : } else if (FstNum < 0 || FstNum > 366) {
339 0 : ShowSevereError(state, format("Invalid Julian date Entered={}", String));
340 0 : ErrorsFound = true;
341 : } else {
342 0 : InvOrdinalDay(FstNum, PMonth, PDay, 0);
343 0 : DateType = Weather::DateType::LastDayInMonth;
344 : }
345 : } else {
346 34131 : int NumTokens = 0;
347 34131 : int TokenDay = 0;
348 34131 : int TokenMonth = 0;
349 34131 : int TokenWeekday = 0;
350 : // Error when processing as number, try x/x
351 34131 : if (!present(PYear)) {
352 32555 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
353 : } else {
354 1576 : int TokenYear = 0;
355 1576 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
356 1576 : PYear = TokenYear;
357 : }
358 34131 : if (DateType == Weather::DateType::MonthDay) {
359 33003 : PDay = TokenDay;
360 33003 : PMonth = TokenMonth;
361 1128 : } else if (DateType == Weather::DateType::NthDayInMonth || DateType == Weather::DateType::LastDayInMonth) {
362 : // interpret as TokenDay TokenWeekday in TokenMonth
363 1128 : PDay = TokenDay;
364 1128 : PMonth = TokenMonth;
365 1128 : PWeekDay = TokenWeekday;
366 : }
367 : }
368 35705 : }
369 :
370 34131 : void DetermineDateTokens(EnergyPlusData &state,
371 : std::string const &String,
372 : int &NumTokens, // Number of tokens found in string
373 : int &TokenDay, // Value of numeric field found
374 : int &TokenMonth, // Value of Month field found (1=Jan, 2=Feb, etc)
375 : int &TokenWeekday, // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
376 : Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
377 : bool &ErrorsFound, // Set to true if cannot process this string as a date
378 : ObjexxFCL::Optional_int TokenYear // Value of Year if one appears to be present and this argument is present
379 : )
380 : {
381 :
382 : // SUBROUTINE INFORMATION:
383 : // AUTHOR Linda Lawrie
384 : // DATE WRITTEN August 2000
385 :
386 : // PURPOSE OF THIS SUBROUTINE:
387 : // This subroutine is invoked for date fields that appear to be strings (give
388 : // error when ProcessNumber is used).
389 :
390 : // METHODOLOGY EMPLOYED:
391 : // Delete everything that is extraneous to the date information needed. Process what
392 : // is left.
393 :
394 : // SUBROUTINE PARAMETER DEFINITIONS:
395 : static constexpr int NumSingleChars(3);
396 : static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
397 : static constexpr int NumDoubleChars(6);
398 : static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
399 : "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want thse only at end of words
400 : static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
401 : static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
402 :
403 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
404 34131 : std::string CurrentString = String;
405 34131 : Array1D_string Fields(3);
406 34131 : bool InternalError = false;
407 34131 : bool WkDayInMonth = false;
408 :
409 34131 : NumTokens = 0;
410 34131 : TokenDay = 0;
411 34131 : TokenMonth = 0;
412 34131 : TokenWeekday = 0;
413 34131 : DateType = Weather::DateType::Invalid;
414 34131 : if (present(TokenYear)) TokenYear = 0;
415 : // Take out separator characters, other extraneous stuff
416 :
417 136524 : for (int Loop = 0; Loop < NumSingleChars; ++Loop) {
418 102393 : size_t Pos = index(CurrentString, SingleChars[Loop]);
419 134878 : while (Pos != std::string::npos) {
420 32485 : CurrentString[Pos] = ' ';
421 32485 : Pos = index(CurrentString, SingleChars[Loop]);
422 : }
423 : }
424 :
425 238917 : for (int Loop = 0; Loop < NumDoubleChars; ++Loop) {
426 204786 : size_t Pos = index(CurrentString, DoubleChars[Loop]);
427 207042 : while (Pos != std::string::npos) {
428 2256 : CurrentString.replace(Pos, 2, " ");
429 2256 : Pos = index(CurrentString, DoubleChars[Loop]);
430 2256 : WkDayInMonth = true;
431 : }
432 : }
433 :
434 34131 : strip(CurrentString);
435 34131 : if (CurrentString == BlankString) {
436 0 : ShowSevereError(state, format("Invalid date field={}", String));
437 0 : ErrorsFound = true;
438 : } else {
439 34131 : int Loop = 0;
440 34131 : bool errFlag = false;
441 : int NumField1;
442 : int NumField2;
443 : int NumField3;
444 103521 : while (Loop < 3) { // Max of 3 fields
445 102393 : if (CurrentString == BlankString) break;
446 69390 : size_t Pos = index(CurrentString, ' ');
447 69390 : ++Loop;
448 69390 : if (Pos == std::string::npos) Pos = CurrentString.length();
449 69390 : Fields(Loop) = CurrentString.substr(0, Pos);
450 69390 : CurrentString.erase(0, Pos);
451 69390 : strip(CurrentString);
452 : }
453 34131 : if (not_blank(CurrentString)) {
454 0 : ShowSevereError(state, format("Invalid date field={}", String));
455 0 : ErrorsFound = true;
456 34131 : } else if (Loop == 2) {
457 : // Field must be Day Month or Month Day (if both numeric, mon / day)
458 33003 : InternalError = false;
459 33003 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
460 33003 : if (errFlag) {
461 : // Month day, but first field is not numeric, 2nd must be
462 499 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
463 499 : if (errFlag) {
464 0 : ShowSevereError(state, format("Invalid date field={}", String));
465 0 : InternalError = true;
466 : } else {
467 499 : TokenDay = NumField2;
468 : }
469 499 : TokenMonth = Util::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
470 499 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
471 499 : if (!InternalError) {
472 499 : DateType = Weather::DateType::MonthDay;
473 : } else {
474 0 : ErrorsFound = true;
475 : }
476 : } else {
477 : // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
478 32504 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
479 32504 : if (!errFlag) {
480 32479 : TokenMonth = NumField1;
481 32479 : TokenDay = NumField2;
482 32479 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
483 32479 : if (!InternalError) {
484 32479 : DateType = Weather::DateType::MonthDay;
485 : } else {
486 0 : ErrorsFound = true;
487 : }
488 : } else { // 2nd field was not numeric. Must be Month
489 25 : TokenDay = NumField1;
490 25 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
491 25 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
492 25 : if (!InternalError) {
493 25 : DateType = Weather::DateType::MonthDay;
494 25 : NumTokens = 2;
495 : } else {
496 0 : ErrorsFound = true;
497 : }
498 : }
499 : }
500 1128 : } else if (Loop == 3) {
501 : // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
502 1128 : if (WkDayInMonth) {
503 1128 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
504 1128 : if (!errFlag) { // the expected result
505 931 : TokenDay = NumField1;
506 931 : TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
507 931 : if (TokenWeekday == 0) {
508 0 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
509 0 : TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
510 0 : if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
511 : } else {
512 931 : TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
513 931 : if (TokenMonth == 0) InternalError = true;
514 : }
515 931 : DateType = Weather::DateType::NthDayInMonth;
516 931 : NumTokens = 3;
517 931 : if (TokenDay < 0 || TokenDay > 5) InternalError = true;
518 : } else { // first field was not numeric....
519 197 : if (Fields(1) == "LA") {
520 197 : DateType = Weather::DateType::LastDayInMonth;
521 197 : NumTokens = 3;
522 197 : TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
523 197 : if (TokenWeekday == 0) {
524 0 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
525 0 : TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
526 0 : if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
527 : } else {
528 197 : TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
529 197 : if (TokenMonth == 0) InternalError = true;
530 : }
531 : } else { // error....
532 0 : ShowSevereError(state, format("First date field not numeric, field={}", String));
533 : }
534 : }
535 : } else { // mm/dd/yyyy or yyyy/mm/dd
536 0 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
537 0 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
538 0 : NumField3 = int(Util::ProcessNumber(Fields(3), errFlag));
539 0 : DateType = Weather::DateType::MonthDay;
540 : // error detection later..
541 0 : if (NumField1 > 100) {
542 0 : if (present(TokenYear)) {
543 0 : TokenYear = NumField1;
544 : }
545 0 : TokenMonth = NumField2;
546 0 : TokenDay = NumField3;
547 0 : } else if (NumField3 > 100) {
548 0 : if (present(TokenYear)) {
549 0 : TokenYear = NumField3;
550 : }
551 0 : TokenMonth = NumField1;
552 0 : TokenDay = NumField2;
553 : }
554 : }
555 : } else {
556 : // Not enough or too many fields
557 0 : ShowSevereError(state, format("Invalid date field={}", String));
558 0 : ErrorsFound = true;
559 : }
560 : }
561 :
562 34131 : if (InternalError) {
563 0 : DateType = Weather::DateType::Invalid;
564 0 : ErrorsFound = true;
565 : }
566 34131 : }
567 :
568 33003 : void ValidateMonthDay(EnergyPlusData &state,
569 : std::string const &String, // REAL(r64) string being processed
570 : int const Day,
571 : int const Month,
572 : bool &ErrorsFound)
573 : {
574 :
575 : // SUBROUTINE INFORMATION:
576 : // AUTHOR Linda Lawrie
577 : // DATE WRITTEN August 2000
578 :
579 : // PURPOSE OF THIS SUBROUTINE:
580 : // This subroutine validates a potential Day, Month values, produces an error
581 : // message when not valid, and sets error flag.
582 :
583 : // SUBROUTINE PARAMETER DEFINITIONS:
584 : static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
585 :
586 33003 : bool InternalError = false;
587 33003 : if (Month < 1 || Month > 12) InternalError = true;
588 33003 : if (!InternalError) {
589 33003 : if (Day < 1 || Day > EndMonthDay[Month - 1]) InternalError = true;
590 : }
591 33003 : if (InternalError) {
592 0 : ShowSevereError(state, format("Invalid Month Day date format={}", String));
593 0 : ErrorsFound = true;
594 : } else {
595 33003 : ErrorsFound = false;
596 : }
597 33003 : }
598 :
599 190238 : int OrdinalDay(int const Month, // Month, 1..12
600 : int const Day, // Day of Month, not validated by month
601 : int const LeapYearValue // 1 if leap year indicated, 0 if not
602 : )
603 : {
604 :
605 : // FUNCTION INFORMATION:
606 : // AUTHOR Linda K. Lawrie
607 : // DATE WRITTEN September 1997
608 : // RE-ENGINEERED from JDAYF in BLAST/IBLAST
609 :
610 : // PURPOSE OF THIS SUBROUTINE:
611 : // This subroutine returns the appropriate Julian Day value for the input
612 : // Month and Day.
613 :
614 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
615 : static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
616 : // End day numbers of each month (without Leap Year)
617 :
618 190238 : if (Month == 1) {
619 : // CASE 1: JANUARY
620 61173 : return Day;
621 :
622 129065 : } else if (Month == 2) {
623 : // CASE 2: FEBRUARY
624 3027 : return Day + EndDayofMonth[0];
625 :
626 126038 : } else if ((Month >= 3) && (Month <= 12)) {
627 : // CASE 3: REMAINING MONTHS
628 126038 : return Day + EndDayofMonth[Month - 2] + LeapYearValue;
629 :
630 : } else {
631 0 : return 0;
632 : }
633 : }
634 :
635 76765 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
636 : {
637 :
638 : // SUBROUTINE INFORMATION:
639 : // AUTHOR Linda Lawrie
640 : // DATE WRITTEN December 1999
641 :
642 : // PURPOSE OF THIS SUBROUTINE:
643 : // This subroutine performs and inverse Julian Day
644 : // calculation, using an input JulianDay and returning
645 : // appropriate Month and Day.
646 :
647 : // SUBROUTINE PARAMETER DEFINITIONS:
648 : static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
649 :
650 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
651 : int WMonth;
652 : int LeapAddPrev;
653 : int LeapAddCur;
654 :
655 76765 : if (Number < 0 || Number > 366) return;
656 496305 : for (WMonth = 1; WMonth <= 12; ++WMonth) {
657 496305 : if (WMonth == 1) {
658 76765 : LeapAddPrev = 0;
659 76765 : LeapAddCur = 0;
660 419540 : } else if (WMonth == 2) {
661 69420 : LeapAddPrev = 0;
662 69420 : LeapAddCur = LeapYr;
663 : } else {
664 350120 : LeapAddPrev = LeapYr;
665 350120 : LeapAddCur = LeapYr;
666 : }
667 496305 : if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) break;
668 : }
669 76765 : PMonth = WMonth;
670 76765 : PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
671 : }
672 :
673 6912 : bool BetweenDateHoursLeftInclusive(
674 : int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
675 : {
676 6912 : Real64 TestRatioOfDay = TestHour / 24.0;
677 6912 : Real64 StartRatioOfDay = StartHour / 24.0;
678 6912 : Real64 EndRatioOfDay = EndHour / 24.0;
679 :
680 6912 : if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
681 5376 : return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
682 : } else { // EndDate < StartDate
683 1536 : return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
684 : }
685 : }
686 :
687 16 : bool BetweenDates(int const TestDate, // Date to test
688 : int const StartDate, // Start date in sequence
689 : int const EndDate // End date in sequence
690 : )
691 : {
692 :
693 : // FUNCTION INFORMATION:
694 : // AUTHOR Linda K. Lawrie
695 : // DATE WRITTEN June 2000
696 :
697 : // PURPOSE OF THIS FUNCTION:
698 : // This function returns true if the TestDate is between
699 : // (StartDate <= TestDate <= EndDate).
700 :
701 : // METHODOLOGY EMPLOYED:
702 : // The input dates are Julian Day format, year is irrelevant.
703 : // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
704 : // this routine accomodates.
705 :
706 : // REFERENCES:
707 : // Adapted from BLAST BTWEEN function.
708 :
709 16 : bool BetweenDates = false; // Default case
710 :
711 16 : if (StartDate <= EndDate) { // Start Date <= End Date
712 0 : if (TestDate >= StartDate && TestDate <= EndDate) BetweenDates = true;
713 : } else { // EndDate < StartDate
714 16 : if (TestDate <= EndDate || TestDate >= StartDate) BetweenDates = true;
715 : }
716 :
717 16 : return BetweenDates;
718 : }
719 :
720 2183338 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
721 : {
722 :
723 : // FUNCTION INFORMATION:
724 : // AUTHOR Linda K. Lawrie
725 : // DATE WRITTEN April 2003
726 :
727 : // PURPOSE OF THIS FUNCTION:
728 : // This function creates the current time interval of the system time step.
729 :
730 : // Using/Aliasing
731 2183338 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
732 2183338 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
733 :
734 2183338 : Real64 constexpr FracToMin(60.0);
735 :
736 : // ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
737 : // CR6902 ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
738 : // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
739 2183338 : Real64 ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
740 2183338 : Real64 ActualTimeE = ActualTimeS + TimeStepSys;
741 2183338 : int ActualTimeHrS = int(ActualTimeS);
742 : // ActualTimeHrE=INT(ActualTimeE)
743 2183338 : int ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
744 :
745 2183338 : if (ActualTimeMinS == 60) {
746 6514 : ++ActualTimeHrS;
747 6514 : ActualTimeMinS = 0;
748 : }
749 2183338 : const std::string TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
750 2183338 : Real64 minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
751 :
752 2183338 : std::string TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
753 :
754 2183338 : if (TimeStmpE[3] == ' ') {
755 380723 : TimeStmpE[3] = '0';
756 : }
757 6550014 : return TimeStmpS + " - " + TimeStmpE;
758 2183338 : }
759 :
760 : // returns the Julian date for the first, second, etc. day of week for a given month
761 3714 : int nthDayOfWeekOfMonth(const EnergyPlusData &state,
762 : int const dayOfWeek, // day of week (Sunday=1, Monday=2, ...)
763 : int const nthTime, // nth time the day of the week occurs (first monday, third tuesday, ..)
764 : int const monthNumber // January = 1
765 : )
766 : {
767 : // J. Glazer - August 2017
768 3714 : int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
769 3714 : int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
770 3714 : if (dayOfWeek >= dayOfWeekForFirstDay) {
771 1880 : return firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
772 : } else {
773 1834 : return firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
774 : }
775 : }
776 :
777 12574684 : Real64 SafeDivide(Real64 const a, Real64 const b)
778 : {
779 :
780 : // returns a / b while preventing division by zero
781 :
782 : // Locals
783 12574684 : Real64 constexpr SMALL(1.E-10);
784 :
785 12574684 : if (std::abs(b) >= SMALL) {
786 12573519 : return a / b;
787 : } else {
788 1165 : return a / sign(SMALL, b);
789 : }
790 : }
791 :
792 286200124 : void Iterate(Real64 &ResultX, // ResultX is the final Iteration result passed back to the calling routine
793 : Real64 const Tol, // Tolerance for Convergence
794 : Real64 const X0, // Current value of X
795 : Real64 const Y0, // Current value of the function Y(X)
796 : Real64 &X1, // First Previous values of X
797 : Real64 &Y1, // First Previous values of Y(X1)
798 : int const Iter, // Number of iterations
799 : int &Cnvg // Convergence flag Cnvg = 0: Not converged
800 : )
801 : {
802 :
803 : // SUBROUTINE INFORMATION:
804 : // AUTHOR Richard Liesen
805 : // DATE WRITTEN March 2004
806 :
807 : // PURPOSE OF THIS SUBROUTINE:
808 : // Iterately solves for the value of X which satisfies Y(X)=0.
809 : // The subroutine tests for convergence and provides a new guess for the value of the
810 : // independent variable X.
811 :
812 : // REFERENCES:
813 : // Linear Correction based on the RegulaFalsi routine in EnergyPlus
814 :
815 : // SUBROUTINE PARAMETER DEFINITIONS:
816 286200124 : Real64 constexpr small(1.e-9); // Small Number used to approximate zero
817 286200124 : Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
818 :
819 : // Check for convergence by comparing change in X
820 286200124 : if (Iter != 1) {
821 258508426 : if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
822 27691635 : ResultX = X0;
823 27691635 : Cnvg = 1;
824 27691635 : return;
825 : }
826 : }
827 :
828 : // Not converged.
829 258508489 : Cnvg = 0;
830 258508489 : if (Iter == 1) {
831 :
832 : // New guess is specified by Perturb
833 27691698 : if (std::abs(X0) > small) {
834 27689923 : ResultX = X0 * (1.0 + Perturb);
835 : } else {
836 1775 : ResultX = Perturb;
837 : }
838 :
839 : } else {
840 :
841 : // New guess calculated from LINEAR FIT of most recent two points
842 230816791 : Real64 DY = Y0 - Y1;
843 230816791 : if (std::abs(DY) < small) {
844 0 : DY = small;
845 : }
846 : // new estimation
847 :
848 230816791 : ResultX = (Y0 * X1 - Y1 * X0) / DY;
849 : }
850 :
851 258508489 : X1 = X0;
852 258508489 : Y1 = Y0;
853 : }
854 :
855 39873 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
856 : {
857 :
858 : // FUNCTION INFORMATION:
859 : // AUTHOR Linda K. Lawrie
860 : // DATE WRITTEN September 2001
861 :
862 : // PURPOSE OF THIS FUNCTION:
863 : // This function looks up a number(integer) in a similar list of
864 : // items and returns the index of the item in the list, if found.
865 :
866 : // Argument array dimensioning
867 39873 : ListOfItems.dim(_);
868 :
869 359954 : for (int Count = 1; Count <= NumItems; ++Count) {
870 327634 : if (WhichNumber == ListOfItems(Count)) {
871 7553 : return Count;
872 : }
873 : }
874 :
875 32320 : return 0;
876 : }
877 :
878 310953 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
879 : int &Month, // month in integer format (1-12)
880 : int &Day, // day in integer format (1-31)
881 : int &Hour, // hour in integer format (1-24)
882 : int &Minute // minute in integer format (0:59)
883 : )
884 : {
885 :
886 : // SUBROUTINE INFORMATION:
887 : // AUTHOR Linda Lawrie
888 : // DATE WRITTEN March 2000
889 :
890 : // PURPOSE OF THIS SUBROUTINE:
891 : // This subroutine decodes the "packed" integer representation of
892 : // the Month, Day, Hour, and Minute. Packed integers are used to
893 : // save memory allocation. Original idea for this routine is contained
894 : // in DECMDH, BLAST code, by Jean Baugh.
895 :
896 : // METHODOLOGY EMPLOYED:
897 : // Using maximum integer concept the original date can be decoded
898 : // from the packed single word. This relies on 4 byte integer representation
899 : // as a minimum (capable of representing up to 2,147,483,647).
900 :
901 : // SUBROUTINE PARAMETER DEFINITIONS:
902 : static constexpr int DecMon(100 * 100 * 100);
903 : static constexpr int DecDay(100 * 100);
904 : static constexpr int DecHr(100);
905 :
906 310953 : int TmpItem = Item;
907 310953 : Month = TmpItem / DecMon;
908 310953 : TmpItem = (TmpItem - Month * DecMon);
909 310953 : Day = TmpItem / DecDay;
910 310953 : TmpItem -= Day * DecDay;
911 310953 : Hour = TmpItem / DecHr;
912 310953 : Minute = mod(TmpItem, DecHr);
913 310953 : }
914 :
915 1108785 : void EncodeMonDayHrMin(int &Item, // word containing encoded month, day, hour, minute
916 : int const Month, // month in integer format (1:12)
917 : int const Day, // day in integer format (1:31)
918 : int const Hour, // hour in integer format (1:24)
919 : int const Minute // minute in integer format (0:59)
920 : )
921 : {
922 :
923 : // SUBROUTINE INFORMATION:
924 : // AUTHOR Linda Lawrie
925 : // DATE WRITTEN March 2000
926 :
927 : // PURPOSE OF THIS SUBROUTINE:
928 : // This subroutine encodes the "packed" integer representation of
929 : // the Month, Day, Hour, and Minute. Packed integers are used to
930 : // save memory allocation. Original idea for this routine is contained
931 : // in DECMDH, BLAST code, by Jean Baugh.
932 :
933 : // METHODOLOGY EMPLOYED:
934 : // Using maximum integer concept the original date can be decoded
935 : // from the packed single word. This relies on 4 byte integer representation
936 : // as a minimum (capable of representing up to 2,147,483,647).
937 :
938 1108785 : Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
939 1108785 : }
940 :
941 0 : std::string CreateTimeString(Real64 const Time) // Time in seconds
942 : {
943 :
944 : // FUNCTION INFORMATION:
945 : // AUTHOR Dimitri Curtil
946 : // DATE WRITTEN January 2005
947 :
948 : // PURPOSE OF THIS FUNCTION:
949 : // This function creates the time stamp string from the time value specified in seconds.
950 : // Inspired by similar function CreateSysTimeIntervalString() in General.cc
951 : // However, this function provides better accuracy for sub-minute time steps
952 : // by also showing information down to the 10th of a second.
953 : // Note that Time is expected to be specified in REAL(r64).
954 :
955 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
956 : int Hours; // Number of hours <= 24
957 : int Minutes; // Remaining minutes < 60
958 : Real64 Seconds; // Remaining seconds < 60
959 :
960 0 : ParseTime(Time, Hours, Minutes, Seconds);
961 :
962 : // TimeStamp written with formatting
963 : // "hh:mm:ss.s"
964 0 : return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
965 : }
966 :
967 14140 : void ParseTime(Real64 const Time, // Time value in seconds
968 : int &Hours, // Number of hours
969 : int &Minutes, // Number of minutes < 60
970 : Real64 &Seconds // Number of seconds < 60
971 : )
972 : {
973 : // FUNCTION INFORMATION:
974 : // AUTHOR Dimitri Curtil
975 : // DATE WRITTEN January 2005
976 :
977 : // PURPOSE OF THIS FUNCTION:
978 : // This subroutine decomposes a time value specified in seconds
979 : // into a triplet { hours : minutes : seconds } such that
980 : // - minutes < 60
981 : // - seconds < 60
982 :
983 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
984 14140 : int constexpr MinToSec = 60;
985 14140 : int constexpr HourToSec = 60 * 60;
986 :
987 : // Get number of hours
988 : // This might undershoot the actual number of hours. See DO WHILE loop.
989 14140 : Hours = int(Time) / HourToSec;
990 :
991 : // Compute remainder in seconds
992 14140 : Real64 Remainder = (Time - Hours * HourToSec);
993 :
994 : // Compute minutes
995 14140 : Minutes = int(Remainder) / MinToSec;
996 :
997 : // Compute remainder in seconds
998 14140 : Remainder -= Minutes * MinToSec;
999 :
1000 : // Compute seconds
1001 14140 : Seconds = Remainder;
1002 14140 : }
1003 :
1004 12736 : void ScanForReports(EnergyPlusData &state,
1005 : std::string const &reportName,
1006 : bool &DoReport,
1007 : ObjexxFCL::Optional_string_const ReportKey,
1008 : ObjexxFCL::Optional_string Option1,
1009 : ObjexxFCL::Optional_string Option2)
1010 : {
1011 :
1012 : // SUBROUTINE INFORMATION:
1013 : // AUTHOR Linda Lawrie
1014 : // DATE WRITTEN March 2009
1015 :
1016 : // PURPOSE OF THIS SUBROUTINE:
1017 : // This routine scans for the global "reports" settings, such as Variable Dictionary,
1018 : // Surfaces (and options), Constructions, etc.
1019 :
1020 : // METHODOLOGY EMPLOYED:
1021 : // First time routine is called, all the viable combinations/settings for the reports are
1022 : // stored in SAVEd variables. Later callings will retrieve those.
1023 :
1024 12736 : if (state.dataGeneral->GetReportInput) {
1025 :
1026 : int NumNames;
1027 : int NumNumbers;
1028 : int IOStat;
1029 : int RepNum;
1030 :
1031 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
1032 796 : cCurrentModuleObject = "Output:Surfaces:List";
1033 :
1034 796 : int NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1035 :
1036 : enum
1037 : {
1038 : EMPTY,
1039 : LINES,
1040 : VERTICES,
1041 : DETAILS,
1042 : DETAILSWITHVERTICES,
1043 : COSTINFO,
1044 : VIEWFACTORINFO,
1045 : DECAYCURVESFROMCOMPONENTLOADSSUMMARY
1046 : };
1047 0 : std::map<std::string, int> localMap = {{"", EMPTY},
1048 0 : {"LINES", LINES},
1049 0 : {"VERTICES", VERTICES},
1050 0 : {"DETAILS", DETAILS},
1051 0 : {"DETAILED", DETAILS},
1052 0 : {"DETAIL", DETAILS},
1053 0 : {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
1054 0 : {"DETAILVERTICES", DETAILSWITHVERTICES},
1055 0 : {"COSTINFO", COSTINFO},
1056 0 : {"VIEWFACTORINFO", VIEWFACTORINFO},
1057 10348 : {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
1058 :
1059 1057 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1060 522 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1061 : cCurrentModuleObject,
1062 : RepNum,
1063 261 : state.dataIPShortCut->cAlphaArgs,
1064 : NumNames,
1065 261 : state.dataIPShortCut->rNumericArgs,
1066 : NumNumbers,
1067 : IOStat,
1068 261 : state.dataIPShortCut->lNumericFieldBlanks,
1069 261 : state.dataIPShortCut->lAlphaFieldBlanks,
1070 261 : state.dataIPShortCut->cAlphaFieldNames,
1071 261 : state.dataIPShortCut->cNumericFieldNames);
1072 :
1073 : try {
1074 261 : int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
1075 261 : switch (value) {
1076 51 : case LINES:
1077 51 : state.dataGeneral->LineRpt = true;
1078 51 : state.dataGeneral->LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1079 51 : break;
1080 5 : case VERTICES:
1081 5 : state.dataGeneral->SurfVert = true;
1082 5 : break;
1083 148 : case DETAILS:
1084 148 : state.dataGeneral->SurfDet = true;
1085 148 : break;
1086 31 : case DETAILSWITHVERTICES:
1087 31 : state.dataGeneral->SurfDetWVert = true;
1088 31 : break;
1089 7 : case COSTINFO:
1090 : // Custom case for reporting surface info for cost estimates (for first costs in opitimzing)
1091 7 : state.dataGeneral->CostInfo = true;
1092 7 : break;
1093 10 : case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
1094 10 : state.dataGeneral->ViewFactorInfo = true;
1095 10 : state.dataGeneral->ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1096 10 : break;
1097 9 : case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
1098 : // load component report appear in the EIO file
1099 9 : state.dataGlobal->ShowDecayCurvesInEIO = true;
1100 9 : break;
1101 0 : default: // including empty
1102 0 : ShowWarningError(state, format("{}: No {} supplied.", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1)));
1103 0 : ShowContinueError(state,
1104 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1105 : }
1106 0 : } catch (int e) {
1107 0 : ShowWarningError(state,
1108 0 : format("{}: Invalid {}=\"{}\" supplied.",
1109 : cCurrentModuleObject,
1110 0 : state.dataIPShortCut->cAlphaFieldNames(1),
1111 0 : state.dataIPShortCut->cAlphaArgs(1)));
1112 0 : ShowContinueError(state,
1113 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1114 0 : }
1115 : }
1116 :
1117 796 : cCurrentModuleObject = "Output:Surfaces:Drawing";
1118 :
1119 796 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1120 1341 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1121 1090 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1122 : cCurrentModuleObject,
1123 : RepNum,
1124 545 : state.dataIPShortCut->cAlphaArgs,
1125 : NumNames,
1126 545 : state.dataIPShortCut->rNumericArgs,
1127 : NumNumbers,
1128 : IOStat,
1129 545 : state.dataIPShortCut->lNumericFieldBlanks,
1130 545 : state.dataIPShortCut->lAlphaFieldBlanks,
1131 545 : state.dataIPShortCut->cAlphaFieldNames,
1132 545 : state.dataIPShortCut->cNumericFieldNames);
1133 :
1134 : ReportType checkReportType =
1135 545 : static_cast<ReportType>(getEnumValue(ReportTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
1136 :
1137 545 : switch (checkReportType) {
1138 480 : case ReportType::DXF: {
1139 480 : state.dataGeneral->DXFReport = true;
1140 480 : state.dataGeneral->DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1141 480 : state.dataGeneral->DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1142 480 : } break;
1143 29 : case ReportType::DXFWireFrame: {
1144 29 : state.dataGeneral->DXFWFReport = true;
1145 29 : state.dataGeneral->DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1146 29 : state.dataGeneral->DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1147 29 : } break;
1148 36 : case ReportType::VRML: {
1149 36 : state.dataGeneral->VRMLReport = true;
1150 36 : state.dataGeneral->VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
1151 36 : state.dataGeneral->VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
1152 36 : } break;
1153 0 : default:
1154 0 : break;
1155 : }
1156 : }
1157 :
1158 796 : RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
1159 796 : if (RepNum > 0) {
1160 0 : state.dataGeneral->VarDict = true;
1161 0 : state.dataGeneral->VarDictOption1 = "REGULAR";
1162 0 : state.dataGeneral->VarDictOption2 = "";
1163 : }
1164 :
1165 796 : cCurrentModuleObject = "Output:VariableDictionary";
1166 :
1167 796 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1168 1587 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1169 1582 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1170 : cCurrentModuleObject,
1171 : RepNum,
1172 791 : state.dataIPShortCut->cAlphaArgs,
1173 : NumNames,
1174 791 : state.dataIPShortCut->rNumericArgs,
1175 : NumNumbers,
1176 : IOStat,
1177 791 : state.dataIPShortCut->lNumericFieldBlanks,
1178 791 : state.dataIPShortCut->lAlphaFieldBlanks,
1179 791 : state.dataIPShortCut->cAlphaFieldNames,
1180 791 : state.dataIPShortCut->cNumericFieldNames);
1181 791 : state.dataGeneral->VarDict = true;
1182 791 : state.dataGeneral->VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
1183 791 : state.dataGeneral->VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
1184 : }
1185 :
1186 796 : cCurrentModuleObject = "Output:Constructions";
1187 796 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1188 1114 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1189 636 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1190 : cCurrentModuleObject,
1191 : RepNum,
1192 318 : state.dataIPShortCut->cAlphaArgs,
1193 : NumNames,
1194 318 : state.dataIPShortCut->rNumericArgs,
1195 : NumNumbers,
1196 : IOStat,
1197 318 : state.dataIPShortCut->lNumericFieldBlanks,
1198 318 : state.dataIPShortCut->lAlphaFieldBlanks,
1199 318 : state.dataIPShortCut->cAlphaFieldNames,
1200 318 : state.dataIPShortCut->cNumericFieldNames);
1201 318 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
1202 307 : state.dataGeneral->Constructions = true;
1203 11 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
1204 11 : state.dataGeneral->Materials = true;
1205 : }
1206 318 : if (NumNames > 1) {
1207 3 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
1208 0 : state.dataGeneral->Constructions = true;
1209 3 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
1210 3 : state.dataGeneral->Materials = true;
1211 : }
1212 : }
1213 : }
1214 :
1215 796 : cCurrentModuleObject = "Output:EnergyManagementSystem";
1216 796 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1217 837 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1218 82 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1219 : cCurrentModuleObject,
1220 : RepNum,
1221 41 : state.dataIPShortCut->cAlphaArgs,
1222 : NumNames,
1223 41 : state.dataIPShortCut->rNumericArgs,
1224 : NumNumbers,
1225 : IOStat,
1226 41 : state.dataIPShortCut->lNumericFieldBlanks,
1227 41 : state.dataIPShortCut->lAlphaFieldBlanks,
1228 41 : state.dataIPShortCut->cAlphaFieldNames,
1229 41 : state.dataIPShortCut->cNumericFieldNames);
1230 :
1231 41 : state.dataGeneral->EMSoutput = true;
1232 :
1233 41 : AvailRpt CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
1234 41 : state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1235 41 : state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
1236 :
1237 41 : CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
1238 41 : state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1239 41 : state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
1240 :
1241 : ERLdebugOutputLevel CheckERLlevel =
1242 41 : static_cast<ERLdebugOutputLevel>(getEnumValue(ERLdebugOutputLevelNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
1243 41 : state.dataRuntimeLang->OutputEMSErrors =
1244 41 : (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
1245 41 : state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
1246 : }
1247 :
1248 796 : state.dataGeneral->GetReportInput = false;
1249 796 : }
1250 :
1251 : // Process the Scan Request
1252 12736 : DoReport = false;
1253 :
1254 12736 : ReportName rptName = static_cast<ReportName>(getEnumValue(ReportNamesUC, Util::makeUPPER(Util::makeUPPER(reportName))));
1255 12736 : switch (rptName) {
1256 2389 : case ReportName::Constructions: {
1257 2389 : if (present(ReportKey)) {
1258 2389 : if (Util::SameString(ReportKey(), "Constructions")) DoReport = state.dataGeneral->Constructions;
1259 2389 : if (Util::SameString(ReportKey(), "Materials")) DoReport = state.dataGeneral->Materials;
1260 : }
1261 2389 : } break;
1262 1592 : case ReportName::Viewfactorinfo: {
1263 1592 : DoReport = state.dataGeneral->ViewFactorInfo;
1264 1592 : if (present(Option1)) Option1 = state.dataGeneral->ViewRptOption1;
1265 1592 : } break;
1266 795 : case ReportName::Variabledictionary: {
1267 795 : DoReport = state.dataGeneral->VarDict;
1268 795 : if (present(Option1)) Option1 = state.dataGeneral->VarDictOption1;
1269 795 : if (present(Option2)) Option2 = state.dataGeneral->VarDictOption2;
1270 : // CASE ('SCHEDULES')
1271 : // DoReport=SchRpt
1272 : // IF (PRESENT(Option1)) Option1=SchRptOption
1273 795 : } break;
1274 7164 : case ReportName::Surfaces: {
1275 7164 : RptKey rptKey = static_cast<RptKey>(getEnumValue(RptKeyNamesUC, Util::makeUPPER(ReportKey())));
1276 : switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
1277 796 : case RptKey::Costinfo: {
1278 796 : DoReport = state.dataGeneral->CostInfo;
1279 796 : } break;
1280 796 : case RptKey::DXF: {
1281 796 : DoReport = state.dataGeneral->DXFReport;
1282 796 : if (present(Option1)) Option1 = state.dataGeneral->DXFOption1;
1283 796 : if (present(Option2)) Option2 = state.dataGeneral->DXFOption2;
1284 796 : } break;
1285 796 : case RptKey::DXFwireframe: {
1286 796 : DoReport = state.dataGeneral->DXFWFReport;
1287 796 : if (present(Option1)) Option1 = state.dataGeneral->DXFWFOption1;
1288 796 : if (present(Option2)) Option2 = state.dataGeneral->DXFWFOption2;
1289 796 : } break;
1290 796 : case RptKey::VRML: {
1291 796 : DoReport = state.dataGeneral->VRMLReport;
1292 796 : if (present(Option1)) Option1 = state.dataGeneral->VRMLOption1;
1293 796 : if (present(Option2)) Option2 = state.dataGeneral->VRMLOption2;
1294 796 : } break;
1295 796 : case RptKey::Vertices: {
1296 796 : DoReport = state.dataGeneral->SurfVert;
1297 796 : } break;
1298 1592 : case RptKey::Details: {
1299 1592 : DoReport = state.dataGeneral->SurfDet;
1300 1592 : } break;
1301 796 : case RptKey::DetailsWithVertices: {
1302 796 : DoReport = state.dataGeneral->SurfDetWVert;
1303 796 : } break;
1304 796 : case RptKey::Lines: {
1305 796 : DoReport = state.dataGeneral->LineRpt;
1306 796 : if (present(Option1)) Option1 = state.dataGeneral->LineRptOption1;
1307 796 : } break;
1308 0 : default:
1309 0 : break;
1310 : }
1311 7164 : } break;
1312 796 : case ReportName::Energymanagementsystem: {
1313 796 : DoReport = state.dataGeneral->EMSoutput;
1314 796 : } break;
1315 0 : default:
1316 0 : break;
1317 : }
1318 12736 : }
1319 :
1320 54 : void CheckCreatedZoneItemName(EnergyPlusData &state,
1321 : std::string_view const calledFrom, // routine called from
1322 : std::string const &CurrentObject, // object being parsed
1323 : std::string const &ZoneName, // Zone Name associated
1324 : std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
1325 : std::string const &ItemName, // Item name (People, Lights, etc object)
1326 : Array1_string const &ItemNames, // Item Names to check for duplication
1327 : int const NumItems, // Number of items in ItemNames array
1328 : std::string &ResultName, // Resultant name
1329 : bool &errFlag // Error flag set to true if error found here.
1330 : )
1331 : {
1332 :
1333 : // SUBROUTINE INFORMATION:
1334 : // AUTHOR Linda Lawrie
1335 : // DATE WRITTEN December 2012
1336 :
1337 : // PURPOSE OF THIS SUBROUTINE:
1338 : // This routine checks "global" objects (that is, ones with ZoneList used in the name
1339 : // specification) along with a specific name for the current object for length and duplication
1340 : // with previous objects of that class.
1341 :
1342 54 : errFlag = false;
1343 54 : std::string::size_type const ItemNameLength = len(ItemName);
1344 54 : std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
1345 54 : ResultName = ZoneName + ' ' + ItemName;
1346 54 : bool TooLong = false;
1347 54 : if (ItemLength > Constant::MaxNameLength) {
1348 0 : ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
1349 0 : ShowContinueError(state, format("Object Name=\"{}\".", ItemName));
1350 0 : ShowContinueError(state, format("ZoneList/Zone Name=\"{}\".", ZoneName));
1351 0 : ShowContinueError(state,
1352 0 : format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, Constant::MaxNameLength));
1353 0 : ShowContinueError(state,
1354 0 : format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
1355 0 : MaxZoneNameLength + 1 + ItemNameLength - Constant::MaxNameLength));
1356 0 : ShowContinueError(state, format("name that will be used (may be needed in reporting)=\"{}\".", ResultName));
1357 0 : TooLong = true;
1358 : }
1359 :
1360 54 : int FoundItem = Util::FindItemInList(ResultName, ItemNames, NumItems);
1361 :
1362 54 : if (FoundItem != 0) {
1363 0 : ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
1364 0 : ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
1365 0 : if (TooLong) ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
1366 0 : ResultName = "xxxxxxx";
1367 0 : errFlag = true;
1368 : }
1369 54 : }
1370 :
1371 0 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
1372 : {
1373 : int currentDate;
1374 0 : int reportStartDate = state.dataWeather->ReportPeriodInput(periodIdx).startJulianDate;
1375 0 : int reportStartHour = state.dataWeather->ReportPeriodInput(periodIdx).startHour;
1376 0 : if (state.dataWeather->ReportPeriodInput(periodIdx).startYear > 0) {
1377 0 : currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1378 : } else {
1379 0 : currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1380 : }
1381 0 : return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
1382 : }
1383 :
1384 5376 : void findReportPeriodIdx(EnergyPlusData &state,
1385 : const Array1D<Weather::ReportPeriodData> &ReportPeriodInputData,
1386 : const int nReportPeriods,
1387 : Array1D_bool &inReportPeriodFlags)
1388 : {
1389 : // return an array of flags, indicating whether the current time is in reporting period i
1390 : int currentDate;
1391 12288 : for (int i = 1; i <= nReportPeriods; i++) {
1392 6912 : int reportStartDate = ReportPeriodInputData(i).startJulianDate;
1393 6912 : int reportStartHour = ReportPeriodInputData(i).startHour;
1394 6912 : int reportEndDate = ReportPeriodInputData(i).endJulianDate;
1395 6912 : int reportEndHour = ReportPeriodInputData(i).endHour;
1396 6912 : if (ReportPeriodInputData(i).startYear > 0) {
1397 0 : currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1398 : } else {
1399 6912 : currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1400 : }
1401 6912 : if (General::BetweenDateHoursLeftInclusive(
1402 6912 : currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
1403 0 : inReportPeriodFlags(i) = true;
1404 : }
1405 : }
1406 5376 : }
1407 :
1408 183 : Real64 rotAzmDiffDeg(Real64 AzmA, Real64 AzmB)
1409 : {
1410 : // This function takes two (azimuth) angles in Degree(s),
1411 : // and returns the rotational angle difference in Degree(s).
1412 :
1413 183 : Real64 diff = AzmB - AzmA;
1414 183 : if (diff > 180.0) {
1415 6 : diff = 360.0 - diff;
1416 177 : } else if (diff < -180.0) {
1417 8 : diff = 360.0 + diff;
1418 : }
1419 183 : return std::abs(diff);
1420 : }
1421 :
1422 : } // namespace EnergyPlus::General
|