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