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