LCOV - code coverage report
Current view: top level - EnergyPlus - UtilityRoutines.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 476 656 72.6 %
Date: 2023-01-17 19:17:23 Functions: 35 40 87.5 %

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

Generated by: LCOV version 1.13