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 : // FMI-Related Headers
49 : extern "C" {
50 : #include <FMI/main.h>
51 : }
52 :
53 : // C++ Headers
54 : #include <cstdlib>
55 : #include <iostream>
56 :
57 : // ObjexxFCL Headers
58 : #include <ObjexxFCL/Array1D.hh>
59 : #include <ObjexxFCL/Array1S.hh>
60 : #include <ObjexxFCL/char.functions.hh>
61 : #include <ObjexxFCL/string.functions.hh>
62 :
63 : // EnergyPlus Headers
64 : #include <EnergyPlus/BranchInputManager.hh>
65 : #include <EnergyPlus/BranchNodeConnections.hh>
66 : // #include <EnergyPlus/Data/EnergyPlusData.hh>
67 : #include <EnergyPlus/DataEnvironment.hh>
68 : #include <EnergyPlus/DataErrorTracking.hh>
69 : // #include <EnergyPlus/DataGlobalConstants.hh>
70 : #include <EnergyPlus/DataReportingFlags.hh>
71 : #include <EnergyPlus/DataStringGlobals.hh>
72 : #include <EnergyPlus/DataSystemVariables.hh>
73 : // #include <EnergyPlus/DataTimings.hh>
74 : #include <EnergyPlus/DaylightingManager.hh>
75 : // #include <EnergyPlus/DisplayRoutines.hh>
76 : #include <EnergyPlus/ExternalInterface.hh>
77 : #include <EnergyPlus/FileSystem.hh>
78 : #include <EnergyPlus/General.hh>
79 : #include <EnergyPlus/GeneralRoutines.hh>
80 : // #include <EnergyPlus/IOFiles.hh>
81 : #include <EnergyPlus/NodeInputManager.hh>
82 : #include <EnergyPlus/OutputReports.hh>
83 : #include <EnergyPlus/Plant/PlantManager.hh>
84 : #include <EnergyPlus/ResultsFramework.hh>
85 : #include <EnergyPlus/SQLiteProcedures.hh>
86 : #include <EnergyPlus/SimulationManager.hh>
87 : #include <EnergyPlus/SolarShading.hh>
88 : #include <EnergyPlus/SystemReports.hh>
89 : #include <EnergyPlus/Timer.hh>
90 : #include <EnergyPlus/UtilityRoutines.hh>
91 : // Third Party Headers
92 : #include <fast_float/fast_float.h>
93 :
94 : namespace EnergyPlus {
95 :
96 : namespace Util {
97 :
98 183456 : Real64 ProcessNumber(std::string_view String, bool &ErrorFlag)
99 : {
100 :
101 : // FUNCTION INFORMATION:
102 : // AUTHOR Linda K. Lawrie
103 : // DATE WRITTEN September 1997
104 :
105 : // PURPOSE OF THIS FUNCTION:
106 : // This function processes a string that should be numeric and
107 : // returns the real value of the string.
108 :
109 : // METHODOLOGY EMPLOYED:
110 : // FUNCTION ProcessNumber translates the argument (a string)
111 : // into a real number. The string should consist of all
112 : // numeric characters (except a decimal point). Numerics
113 : // with exponentiation (i.e. 1.2345E+03) are allowed but if
114 : // it is not a valid number an error message along with the
115 : // string causing the error is printed out and 0.0 is returned
116 : // as the value.
117 :
118 : // REFERENCES:
119 : // List directed Fortran input/output.
120 :
121 : // SUBROUTINE PARAMETER DEFINITIONS:
122 183456 : Real64 rProcessNumber = 0.0;
123 183456 : ErrorFlag = false;
124 :
125 183456 : if (String.empty()) {
126 0 : return rProcessNumber;
127 : }
128 :
129 183456 : size_t const front_trim = String.find_first_not_of(' ');
130 183456 : size_t const back_trim = String.find_last_not_of(' ');
131 183456 : if (front_trim == std::string::npos || back_trim == std::string::npos) {
132 0 : return rProcessNumber;
133 : } else {
134 183456 : String = String.substr(front_trim, back_trim - front_trim + 1);
135 : }
136 :
137 183456 : auto result = fast_float::from_chars(String.data(), String.data() + String.size(), rProcessNumber); // (AUTO_OK_OBJ)
138 183456 : size_t remaining_size = result.ptr - String.data();
139 183456 : if (result.ec == std::errc::result_out_of_range || result.ec == std::errc::invalid_argument) {
140 77 : rProcessNumber = 0.0;
141 77 : ErrorFlag = true;
142 183379 : } else if (remaining_size != String.size()) {
143 2058 : if (*result.ptr == '+' || *result.ptr == '-') {
144 6 : ++result.ptr;
145 6 : remaining_size = result.ptr - String.data();
146 6 : if (remaining_size == String.size()) {
147 0 : rProcessNumber = 0.0;
148 0 : ErrorFlag = true;
149 : }
150 : }
151 2058 : if (*result.ptr == 'd' || *result.ptr == 'D') {
152 : // make FORTRAN floating point number (containing 'd' or 'D')
153 : // standardized by replacing 'd' or 'D' with 'e'
154 2 : std::string str{String};
155 22 : std::replace_if(str.begin(), str.end(), [](const char c) { return c == 'D' || c == 'd'; }, 'e');
156 2 : return ProcessNumber(str, ErrorFlag);
157 2058 : } else if (*result.ptr == 'e' || *result.ptr == 'E') {
158 4 : ++result.ptr;
159 4 : remaining_size = result.ptr - String.data();
160 8 : for (size_t i = remaining_size; i < String.size(); ++i, ++result.ptr) {
161 4 : if (!std::isdigit(*result.ptr)) {
162 0 : rProcessNumber = 0.0;
163 0 : ErrorFlag = true;
164 0 : return rProcessNumber;
165 : }
166 : }
167 4 : } else {
168 2052 : rProcessNumber = 0.0;
169 2052 : ErrorFlag = true;
170 : }
171 181321 : } else if (!std::isfinite(rProcessNumber)) {
172 1 : rProcessNumber = 0.0;
173 1 : ErrorFlag = true;
174 : }
175 :
176 183454 : return rProcessNumber;
177 : }
178 :
179 11029 : int FindItemInList(std::string_view const String, Array1_string const &ListOfItems, int const NumItems)
180 : {
181 :
182 : // FUNCTION INFORMATION:
183 : // AUTHOR Linda K. Lawrie
184 : // DATE WRITTEN September 1997
185 :
186 : // PURPOSE OF THIS FUNCTION:
187 : // This function looks up a string in a similar list of
188 : // items and returns the index of the item in the list, if
189 : // found. This routine is not case insensitive and doesn't need
190 : // for most inputs -- they are automatically turned to UPPERCASE.
191 : // If you need case insensitivity use FindItem.
192 :
193 34563 : for (int Count = 1; Count <= NumItems; ++Count) {
194 27035 : if (String == ListOfItems(Count)) {
195 3501 : return Count;
196 : }
197 : }
198 7528 : return 0; // Not found
199 : }
200 :
201 10206 : int FindItemInList(std::string_view const String, Array1S_string const ListOfItems, int const NumItems)
202 : {
203 :
204 : // FUNCTION INFORMATION:
205 : // AUTHOR Linda K. Lawrie
206 : // DATE WRITTEN September 1997
207 :
208 : // PURPOSE OF THIS FUNCTION:
209 : // This function looks up a string in a similar list of
210 : // items and returns the index of the item in the list, if
211 : // found. This routine is not case insensitive and doesn't need
212 : // for most inputs -- they are automatically turned to UPPERCASE.
213 : // If you need case insensitivity use FindItem.
214 :
215 130348 : for (int Count = 1; Count <= NumItems; ++Count) {
216 125622 : if (String == ListOfItems(Count)) {
217 5480 : return Count;
218 : }
219 : }
220 4726 : return 0; // Not found
221 : }
222 :
223 6 : int FindItemInSortedList(std::string_view const String, Array1S_string const ListOfItems, int const NumItems)
224 : {
225 :
226 : // FUNCTION INFORMATION:
227 : // AUTHOR Linda K. Lawrie
228 : // DATE WRITTEN September 1997
229 :
230 : // PURPOSE OF THIS FUNCTION:
231 : // This function looks up a string in a similar list of
232 : // items and returns the index of the item in the list, if
233 : // found. This routine is case insensitive.
234 :
235 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
236 6 : int Probe = 0;
237 6 : int LBnd = 0;
238 6 : int UBnd = NumItems + 1;
239 6 : bool Found = false;
240 15 : while ((!Found) || (Probe != 0)) {
241 15 : Probe = (UBnd - LBnd) / 2;
242 15 : if (Probe == 0) {
243 0 : break;
244 : }
245 15 : Probe += LBnd;
246 15 : if (equali(String, ListOfItems(Probe))) {
247 6 : Found = true;
248 6 : break;
249 9 : } else if (lessthani(String, ListOfItems(Probe))) {
250 5 : UBnd = Probe;
251 : } else {
252 4 : LBnd = Probe;
253 : }
254 : }
255 6 : return Probe;
256 : }
257 :
258 486 : int FindItem(std::string_view const String, Array1D_string const &ListOfItems, int const NumItems)
259 : {
260 :
261 : // FUNCTION INFORMATION:
262 : // AUTHOR Linda K. Lawrie
263 : // DATE WRITTEN April 1999
264 :
265 : // PURPOSE OF THIS FUNCTION:
266 : // This function looks up a string in a similar list of
267 : // items and returns the index of the item in the list, if
268 : // found. This routine is case insensitive.
269 :
270 486 : int FindItem = Util::FindItemInList(String, ListOfItems, NumItems);
271 486 : if (FindItem != 0) {
272 9 : return FindItem;
273 : }
274 :
275 2315 : for (int Count = 1; Count <= NumItems; ++Count) {
276 2315 : if (equali(String, ListOfItems(Count))) {
277 477 : return Count;
278 : }
279 : }
280 0 : return 0; // Not found
281 : }
282 :
283 0 : int FindItem(std::string_view const String, Array1S_string const ListOfItems, int const NumItems)
284 : {
285 :
286 : // FUNCTION INFORMATION:
287 : // AUTHOR Linda K. Lawrie
288 : // DATE WRITTEN April 1999
289 :
290 : // PURPOSE OF THIS FUNCTION:
291 : // This function looks up a string in a similar list of
292 : // items and returns the index of the item in the list, if
293 : // found. This routine is case insensitive.
294 :
295 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
296 :
297 0 : int FindItem = Util::FindItemInList(String, ListOfItems, NumItems);
298 0 : if (FindItem != 0) {
299 0 : return FindItem;
300 : }
301 :
302 0 : for (int Count = 1; Count <= NumItems; ++Count) {
303 0 : if (equali(String, ListOfItems(Count))) {
304 0 : return Count;
305 : }
306 : }
307 0 : return 0; // Not found
308 : }
309 :
310 0 : void VerifyName(EnergyPlusData &state,
311 : std::string const &NameToVerify,
312 : Array1D_string const &NamesList,
313 : int const NumOfNames,
314 : bool &ErrorFound,
315 : bool &IsBlank,
316 : std::string const &StringToDisplay)
317 : {
318 :
319 : // SUBROUTINE INFORMATION:
320 : // AUTHOR Linda Lawrie
321 : // DATE WRITTEN February 2000
322 :
323 : // PURPOSE OF THIS SUBROUTINE:
324 : // This subroutine verifys that a new name can be added to the
325 : // list of names for this item (i.e., that there isn't one of that
326 : // name already and that this name is not blank).
327 :
328 0 : ErrorFound = false;
329 0 : if (NumOfNames > 0) {
330 0 : int Found = FindItem(NameToVerify, NamesList, NumOfNames);
331 0 : if (Found != 0) {
332 0 : ShowSevereError(state, format("{}, duplicate name={}", StringToDisplay, NameToVerify));
333 0 : ErrorFound = true;
334 : }
335 : }
336 :
337 0 : if (NameToVerify.empty()) {
338 0 : ShowSevereError(state, format("{}, cannot be blank", StringToDisplay));
339 0 : ErrorFound = true;
340 0 : IsBlank = true;
341 : } else {
342 0 : IsBlank = false;
343 : }
344 0 : }
345 :
346 0 : void VerifyName(EnergyPlusData &state,
347 : std::string const &NameToVerify,
348 : Array1S_string const NamesList,
349 : int const NumOfNames,
350 : bool &ErrorFound,
351 : bool &IsBlank,
352 : std::string const &StringToDisplay)
353 : {
354 :
355 : // SUBROUTINE INFORMATION:
356 : // AUTHOR Linda Lawrie
357 : // DATE WRITTEN February 2000
358 :
359 : // PURPOSE OF THIS SUBROUTINE:
360 : // This subroutine verifys that a new name can be added to the
361 : // list of names for this item (i.e., that there isn't one of that
362 : // name already and that this name is not blank).
363 :
364 0 : ErrorFound = false;
365 0 : if (NumOfNames > 0) {
366 0 : int Found = FindItem(NameToVerify, NamesList, NumOfNames);
367 0 : if (Found != 0) {
368 0 : ShowSevereError(state, format("{}, duplicate name={}", StringToDisplay, NameToVerify));
369 0 : ErrorFound = true;
370 : }
371 : }
372 :
373 0 : if (NameToVerify.empty()) {
374 0 : ShowSevereError(state, format("{}, cannot be blank", StringToDisplay));
375 0 : ErrorFound = true;
376 0 : IsBlank = true;
377 : } else {
378 0 : IsBlank = false;
379 : }
380 0 : }
381 :
382 2442 : bool IsNameEmpty(EnergyPlusData &state, std::string &NameToVerify, std::string_view StringToDisplay, bool &ErrorFound)
383 : {
384 2442 : if (NameToVerify.empty()) {
385 0 : ShowSevereError(state, format("{} Name, cannot be blank", StringToDisplay));
386 0 : ErrorFound = true;
387 0 : NameToVerify = "xxxxx";
388 0 : return true;
389 : }
390 2442 : return false;
391 : }
392 :
393 0 : size_t case_insensitive_hasher::operator()(std::string_view const key) const noexcept
394 : {
395 0 : std::string keyCopy = makeUPPER(key);
396 0 : return std::hash<std::string>()(keyCopy);
397 0 : }
398 :
399 203668 : bool case_insensitive_comparator::operator()(std::string_view const a, std::string_view const b) const noexcept
400 : {
401 203668 : return lessthani(a, b); // SameString(a, b);
402 : }
403 :
404 60 : void appendPerfLog(EnergyPlusData &state, std::string const &colHeader, std::string const &colValue, bool finalColumn)
405 : // Add column to the performance log file (comma separated) which is appended to existing log.
406 : // The finalColumn (an optional argument) being true triggers the actual file to be written or appended.
407 : // J.Glazer February 2020
408 : {
409 : // the following was added for unit testing to clear the static strings
410 60 : if (colHeader == "RESET" && colValue == "RESET") {
411 3 : state.dataUtilityRoutines->appendPerfLog_headerRow = "";
412 3 : state.dataUtilityRoutines->appendPerfLog_valuesRow = "";
413 3 : return;
414 : }
415 :
416 : // accumulate the row until ready to be written to the file.
417 57 : state.dataUtilityRoutines->appendPerfLog_headerRow = state.dataUtilityRoutines->appendPerfLog_headerRow + colHeader + ",";
418 57 : state.dataUtilityRoutines->appendPerfLog_valuesRow = state.dataUtilityRoutines->appendPerfLog_valuesRow + colValue + ",";
419 :
420 57 : if (finalColumn) {
421 3 : std::fstream fsPerfLog;
422 3 : if (!FileSystem::fileExists(state.dataStrGlobals->outputPerfLogFilePath)) {
423 2 : if (state.files.outputControl.perflog) {
424 2 : fsPerfLog.open(state.dataStrGlobals->outputPerfLogFilePath, std::fstream::out); // open file normally
425 2 : if (!fsPerfLog) {
426 0 : ShowFatalError(
427 : state,
428 0 : format("appendPerfLog: Could not open file \"{}\" for output (write).", state.dataStrGlobals->outputPerfLogFilePath));
429 : }
430 2 : fsPerfLog << state.dataUtilityRoutines->appendPerfLog_headerRow << std::endl;
431 2 : fsPerfLog << state.dataUtilityRoutines->appendPerfLog_valuesRow << std::endl;
432 : }
433 : } else {
434 1 : if (state.files.outputControl.perflog) {
435 1 : fsPerfLog.open(state.dataStrGlobals->outputPerfLogFilePath, std::fstream::app); // append to already existing file
436 1 : if (!fsPerfLog) {
437 0 : ShowFatalError(
438 : state,
439 0 : format("appendPerfLog: Could not open file \"{}\" for output (append).", state.dataStrGlobals->outputPerfLogFilePath));
440 : }
441 1 : fsPerfLog << state.dataUtilityRoutines->appendPerfLog_valuesRow << std::endl;
442 : }
443 : }
444 3 : fsPerfLog.close();
445 3 : }
446 : }
447 : } // namespace Util
448 :
449 2 : int AbortEnergyPlus(EnergyPlusData &state)
450 : {
451 :
452 : // SUBROUTINE INFORMATION:
453 : // AUTHOR Linda K. Lawrie
454 : // DATE WRITTEN December 1997
455 :
456 : // PURPOSE OF THIS SUBROUTINE:
457 : // This subroutine causes the program to halt due to a fatal error.
458 :
459 : // METHODOLOGY EMPLOYED:
460 : // Puts a message on output files. Closes files. Stops the program.
461 :
462 : // SUBROUTINE PARAMETER DEFINITIONS:
463 2 : std::string NumWarnings;
464 2 : std::string NumSevere;
465 2 : std::string NumWarningsDuringWarmup;
466 2 : std::string NumSevereDuringWarmup;
467 2 : std::string NumWarningsDuringSizing;
468 2 : std::string NumSevereDuringSizing;
469 :
470 2 : if (state.dataSQLiteProcedures->sqlite) {
471 0 : state.dataSQLiteProcedures->sqlite->updateSQLiteSimulationRecord(true, false);
472 : }
473 :
474 2 : state.dataErrTracking->AbortProcessing = true;
475 2 : if (state.dataErrTracking->AskForConnectionsReport) {
476 0 : state.dataErrTracking->AskForConnectionsReport = false; // Set false here in case any further fatal errors in below processing...
477 :
478 0 : ShowMessage(state, "Fatal error -- final processing. More error messages may appear.");
479 0 : NodeInputManager::SetupNodeVarsForReporting(state);
480 :
481 0 : bool ErrFound = false;
482 0 : bool TerminalError = false;
483 0 : BranchInputManager::TestBranchIntegrity(state, ErrFound);
484 0 : if (ErrFound) {
485 0 : TerminalError = true;
486 : }
487 0 : TestAirPathIntegrity(state, ErrFound);
488 0 : if (ErrFound) {
489 0 : TerminalError = true;
490 : }
491 0 : NodeInputManager::CheckMarkedNodes(state, ErrFound);
492 0 : if (ErrFound) {
493 0 : TerminalError = true;
494 : }
495 0 : BranchNodeConnections::CheckNodeConnections(state, ErrFound);
496 0 : if (ErrFound) {
497 0 : TerminalError = true;
498 : }
499 0 : BranchNodeConnections::TestCompSetInletOutletNodes(state, ErrFound);
500 0 : if (ErrFound) {
501 0 : TerminalError = true;
502 : }
503 :
504 0 : if (!TerminalError) {
505 0 : SystemReports::ReportAirLoopConnections(state);
506 0 : SimulationManager::ReportLoopConnections(state);
507 : }
508 :
509 2 : } else if (!state.dataErrTracking->ExitDuringSimulations) {
510 4 : ShowMessage(state, "Warning: Node connection errors not checked - most system input has not been read (see previous warning).");
511 6 : ShowMessage(state, "Fatal error -- final processing. Program exited before simulations began. See previous error messages.");
512 : }
513 :
514 2 : if (state.dataErrTracking->AskForSurfacesReport) {
515 0 : ReportSurfaces(state);
516 : }
517 :
518 2 : SolarShading::ReportSurfaceErrors(state);
519 2 : PlantManager::CheckPlantOnAbort(state);
520 2 : ShowRecurringErrors(state);
521 2 : SummarizeErrors(state);
522 2 : CloseMiscOpenFiles(state);
523 2 : NumWarnings = fmt::to_string(state.dataErrTracking->TotalWarningErrors);
524 2 : NumSevere = fmt::to_string(state.dataErrTracking->TotalSevereErrors);
525 2 : NumWarningsDuringWarmup = fmt::to_string(state.dataErrTracking->TotalWarningErrorsDuringWarmup);
526 2 : NumSevereDuringWarmup = fmt::to_string(state.dataErrTracking->TotalSevereErrorsDuringWarmup);
527 2 : NumWarningsDuringSizing = fmt::to_string(state.dataErrTracking->TotalWarningErrorsDuringSizing);
528 2 : NumSevereDuringSizing = fmt::to_string(state.dataErrTracking->TotalSevereErrorsDuringSizing);
529 :
530 : // catch up with timings if in middle
531 2 : state.dataSysVars->runtimeTimer.tock();
532 2 : const std::string Elapsed = state.dataSysVars->runtimeTimer.formatAsHourMinSecs();
533 :
534 2 : state.dataResultsFramework->resultsFramework->SimulationInformation.setRunTime(Elapsed);
535 2 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsWarmup(NumWarningsDuringWarmup, NumSevereDuringWarmup);
536 2 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsSizing(NumWarningsDuringSizing, NumSevereDuringSizing);
537 2 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsSummary(NumWarnings, NumSevere);
538 :
539 4 : ShowMessage(
540 : state,
541 4 : format("EnergyPlus Warmup Error Summary. During Warmup: {} Warning; {} Severe Errors.", NumWarningsDuringWarmup, NumSevereDuringWarmup));
542 4 : ShowMessage(
543 : state,
544 4 : format("EnergyPlus Sizing Error Summary. During Sizing: {} Warning; {} Severe Errors.", NumWarningsDuringSizing, NumSevereDuringSizing));
545 4 : ShowMessage(
546 4 : state, format("EnergyPlus Terminated--Fatal Error Detected. {} Warning; {} Severe Errors; Elapsed Time={}", NumWarnings, NumSevere, Elapsed));
547 2 : DisplayString(state, "EnergyPlus Run Time=" + Elapsed);
548 :
549 : {
550 2 : auto tempfl = state.files.endFile.try_open(state.files.outputControl.end);
551 :
552 2 : if (!tempfl.good()) {
553 0 : DisplayString(state, fmt::format("AbortEnergyPlus: Could not open file {} for output (write).", tempfl.filePath));
554 : }
555 2 : print(
556 : tempfl, "EnergyPlus Terminated--Fatal Error Detected. {} Warning; {} Severe Errors; Elapsed Time={}\n", NumWarnings, NumSevere, Elapsed);
557 2 : }
558 :
559 2 : state.dataResultsFramework->resultsFramework->writeOutputs(state);
560 :
561 2 : std::cerr << "Program terminated: " << "EnergyPlus Terminated--Error(s) Detected." << std::endl;
562 : // Close the socket used by ExternalInterface. This call also sends the flag "-1" to the ExternalInterface,
563 : // indicating that E+ terminated with an error.
564 2 : if (state.dataExternalInterface->NumExternalInterfaces > 0) {
565 0 : ExternalInterface::CloseSocket(state, -1);
566 : }
567 :
568 2 : if (state.dataGlobal->eplusRunningViaAPI) {
569 2 : state.files.flushAll();
570 : }
571 :
572 : // The audit file seems to be held open in some cases, make sure it is closed before leaving.
573 : // EnergyPlus can close through two paths: EndEnergyPlus and AbortEnergyPlus, so do the same thing there.
574 2 : state.files.audit.close();
575 :
576 2 : return EXIT_FAILURE;
577 2 : }
578 :
579 26 : void CloseMiscOpenFiles(EnergyPlusData &state)
580 : {
581 :
582 : // SUBROUTINE INFORMATION:
583 : // AUTHOR Linda K. Lawrie
584 : // DATE WRITTEN December 1997
585 :
586 : // PURPOSE OF THIS SUBROUTINE:
587 : // This subroutine scans potential unit numbers and closes
588 : // any that are still open.
589 :
590 : // METHODOLOGY EMPLOYED:
591 : // Use INQUIRE to determine if file is open.
592 :
593 26 : Dayltg::CloseReportIllumMaps(state);
594 26 : Dayltg::CloseDFSFile(state);
595 :
596 26 : if (state.dataReportFlag->DebugOutput || (state.files.debug.good() && state.files.debug.position() > 0)) {
597 0 : state.files.debug.close();
598 : } else {
599 26 : state.files.debug.del();
600 : }
601 26 : }
602 :
603 24 : int EndEnergyPlus(EnergyPlusData &state)
604 : {
605 :
606 : // SUBROUTINE INFORMATION:
607 : // AUTHOR Linda K. Lawrie
608 : // DATE WRITTEN December 1997
609 :
610 : // PURPOSE OF THIS SUBROUTINE:
611 : // This subroutine causes the program to terminate when complete (no errors).
612 :
613 : // METHODOLOGY EMPLOYED:
614 : // Puts a message on output files. Closes files. Stops the program.
615 :
616 24 : std::string NumWarnings;
617 24 : std::string NumSevere;
618 24 : std::string NumWarningsDuringWarmup;
619 24 : std::string NumSevereDuringWarmup;
620 24 : std::string NumWarningsDuringSizing;
621 24 : std::string NumSevereDuringSizing;
622 :
623 24 : if (state.dataSQLiteProcedures->sqlite) {
624 0 : state.dataSQLiteProcedures->sqlite->updateSQLiteSimulationRecord(true, true);
625 : }
626 :
627 24 : SolarShading::ReportSurfaceErrors(state);
628 24 : ShowRecurringErrors(state);
629 24 : SummarizeErrors(state);
630 24 : CloseMiscOpenFiles(state);
631 24 : NumWarnings = fmt::to_string(state.dataErrTracking->TotalWarningErrors);
632 24 : strip(NumWarnings);
633 24 : NumSevere = fmt::to_string(state.dataErrTracking->TotalSevereErrors);
634 24 : strip(NumSevere);
635 24 : NumWarningsDuringWarmup = fmt::to_string(state.dataErrTracking->TotalWarningErrorsDuringWarmup);
636 24 : strip(NumWarningsDuringWarmup);
637 24 : NumSevereDuringWarmup = fmt::to_string(state.dataErrTracking->TotalSevereErrorsDuringWarmup);
638 24 : strip(NumSevereDuringWarmup);
639 24 : NumWarningsDuringSizing = fmt::to_string(state.dataErrTracking->TotalWarningErrorsDuringSizing);
640 24 : strip(NumWarningsDuringSizing);
641 24 : NumSevereDuringSizing = fmt::to_string(state.dataErrTracking->TotalSevereErrorsDuringSizing);
642 24 : strip(NumSevereDuringSizing);
643 :
644 24 : state.dataSysVars->runtimeTimer.tock();
645 24 : if (state.dataGlobal->createPerfLog) {
646 0 : Util::appendPerfLog(state, "Run Time [seconds]", format("{:.2R}", state.dataSysVars->runtimeTimer.elapsedSeconds()));
647 : }
648 24 : const std::string Elapsed = state.dataSysVars->runtimeTimer.formatAsHourMinSecs();
649 24 : state.dataResultsFramework->resultsFramework->SimulationInformation.setRunTime(Elapsed);
650 24 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsWarmup(NumWarningsDuringWarmup, NumSevereDuringWarmup);
651 24 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsSizing(NumWarningsDuringSizing, NumSevereDuringSizing);
652 24 : state.dataResultsFramework->resultsFramework->SimulationInformation.setNumErrorsSummary(NumWarnings, NumSevere);
653 :
654 24 : if (state.dataGlobal->createPerfLog) {
655 0 : Util::appendPerfLog(state, "Run Time [string]", Elapsed);
656 0 : Util::appendPerfLog(state, "Number of Warnings", NumWarnings);
657 0 : Util::appendPerfLog(state, "Number of Severe", NumSevere, true); // last item so write the perfLog file
658 : }
659 48 : ShowMessage(
660 : state,
661 48 : format("EnergyPlus Warmup Error Summary. During Warmup: {} Warning; {} Severe Errors.", NumWarningsDuringWarmup, NumSevereDuringWarmup));
662 48 : ShowMessage(
663 : state,
664 48 : format("EnergyPlus Sizing Error Summary. During Sizing: {} Warning; {} Severe Errors.", NumWarningsDuringSizing, NumSevereDuringSizing));
665 24 : ShowMessage(state, format("EnergyPlus Completed Successfully-- {} Warning; {} Severe Errors; Elapsed Time={}", NumWarnings, NumSevere, Elapsed));
666 24 : DisplayString(state, "EnergyPlus Run Time=" + Elapsed);
667 :
668 : {
669 24 : auto tempfl = state.files.endFile.try_open(state.files.outputControl.end);
670 24 : if (!tempfl.good()) {
671 0 : DisplayString(state, fmt::format("EndEnergyPlus: Could not open file {} for output (write).", tempfl.filePath));
672 : }
673 24 : print(tempfl, "EnergyPlus Completed Successfully-- {} Warning; {} Severe Errors; Elapsed Time={}\n", NumWarnings, NumSevere, Elapsed);
674 24 : }
675 :
676 24 : state.dataResultsFramework->resultsFramework->writeOutputs(state);
677 :
678 24 : if (state.dataGlobal->printConsoleOutput) {
679 20 : std::cerr << "EnergyPlus Completed Successfully." << std::endl;
680 : }
681 : // Close the ExternalInterface socket. This call also sends the flag "1" to the ExternalInterface,
682 : // indicating that E+ finished its simulation
683 24 : if ((state.dataExternalInterface->NumExternalInterfaces > 0) && state.dataExternalInterface->haveExternalInterfaceBCVTB) {
684 0 : ExternalInterface::CloseSocket(state, 1);
685 : }
686 :
687 24 : if (state.dataGlobal->fProgressPtr) {
688 1 : state.dataGlobal->fProgressPtr(100);
689 : }
690 24 : if (state.dataGlobal->progressCallback) {
691 6 : state.dataGlobal->progressCallback(100);
692 : }
693 :
694 24 : if (state.dataGlobal->eplusRunningViaAPI) {
695 19 : state.files.flushAll();
696 : }
697 :
698 : // The audit file seems to be held open in some cases, make sure it is closed before leaving.
699 : // EnergyPlus can close through two paths: EndEnergyPlus and AbortEnergyPlus, so do the same thing there.
700 24 : state.files.audit.close();
701 :
702 24 : return EXIT_SUCCESS;
703 24 : }
704 :
705 0 : void ConvertCaseToUpper(std::string_view InputString, // Input string
706 : std::string &OutputString // Output string (in UpperCase)
707 : )
708 : {
709 :
710 : // SUBROUTINE INFORMATION:
711 : // AUTHOR Linda K. Lawrie
712 : // DATE WRITTEN September 1997
713 :
714 : // PURPOSE OF THIS SUBROUTINE:
715 : // Convert a string to upper case
716 :
717 : // METHODOLOGY EMPLOYED:
718 : // This routine is not dependant upon the ASCII
719 : // code. It works by storing the upper and lower case alphabet. It
720 : // scans the whole input string. If it finds a character in the lower
721 : // case alphabet, it makes an appropriate substitution.
722 :
723 : // Using/Aliasing
724 : static constexpr std::string_view UpperCase("ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝ");
725 : static constexpr std::string_view LowerCase("abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüý");
726 :
727 0 : OutputString = InputString;
728 :
729 0 : for (std::string::size_type A = 0; A < len(InputString); ++A) {
730 0 : std::string::size_type const B = index(LowerCase, InputString[A]);
731 0 : if (B != std::string::npos) {
732 0 : OutputString[A] = UpperCase[B];
733 : }
734 : }
735 0 : }
736 :
737 2 : void ConvertCaseToLower(std::string_view InputString, // Input string
738 : std::string &OutputString // Output string (in LowerCase)
739 : )
740 : {
741 :
742 : // SUBROUTINE INFORMATION:
743 : // AUTHOR Linda K. Lawrie
744 : // DATE WRITTEN September 1997
745 :
746 : // PURPOSE OF THIS SUBROUTINE:
747 : // Convert a string to lower case
748 :
749 : // METHODOLOGY EMPLOYED:
750 : // This routine is not dependant upon the ASCII
751 : // code. It works by storing the upper and lower case alphabet. It
752 : // scans the whole input string. If it finds a character in the lower
753 : // case alphabet, it makes an appropriate substitution.
754 :
755 : // Using/Aliasing
756 : static constexpr std::string_view UpperCase("ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝ");
757 : static constexpr std::string_view LowerCase("abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüý");
758 :
759 2 : OutputString = InputString;
760 :
761 12 : for (std::string::size_type A = 0; A < len(InputString); ++A) {
762 10 : std::string::size_type const B = index(UpperCase, InputString[A]);
763 10 : if (B != std::string::npos) {
764 10 : OutputString[A] = LowerCase[B];
765 : }
766 : }
767 2 : }
768 :
769 240 : std::string::size_type FindNonSpace(std::string const &String) // String to be scanned
770 : {
771 :
772 : // FUNCTION INFORMATION:
773 : // AUTHOR Linda K. Lawrie
774 : // DATE WRITTEN September 1997
775 :
776 : // PURPOSE OF THIS FUNCTION:
777 : // This function finds the first non-space character in the passed string
778 : // and returns that position as the result to the calling program.
779 :
780 : // METHODOLOGY EMPLOYED:
781 : // Scan string for character not equal to blank.
782 :
783 240 : return String.find_first_not_of(' ');
784 : }
785 :
786 130 : bool env_var_on(std::string const &env_var_str)
787 : {
788 :
789 : // FUNCTION INFORMATION:
790 : // AUTHOR Stuart G. Mentzer
791 : // DATE WRITTEN April 2014
792 :
793 : // PURPOSE OF THIS FUNCTION:
794 : // Test if a boolean environment variable value is "on" (has value starting with Y or T)
795 :
796 130 : return ((!env_var_str.empty()) && is_any_of(env_var_str[0], "YyTt"));
797 : }
798 :
799 0 : void emitErrorMessage(EnergyPlusData &state, [[maybe_unused]] ErrorMessageCategory category, std::string const &msg, bool shouldFatal)
800 : {
801 0 : if (!shouldFatal) {
802 0 : ShowSevereError(state, msg);
803 : } else { // should fatal
804 0 : ShowFatalError(state, msg);
805 : }
806 0 : }
807 0 : void emitErrorMessages(EnergyPlusData &state,
808 : [[maybe_unused]] ErrorMessageCategory category,
809 : std::initializer_list<std::string> const &msgs,
810 : bool const shouldFatal,
811 : int const zeroBasedTimeStampIndex)
812 : {
813 0 : for (auto msg = msgs.begin(); msg != msgs.end(); ++msg) {
814 0 : if (msg - msgs.begin() == zeroBasedTimeStampIndex) {
815 0 : ShowContinueErrorTimeStamp(state, *msg);
816 0 : continue;
817 : }
818 0 : if (msg == msgs.begin()) {
819 0 : ShowSevereError(state, *msg);
820 0 : } else if (std::next(msg) == msgs.end() && shouldFatal) {
821 0 : ShowFatalError(state, *msg);
822 : } else { // should be an intermediate message, or a final one where there is no fatal
823 0 : ShowContinueError(state, *msg);
824 : }
825 : }
826 0 : }
827 0 : void emitWarningMessage(EnergyPlusData &state, [[maybe_unused]] ErrorMessageCategory category, std::string const &msg, bool const countAsError)
828 : {
829 0 : if (countAsError) { // ideally this path goes away and we just have distinct warnings and errors
830 0 : ShowWarningError(state, msg);
831 : } else {
832 0 : ShowWarningMessage(state, msg);
833 : }
834 0 : }
835 0 : void emitWarningMessages(EnergyPlusData &state,
836 : [[maybe_unused]] ErrorMessageCategory category,
837 : std::initializer_list<std::string> const &msgs,
838 : bool const countAsError)
839 : {
840 0 : for (auto msg = msgs.begin(); msg != msgs.end(); ++msg) {
841 0 : if (msg == msgs.begin()) {
842 0 : if (countAsError) { // ideally this path goes away and we just have distinct warnings and errors
843 0 : ShowWarningError(state, *msg);
844 : } else {
845 0 : ShowWarningMessage(state, *msg);
846 : }
847 : } else {
848 0 : ShowContinueError(state, *msg);
849 : }
850 : }
851 0 : }
852 :
853 120 : void ShowFatalError(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
854 : {
855 :
856 : // SUBROUTINE INFORMATION:
857 : // AUTHOR Linda K. Lawrie
858 : // DATE WRITTEN September 1997
859 : // MODIFIED Kyle Benne August 2010 Added sqlite output
860 :
861 : // PURPOSE OF THIS SUBROUTINE:
862 : // This subroutine puts ErrorMessage with a Fatal designation on
863 : // designated output files. Then, the program is aborted.
864 :
865 : // METHODOLOGY EMPLOYED:
866 : // Calls ShowErrorMessage utility routine.
867 : // Calls AbortEnergyPlus
868 :
869 : using namespace DataErrorTracking;
870 :
871 120 : ShowErrorMessage(state, format(" ** Fatal ** {}", ErrorMessage), OutUnit1, OutUnit2);
872 120 : DisplayString(state, "**FATAL:" + ErrorMessage);
873 :
874 120 : ShowErrorMessage(state, " ...Summary of Errors that led to program termination:", OutUnit1, OutUnit2);
875 120 : ShowErrorMessage(state, format(" ..... Reference severe error count={}", state.dataErrTracking->TotalSevereErrors), OutUnit1, OutUnit2);
876 120 : ShowErrorMessage(state, format(" ..... Last severe error={}", state.dataErrTracking->LastSevereError), OutUnit1, OutUnit2);
877 120 : if (state.dataSQLiteProcedures->sqlite) {
878 0 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 2, ErrorMessage, 1);
879 0 : if (state.dataSQLiteProcedures->sqlite->sqliteWithinTransaction()) {
880 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit();
881 : }
882 : }
883 120 : if (state.dataGlobal->errorCallback) {
884 0 : state.dataGlobal->errorCallback(Error::Fatal, ErrorMessage);
885 : }
886 120 : throw FatalError(ErrorMessage);
887 : }
888 :
889 668 : void ShowSevereError(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
890 : {
891 :
892 : // SUBROUTINE INFORMATION:
893 : // AUTHOR Linda K. Lawrie
894 : // DATE WRITTEN September 1997
895 :
896 : // PURPOSE OF THIS SUBROUTINE:
897 : // This subroutine puts ErrorMessage with a Severe designation on
898 : // designated output files.
899 :
900 : // METHODOLOGY EMPLOYED:
901 : // Calls ShowErrorMessage utility routine.
902 :
903 14028 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
904 13360 : if (has(ErrorMessage, DataErrorTracking::MessageSearch[Loop])) {
905 27 : ++state.dataErrTracking->MatchCounts(Loop);
906 : }
907 : }
908 :
909 668 : ++state.dataErrTracking->TotalSevereErrors;
910 673 : if (state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
911 5 : !state.dataErrTracking->AbortProcessing) {
912 5 : ++state.dataErrTracking->TotalSevereErrorsDuringWarmup;
913 : }
914 668 : if (state.dataGlobal->DoingSizing) {
915 2 : ++state.dataErrTracking->TotalSevereErrorsDuringSizing;
916 : }
917 668 : ShowErrorMessage(state, format(" ** Severe ** {}", ErrorMessage), OutUnit1, OutUnit2);
918 668 : state.dataErrTracking->LastSevereError = ErrorMessage;
919 :
920 : // Could set a variable here that gets checked at some point?
921 :
922 668 : if (state.dataSQLiteProcedures->sqlite) {
923 34 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 1, ErrorMessage, 1);
924 : }
925 668 : if (state.dataGlobal->errorCallback) {
926 0 : state.dataGlobal->errorCallback(Error::Severe, ErrorMessage);
927 : }
928 668 : }
929 :
930 19 : void ShowSevereMessage(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
931 : {
932 :
933 : // SUBROUTINE INFORMATION:
934 : // AUTHOR Linda K. Lawrie
935 : // DATE WRITTEN September 2009
936 :
937 : // PURPOSE OF THIS SUBROUTINE:
938 : // This subroutine puts ErrorMessage with a Severe designation on designated output files.
939 : // But does not bump the error count so can be used in conjunction with recurring error calls.
940 :
941 : // METHODOLOGY EMPLOYED:
942 : // Calls ShowErrorMessage utility routine.
943 :
944 399 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
945 380 : if (has(ErrorMessage, DataErrorTracking::MessageSearch[Loop])) {
946 4 : ++state.dataErrTracking->MatchCounts(Loop);
947 : }
948 : }
949 :
950 19 : ShowErrorMessage(state, format(" ** Severe ** {}", ErrorMessage), OutUnit1, OutUnit2);
951 19 : state.dataErrTracking->LastSevereError = ErrorMessage;
952 :
953 : // Could set a variable here that gets checked at some point?
954 :
955 19 : if (state.dataSQLiteProcedures->sqlite) {
956 0 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 1, ErrorMessage, 0);
957 : }
958 19 : if (state.dataGlobal->errorCallback) {
959 0 : state.dataGlobal->errorCallback(Error::Severe, ErrorMessage);
960 : }
961 19 : }
962 :
963 5217 : void ShowContinueError(EnergyPlusData &state, std::string const &Message, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
964 : {
965 :
966 : // SUBROUTINE INFORMATION:
967 : // AUTHOR Linda K. Lawrie
968 : // DATE WRITTEN October 2001
969 :
970 : // PURPOSE OF THIS SUBROUTINE:
971 : // This subroutine displays a 'continued error' message on designated output files.
972 :
973 : // METHODOLOGY EMPLOYED:
974 : // Calls ShowErrorMessage utility routine.
975 :
976 5217 : ShowErrorMessage(state, format(" ** ~~~ ** {}", Message), OutUnit1, OutUnit2);
977 5217 : if (state.dataSQLiteProcedures->sqlite) {
978 81 : state.dataSQLiteProcedures->sqlite->updateSQLiteErrorRecord(Message);
979 : }
980 5217 : if (state.dataGlobal->errorCallback) {
981 10 : state.dataGlobal->errorCallback(Error::Continue, Message);
982 : }
983 5217 : }
984 :
985 137 : void ShowContinueErrorTimeStamp(EnergyPlusData &state, std::string const &Message, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
986 : {
987 :
988 : // SUBROUTINE INFORMATION:
989 : // AUTHOR Linda K. Lawrie
990 : // DATE WRITTEN February 2004
991 :
992 : // PURPOSE OF THIS SUBROUTINE:
993 : // This subroutine displays a 'continued error' timestamp message on designated output files.
994 :
995 : // METHODOLOGY EMPLOYED:
996 : // Calls ShowErrorMessage utility routine.
997 :
998 137 : std::string cEnvHeader;
999 :
1000 137 : if (state.dataGlobal->WarmupFlag) {
1001 5 : if (!state.dataGlobal->DoingSizing) {
1002 5 : cEnvHeader = " During Warmup, Environment=";
1003 : } else {
1004 0 : cEnvHeader = " During Warmup & Sizing, Environment=";
1005 : }
1006 : } else {
1007 132 : if (!state.dataGlobal->DoingSizing) {
1008 130 : cEnvHeader = " Environment=";
1009 : } else {
1010 2 : cEnvHeader = " During Sizing, Environment=";
1011 : }
1012 : }
1013 :
1014 137 : if (len(Message) < 50) {
1015 126 : const std::string m = format("{}{}{}, at Simulation time={} {}",
1016 : Message,
1017 : cEnvHeader,
1018 126 : state.dataEnvrn->EnvironmentName,
1019 126 : state.dataEnvrn->CurMnDy,
1020 252 : General::CreateSysTimeIntervalString(state));
1021 :
1022 126 : ShowErrorMessage(state, format(" ** ~~~ ** {}", m), OutUnit1, OutUnit2);
1023 126 : if (state.dataSQLiteProcedures->sqlite) {
1024 4 : state.dataSQLiteProcedures->sqlite->updateSQLiteErrorRecord(m);
1025 : }
1026 126 : if (state.dataGlobal->errorCallback) {
1027 2 : state.dataGlobal->errorCallback(Error::Continue, m);
1028 : }
1029 126 : } else {
1030 11 : const std::string postfix = format("{}{}, at Simulation time={} {}",
1031 : cEnvHeader,
1032 11 : state.dataEnvrn->EnvironmentName,
1033 11 : state.dataEnvrn->CurMnDy,
1034 22 : General::CreateSysTimeIntervalString(state));
1035 11 : ShowErrorMessage(state, format(" ** ~~~ ** {}", Message));
1036 11 : ShowErrorMessage(state, format(" ** ~~~ ** {}", postfix), OutUnit1, OutUnit2);
1037 11 : if (state.dataSQLiteProcedures->sqlite) {
1038 0 : state.dataSQLiteProcedures->sqlite->updateSQLiteErrorRecord(Message);
1039 : }
1040 11 : if (state.dataGlobal->errorCallback) {
1041 0 : state.dataGlobal->errorCallback(Error::Continue, Message);
1042 0 : state.dataGlobal->errorCallback(Error::Continue, postfix);
1043 : }
1044 11 : }
1045 137 : }
1046 :
1047 2994 : void ShowMessage(EnergyPlusData &state, std::string const &Message, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
1048 : {
1049 :
1050 : // SUBROUTINE INFORMATION:
1051 : // AUTHOR Linda K. Lawrie
1052 : // DATE WRITTEN September 1997
1053 :
1054 : // PURPOSE OF THIS SUBROUTINE:
1055 : // This subroutine displays a simple message on designated output files.
1056 :
1057 : // METHODOLOGY EMPLOYED:
1058 : // Calls ShowErrorMessage utility routine.
1059 :
1060 2994 : if (Message.empty()) {
1061 4 : ShowErrorMessage(state, " *************", OutUnit1, OutUnit2);
1062 : } else {
1063 2992 : ShowErrorMessage(state, format(" ************* {}", Message), OutUnit1, OutUnit2);
1064 2992 : if (state.dataSQLiteProcedures->sqlite) {
1065 50 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, -1, Message, 0);
1066 : }
1067 2992 : if (state.dataGlobal->errorCallback) {
1068 12 : state.dataGlobal->errorCallback(Error::Info, Message);
1069 : }
1070 : }
1071 2994 : }
1072 :
1073 2199 : void ShowWarningError(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
1074 : {
1075 :
1076 : // SUBROUTINE INFORMATION:
1077 : // AUTHOR Linda K. Lawrie
1078 : // DATE WRITTEN September 1997
1079 :
1080 : // PURPOSE OF THIS SUBROUTINE:
1081 : // This subroutine puts ErrorMessage with a Warning designation on
1082 : // designated output files.
1083 :
1084 : // METHODOLOGY EMPLOYED:
1085 : // Calls ShowErrorMessage utility routine.
1086 :
1087 46179 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1088 43980 : if (has(ErrorMessage, DataErrorTracking::MessageSearch[Loop])) {
1089 62 : ++state.dataErrTracking->MatchCounts(Loop);
1090 : }
1091 : }
1092 :
1093 2199 : ++state.dataErrTracking->TotalWarningErrors;
1094 2216 : if (state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
1095 17 : !state.dataErrTracking->AbortProcessing) {
1096 17 : ++state.dataErrTracking->TotalWarningErrorsDuringWarmup;
1097 : }
1098 2199 : if (state.dataGlobal->DoingSizing) {
1099 166 : ++state.dataErrTracking->TotalWarningErrorsDuringSizing;
1100 : }
1101 2199 : ShowErrorMessage(state, format(" ** Warning ** {}", ErrorMessage), OutUnit1, OutUnit2);
1102 :
1103 2199 : if (state.dataSQLiteProcedures->sqlite) {
1104 25 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 0, ErrorMessage, 1);
1105 : }
1106 2199 : if (state.dataGlobal->errorCallback) {
1107 3 : state.dataGlobal->errorCallback(Error::Warning, ErrorMessage);
1108 : }
1109 2199 : }
1110 :
1111 121 : void ShowWarningMessage(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
1112 : {
1113 :
1114 : // SUBROUTINE INFORMATION:
1115 : // AUTHOR Linda K. Lawrie
1116 : // DATE WRITTEN September 2009
1117 :
1118 : // PURPOSE OF THIS SUBROUTINE:
1119 : // This subroutine puts ErrorMessage with a Warning designation on
1120 : // designated output files.
1121 : // But does not bump the error count so can be used in conjunction with recurring
1122 : // error calls.
1123 :
1124 : // METHODOLOGY EMPLOYED:
1125 : // Calls ShowErrorMessage utility routine.
1126 :
1127 2541 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1128 2420 : if (has(ErrorMessage, DataErrorTracking::MessageSearch[Loop])) {
1129 0 : ++state.dataErrTracking->MatchCounts(Loop);
1130 : }
1131 : }
1132 :
1133 121 : ShowErrorMessage(state, format(" ** Warning ** {}", ErrorMessage), OutUnit1, OutUnit2);
1134 121 : if (state.dataSQLiteProcedures->sqlite) {
1135 7 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 0, ErrorMessage, 0);
1136 : }
1137 121 : if (state.dataGlobal->errorCallback) {
1138 2 : state.dataGlobal->errorCallback(Error::Warning, ErrorMessage);
1139 : }
1140 121 : }
1141 :
1142 31 : void ShowRecurringSevereErrorAtEnd(EnergyPlusData &state,
1143 : std::string const &Message, // Message automatically written to "error file" at end of simulation
1144 : int &MsgIndex, // Recurring message index, if zero, next available index is assigned
1145 : ObjexxFCL::Optional<Real64 const> ReportMaxOf, // Track and report the max of the values passed to this argument
1146 : ObjexxFCL::Optional<Real64 const> ReportMinOf, // Track and report the min of the values passed to this argument
1147 : ObjexxFCL::Optional<Real64 const> ReportSumOf, // Track and report the sum of the values passed to this argument
1148 : std::string const &ReportMaxUnits, // optional char string (<=15 length) of units for max value
1149 : std::string const &ReportMinUnits, // optional char string (<=15 length) of units for min value
1150 : std::string const &ReportSumUnits // optional char string (<=15 length) of units for sum value
1151 : )
1152 : {
1153 :
1154 : // SUBROUTINE INFORMATION:
1155 : // AUTHOR Michael J. Witte
1156 : // DATE WRITTEN August 2004
1157 :
1158 : // PURPOSE OF THIS SUBROUTINE:
1159 : // This subroutine stores a recurring ErrorMessage with a Severe designation
1160 : // for output at the end of the simulation with automatic tracking of number
1161 : // of occurrences and optional tracking of associated min, max, and sum values
1162 :
1163 : // METHODOLOGY EMPLOYED:
1164 : // Calls StoreRecurringErrorMessage utility routine.
1165 :
1166 : // INTERFACE BLOCK SPECIFICATIONS
1167 : // Use for recurring "severe" error messages shown once at end of simulation
1168 : // with count of occurrences and optional max, min, sum
1169 :
1170 633 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1171 606 : if (has(Message, DataErrorTracking::MessageSearch[Loop])) {
1172 4 : ++state.dataErrTracking->MatchCounts(Loop);
1173 4 : break;
1174 : }
1175 : }
1176 31 : bool bNewMessageFound = true;
1177 48 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1178 38 : if (Util::SameString(state.dataErrTracking->RecurringErrors(Loop).Message, " ** Severe ** " + Message)) {
1179 21 : bNewMessageFound = false;
1180 21 : MsgIndex = Loop;
1181 21 : break;
1182 : }
1183 : }
1184 31 : if (bNewMessageFound) {
1185 10 : MsgIndex = 0;
1186 : }
1187 :
1188 31 : ++state.dataErrTracking->TotalSevereErrors;
1189 93 : StoreRecurringErrorMessage(
1190 62 : state, " ** Severe ** " + Message, MsgIndex, ReportMaxOf, ReportMinOf, ReportSumOf, ReportMaxUnits, ReportMinUnits, ReportSumUnits);
1191 31 : }
1192 :
1193 16 : void ShowRecurringSevereErrorAtEnd(EnergyPlusData &state,
1194 : std::string const &Message, // Message automatically written to "error file" at end of simulation
1195 : int &MsgIndex, // Recurring message index, if zero, next available index is assigned
1196 : Real64 const val,
1197 : std::string const &units // optional char string (<=15 length) of units for sum value
1198 : )
1199 : {
1200 :
1201 : // SUBROUTINE INFORMATION:
1202 : // AUTHOR Michael J. Witte
1203 : // DATE WRITTEN August 2004
1204 :
1205 : // PURPOSE OF THIS SUBROUTINE:
1206 : // This subroutine stores a recurring ErrorMessage with a Severe designation
1207 : // for output at the end of the simulation with automatic tracking of number
1208 : // of occurrences and optional tracking of associated min, max, and sum values
1209 :
1210 : // METHODOLOGY EMPLOYED:
1211 : // Calls StoreRecurringErrorMessage utility routine.
1212 :
1213 : // INTERFACE BLOCK SPECIFICATIONS
1214 : // Use for recurring "severe" error messages shown once at end of simulation
1215 : // with count of occurrences and optional max, min, sum
1216 :
1217 336 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1218 320 : if (has(Message, DataErrorTracking::MessageSearch[Loop])) {
1219 0 : ++state.dataErrTracking->MatchCounts(Loop);
1220 0 : break;
1221 : }
1222 : }
1223 16 : bool bNewMessageFound = true;
1224 16 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1225 13 : if (Util::SameString(state.dataErrTracking->RecurringErrors(Loop).Message, " ** Severe ** " + Message)) {
1226 13 : bNewMessageFound = false;
1227 13 : MsgIndex = Loop;
1228 13 : break;
1229 : }
1230 : }
1231 16 : if (bNewMessageFound) {
1232 3 : MsgIndex = 0;
1233 : }
1234 :
1235 16 : ++state.dataErrTracking->TotalSevereErrors;
1236 16 : StoreRecurringErrorMessage(state, " ** Severe ** " + Message, MsgIndex, val, val, _, units, units, "");
1237 16 : }
1238 :
1239 13069 : void ShowRecurringWarningErrorAtEnd(EnergyPlusData &state,
1240 : std::string const &Message, // Message automatically written to "error file" at end of simulation
1241 : int &MsgIndex, // Recurring message index, if zero, next available index is assigned
1242 : ObjexxFCL::Optional<Real64 const> ReportMaxOf, // Track and report the max of the values passed to this argument
1243 : ObjexxFCL::Optional<Real64 const> ReportMinOf, // Track and report the min of the values passed to this argument
1244 : ObjexxFCL::Optional<Real64 const> ReportSumOf, // Track and report the sum of the values passed to this argument
1245 : std::string const &ReportMaxUnits, // optional char string (<=15 length) of units for max value
1246 : std::string const &ReportMinUnits, // optional char string (<=15 length) of units for min value
1247 : std::string const &ReportSumUnits // optional char string (<=15 length) of units for sum value
1248 : )
1249 : {
1250 :
1251 : // SUBROUTINE INFORMATION:
1252 : // AUTHOR Michael J. Witte
1253 : // DATE WRITTEN August 2004
1254 :
1255 : // PURPOSE OF THIS SUBROUTINE:
1256 : // This subroutine stores a recurring ErrorMessage with a Warning designation
1257 : // for output at the end of the simulation with automatic tracking of number
1258 : // of occurrences and optional tracking of associated min, max, and sum values
1259 :
1260 : // METHODOLOGY EMPLOYED:
1261 : // Calls StoreRecurringErrorMessage utility routine.
1262 :
1263 : // INTERFACE BLOCK SPECIFICATIONS
1264 : // Use for recurring "warning" error messages shown once at end of simulation
1265 : // with count of occurrences and optional max, min, sum
1266 :
1267 274449 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1268 261380 : if (has(Message, DataErrorTracking::MessageSearch[Loop])) {
1269 0 : ++state.dataErrTracking->MatchCounts(Loop);
1270 0 : break;
1271 : }
1272 : }
1273 13069 : bool bNewMessageFound = true;
1274 15246 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1275 15137 : if (Util::SameString(state.dataErrTracking->RecurringErrors(Loop).Message, " ** Warning ** " + Message)) {
1276 12960 : bNewMessageFound = false;
1277 12960 : MsgIndex = Loop;
1278 12960 : break;
1279 : }
1280 : }
1281 13069 : if (bNewMessageFound) {
1282 109 : MsgIndex = 0;
1283 : }
1284 :
1285 13069 : ++state.dataErrTracking->TotalWarningErrors;
1286 39207 : StoreRecurringErrorMessage(
1287 26138 : state, " ** Warning ** " + Message, MsgIndex, ReportMaxOf, ReportMinOf, ReportSumOf, ReportMaxUnits, ReportMinUnits, ReportSumUnits);
1288 13069 : }
1289 :
1290 3444 : void ShowRecurringWarningErrorAtEnd(EnergyPlusData &state,
1291 : std::string const &Message, // Message automatically written to "error file" at end of simulation
1292 : int &MsgIndex, // Recurring message index, if zero, next available index is assigned
1293 : Real64 const val,
1294 : std::string const &units // optional char string (<=15 length) of units for sum value
1295 : )
1296 : {
1297 :
1298 : // SUBROUTINE INFORMATION:
1299 : // AUTHOR Michael J. Witte
1300 : // DATE WRITTEN August 2004
1301 :
1302 : // PURPOSE OF THIS SUBROUTINE:
1303 : // This subroutine stores a recurring ErrorMessage with a Warning designation
1304 : // for output at the end of the simulation with automatic tracking of number
1305 : // of occurrences and optional tracking of associated min, max, and sum values
1306 :
1307 : // METHODOLOGY EMPLOYED:
1308 : // Calls StoreRecurringErrorMessage utility routine.
1309 :
1310 : // INTERFACE BLOCK SPECIFICATIONS
1311 : // Use for recurring "warning" error messages shown once at end of simulation
1312 : // with count of occurrences and optional max, min, sum
1313 :
1314 72324 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1315 68880 : if (has(Message, DataErrorTracking::MessageSearch[Loop])) {
1316 0 : ++state.dataErrTracking->MatchCounts(Loop);
1317 0 : break;
1318 : }
1319 : }
1320 3444 : bool bNewMessageFound = true;
1321 9572 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1322 9565 : if (Util::SameString(state.dataErrTracking->RecurringErrors(Loop).Message, " ** Warning ** " + Message)) {
1323 3437 : bNewMessageFound = false;
1324 3437 : MsgIndex = Loop;
1325 3437 : break;
1326 : }
1327 : }
1328 3444 : if (bNewMessageFound) {
1329 7 : MsgIndex = 0;
1330 : }
1331 :
1332 3444 : ++state.dataErrTracking->TotalWarningErrors;
1333 3444 : StoreRecurringErrorMessage(state, " ** Warning ** " + Message, MsgIndex, val, val, _, units, units, "");
1334 3444 : }
1335 :
1336 1 : void ShowRecurringContinueErrorAtEnd(EnergyPlusData &state,
1337 : std::string const &Message, // Message automatically written to "error file" at end of simulation
1338 : int &MsgIndex, // Recurring message index, if zero, next available index is assigned
1339 : ObjexxFCL::Optional<Real64 const> ReportMaxOf, // Track and report the max of the values passed to this argument
1340 : ObjexxFCL::Optional<Real64 const> ReportMinOf, // Track and report the min of the values passed to this argument
1341 : ObjexxFCL::Optional<Real64 const> ReportSumOf, // Track and report the sum of the values passed to this argument
1342 : std::string const &ReportMaxUnits, // optional char string (<=15 length) of units for max value
1343 : std::string const &ReportMinUnits, // optional char string (<=15 length) of units for min value
1344 : std::string const &ReportSumUnits // optional char string (<=15 length) of units for sum value
1345 : )
1346 : {
1347 :
1348 : // SUBROUTINE INFORMATION:
1349 : // AUTHOR Michael J. Witte
1350 : // DATE WRITTEN August 2004
1351 :
1352 : // PURPOSE OF THIS SUBROUTINE:
1353 : // This subroutine stores a recurring ErrorMessage with a continue designation
1354 : // for output at the end of the simulation with automatic tracking of number
1355 : // of occurrences and optional tracking of associated min, max, and sum values
1356 :
1357 : // METHODOLOGY EMPLOYED:
1358 : // Calls StoreRecurringErrorMessage utility routine.
1359 :
1360 : // INTERFACE BLOCK SPECIFICATIONS
1361 : // Use for recurring "continue" error messages shown once at end of simulation
1362 : // with count of occurrences and optional max, min, sum
1363 :
1364 21 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1365 20 : if (has(Message, DataErrorTracking::MessageSearch[Loop])) {
1366 0 : ++state.dataErrTracking->MatchCounts(Loop);
1367 0 : break;
1368 : }
1369 : }
1370 1 : bool bNewMessageFound = true;
1371 3 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1372 2 : if (Util::SameString(state.dataErrTracking->RecurringErrors(Loop).Message, " ** ~~~ ** " + Message)) {
1373 0 : bNewMessageFound = false;
1374 0 : MsgIndex = Loop;
1375 0 : break;
1376 : }
1377 : }
1378 1 : if (bNewMessageFound) {
1379 1 : MsgIndex = 0;
1380 : }
1381 :
1382 3 : StoreRecurringErrorMessage(
1383 2 : state, " ** ~~~ ** " + Message, MsgIndex, ReportMaxOf, ReportMinOf, ReportSumOf, ReportMaxUnits, ReportMinUnits, ReportSumUnits);
1384 1 : }
1385 :
1386 16561 : void StoreRecurringErrorMessage(EnergyPlusData &state,
1387 : std::string const &ErrorMessage, // Message automatically written to "error file" at end of simulation
1388 : int &ErrorMsgIndex, // Recurring message index, if zero, next available index is assigned
1389 : ObjexxFCL::Optional<Real64 const> ErrorReportMaxOf, // Track and report the max of the values passed to this argument
1390 : ObjexxFCL::Optional<Real64 const> ErrorReportMinOf, // Track and report the min of the values passed to this argument
1391 : ObjexxFCL::Optional<Real64 const> ErrorReportSumOf, // Track and report the sum of the values passed to this argument
1392 : std::string const &ErrorReportMaxUnits, // Units for "max" reporting
1393 : std::string const &ErrorReportMinUnits, // Units for "min" reporting
1394 : std::string const &ErrorReportSumUnits // Units for "sum" reporting
1395 : )
1396 : {
1397 :
1398 : // SUBROUTINE INFORMATION:
1399 : // AUTHOR Michael J. Witte
1400 : // DATE WRITTEN August 2004
1401 : // MODIFIED September 2005;LKL;Added Units
1402 :
1403 : // PURPOSE OF THIS SUBROUTINE:
1404 : // This subroutine stores a recurring ErrorMessage with
1405 : // for output at the end of the simulation with automatic tracking of number
1406 : // of occurrences and optional tracking of associated min, max, and sum values
1407 :
1408 : // If Index is zero, then assign next available index and reallocate array
1409 16561 : if (ErrorMsgIndex == 0) {
1410 130 : state.dataErrTracking->RecurringErrors.redimension(++state.dataErrTracking->NumRecurringErrors);
1411 130 : ErrorMsgIndex = state.dataErrTracking->NumRecurringErrors;
1412 : // The message string only needs to be stored once when a new recurring message is created
1413 130 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).Message = ErrorMessage;
1414 130 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).Count = 1;
1415 130 : if (state.dataGlobal->WarmupFlag) {
1416 4 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).WarmupCount = 1;
1417 : }
1418 130 : if (state.dataGlobal->DoingSizing) {
1419 2 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).SizingCount = 1;
1420 : }
1421 :
1422 : // For max, min, and sum values, store the current value when a new recurring message is created
1423 130 : if (present(ErrorReportMaxOf)) {
1424 102 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MaxValue = ErrorReportMaxOf;
1425 102 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportMax = true;
1426 102 : if (!ErrorReportMaxUnits.empty()) {
1427 69 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MaxUnits = ErrorReportMaxUnits;
1428 : }
1429 : }
1430 130 : if (present(ErrorReportMinOf)) {
1431 100 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MinValue = ErrorReportMinOf;
1432 100 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportMin = true;
1433 100 : if (!ErrorReportMinUnits.empty()) {
1434 69 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MinUnits = ErrorReportMinUnits;
1435 : }
1436 : }
1437 130 : if (present(ErrorReportSumOf)) {
1438 0 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).SumValue = ErrorReportSumOf;
1439 0 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportSum = true;
1440 0 : if (!ErrorReportSumUnits.empty()) {
1441 0 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).SumUnits = ErrorReportSumUnits;
1442 : }
1443 : }
1444 :
1445 16431 : } else if (ErrorMsgIndex > 0) {
1446 : // Do stats and store
1447 16431 : ++state.dataErrTracking->RecurringErrors(ErrorMsgIndex).Count;
1448 16431 : if (state.dataGlobal->WarmupFlag) {
1449 8643 : ++state.dataErrTracking->RecurringErrors(ErrorMsgIndex).WarmupCount;
1450 : }
1451 16431 : if (state.dataGlobal->DoingSizing) {
1452 0 : ++state.dataErrTracking->RecurringErrors(ErrorMsgIndex).SizingCount;
1453 : }
1454 :
1455 16431 : if (present(ErrorReportMaxOf)) {
1456 16412 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MaxValue =
1457 16412 : max(ErrorReportMaxOf, state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MaxValue);
1458 16412 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportMax = true;
1459 : }
1460 16431 : if (present(ErrorReportMinOf)) {
1461 15770 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MinValue =
1462 15770 : min(ErrorReportMinOf, state.dataErrTracking->RecurringErrors(ErrorMsgIndex).MinValue);
1463 15770 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportMin = true;
1464 : }
1465 16431 : if (present(ErrorReportSumOf)) {
1466 0 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).SumValue += ErrorReportSumOf;
1467 0 : state.dataErrTracking->RecurringErrors(ErrorMsgIndex).ReportSum = true;
1468 : }
1469 : } else {
1470 : // If ErrorMsgIndex < 0, then do nothing
1471 : }
1472 16561 : }
1473 :
1474 11846 : void ShowErrorMessage(EnergyPlusData &state, std::string const &ErrorMessage, OptionalOutputFileRef OutUnit1, OptionalOutputFileRef OutUnit2)
1475 : {
1476 :
1477 : // SUBROUTINE INFORMATION:
1478 : // AUTHOR Linda K. Lawrie
1479 : // DATE WRITTEN December 1997
1480 :
1481 : // PURPOSE OF THIS SUBROUTINE:
1482 : // This subroutine displays the error messages on the indicated
1483 : // file unit numbers, in addition to the "standard error output" unit.
1484 :
1485 : // METHODOLOGY EMPLOYED:
1486 : // If arguments OutUnit1 and/or OutUnit2 are present the
1487 : // error message is written to these as well and the standard one.
1488 :
1489 11846 : auto *err_stream = state.files.err_stream.get();
1490 :
1491 11846 : if (state.dataUtilityRoutines->outputErrorHeader && err_stream) {
1492 26 : *err_stream << "Program Version," << state.dataStrGlobals->VerStringVar << ',' << state.dataStrGlobals->IDDVerString << '\n';
1493 26 : state.dataUtilityRoutines->outputErrorHeader = false;
1494 : }
1495 :
1496 11846 : if (!state.dataGlobal->DoingInputProcessing) {
1497 11846 : if (err_stream) {
1498 9734 : *err_stream << " " << ErrorMessage << '\n';
1499 : }
1500 : } else {
1501 : // CacheIPErrorFile is never opened or closed
1502 : // so this output would just go to stdout
1503 : // ObjexxFCL::gio::write(CacheIPErrorFile, fmtA) << ErrorMessage;
1504 0 : if (state.dataGlobal->printConsoleOutput) {
1505 0 : std::cout << ErrorMessage << '\n';
1506 : }
1507 : }
1508 11846 : if (OutUnit1) {
1509 0 : print(OutUnit1.value(), " {}", ErrorMessage);
1510 : }
1511 11846 : if (OutUnit2) {
1512 0 : print(OutUnit2.value(), " {}", ErrorMessage);
1513 : }
1514 : // std::string tmp = " " + ErrorMessage + '\n';
1515 : // if (errorCallback) DataGlobals::errorCallback(tmp.c_str());
1516 11846 : }
1517 :
1518 26 : void SummarizeErrors(EnergyPlusData &state)
1519 : {
1520 :
1521 : // SUBROUTINE INFORMATION:
1522 : // AUTHOR Linda K. Lawrie
1523 : // DATE WRITTEN March 2003
1524 :
1525 : // PURPOSE OF THIS SUBROUTINE:
1526 : // This subroutine provides a summary of certain errors that might
1527 : // otherwise get lost in the shuffle of many similar messages.
1528 :
1529 : std::string::size_type StartC;
1530 : std::string::size_type EndC;
1531 :
1532 26 : if (any_gt(state.dataErrTracking->MatchCounts, 0)) {
1533 2 : ShowMessage(state, "");
1534 2 : ShowMessage(state, "===== Final Error Summary =====");
1535 2 : ShowMessage(state, "The following error categories occurred. Consider correcting or noting.");
1536 21 : for (int Loop = 1; Loop <= DataErrorTracking::SearchCounts; ++Loop) {
1537 20 : if (state.dataErrTracking->MatchCounts(Loop) > 0) {
1538 3 : ShowMessage(state, DataErrorTracking::Summaries[Loop]);
1539 1 : std::string thisMoreDetails = DataErrorTracking::MoreDetails[Loop];
1540 1 : if (!thisMoreDetails.empty()) {
1541 1 : StartC = 0;
1542 1 : EndC = len(thisMoreDetails) - 1;
1543 3 : while (EndC != std::string::npos) {
1544 3 : EndC = index(thisMoreDetails.substr(StartC), "<CR");
1545 3 : ShowMessage(state, format("..{}", thisMoreDetails.substr(StartC, EndC)));
1546 3 : if (thisMoreDetails.substr(StartC + EndC, 5) == "<CRE>") {
1547 1 : break;
1548 : }
1549 2 : StartC += EndC + 4;
1550 2 : EndC = len(thisMoreDetails.substr(StartC)) - 1;
1551 : }
1552 : }
1553 1 : }
1554 : }
1555 3 : ShowMessage(state, "");
1556 : }
1557 26 : }
1558 :
1559 26 : void ShowRecurringErrors(EnergyPlusData &state)
1560 : {
1561 :
1562 : // SUBROUTINE INFORMATION:
1563 : // AUTHOR Linda K. Lawrie
1564 : // DATE WRITTEN March 2003
1565 :
1566 : // PURPOSE OF THIS SUBROUTINE:
1567 : // This subroutine provides a summary of certain errors that might
1568 : // otherwise get lost in the shuffle of many similar messages.
1569 :
1570 : static constexpr std::string_view StatMessageStart(" ** ~~~ ** ");
1571 :
1572 26 : if (state.dataErrTracking->NumRecurringErrors > 0) {
1573 0 : ShowMessage(state, "");
1574 0 : ShowMessage(state, "===== Recurring Error Summary =====");
1575 0 : ShowMessage(state, "The following recurring error messages occurred.");
1576 0 : for (int Loop = 1; Loop <= state.dataErrTracking->NumRecurringErrors; ++Loop) {
1577 0 : auto const &error = state.dataErrTracking->RecurringErrors(Loop);
1578 : // Suppress reporting the count if it is a continue error
1579 0 : if (has_prefix(error.Message, " ** ~~~ ** ")) {
1580 0 : ShowMessage(state, error.Message);
1581 0 : if (state.dataSQLiteProcedures->sqlite) {
1582 0 : state.dataSQLiteProcedures->sqlite->updateSQLiteErrorRecord(error.Message);
1583 : }
1584 0 : if (state.dataGlobal->errorCallback) {
1585 0 : state.dataGlobal->errorCallback(Error::Continue, error.Message);
1586 : }
1587 : } else {
1588 0 : const bool warning = has_prefix(error.Message, " ** Warning ** ");
1589 0 : const bool severe = has_prefix(error.Message, " ** Severe ** ");
1590 :
1591 0 : ShowMessage(state, "");
1592 0 : ShowMessage(state, error.Message);
1593 0 : ShowMessage(state, format("{} This error occurred {} total times;", StatMessageStart, error.Count));
1594 0 : ShowMessage(state, format("{} during Warmup {} times;", StatMessageStart, error.WarmupCount));
1595 0 : ShowMessage(state, format("{} during Sizing {} times.", StatMessageStart, error.SizingCount));
1596 0 : if (state.dataSQLiteProcedures->sqlite) {
1597 0 : if (warning) {
1598 0 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 0, error.Message.substr(15), error.Count);
1599 0 : } else if (severe) {
1600 0 : state.dataSQLiteProcedures->sqlite->createSQLiteErrorRecord(1, 1, error.Message.substr(15), error.Count);
1601 : }
1602 : }
1603 0 : if (state.dataGlobal->errorCallback) {
1604 0 : Error level = Error::Warning;
1605 0 : if (severe) {
1606 0 : level = Error::Severe;
1607 : }
1608 0 : state.dataGlobal->errorCallback(level, error.Message);
1609 0 : state.dataGlobal->errorCallback(Error::Continue, "");
1610 : }
1611 : }
1612 0 : std::string StatMessage = "";
1613 0 : if (error.ReportMax) {
1614 0 : std::string MaxOut = format("{:.6f}", error.MaxValue);
1615 0 : StatMessage += " Max=" + MaxOut;
1616 0 : if (!error.MaxUnits.empty()) {
1617 0 : StatMessage += ' ' + error.MaxUnits;
1618 : }
1619 0 : }
1620 0 : if (error.ReportMin) {
1621 0 : std::string MinOut = format("{:.6f}", error.MinValue);
1622 0 : StatMessage += " Min=" + MinOut;
1623 0 : if (!error.MinUnits.empty()) {
1624 0 : StatMessage += ' ' + error.MinUnits;
1625 : }
1626 0 : }
1627 0 : if (error.ReportSum) {
1628 0 : std::string SumOut = format("{:.6f}", error.SumValue);
1629 0 : StatMessage += " Sum=" + SumOut;
1630 0 : if (!error.SumUnits.empty()) {
1631 0 : StatMessage += ' ' + error.SumUnits;
1632 : }
1633 0 : }
1634 0 : if (error.ReportMax || error.ReportMin || error.ReportSum) {
1635 0 : ShowMessage(state, format("{}{}", StatMessageStart, StatMessage));
1636 : }
1637 0 : }
1638 0 : ShowMessage(state, "");
1639 : }
1640 26 : }
1641 :
1642 1 : void ShowSevereDuplicateName(EnergyPlusData &state, ErrorObjectHeader const &eoh)
1643 : {
1644 1 : ShowSevereError(state, format("{}: {} = {}, duplicate name.", eoh.routineName, eoh.objectType, eoh.objectName));
1645 1 : }
1646 :
1647 0 : void ShowSevereEmptyField(
1648 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view depFieldName, std::string_view depFieldVal)
1649 : {
1650 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1651 0 : ShowContinueError(state,
1652 0 : format("{} cannot be empty{}.", fieldName, depFieldName.empty() ? "" : format(" when {} = {}", depFieldName, depFieldVal)));
1653 0 : }
1654 :
1655 39 : void ShowSevereItemNotFound(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal)
1656 : {
1657 39 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1658 39 : ShowContinueError(state, format("{} = {}, item not found.", fieldName, fieldVal));
1659 39 : }
1660 :
1661 0 : void ShowSevereItemNotFoundAudit(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal)
1662 : {
1663 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName), OptionalOutputFileRef{state.files.audit});
1664 0 : ShowContinueError(state, format("{} = {}, item not found.", fieldName, fieldVal), OptionalOutputFileRef{state.files.audit});
1665 0 : }
1666 :
1667 0 : void ShowSevereDuplicateAssignment(
1668 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal, std::string_view prevVal)
1669 : {
1670 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1671 0 : ShowContinueError(state, format("{} = {}, field previously assigned to {}.", fieldName, fieldVal, prevVal));
1672 0 : }
1673 :
1674 3 : void ShowSevereInvalidKey(
1675 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal, std::string_view msg)
1676 : {
1677 3 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1678 3 : ShowContinueError(state, format("{} = {}, invalid key.", fieldName, fieldVal));
1679 3 : if (!msg.empty()) {
1680 0 : ShowContinueError(state, format(msg));
1681 : }
1682 3 : }
1683 :
1684 4 : void ShowSevereInvalidBool(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal)
1685 : {
1686 4 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1687 4 : ShowContinueError(state, format("{} = {}, invalid boolean (\"Yes\"/\"No\").", fieldName, fieldVal));
1688 4 : }
1689 :
1690 0 : void ShowSevereCustom(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view msg)
1691 : {
1692 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1693 0 : ShowContinueError(state, format("{}", msg));
1694 0 : }
1695 :
1696 0 : void ShowSevereCustomAudit(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view msg)
1697 : {
1698 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName), OptionalOutputFileRef{state.files.audit});
1699 0 : ShowContinueError(state, format("{}", msg), OptionalOutputFileRef{state.files.audit});
1700 0 : }
1701 :
1702 0 : void ShowSevereCustomField(
1703 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldValue, std::string_view msg)
1704 : {
1705 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1706 0 : ShowContinueError(state, format("{} = {}, {}", fieldName, fieldValue, msg));
1707 0 : }
1708 :
1709 0 : void ShowSevereBadMin(EnergyPlusData &state,
1710 : ErrorObjectHeader const &eoh,
1711 : std::string_view fieldName,
1712 : Real64 fieldVal,
1713 : Clusive cluMin,
1714 : Real64 minVal,
1715 : std::string_view msg)
1716 : {
1717 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1718 0 : ShowContinueError(state, format("{} = {}, but must be {} {}", fieldName, fieldVal, cluMin == Clusive::In ? ">=" : ">", minVal));
1719 0 : if (!msg.empty()) {
1720 0 : ShowContinueError(state, format("{}", msg));
1721 : }
1722 0 : }
1723 :
1724 0 : void ShowSevereBadMax(EnergyPlusData &state,
1725 : ErrorObjectHeader const &eoh,
1726 : std::string_view fieldName,
1727 : Real64 fieldVal,
1728 : Clusive cluMax,
1729 : Real64 maxVal,
1730 : std::string_view msg)
1731 : {
1732 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1733 0 : ShowContinueError(state, format("{} = {}, but must be {} {}", fieldName, fieldVal, cluMax == Clusive::In ? "<=" : "<", maxVal));
1734 0 : if (!msg.empty()) {
1735 0 : ShowContinueError(state, format("{}", msg));
1736 : }
1737 0 : }
1738 :
1739 0 : void ShowSevereBadMinMax(EnergyPlusData &state,
1740 : ErrorObjectHeader const &eoh,
1741 : std::string_view fieldName,
1742 : Real64 fieldVal,
1743 : Clusive cluMin,
1744 : Real64 minVal,
1745 : Clusive cluMax,
1746 : Real64 maxVal,
1747 : std::string_view msg)
1748 : {
1749 0 : ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1750 0 : ShowContinueError(state,
1751 0 : format("{} = {}, but must be {} {} and {} {}",
1752 : fieldName,
1753 : fieldVal,
1754 0 : cluMin == Clusive::In ? ">=" : ">",
1755 : minVal,
1756 0 : cluMax == Clusive::In ? "<=" : "<",
1757 : maxVal));
1758 0 : if (!msg.empty()) {
1759 0 : ShowContinueError(state, format("{}", msg));
1760 : }
1761 0 : }
1762 :
1763 0 : void ShowWarningItemNotFound(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal)
1764 : {
1765 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1766 0 : ShowContinueError(state, format("{} = {}, item not found", fieldName, fieldVal));
1767 0 : }
1768 :
1769 7 : void ShowWarningCustom(EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view msg)
1770 : {
1771 7 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1772 7 : ShowContinueError(state, format("{}", msg));
1773 7 : }
1774 :
1775 0 : void ShowWarningCustomField(
1776 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldValue, std::string_view msg)
1777 : {
1778 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1779 0 : ShowContinueError(state, format("{} = {}, {}", fieldName, fieldValue, msg));
1780 0 : }
1781 :
1782 2 : void ShowWarningInvalidKey(EnergyPlusData &state,
1783 : ErrorObjectHeader const &eoh,
1784 : std::string_view fieldName,
1785 : std::string_view fieldVal,
1786 : std::string_view defaultVal,
1787 : std::string_view msg)
1788 : {
1789 2 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1790 2 : ShowContinueError(state, format("{} = {}, invalid key, {} will be used.", fieldName, fieldVal, defaultVal));
1791 2 : if (!msg.empty()) {
1792 0 : ShowContinueError(state, format(msg));
1793 : }
1794 2 : }
1795 :
1796 0 : void ShowWarningInvalidBool(
1797 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal, std::string_view defaultVal)
1798 : {
1799 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1800 0 : ShowContinueError(state, format("{} = {}, invalid boolean (\"Yes\"/\"No\"), {} will be used.", fieldName, fieldVal, defaultVal));
1801 0 : }
1802 :
1803 275 : void ShowWarningEmptyField(EnergyPlusData &state,
1804 : ErrorObjectHeader const &eoh,
1805 : std::string_view fieldName,
1806 : std::string_view defaultVal,
1807 : std::string_view depFieldName,
1808 : std::string_view depFieldVal)
1809 : {
1810 275 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1811 275 : ShowContinueError(state, format("{} is empty.", fieldName));
1812 :
1813 275 : if (!depFieldName.empty()) {
1814 0 : ShowContinueError(state, format("Cannot be empty when {} = {}", depFieldName, depFieldVal));
1815 : }
1816 275 : if (!defaultVal.empty()) {
1817 0 : ShowContinueError(state, format("{} will be used.", defaultVal));
1818 : }
1819 275 : }
1820 :
1821 1 : void ShowWarningNonEmptyField(
1822 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view depFieldName, std::string_view depFieldValue)
1823 : {
1824 1 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1825 1 : ShowContinueError(state, format("{} is not empty.", fieldName));
1826 1 : if (!depFieldName.empty()) {
1827 0 : ShowContinueError(state, format("{} is ignored when {} = {}.", fieldName, depFieldName, depFieldValue));
1828 : }
1829 1 : }
1830 :
1831 362 : void ShowWarningItemNotFound(
1832 : EnergyPlusData &state, ErrorObjectHeader const &eoh, std::string_view fieldName, std::string_view fieldVal, std::string_view defaultVal)
1833 : {
1834 362 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1835 362 : if (defaultVal.empty()) {
1836 349 : ShowContinueError(state, format("{} = {}, item not found.", fieldName, fieldVal));
1837 : } else {
1838 13 : ShowContinueError(state, format("{} = {}, item not found, {} will be used.", fieldName, fieldVal, defaultVal));
1839 : }
1840 362 : }
1841 :
1842 0 : void ShowWarningBadMin(EnergyPlusData &state,
1843 : ErrorObjectHeader const &eoh,
1844 : std::string_view fieldName,
1845 : Real64 fieldVal,
1846 : Clusive cluMin,
1847 : Real64 minVal,
1848 : std::string_view msg)
1849 : {
1850 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1851 0 : ShowContinueError(state, format("{} = {}, but must be {} {}", fieldName, fieldVal, cluMin == Clusive::In ? ">=" : ">", minVal));
1852 0 : if (!msg.empty()) {
1853 0 : ShowContinueError(state, format("{}", msg));
1854 : }
1855 0 : }
1856 :
1857 0 : void ShowWarningBadMax(EnergyPlusData &state,
1858 : ErrorObjectHeader const &eoh,
1859 : std::string_view fieldName,
1860 : Real64 fieldVal,
1861 : Clusive cluMax,
1862 : Real64 maxVal,
1863 : std::string_view msg)
1864 : {
1865 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1866 0 : ShowContinueError(state, format("{} = {}, but must be {} {}", fieldName, fieldVal, cluMax == Clusive::In ? "<=" : "<", maxVal));
1867 0 : ShowContinueError(state, format("{} = {}, but must be {} {}", fieldName, fieldVal, cluMax == Clusive::In ? "<=" : "<", maxVal));
1868 0 : if (!msg.empty()) {
1869 0 : ShowContinueError(state, format("{}", msg));
1870 : }
1871 0 : }
1872 :
1873 0 : void ShowWarningBadMinMax(EnergyPlusData &state,
1874 : ErrorObjectHeader const &eoh,
1875 : std::string_view fieldName,
1876 : Real64 fieldVal,
1877 : Clusive cluMin,
1878 : Real64 minVal,
1879 : Clusive cluMax,
1880 : Real64 maxVal,
1881 : std::string_view msg)
1882 : {
1883 0 : ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
1884 0 : ShowContinueError(state,
1885 0 : format("{} = {}, but must be {} {} and {} {}",
1886 : fieldName,
1887 : fieldVal,
1888 0 : cluMin == Clusive::In ? ">=" : ">",
1889 : minVal,
1890 0 : cluMax == Clusive::In ? "<=" : "<",
1891 : maxVal));
1892 0 : if (!msg.empty()) {
1893 0 : ShowContinueError(state, format("{}", msg));
1894 : }
1895 0 : }
1896 :
1897 : } // namespace EnergyPlus
|