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