LCOV - code coverage report
Current view: top level - EnergyPlus - UtilityRoutines.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 64.6 % 759 490
Test Date: 2025-05-22 16:09:37 Functions: 63.1 % 65 41

            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
        

Generated by: LCOV version 2.0-1