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 <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 18226338 : 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 18226338 : Real64 constexpr SMALL(1.e-10);
186 18226338 : Real64 X0 = X_0; // present 1st bound
187 18226338 : Real64 X1 = X_1; // present 2nd bound
188 18226338 : Real64 XTemp = X0; // new estimate
189 18226338 : int NIte = 0; // number of iterations
190 18226338 : int AltIte = 0; // an accounter used for Alternation choice
191 :
192 18226338 : Real64 Y0 = f(X0); // f at X0
193 18226338 : Real64 Y1 = f(X1); // f at X1
194 : // check initial values
195 18226338 : if (Y0 * Y1 > 0) {
196 1116597 : Flag = -2;
197 1116597 : XRes = X0;
198 1116597 : return;
199 : }
200 17109741 : XRes = XTemp;
201 :
202 : while (true) {
203 :
204 34983156 : Real64 DY = Y0 - Y1;
205 34983156 : if (std::abs(DY) < SMALL) {
206 0 : DY = SMALL;
207 : }
208 34983156 : if (std::abs(X1 - X0) < SMALL) {
209 5802 : break;
210 : }
211 : // new estimation
212 34977354 : switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolverMethod) {
213 34971848 : case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
214 34971848 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
215 34971848 : break;
216 : }
217 0 : case HVACSystemRootSolverAlgorithm::Bisection: {
218 0 : XTemp = (X1 + X0) / 2.0;
219 0 : break;
220 : }
221 5506 : case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
222 5506 : if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
223 71 : XTemp = (X1 + X0) / 2.0;
224 : } else {
225 5435 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
226 : }
227 5506 : break;
228 : }
229 0 : case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
230 0 : if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
231 0 : XTemp = (X1 + X0) / 2.0;
232 : } else {
233 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
234 : }
235 0 : break;
236 : }
237 0 : case HVACSystemRootSolverAlgorithm::Alternation: {
238 0 : if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
239 0 : XTemp = (X1 + X0) / 2.0;
240 0 : if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
241 0 : AltIte = 0;
242 : }
243 : } else {
244 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
245 : }
246 0 : break;
247 : }
248 0 : case HVACSystemRootSolverAlgorithm::ShortBisectionThenRegulaFalsi: {
249 0 : if (NIte < 3) {
250 0 : XTemp = (X1 + X0) / 2.0;
251 : } else {
252 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
253 : }
254 0 : break;
255 : }
256 0 : default: {
257 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
258 : }
259 : }
260 :
261 34977354 : Real64 const YTemp = f(XTemp);
262 :
263 34977354 : ++NIte;
264 34977354 : ++AltIte;
265 :
266 : // check convergence
267 34977354 : if (std::abs(YTemp) < Eps) {
268 17103742 : Flag = NIte;
269 17103742 : XRes = XTemp;
270 17103742 : return;
271 : };
272 :
273 : // OK, so we didn't converge, lets check max iterations to see if we should break early
274 17873612 : if (NIte > MaxIte) {
275 197 : break;
276 : }
277 :
278 : // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
279 : // and reassign values (only if further iteration required)
280 17873415 : if (Y0 < 0.0) {
281 15728400 : if (YTemp < 0.0) {
282 7388830 : X0 = XTemp;
283 7388830 : Y0 = YTemp;
284 : } else {
285 8339570 : X1 = XTemp;
286 8339570 : Y1 = YTemp;
287 : }
288 : } else {
289 2145015 : if (YTemp < 0.0) {
290 1249186 : X1 = XTemp;
291 1249186 : Y1 = YTemp;
292 : } else {
293 895829 : X0 = XTemp;
294 895829 : Y0 = YTemp;
295 : }
296 : } // ( Y0 < 0 )
297 17873415 : } // Cont
298 :
299 : // if we make it here we haven't converged, so just set the flag and leave
300 5999 : Flag = -1;
301 5999 : XRes = XTemp;
302 : }
303 :
304 214804 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
305 : {
306 214804 : if (NumItemsInAvg <= 1) {
307 2208 : return; // no need to average/smooth
308 : }
309 :
310 212596 : Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
311 :
312 25756852 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
313 25544256 : TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
314 25544256 : DataIn(i) = 0.0;
315 : }
316 :
317 25756852 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
318 238904256 : for (int j = 1; j <= NumItemsInAvg; ++j) {
319 213360000 : DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
320 : }
321 25544256 : DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
322 : }
323 212596 : }
324 :
325 37235 : void ProcessDateString(EnergyPlusData &state,
326 : std::string const &String,
327 : int &PMonth,
328 : int &PDay,
329 : int &PWeekDay,
330 : Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
331 : bool &ErrorsFound,
332 : ObjexxFCL::Optional_int PYear)
333 : {
334 :
335 : // SUBROUTINE INFORMATION:
336 : // AUTHOR Linda Lawrie
337 : // DATE WRITTEN December 1999
338 :
339 : // PURPOSE OF THIS SUBROUTINE:
340 : // This subroutine will process a date from a string and determine
341 : // the proper month and day for that date string.
342 :
343 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
344 : bool errFlag;
345 :
346 37235 : int FstNum = int(Util::ProcessNumber(String, errFlag));
347 37235 : DateType = Weather::DateType::Invalid;
348 37235 : if (!errFlag) {
349 : // Entered single number, do inverse JDay
350 1584 : if (FstNum == 0) {
351 1584 : PMonth = 0;
352 1584 : PDay = 0;
353 1584 : DateType = Weather::DateType::MonthDay;
354 0 : } else if (FstNum < 0 || FstNum > 366) {
355 0 : ShowSevereError(state, format("Invalid Julian date Entered={}", String));
356 0 : ErrorsFound = true;
357 : } else {
358 0 : InvOrdinalDay(FstNum, PMonth, PDay, 0);
359 0 : DateType = Weather::DateType::LastDayInMonth;
360 : }
361 : } else {
362 35651 : int NumTokens = 0;
363 35651 : int TokenDay = 0;
364 35651 : int TokenMonth = 0;
365 35651 : int TokenWeekday = 0;
366 : // Error when processing as number, try x/x
367 35651 : if (!present(PYear)) {
368 34065 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
369 : } else {
370 1586 : int TokenYear = 0;
371 1586 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
372 1586 : PYear = TokenYear;
373 : }
374 35651 : if (DateType == Weather::DateType::MonthDay) {
375 34507 : PDay = TokenDay;
376 34507 : PMonth = TokenMonth;
377 1144 : } else if (DateType == Weather::DateType::NthDayInMonth || DateType == Weather::DateType::LastDayInMonth) {
378 : // interpret as TokenDay TokenWeekday in TokenMonth
379 1144 : PDay = TokenDay;
380 1144 : PMonth = TokenMonth;
381 1144 : PWeekDay = TokenWeekday;
382 : }
383 : }
384 37235 : }
385 :
386 35651 : void DetermineDateTokens(EnergyPlusData &state,
387 : std::string const &String,
388 : int &NumTokens, // Number of tokens found in string
389 : int &TokenDay, // Value of numeric field found
390 : int &TokenMonth, // Value of Month field found (1=Jan, 2=Feb, etc)
391 : int &TokenWeekday, // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
392 : Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
393 : bool &ErrorsFound, // Set to true if cannot process this string as a date
394 : ObjexxFCL::Optional_int TokenYear // Value of Year if one appears to be present and this argument is present
395 : )
396 : {
397 :
398 : // SUBROUTINE INFORMATION:
399 : // AUTHOR Linda Lawrie
400 : // DATE WRITTEN August 2000
401 :
402 : // PURPOSE OF THIS SUBROUTINE:
403 : // This subroutine is invoked for date fields that appear to be strings (give
404 : // error when ProcessNumber is used).
405 :
406 : // METHODOLOGY EMPLOYED:
407 : // Delete everything that is extraneous to the date information needed. Process what
408 : // is left.
409 :
410 : // SUBROUTINE PARAMETER DEFINITIONS:
411 : static constexpr int NumSingleChars(3);
412 : static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
413 : static constexpr int NumDoubleChars(6);
414 : static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
415 : "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want these only at end of words
416 : static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
417 : static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
418 :
419 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
420 35651 : std::string CurrentString = String;
421 35651 : Array1D_string Fields(3);
422 35651 : bool InternalError = false;
423 35651 : bool WkDayInMonth = false;
424 :
425 35651 : NumTokens = 0;
426 35651 : TokenDay = 0;
427 35651 : TokenMonth = 0;
428 35651 : TokenWeekday = 0;
429 35651 : DateType = Weather::DateType::Invalid;
430 35651 : if (present(TokenYear)) {
431 1586 : TokenYear = 0;
432 : }
433 : // Take out separator characters, other extraneous stuff
434 :
435 142604 : for (int Loop = 0; Loop < NumSingleChars; ++Loop) {
436 106953 : size_t Pos = index(CurrentString, SingleChars[Loop]);
437 140930 : while (Pos != std::string::npos) {
438 33977 : CurrentString[Pos] = ' ';
439 33977 : Pos = index(CurrentString, SingleChars[Loop]);
440 : }
441 : }
442 :
443 249557 : for (int Loop = 0; Loop < NumDoubleChars; ++Loop) {
444 213906 : size_t Pos = index(CurrentString, DoubleChars[Loop]);
445 216194 : while (Pos != std::string::npos) {
446 2288 : CurrentString.replace(Pos, 2, " ");
447 2288 : Pos = index(CurrentString, DoubleChars[Loop]);
448 2288 : WkDayInMonth = true;
449 : }
450 : }
451 :
452 35651 : strip(CurrentString);
453 35651 : if (CurrentString == BlankString) {
454 0 : ShowSevereError(state, format("Invalid date field={}", String));
455 0 : ErrorsFound = true;
456 : } else {
457 35651 : int Loop = 0;
458 35651 : bool errFlag = false;
459 : int NumField1;
460 : int NumField2;
461 : int NumField3;
462 108097 : while (Loop < 3) { // Max of 3 fields
463 106953 : if (CurrentString == BlankString) {
464 34507 : break;
465 : }
466 72446 : size_t Pos = index(CurrentString, ' ');
467 72446 : ++Loop;
468 72446 : if (Pos == std::string::npos) {
469 35651 : Pos = CurrentString.length();
470 : }
471 72446 : Fields(Loop) = CurrentString.substr(0, Pos);
472 72446 : CurrentString.erase(0, Pos);
473 72446 : strip(CurrentString);
474 : }
475 35651 : if (not_blank(CurrentString)) {
476 0 : ShowSevereError(state, format("Invalid date field={}", String));
477 0 : ErrorsFound = true;
478 35651 : } else if (Loop == 2) {
479 : // Field must be Day Month or Month Day (if both numeric, mon / day)
480 34507 : InternalError = false;
481 34507 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
482 34507 : if (errFlag) {
483 : // Month day, but first field is not numeric, 2nd must be
484 511 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
485 511 : if (errFlag) {
486 0 : ShowSevereError(state, format("Invalid date field={}", String));
487 0 : InternalError = true;
488 : } else {
489 511 : TokenDay = NumField2;
490 : }
491 511 : TokenMonth = Util::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
492 511 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
493 511 : if (!InternalError) {
494 511 : DateType = Weather::DateType::MonthDay;
495 : } else {
496 0 : ErrorsFound = true;
497 : }
498 : } else {
499 : // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
500 33996 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
501 33996 : if (!errFlag) {
502 33971 : TokenMonth = NumField1;
503 33971 : TokenDay = NumField2;
504 33971 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
505 33971 : if (!InternalError) {
506 33971 : DateType = Weather::DateType::MonthDay;
507 : } else {
508 0 : ErrorsFound = true;
509 : }
510 : } else { // 2nd field was not numeric. Must be Month
511 25 : TokenDay = NumField1;
512 25 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
513 25 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
514 25 : if (!InternalError) {
515 25 : DateType = Weather::DateType::MonthDay;
516 25 : NumTokens = 2;
517 : } else {
518 0 : ErrorsFound = true;
519 : }
520 : }
521 : }
522 1144 : } else if (Loop == 3) {
523 : // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
524 1144 : if (WkDayInMonth) {
525 1144 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
526 1144 : if (!errFlag) { // the expected result
527 944 : TokenDay = NumField1;
528 944 : TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
529 944 : if (TokenWeekday == 0) {
530 0 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
531 0 : TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
532 0 : if (TokenMonth == 0 || TokenWeekday == 0) {
533 0 : InternalError = true;
534 : }
535 : } else {
536 944 : TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
537 944 : if (TokenMonth == 0) {
538 0 : InternalError = true;
539 : }
540 : }
541 944 : DateType = Weather::DateType::NthDayInMonth;
542 944 : NumTokens = 3;
543 944 : if (TokenDay < 0 || TokenDay > 5) {
544 0 : InternalError = true;
545 : }
546 : } else { // first field was not numeric....
547 200 : if (Fields(1) == "LA") {
548 200 : DateType = Weather::DateType::LastDayInMonth;
549 200 : NumTokens = 3;
550 200 : TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
551 200 : if (TokenWeekday == 0) {
552 0 : TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
553 0 : TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
554 0 : if (TokenMonth == 0 || TokenWeekday == 0) {
555 0 : InternalError = true;
556 : }
557 : } else {
558 200 : TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
559 200 : if (TokenMonth == 0) {
560 0 : InternalError = true;
561 : }
562 : }
563 : } else { // error....
564 0 : ShowSevereError(state, format("First date field not numeric, field={}", String));
565 : }
566 : }
567 : } else { // mm/dd/yyyy or yyyy/mm/dd
568 0 : NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
569 0 : NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
570 0 : NumField3 = int(Util::ProcessNumber(Fields(3), errFlag));
571 0 : DateType = Weather::DateType::MonthDay;
572 : // error detection later..
573 0 : if (NumField1 > 100) {
574 0 : if (present(TokenYear)) {
575 0 : TokenYear = NumField1;
576 : }
577 0 : TokenMonth = NumField2;
578 0 : TokenDay = NumField3;
579 0 : } else if (NumField3 > 100) {
580 0 : if (present(TokenYear)) {
581 0 : TokenYear = NumField3;
582 : }
583 0 : TokenMonth = NumField1;
584 0 : TokenDay = NumField2;
585 : }
586 : }
587 : } else {
588 : // Not enough or too many fields
589 0 : ShowSevereError(state, format("Invalid date field={}", String));
590 0 : ErrorsFound = true;
591 : }
592 : }
593 :
594 35651 : if (InternalError) {
595 0 : DateType = Weather::DateType::Invalid;
596 0 : ErrorsFound = true;
597 : }
598 35651 : }
599 :
600 34507 : void ValidateMonthDay(EnergyPlusData &state,
601 : std::string const &String, // REAL(r64) string being processed
602 : int const Day,
603 : int const Month,
604 : bool &ErrorsFound)
605 : {
606 :
607 : // SUBROUTINE INFORMATION:
608 : // AUTHOR Linda Lawrie
609 : // DATE WRITTEN August 2000
610 :
611 : // PURPOSE OF THIS SUBROUTINE:
612 : // This subroutine validates a potential Day, Month values, produces an error
613 : // message when not valid, and sets error flag.
614 :
615 : // SUBROUTINE PARAMETER DEFINITIONS:
616 : static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
617 :
618 34507 : bool InternalError = false;
619 34507 : if (Month < 1 || Month > 12) {
620 0 : InternalError = true;
621 : }
622 34507 : if (!InternalError) {
623 34507 : if (Day < 1 || Day > EndMonthDay[Month - 1]) {
624 0 : InternalError = true;
625 : }
626 : }
627 34507 : if (InternalError) {
628 0 : ShowSevereError(state, format("Invalid Month Day date format={}", String));
629 0 : ErrorsFound = true;
630 : } else {
631 34507 : ErrorsFound = false;
632 : }
633 34507 : }
634 :
635 193976 : int OrdinalDay(int const Month, // Month, 1..12
636 : int const Day, // Day of Month, not validated by month
637 : int const LeapYearValue // 1 if leap year indicated, 0 if not
638 : )
639 : {
640 :
641 : // FUNCTION INFORMATION:
642 : // AUTHOR Linda K. Lawrie
643 : // DATE WRITTEN September 1997
644 : // RE-ENGINEERED from JDAYF in BLAST/IBLAST
645 :
646 : // PURPOSE OF THIS SUBROUTINE:
647 : // This subroutine returns the appropriate Julian Day value for the input
648 : // Month and Day.
649 :
650 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
651 : static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
652 : // End day numbers of each month (without Leap Year)
653 :
654 193976 : if (Month == 1) {
655 : // CASE 1: JANUARY
656 61790 : return Day;
657 :
658 132186 : } else if (Month == 2) {
659 : // CASE 2: FEBRUARY
660 3191 : return Day + EndDayofMonth[0];
661 :
662 128995 : } else if ((Month >= 3) && (Month <= 12)) {
663 : // CASE 3: REMAINING MONTHS
664 128995 : return Day + EndDayofMonth[Month - 2] + LeapYearValue;
665 :
666 : } else {
667 0 : return 0;
668 : }
669 : }
670 :
671 76763 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
672 : {
673 :
674 : // SUBROUTINE INFORMATION:
675 : // AUTHOR Linda Lawrie
676 : // DATE WRITTEN December 1999
677 :
678 : // PURPOSE OF THIS SUBROUTINE:
679 : // This subroutine performs and inverse Julian Day
680 : // calculation, using an input JulianDay and returning
681 : // appropriate Month and Day.
682 :
683 : // SUBROUTINE PARAMETER DEFINITIONS:
684 : static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
685 :
686 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
687 : int WMonth;
688 : int LeapAddPrev;
689 : int LeapAddCur;
690 :
691 76763 : if (Number < 0 || Number > 366) {
692 0 : return;
693 : }
694 496281 : for (WMonth = 1; WMonth <= 12; ++WMonth) {
695 496281 : if (WMonth == 1) {
696 76763 : LeapAddPrev = 0;
697 76763 : LeapAddCur = 0;
698 419518 : } else if (WMonth == 2) {
699 69418 : LeapAddPrev = 0;
700 69418 : LeapAddCur = LeapYr;
701 : } else {
702 350100 : LeapAddPrev = LeapYr;
703 350100 : LeapAddCur = LeapYr;
704 : }
705 496281 : if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) {
706 76763 : break;
707 : }
708 : }
709 76763 : PMonth = WMonth;
710 76763 : PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
711 : }
712 :
713 6912 : bool BetweenDateHoursLeftInclusive(
714 : int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
715 : {
716 6912 : Real64 TestRatioOfDay = TestHour / 24.0;
717 6912 : Real64 StartRatioOfDay = StartHour / 24.0;
718 6912 : Real64 EndRatioOfDay = EndHour / 24.0;
719 :
720 6912 : if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
721 5376 : return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
722 : } else { // EndDate < StartDate
723 1536 : return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
724 : }
725 : }
726 :
727 16 : bool BetweenDates(int const TestDate, // Date to test
728 : int const StartDate, // Start date in sequence
729 : int const EndDate // End date in sequence
730 : )
731 : {
732 :
733 : // FUNCTION INFORMATION:
734 : // AUTHOR Linda K. Lawrie
735 : // DATE WRITTEN June 2000
736 :
737 : // PURPOSE OF THIS FUNCTION:
738 : // This function returns true if the TestDate is between
739 : // (StartDate <= TestDate <= EndDate).
740 :
741 : // METHODOLOGY EMPLOYED:
742 : // The input dates are Julian Day format, year is irrelevant.
743 : // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
744 : // this routine accommodates.
745 :
746 : // REFERENCES:
747 : // Adapted from BLAST BTWEEN function.
748 :
749 16 : bool BetweenDates = false; // Default case
750 :
751 16 : if (StartDate <= EndDate) { // Start Date <= End Date
752 0 : if (TestDate >= StartDate && TestDate <= EndDate) {
753 0 : BetweenDates = true;
754 : }
755 : } else { // EndDate < StartDate
756 16 : if (TestDate <= EndDate || TestDate >= StartDate) {
757 8 : BetweenDates = true;
758 : }
759 : }
760 :
761 16 : return BetweenDates;
762 : }
763 :
764 2247702 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
765 : {
766 :
767 : // FUNCTION INFORMATION:
768 : // AUTHOR Linda K. Lawrie
769 : // DATE WRITTEN April 2003
770 :
771 : // PURPOSE OF THIS FUNCTION:
772 : // This function creates the current time interval of the system time step.
773 :
774 : // Using/Aliasing
775 2247702 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
776 2247702 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
777 :
778 2247702 : Real64 constexpr FracToMin(60.0);
779 :
780 : // ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
781 : // CR6902 ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
782 : // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
783 2247702 : Real64 ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
784 2247702 : Real64 ActualTimeE = ActualTimeS + TimeStepSys;
785 2247702 : int ActualTimeHrS = int(ActualTimeS);
786 : // ActualTimeHrE=INT(ActualTimeE)
787 2247702 : int ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
788 :
789 2247702 : if (ActualTimeMinS == 60) {
790 6458 : ++ActualTimeHrS;
791 6458 : ActualTimeMinS = 0;
792 : }
793 2247702 : const std::string TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
794 2247702 : Real64 minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
795 :
796 2247702 : std::string TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
797 :
798 2247702 : if (TimeStmpE[3] == ' ') {
799 396430 : TimeStmpE[3] = '0';
800 : }
801 4495404 : return TimeStmpS + " - " + TimeStmpE;
802 2247702 : }
803 :
804 : // returns the Julian date for the first, second, etc. day of week for a given month
805 3736 : int nthDayOfWeekOfMonth(const EnergyPlusData &state,
806 : int const dayOfWeek, // day of week (Sunday=1, Monday=2, ...)
807 : int const nthTime, // nth time the day of the week occurs (first monday, third tuesday, ..)
808 : int const monthNumber // January = 1
809 : )
810 : {
811 : // J. Glazer - August 2017
812 3736 : int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
813 3736 : int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
814 3736 : if (dayOfWeek >= dayOfWeekForFirstDay) {
815 1894 : return firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
816 : } else {
817 1842 : return firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
818 : }
819 : }
820 :
821 12572670 : Real64 SafeDivide(Real64 const a, Real64 const b)
822 : {
823 :
824 : // returns a / b while preventing division by zero
825 :
826 : // Locals
827 12572670 : Real64 constexpr SMALL(1.E-10);
828 :
829 12572670 : if (std::abs(b) >= SMALL) {
830 12571504 : return a / b;
831 : } else {
832 1166 : return a / sign(SMALL, b);
833 : }
834 : }
835 :
836 317089875 : void Iterate(Real64 &ResultX, // ResultX is the final Iteration result passed back to the calling routine
837 : Real64 const Tol, // Tolerance for Convergence
838 : Real64 const X0, // Current value of X
839 : Real64 const Y0, // Current value of the function Y(X)
840 : Real64 &X1, // First Previous values of X
841 : Real64 &Y1, // First Previous values of Y(X1)
842 : int const Iter, // Number of iterations
843 : int &Cnvg // Convergence flag Cnvg = 0: Not converged
844 : )
845 : {
846 :
847 : // SUBROUTINE INFORMATION:
848 : // AUTHOR Richard Liesen
849 : // DATE WRITTEN March 2004
850 :
851 : // PURPOSE OF THIS SUBROUTINE:
852 : // Iteratively solves for the value of X which satisfies Y(X)=0.
853 : // The subroutine tests for convergence and provides a new guess for the value of the
854 : // independent variable X.
855 :
856 : // REFERENCES:
857 : // Linear Correction based on the RegulaFalsi routine in EnergyPlus
858 :
859 : // SUBROUTINE PARAMETER DEFINITIONS:
860 317089875 : Real64 constexpr small(1.e-9); // Small Number used to approximate zero
861 317089875 : Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
862 :
863 : // Check for convergence by comparing change in X
864 317089875 : if (Iter != 1) {
865 285410396 : if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
866 31679417 : ResultX = X0;
867 31679417 : Cnvg = 1;
868 31679417 : return;
869 : }
870 : }
871 :
872 : // Not converged.
873 285410458 : Cnvg = 0;
874 285410458 : if (Iter == 1) {
875 :
876 : // New guess is specified by Perturb
877 31679479 : if (std::abs(X0) > small) {
878 31677564 : ResultX = X0 * (1.0 + Perturb);
879 : } else {
880 1915 : ResultX = Perturb;
881 : }
882 :
883 : } else {
884 :
885 : // New guess calculated from LINEAR FIT of most recent two points
886 253730979 : Real64 DY = Y0 - Y1;
887 253730979 : if (std::abs(DY) < small) {
888 0 : DY = small;
889 : }
890 : // new estimation
891 :
892 253730979 : ResultX = (Y0 * X1 - Y1 * X0) / DY;
893 : }
894 :
895 285410458 : X1 = X0;
896 285410458 : Y1 = Y0;
897 : }
898 :
899 39873 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
900 : {
901 :
902 : // FUNCTION INFORMATION:
903 : // AUTHOR Linda K. Lawrie
904 : // DATE WRITTEN September 2001
905 :
906 : // PURPOSE OF THIS FUNCTION:
907 : // This function looks up a number(integer) in a similar list of
908 : // items and returns the index of the item in the list, if found.
909 :
910 : // Argument array dimensioning
911 39873 : ListOfItems.dim(_);
912 :
913 359954 : for (int Count = 1; Count <= NumItems; ++Count) {
914 327634 : if (WhichNumber == ListOfItems(Count)) {
915 7553 : return Count;
916 : }
917 : }
918 :
919 32320 : return 0;
920 : }
921 :
922 315296 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
923 : int &Month, // month in integer format (1-12)
924 : int &Day, // day in integer format (1-31)
925 : int &Hour, // hour in integer format (1-24)
926 : int &Minute // minute in integer format (0:59)
927 : )
928 : {
929 :
930 : // SUBROUTINE INFORMATION:
931 : // AUTHOR Linda Lawrie
932 : // DATE WRITTEN March 2000
933 :
934 : // PURPOSE OF THIS SUBROUTINE:
935 : // This subroutine decodes the "packed" integer representation of
936 : // the Month, Day, Hour, and Minute. Packed integers are used to
937 : // save memory allocation. Original idea for this routine is contained
938 : // in DECMDH, BLAST code, by Jean Baugh.
939 :
940 : // METHODOLOGY EMPLOYED:
941 : // Using maximum integer concept the original date can be decoded
942 : // from the packed single word. This relies on 4 byte integer representation
943 : // as a minimum (capable of representing up to 2,147,483,647).
944 :
945 : // SUBROUTINE PARAMETER DEFINITIONS:
946 : static constexpr int DecMon(100 * 100 * 100);
947 : static constexpr int DecDay(100 * 100);
948 : static constexpr int DecHr(100);
949 :
950 315296 : int TmpItem = Item;
951 315296 : Month = TmpItem / DecMon;
952 315296 : TmpItem = (TmpItem - Month * DecMon);
953 315296 : Day = TmpItem / DecDay;
954 315296 : TmpItem -= Day * DecDay;
955 315296 : Hour = TmpItem / DecHr;
956 315296 : Minute = mod(TmpItem, DecHr);
957 315296 : }
958 :
959 1171756 : void EncodeMonDayHrMin(int &Item, // word containing encoded month, day, hour, minute
960 : int const Month, // month in integer format (1:12)
961 : int const Day, // day in integer format (1:31)
962 : int const Hour, // hour in integer format (1:24)
963 : int const Minute // minute in integer format (0:59)
964 : )
965 : {
966 :
967 : // SUBROUTINE INFORMATION:
968 : // AUTHOR Linda Lawrie
969 : // DATE WRITTEN March 2000
970 :
971 : // PURPOSE OF THIS SUBROUTINE:
972 : // This subroutine encodes the "packed" integer representation of
973 : // the Month, Day, Hour, and Minute. Packed integers are used to
974 : // save memory allocation. Original idea for this routine is contained
975 : // in DECMDH, BLAST code, by Jean Baugh.
976 :
977 : // METHODOLOGY EMPLOYED:
978 : // Using maximum integer concept the original date can be decoded
979 : // from the packed single word. This relies on 4 byte integer representation
980 : // as a minimum (capable of representing up to 2,147,483,647).
981 :
982 1171756 : Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
983 1171756 : }
984 :
985 0 : std::string CreateTimeString(Real64 const Time) // Time in seconds
986 : {
987 :
988 : // FUNCTION INFORMATION:
989 : // AUTHOR Dimitri Curtil
990 : // DATE WRITTEN January 2005
991 :
992 : // PURPOSE OF THIS FUNCTION:
993 : // This function creates the time stamp string from the time value specified in seconds.
994 : // Inspired by similar function CreateSysTimeIntervalString() in General.cc
995 : // However, this function provides better accuracy for sub-minute time steps
996 : // by also showing information down to the 10th of a second.
997 : // Note that Time is expected to be specified in REAL(r64).
998 :
999 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1000 : int Hours; // Number of hours <= 24
1001 : int Minutes; // Remaining minutes < 60
1002 : Real64 Seconds; // Remaining seconds < 60
1003 :
1004 0 : ParseTime(Time, Hours, Minutes, Seconds);
1005 :
1006 : // TimeStamp written with formatting
1007 : // "hh:mm:ss.s"
1008 0 : return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
1009 : }
1010 :
1011 14736 : void ParseTime(Real64 const Time, // Time value in seconds
1012 : int &Hours, // Number of hours
1013 : int &Minutes, // Number of minutes < 60
1014 : Real64 &Seconds // Number of seconds < 60
1015 : )
1016 : {
1017 : // FUNCTION INFORMATION:
1018 : // AUTHOR Dimitri Curtil
1019 : // DATE WRITTEN January 2005
1020 :
1021 : // PURPOSE OF THIS FUNCTION:
1022 : // This subroutine decomposes a time value specified in seconds
1023 : // into a triplet { hours : minutes : seconds } such that
1024 : // - minutes < 60
1025 : // - seconds < 60
1026 :
1027 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1028 14736 : int constexpr MinToSec = 60;
1029 14736 : int constexpr HourToSec = 60 * 60;
1030 :
1031 : // Get number of hours
1032 : // This might undershoot the actual number of hours. See DO WHILE loop.
1033 14736 : Hours = int(Time) / HourToSec;
1034 :
1035 : // Compute remainder in seconds
1036 14736 : Real64 Remainder = (Time - Hours * HourToSec);
1037 :
1038 : // Compute minutes
1039 14736 : Minutes = int(Remainder) / MinToSec;
1040 :
1041 : // Compute remainder in seconds
1042 14736 : Remainder -= Minutes * MinToSec;
1043 :
1044 : // Compute seconds
1045 14736 : Seconds = Remainder;
1046 14736 : }
1047 :
1048 13617 : void ScanForReports(EnergyPlusData &state,
1049 : std::string const &reportName,
1050 : bool &DoReport,
1051 : ObjexxFCL::Optional_string_const ReportKey,
1052 : ObjexxFCL::Optional_string Option1,
1053 : ObjexxFCL::Optional_string Option2)
1054 : {
1055 :
1056 : // SUBROUTINE INFORMATION:
1057 : // AUTHOR Linda Lawrie
1058 : // DATE WRITTEN March 2009
1059 :
1060 : // PURPOSE OF THIS SUBROUTINE:
1061 : // This routine scans for the global "reports" settings, such as Variable Dictionary,
1062 : // Surfaces (and options), Constructions, etc.
1063 :
1064 : // METHODOLOGY EMPLOYED:
1065 : // First time routine is called, all the viable combinations/settings for the reports are
1066 : // stored in SAVEd variables. Later callings will retrieve those.
1067 :
1068 13617 : if (state.dataGeneral->GetReportInput) {
1069 :
1070 : int NumNames;
1071 : int NumNumbers;
1072 : int IOStat;
1073 : int RepNum;
1074 :
1075 801 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
1076 801 : cCurrentModuleObject = "Output:Surfaces:List";
1077 :
1078 801 : int NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1079 :
1080 : enum
1081 : {
1082 : EMPTY,
1083 : LINES,
1084 : VERTICES,
1085 : DETAILS,
1086 : DETAILSWITHVERTICES,
1087 : COSTINFO,
1088 : VIEWFACTORINFO,
1089 : DECAYCURVESFROMCOMPONENTLOADSSUMMARY
1090 : };
1091 0 : std::map<std::string, int> localMap = {{"", EMPTY},
1092 0 : {"LINES", LINES},
1093 0 : {"VERTICES", VERTICES},
1094 0 : {"DETAILS", DETAILS},
1095 0 : {"DETAILED", DETAILS},
1096 0 : {"DETAIL", DETAILS},
1097 0 : {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
1098 0 : {"DETAILVERTICES", DETAILSWITHVERTICES},
1099 0 : {"COSTINFO", COSTINFO},
1100 0 : {"VIEWFACTORINFO", VIEWFACTORINFO},
1101 10413 : {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
1102 :
1103 1064 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1104 526 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1105 : cCurrentModuleObject,
1106 : RepNum,
1107 263 : state.dataIPShortCut->cAlphaArgs,
1108 : NumNames,
1109 263 : state.dataIPShortCut->rNumericArgs,
1110 : NumNumbers,
1111 : IOStat,
1112 263 : state.dataIPShortCut->lNumericFieldBlanks,
1113 263 : state.dataIPShortCut->lAlphaFieldBlanks,
1114 263 : state.dataIPShortCut->cAlphaFieldNames,
1115 263 : state.dataIPShortCut->cNumericFieldNames);
1116 :
1117 : try {
1118 263 : int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
1119 263 : switch (value) {
1120 52 : case LINES:
1121 52 : state.dataGeneral->LineRpt = true;
1122 52 : state.dataGeneral->LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1123 52 : break;
1124 5 : case VERTICES:
1125 5 : state.dataGeneral->SurfVert = true;
1126 5 : break;
1127 149 : case DETAILS:
1128 149 : state.dataGeneral->SurfDet = true;
1129 149 : break;
1130 31 : case DETAILSWITHVERTICES:
1131 31 : state.dataGeneral->SurfDetWVert = true;
1132 31 : break;
1133 7 : case COSTINFO:
1134 : // Custom case for reporting surface info for cost estimates (for first costs in optimizing)
1135 7 : state.dataGeneral->CostInfo = true;
1136 7 : break;
1137 10 : case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
1138 10 : state.dataGeneral->ViewFactorInfo = true;
1139 10 : state.dataGeneral->ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1140 10 : break;
1141 9 : case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
1142 : // load component report appear in the EIO file
1143 9 : state.dataGlobal->ShowDecayCurvesInEIO = true;
1144 9 : break;
1145 0 : default: // including empty
1146 0 : ShowWarningError(state, format("{}: No {} supplied.", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1)));
1147 0 : ShowContinueError(state,
1148 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1149 : }
1150 0 : } catch (int e) {
1151 0 : ShowWarningError(state,
1152 0 : format("{}: Invalid {}=\"{}\" supplied.",
1153 : cCurrentModuleObject,
1154 0 : state.dataIPShortCut->cAlphaFieldNames(1),
1155 0 : state.dataIPShortCut->cAlphaArgs(1)));
1156 0 : ShowContinueError(state,
1157 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1158 0 : }
1159 : }
1160 :
1161 801 : cCurrentModuleObject = "Output:Surfaces:Drawing";
1162 :
1163 801 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1164 1349 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1165 1096 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1166 : cCurrentModuleObject,
1167 : RepNum,
1168 548 : state.dataIPShortCut->cAlphaArgs,
1169 : NumNames,
1170 548 : state.dataIPShortCut->rNumericArgs,
1171 : NumNumbers,
1172 : IOStat,
1173 548 : state.dataIPShortCut->lNumericFieldBlanks,
1174 548 : state.dataIPShortCut->lAlphaFieldBlanks,
1175 548 : state.dataIPShortCut->cAlphaFieldNames,
1176 548 : state.dataIPShortCut->cNumericFieldNames);
1177 :
1178 : ReportType checkReportType =
1179 548 : static_cast<ReportType>(getEnumValue(ReportTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
1180 :
1181 548 : switch (checkReportType) {
1182 483 : case ReportType::DXF: {
1183 483 : state.dataGeneral->DXFReport = true;
1184 483 : state.dataGeneral->DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1185 483 : state.dataGeneral->DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1186 483 : } break;
1187 29 : case ReportType::DXFWireFrame: {
1188 29 : state.dataGeneral->DXFWFReport = true;
1189 29 : state.dataGeneral->DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1190 29 : state.dataGeneral->DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1191 29 : } break;
1192 36 : case ReportType::VRML: {
1193 36 : state.dataGeneral->VRMLReport = true;
1194 36 : state.dataGeneral->VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
1195 36 : state.dataGeneral->VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
1196 36 : } break;
1197 0 : default:
1198 0 : break;
1199 : }
1200 : }
1201 :
1202 1602 : RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
1203 801 : if (RepNum > 0) {
1204 0 : state.dataGeneral->VarDict = true;
1205 0 : state.dataGeneral->VarDictOption1 = "REGULAR";
1206 0 : state.dataGeneral->VarDictOption2 = "";
1207 : }
1208 :
1209 801 : cCurrentModuleObject = "Output:VariableDictionary";
1210 :
1211 801 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1212 1597 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1213 1592 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1214 : cCurrentModuleObject,
1215 : RepNum,
1216 796 : state.dataIPShortCut->cAlphaArgs,
1217 : NumNames,
1218 796 : state.dataIPShortCut->rNumericArgs,
1219 : NumNumbers,
1220 : IOStat,
1221 796 : state.dataIPShortCut->lNumericFieldBlanks,
1222 796 : state.dataIPShortCut->lAlphaFieldBlanks,
1223 796 : state.dataIPShortCut->cAlphaFieldNames,
1224 796 : state.dataIPShortCut->cNumericFieldNames);
1225 796 : state.dataGeneral->VarDict = true;
1226 796 : state.dataGeneral->VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
1227 796 : state.dataGeneral->VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
1228 : }
1229 :
1230 801 : cCurrentModuleObject = "Output:Constructions";
1231 801 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1232 1121 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1233 640 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1234 : cCurrentModuleObject,
1235 : RepNum,
1236 320 : state.dataIPShortCut->cAlphaArgs,
1237 : NumNames,
1238 320 : state.dataIPShortCut->rNumericArgs,
1239 : NumNumbers,
1240 : IOStat,
1241 320 : state.dataIPShortCut->lNumericFieldBlanks,
1242 320 : state.dataIPShortCut->lAlphaFieldBlanks,
1243 320 : state.dataIPShortCut->cAlphaFieldNames,
1244 320 : state.dataIPShortCut->cNumericFieldNames);
1245 320 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
1246 309 : state.dataGeneral->Constructions = true;
1247 11 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
1248 11 : state.dataGeneral->Materials = true;
1249 : }
1250 320 : if (NumNames > 1) {
1251 3 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
1252 0 : state.dataGeneral->Constructions = true;
1253 3 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
1254 3 : state.dataGeneral->Materials = true;
1255 : }
1256 : }
1257 : }
1258 :
1259 801 : cCurrentModuleObject = "Output:EnergyManagementSystem";
1260 801 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1261 842 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1262 82 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1263 : cCurrentModuleObject,
1264 : RepNum,
1265 41 : state.dataIPShortCut->cAlphaArgs,
1266 : NumNames,
1267 41 : state.dataIPShortCut->rNumericArgs,
1268 : NumNumbers,
1269 : IOStat,
1270 41 : state.dataIPShortCut->lNumericFieldBlanks,
1271 41 : state.dataIPShortCut->lAlphaFieldBlanks,
1272 41 : state.dataIPShortCut->cAlphaFieldNames,
1273 41 : state.dataIPShortCut->cNumericFieldNames);
1274 :
1275 41 : state.dataGeneral->EMSoutput = true;
1276 :
1277 41 : AvailRpt CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
1278 41 : state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1279 41 : state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
1280 :
1281 41 : CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
1282 41 : state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1283 41 : state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
1284 :
1285 : ERLdebugOutputLevel CheckERLlevel =
1286 41 : static_cast<ERLdebugOutputLevel>(getEnumValue(ERLdebugOutputLevelNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
1287 41 : state.dataRuntimeLang->OutputEMSErrors =
1288 41 : (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
1289 41 : state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
1290 : }
1291 :
1292 801 : state.dataGeneral->GetReportInput = false;
1293 801 : }
1294 :
1295 : // Process the Scan Request
1296 13617 : DoReport = false;
1297 :
1298 13617 : ReportName rptName = static_cast<ReportName>(getEnumValue(ReportNamesUC, Util::makeUPPER(Util::makeUPPER(reportName))));
1299 13617 : switch (rptName) {
1300 2404 : case ReportName::Constructions: {
1301 2404 : if (present(ReportKey)) {
1302 2404 : if (Util::SameString(ReportKey(), "Constructions")) {
1303 1603 : DoReport = state.dataGeneral->Constructions;
1304 : }
1305 2404 : if (Util::SameString(ReportKey(), "Materials")) {
1306 801 : DoReport = state.dataGeneral->Materials;
1307 : }
1308 : }
1309 2404 : } break;
1310 1602 : case ReportName::Viewfactorinfo: {
1311 1602 : DoReport = state.dataGeneral->ViewFactorInfo;
1312 1602 : if (present(Option1)) {
1313 1602 : Option1 = state.dataGeneral->ViewRptOption1;
1314 : }
1315 1602 : } break;
1316 800 : case ReportName::Variabledictionary: {
1317 800 : DoReport = state.dataGeneral->VarDict;
1318 800 : if (present(Option1)) {
1319 800 : Option1 = state.dataGeneral->VarDictOption1;
1320 : }
1321 800 : if (present(Option2)) {
1322 800 : Option2 = state.dataGeneral->VarDictOption2;
1323 : }
1324 : // CASE ('SCHEDULES')
1325 : // DoReport=SchRpt
1326 : // IF (PRESENT(Option1)) Option1=SchRptOption
1327 800 : } break;
1328 7209 : case ReportName::Surfaces: {
1329 7209 : RptKey rptKey = static_cast<RptKey>(getEnumValue(RptKeyNamesUC, Util::makeUPPER(ReportKey())));
1330 7209 : switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
1331 801 : case RptKey::Costinfo: {
1332 801 : DoReport = state.dataGeneral->CostInfo;
1333 801 : } break;
1334 801 : case RptKey::DXF: {
1335 801 : DoReport = state.dataGeneral->DXFReport;
1336 801 : if (present(Option1)) {
1337 801 : Option1 = state.dataGeneral->DXFOption1;
1338 : }
1339 801 : if (present(Option2)) {
1340 801 : Option2 = state.dataGeneral->DXFOption2;
1341 : }
1342 801 : } break;
1343 801 : case RptKey::DXFwireframe: {
1344 801 : DoReport = state.dataGeneral->DXFWFReport;
1345 801 : if (present(Option1)) {
1346 801 : Option1 = state.dataGeneral->DXFWFOption1;
1347 : }
1348 801 : if (present(Option2)) {
1349 801 : Option2 = state.dataGeneral->DXFWFOption2;
1350 : }
1351 801 : } break;
1352 801 : case RptKey::VRML: {
1353 801 : DoReport = state.dataGeneral->VRMLReport;
1354 801 : if (present(Option1)) {
1355 801 : Option1 = state.dataGeneral->VRMLOption1;
1356 : }
1357 801 : if (present(Option2)) {
1358 801 : Option2 = state.dataGeneral->VRMLOption2;
1359 : }
1360 801 : } break;
1361 801 : case RptKey::Vertices: {
1362 801 : DoReport = state.dataGeneral->SurfVert;
1363 801 : } break;
1364 1602 : case RptKey::Details: {
1365 1602 : DoReport = state.dataGeneral->SurfDet;
1366 1602 : } break;
1367 801 : case RptKey::DetailsWithVertices: {
1368 801 : DoReport = state.dataGeneral->SurfDetWVert;
1369 801 : } break;
1370 801 : case RptKey::Lines: {
1371 801 : DoReport = state.dataGeneral->LineRpt;
1372 801 : if (present(Option1)) {
1373 801 : Option1 = state.dataGeneral->LineRptOption1;
1374 : }
1375 801 : } break;
1376 0 : default:
1377 0 : break;
1378 : }
1379 7209 : } break;
1380 1602 : case ReportName::Energymanagementsystem: {
1381 1602 : DoReport = state.dataGeneral->EMSoutput;
1382 1602 : } break;
1383 0 : default:
1384 0 : break;
1385 : }
1386 14418 : }
1387 :
1388 54 : void CheckCreatedZoneItemName(EnergyPlusData &state,
1389 : std::string_view const calledFrom, // routine called from
1390 : std::string const &CurrentObject, // object being parsed
1391 : std::string const &ZoneName, // Zone Name associated
1392 : std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
1393 : std::string const &ItemName, // Item name (People, Lights, etc object)
1394 : Array1_string const &ItemNames, // Item Names to check for duplication
1395 : int const NumItems, // Number of items in ItemNames array
1396 : std::string &ResultName, // Resultant name
1397 : bool &errFlag // Error flag set to true if error found here.
1398 : )
1399 : {
1400 :
1401 : // SUBROUTINE INFORMATION:
1402 : // AUTHOR Linda Lawrie
1403 : // DATE WRITTEN December 2012
1404 :
1405 : // PURPOSE OF THIS SUBROUTINE:
1406 : // This routine checks "global" objects (that is, ones with ZoneList used in the name
1407 : // specification) along with a specific name for the current object for length and duplication
1408 : // with previous objects of that class.
1409 :
1410 54 : errFlag = false;
1411 54 : std::string::size_type const ItemNameLength = len(ItemName);
1412 54 : std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
1413 54 : ResultName = ZoneName + ' ' + ItemName;
1414 54 : bool TooLong = false;
1415 54 : if (ItemLength > Constant::MaxNameLength) {
1416 0 : ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
1417 0 : ShowContinueError(state, format("Object Name=\"{}\".", ItemName));
1418 0 : ShowContinueError(state, format("ZoneList/Zone Name=\"{}\".", ZoneName));
1419 0 : ShowContinueError(state,
1420 0 : format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, Constant::MaxNameLength));
1421 0 : ShowContinueError(state,
1422 0 : format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
1423 0 : MaxZoneNameLength + 1 + ItemNameLength - Constant::MaxNameLength));
1424 0 : ShowContinueError(state, format("name that will be used (may be needed in reporting)=\"{}\".", ResultName));
1425 0 : TooLong = true;
1426 : }
1427 :
1428 54 : int FoundItem = Util::FindItemInList(ResultName, ItemNames, NumItems);
1429 :
1430 54 : if (FoundItem != 0) {
1431 0 : ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
1432 0 : ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
1433 0 : if (TooLong) {
1434 0 : ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
1435 : }
1436 0 : ResultName = "xxxxxxx";
1437 0 : errFlag = true;
1438 : }
1439 54 : }
1440 :
1441 0 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
1442 : {
1443 : int currentDate;
1444 0 : int reportStartDate = state.dataWeather->ReportPeriodInput(periodIdx).startJulianDate;
1445 0 : int reportStartHour = state.dataWeather->ReportPeriodInput(periodIdx).startHour;
1446 0 : if (state.dataWeather->ReportPeriodInput(periodIdx).startYear > 0) {
1447 0 : currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1448 : } else {
1449 0 : currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1450 : }
1451 0 : return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
1452 : }
1453 :
1454 5376 : void findReportPeriodIdx(EnergyPlusData &state,
1455 : const Array1D<Weather::ReportPeriodData> &ReportPeriodInputData,
1456 : const int nReportPeriods,
1457 : Array1D_bool &inReportPeriodFlags)
1458 : {
1459 : // return an array of flags, indicating whether the current time is in reporting period i
1460 : int currentDate;
1461 12288 : for (int i = 1; i <= nReportPeriods; i++) {
1462 6912 : int reportStartDate = ReportPeriodInputData(i).startJulianDate;
1463 6912 : int reportStartHour = ReportPeriodInputData(i).startHour;
1464 6912 : int reportEndDate = ReportPeriodInputData(i).endJulianDate;
1465 6912 : int reportEndHour = ReportPeriodInputData(i).endHour;
1466 6912 : if (ReportPeriodInputData(i).startYear > 0) {
1467 0 : currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1468 : } else {
1469 6912 : currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1470 : }
1471 6912 : if (General::BetweenDateHoursLeftInclusive(
1472 6912 : currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
1473 0 : inReportPeriodFlags(i) = true;
1474 : }
1475 : }
1476 5376 : }
1477 :
1478 255 : Real64 rotAzmDiffDeg(Real64 AzmA, Real64 AzmB)
1479 : {
1480 : // This function takes two (azimuth) angles in Degree(s),
1481 : // and returns the rotational angle difference in Degree(s).
1482 :
1483 255 : Real64 diff = AzmB - AzmA;
1484 255 : if (diff > 180.0) {
1485 12 : diff = 360.0 - diff;
1486 243 : } else if (diff < -180.0) {
1487 14 : diff = 360.0 + diff;
1488 : }
1489 255 : return std::abs(diff);
1490 : }
1491 :
1492 : } // namespace EnergyPlus::General
|