LCOV - code coverage report
Current view: top level - EnergyPlus - General.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 485 602 80.6 %
Date: 2024-08-24 18:31:18 Functions: 21 23 91.3 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, 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    15416255 : 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    15416255 :     Real64 constexpr SMALL(1.e-10);
     186    15416255 :     Real64 X0 = X_0;   // present 1st bound
     187    15416255 :     Real64 X1 = X_1;   // present 2nd bound
     188    15416255 :     Real64 XTemp = X0; // new estimate
     189    15416255 :     int NIte = 0;      // number of interations
     190    15416255 :     int AltIte = 0;    // an accounter used for Alternation choice
     191             : 
     192    15416255 :     Real64 Y0 = f(X0); // f at X0
     193    15416255 :     Real64 Y1 = f(X1); // f at X1
     194             :     // check initial values
     195    15416255 :     if (Y0 * Y1 > 0) {
     196      415371 :         Flag = -2;
     197      415371 :         XRes = X0;
     198      415371 :         return;
     199             :     }
     200    15000884 :     XRes = XTemp;
     201             : 
     202             :     while (true) {
     203             : 
     204    31704654 :         Real64 DY = Y0 - Y1;
     205    31704654 :         if (std::abs(DY) < SMALL) DY = SMALL;
     206    31704654 :         if (std::abs(X1 - X0) < SMALL) {
     207        7988 :             break;
     208             :         }
     209             :         // new estimation
     210    31696666 :         switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolver) {
     211    31691160 :         case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
     212    31691160 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     213    31691160 :             break;
     214             :         }
     215           0 :         case HVACSystemRootSolverAlgorithm::Bisection: {
     216           0 :             XTemp = (X1 + X0) / 2.0;
     217           0 :             break;
     218             :         }
     219        5506 :         case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
     220        5506 :             if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     221          71 :                 XTemp = (X1 + X0) / 2.0;
     222             :             } else {
     223        5435 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     224             :             }
     225        5506 :             break;
     226             :         }
     227           0 :         case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
     228           0 :             if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     229           0 :                 XTemp = (X1 + X0) / 2.0;
     230             :             } else {
     231           0 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     232             :             }
     233           0 :             break;
     234             :         }
     235           0 :         case HVACSystemRootSolverAlgorithm::Alternation: {
     236           0 :             if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     237           0 :                 XTemp = (X1 + X0) / 2.0;
     238           0 :                 if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) AltIte = 0;
     239             :             } else {
     240           0 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     241             :             }
     242           0 :             break;
     243             :         }
     244           0 :         default: {
     245           0 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     246             :         }
     247             :         }
     248             : 
     249    31696666 :         Real64 const YTemp = f(XTemp);
     250             : 
     251    31696666 :         ++NIte;
     252    31696666 :         ++AltIte;
     253             : 
     254             :         // check convergence
     255    31696666 :         if (std::abs(YTemp) < Eps) {
     256    14992699 :             Flag = NIte;
     257    14992699 :             XRes = XTemp;
     258    14992699 :             return;
     259             :         };
     260             : 
     261             :         // OK, so we didn't converge, lets check max iterations to see if we should break early
     262    16703967 :         if (NIte > MaxIte) break;
     263             : 
     264             :         // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
     265             :         // and reassign values (only if further iteration required)
     266    16703770 :         if (Y0 < 0.0) {
     267    14590139 :             if (YTemp < 0.0) {
     268     6734606 :                 X0 = XTemp;
     269     6734606 :                 Y0 = YTemp;
     270             :             } else {
     271     7855533 :                 X1 = XTemp;
     272     7855533 :                 Y1 = YTemp;
     273             :             }
     274             :         } else {
     275     2113631 :             if (YTemp < 0.0) {
     276     1304396 :                 X1 = XTemp;
     277     1304396 :                 Y1 = YTemp;
     278             :             } else {
     279      809235 :                 X0 = XTemp;
     280      809235 :                 Y0 = YTemp;
     281             :             }
     282             :         } // ( Y0 < 0 )
     283    16703770 :     }     // Cont
     284             : 
     285             :     // if we make it here we haven't converged, so just set the flag and leave
     286        8185 :     Flag = -1;
     287        8185 :     XRes = XTemp;
     288             : }
     289             : 
     290      203538 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
     291             : {
     292      203538 :     if (NumItemsInAvg <= 1) return; // no need to average/smooth
     293             : 
     294      201330 :     Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
     295             : 
     296    24631794 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     297    24430464 :         TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
     298    24430464 :         DataIn(i) = 0.0;
     299             :     }
     300             : 
     301    24631794 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     302   231344640 :         for (int j = 1; j <= NumItemsInAvg; ++j) {
     303   206914176 :             DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
     304             :         }
     305    24430464 :         DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
     306             :     }
     307      201330 : }
     308             : 
     309       35705 : void ProcessDateString(EnergyPlusData &state,
     310             :                        std::string const &String,
     311             :                        int &PMonth,
     312             :                        int &PDay,
     313             :                        int &PWeekDay,
     314             :                        Weather::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     315             :                        bool &ErrorsFound,
     316             :                        ObjexxFCL::Optional_int PYear)
     317             : {
     318             : 
     319             :     // SUBROUTINE INFORMATION:
     320             :     //       AUTHOR         Linda Lawrie
     321             :     //       DATE WRITTEN   December 1999
     322             : 
     323             :     // PURPOSE OF THIS SUBROUTINE:
     324             :     // This subroutine will process a date from a string and determine
     325             :     // the proper month and day for that date string.
     326             : 
     327             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     328             :     bool errFlag;
     329             : 
     330       35705 :     int FstNum = int(Util::ProcessNumber(String, errFlag));
     331       35705 :     DateType = Weather::DateType::Invalid;
     332       35705 :     if (!errFlag) {
     333             :         // Entered single number, do inverse JDay
     334        1574 :         if (FstNum == 0) {
     335        1574 :             PMonth = 0;
     336        1574 :             PDay = 0;
     337        1574 :             DateType = Weather::DateType::MonthDay;
     338           0 :         } else if (FstNum < 0 || FstNum > 366) {
     339           0 :             ShowSevereError(state, format("Invalid Julian date Entered={}", String));
     340           0 :             ErrorsFound = true;
     341             :         } else {
     342           0 :             InvOrdinalDay(FstNum, PMonth, PDay, 0);
     343           0 :             DateType = Weather::DateType::LastDayInMonth;
     344             :         }
     345             :     } else {
     346       34131 :         int NumTokens = 0;
     347       34131 :         int TokenDay = 0;
     348       34131 :         int TokenMonth = 0;
     349       34131 :         int TokenWeekday = 0;
     350             :         // Error when processing as number, try x/x
     351       34131 :         if (!present(PYear)) {
     352       32555 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
     353             :         } else {
     354        1576 :             int TokenYear = 0;
     355        1576 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
     356        1576 :             PYear = TokenYear;
     357             :         }
     358       34131 :         if (DateType == Weather::DateType::MonthDay) {
     359       33003 :             PDay = TokenDay;
     360       33003 :             PMonth = TokenMonth;
     361        1128 :         } else if (DateType == Weather::DateType::NthDayInMonth || DateType == Weather::DateType::LastDayInMonth) {
     362             :             // interpret as TokenDay TokenWeekday in TokenMonth
     363        1128 :             PDay = TokenDay;
     364        1128 :             PMonth = TokenMonth;
     365        1128 :             PWeekDay = TokenWeekday;
     366             :         }
     367             :     }
     368       35705 : }
     369             : 
     370       34131 : void DetermineDateTokens(EnergyPlusData &state,
     371             :                          std::string const &String,
     372             :                          int &NumTokens,                   // Number of tokens found in string
     373             :                          int &TokenDay,                    // Value of numeric field found
     374             :                          int &TokenMonth,                  // Value of Month field found (1=Jan, 2=Feb, etc)
     375             :                          int &TokenWeekday,                // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
     376             :                          Weather::DateType &DateType,      // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     377             :                          bool &ErrorsFound,                // Set to true if cannot process this string as a date
     378             :                          ObjexxFCL::Optional_int TokenYear // Value of Year if one appears to be present and this argument is present
     379             : )
     380             : {
     381             : 
     382             :     // SUBROUTINE INFORMATION:
     383             :     //       AUTHOR         Linda Lawrie
     384             :     //       DATE WRITTEN   August 2000
     385             : 
     386             :     // PURPOSE OF THIS SUBROUTINE:
     387             :     // This subroutine is invoked for date fields that appear to be strings (give
     388             :     // error when ProcessNumber is used).
     389             : 
     390             :     // METHODOLOGY EMPLOYED:
     391             :     // Delete everything that is extraneous to the date information needed.  Process what
     392             :     // is left.
     393             : 
     394             :     // SUBROUTINE PARAMETER DEFINITIONS:
     395             :     static constexpr int NumSingleChars(3);
     396             :     static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
     397             :     static constexpr int NumDoubleChars(6);
     398             :     static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
     399             :         "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want thse only at end of words
     400             :     static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
     401             :     static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
     402             : 
     403             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     404       34131 :     std::string CurrentString = String;
     405       34131 :     Array1D_string Fields(3);
     406       34131 :     bool InternalError = false;
     407       34131 :     bool WkDayInMonth = false;
     408             : 
     409       34131 :     NumTokens = 0;
     410       34131 :     TokenDay = 0;
     411       34131 :     TokenMonth = 0;
     412       34131 :     TokenWeekday = 0;
     413       34131 :     DateType = Weather::DateType::Invalid;
     414       34131 :     if (present(TokenYear)) TokenYear = 0;
     415             :     // Take out separator characters, other extraneous stuff
     416             : 
     417      136524 :     for (int Loop = 0; Loop < NumSingleChars; ++Loop) {
     418      102393 :         size_t Pos = index(CurrentString, SingleChars[Loop]);
     419      134878 :         while (Pos != std::string::npos) {
     420       32485 :             CurrentString[Pos] = ' ';
     421       32485 :             Pos = index(CurrentString, SingleChars[Loop]);
     422             :         }
     423             :     }
     424             : 
     425      238917 :     for (int Loop = 0; Loop < NumDoubleChars; ++Loop) {
     426      204786 :         size_t Pos = index(CurrentString, DoubleChars[Loop]);
     427      207042 :         while (Pos != std::string::npos) {
     428        2256 :             CurrentString.replace(Pos, 2, "  ");
     429        2256 :             Pos = index(CurrentString, DoubleChars[Loop]);
     430        2256 :             WkDayInMonth = true;
     431             :         }
     432             :     }
     433             : 
     434       34131 :     strip(CurrentString);
     435       34131 :     if (CurrentString == BlankString) {
     436           0 :         ShowSevereError(state, format("Invalid date field={}", String));
     437           0 :         ErrorsFound = true;
     438             :     } else {
     439       34131 :         int Loop = 0;
     440       34131 :         bool errFlag = false;
     441             :         int NumField1;
     442             :         int NumField2;
     443             :         int NumField3;
     444      103521 :         while (Loop < 3) { // Max of 3 fields
     445      102393 :             if (CurrentString == BlankString) break;
     446       69390 :             size_t Pos = index(CurrentString, ' ');
     447       69390 :             ++Loop;
     448       69390 :             if (Pos == std::string::npos) Pos = CurrentString.length();
     449       69390 :             Fields(Loop) = CurrentString.substr(0, Pos);
     450       69390 :             CurrentString.erase(0, Pos);
     451       69390 :             strip(CurrentString);
     452             :         }
     453       34131 :         if (not_blank(CurrentString)) {
     454           0 :             ShowSevereError(state, format("Invalid date field={}", String));
     455           0 :             ErrorsFound = true;
     456       34131 :         } else if (Loop == 2) {
     457             :             // Field must be Day Month or Month Day (if both numeric, mon / day)
     458       33003 :             InternalError = false;
     459       33003 :             NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     460       33003 :             if (errFlag) {
     461             :                 // Month day, but first field is not numeric, 2nd must be
     462         499 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     463         499 :                 if (errFlag) {
     464           0 :                     ShowSevereError(state, format("Invalid date field={}", String));
     465           0 :                     InternalError = true;
     466             :                 } else {
     467         499 :                     TokenDay = NumField2;
     468             :                 }
     469         499 :                 TokenMonth = Util::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
     470         499 :                 ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     471         499 :                 if (!InternalError) {
     472         499 :                     DateType = Weather::DateType::MonthDay;
     473             :                 } else {
     474           0 :                     ErrorsFound = true;
     475             :                 }
     476             :             } else {
     477             :                 // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
     478       32504 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     479       32504 :                 if (!errFlag) {
     480       32479 :                     TokenMonth = NumField1;
     481       32479 :                     TokenDay = NumField2;
     482       32479 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     483       32479 :                     if (!InternalError) {
     484       32479 :                         DateType = Weather::DateType::MonthDay;
     485             :                     } else {
     486           0 :                         ErrorsFound = true;
     487             :                     }
     488             :                 } else { // 2nd field was not numeric.  Must be Month
     489          25 :                     TokenDay = NumField1;
     490          25 :                     TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     491          25 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     492          25 :                     if (!InternalError) {
     493          25 :                         DateType = Weather::DateType::MonthDay;
     494          25 :                         NumTokens = 2;
     495             :                     } else {
     496           0 :                         ErrorsFound = true;
     497             :                     }
     498             :                 }
     499             :             }
     500        1128 :         } else if (Loop == 3) {
     501             :             // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
     502        1128 :             if (WkDayInMonth) {
     503        1128 :                 NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     504        1128 :                 if (!errFlag) { // the expected result
     505         931 :                     TokenDay = NumField1;
     506         931 :                     TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     507         931 :                     if (TokenWeekday == 0) {
     508           0 :                         TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     509           0 :                         TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     510           0 :                         if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     511             :                     } else {
     512         931 :                         TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     513         931 :                         if (TokenMonth == 0) InternalError = true;
     514             :                     }
     515         931 :                     DateType = Weather::DateType::NthDayInMonth;
     516         931 :                     NumTokens = 3;
     517         931 :                     if (TokenDay < 0 || TokenDay > 5) InternalError = true;
     518             :                 } else { // first field was not numeric....
     519         197 :                     if (Fields(1) == "LA") {
     520         197 :                         DateType = Weather::DateType::LastDayInMonth;
     521         197 :                         NumTokens = 3;
     522         197 :                         TokenWeekday = Util::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     523         197 :                         if (TokenWeekday == 0) {
     524           0 :                             TokenMonth = Util::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     525           0 :                             TokenWeekday = Util::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     526           0 :                             if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     527             :                         } else {
     528         197 :                             TokenMonth = Util::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     529         197 :                             if (TokenMonth == 0) InternalError = true;
     530             :                         }
     531             :                     } else { // error....
     532           0 :                         ShowSevereError(state, format("First date field not numeric, field={}", String));
     533             :                     }
     534             :                 }
     535             :             } else { // mm/dd/yyyy or yyyy/mm/dd
     536           0 :                 NumField1 = int(Util::ProcessNumber(Fields(1), errFlag));
     537           0 :                 NumField2 = int(Util::ProcessNumber(Fields(2), errFlag));
     538           0 :                 NumField3 = int(Util::ProcessNumber(Fields(3), errFlag));
     539           0 :                 DateType = Weather::DateType::MonthDay;
     540             :                 // error detection later..
     541           0 :                 if (NumField1 > 100) {
     542           0 :                     if (present(TokenYear)) {
     543           0 :                         TokenYear = NumField1;
     544             :                     }
     545           0 :                     TokenMonth = NumField2;
     546           0 :                     TokenDay = NumField3;
     547           0 :                 } else if (NumField3 > 100) {
     548           0 :                     if (present(TokenYear)) {
     549           0 :                         TokenYear = NumField3;
     550             :                     }
     551           0 :                     TokenMonth = NumField1;
     552           0 :                     TokenDay = NumField2;
     553             :                 }
     554             :             }
     555             :         } else {
     556             :             // Not enough or too many fields
     557           0 :             ShowSevereError(state, format("Invalid date field={}", String));
     558           0 :             ErrorsFound = true;
     559             :         }
     560             :     }
     561             : 
     562       34131 :     if (InternalError) {
     563           0 :         DateType = Weather::DateType::Invalid;
     564           0 :         ErrorsFound = true;
     565             :     }
     566       34131 : }
     567             : 
     568       33003 : void ValidateMonthDay(EnergyPlusData &state,
     569             :                       std::string const &String, // REAL(r64) string being processed
     570             :                       int const Day,
     571             :                       int const Month,
     572             :                       bool &ErrorsFound)
     573             : {
     574             : 
     575             :     // SUBROUTINE INFORMATION:
     576             :     //       AUTHOR         Linda Lawrie
     577             :     //       DATE WRITTEN   August 2000
     578             : 
     579             :     // PURPOSE OF THIS SUBROUTINE:
     580             :     // This subroutine validates a potential Day, Month values, produces an error
     581             :     // message when not valid, and sets error flag.
     582             : 
     583             :     // SUBROUTINE PARAMETER DEFINITIONS:
     584             :     static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     585             : 
     586       33003 :     bool InternalError = false;
     587       33003 :     if (Month < 1 || Month > 12) InternalError = true;
     588       33003 :     if (!InternalError) {
     589       33003 :         if (Day < 1 || Day > EndMonthDay[Month - 1]) InternalError = true;
     590             :     }
     591       33003 :     if (InternalError) {
     592           0 :         ShowSevereError(state, format("Invalid Month Day date format={}", String));
     593           0 :         ErrorsFound = true;
     594             :     } else {
     595       33003 :         ErrorsFound = false;
     596             :     }
     597       33003 : }
     598             : 
     599      190238 : int OrdinalDay(int const Month,        // Month, 1..12
     600             :                int const Day,          // Day of Month, not validated by month
     601             :                int const LeapYearValue // 1 if leap year indicated, 0 if not
     602             : )
     603             : {
     604             : 
     605             :     // FUNCTION INFORMATION:
     606             :     //       AUTHOR         Linda K. Lawrie
     607             :     //       DATE WRITTEN   September 1997
     608             :     //       RE-ENGINEERED  from JDAYF in BLAST/IBLAST
     609             : 
     610             :     // PURPOSE OF THIS SUBROUTINE:
     611             :     // This subroutine returns the appropriate Julian Day value for the input
     612             :     // Month and Day.
     613             : 
     614             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     615             :     static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     616             :     // End day numbers of each month (without Leap Year)
     617             : 
     618      190238 :     if (Month == 1) {
     619             :         //                                       CASE 1: JANUARY
     620       61173 :         return Day;
     621             : 
     622      129065 :     } else if (Month == 2) {
     623             :         //                                       CASE 2: FEBRUARY
     624        3027 :         return Day + EndDayofMonth[0];
     625             : 
     626      126038 :     } else if ((Month >= 3) && (Month <= 12)) {
     627             :         //                                       CASE 3: REMAINING MONTHS
     628      126038 :         return Day + EndDayofMonth[Month - 2] + LeapYearValue;
     629             : 
     630             :     } else {
     631           0 :         return 0;
     632             :     }
     633             : }
     634             : 
     635       76765 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
     636             : {
     637             : 
     638             :     // SUBROUTINE INFORMATION:
     639             :     //       AUTHOR         Linda Lawrie
     640             :     //       DATE WRITTEN   December 1999
     641             : 
     642             :     // PURPOSE OF THIS SUBROUTINE:
     643             :     // This subroutine performs and inverse Julian Day
     644             :     // calculation, using an input JulianDay and returning
     645             :     // appropriate Month and Day.
     646             : 
     647             :     // SUBROUTINE PARAMETER DEFINITIONS:
     648             :     static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     649             : 
     650             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     651             :     int WMonth;
     652             :     int LeapAddPrev;
     653             :     int LeapAddCur;
     654             : 
     655       76765 :     if (Number < 0 || Number > 366) return;
     656      496305 :     for (WMonth = 1; WMonth <= 12; ++WMonth) {
     657      496305 :         if (WMonth == 1) {
     658       76765 :             LeapAddPrev = 0;
     659       76765 :             LeapAddCur = 0;
     660      419540 :         } else if (WMonth == 2) {
     661       69420 :             LeapAddPrev = 0;
     662       69420 :             LeapAddCur = LeapYr;
     663             :         } else {
     664      350120 :             LeapAddPrev = LeapYr;
     665      350120 :             LeapAddCur = LeapYr;
     666             :         }
     667      496305 :         if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) break;
     668             :     }
     669       76765 :     PMonth = WMonth;
     670       76765 :     PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
     671             : }
     672             : 
     673        6912 : bool BetweenDateHoursLeftInclusive(
     674             :     int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
     675             : {
     676        6912 :     Real64 TestRatioOfDay = TestHour / 24.0;
     677        6912 :     Real64 StartRatioOfDay = StartHour / 24.0;
     678        6912 :     Real64 EndRatioOfDay = EndHour / 24.0;
     679             : 
     680        6912 :     if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
     681        5376 :         return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
     682             :     } else { // EndDate < StartDate
     683        1536 :         return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
     684             :     }
     685             : }
     686             : 
     687          16 : bool BetweenDates(int const TestDate,  // Date to test
     688             :                   int const StartDate, // Start date in sequence
     689             :                   int const EndDate    // End date in sequence
     690             : )
     691             : {
     692             : 
     693             :     // FUNCTION INFORMATION:
     694             :     //       AUTHOR         Linda K. Lawrie
     695             :     //       DATE WRITTEN   June 2000
     696             : 
     697             :     // PURPOSE OF THIS FUNCTION:
     698             :     // This function returns true if the TestDate is between
     699             :     // (StartDate <= TestDate <= EndDate).
     700             : 
     701             :     // METHODOLOGY EMPLOYED:
     702             :     // The input dates are Julian Day format, year is irrelevant.
     703             :     // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
     704             :     // this routine accomodates.
     705             : 
     706             :     // REFERENCES:
     707             :     // Adapted from BLAST BTWEEN function.
     708             : 
     709          16 :     bool BetweenDates = false; // Default case
     710             : 
     711          16 :     if (StartDate <= EndDate) { // Start Date <= End Date
     712           0 :         if (TestDate >= StartDate && TestDate <= EndDate) BetweenDates = true;
     713             :     } else { // EndDate < StartDate
     714          16 :         if (TestDate <= EndDate || TestDate >= StartDate) BetweenDates = true;
     715             :     }
     716             : 
     717          16 :     return BetweenDates;
     718             : }
     719             : 
     720     2183338 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
     721             : {
     722             : 
     723             :     // FUNCTION INFORMATION:
     724             :     //       AUTHOR         Linda K. Lawrie
     725             :     //       DATE WRITTEN   April 2003
     726             : 
     727             :     // PURPOSE OF THIS FUNCTION:
     728             :     // This function creates the current time interval of the system time step.
     729             : 
     730             :     // Using/Aliasing
     731     2183338 :     Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     732     2183338 :     Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
     733             : 
     734     2183338 :     Real64 constexpr FracToMin(60.0);
     735             : 
     736             :     //  ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
     737             :     // CR6902  ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
     738             :     // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
     739     2183338 :     Real64 ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
     740     2183338 :     Real64 ActualTimeE = ActualTimeS + TimeStepSys;
     741     2183338 :     int ActualTimeHrS = int(ActualTimeS);
     742             :     //  ActualTimeHrE=INT(ActualTimeE)
     743     2183338 :     int ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
     744             : 
     745     2183338 :     if (ActualTimeMinS == 60) {
     746        6514 :         ++ActualTimeHrS;
     747        6514 :         ActualTimeMinS = 0;
     748             :     }
     749     2183338 :     const std::string TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
     750     2183338 :     Real64 minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
     751             : 
     752     2183338 :     std::string TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
     753             : 
     754     2183338 :     if (TimeStmpE[3] == ' ') {
     755      380723 :         TimeStmpE[3] = '0';
     756             :     }
     757     6550014 :     return TimeStmpS + " - " + TimeStmpE;
     758     2183338 : }
     759             : 
     760             : // returns the Julian date for the first, second, etc. day of week for a given month
     761        3714 : int nthDayOfWeekOfMonth(const EnergyPlusData &state,
     762             :                         int const dayOfWeek,  // day of week (Sunday=1, Monday=2, ...)
     763             :                         int const nthTime,    // nth time the day of the week occurs (first monday, third tuesday, ..)
     764             :                         int const monthNumber // January = 1
     765             : )
     766             : {
     767             :     // J. Glazer - August 2017
     768        3714 :     int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
     769        3714 :     int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
     770        3714 :     if (dayOfWeek >= dayOfWeekForFirstDay) {
     771        1880 :         return firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
     772             :     } else {
     773        1834 :         return firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
     774             :     }
     775             : }
     776             : 
     777    12574684 : Real64 SafeDivide(Real64 const a, Real64 const b)
     778             : {
     779             : 
     780             :     // returns a / b while preventing division by zero
     781             : 
     782             :     // Locals
     783    12574684 :     Real64 constexpr SMALL(1.E-10);
     784             : 
     785    12574684 :     if (std::abs(b) >= SMALL) {
     786    12573519 :         return a / b;
     787             :     } else {
     788        1165 :         return a / sign(SMALL, b);
     789             :     }
     790             : }
     791             : 
     792   286200124 : void Iterate(Real64 &ResultX,  // ResultX is the final Iteration result passed back to the calling routine
     793             :              Real64 const Tol, // Tolerance for Convergence
     794             :              Real64 const X0,  // Current value of X
     795             :              Real64 const Y0,  // Current value of the function Y(X)
     796             :              Real64 &X1,       // First Previous values of X
     797             :              Real64 &Y1,       // First Previous values of Y(X1)
     798             :              int const Iter,   // Number of iterations
     799             :              int &Cnvg         // Convergence flag  Cnvg = 0:  Not converged
     800             : )
     801             : {
     802             : 
     803             :     // SUBROUTINE INFORMATION:
     804             :     //       AUTHOR         Richard Liesen
     805             :     //       DATE WRITTEN   March 2004
     806             : 
     807             :     // PURPOSE OF THIS SUBROUTINE:
     808             :     // Iterately solves for the value of X which satisfies Y(X)=0.
     809             :     // The subroutine tests for convergence and provides a new guess for the value of the
     810             :     // independent variable X.
     811             : 
     812             :     // REFERENCES:
     813             :     // Linear Correction based on the RegulaFalsi routine in EnergyPlus
     814             : 
     815             :     // SUBROUTINE PARAMETER DEFINITIONS:
     816   286200124 :     Real64 constexpr small(1.e-9); // Small Number used to approximate zero
     817   286200124 :     Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
     818             : 
     819             :     // Check for convergence by comparing change in X
     820   286200124 :     if (Iter != 1) {
     821   258508426 :         if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
     822    27691635 :             ResultX = X0;
     823    27691635 :             Cnvg = 1;
     824    27691635 :             return;
     825             :         }
     826             :     }
     827             : 
     828             :     // Not converged.
     829   258508489 :     Cnvg = 0;
     830   258508489 :     if (Iter == 1) {
     831             : 
     832             :         // New guess is specified by Perturb
     833    27691698 :         if (std::abs(X0) > small) {
     834    27689923 :             ResultX = X0 * (1.0 + Perturb);
     835             :         } else {
     836        1775 :             ResultX = Perturb;
     837             :         }
     838             : 
     839             :     } else {
     840             : 
     841             :         // New guess calculated from LINEAR FIT of most recent two points
     842   230816791 :         Real64 DY = Y0 - Y1;
     843   230816791 :         if (std::abs(DY) < small) {
     844           0 :             DY = small;
     845             :         }
     846             :         // new estimation
     847             : 
     848   230816791 :         ResultX = (Y0 * X1 - Y1 * X0) / DY;
     849             :     }
     850             : 
     851   258508489 :     X1 = X0;
     852   258508489 :     Y1 = Y0;
     853             : }
     854             : 
     855       39873 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
     856             : {
     857             : 
     858             :     // FUNCTION INFORMATION:
     859             :     //       AUTHOR         Linda K. Lawrie
     860             :     //       DATE WRITTEN   September 2001
     861             : 
     862             :     // PURPOSE OF THIS FUNCTION:
     863             :     // This function looks up a number(integer) in a similar list of
     864             :     // items and returns the index of the item in the list, if found.
     865             : 
     866             :     // Argument array dimensioning
     867       39873 :     ListOfItems.dim(_);
     868             : 
     869      359954 :     for (int Count = 1; Count <= NumItems; ++Count) {
     870      327634 :         if (WhichNumber == ListOfItems(Count)) {
     871        7553 :             return Count;
     872             :         }
     873             :     }
     874             : 
     875       32320 :     return 0;
     876             : }
     877             : 
     878      310953 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
     879             :                        int &Month,     // month in integer format (1-12)
     880             :                        int &Day,       // day in integer format (1-31)
     881             :                        int &Hour,      // hour in integer format (1-24)
     882             :                        int &Minute     // minute in integer format (0:59)
     883             : )
     884             : {
     885             : 
     886             :     // SUBROUTINE INFORMATION:
     887             :     //       AUTHOR         Linda Lawrie
     888             :     //       DATE WRITTEN   March 2000
     889             : 
     890             :     // PURPOSE OF THIS SUBROUTINE:
     891             :     // This subroutine decodes the "packed" integer representation of
     892             :     // the Month, Day, Hour, and Minute.  Packed integers are used to
     893             :     // save memory allocation.  Original idea for this routine is contained
     894             :     // in DECMDH, BLAST code, by Jean Baugh.
     895             : 
     896             :     // METHODOLOGY EMPLOYED:
     897             :     // Using maximum integer concept the original date can be decoded
     898             :     // from the packed single word.  This relies on 4 byte integer representation
     899             :     // as a minimum (capable of representing up to 2,147,483,647).
     900             : 
     901             :     // SUBROUTINE PARAMETER DEFINITIONS:
     902             :     static constexpr int DecMon(100 * 100 * 100);
     903             :     static constexpr int DecDay(100 * 100);
     904             :     static constexpr int DecHr(100);
     905             : 
     906      310953 :     int TmpItem = Item;
     907      310953 :     Month = TmpItem / DecMon;
     908      310953 :     TmpItem = (TmpItem - Month * DecMon);
     909      310953 :     Day = TmpItem / DecDay;
     910      310953 :     TmpItem -= Day * DecDay;
     911      310953 :     Hour = TmpItem / DecHr;
     912      310953 :     Minute = mod(TmpItem, DecHr);
     913      310953 : }
     914             : 
     915     1108785 : void EncodeMonDayHrMin(int &Item,       // word containing encoded month, day, hour, minute
     916             :                        int const Month, // month in integer format (1:12)
     917             :                        int const Day,   // day in integer format (1:31)
     918             :                        int const Hour,  // hour in integer format (1:24)
     919             :                        int const Minute // minute in integer format (0:59)
     920             : )
     921             : {
     922             : 
     923             :     // SUBROUTINE INFORMATION:
     924             :     //       AUTHOR         Linda Lawrie
     925             :     //       DATE WRITTEN   March 2000
     926             : 
     927             :     // PURPOSE OF THIS SUBROUTINE:
     928             :     // This subroutine encodes the "packed" integer representation of
     929             :     // the Month, Day, Hour, and Minute.  Packed integers are used to
     930             :     // save memory allocation.  Original idea for this routine is contained
     931             :     // in DECMDH, BLAST code, by Jean Baugh.
     932             : 
     933             :     // METHODOLOGY EMPLOYED:
     934             :     // Using maximum integer concept the original date can be decoded
     935             :     // from the packed single word.  This relies on 4 byte integer representation
     936             :     // as a minimum (capable of representing up to 2,147,483,647).
     937             : 
     938     1108785 :     Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
     939     1108785 : }
     940             : 
     941           0 : std::string CreateTimeString(Real64 const Time) // Time in seconds
     942             : {
     943             : 
     944             :     // FUNCTION INFORMATION:
     945             :     //       AUTHOR         Dimitri Curtil
     946             :     //       DATE WRITTEN   January 2005
     947             : 
     948             :     // PURPOSE OF THIS FUNCTION:
     949             :     // This function creates the time stamp string from the time value specified in seconds.
     950             :     // Inspired by similar function CreateSysTimeIntervalString() in General.cc
     951             :     // However, this function provides better accuracy for sub-minute time steps
     952             :     // by also showing information down to the 10th of a second.
     953             :     // Note that Time is expected to be specified in REAL(r64).
     954             : 
     955             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     956             :     int Hours;      // Number of hours <= 24
     957             :     int Minutes;    // Remaining minutes < 60
     958             :     Real64 Seconds; // Remaining seconds < 60
     959             : 
     960           0 :     ParseTime(Time, Hours, Minutes, Seconds);
     961             : 
     962             :     // TimeStamp written with formatting
     963             :     // "hh:mm:ss.s"
     964           0 :     return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
     965             : }
     966             : 
     967       14140 : void ParseTime(Real64 const Time, // Time value in seconds
     968             :                int &Hours,        // Number of hours
     969             :                int &Minutes,      // Number of minutes < 60
     970             :                Real64 &Seconds    // Number of seconds < 60
     971             : )
     972             : {
     973             :     // FUNCTION INFORMATION:
     974             :     //       AUTHOR         Dimitri Curtil
     975             :     //       DATE WRITTEN   January 2005
     976             : 
     977             :     // PURPOSE OF THIS FUNCTION:
     978             :     // This subroutine decomposes a time value specified in seconds
     979             :     // into a triplet { hours : minutes : seconds } such that
     980             :     // - minutes < 60
     981             :     // - seconds < 60
     982             : 
     983             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     984       14140 :     int constexpr MinToSec = 60;
     985       14140 :     int constexpr HourToSec = 60 * 60;
     986             : 
     987             :     // Get number of hours
     988             :     // This might undershoot the actual number of hours. See DO WHILE loop.
     989       14140 :     Hours = int(Time) / HourToSec;
     990             : 
     991             :     // Compute remainder in seconds
     992       14140 :     Real64 Remainder = (Time - Hours * HourToSec);
     993             : 
     994             :     // Compute minutes
     995       14140 :     Minutes = int(Remainder) / MinToSec;
     996             : 
     997             :     // Compute remainder in seconds
     998       14140 :     Remainder -= Minutes * MinToSec;
     999             : 
    1000             :     // Compute seconds
    1001       14140 :     Seconds = Remainder;
    1002       14140 : }
    1003             : 
    1004       12736 : void ScanForReports(EnergyPlusData &state,
    1005             :                     std::string const &reportName,
    1006             :                     bool &DoReport,
    1007             :                     ObjexxFCL::Optional_string_const ReportKey,
    1008             :                     ObjexxFCL::Optional_string Option1,
    1009             :                     ObjexxFCL::Optional_string Option2)
    1010             : {
    1011             : 
    1012             :     // SUBROUTINE INFORMATION:
    1013             :     //       AUTHOR         Linda Lawrie
    1014             :     //       DATE WRITTEN   March 2009
    1015             : 
    1016             :     // PURPOSE OF THIS SUBROUTINE:
    1017             :     // This routine scans for the global "reports" settings, such as Variable Dictionary,
    1018             :     // Surfaces (and options), Constructions, etc.
    1019             : 
    1020             :     // METHODOLOGY EMPLOYED:
    1021             :     // First time routine is called, all the viable combinations/settings for the reports are
    1022             :     // stored in SAVEd variables.  Later callings will retrieve those.
    1023             : 
    1024       12736 :     if (state.dataGeneral->GetReportInput) {
    1025             : 
    1026             :         int NumNames;
    1027             :         int NumNumbers;
    1028             :         int IOStat;
    1029             :         int RepNum;
    1030             : 
    1031         796 :         auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    1032         796 :         cCurrentModuleObject = "Output:Surfaces:List";
    1033             : 
    1034         796 :         int NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1035             : 
    1036             :         enum
    1037             :         {
    1038             :             EMPTY,
    1039             :             LINES,
    1040             :             VERTICES,
    1041             :             DETAILS,
    1042             :             DETAILSWITHVERTICES,
    1043             :             COSTINFO,
    1044             :             VIEWFACTORINFO,
    1045             :             DECAYCURVESFROMCOMPONENTLOADSSUMMARY
    1046             :         };
    1047           0 :         std::map<std::string, int> localMap = {{"", EMPTY},
    1048           0 :                                                {"LINES", LINES},
    1049           0 :                                                {"VERTICES", VERTICES},
    1050           0 :                                                {"DETAILS", DETAILS},
    1051           0 :                                                {"DETAILED", DETAILS},
    1052           0 :                                                {"DETAIL", DETAILS},
    1053           0 :                                                {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
    1054           0 :                                                {"DETAILVERTICES", DETAILSWITHVERTICES},
    1055           0 :                                                {"COSTINFO", COSTINFO},
    1056           0 :                                                {"VIEWFACTORINFO", VIEWFACTORINFO},
    1057       10348 :                                                {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
    1058             : 
    1059        1057 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1060         522 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1061             :                                                                      cCurrentModuleObject,
    1062             :                                                                      RepNum,
    1063         261 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1064             :                                                                      NumNames,
    1065         261 :                                                                      state.dataIPShortCut->rNumericArgs,
    1066             :                                                                      NumNumbers,
    1067             :                                                                      IOStat,
    1068         261 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1069         261 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1070         261 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1071         261 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1072             : 
    1073             :             try {
    1074         261 :                 int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
    1075         261 :                 switch (value) {
    1076          51 :                 case LINES:
    1077          51 :                     state.dataGeneral->LineRpt = true;
    1078          51 :                     state.dataGeneral->LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1079          51 :                     break;
    1080           5 :                 case VERTICES:
    1081           5 :                     state.dataGeneral->SurfVert = true;
    1082           5 :                     break;
    1083         148 :                 case DETAILS:
    1084         148 :                     state.dataGeneral->SurfDet = true;
    1085         148 :                     break;
    1086          31 :                 case DETAILSWITHVERTICES:
    1087          31 :                     state.dataGeneral->SurfDetWVert = true;
    1088          31 :                     break;
    1089           7 :                 case COSTINFO:
    1090             :                     //   Custom case for reporting surface info for cost estimates (for first costs in opitimzing)
    1091           7 :                     state.dataGeneral->CostInfo = true;
    1092           7 :                     break;
    1093          10 :                 case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
    1094          10 :                     state.dataGeneral->ViewFactorInfo = true;
    1095          10 :                     state.dataGeneral->ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1096          10 :                     break;
    1097           9 :                 case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
    1098             :                                                            // load component report appear in the EIO file
    1099           9 :                     state.dataGlobal->ShowDecayCurvesInEIO = true;
    1100           9 :                     break;
    1101           0 :                 default: // including empty
    1102           0 :                     ShowWarningError(state, format("{}: No {} supplied.", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1)));
    1103           0 :                     ShowContinueError(state,
    1104             :                                       R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1105             :                 }
    1106           0 :             } catch (int e) {
    1107           0 :                 ShowWarningError(state,
    1108           0 :                                  format("{}: Invalid {}=\"{}\" supplied.",
    1109             :                                         cCurrentModuleObject,
    1110           0 :                                         state.dataIPShortCut->cAlphaFieldNames(1),
    1111           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    1112           0 :                 ShowContinueError(state,
    1113             :                                   R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1114           0 :             }
    1115             :         }
    1116             : 
    1117         796 :         cCurrentModuleObject = "Output:Surfaces:Drawing";
    1118             : 
    1119         796 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1120        1341 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1121        1090 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1122             :                                                                      cCurrentModuleObject,
    1123             :                                                                      RepNum,
    1124         545 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1125             :                                                                      NumNames,
    1126         545 :                                                                      state.dataIPShortCut->rNumericArgs,
    1127             :                                                                      NumNumbers,
    1128             :                                                                      IOStat,
    1129         545 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1130         545 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1131         545 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1132         545 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1133             : 
    1134             :             ReportType checkReportType =
    1135         545 :                 static_cast<ReportType>(getEnumValue(ReportTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
    1136             : 
    1137         545 :             switch (checkReportType) {
    1138         480 :             case ReportType::DXF: {
    1139         480 :                 state.dataGeneral->DXFReport = true;
    1140         480 :                 state.dataGeneral->DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1141         480 :                 state.dataGeneral->DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1142         480 :             } break;
    1143          29 :             case ReportType::DXFWireFrame: {
    1144          29 :                 state.dataGeneral->DXFWFReport = true;
    1145          29 :                 state.dataGeneral->DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1146          29 :                 state.dataGeneral->DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1147          29 :             } break;
    1148          36 :             case ReportType::VRML: {
    1149          36 :                 state.dataGeneral->VRMLReport = true;
    1150          36 :                 state.dataGeneral->VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1151          36 :                 state.dataGeneral->VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1152          36 :             } break;
    1153           0 :             default:
    1154           0 :                 break;
    1155             :             }
    1156             :         }
    1157             : 
    1158         796 :         RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
    1159         796 :         if (RepNum > 0) {
    1160           0 :             state.dataGeneral->VarDict = true;
    1161           0 :             state.dataGeneral->VarDictOption1 = "REGULAR";
    1162           0 :             state.dataGeneral->VarDictOption2 = "";
    1163             :         }
    1164             : 
    1165         796 :         cCurrentModuleObject = "Output:VariableDictionary";
    1166             : 
    1167         796 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1168        1587 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1169        1582 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1170             :                                                                      cCurrentModuleObject,
    1171             :                                                                      RepNum,
    1172         791 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1173             :                                                                      NumNames,
    1174         791 :                                                                      state.dataIPShortCut->rNumericArgs,
    1175             :                                                                      NumNumbers,
    1176             :                                                                      IOStat,
    1177         791 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1178         791 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1179         791 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1180         791 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1181         791 :             state.dataGeneral->VarDict = true;
    1182         791 :             state.dataGeneral->VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
    1183         791 :             state.dataGeneral->VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
    1184             :         }
    1185             : 
    1186         796 :         cCurrentModuleObject = "Output:Constructions";
    1187         796 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1188        1114 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1189         636 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1190             :                                                                      cCurrentModuleObject,
    1191             :                                                                      RepNum,
    1192         318 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1193             :                                                                      NumNames,
    1194         318 :                                                                      state.dataIPShortCut->rNumericArgs,
    1195             :                                                                      NumNumbers,
    1196             :                                                                      IOStat,
    1197         318 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1198         318 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1199         318 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1200         318 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1201         318 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
    1202         307 :                 state.dataGeneral->Constructions = true;
    1203          11 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
    1204          11 :                 state.dataGeneral->Materials = true;
    1205             :             }
    1206         318 :             if (NumNames > 1) {
    1207           3 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
    1208           0 :                     state.dataGeneral->Constructions = true;
    1209           3 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
    1210           3 :                     state.dataGeneral->Materials = true;
    1211             :                 }
    1212             :             }
    1213             :         }
    1214             : 
    1215         796 :         cCurrentModuleObject = "Output:EnergyManagementSystem";
    1216         796 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1217         837 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1218          82 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1219             :                                                                      cCurrentModuleObject,
    1220             :                                                                      RepNum,
    1221          41 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1222             :                                                                      NumNames,
    1223          41 :                                                                      state.dataIPShortCut->rNumericArgs,
    1224             :                                                                      NumNumbers,
    1225             :                                                                      IOStat,
    1226          41 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1227          41 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1228          41 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1229          41 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1230             : 
    1231          41 :             state.dataGeneral->EMSoutput = true;
    1232             : 
    1233          41 :             AvailRpt CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(1))));
    1234          41 :             state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1235          41 :             state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
    1236             : 
    1237          41 :             CheckAvailRpt = static_cast<AvailRpt>(getEnumValue(AvailRptNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
    1238          41 :             state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1239          41 :             state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
    1240             : 
    1241             :             ERLdebugOutputLevel CheckERLlevel =
    1242          41 :                 static_cast<ERLdebugOutputLevel>(getEnumValue(ERLdebugOutputLevelNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    1243          41 :             state.dataRuntimeLang->OutputEMSErrors =
    1244          41 :                 (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1245          41 :             state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1246             :         }
    1247             : 
    1248         796 :         state.dataGeneral->GetReportInput = false;
    1249         796 :     }
    1250             : 
    1251             :     // Process the Scan Request
    1252       12736 :     DoReport = false;
    1253             : 
    1254       12736 :     ReportName rptName = static_cast<ReportName>(getEnumValue(ReportNamesUC, Util::makeUPPER(Util::makeUPPER(reportName))));
    1255       12736 :     switch (rptName) {
    1256        2389 :     case ReportName::Constructions: {
    1257        2389 :         if (present(ReportKey)) {
    1258        2389 :             if (Util::SameString(ReportKey(), "Constructions")) DoReport = state.dataGeneral->Constructions;
    1259        2389 :             if (Util::SameString(ReportKey(), "Materials")) DoReport = state.dataGeneral->Materials;
    1260             :         }
    1261        2389 :     } break;
    1262        1592 :     case ReportName::Viewfactorinfo: {
    1263        1592 :         DoReport = state.dataGeneral->ViewFactorInfo;
    1264        1592 :         if (present(Option1)) Option1 = state.dataGeneral->ViewRptOption1;
    1265        1592 :     } break;
    1266         795 :     case ReportName::Variabledictionary: {
    1267         795 :         DoReport = state.dataGeneral->VarDict;
    1268         795 :         if (present(Option1)) Option1 = state.dataGeneral->VarDictOption1;
    1269         795 :         if (present(Option2)) Option2 = state.dataGeneral->VarDictOption2;
    1270             :         //    CASE ('SCHEDULES')
    1271             :         //     DoReport=SchRpt
    1272             :         //      IF (PRESENT(Option1)) Option1=SchRptOption
    1273         795 :     } break;
    1274        7164 :     case ReportName::Surfaces: {
    1275        7164 :         RptKey rptKey = static_cast<RptKey>(getEnumValue(RptKeyNamesUC, Util::makeUPPER(ReportKey())));
    1276             :         switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
    1277         796 :         case RptKey::Costinfo: {
    1278         796 :             DoReport = state.dataGeneral->CostInfo;
    1279         796 :         } break;
    1280         796 :         case RptKey::DXF: {
    1281         796 :             DoReport = state.dataGeneral->DXFReport;
    1282         796 :             if (present(Option1)) Option1 = state.dataGeneral->DXFOption1;
    1283         796 :             if (present(Option2)) Option2 = state.dataGeneral->DXFOption2;
    1284         796 :         } break;
    1285         796 :         case RptKey::DXFwireframe: {
    1286         796 :             DoReport = state.dataGeneral->DXFWFReport;
    1287         796 :             if (present(Option1)) Option1 = state.dataGeneral->DXFWFOption1;
    1288         796 :             if (present(Option2)) Option2 = state.dataGeneral->DXFWFOption2;
    1289         796 :         } break;
    1290         796 :         case RptKey::VRML: {
    1291         796 :             DoReport = state.dataGeneral->VRMLReport;
    1292         796 :             if (present(Option1)) Option1 = state.dataGeneral->VRMLOption1;
    1293         796 :             if (present(Option2)) Option2 = state.dataGeneral->VRMLOption2;
    1294         796 :         } break;
    1295         796 :         case RptKey::Vertices: {
    1296         796 :             DoReport = state.dataGeneral->SurfVert;
    1297         796 :         } break;
    1298        1592 :         case RptKey::Details: {
    1299        1592 :             DoReport = state.dataGeneral->SurfDet;
    1300        1592 :         } break;
    1301         796 :         case RptKey::DetailsWithVertices: {
    1302         796 :             DoReport = state.dataGeneral->SurfDetWVert;
    1303         796 :         } break;
    1304         796 :         case RptKey::Lines: {
    1305         796 :             DoReport = state.dataGeneral->LineRpt;
    1306         796 :             if (present(Option1)) Option1 = state.dataGeneral->LineRptOption1;
    1307         796 :         } break;
    1308           0 :         default:
    1309           0 :             break;
    1310             :         }
    1311        7164 :     } break;
    1312         796 :     case ReportName::Energymanagementsystem: {
    1313         796 :         DoReport = state.dataGeneral->EMSoutput;
    1314         796 :     } break;
    1315           0 :     default:
    1316           0 :         break;
    1317             :     }
    1318       12736 : }
    1319             : 
    1320          54 : void CheckCreatedZoneItemName(EnergyPlusData &state,
    1321             :                               std::string_view const calledFrom,              // routine called from
    1322             :                               std::string const &CurrentObject,               // object being parsed
    1323             :                               std::string const &ZoneName,                    // Zone Name associated
    1324             :                               std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
    1325             :                               std::string const &ItemName,                    // Item name (People, Lights, etc object)
    1326             :                               Array1_string const &ItemNames,                 // Item Names to check for duplication
    1327             :                               int const NumItems,                             // Number of items in ItemNames array
    1328             :                               std::string &ResultName,                        // Resultant name
    1329             :                               bool &errFlag                                   // Error flag set to true if error found here.
    1330             : )
    1331             : {
    1332             : 
    1333             :     // SUBROUTINE INFORMATION:
    1334             :     //       AUTHOR         Linda Lawrie
    1335             :     //       DATE WRITTEN   December 2012
    1336             : 
    1337             :     // PURPOSE OF THIS SUBROUTINE:
    1338             :     // This routine checks "global" objects (that is, ones with ZoneList used in the name
    1339             :     // specification) along with a specific name for the current object for length and duplication
    1340             :     // with previous objects of that class.
    1341             : 
    1342          54 :     errFlag = false;
    1343          54 :     std::string::size_type const ItemNameLength = len(ItemName);
    1344          54 :     std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
    1345          54 :     ResultName = ZoneName + ' ' + ItemName;
    1346          54 :     bool TooLong = false;
    1347          54 :     if (ItemLength > Constant::MaxNameLength) {
    1348           0 :         ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
    1349           0 :         ShowContinueError(state, format("Object Name=\"{}\".", ItemName));
    1350           0 :         ShowContinueError(state, format("ZoneList/Zone Name=\"{}\".", ZoneName));
    1351           0 :         ShowContinueError(state,
    1352           0 :                           format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, Constant::MaxNameLength));
    1353           0 :         ShowContinueError(state,
    1354           0 :                           format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
    1355           0 :                                  MaxZoneNameLength + 1 + ItemNameLength - Constant::MaxNameLength));
    1356           0 :         ShowContinueError(state, format("name that will be used (may be needed in reporting)=\"{}\".", ResultName));
    1357           0 :         TooLong = true;
    1358             :     }
    1359             : 
    1360          54 :     int FoundItem = Util::FindItemInList(ResultName, ItemNames, NumItems);
    1361             : 
    1362          54 :     if (FoundItem != 0) {
    1363           0 :         ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
    1364           0 :         ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
    1365           0 :         if (TooLong) ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
    1366           0 :         ResultName = "xxxxxxx";
    1367           0 :         errFlag = true;
    1368             :     }
    1369          54 : }
    1370             : 
    1371           0 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
    1372             : {
    1373             :     int currentDate;
    1374           0 :     int reportStartDate = state.dataWeather->ReportPeriodInput(periodIdx).startJulianDate;
    1375           0 :     int reportStartHour = state.dataWeather->ReportPeriodInput(periodIdx).startHour;
    1376           0 :     if (state.dataWeather->ReportPeriodInput(periodIdx).startYear > 0) {
    1377           0 :         currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1378             :     } else {
    1379           0 :         currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1380             :     }
    1381           0 :     return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
    1382             : }
    1383             : 
    1384        5376 : void findReportPeriodIdx(EnergyPlusData &state,
    1385             :                          const Array1D<Weather::ReportPeriodData> &ReportPeriodInputData,
    1386             :                          const int nReportPeriods,
    1387             :                          Array1D_bool &inReportPeriodFlags)
    1388             : {
    1389             :     // return an array of flags, indicating whether the current time is in reporting period i
    1390             :     int currentDate;
    1391       12288 :     for (int i = 1; i <= nReportPeriods; i++) {
    1392        6912 :         int reportStartDate = ReportPeriodInputData(i).startJulianDate;
    1393        6912 :         int reportStartHour = ReportPeriodInputData(i).startHour;
    1394        6912 :         int reportEndDate = ReportPeriodInputData(i).endJulianDate;
    1395        6912 :         int reportEndHour = ReportPeriodInputData(i).endHour;
    1396        6912 :         if (ReportPeriodInputData(i).startYear > 0) {
    1397           0 :             currentDate = Weather::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1398             :         } else {
    1399        6912 :             currentDate = Weather::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1400             :         }
    1401        6912 :         if (General::BetweenDateHoursLeftInclusive(
    1402        6912 :                 currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
    1403           0 :             inReportPeriodFlags(i) = true;
    1404             :         }
    1405             :     }
    1406        5376 : }
    1407             : 
    1408         183 : Real64 rotAzmDiffDeg(Real64 AzmA, Real64 AzmB)
    1409             : {
    1410             :     // This function takes two (azimuth) angles in Degree(s),
    1411             :     // and returns the rotational angle difference in Degree(s).
    1412             : 
    1413         183 :     Real64 diff = AzmB - AzmA;
    1414         183 :     if (diff > 180.0) {
    1415           6 :         diff = 360.0 - diff;
    1416         177 :     } else if (diff < -180.0) {
    1417           8 :         diff = 360.0 + diff;
    1418             :     }
    1419         183 :     return std::abs(diff);
    1420             : }
    1421             : 
    1422             : } // namespace EnergyPlus::General

Generated by: LCOV version 1.14