LCOV - code coverage report
Current view: top level - EnergyPlus - General.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 576 730 78.9 %
Date: 2023-01-17 19:17:23 Functions: 28 36 77.8 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // 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/OutputProcessor.hh>
      68             : #include <EnergyPlus/UtilityRoutines.hh>
      69             : #include <EnergyPlus/WeatherManager.hh>
      70             : 
      71             : #if defined(_WIN32) && _MSC_VER < 1900
      72             : #define snprintf _snprintf
      73             : #endif
      74             : 
      75             : namespace EnergyPlus::General {
      76             : 
      77             : // Module containing routines for general use
      78             : 
      79             : // MODULE INFORMATION:
      80             : //       AUTHOR         Fred Buhl, Linda Lawrie
      81             : //       DATE WRITTEN   December 2001
      82             : //       MODIFIED       na
      83             : //       RE-ENGINEERED  na
      84             : 
      85             : // PURPOSE OF THIS MODULE:
      86             : // contains routines (most likely numeric) that may be needed in several parts
      87             : // of EnergyPlus
      88             : 
      89             : // Using/Aliasing
      90             : using DataHVACGlobals::Bisection;
      91             : 
      92             : // MODULE PARAMETER DEFINITIONS
      93             : static constexpr std::string_view BlankString;
      94             : 
      95             : enum class ReportType
      96             : {
      97             :     Invalid = -1,
      98             :     DXF,
      99             :     DXFWireFrame,
     100             :     VRML,
     101             :     Num
     102             : };
     103             : 
     104             : constexpr std::array<std::string_view, static_cast<int>(ReportType::Num)> ReportTypeNamesUC{"DXF", "DXF:WIREFRAME", "VRML"};
     105             : 
     106             : enum class AvailRpt
     107             : {
     108             :     Invalid = -1,
     109             :     None,
     110             :     NotByUniqueKeyNames,
     111             :     Verbose,
     112             :     Num
     113             : };
     114             : 
     115             : constexpr std::array<std::string_view, static_cast<int>(AvailRpt::Num)> AvailRptNamesUC{"NONE", "NOTBYUNIQUEKEYNAMES", "VERBOSE"};
     116             : 
     117             : enum class ERLdebugOutputLevel
     118             : {
     119             :     Invalid = -1,
     120             :     None,
     121             :     ErrorsOnly,
     122             :     Verbose,
     123             :     Num
     124             : };
     125             : 
     126             : constexpr std::array<std::string_view, static_cast<int>(ERLdebugOutputLevel::Num)> ERLdebugOutputLevelNamesUC{"NONE", "ERRORSONLY", "VERBOSE"};
     127             : 
     128             : enum class ReportName
     129             : {
     130             :     Invalid = -1,
     131             :     Constructions,
     132             :     Viewfactorinfo,
     133             :     Variabledictionary,
     134             :     Surfaces,
     135             :     Energymanagementsystem,
     136             :     Num
     137             : };
     138             : 
     139             : constexpr std::array<std::string_view, static_cast<int>(ReportName::Num)> ReportNamesUC{
     140             :     "CONSTRUCTIONS", "VIEWFACTORINFO", "VARIABLEDICTIONARY", "SURFACES", "ENERGYMANAGEMENTSYSTEM"};
     141             : 
     142             : enum class RptKey
     143             : {
     144             :     Invalid = -1,
     145             :     Costinfo,
     146             :     DXF,
     147             :     DXFwireframe,
     148             :     VRML,
     149             :     Vertices,
     150             :     Details,
     151             :     DetailsWithVertices,
     152             :     Lines,
     153             :     Num
     154             : };
     155             : 
     156             : constexpr std::array<std::string_view, static_cast<int>(RptKey::Num)> RptKeyNamesUC{
     157             :     "COSTINFO", "DXF", "DXF:WIREFRAME", "VRML", "VERTICES", "DETAILS", "DETAILSWITHVERTICES", "LINES"};
     158             : 
     159             : // A second version that does not require a payload -- use lambdas
     160    14597785 : void SolveRoot(EnergyPlusData &state,
     161             :                Real64 Eps,   // required absolute accuracy
     162             :                int MaxIte,   // maximum number of allowed iterations
     163             :                int &Flag,    // integer storing exit status
     164             :                Real64 &XRes, // value of x that solves f(x,Par) = 0
     165             :                const std::function<Real64(Real64)> &f,
     166             :                Real64 X_0, // 1st bound of interval that contains the solution
     167             :                Real64 X_1) // 2nd bound of interval that contains the solution
     168             : {
     169             :     // SUBROUTINE INFORMATION:
     170             :     //       AUTHOR         Michael Wetter
     171             :     //       DATE WRITTEN   March 1999
     172             :     //       MODIFIED       Fred Buhl November 2000, R. Raustad October 2006 - made subroutine RECURSIVE
     173             :     //                      L. Gu, May 2017 - allow both Bisection and RegulaFalsi
     174             : 
     175             :     // PURPOSE OF THIS SUBROUTINE:
     176             :     // Find the value of x between x0 and x1 such that f(x,Par)
     177             :     // is equal to zero.
     178             : 
     179             :     // METHODOLOGY EMPLOYED:
     180             :     // Uses the Regula Falsi (false position) method (similar to secant method)
     181             : 
     182             :     // REFERENCES:
     183             :     // See Press et al., Numerical Recipes in Fortran, Cambridge University Press,
     184             :     // 2nd edition, 1992. Page 347 ff.
     185             : 
     186             :     // SUBROUTINE ARGUMENT DEFINITIONS:
     187             :     // = -2: f(x0) and f(x1) have the same sign
     188             :     // = -1: no convergence
     189             :     // >  0: number of iterations performed
     190             : 
     191    14597785 :     Real64 constexpr SMALL(1.e-10);
     192    14597785 :     Real64 X0 = X_0;   // present 1st bound
     193    14597785 :     Real64 X1 = X_1;   // present 2nd bound
     194    14597785 :     Real64 XTemp = X0; // new estimate
     195    14597785 :     int NIte = 0;      // number of interations
     196    14597785 :     int AltIte = 0;    // an accounter used for Alternation choice
     197             : 
     198    14597785 :     Real64 Y0 = f(X0); // f at X0
     199    14597785 :     Real64 Y1 = f(X1); // f at X1
     200             :     // check initial values
     201    14597785 :     if (Y0 * Y1 > 0) {
     202      326196 :         Flag = -2;
     203      326196 :         XRes = X0;
     204      326196 :         return;
     205             :     }
     206    14271589 :     XRes = XTemp;
     207             : 
     208             :     while (true) {
     209             : 
     210    28793024 :         Real64 DY = Y0 - Y1;
     211    28793024 :         if (std::abs(DY) < SMALL) DY = SMALL;
     212    28793024 :         if (std::abs(X1 - X0) < SMALL) {
     213        6780 :             break;
     214             :         }
     215             :         // new estimation
     216    28786244 :         switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolver) {
     217    28780649 :         case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
     218    28780649 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     219    28780649 :             break;
     220             :         }
     221           0 :         case HVACSystemRootSolverAlgorithm::Bisection: {
     222           0 :             XTemp = (X1 + X0) / 2.0;
     223           0 :             break;
     224             :         }
     225        5595 :         case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
     226        5595 :             if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     227          95 :                 XTemp = (X1 + X0) / 2.0;
     228             :             } else {
     229        5500 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     230             :             }
     231        5595 :             break;
     232             :         }
     233           0 :         case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
     234           0 :             if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     235           0 :                 XTemp = (X1 + X0) / 2.0;
     236             :             } else {
     237           0 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     238             :             }
     239           0 :             break;
     240             :         }
     241           0 :         case HVACSystemRootSolverAlgorithm::Alternation: {
     242           0 :             if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
     243           0 :                 XTemp = (X1 + X0) / 2.0;
     244           0 :                 if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) AltIte = 0;
     245             :             } else {
     246           0 :                 XTemp = (Y0 * X1 - Y1 * X0) / DY;
     247             :             }
     248           0 :             break;
     249             :         }
     250           0 :         default: {
     251           0 :             XTemp = (Y0 * X1 - Y1 * X0) / DY;
     252             :         }
     253             :         }
     254             : 
     255    28786244 :         Real64 const YTemp = f(XTemp);
     256             : 
     257    28786244 :         ++NIte;
     258    28786244 :         ++AltIte;
     259             : 
     260             :         // check convergence
     261    28786244 :         if (std::abs(YTemp) < Eps) {
     262    14264677 :             Flag = NIte;
     263    14264677 :             XRes = XTemp;
     264    14264677 :             return;
     265             :         };
     266             : 
     267             :         // OK, so we didn't converge, lets check max iterations to see if we should break early
     268    14521567 :         if (NIte > MaxIte) break;
     269             : 
     270             :         // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
     271             :         // and reassign values (only if further iteration required)
     272    14521435 :         if (Y0 < 0.0) {
     273    12643219 :             if (YTemp < 0.0) {
     274     5876724 :                 X0 = XTemp;
     275     5876724 :                 Y0 = YTemp;
     276             :             } else {
     277     6766495 :                 X1 = XTemp;
     278     6766495 :                 Y1 = YTemp;
     279             :             }
     280             :         } else {
     281     1878216 :             if (YTemp < 0.0) {
     282     1201193 :                 X1 = XTemp;
     283     1201193 :                 Y1 = YTemp;
     284             :             } else {
     285      677023 :                 X0 = XTemp;
     286      677023 :                 Y0 = YTemp;
     287             :             }
     288             :         } // ( Y0 < 0 )
     289    14521435 :     }     // Cont
     290             : 
     291             :     // if we make it here we haven't converged, so just set the flag and leave
     292        6912 :     Flag = -1;
     293        6912 :     XRes = XTemp;
     294             : }
     295             : 
     296       10656 : Real64 InterpProfAng(Real64 const ProfAng,           // Profile angle (rad)
     297             :                      Array1S<Real64> const PropArray // Array of blind properties
     298             : )
     299             : {
     300             : 
     301             :     // SUBROUTINE INFORMATION:
     302             :     //       AUTHOR         Fred Winkelmann
     303             :     //       DATE WRITTEN   May 2001
     304             :     //       MODIFIED       na
     305             :     //       RE-ENGINEERED  na
     306             : 
     307             :     // PURPOSE OF THIS SUBROUTINE:
     308             :     // Does profile-angle interpolation of window blind solar-thermal properties
     309             : 
     310             :     // METHODOLOGY EMPLOYED:
     311             :     // Linear interpolation.
     312             : 
     313             :     // Return value
     314             :     Real64 InterpProfAng;
     315             : 
     316             :     // FUNCTION PARAMETER DEFINITIONS:
     317       10656 :     Real64 const DeltaAngRad(DataGlobalConstants::Pi / 36.0); // Profile angle increment (rad)
     318             : 
     319             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     320             :     Real64 InterpFac; // Interpolation factor
     321             :     int IAlpha;       // Profile angle index
     322             : 
     323             :     // DeltaAng = Pi/36
     324       10656 :     if (ProfAng > DataGlobalConstants::PiOvr2 || ProfAng < -DataGlobalConstants::PiOvr2) {
     325           0 :         InterpProfAng = 0.0;
     326             :     } else {
     327       10656 :         IAlpha = 1 + int((ProfAng + DataGlobalConstants::PiOvr2) / DeltaAngRad);
     328       10656 :         InterpFac = (ProfAng - (-DataGlobalConstants::PiOvr2 + DeltaAngRad * (IAlpha - 1))) / DeltaAngRad;
     329       10656 :         InterpProfAng = (1.0 - InterpFac) * PropArray(IAlpha) + InterpFac * PropArray(IAlpha + 1);
     330             :     }
     331       10656 :     return InterpProfAng;
     332             : }
     333             : 
     334        5517 : Real64 InterpSlatAng(Real64 const SlatAng,           // Slat angle (rad)
     335             :                      bool const VarSlats,            // True if slat angle is variable
     336             :                      Array1S<Real64> const PropArray // Array of blind properties as function of slat angle
     337             : )
     338             : {
     339             : 
     340             :     // SUBROUTINE INFORMATION:
     341             :     //       AUTHOR         Fred Winkelmann
     342             :     //       DATE WRITTEN   Dec 2001
     343             :     //       MODIFIED       na
     344             :     //       RE-ENGINEERED  na
     345             : 
     346             :     // PURPOSE OF THIS SUBROUTINE:
     347             :     // Does slat-angle interpolation of window blind solar-thermal properties that
     348             :     // do not depend on profile angle
     349             : 
     350             :     // METHODOLOGY EMPLOYED:
     351             :     // Linear interpolation.
     352             : 
     353             :     // Using/Aliasing
     354             :     using DataSurfaces::MaxSlatAngs;
     355             : 
     356             :     // Return value
     357             :     Real64 InterpSlatAng;
     358             : 
     359             :     // FUNCTION PARAMETER DEFINITIONS:
     360             :     static Real64 const DeltaAng(DataGlobalConstants::Pi / (double(MaxSlatAngs) - 1.0));
     361             :     static Real64 const DeltaAng_inv((double(MaxSlatAngs) - 1.0) / DataGlobalConstants::Pi);
     362             : 
     363             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     364             :     Real64 InterpFac; // Interpolation factor
     365             :     int IBeta;        // Slat angle index
     366             :     Real64 SlatAng1;
     367             : 
     368        5517 :     if (SlatAng > DataGlobalConstants::Pi || SlatAng < 0.0) {
     369           0 :         SlatAng1 = min(max(SlatAng, 0.0), DataGlobalConstants::Pi);
     370             :     } else {
     371        5517 :         SlatAng1 = SlatAng;
     372             :     }
     373             : 
     374        5517 :     if (VarSlats) { // Variable-angle slats
     375          21 :         IBeta = 1 + int(SlatAng1 * DeltaAng_inv);
     376          21 :         InterpFac = (SlatAng1 - DeltaAng * (IBeta - 1)) * DeltaAng_inv;
     377          21 :         InterpSlatAng = PropArray(IBeta) + InterpFac * (PropArray(min(MaxSlatAngs, IBeta + 1)) - PropArray(IBeta));
     378             :     } else { // Fixed-angle slats or shade
     379        5496 :         InterpSlatAng = PropArray(1);
     380             :     }
     381             : 
     382        5517 :     return InterpSlatAng;
     383             : }
     384             : 
     385         129 : Real64 InterpProfSlatAng(Real64 const ProfAng,           // Profile angle (rad)
     386             :                          Real64 const SlatAng,           // Slat angle (rad)
     387             :                          bool const VarSlats,            // True if variable-angle slats
     388             :                          Array2A<Real64> const PropArray // Array of blind properties
     389             : )
     390             : {
     391             : 
     392             :     // SUBROUTINE INFORMATION:
     393             :     //       AUTHOR         Fred Winkelmann
     394             :     //       DATE WRITTEN   Dec 2001
     395             :     //       MODIFIED       na
     396             :     //       RE-ENGINEERED  na
     397             : 
     398             :     // PURPOSE OF THIS SUBROUTINE:
     399             :     // Does simultaneous profile-angle and slat-angle interpolation of window
     400             :     // blind solar-thermal properties that depend on profile angle and slat angle
     401             : 
     402             :     // METHODOLOGY EMPLOYED:
     403             :     // Linear interpolation.
     404             : 
     405             :     // Using/Aliasing
     406             :     using DataSurfaces::MaxSlatAngs;
     407             : 
     408             :     // Return value
     409             :     Real64 InterpProfSlatAng;
     410             : 
     411             :     // Argument array dimensioning
     412         129 :     PropArray.dim(MaxSlatAngs, 37);
     413             : 
     414             :     // FUNCTION PARAMETER DEFINITIONS:
     415         129 :     Real64 const DeltaProfAng(DataGlobalConstants::Pi / 36.0);
     416         129 :     Real64 const DeltaSlatAng(DataGlobalConstants::Pi / (double(MaxSlatAngs) - 1.0));
     417             : 
     418             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     419             :     Real64 ProfAngRatio; // Profile angle interpolation factor
     420             :     Real64 SlatAngRatio; // Slat angle interpolation factor
     421             :     int IAlpha;          // Profile angle index
     422             :     int IBeta;           // Slat angle index
     423             :     Real64 Val1;         // Property values at points enclosing the given ProfAngle and SlatAngle
     424             :     Real64 Val2;
     425             :     Real64 Val3;
     426             :     Real64 Val4;
     427             :     Real64 ValA; // Property values at given SlatAngle to be interpolated in profile angle
     428             :     Real64 ValB;
     429             :     Real64 SlatAng1;
     430             :     Real64 ProfAng1;
     431             : 
     432         129 :     if (SlatAng > DataGlobalConstants::Pi || SlatAng < 0.0 || ProfAng > DataGlobalConstants::PiOvr2 || ProfAng < -DataGlobalConstants::PiOvr2) {
     433           0 :         SlatAng1 = min(max(SlatAng, 0.0), DataGlobalConstants::Pi);
     434             : 
     435             :         // This is not correct, fixed 2/17/2010
     436             :         // ProfAng1 = MIN(MAX(SlatAng,-PiOvr2),PiOvr2)
     437           0 :         ProfAng1 = min(max(ProfAng, -DataGlobalConstants::PiOvr2), DataGlobalConstants::PiOvr2);
     438             :     } else {
     439         129 :         SlatAng1 = SlatAng;
     440         129 :         ProfAng1 = ProfAng;
     441             :     }
     442             : 
     443         129 :     IAlpha = int((ProfAng1 + DataGlobalConstants::PiOvr2) / DeltaProfAng) + 1;
     444         129 :     ProfAngRatio = (ProfAng1 + DataGlobalConstants::PiOvr2 - (IAlpha - 1) * DeltaProfAng) / DeltaProfAng;
     445             : 
     446         129 :     if (VarSlats) { // Variable-angle slats: interpolate in profile angle and slat angle
     447          27 :         IBeta = int(SlatAng1 / DeltaSlatAng) + 1;
     448          27 :         SlatAngRatio = (SlatAng1 - (IBeta - 1) * DeltaSlatAng) / DeltaSlatAng;
     449          27 :         Val1 = PropArray(IBeta, IAlpha);
     450          27 :         Val2 = PropArray(min(MaxSlatAngs, IBeta + 1), IAlpha);
     451          27 :         Val3 = PropArray(IBeta, min(37, IAlpha + 1));
     452          27 :         Val4 = PropArray(min(MaxSlatAngs, IBeta + 1), min(37, IAlpha + 1));
     453          27 :         ValA = Val1 + SlatAngRatio * (Val2 - Val1);
     454          27 :         ValB = Val3 + SlatAngRatio * (Val4 - Val3);
     455          27 :         InterpProfSlatAng = ValA + ProfAngRatio * (ValB - ValA);
     456             :     } else { // Fixed-angle slats: interpolate only in profile angle
     457         102 :         Val1 = PropArray(1, IAlpha);
     458         102 :         Val2 = PropArray(1, min(37, IAlpha + 1));
     459         102 :         InterpProfSlatAng = Val1 + ProfAngRatio * (Val2 - Val1);
     460             :     }
     461             : 
     462         129 :     return InterpProfSlatAng;
     463             : }
     464             : 
     465       41235 : Real64 BlindBeamBeamTrans(Real64 const ProfAng,        // Solar profile angle (rad)
     466             :                           Real64 const SlatAng,        // Slat angle (rad)
     467             :                           Real64 const SlatWidth,      // Slat width (m)
     468             :                           Real64 const SlatSeparation, // Slat separation (distance between surfaces of adjacent slats) (m)
     469             :                           Real64 const SlatThickness   // Slat thickness (m)
     470             : )
     471             : {
     472             : 
     473             :     // FUNCTION INFORMATION:
     474             :     //       AUTHOR         Fred Winkelmann
     475             :     //       DATE WRITTEN   Jan 2002
     476             :     //       MODIFIED       na
     477             :     //       RE-ENGINEERED  na
     478             : 
     479             :     // PURPOSE OF THIS SUBROUTINE:
     480             :     // Calculates beam-to-beam transmittance of a window blind
     481             : 
     482             :     // METHODOLOGY EMPLOYED:
     483             :     // Based on solar profile angle and slat geometry
     484             : 
     485             :     // Return value
     486             :     Real64 BlindBeamBeamTrans;
     487             : 
     488             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     489             :     Real64 fEdge;      // Slat edge correction factor
     490             :     Real64 wbar;       // Intermediate variable
     491             :     Real64 gamma;      // Intermediate variable
     492             :     Real64 fEdge1;     // Intermediate variable
     493             :     Real64 CosProfAng; // Cosine of profile angle
     494             : 
     495       41235 :     CosProfAng = std::cos(ProfAng);
     496       41235 :     gamma = SlatAng - ProfAng;
     497       41235 :     wbar = SlatSeparation;
     498       41235 :     if (CosProfAng != 0.0) wbar = SlatWidth * std::cos(gamma) / CosProfAng;
     499       41235 :     BlindBeamBeamTrans = max(0.0, 1.0 - std::abs(wbar / SlatSeparation));
     500             : 
     501       41235 :     if (BlindBeamBeamTrans > 0.0) {
     502             : 
     503             :         // Correction factor that accounts for finite thickness of slats. It is used to modify the
     504             :         // blind transmittance to account for reflection and absorption by the slat edges.
     505             :         // fEdge is ratio of area subtended by edge of slat to area between tops of adjacent slats.
     506             : 
     507        4554 :         fEdge = 0.0;
     508        4554 :         fEdge1 = 0.0;
     509        4554 :         if (std::abs(std::sin(gamma)) > 0.01) {
     510        4554 :             if ((SlatAng > 0.0 && SlatAng <= DataGlobalConstants::PiOvr2 && ProfAng <= SlatAng) ||
     511        2512 :                 (SlatAng > DataGlobalConstants::PiOvr2 && SlatAng <= DataGlobalConstants::Pi && ProfAng > -(DataGlobalConstants::Pi - SlatAng)))
     512        4554 :                 fEdge1 = SlatThickness * std::abs(std::sin(gamma)) / ((SlatSeparation + SlatThickness / std::abs(std::sin(SlatAng))) * CosProfAng);
     513        4554 :             fEdge = min(1.0, std::abs(fEdge1));
     514             :         }
     515        4554 :         BlindBeamBeamTrans *= (1.0 - fEdge);
     516             :     }
     517             : 
     518       41235 :     return BlindBeamBeamTrans;
     519             : }
     520             : 
     521         808 : std::string &strip_trailing_zeros(std::string &InputString)
     522             : {
     523             :     // FUNCTION INFORMATION:
     524             :     //       AUTHOR         Stuart Mentzer (in-place version of RemoveTrailingZeros by Linda Lawrie)
     525             :     //       DATE WRITTEN   July 2014
     526             :     //       MODIFIED       na
     527             :     //       RE-ENGINEERED  na
     528             : 
     529             :     // PURPOSE OF THIS FUNCTION:
     530             :     // Remove trailing fractional zeros from floating point representation strings in place.
     531             : 
     532             :     static constexpr std::string_view ED("ED");
     533             :     static constexpr std::string_view zero_string("0.");
     534             : 
     535         808 :     assert(!has_any_of(InputString, "ed"));       // Pre Not using lowercase exponent letter
     536         808 :     assert(InputString == stripped(InputString)); // Pre Already stripped surrounding spaces
     537             : 
     538         808 :     if (has(InputString, '.') && (!has_any_of(InputString, ED))) { // Has decimal point and no exponent part
     539         645 :         std::string::size_type const pos(InputString.find_last_not_of('0'));
     540         645 :         if (pos + 1 < InputString.length()) {
     541         170 :             switch (pos) { // Handle [+/-].000... format
     542           0 :             case 0u:       // .0*
     543           0 :                 InputString = zero_string;
     544           0 :                 break;
     545          24 :             case 1u:
     546          24 :                 if (InputString[1] == '.') {
     547          24 :                     char const c0(InputString[0]);
     548          24 :                     if ((c0 == '+') || (c0 == '-')) {
     549           0 :                         InputString = zero_string;
     550           0 :                         break;
     551             :                     }
     552             :                 }
     553             :                 // fallthrough
     554             :             default:
     555         170 :                 InputString.erase(pos + 1);
     556             :             }
     557             :         }
     558             :     }
     559         808 :     return InputString; // Allows chaining
     560             : }
     561             : 
     562      183696 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
     563             : {
     564      183696 :     if (NumItemsInAvg <= 1) return; // no need to average/smooth
     565             : 
     566      362976 :     Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
     567             : 
     568    22625328 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     569    22443840 :         TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
     570    22443840 :         DataIn(i) = 0.0;
     571             :     }
     572             : 
     573    22625328 :     for (std::size_t i = 1; i <= DataIn.size(); ++i) {
     574   220349376 :         for (int j = 1; j <= NumItemsInAvg; ++j) {
     575   197905536 :             DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
     576             :         }
     577    22443840 :         DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
     578             :     }
     579             : }
     580             : 
     581       34638 : void ProcessDateString(EnergyPlusData &state,
     582             :                        std::string const &String,
     583             :                        int &PMonth,
     584             :                        int &PDay,
     585             :                        int &PWeekDay,
     586             :                        WeatherManager::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     587             :                        bool &ErrorsFound,
     588             :                        Optional_int PYear)
     589             : {
     590             : 
     591             :     // SUBROUTINE INFORMATION:
     592             :     //       AUTHOR         Linda Lawrie
     593             :     //       DATE WRITTEN   December 1999
     594             :     //       MODIFIED       na
     595             :     //       RE-ENGINEERED  na
     596             : 
     597             :     // PURPOSE OF THIS SUBROUTINE:
     598             :     // This subroutine will process a date from a string and determine
     599             :     // the proper month and day for that date string.
     600             : 
     601             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     602       34638 :     int FstNum{};
     603       34638 :     bool errFlag{};
     604       34638 :     int NumTokens{};
     605       34638 :     int TokenDay{};
     606       34638 :     int TokenMonth{};
     607       34638 :     int TokenWeekday{};
     608             : 
     609       34638 :     FstNum = int(UtilityRoutines::ProcessNumber(String, errFlag));
     610       34638 :     DateType = WeatherManager::DateType::Invalid;
     611       34638 :     if (!errFlag) {
     612             :         // Entered single number, do inverse JDay
     613        1520 :         if (FstNum == 0) {
     614        1520 :             PMonth = 0;
     615        1520 :             PDay = 0;
     616        1520 :             DateType = WeatherManager::DateType::MonthDay;
     617           0 :         } else if (FstNum < 0 || FstNum > 366) {
     618           0 :             ShowSevereError(state, "Invalid Julian date Entered=" + String);
     619           0 :             ErrorsFound = true;
     620             :         } else {
     621           0 :             InvOrdinalDay(FstNum, PMonth, PDay, 0);
     622           0 :             DateType = WeatherManager::DateType::LastDayInMonth;
     623             :         }
     624             :     } else {
     625             :         // Error when processing as number, try x/x
     626       33118 :         if (!present(PYear)) {
     627       31596 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
     628             :         } else {
     629        1522 :             int TokenYear = 0;
     630        1522 :             DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
     631        1522 :             PYear = TokenYear;
     632             :         }
     633       33118 :         if (DateType == WeatherManager::DateType::MonthDay) {
     634       32024 :             PDay = TokenDay;
     635       32024 :             PMonth = TokenMonth;
     636        1094 :         } else if (DateType == WeatherManager::DateType::NthDayInMonth || DateType == WeatherManager::DateType::LastDayInMonth) {
     637             :             // interpret as TokenDay TokenWeekday in TokenMonth
     638        1094 :             PDay = TokenDay;
     639        1094 :             PMonth = TokenMonth;
     640        1094 :             PWeekDay = TokenWeekday;
     641             :         }
     642             :     }
     643       34638 : }
     644             : 
     645       33118 : void DetermineDateTokens(EnergyPlusData &state,
     646             :                          std::string const &String,
     647             :                          int &NumTokens,                     // Number of tokens found in string
     648             :                          int &TokenDay,                      // Value of numeric field found
     649             :                          int &TokenMonth,                    // Value of Month field found (1=Jan, 2=Feb, etc)
     650             :                          int &TokenWeekday,                  // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
     651             :                          WeatherManager::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
     652             :                          bool &ErrorsFound,                  // Set to true if cannot process this string as a date
     653             :                          Optional_int TokenYear              // Value of Year if one appears to be present and this argument is present
     654             : )
     655             : {
     656             : 
     657             :     // SUBROUTINE INFORMATION:
     658             :     //       AUTHOR         Linda Lawrie
     659             :     //       DATE WRITTEN   August 2000
     660             :     //       MODIFIED       na
     661             :     //       RE-ENGINEERED  na
     662             : 
     663             :     // PURPOSE OF THIS SUBROUTINE:
     664             :     // This subroutine is invoked for date fields that appear to be strings (give
     665             :     // error when ProcessNumber is used).
     666             : 
     667             :     // METHODOLOGY EMPLOYED:
     668             :     // Delete everything that is extraneous to the date information needed.  Process what
     669             :     // is left.
     670             : 
     671             :     // SUBROUTINE PARAMETER DEFINITIONS:
     672             :     static constexpr int NumSingleChars(3);
     673             :     static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
     674             :     static constexpr int NumDoubleChars(6);
     675             :     static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
     676             :         "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want thse only at end of words
     677             :     static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
     678             :     static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
     679             : 
     680             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     681       66236 :     std::string CurrentString = String;
     682       33118 :     int Loop{};
     683       66236 :     Array1D_string Fields(3);
     684       33118 :     int NumField1{};
     685       33118 :     int NumField2{};
     686       33118 :     int NumField3{};
     687       33118 :     bool errFlag{};
     688       33118 :     bool InternalError = false;
     689       33118 :     bool WkDayInMonth = false;
     690             : 
     691       33118 :     NumTokens = 0;
     692       33118 :     TokenDay = 0;
     693       33118 :     TokenMonth = 0;
     694       33118 :     TokenWeekday = 0;
     695       33118 :     DateType = WeatherManager::DateType::Invalid;
     696       33118 :     if (present(TokenYear)) TokenYear = 0;
     697             :     // Take out separator characters, other extraneous stuff
     698             : 
     699      132472 :     for (Loop = 0; Loop < NumSingleChars; ++Loop) {
     700       99354 :         auto Pos = index(CurrentString, SingleChars[Loop]);
     701      162398 :         while (Pos != std::string::npos) {
     702       31522 :             CurrentString[Pos] = ' ';
     703       31522 :             Pos = index(CurrentString, SingleChars[Loop]);
     704             :         }
     705             :     }
     706             : 
     707      231826 :     for (Loop = 0; Loop < NumDoubleChars; ++Loop) {
     708      198708 :         auto Pos = index(CurrentString, DoubleChars[Loop]);
     709      203084 :         while (Pos != std::string::npos) {
     710        2188 :             CurrentString.replace(Pos, 2, "  ");
     711        2188 :             Pos = index(CurrentString, DoubleChars[Loop]);
     712        2188 :             WkDayInMonth = true;
     713             :         }
     714             :     }
     715             : 
     716       33118 :     strip(CurrentString);
     717       33118 :     if (CurrentString == BlankString) {
     718           0 :         ShowSevereError(state, "Invalid date field=" + String);
     719           0 :         ErrorsFound = true;
     720             :     } else {
     721       33118 :         Loop = 0;
     722      167778 :         while (Loop < 3) { // Max of 3 fields
     723       99354 :             if (CurrentString == BlankString) break;
     724       67330 :             auto Pos = index(CurrentString, ' ');
     725       67330 :             ++Loop;
     726       67330 :             if (Pos == std::string::npos) Pos = CurrentString.length();
     727       67330 :             Fields(Loop) = CurrentString.substr(0, Pos);
     728       67330 :             CurrentString.erase(0, Pos);
     729       67330 :             strip(CurrentString);
     730             :         }
     731       33118 :         if (not_blank(CurrentString)) {
     732           0 :             ShowSevereError(state, "Invalid date field=" + String);
     733           0 :             ErrorsFound = true;
     734       33118 :         } else if (Loop == 2) {
     735             :             // Field must be Day Month or Month Day (if both numeric, mon / day)
     736       32024 :             InternalError = false;
     737       32024 :             NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
     738       32024 :             if (errFlag) {
     739             :                 // Month day, but first field is not numeric, 2nd must be
     740         483 :                 NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
     741         483 :                 if (errFlag) {
     742           0 :                     ShowSevereError(state, "Invalid date field=" + String);
     743           0 :                     InternalError = true;
     744             :                 } else {
     745         483 :                     TokenDay = NumField2;
     746             :                 }
     747         483 :                 TokenMonth = UtilityRoutines::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
     748         483 :                 ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     749         483 :                 if (!InternalError) {
     750         483 :                     DateType = WeatherManager::DateType::MonthDay;
     751             :                 } else {
     752           0 :                     ErrorsFound = true;
     753             :                 }
     754             :             } else {
     755             :                 // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
     756       31541 :                 NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
     757       31541 :                 if (!errFlag) {
     758       31516 :                     TokenMonth = NumField1;
     759       31516 :                     TokenDay = NumField2;
     760       31516 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     761       31516 :                     if (!InternalError) {
     762       31516 :                         DateType = WeatherManager::DateType::MonthDay;
     763             :                     } else {
     764           0 :                         ErrorsFound = true;
     765             :                     }
     766             :                 } else { // 2nd field was not numeric.  Must be Month
     767          25 :                     TokenDay = NumField1;
     768          25 :                     TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     769          25 :                     ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
     770          25 :                     if (!InternalError) {
     771          25 :                         DateType = WeatherManager::DateType::MonthDay;
     772          25 :                         NumTokens = 2;
     773             :                     } else {
     774           0 :                         ErrorsFound = true;
     775             :                     }
     776             :                 }
     777             :             }
     778        1094 :         } else if (Loop == 3) {
     779             :             // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
     780        1094 :             if (WkDayInMonth) {
     781        1094 :                 NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
     782        1094 :                 if (!errFlag) { // the expected result
     783         902 :                     TokenDay = NumField1;
     784         902 :                     TokenWeekday = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     785         902 :                     if (TokenWeekday == 0) {
     786           0 :                         TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     787           0 :                         TokenWeekday = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     788           0 :                         if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     789             :                     } else {
     790         902 :                         TokenMonth = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     791         902 :                         if (TokenMonth == 0) InternalError = true;
     792             :                     }
     793         902 :                     DateType = WeatherManager::DateType::NthDayInMonth;
     794         902 :                     NumTokens = 3;
     795         902 :                     if (TokenDay < 0 || TokenDay > 5) InternalError = true;
     796             :                 } else { // first field was not numeric....
     797         192 :                     if (Fields(1) == "LA") {
     798         192 :                         DateType = WeatherManager::DateType::LastDayInMonth;
     799         192 :                         NumTokens = 3;
     800         192 :                         TokenWeekday = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
     801         192 :                         if (TokenWeekday == 0) {
     802           0 :                             TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
     803           0 :                             TokenWeekday = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
     804           0 :                             if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
     805             :                         } else {
     806         192 :                             TokenMonth = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
     807         192 :                             if (TokenMonth == 0) InternalError = true;
     808             :                         }
     809             :                     } else { // error....
     810           0 :                         ShowSevereError(state, "First date field not numeric, field=" + String);
     811             :                     }
     812             :                 }
     813             :             } else { // mm/dd/yyyy or yyyy/mm/dd
     814           0 :                 NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
     815           0 :                 NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
     816           0 :                 NumField3 = int(UtilityRoutines::ProcessNumber(Fields(3), errFlag));
     817           0 :                 DateType = WeatherManager::DateType::MonthDay;
     818             :                 // error detection later..
     819           0 :                 if (NumField1 > 100) {
     820           0 :                     if (present(TokenYear)) {
     821           0 :                         TokenYear = NumField1;
     822             :                     }
     823           0 :                     TokenMonth = NumField2;
     824           0 :                     TokenDay = NumField3;
     825           0 :                 } else if (NumField3 > 100) {
     826           0 :                     if (present(TokenYear)) {
     827           0 :                         TokenYear = NumField3;
     828             :                     }
     829           0 :                     TokenMonth = NumField1;
     830           0 :                     TokenDay = NumField2;
     831             :                 }
     832             :             }
     833             :         } else {
     834             :             // Not enough or too many fields
     835           0 :             ShowSevereError(state, "Invalid date field=" + String);
     836           0 :             ErrorsFound = true;
     837             :         }
     838             :     }
     839             : 
     840       33118 :     if (InternalError) {
     841           0 :         DateType = WeatherManager::DateType::Invalid;
     842           0 :         ErrorsFound = true;
     843             :     }
     844       33118 : }
     845             : 
     846       32024 : void ValidateMonthDay(EnergyPlusData &state,
     847             :                       std::string const &String, // REAL(r64) string being processed
     848             :                       int const Day,
     849             :                       int const Month,
     850             :                       bool &ErrorsFound)
     851             : {
     852             : 
     853             :     // SUBROUTINE INFORMATION:
     854             :     //       AUTHOR         Linda Lawrie
     855             :     //       DATE WRITTEN   August 2000
     856             :     //       MODIFIED       na
     857             :     //       RE-ENGINEERED  na
     858             : 
     859             :     // PURPOSE OF THIS SUBROUTINE:
     860             :     // This subroutine validates a potential Day, Month values, produces an error
     861             :     // message when not valid, and sets error flag.
     862             : 
     863             :     // SUBROUTINE PARAMETER DEFINITIONS:
     864             :     static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     865             : 
     866             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     867             :     bool InternalError;
     868             : 
     869       32024 :     InternalError = false;
     870       32024 :     if (Month < 1 || Month > 12) InternalError = true;
     871       32024 :     if (!InternalError) {
     872       32024 :         if (Day < 1 || Day > EndMonthDay[Month - 1]) InternalError = true;
     873             :     }
     874       32024 :     if (InternalError) {
     875           0 :         ShowSevereError(state, "Invalid Month Day date format=" + String);
     876           0 :         ErrorsFound = true;
     877             :     } else {
     878       32024 :         ErrorsFound = false;
     879             :     }
     880       32024 : }
     881             : 
     882      175227 : int OrdinalDay(int const Month,        // Month, 1..12
     883             :                int const Day,          // Day of Month, not validated by month
     884             :                int const LeapYearValue // 1 if leap year indicated, 0 if not
     885             : )
     886             : {
     887             : 
     888             :     // FUNCTION INFORMATION:
     889             :     //       AUTHOR         Linda K. Lawrie
     890             :     //       DATE WRITTEN   September 1997
     891             :     //       MODIFIED       na
     892             :     //       RE-ENGINEERED  from JDAYF in BLAST/IBLAST
     893             : 
     894             :     // PURPOSE OF THIS SUBROUTINE:
     895             :     // This subroutine returns the appropriate Julian Day value for the input
     896             :     // Month and Day.
     897             : 
     898             :     // Return value
     899             :     int JulianDay;
     900             : 
     901             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     902             :     static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     903             :     // End day numbers of each month (without Leap Year)
     904             : 
     905      175227 :     if (Month == 1) {
     906             :         //                                       CASE 1: JANUARY
     907       58347 :         JulianDay = Day;
     908             : 
     909      116880 :     } else if (Month == 2) {
     910             :         //                                       CASE 2: FEBRUARY
     911        2189 :         JulianDay = Day + EndDayofMonth[0];
     912             : 
     913      114691 :     } else if ((Month >= 3) && (Month <= 12)) {
     914             :         //                                       CASE 3: REMAINING MONTHS
     915      114691 :         JulianDay = Day + EndDayofMonth[Month - 2] + LeapYearValue;
     916             : 
     917             :     } else {
     918           0 :         JulianDay = 0;
     919             :     }
     920             : 
     921      175227 :     return JulianDay;
     922             : }
     923             : 
     924       76765 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
     925             : {
     926             : 
     927             :     // SUBROUTINE INFORMATION:
     928             :     //       AUTHOR         Linda Lawrie
     929             :     //       DATE WRITTEN   December 1999
     930             :     //       MODIFIED       na
     931             :     //       RE-ENGINEERED  na
     932             : 
     933             :     // PURPOSE OF THIS SUBROUTINE:
     934             :     // This subroutine performs and inverse Julian Day
     935             :     // calculation, using an input JulianDay and returning
     936             :     // appropriate Month and Day.
     937             : 
     938             :     // SUBROUTINE PARAMETER DEFINITIONS:
     939             :     static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
     940             : 
     941             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     942             :     int WMonth;
     943             :     int LeapAddPrev;
     944             :     int LeapAddCur;
     945             : 
     946       76765 :     if (Number < 0 || Number > 366) return;
     947      496305 :     for (WMonth = 1; WMonth <= 12; ++WMonth) {
     948      496305 :         if (WMonth == 1) {
     949       76765 :             LeapAddPrev = 0;
     950       76765 :             LeapAddCur = 0;
     951      419540 :         } else if (WMonth == 2) {
     952       69420 :             LeapAddPrev = 0;
     953       69420 :             LeapAddCur = LeapYr;
     954             :         } else {
     955      350120 :             LeapAddPrev = LeapYr;
     956      350120 :             LeapAddCur = LeapYr;
     957             :         }
     958      496305 :         if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) break;
     959             :     }
     960       76765 :     PMonth = WMonth;
     961       76765 :     PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
     962             : }
     963             : 
     964        6912 : bool BetweenDateHoursLeftInclusive(
     965             :     int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
     966             : {
     967        6912 :     Real64 TestRatioOfDay = TestHour / 24.0;
     968        6912 :     Real64 StartRatioOfDay = StartHour / 24.0;
     969        6912 :     Real64 EndRatioOfDay = EndHour / 24.0;
     970             : 
     971        6912 :     if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
     972        5376 :         return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
     973             :     } else { // EndDate < StartDate
     974        1536 :         return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
     975             :     }
     976             : }
     977             : 
     978          16 : bool BetweenDates(int const TestDate,  // Date to test
     979             :                   int const StartDate, // Start date in sequence
     980             :                   int const EndDate    // End date in sequence
     981             : )
     982             : {
     983             : 
     984             :     // FUNCTION INFORMATION:
     985             :     //       AUTHOR         Linda K. Lawrie
     986             :     //       DATE WRITTEN   June 2000
     987             :     //       MODIFIED       na
     988             :     //       RE-ENGINEERED  na
     989             : 
     990             :     // PURPOSE OF THIS FUNCTION:
     991             :     // This function returns true if the TestDate is between
     992             :     // (StartDate <= TestDate <= EndDate).
     993             : 
     994             :     // METHODOLOGY EMPLOYED:
     995             :     // The input dates are Julian Day format, year is irrelevant.
     996             :     // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
     997             :     // this routine accomodates.
     998             : 
     999             :     // REFERENCES:
    1000             :     // Adapted from BLAST BTWEEN function.
    1001             : 
    1002             :     // Return value
    1003             :     bool BetweenDates;
    1004             : 
    1005          16 :     BetweenDates = false; // Default case
    1006             : 
    1007          16 :     if (StartDate <= EndDate) { // Start Date <= End Date
    1008           0 :         if (TestDate >= StartDate && TestDate <= EndDate) BetweenDates = true;
    1009             :     } else { // EndDate <= StartDate
    1010          16 :         if (TestDate <= EndDate || TestDate >= StartDate) BetweenDates = true;
    1011             :     }
    1012             : 
    1013          16 :     return BetweenDates;
    1014             : }
    1015             : 
    1016     1920347 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
    1017             : {
    1018             : 
    1019             :     // FUNCTION INFORMATION:
    1020             :     //       AUTHOR         Linda K. Lawrie
    1021             :     //       DATE WRITTEN   April 2003
    1022             :     //       MODIFIED       na
    1023             :     //       RE-ENGINEERED  na
    1024             : 
    1025             :     // PURPOSE OF THIS FUNCTION:
    1026             :     // This function creates the current time interval of the system
    1027             :     // time step.
    1028             : 
    1029             :     // Using/Aliasing
    1030     1920347 :     auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    1031     1920347 :     auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    1032             : 
    1033             :     // Return value
    1034     1920347 :     std::string OutputString;
    1035             : 
    1036     1920347 :     Real64 constexpr FracToMin(60.0);
    1037             : 
    1038             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1039             :     Real64 ActualTimeS; // Start of current interval (HVAC time step)
    1040             :     Real64 ActualTimeE; // End of current interval (HVAC time step)
    1041             :     int ActualTimeHrS;
    1042             :     //  INTEGER ActualTimeHrE
    1043             :     int ActualTimeMinS;
    1044             : 
    1045             :     //  ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
    1046             :     // CR6902  ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
    1047             :     // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
    1048     1920347 :     ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
    1049     1920347 :     ActualTimeE = ActualTimeS + TimeStepSys;
    1050     1920347 :     ActualTimeHrS = int(ActualTimeS);
    1051             :     //  ActualTimeHrE=INT(ActualTimeE)
    1052     1920347 :     ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
    1053             : 
    1054     1920347 :     if (ActualTimeMinS == 60) {
    1055        5684 :         ++ActualTimeHrS;
    1056        5684 :         ActualTimeMinS = 0;
    1057             :     }
    1058     3840694 :     const auto TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
    1059     1920347 :     auto minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
    1060             : 
    1061     3840694 :     auto TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
    1062             : 
    1063     1920347 :     if (TimeStmpE[3] == ' ') {
    1064      344554 :         TimeStmpE[3] = '0';
    1065             :     }
    1066     1920347 :     OutputString = TimeStmpS + " - " + TimeStmpE;
    1067             : 
    1068     3840694 :     return OutputString;
    1069             : }
    1070             : 
    1071             : // returns the Julian date for the first, second, etc. day of week for a given month
    1072        3604 : int nthDayOfWeekOfMonth(EnergyPlusData &state,
    1073             :                         int const dayOfWeek,  // day of week (Sunday=1, Monday=2, ...)
    1074             :                         int const nthTime,    // nth time the day of the week occurs (first monday, third tuesday, ..)
    1075             :                         int const monthNumber // January = 1
    1076             : )
    1077             : {
    1078             :     // J. Glazer - August 2017
    1079        3604 :     int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
    1080        3604 :     int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
    1081             :     int jdatForNth;
    1082        3604 :     if (dayOfWeek >= dayOfWeekForFirstDay) {
    1083        1818 :         jdatForNth = firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
    1084             :     } else {
    1085        1786 :         jdatForNth = firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
    1086             :     }
    1087        3604 :     return jdatForNth;
    1088             : }
    1089             : 
    1090    12214865 : Real64 SafeDivide(Real64 const a, Real64 const b)
    1091             : {
    1092             : 
    1093             :     // returns a / b while preventing division by zero
    1094             : 
    1095             :     // Return value
    1096             :     Real64 c;
    1097             : 
    1098             :     // Locals
    1099    12214865 :     Real64 constexpr SMALL(1.E-10);
    1100             : 
    1101    12214865 :     if (std::abs(b) >= SMALL) {
    1102    12213741 :         c = a / b;
    1103             :     } else {
    1104        1124 :         c = a / sign(SMALL, b);
    1105             :     }
    1106    12214865 :     return c;
    1107             : }
    1108             : 
    1109   255955274 : void Iterate(Real64 &ResultX,  // ResultX is the final Iteration result passed back to the calling routine
    1110             :              Real64 const Tol, // Tolerance for Convergence
    1111             :              Real64 const X0,  // Current value of X
    1112             :              Real64 const Y0,  // Current value of the function Y(X)
    1113             :              Real64 &X1,       // First Previous values of X
    1114             :              Real64 &Y1,       // First Previous values of Y(X1)
    1115             :              int const Iter,   // Number of iterations
    1116             :              int &Cnvg         // Convergence flag  Cnvg = 0:  Not converged
    1117             : )
    1118             : {
    1119             : 
    1120             :     // SUBROUTINE INFORMATION:
    1121             :     //       AUTHOR         Richard Liesen
    1122             :     //       DATE WRITTEN   March 2004
    1123             :     //       MODIFIED       na
    1124             :     //       RE-ENGINEERED  na
    1125             : 
    1126             :     // PURPOSE OF THIS SUBROUTINE:
    1127             :     // Iterately solves for the value of X which satisfies Y(X)=0.
    1128             :     // The subroutine tests for convergence and provides a new guess for the value of the
    1129             :     // independent variable X.
    1130             : 
    1131             :     // REFERENCES:
    1132             :     // Linear Correction based on the RegulaFalsi routine in EnergyPlus
    1133             : 
    1134             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1135   255955274 :     Real64 constexpr small(1.e-9); // Small Number used to approximate zero
    1136   255955274 :     Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
    1137             : 
    1138             :     Real64 DY; // Linear fit result
    1139             : 
    1140             :     // Check for convergence by comparing change in X
    1141   255955274 :     if (Iter != 1) {
    1142   231641992 :         if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
    1143    24313222 :             ResultX = X0;
    1144    24313222 :             Cnvg = 1;
    1145    24313222 :             return;
    1146             :         }
    1147             :     }
    1148             : 
    1149             :     // Not converged.
    1150   231642052 :     Cnvg = 0;
    1151   231642052 :     if (Iter == 1) {
    1152             : 
    1153             :         // New guess is specified by Perturb
    1154    24313282 :         if (std::abs(X0) > small) {
    1155    24312766 :             ResultX = X0 * (1.0 + Perturb);
    1156             :         } else {
    1157         516 :             ResultX = Perturb;
    1158             :         }
    1159             : 
    1160             :     } else {
    1161             : 
    1162             :         // New guess calculated from LINEAR FIT of most recent two points
    1163   207328770 :         DY = Y0 - Y1;
    1164   207328770 :         if (std::abs(DY) < small) {
    1165           0 :             DY = small;
    1166             :         }
    1167             :         // new estimation
    1168             : 
    1169   207328770 :         ResultX = (Y0 * X1 - Y1 * X0) / DY;
    1170             :     }
    1171             : 
    1172   231642052 :     X1 = X0;
    1173   231642052 :     Y1 = Y0;
    1174             : }
    1175             : 
    1176       40820 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
    1177             : {
    1178             : 
    1179             :     // FUNCTION INFORMATION:
    1180             :     //       AUTHOR         Linda K. Lawrie
    1181             :     //       DATE WRITTEN   September 2001
    1182             :     //       MODIFIED       na
    1183             :     //       RE-ENGINEERED  na
    1184             : 
    1185             :     // PURPOSE OF THIS FUNCTION:
    1186             :     // This function looks up a number(integer) in a similar list of
    1187             :     // items and returns the index of the item in the list, if
    1188             :     // found.
    1189             : 
    1190             :     // Return value
    1191             :     int FindNumberInList;
    1192             : 
    1193             :     // Argument array dimensioning
    1194       40820 :     ListOfItems.dim(_);
    1195             : 
    1196             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1197             :     int Count;
    1198             : 
    1199       40820 :     FindNumberInList = 0;
    1200             : 
    1201      357346 :     for (Count = 1; Count <= NumItems; ++Count) {
    1202      323951 :         if (WhichNumber == ListOfItems(Count)) {
    1203        7425 :             FindNumberInList = Count;
    1204        7425 :             break;
    1205             :         }
    1206             :     }
    1207             : 
    1208       40820 :     return FindNumberInList;
    1209             : }
    1210             : 
    1211      297313 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
    1212             :                        int &Month,     // month in integer format (1-12)
    1213             :                        int &Day,       // day in integer format (1-31)
    1214             :                        int &Hour,      // hour in integer format (1-24)
    1215             :                        int &Minute     // minute in integer format (0:59)
    1216             : )
    1217             : {
    1218             : 
    1219             :     // SUBROUTINE INFORMATION:
    1220             :     //       AUTHOR         Linda Lawrie
    1221             :     //       DATE WRITTEN   March 2000
    1222             :     //       MODIFIED       na
    1223             :     //       RE-ENGINEERED  na
    1224             : 
    1225             :     // PURPOSE OF THIS SUBROUTINE:
    1226             :     // This subroutine decodes the "packed" integer representation of
    1227             :     // the Month, Day, Hour, and Minute.  Packed integers are used to
    1228             :     // save memory allocation.  Original idea for this routine is contained
    1229             :     // in DECMDH, BLAST code, by Jean Baugh.
    1230             : 
    1231             :     // METHODOLOGY EMPLOYED:
    1232             :     // Using maximum integer concept the original date can be decoded
    1233             :     // from the packed single word.  This relies on 4 byte integer representation
    1234             :     // as a minimum (capable of representing up to 2,147,483,647).
    1235             : 
    1236             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1237             :     static constexpr int DecMon(100 * 100 * 100);
    1238             :     static constexpr int DecDay(100 * 100);
    1239             :     static constexpr int DecHr(100);
    1240             : 
    1241             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1242             :     int TmpItem;
    1243             : 
    1244      297313 :     TmpItem = Item;
    1245      297313 :     Month = TmpItem / DecMon;
    1246      297313 :     TmpItem = (TmpItem - Month * DecMon);
    1247      297313 :     Day = TmpItem / DecDay;
    1248      297313 :     TmpItem -= Day * DecDay;
    1249      297313 :     Hour = TmpItem / DecHr;
    1250      297313 :     Minute = mod(TmpItem, DecHr);
    1251      297313 : }
    1252             : 
    1253        2133 : int DetermineMinuteForReporting(EnergyPlusData &state, OutputProcessor::TimeStepType t_timeStepType) // kind of reporting, Zone Timestep or System
    1254             : {
    1255             : 
    1256             :     // FUNCTION INFORMATION:
    1257             :     //       AUTHOR         Linda Lawrie
    1258             :     //       DATE WRITTEN   January 2012
    1259             :     //       MODIFIED       na
    1260             :     //       RE-ENGINEERED  na
    1261             : 
    1262             :     // PURPOSE OF THIS FUNCTION:
    1263             :     // When reporting peaks, minutes are used but not necessarily easily calculated.
    1264             : 
    1265             :     // METHODOLOGY EMPLOYED:
    1266             :     // Could use the access to the minute as OP (OutputProcessor) does but uses
    1267             :     // external calculation.
    1268             : 
    1269             :     // Using/Aliasing
    1270        2133 :     auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    1271        2133 :     auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    1272             : 
    1273             :     // Return value
    1274             :     int ActualTimeMin; // calculated Minute for reporting
    1275             : 
    1276             :     // FUNCTION PARAMETER DEFINITIONS:
    1277        2133 :     Real64 constexpr FracToMin(60.0);
    1278             : 
    1279             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1280             :     Real64 ActualTimeS; // Start of current interval (HVAC time step)
    1281             :     Real64 ActualTimeE; // End of current interval (HVAC time step)
    1282             :     int ActualTimeHrS;
    1283             : 
    1284        2133 :     if (t_timeStepType == OutputProcessor::TimeStepType::System) {
    1285        1931 :         ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
    1286        1931 :         ActualTimeE = ActualTimeS + TimeStepSys;
    1287        1931 :         ActualTimeHrS = int(ActualTimeS);
    1288        1931 :         ActualTimeMin = nint((ActualTimeE - ActualTimeHrS) * FracToMin);
    1289             :     } else {
    1290         202 :         ActualTimeMin = (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)) * FracToMin;
    1291             :     }
    1292             : 
    1293        2133 :     return ActualTimeMin;
    1294             : }
    1295             : 
    1296      692612 : void EncodeMonDayHrMin(int &Item,       // word containing encoded month, day, hour, minute
    1297             :                        int const Month, // month in integer format (1:12)
    1298             :                        int const Day,   // day in integer format (1:31)
    1299             :                        int const Hour,  // hour in integer format (1:24)
    1300             :                        int const Minute // minute in integer format (0:59)
    1301             : )
    1302             : {
    1303             : 
    1304             :     // SUBROUTINE INFORMATION:
    1305             :     //       AUTHOR         Linda Lawrie
    1306             :     //       DATE WRITTEN   March 2000
    1307             :     //       MODIFIED       na
    1308             :     //       RE-ENGINEERED  na
    1309             : 
    1310             :     // PURPOSE OF THIS SUBROUTINE:
    1311             :     // This subroutine encodes the "packed" integer representation of
    1312             :     // the Month, Day, Hour, and Minute.  Packed integers are used to
    1313             :     // save memory allocation.  Original idea for this routine is contained
    1314             :     // in DECMDH, BLAST code, by Jean Baugh.
    1315             : 
    1316             :     // METHODOLOGY EMPLOYED:
    1317             :     // Using maximum integer concept the original date can be decoded
    1318             :     // from the packed single word.  This relies on 4 byte integer representation
    1319             :     // as a minimum (capable of representing up to 2,147,483,647).
    1320             : 
    1321      692612 :     Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
    1322      692612 : }
    1323             : 
    1324           0 : int LogicalToInteger(bool const Flag)
    1325             : {
    1326             :     // SUBROUTINE INFORMATION:
    1327             :     //       AUTHOR         Dimitri Curtil
    1328             :     //       DATE WRITTEN   November 2004
    1329             :     //       MODIFIED       na
    1330             :     //       RE-ENGINEERED  na
    1331             : 
    1332             :     // PURPOSE OF THIS FUNCTION:
    1333             :     // This subroutine uses an input logical and makes
    1334             :     // an integer (true=1, false=0)
    1335             : 
    1336             :     // Return value
    1337             :     int LogicalToInteger;
    1338             : 
    1339           0 :     if (Flag) {
    1340           0 :         LogicalToInteger = 1;
    1341             :     } else {
    1342           0 :         LogicalToInteger = 0;
    1343             :     }
    1344             : 
    1345           0 :     return LogicalToInteger;
    1346             : }
    1347             : 
    1348           0 : Real64 GetCurrentHVACTime(EnergyPlusData &state)
    1349             : {
    1350             :     // SUBROUTINE INFORMATION:
    1351             :     //       AUTHOR         Dimitri Curtil
    1352             :     //       DATE WRITTEN   November 2004
    1353             :     //       MODIFIED       na
    1354             :     //       RE-ENGINEERED  na
    1355             : 
    1356             :     // PURPOSE OF THIS FUNCTION:
    1357             :     // This routine returns the time in seconds at the end of the current HVAC step.
    1358             : 
    1359             :     // Using/Aliasing
    1360           0 :     auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    1361           0 :     auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    1362             : 
    1363             :     // Return value
    1364             :     Real64 GetCurrentHVACTime;
    1365             : 
    1366             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1367             :     Real64 CurrentHVACTime;
    1368             : 
    1369             :     // This is the correct formula that does not use MinutesPerSystemTimeStep, which would
    1370             :     // erronously truncate all sub-minute system time steps down to the closest full minute.
    1371             :     // Maybe later TimeStepZone, TimeStepSys and SysTimeElapsed could also be specified
    1372             :     // as real.
    1373           0 :     CurrentHVACTime = (state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone) + SysTimeElapsed + TimeStepSys;
    1374           0 :     GetCurrentHVACTime = CurrentHVACTime * DataGlobalConstants::SecInHour;
    1375             : 
    1376           0 :     return GetCurrentHVACTime;
    1377             : }
    1378             : 
    1379     2638872 : Real64 GetPreviousHVACTime(EnergyPlusData &state)
    1380             : {
    1381             :     // SUBROUTINE INFORMATION:
    1382             :     //       AUTHOR         Dimitri Curtil
    1383             :     //       DATE WRITTEN   November 2004
    1384             :     //       MODIFIED       na
    1385             :     //       RE-ENGINEERED  na
    1386             : 
    1387             :     // PURPOSE OF THIS FUNCTION:
    1388             :     // This routine returns the time in seconds at the beginning of the current HVAC step.
    1389             : 
    1390             :     // Using/Aliasing
    1391     2638872 :     auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    1392             : 
    1393             :     // Return value
    1394             :     Real64 GetPreviousHVACTime;
    1395             : 
    1396             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1397             :     Real64 PreviousHVACTime;
    1398             : 
    1399             :     // This is the correct formula that does not use MinutesPerSystemTimeStep, which would
    1400             :     // erronously truncate all sub-minute system time steps down to the closest full minute.
    1401     2638872 :     PreviousHVACTime = (state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone) + SysTimeElapsed;
    1402     2638872 :     GetPreviousHVACTime = PreviousHVACTime * DataGlobalConstants::SecInHour;
    1403             : 
    1404     2638872 :     return GetPreviousHVACTime;
    1405             : }
    1406             : 
    1407           0 : std::string CreateHVACTimeIntervalString(EnergyPlusData &state)
    1408             : {
    1409             : 
    1410             :     // FUNCTION INFORMATION:
    1411             :     //       AUTHOR         Dimitri Curtil
    1412             :     //       DATE WRITTEN   January 2005
    1413             :     //       MODIFIED       na
    1414             :     //       RE-ENGINEERED  na
    1415             : 
    1416             :     // PURPOSE OF THIS FUNCTION:
    1417             :     // This function creates the time stamp with the current time interval for the HVAC
    1418             :     // time step.
    1419             : 
    1420             :     // Return value
    1421           0 :     std::string OutputString;
    1422             : 
    1423           0 :     OutputString = CreateTimeIntervalString(GetPreviousHVACTime(state), GetCurrentHVACTime(state));
    1424             : 
    1425           0 :     return OutputString;
    1426             : }
    1427             : 
    1428           0 : std::string CreateTimeString(Real64 const Time) // Time in seconds
    1429             : {
    1430             : 
    1431             :     // FUNCTION INFORMATION:
    1432             :     //       AUTHOR         Dimitri Curtil
    1433             :     //       DATE WRITTEN   January 2005
    1434             :     //       MODIFIED       na
    1435             :     //       RE-ENGINEERED  na
    1436             : 
    1437             :     // PURPOSE OF THIS FUNCTION:
    1438             :     // This function creates the time stamp string from the time value specified in seconds.
    1439             :     // Inspired by similar function CreateSysTimeIntervalString() in General.cc
    1440             :     // However, this function provides better accuracy for sub-minute time steps
    1441             :     // by also showing information down to the 10th of a second.
    1442             :     // Note that Time is expected to be specified in REAL(r64).
    1443             : 
    1444             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1445             :     int Hours;      // Number of hours <= 24
    1446             :     int Minutes;    // Remaining minutes < 60
    1447             :     Real64 Seconds; // Remaining seconds < 60
    1448             : 
    1449           0 :     ParseTime(Time, Hours, Minutes, Seconds);
    1450             : 
    1451             :     // TimeStamp written with formatting
    1452             :     // "hh:mm:ss.s"
    1453           0 :     return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
    1454             : }
    1455             : 
    1456           0 : std::string CreateTimeIntervalString(Real64 const StartTime, // Start of current interval in seconds
    1457             :                                      Real64 const EndTime    // End of current interval in seconds
    1458             : )
    1459             : {
    1460             : 
    1461             :     // FUNCTION INFORMATION:
    1462             :     //       AUTHOR         Dimitri Curtil
    1463             :     //       DATE WRITTEN   January 2005
    1464             :     //       MODIFIED       na
    1465             :     //       RE-ENGINEERED  na
    1466             : 
    1467             :     // PURPOSE OF THIS FUNCTION:
    1468             :     // This function creates the time stamp with the current time interval from start and end
    1469             :     // time values specified in seconds.
    1470             :     // Inspired by similar function CreateSysTimeIntervalString() in General.cc
    1471             : 
    1472             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1473           0 :     std::string TimeStmpS; // Character representation of start of interval
    1474           0 :     std::string TimeStmpE; // Character representation of end of interval
    1475             : 
    1476           0 :     TimeStmpS = CreateTimeString(StartTime);
    1477           0 :     TimeStmpE = CreateTimeString(EndTime);
    1478             : 
    1479           0 :     return TimeStmpS + " - " + TimeStmpE;
    1480             : }
    1481             : 
    1482           0 : void ParseTime(Real64 const Time, // Time value in seconds
    1483             :                int &Hours,        // Number of hours
    1484             :                int &Minutes,      // Number of minutes < 60
    1485             :                Real64 &Seconds    // Number of seconds < 60
    1486             : )
    1487             : {
    1488             :     // FUNCTION INFORMATION:
    1489             :     //       AUTHOR         Dimitri Curtil
    1490             :     //       DATE WRITTEN   January 2005
    1491             :     //       MODIFIED       na
    1492             :     //       RE-ENGINEERED  na
    1493             : 
    1494             :     // PURPOSE OF THIS FUNCTION:
    1495             :     // This subroutine decomposes a time value specified in seconds
    1496             :     // into a triplet { hours : minutes : seconds } such that
    1497             :     // - minutes < 60
    1498             :     // - seconds < 60
    1499             : 
    1500             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1501           0 :     int constexpr MinToSec(60);
    1502           0 :     int const HourToSec(MinToSec * 60);
    1503             : 
    1504             :     // Get number of hours
    1505             :     // This might undershoot the actual number of hours. See DO WHILE loop.
    1506           0 :     Hours = int(Time) / HourToSec;
    1507             : 
    1508             :     // Compute remainder in seconds
    1509           0 :     Real64 Remainder = (Time - Hours * HourToSec);
    1510             : 
    1511             :     // Compute minutes
    1512           0 :     Minutes = int(Remainder) / MinToSec;
    1513             : 
    1514             :     // Compute remainder in seconds
    1515           0 :     Remainder -= Minutes * MinToSec;
    1516             : 
    1517             :     // Compute seconds
    1518           0 :     Seconds = Remainder;
    1519           0 : }
    1520             : 
    1521       12335 : void ScanForReports(EnergyPlusData &state,
    1522             :                     std::string const &reportName,
    1523             :                     bool &DoReport,
    1524             :                     Optional_string_const ReportKey,
    1525             :                     Optional_string Option1,
    1526             :                     Optional_string Option2)
    1527             : {
    1528             : 
    1529             :     // SUBROUTINE INFORMATION:
    1530             :     //       AUTHOR         Linda Lawrie
    1531             :     //       DATE WRITTEN   March 2009
    1532             :     //       MODIFIED       na
    1533             :     //       RE-ENGINEERED  na
    1534             : 
    1535             :     // PURPOSE OF THIS SUBROUTINE:
    1536             :     // This routine scans for the global "reports" settings, such as Variable Dictionary,
    1537             :     // Surfaces (and options), Constructions, etc.
    1538             : 
    1539             :     // METHODOLOGY EMPLOYED:
    1540             :     // First time routine is called, all the viable combinations/settings for the reports are
    1541             :     // stored in SAVEd variables.  Later callings will retrieve those.
    1542             : 
    1543             :     // Using/Aliasing
    1544             : 
    1545             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1546             :     int NumReports;
    1547             :     int RepNum;
    1548             :     int NumNames;
    1549             :     int NumNumbers;
    1550             :     int IOStat;
    1551       12335 :     auto &DXFOption1 = state.dataGeneral->DXFOption1;
    1552       12335 :     auto &DXFOption2 = state.dataGeneral->DXFOption2;
    1553       12335 :     auto &DXFWFOption1 = state.dataGeneral->DXFWFOption1;
    1554       12335 :     auto &DXFWFOption2 = state.dataGeneral->DXFWFOption2;
    1555       12335 :     auto &VRMLOption1 = state.dataGeneral->VRMLOption1;
    1556       12335 :     auto &VRMLOption2 = state.dataGeneral->VRMLOption2;
    1557       12335 :     auto &ViewRptOption1 = state.dataGeneral->ViewRptOption1;
    1558       12335 :     auto &LineRptOption1 = state.dataGeneral->LineRptOption1;
    1559       12335 :     auto &VarDictOption1 = state.dataGeneral->VarDictOption1;
    1560       12335 :     auto &VarDictOption2 = state.dataGeneral->VarDictOption2;
    1561       12335 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    1562             : 
    1563       12335 :     if (state.dataGeneral->GetReportInput) {
    1564             : 
    1565         771 :         cCurrentModuleObject = "Output:Surfaces:List";
    1566             : 
    1567         771 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1568             : 
    1569             :         enum
    1570             :         {
    1571             :             EMPTY,
    1572             :             LINES,
    1573             :             VERTICES,
    1574             :             DETAILS,
    1575             :             DETAILSWITHVERTICES,
    1576             :             COSTINFO,
    1577             :             VIEWFACTORINFO,
    1578             :             DECAYCURVESFROMCOMPONENTLOADSSUMMARY
    1579             :         };
    1580             :         std::map<std::string, int> localMap = {{"", EMPTY},
    1581             :                                                {"LINES", LINES},
    1582             :                                                {"VERTICES", VERTICES},
    1583             :                                                {"DETAILS", DETAILS},
    1584             :                                                {"DETAILED", DETAILS},
    1585             :                                                {"DETAIL", DETAILS},
    1586             :                                                {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
    1587             :                                                {"DETAILVERTICES", DETAILSWITHVERTICES},
    1588             :                                                {"COSTINFO", COSTINFO},
    1589             :                                                {"VIEWFACTORINFO", VIEWFACTORINFO},
    1590        1542 :                                                {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
    1591             : 
    1592        1017 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1593        1722 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1594             :                                                                      cCurrentModuleObject,
    1595             :                                                                      RepNum,
    1596         246 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1597             :                                                                      NumNames,
    1598         246 :                                                                      state.dataIPShortCut->rNumericArgs,
    1599             :                                                                      NumNumbers,
    1600             :                                                                      IOStat,
    1601         246 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1602         246 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1603         246 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1604         246 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1605             : 
    1606             :             try {
    1607         246 :                 int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
    1608         246 :                 switch (value) {
    1609          50 :                 case LINES:
    1610          50 :                     state.dataGeneral->LineRpt = true;
    1611          50 :                     LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1612          50 :                     break;
    1613           5 :                 case VERTICES:
    1614           5 :                     state.dataGeneral->SurfVert = true;
    1615           5 :                     break;
    1616         140 :                 case DETAILS:
    1617         140 :                     state.dataGeneral->SurfDet = true;
    1618         140 :                     break;
    1619          31 :                 case DETAILSWITHVERTICES:
    1620          31 :                     state.dataGeneral->SurfDetWVert = true;
    1621          31 :                     break;
    1622           7 :                 case COSTINFO:
    1623             :                     //   Custom case for reporting surface info for cost estimates (for first costs in opitimzing)
    1624           7 :                     state.dataGeneral->CostInfo = true;
    1625           7 :                     break;
    1626           8 :                 case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
    1627           8 :                     state.dataGeneral->ViewFactorInfo = true;
    1628           8 :                     ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1629           8 :                     break;
    1630           5 :                 case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
    1631             :                                                            // load component report appear in the EIO file
    1632           5 :                     state.dataGlobal->ShowDecayCurvesInEIO = true;
    1633           5 :                     break;
    1634           0 :                 default: // including empty
    1635           0 :                     ShowWarningError(state, cCurrentModuleObject + ": No " + state.dataIPShortCut->cAlphaFieldNames(1) + " supplied.");
    1636           0 :                     ShowContinueError(state,
    1637             :                                       R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1638             :                 }
    1639           0 :             } catch (int e) {
    1640           0 :                 ShowWarningError(state,
    1641           0 :                                  cCurrentModuleObject + ": Invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
    1642           0 :                                      state.dataIPShortCut->cAlphaArgs(1) + "\" supplied.");
    1643           0 :                 ShowContinueError(state,
    1644             :                                   R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
    1645             :             }
    1646             :         }
    1647             : 
    1648         771 :         cCurrentModuleObject = "Output:Surfaces:Drawing";
    1649             : 
    1650         771 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1651        1299 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1652        3696 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1653             :                                                                      cCurrentModuleObject,
    1654             :                                                                      RepNum,
    1655         528 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1656             :                                                                      NumNames,
    1657         528 :                                                                      state.dataIPShortCut->rNumericArgs,
    1658             :                                                                      NumNumbers,
    1659             :                                                                      IOStat,
    1660         528 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1661         528 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1662         528 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1663         528 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1664             : 
    1665             :             ReportType checkReportType =
    1666         528 :                 static_cast<ReportType>(getEnumerationValue(ReportTypeNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(1))));
    1667             : 
    1668         528 :             switch (checkReportType) {
    1669         468 :             case ReportType::DXF: {
    1670         468 :                 state.dataGeneral->DXFReport = true;
    1671         468 :                 DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1672         468 :                 DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1673         468 :             } break;
    1674          27 :             case ReportType::DXFWireFrame: {
    1675          27 :                 state.dataGeneral->DXFWFReport = true;
    1676          27 :                 DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1677          27 :                 DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1678          27 :             } break;
    1679          33 :             case ReportType::VRML: {
    1680          33 :                 state.dataGeneral->VRMLReport = true;
    1681          33 :                 VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
    1682          33 :                 VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
    1683          33 :             } break;
    1684           0 :             default:
    1685           0 :                 break;
    1686             :             }
    1687             :         }
    1688             : 
    1689         771 :         RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
    1690         771 :         if (RepNum > 0) {
    1691           0 :             state.dataGeneral->VarDict = true;
    1692           0 :             VarDictOption1 = "REGULAR";
    1693           0 :             VarDictOption2 = "";
    1694             :         }
    1695             : 
    1696         771 :         cCurrentModuleObject = "Output:VariableDictionary";
    1697             : 
    1698         771 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1699        1537 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1700        5362 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1701             :                                                                      cCurrentModuleObject,
    1702             :                                                                      RepNum,
    1703         766 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1704             :                                                                      NumNames,
    1705         766 :                                                                      state.dataIPShortCut->rNumericArgs,
    1706             :                                                                      NumNumbers,
    1707             :                                                                      IOStat,
    1708         766 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1709         766 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1710         766 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1711         766 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1712         766 :             state.dataGeneral->VarDict = true;
    1713         766 :             VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
    1714         766 :             VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
    1715             :         }
    1716             : 
    1717         771 :         cCurrentModuleObject = "Output:Constructions";
    1718         771 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1719        1080 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1720        2163 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1721             :                                                                      cCurrentModuleObject,
    1722             :                                                                      RepNum,
    1723         309 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1724             :                                                                      NumNames,
    1725         309 :                                                                      state.dataIPShortCut->rNumericArgs,
    1726             :                                                                      NumNumbers,
    1727             :                                                                      IOStat,
    1728         309 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1729         309 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1730         309 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1731         309 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1732         309 :             if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
    1733         298 :                 state.dataGeneral->Constructions = true;
    1734          11 :             } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
    1735          11 :                 state.dataGeneral->Materials = true;
    1736             :             }
    1737         309 :             if (NumNames > 1) {
    1738           2 :                 if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
    1739           0 :                     state.dataGeneral->Constructions = true;
    1740           2 :                 } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
    1741           2 :                     state.dataGeneral->Materials = true;
    1742             :                 }
    1743             :             }
    1744             :         }
    1745             : 
    1746         771 :         cCurrentModuleObject = "Output:EnergyManagementSystem";
    1747         771 :         NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1748         810 :         for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
    1749         273 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1750             :                                                                      cCurrentModuleObject,
    1751             :                                                                      RepNum,
    1752          39 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1753             :                                                                      NumNames,
    1754          39 :                                                                      state.dataIPShortCut->rNumericArgs,
    1755             :                                                                      NumNumbers,
    1756             :                                                                      IOStat,
    1757          39 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1758          39 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1759          39 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1760          39 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1761             : 
    1762          39 :             state.dataGeneral->EMSoutput = true;
    1763             : 
    1764             :             AvailRpt CheckAvailRpt =
    1765          39 :                 static_cast<AvailRpt>(getEnumerationValue(AvailRptNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(1))));
    1766          39 :             state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1767          39 :             state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
    1768             : 
    1769          39 :             CheckAvailRpt =
    1770          78 :                 static_cast<AvailRpt>(getEnumerationValue(AvailRptNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(2))));
    1771          39 :             state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
    1772          39 :             state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
    1773             : 
    1774             :             ERLdebugOutputLevel CheckERLlevel = static_cast<ERLdebugOutputLevel>(
    1775          39 :                 getEnumerationValue(ERLdebugOutputLevelNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(3))));
    1776          39 :             state.dataRuntimeLang->OutputEMSErrors =
    1777          39 :                 (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1778          39 :             state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
    1779             :         }
    1780             : 
    1781         771 :         state.dataGeneral->GetReportInput = false;
    1782             :     }
    1783             : 
    1784             :     // Process the Scan Request
    1785       12335 :     DoReport = false;
    1786             : 
    1787             :     ReportName rptName =
    1788       12335 :         static_cast<ReportName>(getEnumerationValue(ReportNamesUC, UtilityRoutines::MakeUPPERCase(UtilityRoutines::MakeUPPERCase(reportName))));
    1789       12335 :     switch (rptName) {
    1790        2314 :     case ReportName::Constructions: {
    1791        2314 :         if (present(ReportKey)) {
    1792        2314 :             if (UtilityRoutines::SameString(ReportKey(), "Constructions")) DoReport = state.dataGeneral->Constructions;
    1793        2314 :             if (UtilityRoutines::SameString(ReportKey(), "Materials")) DoReport = state.dataGeneral->Materials;
    1794             :         }
    1795        2314 :     } break;
    1796        1542 :     case ReportName::Viewfactorinfo: {
    1797        1542 :         DoReport = state.dataGeneral->ViewFactorInfo;
    1798        1542 :         if (present(Option1)) Option1 = ViewRptOption1;
    1799        1542 :     } break;
    1800         769 :     case ReportName::Variabledictionary: {
    1801         769 :         DoReport = state.dataGeneral->VarDict;
    1802         769 :         if (present(Option1)) Option1 = VarDictOption1;
    1803         769 :         if (present(Option2)) Option2 = VarDictOption2;
    1804             :         //    CASE ('SCHEDULES')
    1805             :         //     DoReport=SchRpt
    1806             :         //      IF (PRESENT(Option1)) Option1=SchRptOption
    1807         769 :     } break;
    1808        6939 :     case ReportName::Surfaces: {
    1809        6939 :         RptKey rptKey = static_cast<RptKey>(getEnumerationValue(RptKeyNamesUC, UtilityRoutines::MakeUPPERCase(ReportKey())));
    1810        6939 :         switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
    1811         771 :         case RptKey::Costinfo: {
    1812         771 :             DoReport = state.dataGeneral->CostInfo;
    1813         771 :         } break;
    1814         771 :         case RptKey::DXF: {
    1815         771 :             DoReport = state.dataGeneral->DXFReport;
    1816         771 :             if (present(Option1)) Option1 = DXFOption1;
    1817         771 :             if (present(Option2)) Option2 = DXFOption2;
    1818         771 :         } break;
    1819         771 :         case RptKey::DXFwireframe: {
    1820         771 :             DoReport = state.dataGeneral->DXFWFReport;
    1821         771 :             if (present(Option1)) Option1 = DXFWFOption1;
    1822         771 :             if (present(Option2)) Option2 = DXFWFOption2;
    1823         771 :         } break;
    1824         771 :         case RptKey::VRML: {
    1825         771 :             DoReport = state.dataGeneral->VRMLReport;
    1826         771 :             if (present(Option1)) Option1 = VRMLOption1;
    1827         771 :             if (present(Option2)) Option2 = VRMLOption2;
    1828         771 :         } break;
    1829         771 :         case RptKey::Vertices: {
    1830         771 :             DoReport = state.dataGeneral->SurfVert;
    1831         771 :         } break;
    1832        1542 :         case RptKey::Details: {
    1833        1542 :             DoReport = state.dataGeneral->SurfDet;
    1834        1542 :         } break;
    1835         771 :         case RptKey::DetailsWithVertices: {
    1836         771 :             DoReport = state.dataGeneral->SurfDetWVert;
    1837         771 :         } break;
    1838         771 :         case RptKey::Lines: {
    1839         771 :             DoReport = state.dataGeneral->LineRpt;
    1840         771 :             if (present(Option1)) Option1 = LineRptOption1;
    1841         771 :         } break;
    1842           0 :         default:
    1843           0 :             break;
    1844             :         }
    1845        6939 :     } break;
    1846         771 :     case ReportName::Energymanagementsystem: {
    1847         771 :         DoReport = state.dataGeneral->EMSoutput;
    1848         771 :     } break;
    1849           0 :     default:
    1850           0 :         break;
    1851             :     }
    1852       12335 : }
    1853             : 
    1854          49 : void CheckCreatedZoneItemName(EnergyPlusData &state,
    1855             :                               std::string_view const calledFrom,              // routine called from
    1856             :                               std::string const &CurrentObject,               // object being parsed
    1857             :                               std::string const &ZoneName,                    // Zone Name associated
    1858             :                               std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
    1859             :                               std::string const &ItemName,                    // Item name (People, Lights, etc object)
    1860             :                               Array1_string const &ItemNames,                 // Item Names to check for duplication
    1861             :                               int const NumItems,                             // Number of items in ItemNames array
    1862             :                               std::string &ResultName,                        // Resultant name
    1863             :                               bool &errFlag                                   // Error flag set to true if error found here.
    1864             : )
    1865             : {
    1866             : 
    1867             :     // SUBROUTINE INFORMATION:
    1868             :     //       AUTHOR         Linda Lawrie
    1869             :     //       DATE WRITTEN   December 2012
    1870             :     //       MODIFIED       na
    1871             :     //       RE-ENGINEERED  na
    1872             : 
    1873             :     // PURPOSE OF THIS SUBROUTINE:
    1874             :     // This routine checks "global" objects (that is, ones with ZoneList used in the name
    1875             :     // specification) along with a specific name for the current object for length and duplication
    1876             :     // with previous objects of that class.
    1877             : 
    1878          49 :     errFlag = false;
    1879          49 :     std::string::size_type const ItemNameLength = len(ItemName);
    1880          49 :     std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
    1881          49 :     ResultName = ZoneName + ' ' + ItemName;
    1882          49 :     bool TooLong = false;
    1883          49 :     if (ItemLength > DataGlobalConstants::MaxNameLength) {
    1884           0 :         ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
    1885           0 :         ShowContinueError(state, "Object Name=\"" + ItemName + "\".");
    1886           0 :         ShowContinueError(state, "ZoneList/Zone Name=\"" + ZoneName + "\".");
    1887           0 :         ShowContinueError(
    1888             :             state,
    1889           0 :             format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, DataGlobalConstants::MaxNameLength));
    1890           0 :         ShowContinueError(state,
    1891           0 :                           format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
    1892           0 :                                  MaxZoneNameLength + 1 + ItemNameLength - DataGlobalConstants::MaxNameLength));
    1893           0 :         ShowContinueError(state, "name that will be used (may be needed in reporting)=\"" + ResultName + "\".");
    1894           0 :         TooLong = true;
    1895             :     }
    1896             : 
    1897          49 :     int FoundItem = UtilityRoutines::FindItemInList(ResultName, ItemNames, NumItems);
    1898             : 
    1899          49 :     if (FoundItem != 0) {
    1900           0 :         ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
    1901           0 :         ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
    1902           0 :         if (TooLong) ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
    1903           0 :         ResultName = "xxxxxxx";
    1904           0 :         errFlag = true;
    1905             :     }
    1906          49 : }
    1907             : 
    1908             : // This is from OpenStudio
    1909           0 : std::vector<std::string> splitString(const std::string &string, char delimiter)
    1910             : {
    1911           0 :     std::vector<std::string> results;
    1912           0 :     if (!string.empty()) { // Only do work if there is work to do
    1913           0 :         std::stringstream stream(string);
    1914           0 :         std::string substring;
    1915           0 :         while (std::getline(stream, substring, delimiter)) { // Loop and fill the results vector
    1916           0 :             results.push_back(substring);
    1917             :         }
    1918           0 :         if (*(string.end() - 1) == ',') { // Add an empty string if the last char is the delimiter
    1919           0 :             results.emplace_back();
    1920             :         }
    1921             :     }
    1922           0 :     return results;
    1923             : }
    1924             : 
    1925           0 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
    1926             : {
    1927             :     int currentDate;
    1928           0 :     int reportStartDate = state.dataWeatherManager->ReportPeriodInput(periodIdx).startJulianDate;
    1929           0 :     int reportStartHour = state.dataWeatherManager->ReportPeriodInput(periodIdx).startHour;
    1930           0 :     if (state.dataWeatherManager->ReportPeriodInput(periodIdx).startYear > 0) {
    1931           0 :         currentDate = WeatherManager::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1932             :     } else {
    1933           0 :         currentDate = WeatherManager::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1934             :     }
    1935           0 :     return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
    1936             : }
    1937             : 
    1938        5376 : void findReportPeriodIdx(EnergyPlusData &state,
    1939             :                          const Array1D<WeatherManager::ReportPeriodData> &ReportPeriodInputData,
    1940             :                          const int nReportPeriods,
    1941             :                          Array1D_bool &inReportPeriodFlags)
    1942             : {
    1943             :     // return an array of flags, indicating whether the current time is in reporting period i
    1944             :     int currentDate;
    1945       12288 :     for (int i = 1; i <= nReportPeriods; i++) {
    1946        6912 :         int reportStartDate = ReportPeriodInputData(i).startJulianDate;
    1947        6912 :         int reportStartHour = ReportPeriodInputData(i).startHour;
    1948        6912 :         int reportEndDate = ReportPeriodInputData(i).endJulianDate;
    1949        6912 :         int reportEndHour = ReportPeriodInputData(i).endHour;
    1950        6912 :         if (ReportPeriodInputData(i).startYear > 0) {
    1951           0 :             currentDate = WeatherManager::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1952             :         } else {
    1953        6912 :             currentDate = WeatherManager::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    1954             :         }
    1955        6912 :         if (General::BetweenDateHoursLeftInclusive(
    1956        6912 :                 currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
    1957           0 :             inReportPeriodFlags(i) = true;
    1958             :         }
    1959             :     }
    1960        5376 : }
    1961             : 
    1962        2313 : } // namespace EnergyPlus::General

Generated by: LCOV version 1.13