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