LCOV - code coverage report
Current view: top level - EnergyPlus - General.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 78.1 % 608 475
Test Date: 2025-05-22 16:09:37 Functions: 95.7 % 23 22

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : #include <cstdlib>
      52              : 
      53              : // ObjexxFCL Headers
      54              : #include <ObjexxFCL/Fmath.hh>
      55              : #include <ObjexxFCL/string.functions.hh>
      56              : 
      57              : // EnergyPlus Headers
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataEnvironment.hh>
      60              : #include <EnergyPlus/DataHVACGlobals.hh>
      61              : #include <EnergyPlus/DataIPShortCuts.hh>
      62              : #include <EnergyPlus/DataRuntimeLanguage.hh>
      63              : #include <EnergyPlus/DataSurfaces.hh>
      64              : #include <EnergyPlus/General.hh>
      65              : #include <EnergyPlus/HVACSystemRootFindingAlgorithm.hh>
      66              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      67              : #include <EnergyPlus/UtilityRoutines.hh>
      68              : #include <EnergyPlus/WeatherManager.hh>
      69              : 
      70              : #if defined(_WIN32) && _MSC_VER < 1900
      71              : #    define snprintf _snprintf
      72              : #endif
      73              : 
      74              : namespace EnergyPlus::General {
      75              : 
      76              : // Module containing routines for general use
      77              : 
      78              : // MODULE INFORMATION:
      79              : //       AUTHOR         Fred Buhl, Linda Lawrie
      80              : //       DATE WRITTEN   December 2001
      81              : 
      82              : // PURPOSE OF THIS MODULE:
      83              : // contains routines (most likely numeric) that may be needed in several parts
      84              : // of EnergyPlus
      85              : 
      86              : // MODULE PARAMETER DEFINITIONS
      87              : static constexpr std::string_view BlankString;
      88              : 
      89              : enum class ReportType
      90              : {
      91              :     Invalid = -1,
      92              :     DXF,
      93              :     DXFWireFrame,
      94              :     VRML,
      95              :     Num
      96              : };
      97              : 
      98              : constexpr std::array<std::string_view, static_cast<int>(ReportType::Num)> ReportTypeNamesUC{"DXF", "DXF:WIREFRAME", "VRML"};
      99              : 
     100              : enum class AvailRpt
     101              : {
     102              :     Invalid = -1,
     103              :     None,
     104              :     NotByUniqueKeyNames,
     105              :     Verbose,
     106              :     Num
     107              : };
     108              : 
     109              : constexpr std::array<std::string_view, static_cast<int>(AvailRpt::Num)> AvailRptNamesUC{"NONE", "NOTBYUNIQUEKEYNAMES", "VERBOSE"};
     110              : 
     111              : enum class ERLdebugOutputLevel
     112              : {
     113              :     Invalid = -1,
     114              :     None,
     115              :     ErrorsOnly,
     116              :     Verbose,
     117              :     Num
     118              : };
     119              : 
     120              : constexpr std::array<std::string_view, static_cast<int>(ERLdebugOutputLevel::Num)> ERLdebugOutputLevelNamesUC{"NONE", "ERRORSONLY", "VERBOSE"};
     121              : 
     122              : enum class ReportName
     123              : {
     124              :     Invalid = -1,
     125              :     Constructions,
     126              :     Viewfactorinfo,
     127              :     Variabledictionary,
     128              :     Surfaces,
     129              :     Energymanagementsystem,
     130              :     Num
     131              : };
     132              : 
     133              : constexpr std::array<std::string_view, static_cast<int>(ReportName::Num)> ReportNamesUC{
     134              :     "CONSTRUCTIONS", "VIEWFACTORINFO", "VARIABLEDICTIONARY", "SURFACES", "ENERGYMANAGEMENTSYSTEM"};
     135              : 
     136              : enum class RptKey
     137              : {
     138              :     Invalid = -1,
     139              :     Costinfo,
     140              :     DXF,
     141              :     DXFwireframe,
     142              :     VRML,
     143              :     Vertices,
     144              :     Details,
     145              :     DetailsWithVertices,
     146              :     Lines,
     147              :     Num
     148              : };
     149              : 
     150              : constexpr std::array<std::string_view, static_cast<int>(RptKey::Num)> RptKeyNamesUC{
     151              :     "COSTINFO", "DXF", "DXF:WIREFRAME", "VRML", "VERTICES", "DETAILS", "DETAILSWITHVERTICES", "LINES"};
     152              : 
     153              : // A second version that does not require a payload -- use lambdas
     154       198612 : void SolveRoot(const EnergyPlusData &state,
     155              :                Real64 Eps,   // required absolute accuracy
     156              :                int MaxIte,   // maximum number of allowed iterations
     157              :                int &Flag,    // integer storing exit status
     158              :                Real64 &XRes, // value of x that solves f(x,Par) = 0
     159              :                const std::function<Real64(Real64)> &f,
     160              :                Real64 X_0, // 1st bound of interval that contains the solution
     161              :                Real64 X_1) // 2nd bound of interval that contains the solution
     162              : {
     163              :     // SUBROUTINE INFORMATION:
     164              :     //       AUTHOR         Michael Wetter
     165              :     //       DATE WRITTEN   March 1999
     166              :     //       MODIFIED       Fred Buhl November 2000, R. Raustad October 2006 - made subroutine RECURSIVE
     167              :     //                      L. Gu, May 2017 - allow both Bisection and RegulaFalsi
     168              : 
     169              :     // PURPOSE OF THIS SUBROUTINE:
     170              :     // Find the value of x between x0 and x1 such that f(x,Par)
     171              :     // is equal to zero.
     172              : 
     173              :     // METHODOLOGY EMPLOYED:
     174              :     // Uses the Regula Falsi (false position) method (similar to secant method)
     175              : 
     176              :     // REFERENCES:
     177              :     // See Press et al., Numerical Recipes in Fortran, Cambridge University Press,
     178              :     // 2nd edition, 1992. Page 347 ff.
     179              : 
     180              :     // SUBROUTINE ARGUMENT DEFINITIONS:
     181              :     // = -2: f(x0) and f(x1) have the same sign
     182              :     // = -1: no convergence
     183              :     // >  0: number of iterations performed
     184              : 
     185       198612 :     Real64 constexpr SMALL(1.e-10);
     186       198612 :     Real64 X0 = X_0;   // present 1st bound
     187       198612 :     Real64 X1 = X_1;   // present 2nd bound
     188       198612 :     Real64 XTemp = X0; // new estimate
     189       198612 :     int NIte = 0;      // number of iterations
     190       198612 :     int AltIte = 0;    // an accounter used for Alternation choice
     191              : 
     192       198612 :     Real64 Y0 = f(X0); // f at X0
     193       198612 :     Real64 Y1 = f(X1); // f at X1
     194              :     // check initial values
     195       198612 :     if (Y0 * Y1 > 0) {
     196        16573 :         Flag = -2;
     197        16573 :         XRes = X0;
     198        16573 :         return;
     199              :     }
     200       182039 :     XRes = XTemp;
     201              : 
     202              :     while (true) {
     203              : 
     204       416271 :         Real64 DY = Y0 - Y1;
     205       416271 :         if (std::abs(DY) < SMALL) DY = SMALL;
     206       416271 :         if (std::abs(X1 - X0) < SMALL) {
     207           11 :             break;
     208              :         }
     209              :         // new estimation
     210       416260 :         switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolverMethod) {
     211       342950 :         case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
     212       342950 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     213       342950 :             break;
     214              :         }
     215        21888 :         case HVACSystemRootSolverAlgorithm::Bisection: {
     216        21888 :             XTemp = (X1 + X0) / 2.0;
     217        21888 :             break;
     218              :         }
     219           28 :         case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
     220           28 :             if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     221           17 :                 XTemp = (X1 + X0) / 2.0;
     222              :             } else {
     223           11 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     224              :             }
     225           28 :             break;
     226              :         }
     227           12 :         case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
     228           12 :             if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     229           11 :                 XTemp = (X1 + X0) / 2.0;
     230              :             } else {
     231            1 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     232              :             }
     233           12 :             break;
     234              :         }
     235           15 :         case HVACSystemRootSolverAlgorithm::Alternation: {
     236           15 :             if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     237            6 :                 XTemp = (X1 + X0) / 2.0;
     238            6 :                 if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) AltIte = 0;
     239              :             } else {
     240            9 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     241              :             }
     242           15 :             break;
     243              :         }
     244        51367 :         case HVACSystemRootSolverAlgorithm::ShortBisectionThenRegulaFalsi: {
     245        51367 :             if (NIte < 3) {
     246        21126 :                 XTemp = (X1 + X0) / 2.0;
     247              :             } else {
     248        30241 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     249              :             }
     250        51367 :             break;
     251              :         }
     252            0 :         default: {
     253            0 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     254              :         }
     255              :         }
     256              : 
     257       416260 :         Real64 const YTemp = f(XTemp);
     258              : 
     259       416260 :         ++NIte;
     260       416260 :         ++AltIte;
     261              : 
     262              :         // check convergence
     263       416260 :         if (std::abs(YTemp) < Eps) {
     264       182026 :             Flag = NIte;
     265       182026 :             XRes = XTemp;
     266       182026 :             return;
     267              :         };
     268              : 
     269              :         // OK, so we didn't converge, lets check max iterations to see if we should break early
     270       234234 :         if (NIte > MaxIte) break;
     271              : 
     272              :         // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
     273              :         // and reassign values (only if further iteration required)
     274       234232 :         if (Y0 < 0.0) {
     275       196527 :             if (YTemp < 0.0) {
     276       134126 :                 X0 = XTemp;
     277       134126 :                 Y0 = YTemp;
     278              :             } else {
     279        62401 :                 X1 = XTemp;
     280        62401 :                 Y1 = YTemp;
     281              :             }
     282              :         } else {
     283        37705 :             if (YTemp < 0.0) {
     284        21356 :                 X1 = XTemp;
     285        21356 :                 Y1 = YTemp;
     286              :             } else {
     287        16349 :                 X0 = XTemp;
     288        16349 :                 Y0 = YTemp;
     289              :             }
     290              :         } // ( Y0 < 0 )
     291       234232 :     }     // Cont
     292              : 
     293              :     // if we make it here we haven't converged, so just set the flag and leave
     294           13 :     Flag = -1;
     295           13 :     XRes = XTemp;
     296              : }
     297              : 
     298         5545 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
     299              : {
     300         5545 :     if (NumItemsInAvg <= 1) return; // no need to average/smooth
     301              : 
     302         5306 :     Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
     303              : 
     304       644306 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     305       639000 :         TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
     306       639000 :         DataIn(i) = 0.0;
     307              :     }
     308              : 
     309       644306 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     310      3973728 :         for (int j = 1; j <= NumItemsInAvg; ++j) {
     311      3334728 :             DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
     312              :         }
     313       639000 :         DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
     314              :     }
     315         5306 : }
     316              : 
     317         2113 : void ProcessDateString(EnergyPlusData &state,
     318              :                        std::string const &String,
     319              :                        int &PMonth,
     320              :                        int &PDay,
     321              :                        int &PWeekDay,
     322              :                        Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     323              :                        bool &ErrorsFound,
     324              :                        ObjexxFCL::Optional_int PYear)
     325              : {
     326              : 
     327              :     // SUBROUTINE INFORMATION:
     328              :     //       AUTHOR         Linda Lawrie
     329              :     //       DATE WRITTEN   December 1999
     330              : 
     331              :     // PURPOSE OF THIS SUBROUTINE:
     332              :     // This subroutine will process a date from a string and determine
     333              :     // the proper month and day for that date string.
     334              : 
     335              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     336              :     bool errFlag;
     337              : 
     338         2113 :     int FstNum = int(Util::ProcessNumber(String, errFlag));
     339         2113 :     DateType = Weather::DateType::Invalid;
     340         2113 :     if (!errFlag) {
     341              :         // Entered single number, do inverse JDay
     342           60 :         if (FstNum == 0) {
     343           60 :             PMonth = 0;
     344           60 :             PDay = 0;
     345           60 :             DateType = Weather::DateType::MonthDay;
     346            0 :         } else if (FstNum < 0 || FstNum > 366) {
     347            0 :             ShowSevereError(state, format("Invalid Julian date Entered={}", String));
     348            0 :             ErrorsFound = true;
     349              :         } else {
     350            0 :             InvOrdinalDay(FstNum, PMonth, PDay, 0);
     351            0 :             DateType = Weather::DateType::LastDayInMonth;
     352              :         }
     353              :     } else {
     354         2053 :         int NumTokens = 0;
     355         2053 :         int TokenDay = 0;
     356         2053 :         int TokenMonth = 0;
     357         2053 :         int TokenWeekday = 0;
     358              :         // Error when processing as number, try x/x
     359         2053 :         if (!present(PYear)) {
     360         1991 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
     361              :         } else {
     362           62 :             int TokenYear = 0;
     363           62 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
     364           62 :             PYear = TokenYear;
     365              :         }
     366         2053 :         if (DateType == Weather::DateType::MonthDay) {
     367         2052 :             PDay = TokenDay;
     368         2052 :             PMonth = TokenMonth;
     369            1 :         } else if (DateType == Weather::DateType::NthDayInMonth || DateType == Weather::DateType::LastDayInMonth) {
     370              :             // interpret as TokenDay TokenWeekday in TokenMonth
     371            1 :             PDay = TokenDay;
     372            1 :             PMonth = TokenMonth;
     373            1 :             PWeekDay = TokenWeekday;
     374              :         }
     375              :     }
     376         2113 : }
     377              : 
     378         2053 : void DetermineDateTokens(EnergyPlusData &state,
     379              :                          std::string const &String,
     380              :                          int &NumTokens,                   // Number of tokens found in string
     381              :                          int &TokenDay,                    // Value of numeric field found
     382              :                          int &TokenMonth,                  // Value of Month field found (1=Jan, 2=Feb, etc)
     383              :                          int &TokenWeekday,                // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
     384              :                          Weather::DateType &DateType,      // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     385              :                          bool &ErrorsFound,                // Set to true if cannot process this string as a date
     386              :                          ObjexxFCL::Optional_int TokenYear // Value of Year if one appears to be present and this argument is present
     387              : )
     388              : {
     389              : 
     390              :     // SUBROUTINE INFORMATION:
     391              :     //       AUTHOR         Linda Lawrie
     392              :     //       DATE WRITTEN   August 2000
     393              : 
     394              :     // PURPOSE OF THIS SUBROUTINE:
     395              :     // This subroutine is invoked for date fields that appear to be strings (give
     396              :     // error when ProcessNumber is used).
     397              : 
     398              :     // METHODOLOGY EMPLOYED:
     399              :     // Delete everything that is extraneous to the date information needed.  Process what
     400              :     // is left.
     401              : 
     402              :     // SUBROUTINE PARAMETER DEFINITIONS:
     403              :     static constexpr int NumSingleChars(3);
     404              :     static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
     405              :     static constexpr int NumDoubleChars(6);
     406              :     static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
     407              :         "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want these only at end of words
     408              :     static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
     409              :     static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
     410              : 
     411              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     412         2053 :     std::string CurrentString = String;
     413         2053 :     Array1D_string Fields(3);
     414         2053 :     bool InternalError = false;
     415         2053 :     bool WkDayInMonth = false;
     416              : 
     417         2053 :     NumTokens = 0;
     418         2053 :     TokenDay = 0;
     419         2053 :     TokenMonth = 0;
     420         2053 :     TokenWeekday = 0;
     421         2053 :     DateType = Weather::DateType::Invalid;
     422         2053 :     if (present(TokenYear)) TokenYear = 0;
     423              :     // Take out separator characters, other extraneous stuff
     424              : 
     425         8212 :     for (int Loop = 0; Loop < NumSingleChars; ++Loop) {
     426         6159 :         size_t Pos = index(CurrentString, SingleChars[Loop]);
     427         8209 :         while (Pos != std::string::npos) {
     428         2050 :             CurrentString[Pos] = ' ';
     429         2050 :             Pos = index(CurrentString, SingleChars[Loop]);
     430              :         }
     431              :     }
     432              : 
     433        14371 :     for (int Loop = 0; Loop < NumDoubleChars; ++Loop) {
     434        12318 :         size_t Pos = index(CurrentString, DoubleChars[Loop]);
     435        12320 :         while (Pos != std::string::npos) {
     436            2 :             CurrentString.replace(Pos, 2, "  ");
     437            2 :             Pos = index(CurrentString, DoubleChars[Loop]);
     438            2 :             WkDayInMonth = true;
     439              :         }
     440              :     }
     441              : 
     442         2053 :     strip(CurrentString);
     443         2053 :     if (CurrentString == BlankString) {
     444            0 :         ShowSevereError(state, format("Invalid date field={}", String));
     445            0 :         ErrorsFound = true;
     446              :     } else {
     447         2053 :         int Loop = 0;
     448         2053 :         bool errFlag = false;
     449              :         int NumField1;
     450              :         int NumField2;
     451              :         int NumField3;
     452         6162 :         while (Loop < 3) { // Max of 3 fields
     453         6159 :             if (CurrentString == BlankString) break;
     454         4109 :             size_t Pos = index(CurrentString, ' ');
     455         4109 :             ++Loop;
     456         4109 :             if (Pos == std::string::npos) Pos = CurrentString.length();
     457         4109 :             Fields(Loop) = CurrentString.substr(0, Pos);
     458         4109 :             CurrentString.erase(0, Pos);
     459         4109 :             strip(CurrentString);
     460              :         }
     461         2053 :         if (not_blank(CurrentString)) {
     462            0 :             ShowSevereError(state, format("Invalid date field={}", String));
     463            0 :             ErrorsFound = true;
     464         2053 :         } else if (Loop == 2) {
     465              :             // Field must be Day Month or Month Day (if both numeric, mon / day)
     466         2050 :             InternalError = false;
     467         2050 :             NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     468         2050 :             if (errFlag) {
     469              :                 // Month day, but first field is not numeric, 2nd must be
     470            4 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     471            4 :                 if (errFlag) {
     472            0 :                     ShowSevereError(state, format("Invalid date field={}", String));
     473            0 :                     InternalError = true;
     474              :                 } else {
     475            4 :                     TokenDay = NumField2;
     476              :                 }
     477            4 :                 TokenMonth = Util::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
     478            4 :                 ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     479            4 :                 if (!InternalError) {
     480            4 :                     DateType = Weather::DateType::MonthDay;
     481              :                 } else {
     482            0 :                     ErrorsFound = true;
     483              :                 }
     484              :             } else {
     485              :                 // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
     486         2046 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     487         2046 :                 if (!errFlag) {
     488         2046 :                     TokenMonth = NumField1;
     489         2046 :                     TokenDay = NumField2;
     490         2046 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     491         2046 :                     if (!InternalError) {
     492         2046 :                         DateType = Weather::DateType::MonthDay;
     493              :                     } else {
     494            0 :                         ErrorsFound = true;
     495              :                     }
     496              :                 } else { // 2nd field was not numeric.  Must be Month
     497            0 :                     TokenDay = NumField1;
     498            0 :                     TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     499            0 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     500            0 :                     if (!InternalError) {
     501            0 :                         DateType = Weather::DateType::MonthDay;
     502            0 :                         NumTokens = 2;
     503              :                     } else {
     504            0 :                         ErrorsFound = true;
     505              :                     }
     506              :                 }
     507              :             }
     508            3 :         } else if (Loop == 3) {
     509              :             // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
     510            3 :             if (WkDayInMonth) {
     511            1 :                 NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     512            1 :                 if (!errFlag) { // the expected result
     513            1 :                     TokenDay = NumField1;
     514            1 :                     TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     515            1 :                     if (TokenWeekday == 0) {
     516            0 :                         TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     517            0 :                         TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     518            0 :                         if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     519              :                     } else {
     520            1 :                         TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     521            1 :                         if (TokenMonth == 0) InternalError = true;
     522              :                     }
     523            1 :                     DateType = Weather::DateType::NthDayInMonth;
     524            1 :                     NumTokens = 3;
     525            1 :                     if (TokenDay < 0 || TokenDay > 5) InternalError = true;
     526              :                 } else { // first field was not numeric....
     527            0 :                     if (Fields(1) == "LA") {
     528            0 :                         DateType = Weather::DateType::LastDayInMonth;
     529            0 :                         NumTokens = 3;
     530            0 :                         TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     531            0 :                         if (TokenWeekday == 0) {
     532            0 :                             TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     533            0 :                             TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     534            0 :                             if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     535              :                         } else {
     536            0 :                             TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     537            0 :                             if (TokenMonth == 0) InternalError = true;
     538              :                         }
     539              :                     } else { // error....
     540            0 :                         ShowSevereError(state, format("First date field not numeric, field={}", String));
     541              :                     }
     542              :                 }
     543              :             } else { // mm/dd/yyyy or yyyy/mm/dd
     544            2 :                 NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     545            2 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     546            2 :                 NumField3 = int(Util::ProcessNumber(Fields(3), errFlag));
     547            2 :                 DateType = Weather::DateType::MonthDay;
     548              :                 // error detection later..
     549            2 :                 if (NumField1 > 100) {
     550            0 :                     if (present(TokenYear)) {
     551            0 :                         TokenYear = NumField1;
     552              :                     }
     553            0 :                     TokenMonth = NumField2;
     554            0 :                     TokenDay = NumField3;
     555            2 :                 } else if (NumField3 > 100) {
     556            2 :                     if (present(TokenYear)) {
     557            2 :                         TokenYear = NumField3;
     558              :                     }
     559            2 :                     TokenMonth = NumField1;
     560            2 :                     TokenDay = NumField2;
     561              :                 }
     562              :             }
     563              :         } else {
     564              :             // Not enough or too many fields
     565            0 :             ShowSevereError(state, format("Invalid date field={}", String));
     566            0 :             ErrorsFound = true;
     567              :         }
     568              :     }
     569              : 
     570         2053 :     if (InternalError) {
     571            0 :         DateType = Weather::DateType::Invalid;
     572            0 :         ErrorsFound = true;
     573              :     }
     574         2053 : }
     575              : 
     576         2050 : void ValidateMonthDay(EnergyPlusData &state,
     577              :                       std::string const &String, // REAL(r64) string being processed
     578              :                       int const Day,
     579              :                       int const Month,
     580              :                       bool &ErrorsFound)
     581              : {
     582              : 
     583              :     // SUBROUTINE INFORMATION:
     584              :     //       AUTHOR         Linda Lawrie
     585              :     //       DATE WRITTEN   August 2000
     586              : 
     587              :     // PURPOSE OF THIS SUBROUTINE:
     588              :     // This subroutine validates a potential Day, Month values, produces an error
     589              :     // message when not valid, and sets error flag.
     590              : 
     591              :     // SUBROUTINE PARAMETER DEFINITIONS:
     592              :     static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     593              : 
     594         2050 :     bool InternalError = false;
     595         2050 :     if (Month < 1 || Month > 12) InternalError = true;
     596         2050 :     if (!InternalError) {
     597         2050 :         if (Day < 1 || Day > EndMonthDay[Month - 1]) InternalError = true;
     598              :     }
     599         2050 :     if (InternalError) {
     600            0 :         ShowSevereError(state, format("Invalid Month Day date format={}", String));
     601            0 :         ErrorsFound = true;
     602              :     } else {
     603         2050 :         ErrorsFound = false;
     604              :     }
     605         2050 : }
     606              : 
     607        20743 : int OrdinalDay(int const Month,        // Month, 1..12
     608              :                int const Day,          // Day of Month, not validated by month
     609              :                int const LeapYearValue // 1 if leap year indicated, 0 if not
     610              : )
     611              : {
     612              : 
     613              :     // FUNCTION INFORMATION:
     614              :     //       AUTHOR         Linda K. Lawrie
     615              :     //       DATE WRITTEN   September 1997
     616              :     //       RE-ENGINEERED  from JDAYF in BLAST/IBLAST
     617              : 
     618              :     // PURPOSE OF THIS SUBROUTINE:
     619              :     // This subroutine returns the appropriate Julian Day value for the input
     620              :     // Month and Day.
     621              : 
     622              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     623              :     static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     624              :     // End day numbers of each month (without Leap Year)
     625              : 
     626        20743 :     if (Month == 1) {
     627              :         //                                       CASE 1: JANUARY
     628         4182 :         return Day;
     629              : 
     630        16561 :     } else if (Month == 2) {
     631              :         //                                       CASE 2: FEBRUARY
     632          563 :         return Day + EndDayofMonth[0];
     633              : 
     634        15998 :     } else if ((Month >= 3) && (Month <= 12)) {
     635              :         //                                       CASE 3: REMAINING MONTHS
     636        15998 :         return Day + EndDayofMonth[Month - 2] + LeapYearValue;
     637              : 
     638              :     } else {
     639            0 :         return 0;
     640              :     }
     641              : }
     642              : 
     643        35136 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
     644              : {
     645              : 
     646              :     // SUBROUTINE INFORMATION:
     647              :     //       AUTHOR         Linda Lawrie
     648              :     //       DATE WRITTEN   December 1999
     649              : 
     650              :     // PURPOSE OF THIS SUBROUTINE:
     651              :     // This subroutine performs and inverse Julian Day
     652              :     // calculation, using an input JulianDay and returning
     653              :     // appropriate Month and Day.
     654              : 
     655              :     // SUBROUTINE PARAMETER DEFINITIONS:
     656              :     static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     657              : 
     658              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     659              :     int WMonth;
     660              :     int LeapAddPrev;
     661              :     int LeapAddCur;
     662              : 
     663        35136 :     if (Number < 0 || Number > 366) return;
     664       228864 :     for (WMonth = 1; WMonth <= 12; ++WMonth) {
     665       228864 :         if (WMonth == 1) {
     666        35136 :             LeapAddPrev = 0;
     667        35136 :             LeapAddCur = 0;
     668       193728 :         } else if (WMonth == 2) {
     669        32160 :             LeapAddPrev = 0;
     670        32160 :             LeapAddCur = LeapYr;
     671              :         } else {
     672       161568 :             LeapAddPrev = LeapYr;
     673       161568 :             LeapAddCur = LeapYr;
     674              :         }
     675       228864 :         if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) break;
     676              :     }
     677        35136 :     PMonth = WMonth;
     678        35136 :     PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
     679              : }
     680              : 
     681          130 : bool BetweenDateHoursLeftInclusive(
     682              :     int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
     683              : {
     684          130 :     Real64 TestRatioOfDay = TestHour / 24.0;
     685          130 :     Real64 StartRatioOfDay = StartHour / 24.0;
     686          130 :     Real64 EndRatioOfDay = EndHour / 24.0;
     687              : 
     688          130 :     if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
     689          129 :         return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
     690              :     } else { // EndDate < StartDate
     691            1 :         return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
     692              :     }
     693              : }
     694              : 
     695            0 : bool BetweenDates(int const TestDate,  // Date to test
     696              :                   int const StartDate, // Start date in sequence
     697              :                   int const EndDate    // End date in sequence
     698              : )
     699              : {
     700              : 
     701              :     // FUNCTION INFORMATION:
     702              :     //       AUTHOR         Linda K. Lawrie
     703              :     //       DATE WRITTEN   June 2000
     704              : 
     705              :     // PURPOSE OF THIS FUNCTION:
     706              :     // This function returns true if the TestDate is between
     707              :     // (StartDate <= TestDate <= EndDate).
     708              : 
     709              :     // METHODOLOGY EMPLOYED:
     710              :     // The input dates are Julian Day format, year is irrelevant.
     711              :     // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
     712              :     // this routine accommodates.
     713              : 
     714              :     // REFERENCES:
     715              :     // Adapted from BLAST BTWEEN function.
     716              : 
     717            0 :     bool BetweenDates = false; // Default case
     718              : 
     719            0 :     if (StartDate <= EndDate) { // Start Date <= End Date
     720            0 :         if (TestDate >= StartDate && TestDate <= EndDate) BetweenDates = true;
     721              :     } else { // EndDate < StartDate
     722            0 :         if (TestDate <= EndDate || TestDate >= StartDate) BetweenDates = true;
     723              :     }
     724              : 
     725            0 :     return BetweenDates;
     726              : }
     727              : 
     728          423 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
     729              : {
     730              : 
     731              :     // FUNCTION INFORMATION:
     732              :     //       AUTHOR         Linda K. Lawrie
     733              :     //       DATE WRITTEN   April 2003
     734              : 
     735              :     // PURPOSE OF THIS FUNCTION:
     736              :     // This function creates the current time interval of the system time step.
     737              : 
     738              :     // Using/Aliasing
     739          423 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     740          423 :     Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
     741              : 
     742          423 :     Real64 constexpr FracToMin(60.0);
     743              : 
     744              :     //  ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
     745              :     // CR6902  ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
     746              :     // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
     747          423 :     Real64 ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
     748          423 :     Real64 ActualTimeE = ActualTimeS + TimeStepSys;
     749          423 :     int ActualTimeHrS = int(ActualTimeS);
     750              :     //  ActualTimeHrE=INT(ActualTimeE)
     751          423 :     int ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
     752              : 
     753          423 :     if (ActualTimeMinS == 60) {
     754            0 :         ++ActualTimeHrS;
     755            0 :         ActualTimeMinS = 0;
     756              :     }
     757          423 :     const std::string TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
     758          423 :     Real64 minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
     759              : 
     760          423 :     std::string TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
     761              : 
     762          423 :     if (TimeStmpE[3] == ' ') {
     763           59 :         TimeStmpE[3] = '0';
     764              :     }
     765          846 :     return TimeStmpS + " - " + TimeStmpE;
     766          423 : }
     767              : 
     768              : // returns the Julian date for the first, second, etc. day of week for a given month
     769          173 : int nthDayOfWeekOfMonth(const EnergyPlusData &state,
     770              :                         int const dayOfWeek,  // day of week (Sunday=1, Monday=2, ...)
     771              :                         int const nthTime,    // nth time the day of the week occurs (first monday, third tuesday, ..)
     772              :                         int const monthNumber // January = 1
     773              : )
     774              : {
     775              :     // J. Glazer - August 2017
     776          173 :     int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
     777          173 :     int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
     778          173 :     if (dayOfWeek >= dayOfWeekForFirstDay) {
     779           93 :         return firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
     780              :     } else {
     781           80 :         return firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
     782              :     }
     783              : }
     784              : 
     785        54925 : Real64 SafeDivide(Real64 const a, Real64 const b)
     786              : {
     787              : 
     788              :     // returns a / b while preventing division by zero
     789              : 
     790              :     // Locals
     791        54925 :     Real64 constexpr SMALL(1.E-10);
     792              : 
     793        54925 :     if (std::abs(b) >= SMALL) {
     794        54458 :         return a / b;
     795              :     } else {
     796          467 :         return a / sign(SMALL, b);
     797              :     }
     798              : }
     799              : 
     800      4196042 : void Iterate(Real64 &ResultX,  // ResultX is the final Iteration result passed back to the calling routine
     801              :              Real64 const Tol, // Tolerance for Convergence
     802              :              Real64 const X0,  // Current value of X
     803              :              Real64 const Y0,  // Current value of the function Y(X)
     804              :              Real64 &X1,       // First Previous values of X
     805              :              Real64 &Y1,       // First Previous values of Y(X1)
     806              :              int const Iter,   // Number of iterations
     807              :              int &Cnvg         // Convergence flag  Cnvg = 0:  Not converged
     808              : )
     809              : {
     810              : 
     811              :     // SUBROUTINE INFORMATION:
     812              :     //       AUTHOR         Richard Liesen
     813              :     //       DATE WRITTEN   March 2004
     814              : 
     815              :     // PURPOSE OF THIS SUBROUTINE:
     816              :     // Iteratively solves for the value of X which satisfies Y(X)=0.
     817              :     // The subroutine tests for convergence and provides a new guess for the value of the
     818              :     // independent variable X.
     819              : 
     820              :     // REFERENCES:
     821              :     // Linear Correction based on the RegulaFalsi routine in EnergyPlus
     822              : 
     823              :     // SUBROUTINE PARAMETER DEFINITIONS:
     824      4196042 :     Real64 constexpr small(1.e-9); // Small Number used to approximate zero
     825      4196042 :     Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
     826              : 
     827              :     // Check for convergence by comparing change in X
     828      4196042 :     if (Iter != 1) {
     829      3634598 :         if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
     830       561434 :             ResultX = X0;
     831       561434 :             Cnvg = 1;
     832       561434 :             return;
     833              :         }
     834              :     }
     835              : 
     836              :     // Not converged.
     837      3634608 :     Cnvg = 0;
     838      3634608 :     if (Iter == 1) {
     839              : 
     840              :         // New guess is specified by Perturb
     841       561444 :         if (std::abs(X0) > small) {
     842       560937 :             ResultX = X0 * (1.0 + Perturb);
     843              :         } else {
     844          507 :             ResultX = Perturb;
     845              :         }
     846              : 
     847              :     } else {
     848              : 
     849              :         // New guess calculated from LINEAR FIT of most recent two points
     850      3073164 :         Real64 DY = Y0 - Y1;
     851      3073164 :         if (std::abs(DY) < small) {
     852          186 :             DY = small;
     853              :         }
     854              :         // new estimation
     855              : 
     856      3073164 :         ResultX = (Y0 * X1 - Y1 * X0) / DY;
     857              :     }
     858              : 
     859      3634608 :     X1 = X0;
     860      3634608 :     Y1 = Y0;
     861              : }
     862              : 
     863           21 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
     864              : {
     865              : 
     866              :     // FUNCTION INFORMATION:
     867              :     //       AUTHOR         Linda K. Lawrie
     868              :     //       DATE WRITTEN   September 2001
     869              : 
     870              :     // PURPOSE OF THIS FUNCTION:
     871              :     // This function looks up a number(integer) in a similar list of
     872              :     // items and returns the index of the item in the list, if found.
     873              : 
     874              :     // Argument array dimensioning
     875           21 :     ListOfItems.dim(_);
     876              : 
     877           21 :     for (int Count = 1; Count <= NumItems; ++Count) {
     878           21 :         if (WhichNumber == ListOfItems(Count)) {
     879           21 :             return Count;
     880              :         }
     881              :     }
     882              : 
     883            0 :     return 0;
     884              : }
     885              : 
     886         8252 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
     887              :                        int &Month,     // month in integer format (1-12)
     888              :                        int &Day,       // day in integer format (1-31)
     889              :                        int &Hour,      // hour in integer format (1-24)
     890              :                        int &Minute     // minute in integer format (0:59)
     891              : )
     892              : {
     893              : 
     894              :     // SUBROUTINE INFORMATION:
     895              :     //       AUTHOR         Linda Lawrie
     896              :     //       DATE WRITTEN   March 2000
     897              : 
     898              :     // PURPOSE OF THIS SUBROUTINE:
     899              :     // This subroutine decodes the "packed" integer representation of
     900              :     // the Month, Day, Hour, and Minute.  Packed integers are used to
     901              :     // save memory allocation.  Original idea for this routine is contained
     902              :     // in DECMDH, BLAST code, by Jean Baugh.
     903              : 
     904              :     // METHODOLOGY EMPLOYED:
     905              :     // Using maximum integer concept the original date can be decoded
     906              :     // from the packed single word.  This relies on 4 byte integer representation
     907              :     // as a minimum (capable of representing up to 2,147,483,647).
     908              : 
     909              :     // SUBROUTINE PARAMETER DEFINITIONS:
     910              :     static constexpr int DecMon(100 * 100 * 100);
     911              :     static constexpr int DecDay(100 * 100);
     912              :     static constexpr int DecHr(100);
     913              : 
     914         8252 :     int TmpItem = Item;
     915         8252 :     Month = TmpItem / DecMon;
     916         8252 :     TmpItem = (TmpItem - Month * DecMon);
     917         8252 :     Day = TmpItem / DecDay;
     918         8252 :     TmpItem -= Day * DecDay;
     919         8252 :     Hour = TmpItem / DecHr;
     920         8252 :     Minute = mod(TmpItem, DecHr);
     921         8252 : }
     922              : 
     923        41279 : void EncodeMonDayHrMin(int &Item,       // word containing encoded month, day, hour, minute
     924              :                        int const Month, // month in integer format (1:12)
     925              :                        int const Day,   // day in integer format (1:31)
     926              :                        int const Hour,  // hour in integer format (1:24)
     927              :                        int const Minute // minute in integer format (0:59)
     928              : )
     929              : {
     930              : 
     931              :     // SUBROUTINE INFORMATION:
     932              :     //       AUTHOR         Linda Lawrie
     933              :     //       DATE WRITTEN   March 2000
     934              : 
     935              :     // PURPOSE OF THIS SUBROUTINE:
     936              :     // This subroutine encodes the "packed" integer representation of
     937              :     // the Month, Day, Hour, and Minute.  Packed integers are used to
     938              :     // save memory allocation.  Original idea for this routine is contained
     939              :     // in DECMDH, BLAST code, by Jean Baugh.
     940              : 
     941              :     // METHODOLOGY EMPLOYED:
     942              :     // Using maximum integer concept the original date can be decoded
     943              :     // from the packed single word.  This relies on 4 byte integer representation
     944              :     // as a minimum (capable of representing up to 2,147,483,647).
     945              : 
     946        41279 :     Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
     947        41279 : }
     948              : 
     949           16 : std::string CreateTimeString(Real64 const Time) // Time in seconds
     950              : {
     951              : 
     952              :     // FUNCTION INFORMATION:
     953              :     //       AUTHOR         Dimitri Curtil
     954              :     //       DATE WRITTEN   January 2005
     955              : 
     956              :     // PURPOSE OF THIS FUNCTION:
     957              :     // This function creates the time stamp string from the time value specified in seconds.
     958              :     // Inspired by similar function CreateSysTimeIntervalString() in General.cc
     959              :     // However, this function provides better accuracy for sub-minute time steps
     960              :     // by also showing information down to the 10th of a second.
     961              :     // Note that Time is expected to be specified in REAL(r64).
     962              : 
     963              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     964              :     int Hours;      // Number of hours <= 24
     965              :     int Minutes;    // Remaining minutes < 60
     966              :     Real64 Seconds; // Remaining seconds < 60
     967              : 
     968           16 :     ParseTime(Time, Hours, Minutes, Seconds);
     969              : 
     970              :     // TimeStamp written with formatting
     971              :     // "hh:mm:ss.s"
     972           16 :     return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
     973              : }
     974              : 
     975          396 : void ParseTime(Real64 const Time, // Time value in seconds
     976              :                int &Hours,        // Number of hours
     977              :                int &Minutes,      // Number of minutes < 60
     978              :                Real64 &Seconds    // Number of seconds < 60
     979              : )
     980              : {
     981              :     // FUNCTION INFORMATION:
     982              :     //       AUTHOR         Dimitri Curtil
     983              :     //       DATE WRITTEN   January 2005
     984              : 
     985              :     // PURPOSE OF THIS FUNCTION:
     986              :     // This subroutine decomposes a time value specified in seconds
     987              :     // into a triplet { hours : minutes : seconds } such that
     988              :     // - minutes < 60
     989              :     // - seconds < 60
     990              : 
     991              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     992          396 :     int constexpr MinToSec = 60;
     993          396 :     int constexpr HourToSec = 60 * 60;
     994              : 
     995              :     // Get number of hours
     996              :     // This might undershoot the actual number of hours. See DO WHILE loop.
     997          396 :     Hours = int(Time) / HourToSec;
     998              : 
     999              :     // Compute remainder in seconds
    1000          396 :     Real64 Remainder = (Time - Hours * HourToSec);
    1001              : 
    1002              :     // Compute minutes
    1003          396 :     Minutes = int(Remainder) / MinToSec;
    1004              : 
    1005              :     // Compute remainder in seconds
    1006          396 :     Remainder -= Minutes * MinToSec;
    1007              : 
    1008              :     // Compute seconds
    1009          396 :     Seconds = Remainder;
    1010          396 : }
    1011              : 
    1012         2771 : void ScanForReports(EnergyPlusData &state,
    1013              :                     std::string const &reportName,
    1014              :                     bool &DoReport,
    1015              :                     ObjexxFCL::Optional_string_const ReportKey,
    1016              :                     ObjexxFCL::Optional_string Option1,
    1017              :                     ObjexxFCL::Optional_string Option2)
    1018              : {
    1019              : 
    1020              :     // SUBROUTINE INFORMATION:
    1021              :     //       AUTHOR         Linda Lawrie
    1022              :     //       DATE WRITTEN   March 2009
    1023              : 
    1024              :     // PURPOSE OF THIS SUBROUTINE:
    1025              :     // This routine scans for the global "reports" settings, such as Variable Dictionary,
    1026              :     // Surfaces (and options), Constructions, etc.
    1027              : 
    1028              :     // METHODOLOGY EMPLOYED:
    1029              :     // First time routine is called, all the viable combinations/settings for the reports are
    1030              :     // stored in SAVEd variables.  Later callings will retrieve those.
    1031              : 
    1032         2771 :     if (state.dataGeneral->GetReportInput) {
    1033              : 
    1034              :         int NumNames;
    1035              :         int NumNumbers;
    1036              :         int IOStat;
    1037              :         int RepNum;
    1038              : 
    1039         1199 :         auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    1040         1199 :         cCurrentModuleObject = "Output:Surfaces:List";
    1041              : 
    1042         1199 :         int NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1043              : 
    1044              :         enum
    1045              :         {
    1046              :             EMPTY,
    1047              :             LINES,
    1048              :             VERTICES,
    1049              :             DETAILS,
    1050              :             DETAILSWITHVERTICES,
    1051              :             COSTINFO,
    1052              :             VIEWFACTORINFO,
    1053              :             DECAYCURVESFROMCOMPONENTLOADSSUMMARY
    1054              :         };
    1055            0 :         std::map<std::string, int> localMap = {{"", EMPTY},
    1056            0 :                                                {"LINES", LINES},
    1057            0 :                                                {"VERTICES", VERTICES},
    1058            0 :                                                {"DETAILS", DETAILS},
    1059            0 :                                                {"DETAILED", DETAILS},
    1060            0 :                                                {"DETAIL", DETAILS},
    1061            0 :                                                {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
    1062            0 :                                                {"DETAILVERTICES", DETAILSWITHVERTICES},
    1063            0 :                                                {"COSTINFO", COSTINFO},
    1064            0 :                                                {"VIEWFACTORINFO", VIEWFACTORINFO},
    1065        15587 :                                                {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
    1066              : 
    1067         1200 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1068            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1069              :                                                                      cCurrentModuleObject,
    1070              :                                                                      RepNum,
    1071            1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1072              :                                                                      NumNames,
    1073            1 :                                                                      state.dataIPShortCut->rNumericArgs,
    1074              :                                                                      NumNumbers,
    1075              :                                                                      IOStat,
    1076            1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1077            1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1078            1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1079            1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1080              : 
    1081              :             try {
    1082            1 :                 int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
    1083            1 :                 switch (value) {
    1084            0 :                 case LINES:
    1085            0 :                     state.dataGeneral->LineRpt = true;
    1086            0 :                     state.dataGeneral->LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1087            0 :                     break;
    1088            0 :                 case VERTICES:
    1089            0 :                     state.dataGeneral->SurfVert = true;
    1090            0 :                     break;
    1091            1 :                 case DETAILS:
    1092            1 :                     state.dataGeneral->SurfDet = true;
    1093            1 :                     break;
    1094            0 :                 case DETAILSWITHVERTICES:
    1095            0 :                     state.dataGeneral->SurfDetWVert = true;
    1096            0 :                     break;
    1097            0 :                 case COSTINFO:
    1098              :                     //   Custom case for reporting surface info for cost estimates (for first costs in optimizing)
    1099            0 :                     state.dataGeneral->CostInfo = true;
    1100            0 :                     break;
    1101            0 :                 case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
    1102            0 :                     state.dataGeneral->ViewFactorInfo = true;
    1103            0 :                     state.dataGeneral->ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1104            0 :                     break;
    1105            0 :                 case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
    1106              :                                                            // load component report appear in the EIO file
    1107            0 :                     state.dataGlobal->ShowDecayCurvesInEIO = true;
    1108            0 :                     break;
    1109            0 :                 default: // including empty
    1110            0 :                     ShowWarningError(state, format("{}: No {} supplied.", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1)));
    1111            0 :                     ShowContinueError(state,
    1112              :                                       R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1113              :                 }
    1114            0 :             } catch (int e) {
    1115            0 :                 ShowWarningError(state,
    1116            0 :                                  format("{}: Invalid {}=\"{}\" supplied.",
    1117              :                                         cCurrentModuleObject,
    1118            0 :                                         state.dataIPShortCut->cAlphaFieldNames(1),
    1119            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    1120            0 :                 ShowContinueError(state,
    1121              :                                   R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1122            0 :             }
    1123              :         }
    1124              : 
    1125         1199 :         cCurrentModuleObject = "Output:Surfaces:Drawing";
    1126              : 
    1127         1199 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1128         1222 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1129           46 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1130              :                                                                      cCurrentModuleObject,
    1131              :                                                                      RepNum,
    1132           23 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1133              :                                                                      NumNames,
    1134           23 :                                                                      state.dataIPShortCut->rNumericArgs,
    1135              :                                                                      NumNumbers,
    1136              :                                                                      IOStat,
    1137           23 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1138           23 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1139           23 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1140           23 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1141              : 
    1142              :             ReportType checkReportType =
    1143           23 :                 static_cast<ReportType>(getEnumValue(ReportTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
    1144              : 
    1145           23 :             switch (checkReportType) {
    1146            0 :             case ReportType::DXF: {
    1147            0 :                 state.dataGeneral->DXFReport = true;
    1148            0 :                 state.dataGeneral->DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1149            0 :                 state.dataGeneral->DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1150            0 :             } break;
    1151           23 :             case ReportType::DXFWireFrame: {
    1152           23 :                 state.dataGeneral->DXFWFReport = true;
    1153           23 :                 state.dataGeneral->DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1154           23 :                 state.dataGeneral->DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1155           23 :             } break;
    1156            0 :             case ReportType::VRML: {
    1157            0 :                 state.dataGeneral->VRMLReport = true;
    1158            0 :                 state.dataGeneral->VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1159            0 :                 state.dataGeneral->VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1160            0 :             } break;
    1161            0 :             default:
    1162            0 :                 break;
    1163              :             }
    1164              :         }
    1165              : 
    1166         2398 :         RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
    1167         1199 :         if (RepNum > 0) {
    1168            0 :             state.dataGeneral->VarDict = true;
    1169            0 :             state.dataGeneral->VarDictOption1 = "REGULAR";
    1170            0 :             state.dataGeneral->VarDictOption2 = "";
    1171              :         }
    1172              : 
    1173         1199 :         cCurrentModuleObject = "Output:VariableDictionary";
    1174              : 
    1175         1199 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1176         1227 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1177           56 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1178              :                                                                      cCurrentModuleObject,
    1179              :                                                                      RepNum,
    1180           28 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1181              :                                                                      NumNames,
    1182           28 :                                                                      state.dataIPShortCut->rNumericArgs,
    1183              :                                                                      NumNumbers,
    1184              :                                                                      IOStat,
    1185           28 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1186           28 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1187           28 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1188           28 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1189           28 :             state.dataGeneral->VarDict = true;
    1190           28 :             state.dataGeneral->VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
    1191           28 :             state.dataGeneral->VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
    1192              :         }
    1193              : 
    1194         1199 :         cCurrentModuleObject = "Output:Constructions";
    1195         1199 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1196         1225 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1197           52 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1198              :                                                                      cCurrentModuleObject,
    1199              :                                                                      RepNum,
    1200           26 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1201              :                                                                      NumNames,
    1202           26 :                                                                      state.dataIPShortCut->rNumericArgs,
    1203              :                                                                      NumNumbers,
    1204              :                                                                      IOStat,
    1205           26 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1206           26 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1207           26 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1208           26 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1209           26 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
    1210           25 :                 state.dataGeneral->Constructions = true;
    1211            1 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
    1212            1 :                 state.dataGeneral->Materials = true;
    1213              :             }
    1214           26 :             if (NumNames > 1) {
    1215            1 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
    1216            0 :                     state.dataGeneral->Constructions = true;
    1217            1 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
    1218            1 :                     state.dataGeneral->Materials = true;
    1219              :                 }
    1220              :             }
    1221              :         }
    1222              : 
    1223         1199 :         cCurrentModuleObject = "Output:EnergyManagementSystem";
    1224         1199 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1225         1209 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1226           20 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1227              :                                                                      cCurrentModuleObject,
    1228              :                                                                      RepNum,
    1229           10 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1230              :                                                                      NumNames,
    1231           10 :                                                                      state.dataIPShortCut->rNumericArgs,
    1232              :                                                                      NumNumbers,
    1233              :                                                                      IOStat,
    1234           10 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1235           10 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1236           10 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1237           10 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1238              : 
    1239           10 :             state.dataGeneral->EMSoutput = true;
    1240              : 
    1241           10 :             AvailRpt CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
    1242           10 :             state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1243           10 :             state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
    1244              : 
    1245           10 :             CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
    1246           10 :             state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1247           10 :             state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
    1248              : 
    1249              :             ERLdebugOutputLevel CheckERLlevel =
    1250           10 :                 static_cast<ERLdebugOutputLevel>(getEnumValue(ERLdebugOutputLevelNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    1251           10 :             state.dataRuntimeLang->OutputEMSErrors =
    1252           10 :                 (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1253           10 :             state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1254              :         }
    1255              : 
    1256         1199 :         state.dataGeneral->GetReportInput = false;
    1257         1199 :     }
    1258              : 
    1259              :     // Process the Scan Request
    1260         2771 :     DoReport = false;
    1261              : 
    1262         2771 :     ReportName rptName = static_cast<ReportName>(getEnumValue(ReportNamesUC, Util::makeUPPER(Util::makeUPPER(reportName))));
    1263         2771 :     switch (rptName) {
    1264          494 :     case ReportName::Constructions: {
    1265          494 :         if (present(ReportKey)) {
    1266          494 :             if (Util::SameString(ReportKey(), "Constructions")) DoReport = state.dataGeneral->Constructions;
    1267          494 :             if (Util::SameString(ReportKey(), "Materials")) DoReport = state.dataGeneral->Materials;
    1268              :         }
    1269          494 :     } break;
    1270          248 :     case ReportName::Viewfactorinfo: {
    1271          248 :         DoReport = state.dataGeneral->ViewFactorInfo;
    1272          248 :         if (present(Option1)) Option1 = state.dataGeneral->ViewRptOption1;
    1273          248 :     } break;
    1274           73 :     case ReportName::Variabledictionary: {
    1275           73 :         DoReport = state.dataGeneral->VarDict;
    1276           73 :         if (present(Option1)) Option1 = state.dataGeneral->VarDictOption1;
    1277           73 :         if (present(Option2)) Option2 = state.dataGeneral->VarDictOption2;
    1278              :         //    CASE ('SCHEDULES')
    1279              :         //     DoReport=SchRpt
    1280              :         //      IF (PRESENT(Option1)) Option1=SchRptOption
    1281           73 :     } break;
    1282          707 :     case ReportName::Surfaces: {
    1283          707 :         RptKey rptKey = static_cast<RptKey>(getEnumValue(RptKeyNamesUC, Util::makeUPPER(ReportKey())));
    1284          707 :         switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
    1285           73 :         case RptKey::Costinfo: {
    1286           73 :             DoReport = state.dataGeneral->CostInfo;
    1287           73 :         } break;
    1288           73 :         case RptKey::DXF: {
    1289           73 :             DoReport = state.dataGeneral->DXFReport;
    1290           73 :             if (present(Option1)) Option1 = state.dataGeneral->DXFOption1;
    1291           73 :             if (present(Option2)) Option2 = state.dataGeneral->DXFOption2;
    1292           73 :         } break;
    1293           73 :         case RptKey::DXFwireframe: {
    1294           73 :             DoReport = state.dataGeneral->DXFWFReport;
    1295           73 :             if (present(Option1)) Option1 = state.dataGeneral->DXFWFOption1;
    1296           73 :             if (present(Option2)) Option2 = state.dataGeneral->DXFWFOption2;
    1297           73 :         } break;
    1298           73 :         case RptKey::VRML: {
    1299           73 :             DoReport = state.dataGeneral->VRMLReport;
    1300           73 :             if (present(Option1)) Option1 = state.dataGeneral->VRMLOption1;
    1301           73 :             if (present(Option2)) Option2 = state.dataGeneral->VRMLOption2;
    1302           73 :         } break;
    1303           73 :         case RptKey::Vertices: {
    1304           73 :             DoReport = state.dataGeneral->SurfVert;
    1305           73 :         } break;
    1306          196 :         case RptKey::Details: {
    1307          196 :             DoReport = state.dataGeneral->SurfDet;
    1308          196 :         } break;
    1309           73 :         case RptKey::DetailsWithVertices: {
    1310           73 :             DoReport = state.dataGeneral->SurfDetWVert;
    1311           73 :         } break;
    1312           73 :         case RptKey::Lines: {
    1313           73 :             DoReport = state.dataGeneral->LineRpt;
    1314           73 :             if (present(Option1)) Option1 = state.dataGeneral->LineRptOption1;
    1315           73 :         } break;
    1316            0 :         default:
    1317            0 :             break;
    1318              :         }
    1319          707 :     } break;
    1320         1249 :     case ReportName::Energymanagementsystem: {
    1321         1249 :         DoReport = state.dataGeneral->EMSoutput;
    1322         1249 :     } break;
    1323            0 :     default:
    1324            0 :         break;
    1325              :     }
    1326         3970 : }
    1327              : 
    1328           27 : void CheckCreatedZoneItemName(EnergyPlusData &state,
    1329              :                               std::string_view const calledFrom,              // routine called from
    1330              :                               std::string const &CurrentObject,               // object being parsed
    1331              :                               std::string const &ZoneName,                    // Zone Name associated
    1332              :                               std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
    1333              :                               std::string const &ItemName,                    // Item name (People, Lights, etc object)
    1334              :                               Array1_string const &ItemNames,                 // Item Names to check for duplication
    1335              :                               int const NumItems,                             // Number of items in ItemNames array
    1336              :                               std::string &ResultName,                        // Resultant name
    1337              :                               bool &errFlag                                   // Error flag set to true if error found here.
    1338              : )
    1339              : {
    1340              : 
    1341              :     // SUBROUTINE INFORMATION:
    1342              :     //       AUTHOR         Linda Lawrie
    1343              :     //       DATE WRITTEN   December 2012
    1344              : 
    1345              :     // PURPOSE OF THIS SUBROUTINE:
    1346              :     // This routine checks "global" objects (that is, ones with ZoneList used in the name
    1347              :     // specification) along with a specific name for the current object for length and duplication
    1348              :     // with previous objects of that class.
    1349              : 
    1350           27 :     errFlag = false;
    1351           27 :     std::string::size_type const ItemNameLength = len(ItemName);
    1352           27 :     std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
    1353           27 :     ResultName = ZoneName + ' ' + ItemName;
    1354           27 :     bool TooLong = false;
    1355           27 :     if (ItemLength > Constant::MaxNameLength) {
    1356            0 :         ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
    1357            0 :         ShowContinueError(state, format("Object Name=\"{}\".", ItemName));
    1358            0 :         ShowContinueError(state, format("ZoneList/Zone Name=\"{}\".", ZoneName));
    1359            0 :         ShowContinueError(state,
    1360            0 :                           format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, Constant::MaxNameLength));
    1361            0 :         ShowContinueError(state,
    1362            0 :                           format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
    1363            0 :                                  MaxZoneNameLength + 1 + ItemNameLength - Constant::MaxNameLength));
    1364            0 :         ShowContinueError(state, format("name that will be used (may be needed in reporting)=\"{}\".", ResultName));
    1365            0 :         TooLong = true;
    1366              :     }
    1367              : 
    1368           27 :     int FoundItem = Util::FindItemInList(ResultName, ItemNames, NumItems);
    1369              : 
    1370           27 :     if (FoundItem != 0) {
    1371            0 :         ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
    1372            0 :         ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
    1373            0 :         if (TooLong) ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
    1374            0 :         ResultName = "xxxxxxx";
    1375            0 :         errFlag = true;
    1376              :     }
    1377           27 : }
    1378              : 
    1379           18 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
    1380              : {
    1381              :     int currentDate;
    1382           18 :     int reportStartDate = state.dataWeather->ReportPeriodInput(periodIdx).startJulianDate;
    1383           18 :     int reportStartHour = state.dataWeather->ReportPeriodInput(periodIdx).startHour;
    1384           18 :     if (state.dataWeather->ReportPeriodInput(periodIdx).startYear > 0) {
    1385            0 :         currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1386              :     } else {
    1387           18 :         currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1388              :     }
    1389           18 :     return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
    1390              : }
    1391              : 
    1392           62 : void findReportPeriodIdx(EnergyPlusData &state,
    1393              :                          const Array1D<Weather::ReportPeriodData> &ReportPeriodInputData,
    1394              :                          const int nReportPeriods,
    1395              :                          Array1D_bool &inReportPeriodFlags)
    1396              : {
    1397              :     // return an array of flags, indicating whether the current time is in reporting period i
    1398              :     int currentDate;
    1399          186 :     for (int i = 1; i <= nReportPeriods; i++) {
    1400          124 :         int reportStartDate = ReportPeriodInputData(i).startJulianDate;
    1401          124 :         int reportStartHour = ReportPeriodInputData(i).startHour;
    1402          124 :         int reportEndDate = ReportPeriodInputData(i).endJulianDate;
    1403          124 :         int reportEndHour = ReportPeriodInputData(i).endHour;
    1404          124 :         if (ReportPeriodInputData(i).startYear > 0) {
    1405            0 :             currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1406              :         } else {
    1407          124 :             currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1408              :         }
    1409          124 :         if (General::BetweenDateHoursLeftInclusive(
    1410          124 :                 currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
    1411           56 :             inReportPeriodFlags(i) = true;
    1412              :         }
    1413              :     }
    1414           62 : }
    1415              : 
    1416          273 : Real64 rotAzmDiffDeg(Real64 AzmA, Real64 AzmB)
    1417              : {
    1418              :     // This function takes two (azimuth) angles in Degree(s),
    1419              :     // and returns the rotational angle difference in Degree(s).
    1420              : 
    1421          273 :     Real64 diff = AzmB - AzmA;
    1422          273 :     if (diff > 180.0) {
    1423           16 :         diff = 360.0 - diff;
    1424          257 :     } else if (diff < -180.0) {
    1425           12 :         diff = 360.0 + diff;
    1426              :     }
    1427          273 :     return std::abs(diff);
    1428              : }
    1429              : 
    1430              : } // namespace EnergyPlus::General
        

Generated by: LCOV version 2.0-1