LCOV - code coverage report
Current view: top level - EnergyPlus - WeatherManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 67.6 % 4624 3128
Test Date: 2025-06-02 07:23:51 Functions: 90.4 % 83 75

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <array>
      50              : #include <cmath>
      51              : #include <cstdio>
      52              : #include <map>
      53              : 
      54              : // ObjexxFCL Headers
      55              : #include <ObjexxFCL/Array.functions.hh>
      56              : #include <ObjexxFCL/ArrayS.functions.hh>
      57              : #include <ObjexxFCL/string.functions.hh>
      58              : #include <ObjexxFCL/time.hh>
      59              : 
      60              : // EnergyPlus Headers
      61              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      62              : #include <EnergyPlus/DataEnvironment.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      66              : #include <EnergyPlus/DataReportingFlags.hh>
      67              : #include <EnergyPlus/DataSurfaces.hh>
      68              : #include <EnergyPlus/DataSystemVariables.hh>
      69              : #include <EnergyPlus/DataWater.hh>
      70              : #include <EnergyPlus/DisplayRoutines.hh>
      71              : #include <EnergyPlus/EMSManager.hh>
      72              : #include <EnergyPlus/FileSystem.hh>
      73              : #include <EnergyPlus/General.hh>
      74              : #include <EnergyPlus/GlobalNames.hh>
      75              : #include <EnergyPlus/GroundTemperatureModeling/BaseGroundTemperatureModel.hh>
      76              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      77              : #include <EnergyPlus/OutputProcessor.hh>
      78              : #include <EnergyPlus/OutputReportPredefined.hh>
      79              : #include <EnergyPlus/OutputReportTabular.hh>
      80              : #include <EnergyPlus/Psychrometrics.hh>
      81              : #include <EnergyPlus/ScheduleManager.hh>
      82              : #include <EnergyPlus/StringUtilities.hh>
      83              : #include <EnergyPlus/SurfaceGeometry.hh>
      84              : #include <EnergyPlus/ThermalComfort.hh>
      85              : #include <EnergyPlus/UtilityRoutines.hh>
      86              : #include <EnergyPlus/Vectors.hh>
      87              : #include <EnergyPlus/WaterManager.hh>
      88              : #include <EnergyPlus/WeatherManager.hh>
      89              : 
      90              : namespace EnergyPlus {
      91              : 
      92              : namespace Weather {
      93              : 
      94              :     // MODULE INFORMATION:
      95              :     //       AUTHOR         Rick Strand
      96              :     //       DATE WRITTEN   May 1997
      97              :     //       MODIFIED       December 1998, FW; December 1999, LKL.
      98              : 
      99              :     // PURPOSE OF THIS MODULE:
     100              :     // This module contains all of the weather handling routines for
     101              :     // EnergyPlus.  That includes getting user input, defining design day
     102              :     // weather, retrieving data from weather files, and supplying the
     103              :     // outdoor environment for each time step.
     104              : 
     105              :     constexpr std::array<std::string_view, (int)EpwHeaderType::Num> epwHeaders = {"LOCATION",
     106              :                                                                                   "DESIGN CONDITIONS",
     107              :                                                                                   "TYPICAL/EXTREME PERIODS",
     108              :                                                                                   "GROUND TEMPERATURES",
     109              :                                                                                   "HOLIDAYS/DAYLIGHT SAVING",
     110              :                                                                                   "COMMENTS 1",
     111              :                                                                                   "COMMENTS 2",
     112              :                                                                                   "DATA PERIODS"};
     113              : 
     114              :     static constexpr std::array<std::string_view, (int)WaterMainsTempCalcMethod::Num> waterMainsCalcMethodNames{
     115              :         "Schedule", "Correlation", "CorrelationFromWeatherFile", "FixedDefault"};
     116              : 
     117              :     static constexpr std::array<std::string_view, (int)WaterMainsTempCalcMethod::Num> waterMainsCalcMethodNamesUC{
     118              :         "SCHEDULE", "CORRELATION", "CORRELATIONFROMWEATHERFILE", "FIXEDDEFAULT"};
     119              : 
     120              :     static constexpr std::array<std::string_view, (int)SkyTempModel::Num> SkyTempModelNamesUC{
     121              :         "CLARKALLEN", "SCHEDULEVALUE", "DIFFERENCESCHEDULEDRYBULBVALUE", "DIFFERENCESCHEDULEDEWPOINTVALUE", "BRUNT", "IDSO", "BERDAHLMARTIN"};
     122              : 
     123              :     static constexpr std::array<std::string_view, (int)SkyTempModel::Num> SkyTempModelNames{"Clark and Allen",
     124              :                                                                                             "Schedule Value",
     125              :                                                                                             "DryBulb Difference Schedule Value",
     126              :                                                                                             "Dewpoint Difference Schedule Value",
     127              :                                                                                             "Brunt",
     128              :                                                                                             "Idso",
     129              :                                                                                             "Berdahl and Martin"};
     130              : 
     131      2925340 :     void ManageWeather(EnergyPlusData &state)
     132              :     {
     133              : 
     134              :         // SUBROUTINE INFORMATION:
     135              :         //       AUTHOR         Rick Strand
     136              :         //       DATE WRITTEN   May 1997
     137              :         //       MODIFIED       June 1997 (general clean-up)
     138              : 
     139              :         // PURPOSE OF THIS SUBROUTINE:
     140              :         // This subroutine is the main driver of the weather manager module.
     141              :         // It controls the assignment of weather related global variables as
     142              :         // well as the reads and writes for weather information.
     143              : 
     144      2925340 :         InitializeWeather(state, state.dataWeather->PrintEnvrnStamp);
     145              : 
     146              :         // Cannot call this during sizing, because EMS will not initialize properly until after simulation kickoff
     147      2925340 :         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     148      1989001 :             bool anyEMSRan = false;
     149      1989001 :             EMSManager::ManageEMS(state,
     150              :                                   EMSManager::EMSCallFrom::BeginZoneTimestepBeforeSetCurrentWeather,
     151              :                                   anyEMSRan,
     152      3978002 :                                   ObjexxFCL::Optional_int_const()); // calling point
     153              :         }
     154      2925340 :         SetCurrentWeather(state);
     155              : 
     156      2925340 :         ReportWeatherAndTimeInformation(state, state.dataWeather->PrintEnvrnStamp);
     157      2925340 :     }
     158              : 
     159         2859 :     void ResetEnvironmentCounter(EnergyPlusData &state)
     160              :     {
     161         2859 :         state.dataWeather->Envrn = 0;
     162         2859 :     }
     163              : 
     164          799 :     bool CheckIfAnyUnderwaterBoundaries(EnergyPlusData &state)
     165              :     {
     166          799 :         bool errorsFound = false;
     167          799 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     168              : 
     169          799 :         constexpr std::string_view routineName = "CheckIfAnyUnderwaterBoundaries";
     170              : 
     171          799 :         auto const &ipsc = state.dataIPShortCut;
     172          799 :         ipsc->cCurrentModuleObject = "SurfaceProperty:Underwater";
     173          799 :         int Num = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
     174          800 :         for (int i = 1; i <= Num; i++) {
     175            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     176            1 :                                                                      ipsc->cCurrentModuleObject,
     177              :                                                                      i,
     178            1 :                                                                      ipsc->cAlphaArgs,
     179              :                                                                      NumAlpha,
     180            1 :                                                                      ipsc->rNumericArgs,
     181              :                                                                      NumNumber,
     182              :                                                                      IOStat,
     183            1 :                                                                      ipsc->lNumericFieldBlanks,
     184            1 :                                                                      ipsc->lAlphaFieldBlanks,
     185            1 :                                                                      ipsc->cAlphaFieldNames,
     186            1 :                                                                      ipsc->cNumericFieldNames);
     187            1 :             state.dataWeather->underwaterBoundaries.emplace_back();
     188            1 :             auto &underwaterBoundary = state.dataWeather->underwaterBoundaries[i - 1];
     189            1 :             underwaterBoundary.Name = ipsc->cAlphaArgs(1);
     190              : 
     191            1 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, underwaterBoundary.Name};
     192              : 
     193            1 :             underwaterBoundary.distanceFromLeadingEdge = ipsc->rNumericArgs(1);
     194            1 :             underwaterBoundary.OSCMIndex = Util::FindItemInList(underwaterBoundary.Name, state.dataSurface->OSCM);
     195            1 :             if (underwaterBoundary.OSCMIndex <= 0) {
     196            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
     197            0 :                 errorsFound = true;
     198              :             }
     199              : 
     200            1 :             if (ipsc->lAlphaFieldBlanks(2)) {
     201            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
     202            0 :                 errorsFound = true;
     203            1 :             } else if ((underwaterBoundary.waterTempSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(2))) == nullptr) {
     204            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     205            0 :                 errorsFound = true;
     206              :             }
     207              : 
     208            1 :             if (ipsc->lAlphaFieldBlanks(3)) {
     209              :                 // that's OK, we can have a blank schedule, the water will just have no free stream velocity
     210            1 :             } else if ((underwaterBoundary.velocitySched = Sched::GetSchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
     211            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     212            0 :                 errorsFound = true;
     213              :             }
     214            1 :             if (errorsFound) {
     215            0 :                 break;
     216              :             }
     217              :         }
     218          799 :         if (errorsFound) {
     219            0 :             ShowFatalError(state, "Previous input problems cause program termination");
     220              :         }
     221          799 :         return (Num > 0);
     222              :     }
     223              : 
     224              :     Real64
     225         1343 :     calculateWaterBoundaryConvectionCoefficient(Real64 const curWaterTemp, Real64 const freeStreamVelocity, Real64 const distanceFromLeadingEdge)
     226              :     {
     227         1343 :         Real64 constexpr waterKinematicViscosity = 1e-6; // m2/s
     228         1343 :         Real64 constexpr waterPrandtlNumber = 6;         // -
     229         1343 :         Real64 constexpr waterThermalConductivity = 0.6; // W/mK
     230              :         // do some calculation for forced convection from the leading edge of the ship
     231         1343 :         Real64 const localReynoldsNumber = freeStreamVelocity * distanceFromLeadingEdge / waterKinematicViscosity;
     232         1343 :         Real64 const localNusseltNumber = 0.0296 * pow(localReynoldsNumber, 0.8) * pow(waterPrandtlNumber, 1.0 / 3.0);
     233         1343 :         Real64 const localConvectionCoeff = localNusseltNumber * waterThermalConductivity / distanceFromLeadingEdge;
     234              : 
     235              :         // do some calculations for natural convection from the bottom of the ship
     236         1343 :         Real64 constexpr distanceFromBottomOfHull = 12; // meters, assumed for now
     237              :                                                         // this Prandtl correction is from Incropera & Dewitt, Intro to HT, eq 9.20
     238         1343 :         Real64 const prandtlCorrection =
     239              :             (0.75 * pow(waterPrandtlNumber, 0.5)) / pow(0.609 + 1.221 * pow(waterPrandtlNumber, 0.5) + 1.238 * waterPrandtlNumber, 0.25);
     240              :         // calculate the Grashof number
     241         1343 :         Real64 constexpr gravity = 9.81;          // m/s2
     242         1343 :         Real64 constexpr beta = 0.000214;         // water thermal expansion coefficient, from engineeringtoolbox.com, 1/C
     243         1343 :         Real64 constexpr assumedSurfaceTemp = 25; // Grashof requires a surface temp, this should suffice
     244              :         Real64 const localGrashofNumber =
     245         1343 :             (gravity * beta * std::abs(assumedSurfaceTemp - curWaterTemp) * pow(distanceFromBottomOfHull, 3)) / pow(waterKinematicViscosity, 2);
     246         1343 :         Real64 const localNusseltFreeConvection = pow(localGrashofNumber / 4, 0.25) * prandtlCorrection;
     247         1343 :         Real64 const localConvectionCoeffFreeConv = localNusseltFreeConvection * waterThermalConductivity / distanceFromBottomOfHull;
     248         1343 :         return max(localConvectionCoeff, localConvectionCoeffFreeConv);
     249              :     }
     250              : 
     251         1343 :     void UpdateUnderwaterBoundaries(EnergyPlusData &state)
     252              :     {
     253         2686 :         for (auto &thisBoundary : state.dataWeather->underwaterBoundaries) {
     254         1343 :             Real64 const curWaterTemp = thisBoundary.waterTempSched->getCurrentVal(); // C
     255         1343 :             Real64 freeStreamVelocity = 0;
     256         1343 :             if (thisBoundary.velocitySched != nullptr) {
     257         1343 :                 freeStreamVelocity = thisBoundary.velocitySched->getCurrentVal(); // m/s
     258              :             }
     259         1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TConv = curWaterTemp;
     260         1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HConv =
     261         1343 :                 Weather::calculateWaterBoundaryConvectionCoefficient(curWaterTemp, freeStreamVelocity, thisBoundary.distanceFromLeadingEdge);
     262         1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TRad = curWaterTemp;
     263         1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HRad = 0.0;
     264         1343 :         }
     265         1343 :     }
     266              : 
     267          800 :     void ReadVariableLocationOrientation(EnergyPlusData &state)
     268              :     {
     269              :         static constexpr std::string_view routineName = "ReadVariableLocationOrientation";
     270              : 
     271          800 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     272          800 :         auto const &ipsc = state.dataIPShortCut;
     273              : 
     274          800 :         ipsc->cCurrentModuleObject = "Site:VariableLocation";
     275          800 :         if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject) == 0) {
     276          799 :             return;
     277              :         }
     278            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     279            1 :                                                                  ipsc->cCurrentModuleObject,
     280              :                                                                  1,
     281            1 :                                                                  ipsc->cAlphaArgs,
     282              :                                                                  NumAlpha,
     283            1 :                                                                  ipsc->rNumericArgs,
     284              :                                                                  NumNumber,
     285              :                                                                  IOStat,
     286            1 :                                                                  ipsc->lNumericFieldBlanks,
     287            1 :                                                                  ipsc->lAlphaFieldBlanks,
     288            1 :                                                                  ipsc->cAlphaFieldNames,
     289            1 :                                                                  ipsc->cNumericFieldNames);
     290              : 
     291            1 :         ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ""};
     292              : 
     293            1 :         if (ipsc->lAlphaFieldBlanks(1)) {
     294            1 :         } else if ((state.dataEnvrn->varyingLocationLatSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(1))) == nullptr) {
     295            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
     296              :         }
     297              : 
     298            1 :         if (ipsc->lAlphaFieldBlanks(2)) {
     299            1 :         } else if ((state.dataEnvrn->varyingLocationLongSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(2))) == nullptr) {
     300            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     301              :         }
     302              : 
     303            1 :         if (ipsc->lAlphaFieldBlanks(3)) {
     304            1 :         } else if ((state.dataEnvrn->varyingOrientationSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
     305            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     306              :         }
     307              :     }
     308              : 
     309         1344 :     void UpdateLocationAndOrientation(EnergyPlusData &state)
     310              :     {
     311         1344 :         if (state.dataEnvrn->varyingLocationLatSched != nullptr) {
     312         1344 :             state.dataEnvrn->Latitude = state.dataEnvrn->varyingLocationLatSched->getCurrentVal();
     313              :         }
     314         1344 :         if (state.dataEnvrn->varyingLocationLongSched != nullptr) {
     315         1344 :             state.dataEnvrn->Longitude = state.dataEnvrn->varyingLocationLongSched->getCurrentVal();
     316              :         }
     317              : 
     318         1344 :         CheckLocationValidity(state);
     319         1344 :         if (state.dataEnvrn->varyingOrientationSched != nullptr) {
     320         1344 :             state.dataHeatBal->BuildingAzimuth = mod(state.dataEnvrn->varyingOrientationSched->getCurrentVal(), 360.0);
     321         2688 :             state.dataSurfaceGeometry->CosBldgRelNorth =
     322         1344 :                 std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
     323         2688 :             state.dataSurfaceGeometry->SinBldgRelNorth =
     324         1344 :                 std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
     325         8064 :             for (size_t SurfNum = 1; SurfNum < state.dataSurface->Surface.size(); ++SurfNum) {
     326         6720 :                 auto &surf = state.dataSurface->Surface(SurfNum);
     327        33600 :                 for (int n = 1; n <= surf.Sides; ++n) {
     328        26880 :                     Real64 Xb = surf.Vertex(n).x;
     329        26880 :                     Real64 Yb = surf.Vertex(n).y;
     330        26880 :                     surf.NewVertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
     331        26880 :                     surf.NewVertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
     332        26880 :                     surf.NewVertex(n).z = surf.Vertex(n).z;
     333              :                 }
     334         6720 :                 Vectors::CreateNewellSurfaceNormalVector(surf.NewVertex, surf.Sides, surf.NewellSurfaceNormalVector);
     335         6720 :                 Real64 SurfWorldAz = 0.0;
     336         6720 :                 Real64 SurfTilt = 0.0;
     337         6720 :                 Vectors::DetermineAzimuthAndTilt(
     338         6720 :                     surf.NewVertex, SurfWorldAz, SurfTilt, surf.lcsx, surf.lcsy, surf.lcsz, surf.NewellSurfaceNormalVector);
     339         6720 :                 surf.Azimuth = SurfWorldAz;
     340         6720 :                 surf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
     341         6720 :                 surf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
     342         6720 :                 surf.OutNormVec = surf.NewellSurfaceNormalVector;
     343              :             }
     344              :         }
     345         1344 :     }
     346              : 
     347        11353 :     bool GetNextEnvironment(EnergyPlusData &state, bool &Available, bool &ErrorsFound)
     348              :     {
     349              : 
     350              :         // SUBROUTINE INFORMATION:
     351              :         //       AUTHOR         Linda Lawrie
     352              :         //       DATE WRITTEN   August 2000
     353              : 
     354              :         // PURPOSE OF THIS SUBROUTINE:
     355              :         // This subroutine is called from the outer simulation manager and determines
     356              :         // if another environment is available in the "run list" or if the end has been
     357              :         // reached.
     358              : 
     359              :         static constexpr std::string_view RoutineName("GetNextEnvironment: ");
     360              :         static constexpr std::string_view EnvNameFormat("Environment,{},{},{},{},{},{},{},{},{},{},{},{},{}\n");
     361              :         static constexpr std::string_view EnvDSTNFormat("Environment:Daylight Saving,No,{}\n");
     362              :         static constexpr std::string_view EnvDSTYFormat("Environment:Daylight Saving,Yes,{},{},{}\n");
     363              :         static constexpr std::string_view DateFormat("{:02}/{:02}");
     364              :         static constexpr std::string_view DateFormatWithYear("{:02}/{:02}/{:04}");
     365              : 
     366        11353 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->GetEnvironmentFirstCall) {
     367              : 
     368          801 :             state.dataReportFlag->PrintEndDataDictionary = true;
     369              : 
     370          801 :             ReportOutputFileHeaders(state); // Write the output file header information
     371              : 
     372              :             // Setup Output Variables, CurrentModuleObject='All Simulations'
     373              : 
     374         3204 :             SetupOutputVariable(state,
     375              :                                 "Site Outdoor Air Drybulb Temperature",
     376              :                                 Constant::Units::C,
     377          801 :                                 state.dataEnvrn->OutDryBulbTemp,
     378              :                                 OutputProcessor::TimeStepType::Zone,
     379              :                                 OutputProcessor::StoreType::Average,
     380              :                                 "Environment");
     381         3204 :             SetupOutputVariable(state,
     382              :                                 "Site Outdoor Air Dewpoint Temperature",
     383              :                                 Constant::Units::C,
     384          801 :                                 state.dataEnvrn->OutDewPointTemp,
     385              :                                 OutputProcessor::TimeStepType::Zone,
     386              :                                 OutputProcessor::StoreType::Average,
     387              :                                 "Environment");
     388         3204 :             SetupOutputVariable(state,
     389              :                                 "Site Outdoor Air Wetbulb Temperature",
     390              :                                 Constant::Units::C,
     391          801 :                                 state.dataEnvrn->OutWetBulbTemp,
     392              :                                 OutputProcessor::TimeStepType::Zone,
     393              :                                 OutputProcessor::StoreType::Average,
     394              :                                 "Environment");
     395         3204 :             SetupOutputVariable(state,
     396              :                                 "Site Outdoor Air Humidity Ratio",
     397              :                                 Constant::Units::kgWater_kgDryAir,
     398          801 :                                 state.dataEnvrn->OutHumRat,
     399              :                                 OutputProcessor::TimeStepType::Zone,
     400              :                                 OutputProcessor::StoreType::Average,
     401              :                                 "Environment");
     402         3204 :             SetupOutputVariable(state,
     403              :                                 "Site Outdoor Air Relative Humidity",
     404              :                                 Constant::Units::Perc,
     405          801 :                                 state.dataEnvrn->OutRelHum,
     406              :                                 OutputProcessor::TimeStepType::Zone,
     407              :                                 OutputProcessor::StoreType::Average,
     408              :                                 "Environment");
     409         3204 :             SetupOutputVariable(state,
     410              :                                 "Site Outdoor Air Barometric Pressure",
     411              :                                 Constant::Units::Pa,
     412          801 :                                 state.dataEnvrn->OutBaroPress,
     413              :                                 OutputProcessor::TimeStepType::Zone,
     414              :                                 OutputProcessor::StoreType::Average,
     415              :                                 "Environment");
     416         3204 :             SetupOutputVariable(state,
     417              :                                 "Site Wind Speed",
     418              :                                 Constant::Units::m_s,
     419          801 :                                 state.dataEnvrn->WindSpeed,
     420              :                                 OutputProcessor::TimeStepType::Zone,
     421              :                                 OutputProcessor::StoreType::Average,
     422              :                                 "Environment");
     423         3204 :             SetupOutputVariable(state,
     424              :                                 "Site Wind Direction",
     425              :                                 Constant::Units::deg,
     426          801 :                                 state.dataEnvrn->WindDir,
     427              :                                 OutputProcessor::TimeStepType::Zone,
     428              :                                 OutputProcessor::StoreType::Average,
     429              :                                 "Environment");
     430         3204 :             SetupOutputVariable(state,
     431              :                                 "Site Sky Temperature",
     432              :                                 Constant::Units::C,
     433          801 :                                 state.dataEnvrn->SkyTemp,
     434              :                                 OutputProcessor::TimeStepType::Zone,
     435              :                                 OutputProcessor::StoreType::Average,
     436              :                                 "Environment");
     437         3204 :             SetupOutputVariable(state,
     438              :                                 "Site Horizontal Infrared Radiation Rate per Area",
     439              :                                 Constant::Units::W_m2,
     440          801 :                                 state.dataWeather->HorizIRSky,
     441              :                                 OutputProcessor::TimeStepType::Zone,
     442              :                                 OutputProcessor::StoreType::Average,
     443              :                                 "Environment");
     444         3204 :             SetupOutputVariable(state,
     445              :                                 "Site Diffuse Solar Radiation Rate per Area",
     446              :                                 Constant::Units::W_m2,
     447          801 :                                 state.dataEnvrn->DifSolarRad,
     448              :                                 OutputProcessor::TimeStepType::Zone,
     449              :                                 OutputProcessor::StoreType::Average,
     450              :                                 "Environment");
     451         3204 :             SetupOutputVariable(state,
     452              :                                 "Site Direct Solar Radiation Rate per Area",
     453              :                                 Constant::Units::W_m2,
     454          801 :                                 state.dataEnvrn->BeamSolarRad,
     455              :                                 OutputProcessor::TimeStepType::Zone,
     456              :                                 OutputProcessor::StoreType::Average,
     457              :                                 "Environment");
     458         3204 :             SetupOutputVariable(state,
     459              :                                 "Liquid Precipitation Depth",
     460              :                                 Constant::Units::m,
     461          801 :                                 state.dataEnvrn->LiquidPrecipitation,
     462              :                                 OutputProcessor::TimeStepType::Zone,
     463              :                                 OutputProcessor::StoreType::Sum,
     464              :                                 "Environment");
     465         3204 :             SetupOutputVariable(state,
     466              :                                 "Site Precipitation Rate",
     467              :                                 Constant::Units::m_s,
     468          801 :                                 state.dataWaterData->RainFall.CurrentRate,
     469              :                                 OutputProcessor::TimeStepType::Zone,
     470              :                                 OutputProcessor::StoreType::Average,
     471              :                                 "Environment");
     472         3204 :             SetupOutputVariable(state,
     473              :                                 "Site Precipitation Depth",
     474              :                                 Constant::Units::m,
     475          801 :                                 state.dataWaterData->RainFall.CurrentAmount,
     476              :                                 OutputProcessor::TimeStepType::Zone,
     477              :                                 OutputProcessor::StoreType::Sum,
     478              :                                 "Environment");
     479         3204 :             SetupOutputVariable(state,
     480              :                                 "Site Ground Reflected Solar Radiation Rate per Area",
     481              :                                 Constant::Units::W_m2,
     482          801 :                                 state.dataEnvrn->GndSolarRad,
     483              :                                 OutputProcessor::TimeStepType::Zone,
     484              :                                 OutputProcessor::StoreType::Average,
     485              :                                 "Environment");
     486         3204 :             SetupOutputVariable(state,
     487              :                                 "Site Ground Temperature",
     488              :                                 Constant::Units::C,
     489          801 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface],
     490              :                                 OutputProcessor::TimeStepType::Zone,
     491              :                                 OutputProcessor::StoreType::Average,
     492              :                                 "Environment");
     493         3204 :             SetupOutputVariable(state,
     494              :                                 "Site Surface Ground Temperature",
     495              :                                 Constant::Units::C,
     496          801 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow],
     497              :                                 OutputProcessor::TimeStepType::Zone,
     498              :                                 OutputProcessor::StoreType::Average,
     499              :                                 "Environment");
     500         3204 :             SetupOutputVariable(state,
     501              :                                 "Site Deep Ground Temperature",
     502              :                                 Constant::Units::C,
     503          801 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep],
     504              :                                 OutputProcessor::TimeStepType::Zone,
     505              :                                 OutputProcessor::StoreType::Average,
     506              :                                 "Environment");
     507         3204 :             SetupOutputVariable(state,
     508              :                                 "Site Simple Factor Model Ground Temperature",
     509              :                                 Constant::Units::C,
     510          801 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod],
     511              :                                 OutputProcessor::TimeStepType::Zone,
     512              :                                 OutputProcessor::StoreType::Average,
     513              :                                 "Environment");
     514         3204 :             SetupOutputVariable(state,
     515              :                                 "Site Total Sky Cover",
     516              :                                 Constant::Units::None,
     517          801 :                                 state.dataEnvrn->TotalCloudCover,
     518              :                                 OutputProcessor::TimeStepType::Zone,
     519              :                                 OutputProcessor::StoreType::Average,
     520              :                                 "Environment");
     521         3204 :             SetupOutputVariable(state,
     522              :                                 "Site Opaque Sky Cover",
     523              :                                 Constant::Units::None,
     524          801 :                                 state.dataEnvrn->OpaqueCloudCover,
     525              :                                 OutputProcessor::TimeStepType::Zone,
     526              :                                 OutputProcessor::StoreType::Average,
     527              :                                 "Environment");
     528         3204 :             SetupOutputVariable(state,
     529              :                                 "Site Outdoor Air Enthalpy",
     530              :                                 Constant::Units::J_kg,
     531          801 :                                 state.dataEnvrn->OutEnthalpy,
     532              :                                 OutputProcessor::TimeStepType::Zone,
     533              :                                 OutputProcessor::StoreType::Average,
     534              :                                 "Environment");
     535         3204 :             SetupOutputVariable(state,
     536              :                                 "Site Outdoor Air Density",
     537              :                                 Constant::Units::kg_m3,
     538          801 :                                 state.dataEnvrn->OutAirDensity,
     539              :                                 OutputProcessor::TimeStepType::Zone,
     540              :                                 OutputProcessor::StoreType::Average,
     541              :                                 "Environment");
     542         3204 :             SetupOutputVariable(state,
     543              :                                 "Site Solar Azimuth Angle",
     544              :                                 Constant::Units::deg,
     545          801 :                                 state.dataWeather->SolarAzimuthAngle,
     546              :                                 OutputProcessor::TimeStepType::Zone,
     547              :                                 OutputProcessor::StoreType::Average,
     548              :                                 "Environment");
     549         3204 :             SetupOutputVariable(state,
     550              :                                 "Site Solar Altitude Angle",
     551              :                                 Constant::Units::deg,
     552          801 :                                 state.dataWeather->SolarAltitudeAngle,
     553              :                                 OutputProcessor::TimeStepType::Zone,
     554              :                                 OutputProcessor::StoreType::Average,
     555              :                                 "Environment");
     556         3204 :             SetupOutputVariable(state,
     557              :                                 "Site Solar Hour Angle",
     558              :                                 Constant::Units::deg,
     559          801 :                                 state.dataWeather->HrAngle,
     560              :                                 OutputProcessor::TimeStepType::Zone,
     561              :                                 OutputProcessor::StoreType::Average,
     562              :                                 "Environment");
     563         2403 :             SetupOutputVariable(state,
     564              :                                 "Site Rain Status",
     565              :                                 Constant::Units::None,
     566          801 :                                 state.dataWeather->RptIsRain,
     567              :                                 OutputProcessor::TimeStepType::Zone,
     568              :                                 OutputProcessor::StoreType::Average,
     569              :                                 "Environment");
     570         1602 :             SetupOutputVariable(state,
     571              :                                 "Site Snow on Ground Status",
     572              :                                 Constant::Units::None,
     573          801 :                                 state.dataWeather->RptIsSnow,
     574              :                                 OutputProcessor::TimeStepType::Zone,
     575              :                                 OutputProcessor::StoreType::Average,
     576              :                                 "Environment");
     577         3204 :             SetupOutputVariable(state,
     578              :                                 "Site Exterior Horizontal Sky Illuminance",
     579              :                                 Constant::Units::lux,
     580          801 :                                 state.dataEnvrn->HISKF,
     581              :                                 OutputProcessor::TimeStepType::Zone,
     582              :                                 OutputProcessor::StoreType::Average,
     583              :                                 "Environment");
     584         3204 :             SetupOutputVariable(state,
     585              :                                 "Site Exterior Horizontal Beam Illuminance",
     586              :                                 Constant::Units::lux,
     587          801 :                                 state.dataEnvrn->HISUNF,
     588              :                                 OutputProcessor::TimeStepType::Zone,
     589              :                                 OutputProcessor::StoreType::Average,
     590              :                                 "Environment");
     591         3204 :             SetupOutputVariable(state,
     592              :                                 "Site Exterior Beam Normal Illuminance",
     593              :                                 Constant::Units::lux,
     594          801 :                                 state.dataEnvrn->HISUNFnorm,
     595              :                                 OutputProcessor::TimeStepType::Zone,
     596              :                                 OutputProcessor::StoreType::Average,
     597              :                                 "Environment");
     598         3204 :             SetupOutputVariable(state,
     599              :                                 "Site Sky Diffuse Solar Radiation Luminous Efficacy",
     600              :                                 Constant::Units::lum_W,
     601          801 :                                 state.dataEnvrn->PDIFLW,
     602              :                                 OutputProcessor::TimeStepType::Zone,
     603              :                                 OutputProcessor::StoreType::Average,
     604              :                                 "Environment");
     605         3204 :             SetupOutputVariable(state,
     606              :                                 "Site Beam Solar Radiation Luminous Efficacy",
     607              :                                 Constant::Units::lum_W,
     608          801 :                                 state.dataEnvrn->PDIRLW,
     609              :                                 OutputProcessor::TimeStepType::Zone,
     610              :                                 OutputProcessor::StoreType::Average,
     611              :                                 "Environment");
     612         3204 :             SetupOutputVariable(state,
     613              :                                 "Site Daylighting Model Sky Clearness",
     614              :                                 Constant::Units::None,
     615          801 :                                 state.dataEnvrn->SkyClearness,
     616              :                                 OutputProcessor::TimeStepType::Zone,
     617              :                                 OutputProcessor::StoreType::Average,
     618              :                                 "Environment");
     619         3204 :             SetupOutputVariable(state,
     620              :                                 "Site Daylighting Model Sky Brightness",
     621              :                                 Constant::Units::None,
     622          801 :                                 state.dataEnvrn->SkyBrightness,
     623              :                                 OutputProcessor::TimeStepType::Zone,
     624              :                                 OutputProcessor::StoreType::Average,
     625              :                                 "Environment");
     626         2403 :             SetupOutputVariable(state,
     627              :                                 "Site Daylight Saving Time Status",
     628              :                                 Constant::Units::None,
     629          801 :                                 state.dataEnvrn->DSTIndicator,
     630              :                                 OutputProcessor::TimeStepType::Zone,
     631              :                                 OutputProcessor::StoreType::Average,
     632              :                                 "Environment");
     633         1602 :             SetupOutputVariable(state,
     634              :                                 "Site Day Type Index",
     635              :                                 Constant::Units::None,
     636          801 :                                 state.dataWeather->RptDayType,
     637              :                                 OutputProcessor::TimeStepType::Zone,
     638              :                                 OutputProcessor::StoreType::Average,
     639              :                                 "Environment");
     640         3204 :             SetupOutputVariable(state,
     641              :                                 "Site Mains Water Temperature",
     642              :                                 Constant::Units::C,
     643          801 :                                 state.dataEnvrn->WaterMainsTemp,
     644              :                                 OutputProcessor::TimeStepType::Zone,
     645              :                                 OutputProcessor::StoreType::Average,
     646              :                                 "Environment");
     647              : 
     648          801 :             if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
     649           76 :                 SetupEMSActuator(state,
     650              :                                  "Weather Data",
     651              :                                  "Environment",
     652              :                                  "Outdoor Dry Bulb",
     653              :                                  "[C]",
     654           76 :                                  state.dataEnvrn->EMSOutDryBulbOverrideOn,
     655           76 :                                  state.dataEnvrn->EMSOutDryBulbOverrideValue);
     656           76 :                 SetupEMSActuator(state,
     657              :                                  "Weather Data",
     658              :                                  "Environment",
     659              :                                  "Outdoor Dew Point",
     660              :                                  "[C]",
     661           76 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideOn,
     662           76 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideValue);
     663           76 :                 SetupEMSActuator(state,
     664              :                                  "Weather Data",
     665              :                                  "Environment",
     666              :                                  "Outdoor Relative Humidity",
     667              :                                  "[%]",
     668           76 :                                  state.dataEnvrn->EMSOutRelHumOverrideOn,
     669           76 :                                  state.dataEnvrn->EMSOutRelHumOverrideValue);
     670           76 :                 SetupEMSActuator(state,
     671              :                                  "Weather Data",
     672              :                                  "Environment",
     673              :                                  "Diffuse Solar",
     674              :                                  "[W/m2]",
     675           76 :                                  state.dataEnvrn->EMSDifSolarRadOverrideOn,
     676           76 :                                  state.dataEnvrn->EMSDifSolarRadOverrideValue);
     677           76 :                 SetupEMSActuator(state,
     678              :                                  "Weather Data",
     679              :                                  "Environment",
     680              :                                  "Direct Solar",
     681              :                                  "[W/m2]",
     682           76 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideOn,
     683           76 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideValue);
     684           76 :                 SetupEMSActuator(state,
     685              :                                  "Weather Data",
     686              :                                  "Environment",
     687              :                                  "Wind Speed",
     688              :                                  "[m/s]",
     689           76 :                                  state.dataEnvrn->EMSWindSpeedOverrideOn,
     690           76 :                                  state.dataEnvrn->EMSWindSpeedOverrideValue);
     691           76 :                 SetupEMSActuator(state,
     692              :                                  "Weather Data",
     693              :                                  "Environment",
     694              :                                  "Wind Direction",
     695              :                                  "[deg]",
     696           76 :                                  state.dataEnvrn->EMSWindDirOverrideOn,
     697           76 :                                  state.dataEnvrn->EMSWindDirOverrideValue);
     698              :             }
     699          801 :             state.dataWeather->GetEnvironmentFirstCall = false;
     700              : 
     701              :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
     702              : 
     703        11353 :         if (state.dataWeather->GetBranchInputOneTimeFlag) {
     704              : 
     705          801 :             SetupInterpolationValues(state);
     706          801 :             state.dataWeather->TimeStepFraction = 1.0 / double(state.dataGlobal->TimeStepsInHour);
     707          801 :             state.dataEnvrn->rhoAirSTP = Psychrometrics::PsyRhoAirFnPbTdbW(
     708              :                 state, DataEnvironment::StdPressureSeaLevel, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
     709          801 :             OpenWeatherFile(state, ErrorsFound); // moved here because of possibility of special days on EPW file
     710          801 :             CloseWeatherFile(state);
     711          801 :             ReadUserWeatherInput(state);
     712          801 :             AllocateWeatherData(state);
     713          801 :             if (state.dataWeather->NumIntervalsPerHour != 1) {
     714            0 :                 if (state.dataWeather->NumIntervalsPerHour != state.dataGlobal->TimeStepsInHour) {
     715            0 :                     ShowSevereError(
     716              :                         state,
     717            0 :                         format("{}Number of intervals per hour on Weather file does not match specified number of Time Steps Per Hour", RoutineName));
     718            0 :                     ErrorsFound = true;
     719              :                 }
     720              :             }
     721          801 :             state.dataWeather->GetBranchInputOneTimeFlag = false;
     722          801 :             state.dataWeather->Envrn = 0;
     723          801 :             if (state.dataWeather->NumOfEnvrn > 0) {
     724          801 :                 ResolveLocationInformation(state, ErrorsFound); // Obtain weather related info from input file
     725          801 :                 CheckLocationValidity(state);
     726         1577 :                 if ((state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
     727          776 :                     (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
     728          776 :                     CheckWeatherFileValidity(state);
     729              :                 }
     730          801 :                 if (ErrorsFound) {
     731            0 :                     ShowSevereError(state, format("{}No location specified, program will terminate.", RoutineName));
     732              :                 }
     733              :             } else {
     734            0 :                 ErrorsFound = true;
     735            0 :                 ShowSevereError(state, format("{}No Design Days or Run Period(s) specified, program will terminate.", RoutineName));
     736              :             }
     737          801 :             if (state.dataSysVars->DDOnly && state.dataEnvrn->TotDesDays == 0) {
     738            0 :                 ErrorsFound = true;
     739            0 :                 ShowSevereError(
     740              :                     state,
     741            0 :                     format("{}Requested Design Days only (DataSystemVariables::DDOnly) but no Design Days specified, program will terminate.",
     742              :                            RoutineName));
     743              :             }
     744          801 :             if (state.dataSysVars->ReverseDD && state.dataEnvrn->TotDesDays == 1) {
     745            0 :                 ErrorsFound = true;
     746            0 :                 ShowSevereError(
     747              :                     state,
     748            0 :                     format(
     749              :                         "{}Requested Reverse Design Days (DataSystemVariables::ReverseDD) but only 1 Design Day specified, program will terminate.",
     750              :                         RoutineName));
     751              :             }
     752              : 
     753              :             // Throw a Fatal now that we have said it'll terminalte
     754          801 :             if (ErrorsFound) {
     755            0 :                 CloseWeatherFile(state); // will only close if opened.
     756            0 :                 ShowFatalError(state, format("{}Errors found in Weather Data Input. Program terminates.", RoutineName));
     757              :             }
     758              : 
     759          801 :             state.dataEnvrn->CurrentOverallSimDay = 0;
     760          801 :             state.dataEnvrn->TotalOverallSimDays = 0;
     761          801 :             state.dataEnvrn->MaxNumberSimYears = 1;
     762         3674 :             for (int i = 1; i <= state.dataWeather->NumOfEnvrn; ++i) {
     763         2873 :                 state.dataEnvrn->TotalOverallSimDays += state.dataWeather->Environment(i).TotalDays;
     764         2873 :                 if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     765         1191 :                     state.dataEnvrn->MaxNumberSimYears = max(state.dataEnvrn->MaxNumberSimYears, state.dataWeather->Environment(i).NumSimYears);
     766              :                 }
     767              :             }
     768          801 :             DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
     769              :         }
     770              : 
     771        11353 :         CloseWeatherFile(state); // will only close if opened.
     772        11353 :         ++state.dataWeather->Envrn;
     773        11353 :         state.dataWeather->DatesShouldBeReset = false;
     774        11353 :         if (state.dataWeather->Envrn > state.dataWeather->NumOfEnvrn) {
     775         1603 :             Available = false;
     776         1603 :             state.dataWeather->Envrn = 0;
     777         1603 :             state.dataEnvrn->CurEnvirNum = 0;
     778              :         } else {
     779         9750 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
     780         9750 :             state.dataGlobal->KindOfSim = envCurr.KindOfEnvrn;
     781         9750 :             state.dataEnvrn->DayOfYear = envCurr.StartJDay;
     782         9750 :             state.dataEnvrn->DayOfMonth = envCurr.StartDay;
     783         9750 :             state.dataGlobal->CalendarYear = envCurr.StartYear;
     784         9750 :             state.dataGlobal->CalendarYearChr = fmt::to_string(state.dataGlobal->CalendarYear);
     785         9750 :             state.dataEnvrn->Month = envCurr.StartMonth;
     786         9750 :             state.dataGlobal->NumOfDayInEnvrn = envCurr.TotalDays; // Set day loop maximum from DataGlobals
     787              : 
     788        12754 :             if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
     789         3004 :                 (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
     790           13 :                 if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) {
     791            8 :                     if (state.dataGlobal->DoDesDaySim) {
     792            8 :                         ShowWarningError(state, format("{}Adaptive Comfort being reported during design day.", RoutineName));
     793            8 :                         Real64 GrossApproxAvgDryBulb = (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb +
     794            8 :                                                         (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb -
     795            8 :                                                          state.dataWeather->DesDayInput(state.dataWeather->Envrn).DailyDBRange)) /
     796            8 :                                                        2.0;
     797            8 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55) {
     798            8 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, false, GrossApproxAvgDryBulb);
     799              :                         }
     800            8 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251) {
     801            2 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, false, GrossApproxAvgDryBulb);
     802              :                         }
     803              :                     }
     804              :                 } else {
     805            5 :                     if (state.dataGlobal->DoWeathSim || state.dataGlobal->DoDesDaySim) {
     806            5 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55) {
     807            5 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, true, 0.0);
     808              :                         }
     809            5 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251) {
     810            1 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, true, 0.0);
     811              :                         }
     812              :                     }
     813              :                 }
     814              :             }
     815              : 
     816         9750 :             if (state.dataWeather->Envrn > state.dataEnvrn->TotDesDays && state.dataWeather->WeatherFileExists) {
     817         3776 :                 OpenEPlusWeatherFile(state, ErrorsFound, false);
     818              :             }
     819         9750 :             Available = true;
     820        13398 :             if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     821         3648 :                 (!state.dataWeather->WeatherFileExists && state.dataGlobal->DoWeathSim)) {
     822            0 :                 if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     823            0 :                     ShowSevereError(state, "Weather Simulation requested, but no weather file attached.");
     824            0 :                     ErrorsFound = true;
     825              :                 }
     826            0 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) {
     827            0 :                     state.dataWeather->Envrn = 0;
     828              :                 }
     829            0 :                 Available = false;
     830        13398 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     831         3648 :                        (!state.dataWeather->WeatherFileExists && !state.dataGlobal->DoWeathSim)) {
     832           20 :                 Available = false;
     833           20 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) {
     834           20 :                     state.dataWeather->Envrn = 0;
     835              :                 }
     836         9730 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoingSizing) {
     837         1223 :                 Available = false;
     838         1223 :                 state.dataWeather->Envrn = 0;
     839              :             }
     840              : 
     841         9750 :             if (!ErrorsFound && Available && state.dataWeather->Envrn > 0) {
     842         8507 :                 state.dataEnvrn->EnvironmentName = envCurr.Title;
     843         8507 :                 state.dataEnvrn->CurEnvirNum = state.dataWeather->Envrn;
     844         8507 :                 state.dataEnvrn->RunPeriodStartDayOfWeek = 0;
     845        10962 :                 if ((state.dataGlobal->DoDesDaySim && (state.dataGlobal->KindOfSim != Constant::KindOfSim::RunPeriodWeather)) ||
     846         2455 :                     ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoWeathSim)) {
     847         6066 :                     if (state.dataWeather->PrntEnvHeaders && state.dataReportFlag->DoWeatherInitReporting) {
     848              :                         static constexpr std::string_view EnvironFormat(
     849              :                             "! <Environment>,Environment Name,Environment Type, Start Date, End Date, Start DayOfWeek, Duration {#days}, "
     850              :                             "Source:Start DayOfWeek,  Use Daylight Saving, Use Holidays, Apply Weekend Holiday Rule,  Use Rain Values, Use Snow "
     851              :                             "Values, Sky Temperature Model\n! <Environment:Special Days>, Special Day Name, Special Day Type, Source, Start Date, "
     852              :                             "Duration {#days}\n! "
     853              :                             "<Environment:Daylight Saving>, Daylight Saving Indicator, Source, Start Date, End Date\n! <Environment:WarmupDays>, "
     854              :                             "NumberofWarmupDays");
     855          800 :                         print(state.files.eio, "{}\n", EnvironFormat);
     856          800 :                         state.dataWeather->PrntEnvHeaders = false;
     857              :                     }
     858              : 
     859         6066 :                     std::string StDate;
     860         6066 :                     std::string EnDate;
     861        12118 :                     if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) ||
     862         6052 :                         (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign)) {
     863           36 :                         int DSTActStMon = 0;
     864           36 :                         int DSTActStDay = 0;
     865           36 :                         int DSTActEnMon = 0;
     866           36 :                         int DSTActEnDay = 0;
     867           36 :                         std::string kindOfRunPeriod = envCurr.cKindOfEnvrn;
     868           36 :                         state.dataEnvrn->RunPeriodEnvironment = state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather;
     869           36 :                         state.dataEnvrn->CurrentYearIsLeapYear = state.dataWeather->Environment(state.dataWeather->Envrn).IsLeapYear;
     870           36 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears) {
     871            2 :                             state.dataWeather->LeapYearAdd = 1;
     872              :                         } else {
     873           34 :                             state.dataWeather->LeapYearAdd = 0;
     874              :                         }
     875           36 :                         if (state.dataEnvrn->CurrentYearIsLeapYear) {
     876            2 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
     877              :                         }
     878           36 :                         state.dataWeather->UseDaylightSaving = envCurr.UseDST;
     879           36 :                         state.dataWeather->UseSpecialDays = envCurr.UseHolidays;
     880           36 :                         state.dataWeather->UseRainValues = envCurr.UseRain;
     881           36 :                         state.dataWeather->UseSnowValues = envCurr.UseSnow;
     882              : 
     883           36 :                         bool missingLeap(false); // Defer acting on anything found here until after the other range checks (see below)
     884              : 
     885           36 :                         if (envCurr.ActualWeather && !state.dataWeather->WFAllowsLeapYears) {
     886            0 :                             for (int year = envCurr.StartYear; year <= envCurr.EndYear; year++) {
     887            0 :                                 if (!isLeapYear(year)) {
     888            0 :                                     continue;
     889              :                                 }
     890              : 
     891            0 :                                 ShowSevereError(
     892              :                                     state,
     893            0 :                                     format("{}Weatherfile does not support leap years but runperiod includes a leap year ({})", RoutineName, year));
     894            0 :                                 missingLeap = true;
     895              :                             }
     896              :                         }
     897              : 
     898           36 :                         bool OkRun = false;
     899              : 
     900           36 :                         if (envCurr.ActualWeather) {
     901              :                             // Actual weather
     902            0 :                             for (auto const &dataperiod : state.dataWeather->DataPeriods) {
     903            0 :                                 int runStartJulian = dataperiod.DataStJDay;
     904            0 :                                 int runEndJulian = dataperiod.DataEnJDay;
     905            0 :                                 if (!dataperiod.HasYearData) {
     906            0 :                                     ShowSevereError(state,
     907            0 :                                                     format("{}Actual weather runperiod has been entered but weatherfile DATA PERIOD does not have "
     908              :                                                            "year included in start/end date.",
     909              :                                                            RoutineName));
     910            0 :                                     ShowContinueError(state, "...to match the RunPeriod, the DATA PERIOD should be mm/dd/yyyy for both, or");
     911            0 :                                     ShowContinueError(state, "(...set \"Treat Weather as Actual\" to \"No\".)");
     912              :                                 }
     913            0 :                                 if (!General::BetweenDates(envCurr.StartDate, runStartJulian, runEndJulian)) {
     914            0 :                                     continue;
     915              :                                 }
     916            0 :                                 if (!General::BetweenDates(envCurr.EndDate, runStartJulian, runEndJulian)) {
     917            0 :                                     continue;
     918              :                                 }
     919            0 :                                 OkRun = true;
     920            0 :                                 break;
     921            0 :                             }
     922              :                         } else {
     923              :                             // Typical (or just non-actual) weather
     924           36 :                             for (auto &dataperiod : state.dataWeather->DataPeriods) {
     925              :                                 // Since this is not actual weather, there may be issues with this calculation
     926              :                                 // Assume the weather data starts the same year as the simulation, so LeapYearAdd is what
     927              :                                 // should be used.
     928           36 :                                 int runStartOrdinal = General::OrdinalDay(dataperiod.StMon, dataperiod.StDay, state.dataWeather->LeapYearAdd);
     929              :                                 // This one is harder, leave as is for now. What about multiple years of data?
     930           36 :                                 int runEndOrdinal = General::OrdinalDay(dataperiod.EnMon, dataperiod.EnDay, state.dataWeather->LeapYearAdd);
     931           36 :                                 if (runStartOrdinal == 1 && (runEndOrdinal == 366 || runEndOrdinal == 365)) {
     932              :                                     // Complete year(s) of weather data, will wrap around
     933           36 :                                     OkRun = true;
     934           36 :                                     break;
     935              :                                 }
     936            0 :                                 if (!General::BetweenDates(envCurr.StartJDay, runStartOrdinal, runEndOrdinal)) {
     937            0 :                                     continue;
     938              :                                 }
     939            0 :                                 if (!General::BetweenDates(envCurr.EndJDay, runStartOrdinal, runEndOrdinal)) {
     940            0 :                                     continue;
     941              :                                 }
     942            0 :                                 OkRun = true;
     943           36 :                             }
     944              :                         }
     945              : 
     946           36 :                         if (!OkRun) {
     947            0 :                             if (!envCurr.ActualWeather) {
     948            0 :                                 StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     949            0 :                                 EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     950            0 :                                 ShowSevereError(state,
     951            0 :                                                 format("{}Runperiod [mm/dd] (Start={},End={}) requested not within Data Period(s) from Weather File",
     952              :                                                        RoutineName,
     953              :                                                        StDate,
     954              :                                                        EnDate));
     955              :                             } else {
     956            0 :                                 StDate = format(DateFormatWithYear, envCurr.StartMonth, envCurr.StartDay, envCurr.StartYear);
     957            0 :                                 EnDate = format(DateFormatWithYear, envCurr.EndMonth, envCurr.EndDay, envCurr.EndYear);
     958            0 :                                 ShowSevereError(
     959              :                                     state,
     960            0 :                                     format("{}Runperiod [mm/dd/yyyy] (Start={},End={}) requested not within Data Period(s) from Weather File",
     961              :                                            RoutineName,
     962              :                                            StDate,
     963              :                                            EnDate));
     964              :                             }
     965              : 
     966            0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
     967            0 :                             StDate = format(DateFormat, dataPeriod1.StMon, dataPeriod1.StDay);
     968            0 :                             EnDate = format(DateFormat, dataPeriod1.EnMon, dataPeriod1.EnDay);
     969            0 :                             if (dataPeriod1.StYear > 0) {
     970            0 :                                 StDate += format("/{}", dataPeriod1.StYear);
     971              :                             } else {
     972            0 :                                 StDate += "/<noyear>";
     973              :                             }
     974            0 :                             if (dataPeriod1.EnYear > 0) {
     975            0 :                                 EnDate += format("/{}", dataPeriod1.EnYear);
     976              :                             } else {
     977            0 :                                 EnDate += "/<noyear>";
     978              :                             }
     979            0 :                             if (state.dataWeather->NumDataPeriods == 1) {
     980            0 :                                 ShowContinueError(state, format("Weather Data Period (Start={},End={})", StDate, EnDate));
     981              :                             } else {
     982            0 :                                 ShowContinueError(state, format("Multiple Weather Data Periods 1st (Start={},End={})", StDate, EnDate));
     983              :                             }
     984            0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     985              :                         }
     986              : 
     987           36 :                         if (missingLeap) {
     988              :                             // Bail out now if we still need to
     989            0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     990              :                         }
     991              : 
     992              :                         // Following builds Environment start/end for ASHRAE 55 warnings
     993           36 :                         StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     994           36 :                         EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     995           36 :                         if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     996           14 :                             StDate += format("/{}", envCurr.StartYear);
     997           14 :                             EnDate += format("/{}", envCurr.EndYear);
     998              :                         }
     999           36 :                         state.dataEnvrn->EnvironmentStartEnd = StDate + " - " + EnDate;
    1000           36 :                         state.dataEnvrn->StartYear = envCurr.StartYear;
    1001           36 :                         state.dataEnvrn->EndYear = envCurr.EndYear;
    1002              : 
    1003           36 :                         int TWeekDay = (envCurr.DayOfWeek == 0) ? 1 : envCurr.DayOfWeek;
    1004           36 :                         auto const &MonWeekDay = envCurr.MonWeekDay;
    1005              : 
    1006           36 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
    1007           12 :                             std::string_view const AlpUseDST = (envCurr.UseDST) ? "Yes" : "No";
    1008           12 :                             std::string_view const AlpUseSpec = (envCurr.UseHolidays) ? "Yes" : "No";
    1009           12 :                             std::string_view const ApWkRule = (envCurr.ApplyWeekendRule) ? "Yes" : "No";
    1010           12 :                             std::string_view const AlpUseRain = (envCurr.UseRain) ? "Yes" : "No";
    1011           12 :                             std::string_view const AlpUseSnow = (envCurr.UseSnow) ? "Yes" : "No";
    1012              : 
    1013           12 :                             print(state.files.eio,
    1014              :                                   EnvNameFormat,
    1015           12 :                                   envCurr.Title,
    1016              :                                   kindOfRunPeriod,
    1017              :                                   StDate,
    1018              :                                   EnDate,
    1019           12 :                                   Sched::dayTypeNames[TWeekDay],
    1020           24 :                                   fmt::to_string(envCurr.TotalDays),
    1021              :                                   "Use RunPeriod Specified Day",
    1022              :                                   AlpUseDST,
    1023              :                                   AlpUseSpec,
    1024              :                                   ApWkRule,
    1025              :                                   AlpUseRain,
    1026              :                                   AlpUseSnow,
    1027           12 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
    1028              :                         }
    1029              : 
    1030           60 :                         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
    1031           67 :                             (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather && state.dataGlobal->DoWeathSim) &&
    1032            7 :                             (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
    1033            0 :                             if (state.dataWeather->WFAllowsLeapYears) {
    1034            0 :                                 ShowSevereError(
    1035              :                                     state,
    1036            0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with leap years in weather files.", RoutineName));
    1037            0 :                                 ErrorsFound = true;
    1038              :                             }
    1039            0 :                             if (state.dataWeather->NumDataPeriods != 1) {
    1040            0 :                                 ShowSevereError(
    1041              :                                     state,
    1042            0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with multiple dataperiods in weather files.",
    1043              :                                            RoutineName));
    1044            0 :                                 ErrorsFound = true;
    1045              :                             }
    1046            0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
    1047            0 :                             if (dataPeriod1.StMon == 1 && dataPeriod1.StDay == 1) {
    1048            0 :                                 int RunStJDay = General::OrdinalDay(dataPeriod1.StMon, dataPeriod1.StDay, state.dataWeather->LeapYearAdd);
    1049            0 :                                 int RunEnJDay = General::OrdinalDay(dataPeriod1.EnMon, dataPeriod1.EnDay, state.dataWeather->LeapYearAdd);
    1050            0 :                                 if (RunEnJDay - RunStJDay + 1 != 365) {
    1051            0 :                                     ShowSevereError(state,
    1052            0 :                                                     format("{}AdaptiveComfort Reporting does not work correctly with weather files that do "
    1053              :                                                            "not contain 365 days.",
    1054              :                                                            RoutineName));
    1055            0 :                                     ErrorsFound = true;
    1056              :                                 }
    1057            0 :                             } else {
    1058            0 :                                 ShowSevereError(state,
    1059            0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that do not "
    1060              :                                                        "start on 1 January.",
    1061              :                                                        RoutineName));
    1062            0 :                                 ErrorsFound = true;
    1063              :                             }
    1064            0 :                             if (state.dataWeather->NumIntervalsPerHour != 1) {
    1065            0 :                                 ShowSevereError(state,
    1066            0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that have "
    1067              :                                                        "multiple interval records per hour.",
    1068              :                                                        RoutineName));
    1069            0 :                                 ErrorsFound = true;
    1070              :                             }
    1071              :                         } // if
    1072              : 
    1073              :                         // Only need to set Week days for Run Days
    1074           36 :                         state.dataEnvrn->RunPeriodStartDayOfWeek = TWeekDay;
    1075           36 :                         state.dataWeather->WeekDayTypes = 0;
    1076           36 :                         int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1077           36 :                         int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1078              : 
    1079           36 :                         state.dataWeather->curSimDayForEndOfRunPeriod = envCurr.TotalDays;
    1080              : 
    1081           36 :                         int i = JDay5Start;
    1082              :                         while (true) {
    1083         5242 :                             state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1084         5242 :                             TWeekDay = mod(TWeekDay, 7) + 1;
    1085         5242 :                             ++i;
    1086         5242 :                             if (i > 366) {
    1087            0 :                                 i = 1;
    1088              :                             }
    1089         5242 :                             if (i == JDay5End) {
    1090           36 :                                 break;
    1091              :                             }
    1092              :                         }
    1093              : 
    1094           36 :                         state.dataWeather->DaylightSavingIsActive =
    1095           36 :                             (state.dataWeather->UseDaylightSaving && state.dataWeather->EPWDaylightSaving) || state.dataWeather->IDFDaylightSaving;
    1096              : 
    1097           36 :                         envCurr.SetWeekDays = false;
    1098              : 
    1099           36 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1100            4 :                             SetDSTDateRanges(state, MonWeekDay, state.dataWeather->DSTIndex, DSTActStMon, DSTActStDay, DSTActEnMon, DSTActEnDay);
    1101              :                         }
    1102              : 
    1103           36 :                         SetSpecialDayDates(state, MonWeekDay);
    1104              : 
    1105           36 :                         if (envCurr.StartMonth != 1 || envCurr.StartDay != 1) {
    1106           22 :                             state.dataWeather->StartDatesCycleShouldBeReset = true;
    1107           22 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1108              :                         }
    1109              : 
    1110           36 :                         if (envCurr.StartMonth == 1 && envCurr.StartDay == 1) {
    1111           14 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1112           14 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1113              :                         }
    1114              : 
    1115           36 :                         if (envCurr.ActualWeather) {
    1116            0 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1117            0 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1118              :                         }
    1119              : 
    1120              :                         // Report Actual Dates for Daylight Saving and Special Days
    1121           36 :                         if (!state.dataGlobal->KickOffSimulation) {
    1122           24 :                             std::string Source;
    1123           24 :                             if (state.dataWeather->UseDaylightSaving) {
    1124            6 :                                 if (state.dataWeather->EPWDaylightSaving) {
    1125            1 :                                     Source = "WeatherFile";
    1126              :                                 }
    1127              :                             } else {
    1128           18 :                                 Source = "RunPeriod Object";
    1129              :                             }
    1130           24 :                             if (state.dataWeather->IDFDaylightSaving) {
    1131            1 :                                 Source = "InputFile";
    1132              :                             }
    1133           24 :                             if (state.dataWeather->DaylightSavingIsActive && state.dataReportFlag->DoWeatherInitReporting) {
    1134            2 :                                 StDate = format(DateFormat, DSTActStMon, DSTActStDay);
    1135            2 :                                 EnDate = format(DateFormat, DSTActEnMon, DSTActEnDay);
    1136            2 :                                 print(state.files.eio, EnvDSTYFormat, Source, StDate, EnDate);
    1137           22 :                             } else if (state.dataGlobal->DoOutputReporting) {
    1138           10 :                                 print(state.files.eio, EnvDSTNFormat, Source);
    1139              :                             }
    1140           45 :                             for (int k = 1; k <= state.dataWeather->NumSpecialDays; ++k) {
    1141           21 :                                 auto &specialDay = state.dataWeather->SpecialDays(k);
    1142              :                                 static constexpr std::string_view EnvSpDyFormat("Environment:Special Days,{},{},{},{},{:3}\n");
    1143           21 :                                 if (specialDay.WthrFile && state.dataWeather->UseSpecialDays && state.dataReportFlag->DoWeatherInitReporting) {
    1144           11 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1145           11 :                                     print(state.files.eio,
    1146              :                                           EnvSpDyFormat,
    1147           11 :                                           specialDay.Name,
    1148           11 :                                           Sched::dayTypeNames[specialDay.DayType],
    1149              :                                           "WeatherFile",
    1150              :                                           StDate,
    1151           11 :                                           specialDay.Duration);
    1152              :                                 }
    1153           21 :                                 if (!specialDay.WthrFile && state.dataReportFlag->DoWeatherInitReporting) {
    1154           10 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1155           10 :                                     print(state.files.eio,
    1156              :                                           EnvSpDyFormat,
    1157           10 :                                           specialDay.Name,
    1158           10 :                                           Sched::dayTypeNames[specialDay.DayType],
    1159              :                                           "InputFile",
    1160              :                                           StDate,
    1161           10 :                                           specialDay.Duration);
    1162              :                                 }
    1163              :                             }
    1164           24 :                         }
    1165              : 
    1166         6192 :                     } else if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay ||
    1167          126 :                                state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay) { // Design Day
    1168         6029 :                         auto const &desDayInput = state.dataWeather->DesDayInput(envCurr.DesignDayNum);
    1169         6029 :                         state.dataEnvrn->RunPeriodEnvironment = false;
    1170         6029 :                         StDate = format(DateFormat, desDayInput.Month, desDayInput.DayOfMonth);
    1171         6029 :                         EnDate = StDate;
    1172         6029 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
    1173         1855 :                             print(state.files.eio,
    1174              :                                   EnvNameFormat,
    1175         1855 :                                   envCurr.Title,
    1176              :                                   "SizingPeriod:DesignDay",
    1177              :                                   StDate,
    1178              :                                   EnDate,
    1179         1855 :                                   Sched::dayTypeNames[desDayInput.DayType],
    1180              :                                   "1",
    1181              :                                   "N/A",
    1182              :                                   "N/A",
    1183              :                                   "N/A",
    1184              :                                   "N/A",
    1185              :                                   "N/A",
    1186              :                                   "N/A",
    1187         1855 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
    1188              :                         }
    1189         6029 :                         if (desDayInput.DSTIndicator == 0 && state.dataReportFlag->DoWeatherInitReporting) {
    1190         1855 :                             print(state.files.eio, EnvDSTNFormat, "SizingPeriod:DesignDay");
    1191         4174 :                         } else if (state.dataReportFlag->DoWeatherInitReporting) {
    1192            0 :                             print(state.files.eio, EnvDSTYFormat, "SizingPeriod:DesignDay", StDate, EnDate);
    1193              :                         }
    1194              :                     }
    1195         6066 :                 }
    1196              :             } // ErrorsFound
    1197              :         }
    1198              : 
    1199        11353 :         if (ErrorsFound && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    1200            0 :             ShowSevereError(state, format("{}Errors found in getting a new environment", RoutineName));
    1201            0 :             Available = false;
    1202        11353 :         } else if (ErrorsFound) {
    1203            0 :             Available = false;
    1204              :         }
    1205        11353 :         return Available && !ErrorsFound;
    1206              :     }
    1207              : 
    1208           17 :     void AddDesignSetToEnvironmentStruct(EnergyPlusData &state, int const HVACSizingIterCount)
    1209              :     {
    1210           17 :         int OrigNumOfEnvrn = state.dataWeather->NumOfEnvrn;
    1211              : 
    1212           84 :         for (int i = 1; i <= OrigNumOfEnvrn; ++i) {
    1213              :             // Gotcha: references may no longer be valid after a redimension! Cannot declare reference to Environment(i) here.
    1214           67 :             if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1215           35 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1216           35 :                 auto &envBase = state.dataWeather->Environment(i);
    1217           35 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1218           35 :                 envNew = envBase; // copy over seed data from current array element
    1219           35 :                 envNew.SeedEnvrnNum = i;
    1220           35 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeDesignDay;
    1221           35 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1222           35 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1223           32 :             } else if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    1224            0 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1225            0 :                 auto &envBase = state.dataWeather->Environment(i);
    1226            0 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1227            0 :                 envNew = envBase; // copy over seed data
    1228            0 :                 envNew.SeedEnvrnNum = i;
    1229            0 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeRunPeriodDesign;
    1230            0 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1231            0 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1232              :             }
    1233              :         } // for each loop over Environment data strucure
    1234           17 :     }
    1235              : 
    1236         1989 :     void SetupWeekDaysByMonth(EnergyPlusData &state, int const StMon, int const StDay, int const StWeekDay, Array1D_int &WeekDays)
    1237              :     {
    1238              : 
    1239              :         // SUBROUTINE INFORMATION:
    1240              :         //       AUTHOR         Linda Lawrie
    1241              :         //       DATE WRITTEN   August 2000
    1242              : 
    1243              :         // PURPOSE OF THIS SUBROUTINE:
    1244              :         // This subroutine calculates the weekday for each month based on the start date and
    1245              :         // weekday specified for that date.
    1246              : 
    1247              :         // Argument array dimensioning
    1248         1989 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1249              : 
    1250              :         // Set 1st day of Start Month
    1251         1989 :         int CurWeekDay{StWeekDay};
    1252         8198 :         for (int i = 1; i <= StDay - 1; ++i) {
    1253         6209 :             --CurWeekDay;
    1254         6209 :             if (CurWeekDay == 0) {
    1255          941 :                 CurWeekDay = 7;
    1256              :             }
    1257              :         }
    1258              : 
    1259         1989 :         WeekDays(StMon) = CurWeekDay;
    1260        21060 :         for (int i = StMon + 1; i <= 12; ++i) {
    1261              : 
    1262        19071 :             if (i == 2) {
    1263         1482 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1264         7422 :                 while (CurWeekDay > 7) {
    1265         5940 :                     CurWeekDay -= 7;
    1266              :                 }
    1267         1482 :                 WeekDays(i) = CurWeekDay;
    1268        17589 :             } else if (i == 3) {
    1269         1498 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + state.dataWeather->LeapYearAdd;
    1270         7490 :                 while (CurWeekDay > 7) {
    1271         5992 :                     CurWeekDay -= 7;
    1272              :                 }
    1273         1498 :                 WeekDays(i) = CurWeekDay;
    1274              :             } else {
    1275        16091 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1276        86392 :                 while (CurWeekDay > 7) {
    1277        70301 :                     CurWeekDay -= 7;
    1278              :                 }
    1279        16091 :                 WeekDays(i) = CurWeekDay;
    1280              :             }
    1281              :         }
    1282              : 
    1283         1989 :         if (any_eq(WeekDays, 0)) {
    1284              :             // need to start at StMon and go backwards.
    1285              :             // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1286          506 :             CurWeekDay = StWeekDay;
    1287         3133 :             for (int i = 1; i <= StDay - 1; ++i) {
    1288         2627 :                 --CurWeekDay;
    1289         2627 :                 if (CurWeekDay == 0) {
    1290          412 :                     CurWeekDay = 7;
    1291              :                 }
    1292              :             }
    1293              : 
    1294         3308 :             for (int i = StMon - 1; i >= 1; --i) {
    1295              : 
    1296         2802 :                 if (i == 1) {
    1297          506 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1298         2807 :                     while (CurWeekDay <= 0) {
    1299         2301 :                         CurWeekDay += 7;
    1300              :                     }
    1301          506 :                     WeekDays(i) = CurWeekDay;
    1302         2296 :                 } else if (i == 2) {
    1303          490 :                     CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
    1304         2450 :                     while (CurWeekDay <= 0) {
    1305         1960 :                         CurWeekDay += 7;
    1306              :                     }
    1307          490 :                     WeekDays(i) = CurWeekDay;
    1308         1806 :                 } else if ((i >= 3) && (i <= 12)) {
    1309         1806 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1310         9645 :                     while (CurWeekDay <= 0) {
    1311         7839 :                         CurWeekDay += 7;
    1312              :                     }
    1313         1806 :                     WeekDays(i) = CurWeekDay;
    1314              :                 }
    1315              :             }
    1316              :         }
    1317         1989 :     }
    1318              : #pragma clang diagnostic pop
    1319              : 
    1320            0 :     void ResetWeekDaysByMonth(EnergyPlusData &state,
    1321              :                               Array1D_int &WeekDays,
    1322              :                               int const AddLeapYear,
    1323              :                               int const StartMonth,
    1324              :                               int const StartMonthDay,
    1325              :                               int const EndMonth,
    1326              :                               int const EndMonthDay,
    1327              :                               bool const Rollover,
    1328              :                               bool const MidSimReset)
    1329              :     {
    1330              : 
    1331              :         // SUBROUTINE INFORMATION:
    1332              :         //       AUTHOR         Linda Lawrie
    1333              :         //       DATE WRITTEN   March 2012
    1334              : 
    1335              :         // PURPOSE OF THIS SUBROUTINE:
    1336              :         // This subroutine resets the weekday for each month based on the current weekday
    1337              :         // and previous weekdays per month.
    1338              : 
    1339            0 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1340              : 
    1341            0 :         Array1D_int WeekDaysCopy(12);
    1342              :         int CurWeekDay;
    1343              : 
    1344            0 :         WeekDaysCopy = WeekDays;
    1345            0 :         if (!MidSimReset) {
    1346            0 :             if (Rollover) {
    1347            0 :                 if (StartMonth == 1) {
    1348            0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1349              :                 } else {
    1350            0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1351              :                 }
    1352              :             } else { // restart at same as before
    1353            0 :                 CurWeekDay = WeekDays(StartMonth);
    1354              :             }
    1355            0 :             while (CurWeekDay > 7) {
    1356            0 :                 CurWeekDay -= 7;
    1357              :             }
    1358              : 
    1359            0 :             WeekDays = 0;
    1360            0 :             WeekDays(StartMonth) = CurWeekDay;
    1361            0 :             for (int i = StartMonth + 1; i <= 12; ++i) {
    1362            0 :                 if (i == 2) {
    1363            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1364            0 :                     while (CurWeekDay > 7) {
    1365            0 :                         CurWeekDay -= 7;
    1366              :                     }
    1367            0 :                     WeekDays(i) = CurWeekDay;
    1368            0 :                 } else if (i == 3) {
    1369            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1370            0 :                     while (CurWeekDay > 7) {
    1371            0 :                         CurWeekDay -= 7;
    1372              :                     }
    1373            0 :                     WeekDays(i) = CurWeekDay;
    1374              :                 } else {
    1375            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1376            0 :                     while (CurWeekDay > 7) {
    1377            0 :                         CurWeekDay -= 7;
    1378              :                     }
    1379            0 :                     WeekDays(i) = CurWeekDay;
    1380              :                 }
    1381              :             }
    1382              : 
    1383            0 :             if (any_eq(WeekDays, 0)) {
    1384              :                 // need to start at StMon and go backwards.
    1385              :                 // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1386            0 :                 CurWeekDay = WeekDays(StartMonth);
    1387            0 :                 for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1388            0 :                     --CurWeekDay;
    1389            0 :                     if (CurWeekDay == 0) {
    1390            0 :                         CurWeekDay = 7;
    1391              :                     }
    1392              :                 }
    1393              : 
    1394            0 :                 for (int i = StartMonth - 1; i >= 1; --i) {
    1395              : 
    1396            0 :                     if (i == 1) {
    1397            0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1398            0 :                         while (CurWeekDay <= 0) {
    1399            0 :                             CurWeekDay += 7;
    1400              :                         }
    1401            0 :                         WeekDays(i) = CurWeekDay;
    1402            0 :                     } else if (i == 2) {
    1403            0 :                         CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1404            0 :                         while (CurWeekDay <= 0) {
    1405            0 :                             CurWeekDay += 7;
    1406              :                         }
    1407            0 :                         WeekDays(i) = CurWeekDay;
    1408            0 :                     } else if ((i >= 3) && (i <= 12)) {
    1409            0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1410            0 :                         while (CurWeekDay <= 0) {
    1411            0 :                             CurWeekDay += 7;
    1412              :                         }
    1413            0 :                         WeekDays(i) = CurWeekDay;
    1414              :                     }
    1415              :                 }
    1416              :             }
    1417              : 
    1418              :         } else {
    1419            0 :             if (Rollover) {
    1420            0 :                 if (StartMonth == 1) {
    1421            0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1422              :                 } else {
    1423            0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1424              :                 }
    1425              :             } else { // restart at same as before
    1426            0 :                 CurWeekDay = WeekDays(StartMonth);
    1427              :             }
    1428            0 :             while (CurWeekDay > 7) {
    1429            0 :                 CurWeekDay -= 7;
    1430              :             }
    1431            0 :             WeekDays = 0;
    1432            0 :             if (StartMonth != 1) {
    1433            0 :                 CurWeekDay = WeekDaysCopy(12) + state.dataWeather->EndDayOfMonth(12);
    1434            0 :                 while (CurWeekDay > 7) {
    1435            0 :                     CurWeekDay -= 7;
    1436              :                 }
    1437            0 :                 WeekDays(1) = CurWeekDay;
    1438            0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1439            0 :                 while (CurWeekDay > 7) {
    1440            0 :                     CurWeekDay -= 7;
    1441              :                 }
    1442            0 :                 WeekDays(2) = CurWeekDay;
    1443            0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1444            0 :                 while (CurWeekDay > 7) {
    1445            0 :                     CurWeekDay -= 7;
    1446              :                 }
    1447            0 :                 WeekDays(3) = CurWeekDay;
    1448            0 :                 for (int i = 4; i <= 12; ++i) {
    1449            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1450            0 :                     while (CurWeekDay > 7) {
    1451            0 :                         CurWeekDay -= 7;
    1452              :                     }
    1453            0 :                     WeekDays(i) = CurWeekDay;
    1454              :                 }
    1455              :             } else {
    1456            0 :                 WeekDays = 0;
    1457            0 :                 WeekDays(StartMonth) = CurWeekDay;
    1458            0 :                 for (int i = StartMonth + 1; i <= 12; ++i) {
    1459            0 :                     if (i == 2) {
    1460            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1461            0 :                         while (CurWeekDay > 7) {
    1462            0 :                             CurWeekDay -= 7;
    1463              :                         }
    1464            0 :                         WeekDays(i) = CurWeekDay;
    1465            0 :                     } else if (i == 3) {
    1466            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1467            0 :                         while (CurWeekDay > 7) {
    1468            0 :                             CurWeekDay -= 7;
    1469              :                         }
    1470            0 :                         WeekDays(i) = CurWeekDay;
    1471              :                     } else {
    1472            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1473            0 :                         while (CurWeekDay > 7) {
    1474            0 :                             CurWeekDay -= 7;
    1475              :                         }
    1476            0 :                         WeekDays(i) = CurWeekDay;
    1477              :                     }
    1478              :                 }
    1479              : 
    1480            0 :                 if (any_eq(WeekDays, 0)) {
    1481              :                     // need to start at StMon and go backwards.
    1482              :                     // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1483            0 :                     CurWeekDay = WeekDays(StartMonth);
    1484            0 :                     for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1485            0 :                         --CurWeekDay;
    1486            0 :                         if (CurWeekDay == 0) {
    1487            0 :                             CurWeekDay = 7;
    1488              :                         }
    1489              :                     }
    1490              : 
    1491            0 :                     for (int i = StartMonth - 1; i >= 1; --i) {
    1492              : 
    1493            0 :                         if (i == 1) {
    1494            0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1495            0 :                             while (CurWeekDay <= 0) {
    1496            0 :                                 CurWeekDay += 7;
    1497              :                             }
    1498            0 :                             WeekDays(i) = CurWeekDay;
    1499            0 :                         } else if (i == 2) {
    1500            0 :                             CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1501            0 :                             while (CurWeekDay <= 0) {
    1502            0 :                                 CurWeekDay += 7;
    1503              :                             }
    1504            0 :                             WeekDays(i) = CurWeekDay;
    1505            0 :                         } else if ((i >= 3) && (i <= 12)) {
    1506            0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1507            0 :                             while (CurWeekDay <= 0) {
    1508            0 :                                 CurWeekDay += 7;
    1509              :                             }
    1510            0 :                             WeekDays(i) = CurWeekDay;
    1511              :                         }
    1512              :                     }
    1513              :                 }
    1514              :             }
    1515              :         }
    1516            0 :     }
    1517              : 
    1518            6 :     void SetDSTDateRanges(EnergyPlusData &state,
    1519              :                           Array1D_int const &MonWeekDay, // Weekday of each day 1 of month
    1520              :                           Array1D_int &DSTIdx,           // DST Index for each julian day (1:366)
    1521              :                           ObjexxFCL::Optional_int DSTActStMon,
    1522              :                           ObjexxFCL::Optional_int DSTActStDay,
    1523              :                           ObjexxFCL::Optional_int DSTActEnMon,
    1524              :                           ObjexxFCL::Optional_int DSTActEnDay)
    1525              :     {
    1526              : 
    1527              :         // SUBROUTINE INFORMATION:
    1528              :         //       AUTHOR         Linda Lawrie
    1529              :         //       DATE WRITTEN   March 2012
    1530              : 
    1531              :         // PURPOSE OF THIS SUBROUTINE:
    1532              :         // With multiple year weather files (or repeating weather files that rollover day),
    1533              :         // need to set DST (Daylight Saving Time) dates at start of environment or year.
    1534              :         // DST is only projected for one year.
    1535              : 
    1536              :         static constexpr std::string_view RoutineName("SetDSTDateRanges: ");
    1537              : 
    1538              :         int ActStartMonth; // Actual Start Month
    1539              :         int ActStartDay;   // Actual Start Day of Month
    1540              :         int ActEndMonth;   // Actual End Month
    1541              :         int ActEndDay;     // Actual End Day of Month
    1542              : 
    1543            6 :         bool ErrorsFound = false;
    1544            6 :         if (state.dataWeather->DST.StDateType == DateType::MonthDay) {
    1545            3 :             ActStartMonth = state.dataWeather->DST.StMon;
    1546            3 :             ActStartDay = state.dataWeather->DST.StDay;
    1547            3 :         } else if (state.dataWeather->DST.StDateType == DateType::NthDayInMonth) {
    1548            3 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1549            6 :             while (ThisDay <= 0) {
    1550            3 :                 ThisDay += 7;
    1551              :             }
    1552            3 :             ThisDay += 7 * (state.dataWeather->DST.StDay - 1);
    1553            3 :             if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1554            0 :                 ShowSevereError(state, format("{}Determining DST: DST Start Date, Nth Day of Month, not enough Nths", RoutineName));
    1555            0 :                 ErrorsFound = true;
    1556              :             } else {
    1557            3 :                 ActStartMonth = state.dataWeather->DST.StMon;
    1558            3 :                 ActStartDay = ThisDay;
    1559              :             }
    1560              :         } else { // LastWeekDayInMonth
    1561            0 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1562            0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1563            0 :                 ThisDay += 7;
    1564              :             }
    1565            0 :             ActStartMonth = state.dataWeather->DST.StMon;
    1566            0 :             ActStartDay = ThisDay;
    1567              :         }
    1568              : 
    1569            6 :         if (state.dataWeather->DST.EnDateType == DateType::MonthDay) {
    1570            3 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1571            3 :             ActEndDay = state.dataWeather->DST.EnDay;
    1572            3 :         } else if (state.dataWeather->DST.EnDateType == DateType::NthDayInMonth) {
    1573            3 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1574            6 :             while (ThisDay <= 0) {
    1575            3 :                 ThisDay += 7;
    1576              :             }
    1577            3 :             ThisDay += 7 * (state.dataWeather->DST.EnDay - 1);
    1578            3 :             if (ThisDay >> state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1579            0 :                 ActEndMonth = 0; // Suppress uninitialized warning
    1580            0 :                 ActEndDay = 0;   // Suppress uninitialized warning
    1581            0 :                 ShowSevereError(state, format("{}Determining DST: DST End Date, Nth Day of Month, not enough Nths", RoutineName));
    1582            0 :                 ErrorsFound = true;
    1583              :             } else {
    1584            3 :                 ActEndMonth = state.dataWeather->DST.EnMon;
    1585            3 :                 ActEndDay = ThisDay;
    1586              :             }
    1587              :         } else { // LastWeekDayInMonth
    1588            0 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1589            0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1590            0 :                 ThisDay += 7;
    1591              :             }
    1592            0 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1593            0 :             ActEndDay = ThisDay;
    1594              :         }
    1595              : 
    1596            6 :         if (ErrorsFound) {
    1597            0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1598              :         }
    1599              : 
    1600            6 :         if (present(DSTActStMon)) {
    1601            4 :             DSTActStMon = ActStartMonth;
    1602            4 :             DSTActStDay = ActStartDay;
    1603            4 :             DSTActEnMon = ActEndMonth;
    1604            4 :             DSTActEnDay = ActEndDay;
    1605              :         }
    1606              : 
    1607            6 :         DSTIdx = 0;
    1608            6 :         int JDay = General::OrdinalDay(ActStartMonth, ActStartDay, state.dataWeather->LeapYearAdd);
    1609            6 :         int JDay1 = General::OrdinalDay(ActEndMonth, ActEndDay, state.dataWeather->LeapYearAdd);
    1610            6 :         if (JDay1 >= JDay) {
    1611            6 :             DSTIdx({JDay, JDay1}) = 1;
    1612              :         } else {
    1613            0 :             DSTIdx({JDay, 366}) = 1;
    1614            0 :             DSTIdx({1, JDay1}) = 1;
    1615              :         }
    1616            6 :     }
    1617              : 
    1618           43 :     void SetSpecialDayDates(EnergyPlusData &state, Array1D_int const &MonWeekDay) // Weekday of each day 1 of month
    1619              :     {
    1620              : 
    1621              :         // SUBROUTINE INFORMATION:
    1622              :         //       AUTHOR         Linda Lawrie
    1623              :         //       DATE WRITTEN   March 2012
    1624              : 
    1625              :         // PURPOSE OF THIS SUBROUTINE:
    1626              :         // With multiple year weather files (or repeating weather files that rollover day),
    1627              :         // need to set Special Day dates at start of environment or year.
    1628              :         // Special Days are only projected for one year.
    1629              : 
    1630              :         static constexpr std::string_view RoutineName("SetSpecialDayDates: ");
    1631              : 
    1632              :         int JDay;
    1633              : 
    1634           43 :         bool ErrorsFound = false;
    1635           43 :         state.dataWeather->SpecialDayTypes = 0;
    1636          106 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1637           63 :             auto &specialDay = state.dataWeather->SpecialDays(i);
    1638           63 :             if (specialDay.WthrFile && !state.dataWeather->UseSpecialDays) {
    1639            0 :                 continue;
    1640              :             }
    1641           63 :             if (specialDay.dateType <= DateType::MonthDay) {
    1642           30 :                 JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd);
    1643           30 :                 if (specialDay.Duration == 1 && state.dataWeather->Environment(state.dataWeather->Envrn).ApplyWeekendRule) {
    1644           18 :                     if (state.dataWeather->WeekDayTypes(JDay) == static_cast<int>(Sched::DayType::Sunday)) {
    1645              :                         // Sunday, must go to Monday
    1646            6 :                         ++JDay;
    1647            6 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) {
    1648            0 :                             JDay = 1;
    1649              :                         }
    1650           12 :                     } else if (state.dataWeather->WeekDayTypes(JDay) == (int)Sched::DayType::Saturday) {
    1651            0 :                         ++JDay;
    1652            0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) {
    1653            0 :                             JDay = 1;
    1654              :                         }
    1655            0 :                         ++JDay;
    1656            0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) {
    1657            0 :                             JDay = 1;
    1658              :                         }
    1659              :                     }
    1660              :                 }
    1661           30 :                 General::InvOrdinalDay(JDay, specialDay.ActStMon, specialDay.ActStDay, state.dataWeather->LeapYearAdd);
    1662           33 :             } else if (specialDay.dateType == DateType::NthDayInMonth) {
    1663           27 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1664           27 :                 if (specialDay.WeekDay < MonWeekDay(specialDay.Month)) {
    1665           18 :                     ThisDay += 7;
    1666              :                 }
    1667           27 :                 ThisDay += 7 * (specialDay.Day - 1);
    1668           27 :                 if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1669            0 :                     ShowSevereError(state,
    1670            0 :                                     format("{}Special Day Date, Nth Day of Month, not enough Nths, for SpecialDay={}", RoutineName, specialDay.Name));
    1671            0 :                     ErrorsFound = true;
    1672            0 :                     continue;
    1673              :                 }
    1674           27 :                 specialDay.ActStMon = specialDay.Month;
    1675           27 :                 specialDay.ActStDay = ThisDay;
    1676           27 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1677              :             } else { // LastWeekDayInMonth
    1678            6 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1679           33 :                 while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1680           27 :                     ThisDay += 7;
    1681              :                 }
    1682            6 :                 specialDay.ActStMon = specialDay.Month;
    1683            6 :                 specialDay.ActStDay = ThisDay;
    1684            6 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1685              :             }
    1686           63 :             if (state.dataWeather->SpecialDayTypes(JDay) != 0) {
    1687            0 :                 ShowWarningError(
    1688              :                     state,
    1689            0 :                     format("{}Special Day definition ({}) is overwriting previously entered special day period", RoutineName, specialDay.Name));
    1690            0 :                 if (state.dataWeather->UseSpecialDays) {
    1691            0 :                     ShowContinueError(state, "...This could be caused by definitions on the Weather File.");
    1692              :                 }
    1693            0 :                 ShowContinueError(state, "...This could be caused by duplicate definitions in the Input File.");
    1694              :             }
    1695           63 :             int JDay1 = JDay - 1;
    1696          126 :             for (int j = 0; j <= specialDay.Duration - 1; ++j) {
    1697           63 :                 ++JDay1;
    1698           63 :                 if (JDay1 == 366 && state.dataWeather->LeapYearAdd == 0) {
    1699            0 :                     JDay1 = 1;
    1700              :                 }
    1701           63 :                 if (JDay1 == 367) {
    1702            0 :                     JDay1 = 1;
    1703              :                 }
    1704           63 :                 state.dataWeather->SpecialDayTypes(JDay1) = specialDay.DayType;
    1705              :             }
    1706              :         }
    1707              : 
    1708           43 :         if (ErrorsFound) {
    1709            0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1710              :         }
    1711           43 :     }
    1712              : 
    1713      2925340 :     void InitializeWeather(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    1714              :     {
    1715              : 
    1716              :         // SUBROUTINE INFORMATION:
    1717              :         //       AUTHOR         Rick Strand
    1718              :         //       DATE WRITTEN   June 1997
    1719              : 
    1720              :         // PURPOSE OF THIS SUBROUTINE:
    1721              :         // This subroutine is the main driver of the weather initializations.
    1722              :         // Most of the weather handling can be described as "initializations"
    1723              :         // so most of the work is done via this subroutine.
    1724              : 
    1725      2925340 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->FirstCall) {
    1726              : 
    1727          801 :             state.dataWeather->FirstCall = false;
    1728          801 :             state.dataEnvrn->EndMonthFlag = false;
    1729              : 
    1730              :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
    1731              : 
    1732      2925340 :         auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    1733      2925340 :         if (state.dataGlobal->BeginEnvrnFlag) {
    1734              : 
    1735              :             // Call and setup the Design Day environment
    1736         7218 :             if (envCurr.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) {
    1737         6008 :                 if (envCurr.DesignDayNum > 0) {
    1738         5985 :                     SetUpDesignDay(state, envCurr.DesignDayNum);
    1739         5985 :                     state.dataEnvrn->EnvironmentName = envCurr.Title;
    1740              :                 }
    1741              :             }
    1742              : 
    1743              :             // Only used in Weather file environments
    1744              :             // Start over missing values with each environment
    1745         7218 :             state.dataWeather->wvarsMissing.OutBaroPress = state.dataEnvrn->StdBaroPress; // Initial "missing" value
    1746         7218 :             state.dataWeather->wvarsMissing.OutDryBulbTemp = 6.0;                         // Initial "missing" value
    1747         7218 :             state.dataWeather->wvarsMissing.OutDewPointTemp = 3.0;                        // Initial "missing" value
    1748         7218 :             state.dataWeather->wvarsMissing.OutRelHum = 50.0;                             // Initial "missing" value
    1749         7218 :             state.dataWeather->wvarsMissing.WindSpeed = 2.5;                              // Initial "missing" value
    1750         7218 :             state.dataWeather->wvarsMissing.WindDir = 180;                                // Initial "missing" value
    1751         7218 :             state.dataWeather->wvarsMissing.TotalSkyCover = 5;                            // Initial "missing" value
    1752         7218 :             state.dataWeather->wvarsMissing.OpaqueSkyCover = 5;                           // Initial "missing" value
    1753         7218 :             state.dataWeather->wvarsMissing.Visibility = 777.7;                           // Initial "missing" value
    1754         7218 :             state.dataWeather->wvarsMissing.Ceiling = 77777;                              // Initial "missing" value
    1755         7218 :             state.dataWeather->wvarsMissing.AerOptDepth = 0.0;                            // Initial "missing" value
    1756         7218 :             state.dataWeather->wvarsMissing.SnowDepth = 0;                                // Initial "missing" value
    1757         7218 :             state.dataWeather->wvarsMissing.DaysLastSnow = 88;                            // Initial "missing" value
    1758         7218 :             state.dataWeather->wvarsMissing.Albedo = 0.0;                                 // Initial "missing" value
    1759         7218 :             state.dataWeather->wvarsMissing.LiquidPrecip = 0.0;                           // Initial "missing" value
    1760              :             // Counts set to 0 for each environment
    1761         7218 :             state.dataWeather->wvarsMissedCounts = Weather::WeatherVarCounts();
    1762              : 
    1763              :             // Counts set to 0 for each environment
    1764         7218 :             state.dataWeather->wvarsOutOfRangeCounts = Weather::WeatherVarCounts();
    1765              : 
    1766         7218 :             state.dataWeather->IsRainThreshold = 0.8 / double(state.dataGlobal->TimeStepsInHour); // [mm]
    1767              : 
    1768         7218 :             if (!state.dataWeather->RPReadAllWeatherData) {
    1769         7217 :                 printEnvrnStamp = true; // Set this to true so that on first non-warmup day (only) the environment header will print out
    1770              :             }
    1771              : 
    1772        23626 :             for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1773        16408 :                 state.dataWeather->SpecialDays(i).Used = false;
    1774              :             }
    1775              : 
    1776         8531 :             if ((state.dataGlobal->KindOfSim != Constant::KindOfSim::DesignDay) &&
    1777         1313 :                 (state.dataGlobal->KindOfSim != Constant::KindOfSim::HVACSizeDesignDay)) {
    1778         1233 :                 ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read first day's weather
    1779              :             } else {
    1780         5985 :                 state.dataWeather->TomorrowVariables = state.dataWeather->DesignDay(envCurr.DesignDayNum);
    1781              :             }
    1782              : 
    1783              :         } // ... end of DataGlobals::BeginEnvrnFlag IF-THEN block.
    1784              : 
    1785      2925340 :         if (state.dataGlobal->BeginDayFlag) {
    1786              : 
    1787              :             // Check Holidays, Daylight Saving Time, Ground Temperatures, etc.
    1788              : 
    1789        27036 :             UpdateWeatherData(state); // Update daily weather info
    1790              : 
    1791              :             // Read tomorrow's weather only if necessary.  This means that the
    1792              :             // simulation is out of warmup, is using a weather tape for this
    1793              :             // environment, and is not on the last day (day after last day is
    1794              :             // assumed to be equal to last day).
    1795              : 
    1796              :             // Following code checks whether the present day of simulation matches the start month and start day.
    1797              :             // In a multi year simulation with run period less than 365, we need to position the weather line
    1798              :             // appropriately.
    1799              : 
    1800        33395 :             if ((!state.dataGlobal->WarmupFlag) &&
    1801         6359 :                 ((envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) && (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay))) {
    1802         3011 :                 if (state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) {
    1803         2991 :                     if (state.dataGlobal->DayOfSim == state.dataWeather->curSimDayForEndOfRunPeriod) {
    1804            0 :                         state.dataWeather->curSimDayForEndOfRunPeriod += envCurr.RawSimDays;
    1805            0 :                         if (state.dataWeather->StartDatesCycleShouldBeReset) {
    1806            0 :                             ResetWeekDaysByMonth(state,
    1807            0 :                                                  envCurr.MonWeekDay,
    1808            0 :                                                  state.dataWeather->LeapYearAdd,
    1809              :                                                  envCurr.StartMonth,
    1810              :                                                  envCurr.StartDay,
    1811              :                                                  envCurr.EndMonth,
    1812              :                                                  envCurr.EndDay,
    1813            0 :                                                  envCurr.RollDayTypeOnRepeat);
    1814            0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1815            0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1816              :                             }
    1817            0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1818              :                         }
    1819            0 :                         ++state.dataWeather->YearOfSim;
    1820            0 :                         ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1821              :                     } else {
    1822         2991 :                         ReadWeatherForDay(state, state.dataGlobal->DayOfSim + 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1823              :                     }
    1824              :                 }
    1825              :             }
    1826              : 
    1827        27036 :             state.dataEnvrn->EndYearFlag = false;
    1828        27036 :             if (state.dataEnvrn->DayOfMonth == state.dataWeather->EndDayOfMonthWithLeapDay(state.dataEnvrn->Month)) {
    1829          103 :                 state.dataEnvrn->EndMonthFlag = true;
    1830          103 :                 state.dataEnvrn->EndYearFlag = (state.dataEnvrn->Month == 12);
    1831              :             }
    1832              : 
    1833              :             // Set Tomorrow's date data
    1834        27036 :             state.dataEnvrn->MonthTomorrow = state.dataWeather->TomorrowVariables.Month;
    1835        27036 :             state.dataEnvrn->DayOfMonthTomorrow = state.dataWeather->TomorrowVariables.DayOfMonth;
    1836        27036 :             state.dataEnvrn->DayOfWeekTomorrow = state.dataWeather->TomorrowVariables.DayOfWeek;
    1837        27036 :             state.dataEnvrn->HolidayIndexTomorrow = state.dataWeather->TomorrowVariables.HolidayIndex;
    1838        27036 :             state.dataEnvrn->YearTomorrow = state.dataWeather->TomorrowVariables.Year;
    1839              : 
    1840        27036 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1841         3810 :                 if (state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1 && envCurr.ActualWeather) {
    1842            0 :                     if (state.dataWeather->DatesShouldBeReset) {
    1843            0 :                         if (envCurr.TreatYearsAsConsecutive) {
    1844            0 :                             ++envCurr.CurrentYear;
    1845            0 :                             envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1846            0 :                             state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1847            0 :                             state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1848              : 
    1849              :                             // need to reset MonWeekDay and WeekDayTypes
    1850            0 :                             int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1851            0 :                             int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1852            0 :                             if (!envCurr.ActualWeather) {
    1853            0 :                                 state.dataWeather->curSimDayForEndOfRunPeriod =
    1854            0 :                                     state.dataGlobal->DayOfSim + envCurr.RawSimDays + state.dataWeather->LeapYearAdd - 1;
    1855              :                             }
    1856              : 
    1857              :                             {
    1858            0 :                                 int i = JDay5Start;
    1859            0 :                                 int TWeekDay = state.dataEnvrn->DayOfWeek;
    1860              :                                 while (true) {
    1861            0 :                                     state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1862            0 :                                     TWeekDay = mod(TWeekDay, 7) + 1;
    1863            0 :                                     ++i;
    1864            0 :                                     if (i > 366) {
    1865            0 :                                         i = 1;
    1866              :                                     }
    1867            0 :                                     if (i == JDay5End) {
    1868            0 :                                         break;
    1869              :                                     }
    1870              :                                 }
    1871              :                             }
    1872            0 :                             ResetWeekDaysByMonth(state,
    1873            0 :                                                  envCurr.MonWeekDay,
    1874            0 :                                                  state.dataWeather->LeapYearAdd,
    1875              :                                                  envCurr.StartMonth,
    1876              :                                                  envCurr.StartDay,
    1877              :                                                  envCurr.EndMonth,
    1878              :                                                  envCurr.EndDay,
    1879            0 :                                                  envCurr.RollDayTypeOnRepeat);
    1880            0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1881            0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1882              :                             }
    1883            0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1884              :                         }
    1885              :                     }
    1886         3810 :                 } else if ((state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1) && state.dataWeather->DatesShouldBeReset &&
    1887            0 :                            (state.dataWeather->Jan1DatesShouldBeReset)) {
    1888            0 :                     if (envCurr.TreatYearsAsConsecutive) {
    1889            0 :                         ++envCurr.CurrentYear;
    1890            0 :                         envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1891            0 :                         state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1892            0 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && !state.dataWeather->WFAllowsLeapYears) {
    1893            0 :                             state.dataEnvrn->CurrentYearIsLeapYear = false;
    1894              :                         }
    1895            0 :                         if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod && state.dataEnvrn->CurrentYearIsLeapYear) {
    1896            0 :                             ++state.dataWeather->curSimDayForEndOfRunPeriod;
    1897              :                         }
    1898              :                     }
    1899              : 
    1900            0 :                     state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1901              : 
    1902            0 :                     if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod) {
    1903            0 :                         ResetWeekDaysByMonth(state,
    1904            0 :                                              envCurr.MonWeekDay,
    1905            0 :                                              state.dataWeather->LeapYearAdd,
    1906              :                                              envCurr.StartMonth,
    1907              :                                              envCurr.StartDay,
    1908              :                                              envCurr.EndMonth,
    1909              :                                              envCurr.EndDay,
    1910            0 :                                              envCurr.RollDayTypeOnRepeat,
    1911            0 :                                              envCurr.RollDayTypeOnRepeat || state.dataEnvrn->CurrentYearIsLeapYear);
    1912            0 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1913            0 :                             SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1914              :                         }
    1915            0 :                         SetSpecialDayDates(state, envCurr.MonWeekDay);
    1916              :                     }
    1917              :                 }
    1918              :             }
    1919              : 
    1920              :             // at the end of each day find the min/max weather used for DOAS sizing
    1921        27036 :             if (state.dataGlobal->AirLoopHVACDOASUsedInSim) {
    1922           35 :                 if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign || envCurr.KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1923          850 :                     for (int iHr = 1; iHr <= Constant::iHoursInDay; ++iHr) {
    1924         5712 :                         for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour; ++iTS) {
    1925         4896 :                             Real64 Tdb = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDryBulbTemp;
    1926         4896 :                             Real64 Tdp = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDewPointTemp;
    1927         4896 :                             if (Tdb > envCurr.maxCoolingOATSizing) {
    1928           42 :                                 envCurr.maxCoolingOATSizing = Tdb;
    1929           42 :                                 envCurr.maxCoolingOADPSizing = Tdp;
    1930              :                             }
    1931         4896 :                             if (Tdb < envCurr.minHeatingOATSizing) {
    1932           31 :                                 envCurr.minHeatingOATSizing = Tdb;
    1933           31 :                                 envCurr.minHeatingOADPSizing = Tdp;
    1934              :                             }
    1935              :                         } // for (iTS)
    1936              :                     } // for (iHr)
    1937              :                 }
    1938              :             }
    1939              : 
    1940              :         } // ... end of DataGlobals::BeginDayFlag IF-THEN block.
    1941              : 
    1942      5823644 :         if (!state.dataGlobal->BeginDayFlag && !state.dataGlobal->WarmupFlag &&
    1943       703561 :             (state.dataEnvrn->Month != envCurr.StartMonth || state.dataEnvrn->DayOfMonth != envCurr.StartDay) &&
    1944      5823644 :             !state.dataWeather->DatesShouldBeReset && envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1945            7 :             state.dataWeather->DatesShouldBeReset = true;
    1946              :         }
    1947              : 
    1948      2926653 :         if (state.dataGlobal->EndEnvrnFlag && (envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
    1949         1313 :             (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
    1950         1233 :             state.files.inputWeatherFile.rewind();
    1951         1233 :             SkipEPlusWFHeader(state);
    1952         1233 :             ReportMissing_RangeData(state);
    1953              :         }
    1954              : 
    1955              :         // set the EndDesignDayEnvrnsFlag (dataGlobal)
    1956              :         // True at the end of the last design day environment (last time step of last hour of last day of environ which is a design day)
    1957      2925340 :         state.dataGlobal->EndDesignDayEnvrnsFlag = false;
    1958      2925340 :         if (state.dataGlobal->EndEnvrnFlag) {
    1959         7217 :             if (state.dataWeather->Envrn < state.dataWeather->NumOfEnvrn) {
    1960         6355 :                 if (envCurr.KindOfEnvrn != state.dataWeather->Environment(state.dataWeather->Envrn + 1).KindOfEnvrn) {
    1961         2816 :                     state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1962              :                 }
    1963              :             } else {
    1964              :                 // if the last environment set the flag to true.
    1965          862 :                 state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1966              :             }
    1967              :         }
    1968              : 
    1969      2925340 :         if (state.dataWeather->WaterMainsParameterReport) {
    1970              :             // this is done only once
    1971          801 :             if (state.dataWeather->WaterMainsTempsMethod == WaterMainsTempCalcMethod::CorrelationFromWeatherFile) {
    1972            0 :                 if (!state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    1973            0 :                     state.dataWeather->OADryBulbAverage.CalcAnnualAndMonthlyDryBulbTemp(state);
    1974              :                 }
    1975              :             }
    1976              :             // reports to eio file
    1977          801 :             ReportWaterMainsTempParameters(state);
    1978          801 :             state.dataWeather->WaterMainsParameterReport = false;
    1979              :         }
    1980      2925340 :     }
    1981              : 
    1982        27036 :     void UpdateWeatherData(EnergyPlusData &state)
    1983              :     {
    1984              : 
    1985              :         // SUBROUTINE INFORMATION:
    1986              :         //       AUTHOR         Rick Strand
    1987              :         //       DATE WRITTEN   June 1997
    1988              : 
    1989              :         // PURPOSE OF THIS SUBROUTINE:
    1990              :         // This subroutine updates all of the daily weather data in the local
    1991              :         // module level variables and the global variables.
    1992              :         // This subroutine will temporarily transfer the weather data for the
    1993              :         // current day to the old data structure contained in envdat.inc until
    1994              :         // enough reengineering has taken place to eliminate the need for this
    1995              :         // include.
    1996              : 
    1997        27036 :         state.dataWeather->TodayVariables = state.dataWeather->TomorrowVariables; // Transfer Tomorrow's Daily Weather Variables to Today
    1998              : 
    1999        27036 :         if (state.dataGlobal->BeginEnvrnFlag) {
    2000         7218 :             state.dataGlobal->PreviousHour = 24;
    2001              :         }
    2002              : 
    2003        27036 :         state.dataWeather->wvarsHrTsToday = state.dataWeather->wvarsHrTsTomorrow; // What a waste
    2004              : 
    2005              :         // Update Global Data
    2006              : 
    2007        27036 :         state.dataEnvrn->DayOfYear = state.dataWeather->TodayVariables.DayOfYear;
    2008        27036 :         state.dataEnvrn->Year = state.dataWeather->TodayVariables.Year;
    2009        27036 :         state.dataEnvrn->Month = state.dataWeather->TodayVariables.Month;
    2010        27036 :         state.dataEnvrn->DayOfMonth = state.dataWeather->TodayVariables.DayOfMonth;
    2011        27036 :         state.dataEnvrn->DayOfWeek = state.dataWeather->TodayVariables.DayOfWeek;
    2012        27036 :         state.dataEnvrn->HolidayIndex = state.dataWeather->TodayVariables.HolidayIndex;
    2013        27036 :         if (state.dataEnvrn->HolidayIndex > 0) {
    2014        22534 :             state.dataWeather->RptDayType = state.dataEnvrn->HolidayIndex;
    2015              :         } else {
    2016         4502 :             state.dataWeather->RptDayType = state.dataEnvrn->DayOfWeek;
    2017              :         }
    2018        27036 :         state.dataEnvrn->DSTIndicator = state.dataWeather->TodayVariables.DaylightSavingIndex;
    2019        27036 :         state.dataEnvrn->EquationOfTime = state.dataWeather->TodayVariables.EquationOfTime;
    2020        27036 :         state.dataEnvrn->CosSolarDeclinAngle = state.dataWeather->TodayVariables.CosSolarDeclinAngle;
    2021        27036 :         state.dataEnvrn->SinSolarDeclinAngle = state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    2022        27036 :     }
    2023              : 
    2024      2925340 :     void SetCurrentWeather(EnergyPlusData &state)
    2025              :     {
    2026              : 
    2027              :         // SUBROUTINE INFORMATION:
    2028              :         //       AUTHOR         Russ Taylor
    2029              :         //       DATE WRITTEN   March 1990
    2030              :         //       MODIFIED       Aug94 (LKL) Fixed improper weighting
    2031              :         //                      Nov98 (FCW) Added call to get exterior illuminances
    2032              :         //                      Jan02 (FCW) Changed how ground reflectance for daylighting is set
    2033              :         //                      Mar12 (LKL) Changed settings for leap years/ current years.
    2034              :         //       RE-ENGINEERED  Apr97,May97 (RKS)
    2035              : 
    2036              :         // PURPOSE OF THIS SUBROUTINE:
    2037              :         // The purpose of this subroutine is to interpolate the hourly
    2038              :         // environment data for the sub-hourly time steps in EnergyPlus.  In
    2039              :         // other words, this subroutine puts the current weather conditions
    2040              :         // into the proper variables.  Rather than using the same data for
    2041              :         // each time step, environment data is interpolated as a continuum
    2042              :         // throughout the day.
    2043              : 
    2044              :         // METHODOLOGY EMPLOYED:
    2045              :         // The current hour (DataGlobals::HourOfDay) as well as the next hour are used
    2046              :         // to come up with environment data per time step interval.  Method
    2047              :         // used is to assign a weighting for the current hour's data and
    2048              :         // (1-that weighting) to the next hour's data.  Actual method is:  if
    2049              :         // the current time step is 15 minutes into hour, the interpolated dry
    2050              :         // bulb temperature should be 3/4*dry bulb temperature of current hour
    2051              :         // and 1/4*dry bulb temperature of next environment hourly data.  At
    2052              :         // day boundary (current hour = 24), the next hour is hour 1 of next
    2053              :         // weather data day (Tomorrow%).
    2054              : 
    2055              :         static constexpr std::string_view RoutineName("SetCurrentWeather");
    2056              : 
    2057      2925340 :         state.dataWeather->NextHour = state.dataGlobal->HourOfDay + 1;
    2058              : 
    2059      2925340 :         if (state.dataGlobal->HourOfDay == 24) { // Should investigate whether EndDayFlag is always set here and use that instead
    2060       125257 :             state.dataWeather->NextHour = 1;
    2061              :         }
    2062              : 
    2063      2925340 :         if (state.dataGlobal->HourOfDay == 1) { // Should investigate whether DataGlobals::BeginDayFlag is always set here and use that instead
    2064       129107 :             state.dataEnvrn->DayOfYear_Schedule = General::OrdinalDay(state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, 1);
    2065              :         }
    2066              : 
    2067      2925340 :         Sched::UpdateScheduleVals(state);
    2068              : 
    2069      2925340 :         state.dataEnvrn->CurMnDyHr =
    2070      5850680 :             format("{:02d}/{:02d} {:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, (unsigned short)(state.dataGlobal->HourOfDay - 1));
    2071      2925340 :         state.dataEnvrn->CurMnDy = format("{:02d}/{:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    2072      2925340 :         state.dataEnvrn->CurMnDyYr =
    2073      5850680 :             format("{:02d}/{:02d}/{:04d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, state.dataGlobal->CalendarYear);
    2074              : 
    2075      2925340 :         state.dataGlobal->WeightNow = state.dataWeather->Interpolation(state.dataGlobal->TimeStep);
    2076      2925340 :         state.dataGlobal->WeightPreviousHour = 1.0 - state.dataGlobal->WeightNow;
    2077              : 
    2078      2925340 :         state.dataGlobal->CurrentTime = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * (state.dataWeather->TimeStepFraction);
    2079      2925340 :         state.dataGlobal->SimTimeSteps = (state.dataGlobal->DayOfSim - 1) * 24 * state.dataGlobal->TimeStepsInHour +
    2080      2925340 :                                          (state.dataGlobal->HourOfDay - 1) * state.dataGlobal->TimeStepsInHour + state.dataGlobal->TimeStep;
    2081              : 
    2082      2925340 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] =
    2083      2925340 :             state.dataWeather->siteBuildingSurfaceGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2084      2925340 :         state.dataEnvrn->GroundTempKelvin = state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] + Constant::Kelvin;
    2085      2925340 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod] =
    2086      2925340 :             state.dataWeather->siteFCFactorMethodGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2087      2925340 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow] =
    2088      2925340 :             state.dataWeather->siteShallowGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2089      2925340 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep] =
    2090      2925340 :             state.dataWeather->siteDeepGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2091      2925340 :         state.dataEnvrn->GndReflectance = state.dataWeather->GroundReflectances(state.dataEnvrn->Month);
    2092      2925340 :         state.dataEnvrn->GndReflectanceForDayltg = state.dataEnvrn->GndReflectance;
    2093              : 
    2094      2925340 :         CalcWaterMainsTemp(state);
    2095              : 
    2096              :         // Determine if Sun is up or down, set Solar Cosine values for time step.
    2097      2925340 :         DetermineSunUpDown(state, state.dataEnvrn->SOLCOS);
    2098      2925340 :         if (state.dataEnvrn->SunIsUp && state.dataWeather->SolarAltitudeAngle < 0.0) {
    2099            0 :             ShowFatalError(state, format("SetCurrentWeather: At {} Sun is Up but Solar Altitude Angle is < 0.0", state.dataEnvrn->CurMnDyHr));
    2100              :         }
    2101              : 
    2102      2925340 :         auto const &today = state.dataWeather->wvarsHrTsToday(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2103      2925340 :         state.dataEnvrn->OutDryBulbTemp = today.OutDryBulbTemp;
    2104      2925340 :         if (state.dataEnvrn->EMSOutDryBulbOverrideOn) {
    2105            0 :             state.dataEnvrn->OutDryBulbTemp = state.dataEnvrn->EMSOutDryBulbOverrideValue;
    2106              :         }
    2107      2925340 :         state.dataEnvrn->OutBaroPress = today.OutBaroPress;
    2108      2925340 :         state.dataEnvrn->OutDewPointTemp = today.OutDewPointTemp;
    2109      2925340 :         if (state.dataEnvrn->EMSOutDewPointTempOverrideOn) {
    2110            0 :             state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->EMSOutDewPointTempOverrideValue;
    2111              :         }
    2112      2925340 :         state.dataEnvrn->OutRelHum = today.OutRelHum;
    2113      2925340 :         state.dataEnvrn->OutRelHumValue = state.dataEnvrn->OutRelHum / 100.0;
    2114      2925340 :         if (state.dataEnvrn->EMSOutRelHumOverrideOn) {
    2115            0 :             state.dataEnvrn->OutRelHumValue = state.dataEnvrn->EMSOutRelHumOverrideValue / 100.0;
    2116            0 :             state.dataEnvrn->OutRelHum = state.dataEnvrn->EMSOutRelHumOverrideValue;
    2117              :         }
    2118              : 
    2119              :         // Humidity Ratio and Wet Bulb are derived
    2120      2925340 :         state.dataEnvrn->OutHumRat = Psychrometrics::PsyWFnTdbRhPb(
    2121      2925340 :             state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutRelHumValue, state.dataEnvrn->OutBaroPress, RoutineName);
    2122      5850680 :         state.dataEnvrn->OutWetBulbTemp =
    2123      2925340 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
    2124      2925340 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) {
    2125       957737 :             state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2126      1915474 :             Real64 TempVal = Psychrometrics::PsyWFnTdbTwbPb(
    2127       957737 :                 state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutWetBulbTemp, state.dataEnvrn->OutBaroPress);
    2128       957737 :             state.dataEnvrn->OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, TempVal, state.dataEnvrn->OutBaroPress);
    2129              :         }
    2130              : 
    2131      2925340 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) {
    2132      1000823 :             state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2133              :         }
    2134              : 
    2135      3251458 :         if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) ||
    2136       326118 :             (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay)) {
    2137              : 
    2138      9314019 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2139      6682070 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2140              :             }
    2141              : 
    2142      2631949 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2143      2631949 :             int const envrnDayNum = envCurr.DesignDayNum;
    2144      2631949 :             auto const &desDayInput = state.dataWeather->DesDayInput(envrnDayNum);
    2145      2631949 :             auto &spSiteSchedule = state.dataWeather->spSiteSchedules(envrnDayNum);
    2146      2631949 :             auto const &desDayMod = state.dataWeather->desDayMods(envrnDayNum)(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2147              : 
    2148      2631949 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Default) {
    2149         9234 :                 spSiteSchedule.OutDryBulbTemp = desDayMod.OutDryBulbTemp;
    2150              :             }
    2151              : 
    2152      2631949 :             if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    2153      2623174 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    2154        15606 :                 spSiteSchedule.OutRelHum = desDayMod.OutRelHum;
    2155              :             }
    2156      2631949 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    2157         5289 :                 spSiteSchedule.BeamSolarRad = desDayMod.BeamSolarRad;
    2158         5289 :                 spSiteSchedule.DifSolarRad = desDayMod.DifSolarRad;
    2159              :             }
    2160              : 
    2161      2631949 :             if (envCurr.skyTempModel == SkyTempModel::ScheduleValue || envCurr.skyTempModel == SkyTempModel::DryBulbDelta ||
    2162      2630122 :                 envCurr.skyTempModel == SkyTempModel::DewPointDelta) {
    2163         1827 :                 spSiteSchedule.SkyTemp = desDayMod.SkyTemp;
    2164              :             }
    2165       293391 :         } else if (state.dataEnvrn->TotDesDays > 0) {
    2166       880341 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2167       586950 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2168              :             }
    2169              :         }
    2170              : 
    2171      2925340 :         state.dataEnvrn->WindSpeed = today.WindSpeed;
    2172      2925340 :         if (state.dataEnvrn->EMSWindSpeedOverrideOn) {
    2173            0 :             state.dataEnvrn->WindSpeed = state.dataEnvrn->EMSWindSpeedOverrideValue;
    2174              :         }
    2175      2925340 :         state.dataEnvrn->WindDir = today.WindDir;
    2176      2925340 :         if (state.dataEnvrn->EMSWindDirOverrideOn) {
    2177            0 :             state.dataEnvrn->WindDir = state.dataEnvrn->EMSWindDirOverrideValue;
    2178              :         }
    2179      2925340 :         state.dataWeather->HorizIRSky = today.HorizIRSky;
    2180      2925340 :         state.dataEnvrn->SkyTemp = today.SkyTemp;
    2181      2925340 :         state.dataEnvrn->SkyTempKelvin = state.dataEnvrn->SkyTemp + Constant::Kelvin;
    2182      2925340 :         state.dataEnvrn->DifSolarRad = today.DifSolarRad;
    2183      2925340 :         if (state.dataEnvrn->EMSDifSolarRadOverrideOn) {
    2184            0 :             state.dataEnvrn->DifSolarRad = state.dataEnvrn->EMSDifSolarRadOverrideValue;
    2185              :         }
    2186      2925340 :         state.dataEnvrn->BeamSolarRad = today.BeamSolarRad;
    2187      2925340 :         if (state.dataEnvrn->EMSBeamSolarRadOverrideOn) {
    2188            0 :             state.dataEnvrn->BeamSolarRad = state.dataEnvrn->EMSBeamSolarRadOverrideValue;
    2189              :         }
    2190      2925340 :         state.dataEnvrn->LiquidPrecipitation = today.LiquidPrecip / 1000.0; // convert from mm to m
    2191      2925340 :         if ((state.dataEnvrn->RunPeriodEnvironment) && (!state.dataGlobal->WarmupFlag)) {
    2192       254136 :             int month = state.dataEnvrn->Month;
    2193       254136 :             state.dataWaterData->RainFall.MonthlyTotalPrecInWeather.at(month - 1) += state.dataEnvrn->LiquidPrecipitation * 1000.0;
    2194       254136 :             if ((state.dataEnvrn->LiquidPrecipitation > 0) && (state.dataGlobal->TimeStep == 1)) {
    2195          549 :                 state.dataWaterData->RainFall.numRainyHoursInWeather.at(month - 1) += 1;
    2196              :             }
    2197              :         }
    2198              : 
    2199      2925340 :         WaterManager::UpdatePrecipitation(state);
    2200              : 
    2201      2925340 :         state.dataEnvrn->TotalCloudCover = today.TotalSkyCover;
    2202      2925340 :         state.dataEnvrn->OpaqueCloudCover = today.OpaqueSkyCover;
    2203              : 
    2204      2925340 :         if (state.dataWeather->UseRainValues) {
    2205              :             // It is set as LiquidPrecipitation >= .8 mm here: state.dataWeather->TomorrowLiquidPrecip(ts, hour) >=
    2206              :             // state.dataWeather->IsRainThreshold;
    2207      2891293 :             state.dataEnvrn->IsRain = today.IsRain;
    2208      2891293 :             if (state.dataWaterData->RainFall.ModeID == DataWater::RainfallMode::RainSchedDesign && state.dataEnvrn->RunPeriodEnvironment) {
    2209              :                 // CurrentAmount unit: m
    2210            0 :                 state.dataEnvrn->IsRain = state.dataWaterData->RainFall.CurrentAmount >= (state.dataWeather->IsRainThreshold / 1000.0);
    2211              :             }
    2212              :         } else {
    2213        34047 :             state.dataEnvrn->IsRain = false;
    2214              :         }
    2215      2925340 :         if (state.dataWeather->UseSnowValues) {
    2216      2891293 :             state.dataEnvrn->IsSnow = today.IsSnow;
    2217              :         } else {
    2218        34047 :             state.dataEnvrn->IsSnow = false;
    2219              :         }
    2220              : 
    2221      2925340 :         if (state.dataEnvrn->IsSnow) {
    2222            0 :             state.dataEnvrn->GndReflectance = max(min(state.dataEnvrn->GndReflectance * state.dataWeather->SnowGndRefModifier, 1.0), 0.0);
    2223            0 :             state.dataEnvrn->GndReflectanceForDayltg =
    2224            0 :                 max(min(state.dataEnvrn->GndReflectanceForDayltg * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0);
    2225              :         }
    2226              : 
    2227      2925340 :         state.dataEnvrn->GndSolarRad =
    2228      2925340 :             max((state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z + state.dataEnvrn->DifSolarRad) * state.dataEnvrn->GndReflectance, 0.0);
    2229              : 
    2230      2925340 :         if (!state.dataEnvrn->SunIsUp) {
    2231      1463062 :             state.dataEnvrn->DifSolarRad = 0.0;
    2232      1463062 :             state.dataEnvrn->BeamSolarRad = 0.0;
    2233      1463062 :             state.dataEnvrn->GndSolarRad = 0.0;
    2234              :         }
    2235              : 
    2236      2925340 :         state.dataEnvrn->OutEnthalpy = Psychrometrics::PsyHFnTdbW(state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2237      5850680 :         state.dataEnvrn->OutAirDensity =
    2238      2925340 :             Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2239              : 
    2240      2925340 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) {
    2241            0 :             state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2242              :         }
    2243      2925340 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) {
    2244            0 :             state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2245              :         }
    2246              : 
    2247      2925340 :         DayltgCurrentExtHorizIllum(state);
    2248              : 
    2249      2925340 :         if (!state.dataEnvrn->IsRain) {
    2250      2924012 :             state.dataWeather->RptIsRain = 0;
    2251              :         } else {
    2252         1328 :             state.dataWeather->RptIsRain = 1;
    2253              :         }
    2254              : 
    2255      2925340 :         if (!state.dataEnvrn->IsSnow) {
    2256      2925340 :             state.dataWeather->RptIsSnow = 0;
    2257              :         } else {
    2258            0 :             state.dataWeather->RptIsSnow = 1;
    2259              :         }
    2260      2925340 :     }
    2261              : 
    2262         4224 :     void ReadWeatherForDay(EnergyPlusData &state,
    2263              :                            int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2264              :                            int const Environ,            // Environment being simulated
    2265              :                            bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2266              :     )
    2267              :     {
    2268              : 
    2269              :         // SUBROUTINE INFORMATION:
    2270              :         //       AUTHOR         Linda K. Lawrie
    2271              :         //       DATE WRITTEN   April 1999
    2272              : 
    2273              :         // PURPOSE OF THIS SUBROUTINE:
    2274              :         // This subroutine is the driving routine behind reading the weather data.
    2275              :         // Theoretically, several kinds of weather files could be read here.  As
    2276              :         // distributed only EPW files are allowed.
    2277              : 
    2278         4224 :         ReadEPlusWeatherForDay(state, DayToRead, Environ, BackSpaceAfterRead);
    2279         4224 :     }
    2280              : 
    2281         4224 :     void ReadEPlusWeatherForDay(EnergyPlusData &state,
    2282              :                                 int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2283              :                                 int const Environ,            // Environment being simulated
    2284              :                                 bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2285              :     )
    2286              :     {
    2287              : 
    2288              :         // SUBROUTINE INFORMATION:
    2289              :         //       AUTHOR         Linda K. Lawrie
    2290              :         //       DATE WRITTEN   April 1999
    2291              :         //       MODIFIED       March 2012; add actual weather read.
    2292              : 
    2293              :         // PURPOSE OF THIS SUBROUTINE:
    2294              :         // This subroutine reads the appropriate day of EPW weather data.
    2295              : 
    2296              :         int WYear;
    2297              :         int WMonth;
    2298              :         int WDay;
    2299              :         int WHour;
    2300              :         int WMinute;
    2301              :         Real64 DryBulb;
    2302              :         Real64 DewPoint;
    2303              :         Real64 RelHum;
    2304              :         Real64 AtmPress;
    2305              :         Real64 ETHoriz;
    2306              :         Real64 ETDirect;
    2307              :         Real64 IRHoriz;
    2308              :         Real64 GLBHoriz;
    2309              :         Real64 DirectRad;
    2310              :         Real64 DiffuseRad;
    2311              :         Real64 GLBHorizIllum;
    2312              :         Real64 DirectNrmIllum;
    2313              :         Real64 DiffuseHorizIllum;
    2314              :         Real64 ZenLum;
    2315              :         Real64 WindDir;
    2316              :         Real64 WindSpeed;
    2317              :         Real64 TotalSkyCover;
    2318              :         Real64 OpaqueSkyCover;
    2319              :         Real64 Visibility;
    2320              :         Real64 CeilHeight;
    2321              :         Real64 PrecipWater;
    2322              :         Real64 AerosolOptDepth;
    2323              :         Real64 SnowDepth;
    2324              :         Real64 DaysSinceLastSnow;
    2325              :         Real64 Albedo;
    2326              :         Real64 LiquidPrecip;
    2327              :         int PresWeathObs;
    2328         4224 :         Array1D_int PresWeathConds(9);
    2329              : 
    2330         4224 :         constexpr std::string_view routineName = "ReadEPlusWeatherForDay";
    2331              : 
    2332         4224 :         Array1D<WeatherVars> wvarsHr = Array1D<WeatherVars>(Constant::iHoursInDay);
    2333              : 
    2334         4224 :         auto &thisEnviron = state.dataWeather->Environment(Environ);
    2335              : 
    2336         4224 :         if (DayToRead == 1) {
    2337              : 
    2338              :             // Checks whether Weather file contains just one year of data. If yes then rewind and position to first
    2339              :             // day of weather file. The rest of code appropriately positions to the start day.
    2340              : 
    2341         1233 :             bool Ready = false;
    2342         1233 :             int NumRewinds = 0;
    2343              :             //     Must position file to proper day
    2344              :             //     File already position to first data record
    2345              :             //          Set Current Day of Week to "start of Data Period"
    2346         1233 :             state.dataWeather->ReadEPlusWeatherCurTime = 1.0 / double(state.dataWeather->NumIntervalsPerHour);
    2347         1233 :             state.dataWeather->CurDayOfWeek = state.dataWeather->DataPeriods(1).WeekDay - 1;
    2348         1233 :             WYear = 0;
    2349         1233 :             WMonth = 0;
    2350         1233 :             WDay = 0;
    2351         1233 :             WHour = 0;
    2352         1233 :             WMinute = 0;
    2353         1233 :             state.dataWeather->LastHourSet = false;
    2354         1233 :             InputFile::ReadResult<std::string> WeatherDataLine{"", true, false};
    2355        96384 :             while (!Ready) {
    2356        95151 :                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2357        95151 :                 if (WeatherDataLine.good) {
    2358              :                     bool ErrorFound;
    2359        95151 :                     InterpretWeatherDataLine(state,
    2360              :                                              WeatherDataLine.data,
    2361              :                                              ErrorFound,
    2362              :                                              WYear,
    2363              :                                              WMonth,
    2364              :                                              WDay,
    2365              :                                              WHour,
    2366              :                                              WMinute,
    2367              :                                              DryBulb,
    2368              :                                              DewPoint,
    2369              :                                              RelHum,
    2370              :                                              AtmPress,
    2371              :                                              ETHoriz,
    2372              :                                              ETDirect,
    2373              :                                              IRHoriz,
    2374              :                                              GLBHoriz,
    2375              :                                              DirectRad,
    2376              :                                              DiffuseRad,
    2377              :                                              GLBHorizIllum,
    2378              :                                              DirectNrmIllum,
    2379              :                                              DiffuseHorizIllum,
    2380              :                                              ZenLum,
    2381              :                                              WindDir,
    2382              :                                              WindSpeed,
    2383              :                                              TotalSkyCover,
    2384              :                                              OpaqueSkyCover,
    2385              :                                              Visibility,
    2386              :                                              CeilHeight,
    2387              :                                              PresWeathObs,
    2388              :                                              PresWeathConds,
    2389              :                                              PrecipWater,
    2390              :                                              AerosolOptDepth,
    2391              :                                              SnowDepth,
    2392              :                                              DaysSinceLastSnow,
    2393              :                                              Albedo,
    2394              :                                              LiquidPrecip);
    2395            0 :                 } else if (WeatherDataLine.eof) {
    2396            0 :                     if (NumRewinds > 0) {
    2397            0 :                         std::string date = fmt::to_string(thisEnviron.StartMonth) + '/' + fmt::to_string(thisEnviron.StartDay);
    2398            0 :                         if (thisEnviron.MatchYear) {
    2399            0 :                             date += '/' + fmt::to_string(thisEnviron.StartYear);
    2400              :                         }
    2401            0 :                         ShowSevereError(state, format("Multiple rewinds on EPW while searching for first day {}", date));
    2402            0 :                     } else {
    2403            0 :                         state.files.inputWeatherFile.rewind();
    2404            0 :                         ++NumRewinds;
    2405            0 :                         SkipEPlusWFHeader(state);
    2406            0 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2407              :                         bool ErrorFound;
    2408            0 :                         InterpretWeatherDataLine(state,
    2409              :                                                  WeatherDataLine.data,
    2410              :                                                  ErrorFound,
    2411              :                                                  WYear,
    2412              :                                                  WMonth,
    2413              :                                                  WDay,
    2414              :                                                  WHour,
    2415              :                                                  WMinute,
    2416              :                                                  DryBulb,
    2417              :                                                  DewPoint,
    2418              :                                                  RelHum,
    2419              :                                                  AtmPress,
    2420              :                                                  ETHoriz,
    2421              :                                                  ETDirect,
    2422              :                                                  IRHoriz,
    2423              :                                                  GLBHoriz,
    2424              :                                                  DirectRad,
    2425              :                                                  DiffuseRad,
    2426              :                                                  GLBHorizIllum,
    2427              :                                                  DirectNrmIllum,
    2428              :                                                  DiffuseHorizIllum,
    2429              :                                                  ZenLum,
    2430              :                                                  WindDir,
    2431              :                                                  WindSpeed,
    2432              :                                                  TotalSkyCover,
    2433              :                                                  OpaqueSkyCover,
    2434              :                                                  Visibility,
    2435              :                                                  CeilHeight,
    2436              :                                                  PresWeathObs,
    2437              :                                                  PresWeathConds,
    2438              :                                                  PrecipWater,
    2439              :                                                  AerosolOptDepth,
    2440              :                                                  SnowDepth,
    2441              :                                                  DaysSinceLastSnow,
    2442              :                                                  Albedo,
    2443              :                                                  LiquidPrecip);
    2444              :                     }
    2445              :                 }
    2446        95151 :                 if (!WeatherDataLine.good) {
    2447            0 :                     ShowFatalError(state,
    2448            0 :                                    format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2449              :                                           WYear,
    2450              :                                           WMonth,
    2451              :                                           WDay,
    2452              :                                           WHour,
    2453              :                                           WMinute,
    2454            0 :                                           state.files.inputWeatherFile.error_state_to_string()),
    2455            0 :                                    OptionalOutputFileRef{state.files.eso});
    2456              :                 }
    2457        95151 :                 if (state.dataWeather->CurDayOfWeek <= 7) {
    2458        95151 :                     state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2459              :                 }
    2460        95151 :                 bool RecordDateMatch =
    2461       189069 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && !thisEnviron.MatchYear) ||
    2462        93918 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && thisEnviron.MatchYear && WYear == thisEnviron.StartYear);
    2463        95151 :                 if (RecordDateMatch) {
    2464         1233 :                     state.files.inputWeatherFile.backspace();
    2465         1233 :                     Ready = true;
    2466         1233 :                     if (state.dataWeather->CurDayOfWeek <= 7) {
    2467         1233 :                         --state.dataWeather->CurDayOfWeek;
    2468              :                     }
    2469              :                     // Do the range checks on the first set of fields -- no others.
    2470         1233 :                     bool ErrorsFound = false;
    2471         1233 :                     if (DryBulb < 99.9 && (DryBulb < -90.0 || DryBulb > 70.0)) {
    2472            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2473            0 :                         ShowContinueError(state, format("DryBulb Temperature ({:.2R}) is out of range [-90.0, 70.0]", DryBulb));
    2474            0 :                         ErrorsFound = true;
    2475              :                     }
    2476              : 
    2477         1233 :                     if (DewPoint < 99.9 && (DewPoint < -90.0 || DewPoint > 70.0)) {
    2478            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2479            0 :                         ShowContinueError(state, format("DewPoint Temperature ({:.2R}) is out of range [-90.0, 70.0]", DewPoint));
    2480            0 :                         ErrorsFound = true;
    2481              :                     }
    2482              : 
    2483         1233 :                     if (RelHum < 999.0 && (RelHum < 0.0 || RelHum > 110.0)) {
    2484            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2485            0 :                         ShowContinueError(state, format("Relative Humidity ({:.2R}) is out of range [0.0, 100.0]", RelHum));
    2486            0 :                         ErrorsFound = true;
    2487              :                     }
    2488              : 
    2489         1233 :                     if (AtmPress < 999999.0 && (AtmPress <= 31000.0 || AtmPress > 120000.0)) {
    2490            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2491            0 :                         ShowContinueError(state, format("Atmospheric Pressure ({:.0R}) is out of range [31000, 120000]", AtmPress));
    2492            0 :                         ErrorsFound = true;
    2493              :                     }
    2494              : 
    2495         1233 :                     if (DirectRad < 0.0) {
    2496            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2497            0 :                         ShowContinueError(state, format("Direct Radiation ({:.2R}) is out of range [0.0, -]", DirectRad));
    2498            0 :                         ErrorsFound = true;
    2499              :                     }
    2500              : 
    2501         1233 :                     if (DiffuseRad < 0.0) {
    2502            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2503            0 :                         ShowContinueError(state, format("Diffuse Radiation ({:.2R}) is out of range [0.0, -]", DiffuseRad));
    2504            0 :                         ErrorsFound = true;
    2505              :                     }
    2506              : 
    2507         1233 :                     if (WindDir < 999.0 && (WindDir < 0.0 || WindDir > 360.0)) {
    2508            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2509            0 :                         ShowContinueError(state, format("Wind Direction ({:.2R}) is out of range [0.0, 360.0]", WindDir));
    2510            0 :                         ErrorsFound = true;
    2511              :                     }
    2512              : 
    2513         1233 :                     if (WindSpeed < 999.0 && (WindSpeed < 0.0 || WindSpeed > 40.0)) {
    2514            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2515            0 :                         ShowContinueError(state, format("Wind Speed ({:.2R}) is out of range [0.0, 40.0]", WindSpeed));
    2516            0 :                         ErrorsFound = true;
    2517              :                     }
    2518              : 
    2519         1233 :                     if (ErrorsFound) {
    2520            0 :                         ShowSevereError(state, "Out of Range errors found with initial day of WeatherFile");
    2521              :                     }
    2522              :                 } else {
    2523              :                     //  Must skip this day
    2524        93918 :                     for (int i = 2; i <= state.dataWeather->NumIntervalsPerHour; ++i) {
    2525            0 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2526            0 :                         if (!WeatherDataLine.good) {
    2527            0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2528            0 :                             ShowFatalError(state,
    2529            0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2530              :                                                   WYear,
    2531              :                                                   WMonth,
    2532              :                                                   WDay,
    2533              :                                                   WHour,
    2534              :                                                   WMinute,
    2535            0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2536            0 :                                            OptionalOutputFileRef{state.files.eso});
    2537              :                         }
    2538              :                     }
    2539      2254032 :                     for (int i = 1; i <= 23 * state.dataWeather->NumIntervalsPerHour; ++i) {
    2540      2160114 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2541      2160114 :                         if (!WeatherDataLine.good) {
    2542            0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2543            0 :                             ShowFatalError(state,
    2544            0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2545              :                                                   WYear,
    2546              :                                                   WMonth,
    2547              :                                                   WDay,
    2548              :                                                   WHour,
    2549              :                                                   WMinute,
    2550            0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2551            0 :                                            OptionalOutputFileRef{state.files.eso});
    2552              :                         }
    2553              :                     }
    2554              :                 }
    2555              :             }
    2556              : 
    2557         1233 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2558              :             // Why do some things here use state.dataWeather->Envrn and some the parameter Environ?
    2559              : 
    2560              :             // Positioned to proper day
    2561         1245 :             if (!state.dataGlobal->KickOffSimulation && !state.dataGlobal->DoingSizing &&
    2562           12 :                 thisEnviron.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    2563            7 :                 ++thisEnviron.CurrentCycle;
    2564            7 :                 if (!thisEnviron.RollDayTypeOnRepeat) {
    2565            0 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2566            0 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2567            0 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2568              :                     }
    2569            0 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2570            7 :                 } else if (thisEnviron.CurrentCycle == 1) {
    2571            7 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2572            7 :                     thisEnviron.SetWeekDays = true;
    2573            7 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2574            2 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2575              :                     }
    2576            7 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2577              :                 } else {
    2578            0 :                     state.dataWeather->CurDayOfWeek = state.dataEnvrn->DayOfWeekTomorrow;
    2579              :                 }
    2580              :             } else {
    2581         1226 :                 SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2582              :             }
    2583         1233 :         }
    2584              : 
    2585         4224 :         bool TryAgain = true;
    2586         4224 :         bool SkipThisDay = false;
    2587              : 
    2588         8448 :         while (TryAgain) {
    2589              : 
    2590         4224 :             TryAgain = false;
    2591              : 
    2592       105600 :             for (int hour = 1; hour <= 24; ++hour) {
    2593       202752 :                 for (int CurTimeStep = 1; CurTimeStep <= state.dataWeather->NumIntervalsPerHour; ++CurTimeStep) {
    2594       101376 :                     state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour) = WeatherVars();
    2595       101376 :                     auto WeatherDataLine = state.files.inputWeatherFile.readLine();
    2596       101376 :                     if (!WeatherDataLine.good) {
    2597            0 :                         WeatherDataLine.data.clear();
    2598              :                     }
    2599       101376 :                     if (WeatherDataLine.data.empty()) {
    2600            0 :                         if (hour == 1) {
    2601            0 :                             WeatherDataLine.eof = true;
    2602            0 :                             WeatherDataLine.good = false;
    2603              :                         } else {
    2604            0 :                             WeatherDataLine.good = false;
    2605              :                         }
    2606              :                     }
    2607       101376 :                     if (WeatherDataLine.good) {
    2608              :                         bool ErrorFound;
    2609       101376 :                         InterpretWeatherDataLine(state,
    2610              :                                                  WeatherDataLine.data,
    2611              :                                                  ErrorFound,
    2612              :                                                  WYear,
    2613              :                                                  WMonth,
    2614              :                                                  WDay,
    2615              :                                                  WHour,
    2616              :                                                  WMinute,
    2617              :                                                  DryBulb,
    2618              :                                                  DewPoint,
    2619              :                                                  RelHum,
    2620              :                                                  AtmPress,
    2621              :                                                  ETHoriz,
    2622              :                                                  ETDirect,
    2623              :                                                  IRHoriz,
    2624              :                                                  GLBHoriz,
    2625              :                                                  DirectRad,
    2626              :                                                  DiffuseRad,
    2627              :                                                  GLBHorizIllum,
    2628              :                                                  DirectNrmIllum,
    2629              :                                                  DiffuseHorizIllum,
    2630              :                                                  ZenLum,
    2631              :                                                  WindDir,
    2632              :                                                  WindSpeed,
    2633              :                                                  TotalSkyCover,
    2634              :                                                  OpaqueSkyCover,
    2635              :                                                  Visibility,
    2636              :                                                  CeilHeight,
    2637              :                                                  PresWeathObs,
    2638              :                                                  PresWeathConds,
    2639              :                                                  PrecipWater,
    2640              :                                                  AerosolOptDepth,
    2641              :                                                  SnowDepth,
    2642              :                                                  DaysSinceLastSnow,
    2643              :                                                  Albedo,
    2644              :                                                  LiquidPrecip);
    2645              :                     } else { // ReadStatus /=0
    2646            0 :                         if (WeatherDataLine.eof &&
    2647            0 :                             state.dataWeather->NumDataPeriods == 1) { // Standard End-of-file, rewind and position to first day...
    2648            0 :                             if (state.dataWeather->DataPeriods(1).NumDays >= state.dataWeather->NumDaysInYear) {
    2649            0 :                                 state.files.inputWeatherFile.rewind();
    2650            0 :                                 SkipEPlusWFHeader(state);
    2651            0 :                                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2652              :                                 bool ErrorFound;
    2653            0 :                                 InterpretWeatherDataLine(state,
    2654              :                                                          WeatherDataLine.data,
    2655              :                                                          ErrorFound,
    2656              :                                                          WYear,
    2657              :                                                          WMonth,
    2658              :                                                          WDay,
    2659              :                                                          WHour,
    2660              :                                                          WMinute,
    2661              :                                                          DryBulb,
    2662              :                                                          DewPoint,
    2663              :                                                          RelHum,
    2664              :                                                          AtmPress,
    2665              :                                                          ETHoriz,
    2666              :                                                          ETDirect,
    2667              :                                                          IRHoriz,
    2668              :                                                          GLBHoriz,
    2669              :                                                          DirectRad,
    2670              :                                                          DiffuseRad,
    2671              :                                                          GLBHorizIllum,
    2672              :                                                          DirectNrmIllum,
    2673              :                                                          DiffuseHorizIllum,
    2674              :                                                          ZenLum,
    2675              :                                                          WindDir,
    2676              :                                                          WindSpeed,
    2677              :                                                          TotalSkyCover,
    2678              :                                                          OpaqueSkyCover,
    2679              :                                                          Visibility,
    2680              :                                                          CeilHeight,
    2681              :                                                          PresWeathObs,
    2682              :                                                          PresWeathConds,
    2683              :                                                          PrecipWater,
    2684              :                                                          AerosolOptDepth,
    2685              :                                                          SnowDepth,
    2686              :                                                          DaysSinceLastSnow,
    2687              :                                                          Albedo,
    2688              :                                                          LiquidPrecip);
    2689              :                             } else {
    2690            0 :                                 ShowFatalError(state,
    2691            0 :                                                format("End-of-File encountered after {}/{}/{} {}:{}, starting from first day of Weather File would "
    2692              :                                                       "not be \"next day\"",
    2693              :                                                       WYear,
    2694              :                                                       WMonth,
    2695              :                                                       WDay,
    2696              :                                                       WHour,
    2697              :                                                       WMinute));
    2698              :                             }
    2699              :                         } else {
    2700            0 :                             ShowFatalError(state,
    2701            0 :                                            format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2702              :                                                   WYear,
    2703              :                                                   WMonth,
    2704              :                                                   WDay,
    2705              :                                                   WHour,
    2706              :                                                   WMinute),
    2707            0 :                                            OptionalOutputFileRef{state.files.eso});
    2708              :                         }
    2709              :                     }
    2710              : 
    2711       101376 :                     if (hour != WHour) {
    2712            0 :                         ShowFatalError(state,
    2713            0 :                                        format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2714              :                                               WYear,
    2715              :                                               WMonth,
    2716              :                                               WDay,
    2717              :                                               WHour,
    2718              :                                               WMinute),
    2719            0 :                                        OptionalOutputFileRef{state.files.eso});
    2720              :                     }
    2721              : 
    2722              :                     //         Set possible missing values
    2723       101376 :                     if (ETHoriz < 0.0) {
    2724            0 :                         ETHoriz = 9999.0;
    2725              :                     }
    2726       101376 :                     if (ETDirect < 0.0) {
    2727            0 :                         ETDirect = 9999.0;
    2728              :                     }
    2729       101376 :                     if (IRHoriz <= 0.0) {
    2730            0 :                         IRHoriz = 9999.0;
    2731              :                     }
    2732       101376 :                     if (GLBHoriz < 0.0) {
    2733            0 :                         GLBHoriz = 9999.0;
    2734              :                     }
    2735       101376 :                     if (state.dataEnvrn->DisplayWeatherMissingDataWarnings) {
    2736            0 :                         if (DirectRad >= 9999.0) {
    2737            0 :                             ++state.dataWeather->wvarsMissedCounts.BeamSolarRad;
    2738              :                         }
    2739            0 :                         if (DiffuseRad >= 9999.0) {
    2740            0 :                             state.dataWeather->wvarsMissedCounts.DifSolarRad = state.dataWeather->wvarsMissedCounts.BeamSolarRad + 1;
    2741              :                         }
    2742            0 :                         if (DirectRad < 0.0) {
    2743            0 :                             DirectRad = 9999.0;
    2744            0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad;
    2745              :                         }
    2746            0 :                         if (DiffuseRad < 0.0) {
    2747            0 :                             DiffuseRad = 9999.0;
    2748            0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad;
    2749              :                         }
    2750              :                     }
    2751       101376 :                     if (GLBHorizIllum < 0.0) {
    2752            0 :                         GLBHorizIllum = 999999.0;
    2753              :                     }
    2754       101376 :                     if (DirectNrmIllum < 0.0) {
    2755            0 :                         DirectNrmIllum = 999999.0;
    2756              :                     }
    2757       101376 :                     if (DiffuseHorizIllum < 0.0) {
    2758            0 :                         DiffuseHorizIllum = 999999.0;
    2759              :                     }
    2760       101376 :                     if (ZenLum < 0.0) {
    2761            0 :                         ZenLum = 99999.0;
    2762              :                     }
    2763       101376 :                     if (AtmPress < 0.0) {
    2764            0 :                         AtmPress = 999999.0;
    2765              :                     }
    2766       101376 :                     if (WindSpeed < 0.0) {
    2767            0 :                         WindSpeed = 999.0;
    2768              :                     }
    2769       101376 :                     if (WindDir < -360.0 || WindDir > 360.0) {
    2770            0 :                         WindDir = 999.0;
    2771              :                     }
    2772       101376 :                     if (TotalSkyCover < 0.0) {
    2773            0 :                         TotalSkyCover = 99.0;
    2774              :                     }
    2775       101376 :                     if (RelHum < 0.0) {
    2776            0 :                         RelHum = 999.0;
    2777              :                     }
    2778       101376 :                     if (OpaqueSkyCover < 0.0) {
    2779            0 :                         OpaqueSkyCover = 99.0;
    2780              :                     }
    2781       101376 :                     if (Visibility < 0.0) {
    2782            0 :                         Visibility = 9999.0;
    2783              :                     }
    2784       101376 :                     if (CeilHeight < 0.0) {
    2785            0 :                         CeilHeight = 9999.0;
    2786              :                     }
    2787       101376 :                     if (PresWeathObs < 0) {
    2788            0 :                         PresWeathObs = 9;
    2789              :                     }
    2790       101376 :                     if (PrecipWater < 0.0) {
    2791            0 :                         PrecipWater = 999.0;
    2792              :                     }
    2793       101376 :                     if (AerosolOptDepth < 0.0) {
    2794            0 :                         AerosolOptDepth = 999.0;
    2795              :                     }
    2796       101376 :                     if (SnowDepth < 0.0) {
    2797            0 :                         SnowDepth = 999.0;
    2798              :                     }
    2799       101376 :                     if (DaysSinceLastSnow < 0.0) {
    2800            0 :                         DaysSinceLastSnow = 99.0;
    2801              :                     }
    2802       101376 :                     if (Albedo < 0.0) {
    2803            0 :                         Albedo = 999.0;
    2804              :                     }
    2805       101376 :                     if (LiquidPrecip < 0.0) {
    2806            0 :                         LiquidPrecip = 999.0;
    2807              :                     }
    2808              : 
    2809       101376 :                     if (hour == 1 && CurTimeStep == 1) {
    2810         4224 :                         if (WMonth == 2 && WDay == 29 && (!state.dataEnvrn->CurrentYearIsLeapYear || !state.dataWeather->WFAllowsLeapYears)) {
    2811            0 :                             state.dataWeather->EndDayOfMonth(2) = 28;
    2812            0 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = 28;
    2813            0 :                             SkipThisDay = true;
    2814            0 :                             TryAgain = true;
    2815            0 :                             ShowWarningError(state, "ReadEPlusWeatherForDay: Feb29 data encountered but will not be processed.");
    2816            0 :                             if (!state.dataWeather->WFAllowsLeapYears) {
    2817            0 :                                 ShowContinueError(
    2818              :                                     state, "...WeatherFile does not allow Leap Years. HOLIDAYS/DAYLIGHT SAVINGS header must indicate \"Yes\".");
    2819              :                             }
    2820            0 :                             continue;
    2821              :                         } else {
    2822         4224 :                             TryAgain = false;
    2823         4224 :                             SkipThisDay = false;
    2824              :                         }
    2825              : 
    2826         4224 :                         if (thisEnviron.ActualWeather && state.dataEnvrn->CurrentYearIsLeapYear) {
    2827            0 :                             if (WMonth == 3 && WDay == 1 && state.dataEnvrn->Month == 2 && state.dataEnvrn->DayOfMonth == 28) {
    2828            0 :                                 ShowFatalError(state, "ReadEPlusWeatherForDay: Current year is a leap year, but Feb29 data is missing.");
    2829              :                             }
    2830              :                         }
    2831              : 
    2832         4224 :                         state.dataWeather->TomorrowVariables.Year = WYear;
    2833         4224 :                         state.dataWeather->TomorrowVariables.Month = WMonth;
    2834         4224 :                         state.dataWeather->TomorrowVariables.DayOfMonth = WDay;
    2835         4224 :                         state.dataWeather->TomorrowVariables.DayOfYear = General::OrdinalDay(WMonth, WDay, state.dataWeather->LeapYearAdd);
    2836         4224 :                         state.dataWeather->TomorrowVariables.DayOfYear_Schedule = General::OrdinalDay(WMonth, WDay, 1);
    2837              :                         Real64 A;
    2838              :                         Real64 B;
    2839              :                         Real64 C;
    2840              :                         Real64 AVSC;
    2841         4224 :                         CalculateDailySolarCoeffs(state,
    2842         4224 :                                                   state.dataWeather->TomorrowVariables.DayOfYear,
    2843              :                                                   A,
    2844              :                                                   B,
    2845              :                                                   C,
    2846              :                                                   AVSC,
    2847         4224 :                                                   state.dataWeather->TomorrowVariables.EquationOfTime,
    2848         4224 :                                                   state.dataWeather->TomorrowVariables.SinSolarDeclinAngle,
    2849         4224 :                                                   state.dataWeather->TomorrowVariables.CosSolarDeclinAngle);
    2850         4224 :                         if (state.dataWeather->CurDayOfWeek <= 7) {
    2851         4124 :                             state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2852              :                         }
    2853         4224 :                         state.dataWeather->TomorrowVariables.DayOfWeek = state.dataWeather->CurDayOfWeek;
    2854         8448 :                         state.dataWeather->TomorrowVariables.DaylightSavingIndex =
    2855         4224 :                             state.dataWeather->DSTIndex(state.dataWeather->TomorrowVariables.DayOfYear);
    2856         4224 :                         state.dataWeather->TomorrowVariables.HolidayIndex =
    2857         4224 :                             state.dataWeather->SpecialDayTypes(state.dataWeather->TomorrowVariables.DayOfYear);
    2858              :                     }
    2859              : 
    2860       101376 :                     if (SkipThisDay) {
    2861            0 :                         continue;
    2862              :                     }
    2863              : 
    2864              :                     // Check out missing values
    2865              : 
    2866       101376 :                     if (DryBulb >= 99.9) {
    2867            0 :                         DryBulb = state.dataWeather->wvarsMissing.OutDryBulbTemp;
    2868            0 :                         ++state.dataWeather->wvarsMissedCounts.OutDryBulbTemp;
    2869              :                     }
    2870       101376 :                     if (DryBulb < -90.0 || DryBulb > 70.0) {
    2871            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp;
    2872              :                     }
    2873              : 
    2874       101376 :                     if (DewPoint >= 99.9) {
    2875            0 :                         DewPoint = state.dataWeather->wvarsMissing.OutDewPointTemp;
    2876            0 :                         ++state.dataWeather->wvarsMissedCounts.OutDewPointTemp;
    2877              :                     }
    2878       101376 :                     if (DewPoint < -90.0 || DewPoint > 70.0) {
    2879            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp;
    2880              :                     }
    2881              : 
    2882       101376 :                     if (RelHum >= 999.0) {
    2883            0 :                         RelHum = state.dataWeather->wvarsMissing.OutRelHum;
    2884            0 :                         ++state.dataWeather->wvarsMissedCounts.OutRelHum;
    2885              :                     }
    2886       101376 :                     if (RelHum < 0.0 || RelHum > 110.0) {
    2887            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutRelHum;
    2888              :                     }
    2889              : 
    2890       101376 :                     if (AtmPress >= 999999.0) {
    2891            0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2892            0 :                         ++state.dataWeather->wvarsMissedCounts.OutBaroPress;
    2893              :                     }
    2894       101376 :                     if (AtmPress <= 31000.0 || AtmPress > 120000.0) {
    2895            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress;
    2896            0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2897              :                     }
    2898              : 
    2899       101376 :                     if (WindDir >= 999.0) {
    2900            0 :                         WindDir = state.dataWeather->wvarsMissing.WindDir;
    2901            0 :                         ++state.dataWeather->wvarsMissedCounts.WindDir;
    2902              :                     }
    2903       101376 :                     if (WindDir < 0.0 || WindDir > 360.0) {
    2904            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindDir;
    2905              :                     }
    2906              : 
    2907       101376 :                     if (WindSpeed >= 999.0) {
    2908            0 :                         WindSpeed = state.dataWeather->wvarsMissing.WindSpeed;
    2909            0 :                         ++state.dataWeather->wvarsMissedCounts.WindSpeed;
    2910              :                     }
    2911       101376 :                     if (WindSpeed < 0.0 || WindSpeed > 40.0) {
    2912            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindSpeed;
    2913              :                     }
    2914              : 
    2915       101376 :                     if (TotalSkyCover >= 99.0) {
    2916            0 :                         TotalSkyCover = state.dataWeather->wvarsMissing.TotalSkyCover;
    2917            0 :                         ++state.dataWeather->wvarsMissedCounts.TotalSkyCover;
    2918              :                     }
    2919              : 
    2920       101376 :                     if (OpaqueSkyCover >= 99.0) {
    2921            0 :                         OpaqueSkyCover = state.dataWeather->wvarsMissing.OpaqueSkyCover;
    2922            0 :                         ++state.dataWeather->wvarsMissedCounts.OpaqueSkyCover;
    2923              :                     }
    2924              : 
    2925       101376 :                     if (SnowDepth >= 999.0) {
    2926           72 :                         SnowDepth = state.dataWeather->wvarsMissing.SnowDepth;
    2927           72 :                         ++state.dataWeather->wvarsMissedCounts.SnowDepth;
    2928              :                     }
    2929              : 
    2930       101376 :                     if (Albedo >= 999.0) {
    2931        73992 :                         Albedo = state.dataWeather->wvarsMissing.Albedo;
    2932        73992 :                         ++state.dataWeather->wvarsMissedCounts.Albedo;
    2933              :                     }
    2934              : 
    2935       101376 :                     if (LiquidPrecip >= 999.0) {
    2936        82566 :                         LiquidPrecip = state.dataWeather->wvarsMissing.LiquidPrecip;
    2937        82566 :                         ++state.dataWeather->wvarsMissedCounts.LiquidPrecip;
    2938              :                     }
    2939              : 
    2940       101376 :                     auto &tomorrow = state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour);
    2941       101376 :                     tomorrow.OutDryBulbTemp = DryBulb;
    2942       101376 :                     tomorrow.OutDewPointTemp = DewPoint;
    2943       101376 :                     tomorrow.OutBaroPress = AtmPress;
    2944       101376 :                     tomorrow.OutRelHum = RelHum;
    2945       101376 :                     RelHum *= 0.01;
    2946       101376 :                     tomorrow.WindSpeed = WindSpeed;
    2947       101376 :                     tomorrow.WindDir = WindDir;
    2948       101376 :                     tomorrow.LiquidPrecip = LiquidPrecip;
    2949       101376 :                     tomorrow.TotalSkyCover = TotalSkyCover;
    2950       101376 :                     tomorrow.OpaqueSkyCover = OpaqueSkyCover;
    2951              : 
    2952       101376 :                     calcSky(state, tomorrow.HorizIRSky, tomorrow.SkyTemp, OpaqueSkyCover, DryBulb, DewPoint, RelHum, IRHoriz);
    2953              : 
    2954       101376 :                     if (ETHoriz >= 9999.0) {
    2955            0 :                         ETHoriz = 0.0;
    2956              :                     }
    2957       101376 :                     if (ETDirect >= 9999.0) {
    2958           48 :                         ETDirect = 0.0;
    2959              :                     }
    2960       101376 :                     if (GLBHoriz >= 9999.0) {
    2961            0 :                         GLBHoriz = 0.0;
    2962              :                     }
    2963       101376 :                     if (DirectRad >= 9999.0) {
    2964            0 :                         DirectRad = 0.0;
    2965              :                     }
    2966       101376 :                     if (DiffuseRad >= 9999.0) {
    2967            0 :                         DiffuseRad = 0.0;
    2968              :                     }
    2969       101376 :                     if (GLBHorizIllum >= 999900.0) {
    2970           96 :                         GLBHorizIllum = 0.0;
    2971              :                     }
    2972       101376 :                     if (DirectNrmIllum >= 999900.0) {
    2973           96 :                         DirectNrmIllum = 0.0;
    2974              :                     }
    2975       101376 :                     if (DiffuseHorizIllum >= 999900.0) {
    2976           96 :                         DiffuseHorizIllum = 0.0;
    2977              :                     }
    2978       101376 :                     if (ZenLum >= 99990.0) {
    2979          142 :                         ZenLum = 0.0;
    2980              :                     }
    2981       101376 :                     if (state.dataEnvrn->IgnoreSolarRadiation) {
    2982            0 :                         GLBHoriz = 0.0;
    2983            0 :                         DirectRad = 0.0;
    2984            0 :                         DiffuseRad = 0.0;
    2985              :                     }
    2986       101376 :                     if (state.dataEnvrn->IgnoreBeamRadiation) {
    2987            0 :                         DirectRad = 0.0;
    2988              :                     }
    2989       101376 :                     if (state.dataEnvrn->IgnoreDiffuseRadiation) {
    2990            0 :                         DiffuseRad = 0.0;
    2991              :                     }
    2992              : 
    2993       101376 :                     tomorrow.BeamSolarRad = DirectRad;
    2994       101376 :                     tomorrow.DifSolarRad = DiffuseRad;
    2995              : 
    2996       101376 :                     tomorrow.IsRain = false;
    2997       101376 :                     if (PresWeathObs == 0) {
    2998          144 :                         if (PresWeathConds(1) < 9 || PresWeathConds(2) < 9 || PresWeathConds(3) < 9) {
    2999            0 :                             tomorrow.IsRain = true;
    3000              :                         }
    3001              :                     } else {
    3002       101232 :                         tomorrow.IsRain = false;
    3003              :                     }
    3004       101376 :                     tomorrow.IsSnow = (SnowDepth > 0.0);
    3005              : 
    3006              :                     // default if rain but none on weather file
    3007       101376 :                     if (tomorrow.IsRain && tomorrow.LiquidPrecip == 0.0) {
    3008            0 :                         tomorrow.LiquidPrecip = 2.0; // 2mm in an hour ~ .08 inch
    3009              :                     }
    3010              : 
    3011       101376 :                     state.dataWeather->wvarsMissing.OutDryBulbTemp = DryBulb;
    3012       101376 :                     state.dataWeather->wvarsMissing.OutDewPointTemp = DewPoint;
    3013       101376 :                     state.dataWeather->wvarsMissing.OutRelHum = static_cast<int>(std::round(RelHum * 100.0));
    3014       101376 :                     state.dataWeather->wvarsMissing.OutBaroPress = AtmPress;
    3015       101376 :                     state.dataWeather->wvarsMissing.WindDir = WindDir;
    3016       101376 :                     state.dataWeather->wvarsMissing.WindSpeed = WindSpeed;
    3017       101376 :                     state.dataWeather->wvarsMissing.TotalSkyCover = TotalSkyCover;
    3018       101376 :                     state.dataWeather->wvarsMissing.OpaqueSkyCover = OpaqueSkyCover;
    3019       101376 :                     state.dataWeather->wvarsMissing.Visibility = Visibility;
    3020       101376 :                     state.dataWeather->wvarsMissing.Ceiling = CeilHeight;
    3021       101376 :                     state.dataWeather->wvarsMissing.WaterPrecip = PrecipWater;
    3022       101376 :                     state.dataWeather->wvarsMissing.AerOptDepth = AerosolOptDepth;
    3023       101376 :                     state.dataWeather->wvarsMissing.SnowDepth = SnowDepth;
    3024       101376 :                     state.dataWeather->wvarsMissing.DaysLastSnow = DaysSinceLastSnow;
    3025       101376 :                     state.dataWeather->wvarsMissing.Albedo = Albedo;
    3026              : 
    3027       101376 :                 } // for (CurTimeStep)
    3028              : 
    3029              :             } // for (Hour)
    3030              : 
    3031              :         } // Try Again While Loop
    3032              : 
    3033         4224 :         if (BackSpaceAfterRead) {
    3034            0 :             state.files.inputWeatherFile.backspace();
    3035              :         }
    3036              : 
    3037         4224 :         if (state.dataWeather->NumIntervalsPerHour == 1 && state.dataGlobal->TimeStepsInHour > 1) {
    3038              :             // Create interpolated weather for timestep orientation
    3039              :             // First copy ts=1 (hourly) from data arrays to Wthr structure
    3040        87050 :             for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3041        83568 :                 wvarsHr(hour) = state.dataWeather->wvarsHrTsTomorrow(1, hour);
    3042              :             }
    3043              : 
    3044         3482 :             if (!state.dataWeather->LastHourSet) {
    3045              :                 // For first day of weather, all time steps of the first hour will be
    3046              :                 // equal to the first hour's value.
    3047              :                 // 2021-06: An additional input is added to here to allow the user to have chosen which hour to use
    3048         1219 :                 int HrUsedtoInterp = thisEnviron.firstHrInterpUseHr1 ? 1 : 24;
    3049         1219 :                 state.dataWeather->wvarsLastHr = wvarsHr(HrUsedtoInterp);
    3050         1219 :                 state.dataWeather->LastHourSet = true;
    3051              :             }
    3052              : 
    3053        87050 :             for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3054              : 
    3055        83568 :                 int NextHr = (hour == Constant::iHoursInDay) ? 1 : hour + 1;
    3056              : 
    3057        83568 :                 state.dataWeather->wvarsNextHr.BeamSolarRad = wvarsHr(NextHr).BeamSolarRad;
    3058        83568 :                 state.dataWeather->wvarsNextHr.DifSolarRad = wvarsHr(NextHr).DifSolarRad;
    3059        83568 :                 state.dataWeather->wvarsNextHr.LiquidPrecip = wvarsHr(NextHr).LiquidPrecip;
    3060              : 
    3061       500784 :                 for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    3062              : 
    3063       417216 :                     Real64 wgtCurrHr = state.dataWeather->Interpolation(ts);
    3064       417216 :                     Real64 wgtPrevHr = 1.0 - wgtCurrHr;
    3065              : 
    3066              :                     // Do Solar "weighting"
    3067              : 
    3068       417216 :                     Real64 wgtCurrHrSolar = state.dataWeather->SolarInterpolation(ts);
    3069              :                     Real64 wgtPrevHrSolar;
    3070              :                     Real64 wgtNextHrSolar;
    3071              : 
    3072       417216 :                     if (state.dataGlobal->TimeStepsInHour == 1) {
    3073            0 :                         wgtNextHrSolar = 1.0 - wgtCurrHr;
    3074            0 :                         wgtPrevHrSolar = 0.0;
    3075       417216 :                     } else if (wgtCurrHrSolar == 1.0) {
    3076              :                         //  It's at the half hour
    3077        83568 :                         wgtPrevHrSolar = 0.0;
    3078        83568 :                         wgtNextHrSolar = 0.0;
    3079       333648 :                     } else if (ts * state.dataWeather->TimeStepFraction < 0.5) {
    3080       125040 :                         wgtPrevHrSolar = 1.0 - wgtCurrHrSolar;
    3081       125040 :                         wgtNextHrSolar = 0.0;
    3082              :                     } else { // After the half hour
    3083       208608 :                         wgtPrevHrSolar = 0.0;
    3084       208608 :                         wgtNextHrSolar = 1.0 - wgtCurrHrSolar;
    3085              :                     }
    3086              : 
    3087       417216 :                     auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    3088       417216 :                     auto const &wvarsH = wvarsHr(hour);
    3089       417216 :                     tomorrowTs.OutDryBulbTemp = state.dataWeather->wvarsLastHr.OutDryBulbTemp * wgtPrevHr + wvarsH.OutDryBulbTemp * wgtCurrHr;
    3090       417216 :                     tomorrowTs.OutBaroPress = state.dataWeather->wvarsLastHr.OutBaroPress * wgtPrevHr + wvarsH.OutBaroPress * wgtCurrHr;
    3091       417216 :                     tomorrowTs.OutDewPointTemp = state.dataWeather->wvarsLastHr.OutDewPointTemp * wgtPrevHr + wvarsH.OutDewPointTemp * wgtCurrHr;
    3092       417216 :                     tomorrowTs.OutRelHum = state.dataWeather->wvarsLastHr.OutRelHum * wgtPrevHr + wvarsH.OutRelHum * wgtCurrHr;
    3093       417216 :                     tomorrowTs.WindSpeed = state.dataWeather->wvarsLastHr.WindSpeed * wgtPrevHr + wvarsH.WindSpeed * wgtCurrHr;
    3094       417216 :                     tomorrowTs.WindDir = interpolateWindDirection(state.dataWeather->wvarsLastHr.WindDir, wvarsH.WindDir, wgtCurrHr);
    3095       417216 :                     tomorrowTs.TotalSkyCover = state.dataWeather->wvarsLastHr.TotalSkyCover * wgtPrevHr + wvarsH.TotalSkyCover * wgtCurrHr;
    3096       417216 :                     tomorrowTs.OpaqueSkyCover = state.dataWeather->wvarsLastHr.OpaqueSkyCover * wgtPrevHr + wvarsH.OpaqueSkyCover * wgtCurrHr;
    3097              :                     // Sky emissivity now takes interpolated timestep inputs rather than interpolated calculation esky results
    3098       417216 :                     calcSky(state,
    3099       417216 :                             tomorrowTs.HorizIRSky,
    3100       417216 :                             tomorrowTs.SkyTemp,
    3101              :                             tomorrowTs.OpaqueSkyCover,
    3102              :                             tomorrowTs.OutDryBulbTemp,
    3103              :                             tomorrowTs.OutDewPointTemp,
    3104       417216 :                             tomorrowTs.OutRelHum * 0.01,
    3105       417216 :                             state.dataWeather->wvarsLastHr.HorizIRSky * wgtPrevHr + wvarsH.HorizIRSky * wgtCurrHr);
    3106              : 
    3107       417216 :                     tomorrowTs.DifSolarRad = state.dataWeather->wvarsLastHr.DifSolarRad * wgtPrevHrSolar + wvarsH.DifSolarRad * wgtCurrHrSolar +
    3108       417216 :                                              state.dataWeather->wvarsNextHr.DifSolarRad * wgtNextHrSolar;
    3109       417216 :                     tomorrowTs.BeamSolarRad = state.dataWeather->wvarsLastHr.BeamSolarRad * wgtPrevHrSolar + wvarsH.BeamSolarRad * wgtCurrHrSolar +
    3110       417216 :                                               state.dataWeather->wvarsNextHr.BeamSolarRad * wgtNextHrSolar;
    3111              : 
    3112       417216 :                     tomorrowTs.LiquidPrecip = state.dataWeather->wvarsLastHr.LiquidPrecip * wgtPrevHr + wvarsH.LiquidPrecip * wgtCurrHr;
    3113       417216 :                     tomorrowTs.LiquidPrecip /= double(state.dataGlobal->TimeStepsInHour);
    3114       417216 :                     tomorrowTs.IsRain = tomorrowTs.LiquidPrecip >= state.dataWeather->IsRainThreshold; // Wthr%IsRain
    3115       417216 :                     tomorrowTs.IsSnow = wvarsH.IsSnow;
    3116              :                 } // End of TS Loop
    3117              : 
    3118        83568 :                 state.dataWeather->wvarsLastHr = wvarsHr(hour);
    3119              :             } // End of Hour Loop
    3120              :         }
    3121              : 
    3122         4224 :         if (thisEnviron.WP_Type1 != 0) {
    3123            0 :             switch (state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).skyTempModel) {
    3124            0 :             case SkyTempModel::ScheduleValue: {
    3125              :                 std::vector<Real64> const &dayVals =
    3126            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    3127            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    3128              : 
    3129            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3130            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3131            0 :                         state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3132              :                     }
    3133              :                 }
    3134            0 :             } break;
    3135              : 
    3136            0 :             case SkyTempModel::DryBulbDelta: {
    3137              :                 std::vector<Real64> const &dayVals =
    3138            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    3139            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    3140              : 
    3141            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3142            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3143            0 :                         auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3144            0 :                         tomorrowTs.SkyTemp = tomorrowTs.OutDryBulbTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3145              :                     }
    3146              :                 }
    3147            0 :             } break;
    3148              : 
    3149            0 :             case SkyTempModel::DewPointDelta: {
    3150              :                 std::vector<Real64> const &dayVals =
    3151            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    3152            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    3153              : 
    3154            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3155            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3156            0 :                         auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3157            0 :                         tomorrowTs.SkyTemp = tomorrowTs.OutDewPointTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3158              :                     }
    3159              :                 }
    3160            0 :             } break;
    3161              : 
    3162            0 :             default:
    3163            0 :                 break;
    3164              :             }
    3165              :         }
    3166         4224 :     }
    3167              : 
    3168       417216 :     Real64 interpolateWindDirection(Real64 const prevHrWindDir, Real64 const curHrWindDir, Real64 const curHrWeight)
    3169              :     {
    3170              :         // adapted from http://stackoverflow.com/questions/2708476/rotation-interpolation
    3171       417216 :         Real64 curAng = curHrWindDir;
    3172       417216 :         Real64 prevAng = prevHrWindDir;
    3173       417216 :         Real64 diff = std::abs(curAng - prevAng);
    3174       417216 :         if (diff > 180.) {
    3175        33826 :             if (curAng > prevAng) {
    3176        14854 :                 prevAng += 360.;
    3177              :             } else {
    3178        18972 :                 curAng += 360.;
    3179              :             }
    3180              :         }
    3181       417216 :         Real64 interpAng = prevAng + (curAng - prevAng) * curHrWeight;
    3182       417216 :         return (fmod(interpAng, 360.)); // fmod is float modulus function
    3183              :     }
    3184              : 
    3185       784512 :     Real64 CalcSkyEmissivity(
    3186              :         EnergyPlusData &state, SkyTempModel const ESkyCalcType, Real64 const OSky, Real64 const DryBulb, Real64 const DewPoint, Real64 const RelHum)
    3187              :     {
    3188              :         // Calculate Sky Emissivity
    3189              :         // References:
    3190              :         // M. Li, Y. Jiang and C. F. M. Coimbra,
    3191              :         // "On the determination of atmospheric longwave irradiance under all-sky conditions,"
    3192              :         // Solar Energy 144, 2017, pp. 40–48,
    3193              :         // G. Clark and C. Allen, "The Estimation of Atmospheric Radiation for Clear and
    3194              :         // Cloudy Skies," Proc. 2nd National Passive Solar Conference (AS/ISES), 1978, pp. 675-678.
    3195              : 
    3196              :         Real64 ESky;
    3197              : 
    3198       784512 :         if (ESkyCalcType == SkyTempModel::Brunt) {
    3199            0 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3200            0 :             ESky = 0.618 + 0.056 * pow(PartialPress, 0.5);
    3201       784512 :         } else if (ESkyCalcType == SkyTempModel::Idso) {
    3202            0 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3203            0 :             ESky = 0.685 + 0.000032 * PartialPress * exp(1699 / (DryBulb + Constant::Kelvin));
    3204       784512 :         } else if (ESkyCalcType == SkyTempModel::BerdahlMartin) {
    3205            0 :             double const TDewC = min(DryBulb, DewPoint);
    3206            0 :             ESky = 0.758 + 0.521 * (TDewC / 100) + 0.625 * pow_2(TDewC / 100);
    3207              :         } else {
    3208       784512 :             ESky = 0.787 + 0.764 * std::log((min(DryBulb, DewPoint) + Constant::Kelvin) / Constant::Kelvin);
    3209              :         }
    3210       784512 :         return ESky * (1.0 + 0.0224 * OSky - 0.0035 * pow_2(OSky) + 0.00028 * pow_3(OSky));
    3211              :     }
    3212              : 
    3213         1233 :     void SetDayOfWeekInitialValues(int const EnvironDayOfWeek, // Starting Day of Week for the (Weather) RunPeriod (User Input)
    3214              :                                    int &currentDayOfWeek       // Current Day of Week
    3215              :     )
    3216              :     {
    3217              : 
    3218              :         // SUBROUTINE INFORMATION:
    3219              :         //       AUTHOR         Linda Lawrie
    3220              :         //       DATE WRITTEN   March 2012
    3221              : 
    3222              :         // PURPOSE OF THIS SUBROUTINE:
    3223              :         // Set of begin day of week for an environment.  Similar sets but slightly different
    3224              :         // conditions.  Improve code readability by having three routine calls instead of three
    3225              :         // IF blocks.
    3226              : 
    3227         1233 :         if (EnvironDayOfWeek != 0) {
    3228         1233 :             if (EnvironDayOfWeek <= 7) {
    3229         1211 :                 currentDayOfWeek = EnvironDayOfWeek - 1;
    3230              :             } else {
    3231           22 :                 currentDayOfWeek = EnvironDayOfWeek;
    3232              :             }
    3233              :         }
    3234         1233 :     }
    3235              : 
    3236            0 :     void ErrorInterpretWeatherDataLine(EnergyPlusData &state,
    3237              :                                        int const WYear,
    3238              :                                        int const WMonth,
    3239              :                                        int const WDay,
    3240              :                                        int const WHour,
    3241              :                                        int const WMinute,
    3242              :                                        std::string_view SaveLine,
    3243              :                                        std::string_view Line)
    3244              :     {
    3245            0 :         ShowSevereError(state, fmt::format("Invalid Weather Line at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3246            0 :         ShowContinueError(state, fmt::format("Full Data Line={}", SaveLine));
    3247            0 :         ShowContinueError(state, fmt::format("Remainder of line={}", Line));
    3248            0 :         ShowFatalError(state, "Error in Reading Weather Data");
    3249            0 :     }
    3250              : 
    3251       284127 :     void InterpretWeatherDataLine(EnergyPlusData &state,
    3252              :                                   std::string_view Line,
    3253              :                                   bool &ErrorFound, // True if an error is found, false otherwise
    3254              :                                   int &WYear,
    3255              :                                   int &WMonth,
    3256              :                                   int &WDay,
    3257              :                                   int &WHour,
    3258              :                                   int &WMinute,
    3259              :                                   Real64 &DryBulb,
    3260              :                                   Real64 &DewPoint,
    3261              :                                   Real64 &RelHum,
    3262              :                                   Real64 &AtmPress,
    3263              :                                   Real64 &ETHoriz,
    3264              :                                   Real64 &ETDirect,
    3265              :                                   Real64 &IRHoriz,
    3266              :                                   Real64 &GLBHoriz,
    3267              :                                   Real64 &DirectRad,
    3268              :                                   Real64 &DiffuseRad,
    3269              :                                   Real64 &GLBHorizIllum,
    3270              :                                   Real64 &DirectNrmIllum,
    3271              :                                   Real64 &DiffuseHorizIllum,
    3272              :                                   Real64 &ZenLum,
    3273              :                                   Real64 &WindDir,
    3274              :                                   Real64 &WindSpeed,
    3275              :                                   Real64 &TotalSkyCover,
    3276              :                                   Real64 &OpaqueSkyCover,
    3277              :                                   Real64 &Visibility,
    3278              :                                   Real64 &CeilHeight,
    3279              :                                   int &WObs,              // PresWeathObs
    3280              :                                   Array1D_int &WCodesArr, // PresWeathConds
    3281              :                                   Real64 &PrecipWater,
    3282              :                                   Real64 &AerosolOptDepth,
    3283              :                                   Real64 &SnowDepth,
    3284              :                                   Real64 &DaysSinceLastSnow,
    3285              :                                   Real64 &Albedo,
    3286              :                                   Real64 &LiquidPrecip)
    3287              :     {
    3288              : 
    3289              :         // SUBROUTINE INFORMATION:
    3290              :         //       AUTHOR         Linda Lawrie
    3291              :         //       DATE WRITTEN   April 2001
    3292              : 
    3293              :         // PURPOSE OF THIS SUBROUTINE:
    3294              :         // This subroutine interprets the EPW weather data line because comma delimited fields
    3295              :         // may cause problems with some compilers.  (Particularly character variables in
    3296              :         // comma delimited lines.
    3297              : 
    3298              :         // METHODOLOGY EMPLOYED:
    3299              :         // Field by field interpretation, eliminating the "data source field" which is also
    3300              :         // likely to contain blanks.  Note that the "Weatherconditions" must be a 9 character
    3301              :         // alpha field with no intervening blanks.
    3302              : 
    3303       284127 :         EP_SIZE_CHECK(WCodesArr, 9); // NOLINT(misc-static-assert)
    3304              : 
    3305              :         static constexpr std::string_view ValidDigits("0123456789");
    3306              : 
    3307       284127 :         std::string_view::size_type pos = 0;
    3308       284127 :         std::string_view current_line = Line;
    3309              : 
    3310       284127 :         ErrorFound = false;
    3311              : 
    3312              :         // Do the first five.  (To get to the DataSource field)
    3313              :         {
    3314       284127 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 5); // Returns the position **after** the nth occurrence of ','
    3315       284127 :             const bool succeeded = readList(current_line.substr(pos, (nth_pos - 1) - pos), WYear, WMonth, WDay, WHour, WMinute);
    3316       284127 :             if (!succeeded) {
    3317            0 :                 ShowSevereError(state, "Invalid Date info in Weather Line");
    3318            0 :                 ShowContinueError(state, fmt::format("Entire Data Line={}", Line));
    3319            0 :                 ShowFatalError(state, "Error in Reading Weather Data");
    3320              :             }
    3321              :         }
    3322              : 
    3323       284127 :         bool DateInError = false;
    3324       284127 :         if (WMonth >= 1 && WMonth <= 12) {
    3325              :             // Month number is valid
    3326       284127 :             if (WMonth != 2) {
    3327       257223 :                 if (WDay > state.dataWeather->EndDayOfMonth(WMonth)) {
    3328            0 :                     DateInError = true;
    3329              :                 }
    3330        26904 :             } else if (WDay > state.dataWeather->EndDayOfMonth(WMonth) + 1) { // Whether actually used is determined by calling routine.
    3331            0 :                 DateInError = true;
    3332              :             }
    3333              :         } else {
    3334            0 :             DateInError = true;
    3335              :         }
    3336              : 
    3337       284127 :         if (DateInError) {
    3338            0 :             ShowSevereError(state, format("Reading Weather Data Line, Invalid Date, Year={}, Month={}, Day={}", WYear, WMonth, WDay));
    3339            0 :             ShowFatalError(state, "Program terminates due to previous condition.");
    3340              :         }
    3341              : 
    3342              :         // index, unlike nth_occurrence returns the position of the search char, not the position after it
    3343       284127 :         pos = index(Line, ','); // WYear
    3344       284127 :         if (pos == std::string::npos) {
    3345            0 :             ShowSevereError(
    3346            0 :                 state, format("Invalid Weather Line (no commas) at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3347            0 :             ShowContinueError(state, fmt::format("Full Data Line={}", Line));
    3348            0 :             ShowFatalError(state, "Error in Reading Weather Data");
    3349              :         }
    3350       284127 :         current_line.remove_prefix(nth_occurrence(Line, ',', 6)); // remove WYear,WMonth,WDay,WHour,WMinute,Data Source/Integrity
    3351              : 
    3352              :         // Now read more numerics with List Directed I/O (note there is another "character" field lurking)
    3353              :         Real64 RField21;
    3354              :         {
    3355       284127 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 21);
    3356              : 
    3357       284127 :             const bool succeeded = readList(current_line.substr(0, nth_pos - 1),
    3358              :                                             DryBulb,
    3359              :                                             DewPoint,
    3360              :                                             RelHum,
    3361              :                                             AtmPress,
    3362              :                                             ETHoriz,
    3363              :                                             ETDirect,
    3364              :                                             IRHoriz,
    3365              :                                             GLBHoriz,
    3366              :                                             DirectRad,
    3367              :                                             DiffuseRad,
    3368              :                                             GLBHorizIllum,
    3369              :                                             DirectNrmIllum,
    3370              :                                             DiffuseHorizIllum,
    3371              :                                             ZenLum,
    3372              :                                             WindDir,
    3373              :                                             WindSpeed,
    3374              :                                             TotalSkyCover,
    3375              :                                             OpaqueSkyCover,
    3376              :                                             Visibility,
    3377              :                                             CeilHeight,
    3378              :                                             RField21);
    3379              : 
    3380       284127 :             if (!succeeded) {
    3381            0 :                 ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3382              :             }
    3383       284127 :             current_line.remove_prefix(nth_pos);
    3384              :         }
    3385       284127 :         pos = index(current_line, ',');
    3386       284127 :         std::string PresWeathCodes;
    3387       284127 :         if (pos != std::string::npos && pos != 0) {
    3388       284127 :             PresWeathCodes = current_line.substr(0, pos);
    3389              :         } else {
    3390            0 :             PresWeathCodes = "999999999";
    3391              :         }
    3392       284127 :         current_line.remove_prefix(pos + 1);
    3393              : 
    3394       284127 :         auto readNextNumber = // (AUTO_OK_LAMBDA)
    3395      1704762 :             [reachedEndOfCommands = false, &state, &WYear, &WMonth, &WDay, &WHour, &WMinute, &Line, &current_line]() mutable -> Real64 {
    3396      1704762 :             if (reachedEndOfCommands) {
    3397          100 :                 return 999.0;
    3398              :             }
    3399              :             Real64 target;
    3400      1704662 :             std::string_view::size_type pos = index(current_line, ',');
    3401              :             // We found a comma
    3402      1704662 :             if (pos != std::string::npos) {
    3403              :                 // Content is not empty
    3404      1704637 :                 if (pos != 0) {
    3405      1704637 :                     bool error = false;
    3406      1704637 :                     target = Util::ProcessNumber(current_line.substr(0, pos), error);
    3407      1704637 :                     if (error) {
    3408            0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3409              :                     }
    3410              :                 } else {
    3411            0 :                     target = 999.0;
    3412              :                 }
    3413      1704637 :                 current_line.remove_prefix(pos + 1);
    3414              :             } else {
    3415              :                 // Couldn't find next comma, but we need to process the potential current number
    3416           25 :                 reachedEndOfCommands = true;
    3417           25 :                 if (current_line.empty()) {
    3418            0 :                     target = 999.0;
    3419              :                 } else {
    3420           25 :                     bool error = false;
    3421           25 :                     target = Util::ProcessNumber(current_line, error);
    3422           25 :                     if (error) {
    3423            0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3424              :                     }
    3425              :                 }
    3426              :             }
    3427      1704662 :             return target;
    3428       284127 :         };
    3429              : 
    3430       284127 :         PrecipWater = readNextNumber();
    3431       284127 :         AerosolOptDepth = readNextNumber();
    3432       284127 :         SnowDepth = readNextNumber();
    3433       284127 :         DaysSinceLastSnow = readNextNumber();
    3434       284127 :         Albedo = readNextNumber();
    3435       284127 :         LiquidPrecip = readNextNumber();
    3436              : 
    3437       284127 :         WObs = nint(RField21);
    3438       284127 :         if (WObs == 0) { // Obs Indicator indicates Weather Codes valid
    3439              :             // Check for miscellaneous characters
    3440          350 :             pos = index(PresWeathCodes, '\'');
    3441          350 :             while (pos != std::string::npos) {
    3442            0 :                 PresWeathCodes[pos] = ' ';
    3443            0 :                 pos = index(PresWeathCodes, '\'');
    3444              :             }
    3445          350 :             pos = index(PresWeathCodes, '"');
    3446          350 :             while (pos != std::string::npos) {
    3447            0 :                 PresWeathCodes[pos] = ' ';
    3448            0 :                 pos = index(PresWeathCodes, '"');
    3449              :             }
    3450          350 :             strip(PresWeathCodes);
    3451          350 :             if (len(PresWeathCodes) == 9) {
    3452         3500 :                 for (pos = 0; pos < 9; ++pos) {
    3453         3150 :                     if (!has(ValidDigits, PresWeathCodes[pos])) {
    3454            0 :                         PresWeathCodes[pos] = '9';
    3455              :                     }
    3456              :                 }
    3457              : 
    3458              :                 // we are trying to read a string of 9 integers with no spaces, each
    3459              :                 // into its own integer, like:
    3460              :                 // "123456789"
    3461              :                 // becomes
    3462              :                 // std::vector<int>{1,2,3,4,5,6,7,8,9};
    3463          350 :                 std::stringstream reader = stringReader(PresWeathCodes);
    3464         3500 :                 for (auto &value : WCodesArr) {
    3465         3150 :                     char c[2] = {0, 0};   // a string of 2 characters, init both to 0
    3466         3150 :                     reader >> c[0];       // read next char into the first byte
    3467         3150 :                     value = std::atoi(c); // convert this short string into the appropriate int to read
    3468              :                 }
    3469          350 :             } else {
    3470            0 :                 ++state.dataWeather->wvarsMissedCounts.WeathCodes;
    3471            0 :                 WCodesArr = 9;
    3472              :             }
    3473              :         } else {
    3474       283777 :             WCodesArr = 9;
    3475              :         }
    3476       284127 :     }
    3477              : 
    3478         5985 :     void SetUpDesignDay(EnergyPlusData &state, int const EnvrnNum) // Environment number passed into the routine
    3479              :     {
    3480              : 
    3481              :         // SUBROUTINE INFORMATION:
    3482              :         //       AUTHOR         Linda Lawrie
    3483              :         //       DATE WRITTEN   February 1977
    3484              :         //       MODIFIED       June 1997 (RKS); May 2013 (LKL) add temperature profile for drybulb.
    3485              :         //       RE-ENGINEERED  August 2003;LKL -- to generate timestep weather for design days.
    3486              : 
    3487              :         // PURPOSE OF THIS SUBROUTINE:
    3488              :         // This purpose of this subroutine is to convert the user supplied input
    3489              :         // values for the design day parameters into an entire weather day
    3490              :         // record.  This now bypasses any file I/O by keeping all of the
    3491              :         // weather day record information in the local module level derived type
    3492              :         // called DesignDay.
    3493              : 
    3494         5985 :         constexpr Real64 GlobalSolarConstant = 1367.0;
    3495         5985 :         constexpr Real64 ZHGlobalSolarConstant = 1355.0;
    3496              : 
    3497         5985 :         Real64 constexpr ZhangHuang_C0 = 0.5598;   // 37.6865d0
    3498         5985 :         Real64 constexpr ZhangHuang_C1 = 0.4982;   // 13.9263d0
    3499         5985 :         Real64 constexpr ZhangHuang_C2 = -0.6762;  // -20.2354d0
    3500         5985 :         Real64 constexpr ZhangHuang_C3 = 0.02842;  // 0.9695d0
    3501         5985 :         Real64 constexpr ZhangHuang_C4 = -0.00317; // -0.2046d0
    3502         5985 :         Real64 constexpr ZhangHuang_C5 = 0.014;    // -0.0980d0
    3503         5985 :         Real64 constexpr ZhangHuang_D = -17.853;   // -10.8568d0
    3504         5985 :         Real64 constexpr ZhangHuang_K = 0.843;     // 49.3112d0
    3505              :         static constexpr std::string_view RoutineNamePsyWFnTdbTwbPb("SetUpDesignDay:PsyWFnTdbTwbPb");
    3506              :         static constexpr std::string_view RoutineNamePsyWFnTdpPb("SetUpDesignDay:PsyWFnTdpPb");
    3507              :         static constexpr std::string_view RoutineNamePsyWFnTdbH("SetUpDesignDay:PsyWFnTdbH");
    3508              :         static constexpr std::string_view WeatherManager("WeatherManager");
    3509              :         static constexpr std::string_view RoutineNameLong("WeatherManager.cc subroutine SetUpDesignDay");
    3510              : 
    3511         5985 :         std::string StringOut;
    3512              :         //     For reporting purposes, set year to current system year
    3513              : 
    3514              :         struct HourlyWeatherData
    3515              :         {
    3516              :             // Members
    3517              :             Array1D<Real64> BeamSolarRad = Array1D<Real64>(Constant::iHoursInDay, 0.0); // Hourly direct normal solar irradiance
    3518              :             Array1D<Real64> DifSolarRad = Array1D<Real64>(Constant::iHoursInDay, 0.0);  // Hourly sky diffuse horizontal solar irradiance
    3519              :         };
    3520              : 
    3521              :         // Object Data
    3522         5985 :         HourlyWeatherData Wthr;
    3523              : 
    3524         5985 :         auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    3525              : 
    3526         5985 :         bool SaveWarmupFlag = state.dataGlobal->WarmupFlag;
    3527         5985 :         state.dataGlobal->WarmupFlag = true;
    3528              : 
    3529         5985 :         Array1D_int Date0(8);
    3530         5985 :         date_and_time(_, _, _, Date0);
    3531         5985 :         int CurrentYear = Date0(1);
    3532              : 
    3533         5985 :         if (state.dataGlobal->BeginSimFlag) {
    3534          801 :             state.dataWeather->PrintDDHeader = true;
    3535              :         }
    3536              : 
    3537         5985 :         auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    3538         5985 :         auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    3539         5985 :         designDay.Year = CurrentYear; // f90 date_and_time implemented. full 4 digit year !+ 1900
    3540         5985 :         designDay.Month = desDayInput.Month;
    3541         5985 :         designDay.DayOfMonth = desDayInput.DayOfMonth;
    3542         5985 :         designDay.DayOfYear = General::OrdinalDay(designDay.Month, designDay.DayOfMonth, 0);
    3543              :         static constexpr std::string_view MnDyFmt("{:02}/{:02}");
    3544         5985 :         state.dataEnvrn->CurMnDy = format(MnDyFmt, desDayInput.Month, desDayInput.DayOfMonth);
    3545              :         // EnvironmentName = DesDayInput( EnvrnNum ).Title;
    3546         5985 :         state.dataEnvrn->RunPeriodEnvironment = false;
    3547              :         // Following builds Environment start/end for ASHRAE 55 warnings
    3548         5985 :         state.dataEnvrn->EnvironmentStartEnd = state.dataEnvrn->CurMnDy + " - " + state.dataEnvrn->CurMnDy;
    3549              : 
    3550              :         // Check that barometric pressure is within range
    3551         5985 :         if (desDayInput.PressureEntered) {
    3552         5961 :             if (std::abs((desDayInput.PressBarom - state.dataEnvrn->StdBaroPress) / state.dataEnvrn->StdBaroPress) > 0.1) { // 10% off
    3553          108 :                 ShowWarningError(state,
    3554          108 :                                  format("SetUpDesignDay: Entered DesignDay Barometric Pressure={:.0R} differs by more than 10% from Standard "
    3555              :                                         "Barometric Pressure={:.0R}.",
    3556           54 :                                         desDayInput.PressBarom,
    3557           54 :                                         state.dataEnvrn->StdBaroPress));
    3558          108 :                 ShowContinueError(
    3559              :                     state,
    3560          108 :                     format("...occurs in DesignDay={}, Standard Pressure (based on elevation) will be used.", state.dataEnvrn->EnvironmentName));
    3561           54 :                 desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3562              :             }
    3563              :         } else {
    3564           24 :             desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3565              :         }
    3566              : 
    3567              :         // verify that design WB or DP <= design DB
    3568         5985 :         if (desDayInput.HumIndType == DesDayHumIndType::DewPoint && desDayInput.DewPointNeedsSet) {
    3569              :             // dew-point
    3570            0 :             Real64 testval = Psychrometrics::PsyWFnTdbRhPb(state, desDayInput.MaxDryBulb, 1.0, desDayInput.PressBarom);
    3571            0 :             desDayInput.HumIndValue = Psychrometrics::PsyTdpFnWPb(state, testval, desDayInput.PressBarom);
    3572              :         }
    3573              : 
    3574              :         // Day of week defaults to Monday, if day type specified, then that is used.
    3575         5985 :         designDay.DayOfWeek = 2;
    3576         5985 :         if (desDayInput.DayType <= 7) {
    3577           52 :             designDay.DayOfWeek = desDayInput.DayType;
    3578              :         }
    3579              : 
    3580              :         // set Holiday as indicated by user input
    3581         5985 :         designDay.HolidayIndex = 0;
    3582         5985 :         if (desDayInput.DayType > 7) {
    3583         5933 :             designDay.HolidayIndex = desDayInput.DayType;
    3584              :         }
    3585              : 
    3586         5985 :         designDay.DaylightSavingIndex = desDayInput.DSTIndicator;
    3587              : 
    3588              :         //  Set up Solar parameters for day
    3589              :         Real64 A;    // Apparent solar irradiation at air mass = 0
    3590              :         Real64 B;    // Atmospheric extinction coefficient
    3591              :         Real64 C;    // ASHRAE diffuse radiation factor
    3592              :         Real64 AVSC; // Annual variation in the solar constant
    3593         5985 :         CalculateDailySolarCoeffs(
    3594         5985 :             state, designDay.DayOfYear, A, B, C, AVSC, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle);
    3595              : 
    3596         5985 :         if (state.dataWeather->PrintDDHeader && state.dataReportFlag->DoWeatherInitReporting) {
    3597              :             static constexpr std::string_view EnvDDHdFormat(
    3598              :                 "! <Environment:Design Day Data>, Max Dry-Bulb Temp {C}, Temp Range {dC}, Temp Range Ind Type, "
    3599              :                 "Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units, Pressure {Pa}, Wind Direction {deg CW from N}, Wind "
    3600              :                 "Speed {m/s}, Clearness, Rain, Snow");
    3601          793 :             print(state.files.eio, "{}\n", EnvDDHdFormat);
    3602              :             static constexpr std::string_view DDayMiscHdFormat(
    3603              :                 "! <Environment:Design Day Misc>,DayOfYear,ASHRAE A Coeff,ASHRAE B Coeff,ASHRAE C Coeff,Solar "
    3604              :                 "Constant-Annual Variation,Eq of Time {minutes}, Solar Declination Angle {deg}, Solar Model");
    3605          793 :             print(state.files.eio, "{}\n", DDayMiscHdFormat);
    3606          793 :             state.dataWeather->PrintDDHeader = false;
    3607              :         }
    3608         5985 :         if (state.dataReportFlag->DoWeatherInitReporting) {
    3609         1775 :             std::string_view const AlpUseRain = (desDayInput.RainInd == 1) ? "Yes" : "No";
    3610         1775 :             std::string_view const AlpUseSnow = (desDayInput.SnowInd == 1) ? "Yes" : "No";
    3611         1775 :             print(state.files.eio, "Environment:Design Day Data,");
    3612         1775 :             print(state.files.eio, "{:.2R},", desDayInput.MaxDryBulb);
    3613         1775 :             print(state.files.eio, "{:.2R},", desDayInput.DailyDBRange);
    3614              : 
    3615              :             static constexpr std::array<std::string_view, (int)DesDayDryBulbRangeType::Num> DesDayDryBulbRangeTypeStrings = {
    3616              :                 "DefaultMultipliers,", "MultiplierSchedule,", "DifferenceSchedule,", "TemperatureProfile,"};
    3617              : 
    3618         1775 :             print(state.files.eio, "{}", DesDayDryBulbRangeTypeStrings[(int)desDayInput.dryBulbRangeType]);
    3619              : 
    3620              :             static constexpr std::array<std::string_view, (int)DesDayHumIndType::Num> DesDayHumIndTypeStrings = {
    3621              :                 "Wetbulb,{:.2R},{{C}},",
    3622              :                 "Dewpoint,{:.2R},{{C}},",
    3623              :                 "Enthalpy,{:.2R},{{J/kgDryAir}},",
    3624              :                 "HumidityRatio,{:.4R},{{kgWater/kgDryAir}},",
    3625              :                 "Schedule,<schedule values from 0.0 to 100.0>,{{percent}},",
    3626              :                 "WetBulbProfileDefaultMultipliers,{:.2R},{{C}},",
    3627              :                 "WetBulbProfileDifferenceSchedule,{:.2R},{{C}},",
    3628              :                 "WetBulbProfileMultiplierSchedule,{:.2R},{{C}},"};
    3629              : 
    3630              :             // Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units
    3631         1775 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    3632            3 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType]);
    3633         1772 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    3634           12 :                 print(state.files.eio,
    3635           12 :                       DesDayHumIndTypeStrings[(int)desDayInput.HumIndType],
    3636           12 :                       state.dataWeather->DesDayInput(state.dataWeather->Envrn).HumIndValue);
    3637              :             } else {
    3638         1760 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType], desDayInput.HumIndValue);
    3639              :             }
    3640              : 
    3641         1775 :             print(state.files.eio, "{:.0R},", desDayInput.PressBarom);
    3642         1775 :             print(state.files.eio, "{:.0R},", desDayInput.WindDir);
    3643         1775 :             print(state.files.eio, "{:.1R},", desDayInput.WindSpeed);
    3644         1775 :             print(state.files.eio, "{:.2R},", desDayInput.SkyClear);
    3645              : 
    3646         1775 :             print(state.files.eio, "{},{}\n", AlpUseRain, AlpUseSnow);
    3647              : 
    3648              :             static constexpr std::string_view DDayMiscFormat("Environment:Design Day Misc,{:3},");
    3649         1775 :             print(state.files.eio, DDayMiscFormat, designDay.DayOfYear);
    3650         1775 :             print(state.files.eio, "{:.1R},", A);
    3651         1775 :             print(state.files.eio, "{:.4R},", B);
    3652         1775 :             print(state.files.eio, "{:.4R},", C);
    3653         1775 :             print(state.files.eio, "{:.1R},", AVSC);
    3654         1775 :             print(state.files.eio, "{:.2R},", designDay.EquationOfTime * 60.0);
    3655         1775 :             print(state.files.eio, "{:.1R},", std::asin(designDay.SinSolarDeclinAngle) / Constant::DegToRad);
    3656              : 
    3657              :             // Why have a different string for "Schedule" here than the one used for input? Really, why?
    3658              :             static constexpr std::array<std::string_view, (int)DesDaySolarModel::Num> DesDaySolarModelStrings = {
    3659              :                 "ASHRAEClearSky", "ZhangHuang", "User supplied beam/diffuse from schedules", "ASHRAETau", "ASHRAETau2017"};
    3660              : 
    3661         1775 :             print(state.files.eio, "{}\n", DesDaySolarModelStrings[(int)desDayInput.solarModel]);
    3662              :         }
    3663              : 
    3664              :         // Must set up weather values for Design Day.  User can specify the "humidity indicator" as
    3665              :         // Wetbulb, DewPoint or input the relative humidity schedule.  For both wetbulb and dewpoint indicators, the
    3666              :         // humidity for the day will be constant, using the drybulb (max) and humidity indicator temperature to
    3667              :         // set the values.  For the scheduled values, these are already set in the DDxxx array.
    3668              : 
    3669         5985 :         state.dataGlobal->CurrentTime = 25.0;
    3670              :         Real64 HumidityRatio; // Humidity Ratio -- when constant for day
    3671              :         bool ConstantHumidityRatio;
    3672              : 
    3673         5985 :         switch (desDayInput.HumIndType) {
    3674         5909 :         case DesDayHumIndType::WetBulb: {
    3675         5909 :             HumidityRatio = Psychrometrics::PsyWFnTdbTwbPb(
    3676              :                 state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdbTwbPb);
    3677         5909 :             ConstantHumidityRatio = true;
    3678         5909 :         } break;
    3679           25 :         case DesDayHumIndType::DewPoint: {
    3680           25 :             HumidityRatio = Psychrometrics::PsyWFnTdpPb(state, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdpPb);
    3681           25 :             ConstantHumidityRatio = true;
    3682           25 :         } break;
    3683            0 :         case DesDayHumIndType::HumRatio: {
    3684            0 :             HumidityRatio = desDayInput.HumIndValue;
    3685            0 :             ConstantHumidityRatio = true;
    3686            0 :         } break;
    3687           15 :         case DesDayHumIndType::Enthalpy: {
    3688              :             // HumIndValue is already in J/kg, so no conversions needed
    3689           15 :             HumidityRatio = Psychrometrics::PsyWFnTdbH(state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, RoutineNamePsyWFnTdbH);
    3690           15 :             ConstantHumidityRatio = true;
    3691           15 :         } break;
    3692            6 :         case DesDayHumIndType::RelHumSch: {
    3693              :             // nothing to do -- DDHumIndModifier already contains the scheduled Relative Humidity
    3694            6 :             ConstantHumidityRatio = false;
    3695          150 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3696          720 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3697          576 :                     state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).OutRelHum =
    3698          576 :                         state.dataWeather->desDayMods(EnvrnNum)(ts + 1, hr + 1).OutRelHum;
    3699              :                 }
    3700              :             }
    3701            6 :         } break;
    3702           30 :         case DesDayHumIndType::WBProfDef:
    3703              :         case DesDayHumIndType::WBProfDif:
    3704              :         case DesDayHumIndType::WBProfMul: {
    3705           30 :             ConstantHumidityRatio = false;
    3706           30 :         } break;
    3707            0 :         default: {
    3708            0 :             ShowSevereError(state, "SetUpDesignDay: Invalid Humidity Indicator type");
    3709            0 :             ShowContinueError(state, format("Occurred in Design Day={}", desDayInput.Title));
    3710            0 :         } break;
    3711              :         } // switch
    3712              : 
    3713              :         int OSky; // Opaque Sky Cover (tenths)
    3714         5985 :         if (desDayInput.RainInd != 0) {
    3715            0 :             OSky = 10;
    3716            0 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3717            0 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3718            0 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3719            0 :                     wvars.IsRain = true;
    3720            0 :                     wvars.LiquidPrecip = 3.0;
    3721              :                 }
    3722              :             }
    3723              :         } else {
    3724         5985 :             OSky = 0;
    3725       149625 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3726       928152 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3727       784512 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3728       784512 :                     wvars.IsRain = false;
    3729       784512 :                     wvars.LiquidPrecip = 0.0;
    3730              :                 }
    3731              :             }
    3732              :         }
    3733              : 
    3734              :         Real64 GndReflet; // Ground Reflectivity
    3735         5985 :         if (desDayInput.SnowInd == 0) {
    3736         5985 :             GndReflet = 0.2;
    3737       149625 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3738       928152 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3739       784512 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3740       784512 :                     wvars.IsSnow = false;
    3741              :                 }
    3742              :             }
    3743              :         } else { // Snow
    3744            0 :             GndReflet = 0.7;
    3745            0 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3746            0 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3747            0 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3748            0 :                     wvars.IsSnow = true;
    3749              :                 }
    3750              :             }
    3751              :         }
    3752              : 
    3753              :         // Some values are constant
    3754              : 
    3755       149625 :         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3756       928152 :             for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3757       784512 :                 auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3758       784512 :                 wvars.OutBaroPress = desDayInput.PressBarom;
    3759       784512 :                 wvars.WindSpeed = desDayInput.WindSpeed;
    3760       784512 :                 wvars.WindDir = desDayInput.WindDir;
    3761       784512 :                 wvars.Albedo = 0.0;
    3762              :             }
    3763              :         }
    3764              : 
    3765              :         // resolve daily ranges
    3766              :         Real64 DBRange; // working copy of dry-bulb daily range, C (or 1 if input is difference)
    3767         5985 :         if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    3768            4 :             DBRange = 1.0; // use unscaled multiplier values if difference
    3769         5981 :         } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    3770            2 :             DBRange = 0.0;
    3771              :         } else {
    3772         5979 :             DBRange = desDayInput.DailyDBRange;
    3773              :         }
    3774              :         Real64 WBRange; // working copy of wet-bulb daily range. C (or 1 if input is difference)
    3775         5985 :         if (desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    3776            2 :             WBRange = 1.0; // use unscaled multiplier values if difference
    3777              :         } else {
    3778         5983 :             WBRange = desDayInput.DailyWBRange;
    3779              :         }
    3780              : 
    3781         5985 :         auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3782       149625 :         for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3783       928152 :             for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    3784       784512 :                 auto const &desDayModsTS = desDayModsEnvrn(ts, hour);
    3785       784512 :                 auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    3786       784512 :                 if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    3787              :                     // dry-bulb profile
    3788       784320 :                     tomorrowTs.OutDryBulbTemp = desDayInput.MaxDryBulb - desDayModsTS.OutDryBulbTemp * DBRange;
    3789              :                 } else { // DesDayInput(EnvrnNum)%DBTempRangeType == DesDayDryBulbRangeType::Profile
    3790          192 :                     tomorrowTs.OutDryBulbTemp = desDayModsTS.OutDryBulbTemp;
    3791              :                 }
    3792              : 
    3793              :                 // wet-bulb - generate from profile, humidity ratio, or dew point
    3794       784512 :                 if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    3795       782016 :                     desDayInput.HumIndType == DesDayHumIndType::WBProfMul) {
    3796         2880 :                     Real64 WetBulb = desDayInput.HumIndValue - desDayModsTS.OutRelHum * WBRange;
    3797         2880 :                     WetBulb = min(WetBulb, tomorrowTs.OutDryBulbTemp); // WB must be <= DB
    3798         2880 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3799         2880 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3800         2880 :                     tomorrowTs.OutRelHum =
    3801         2880 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3802       784512 :                 } else if (ConstantHumidityRatio) {
    3803              :                     //  Need Dew Point Temperature.  Use Relative Humidity to get Humidity Ratio, unless Humidity Ratio is constant
    3804              :                     // BG 9-26-07  moved following inside this IF statment; when HumIndType is 'Schedule' HumidityRatio wasn't being initialized
    3805              :                     Real64 WetBulb =
    3806       781056 :                         Psychrometrics::PsyTwbFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, RoutineNameLong);
    3807              : 
    3808       781056 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdpPb(state, tomorrowTs.OutDryBulbTemp, desDayInput.PressBarom);
    3809       781056 :                     if (HumidityRatio > OutHumRat) {
    3810       276042 :                         WetBulb = tomorrowTs.OutDryBulbTemp;
    3811              :                     } else {
    3812       505014 :                         OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3813              :                     }
    3814       781056 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3815       781056 :                     tomorrowTs.OutRelHum =
    3816       781056 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3817              :                 } else {
    3818              :                     HumidityRatio =
    3819          576 :                         Psychrometrics::PsyWFnTdbRhPb(state, tomorrowTs.OutDryBulbTemp, desDayModsTS.OutRelHum / 100.0, desDayInput.PressBarom);
    3820          576 :                     tomorrowTs.OutRelHum =
    3821          576 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, WeatherManager) *
    3822              :                         100.0;
    3823              :                     // TomorrowOutRelHum values set earlier
    3824          576 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, HumidityRatio, desDayInput.PressBarom);
    3825              :                 }
    3826              : 
    3827       784512 :                 double DryBulb = tomorrowTs.OutDryBulbTemp;
    3828       784512 :                 double RelHum = tomorrowTs.OutRelHum * 0.01;
    3829              :                 Real64 ESky =
    3830       784512 :                     CalcSkyEmissivity(state, envCurr.skyTempModel, OSky, DryBulb, tomorrowTs.OutDewPointTemp, RelHum); // Emissivitity of Sky
    3831       784512 :                 tomorrowTs.HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    3832              : 
    3833       784512 :                 if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    3834       784512 :                     envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    3835              :                     // Design day not scheduled
    3836       784320 :                     tomorrowTs.SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    3837              :                 }
    3838              :                 // Generate solar values for timestep
    3839              :                 //    working results = BeamRad and DiffRad
    3840              :                 //    stored to program globals at end of loop
    3841              :                 Real64 BeamRad;
    3842              :                 Real64 DiffRad;
    3843       784512 :                 if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    3844              :                     // scheduled: set value unconditionally (whether sun up or not)
    3845          576 :                     BeamRad = desDayModsTS.BeamSolarRad;
    3846          576 :                     DiffRad = desDayModsTS.DifSolarRad;
    3847              :                 } else {
    3848              : 
    3849              :                     // calc time = fractional hour of day
    3850              :                     Real64 CurTime;
    3851       783936 :                     if (state.dataGlobal->TimeStepsInHour != 1) {
    3852       782400 :                         CurTime = double(hour - 1) + double(ts) * state.dataWeather->TimeStepFraction;
    3853              :                     } else {
    3854         1536 :                         CurTime = double(hour) + state.dataEnvrn->TS1TimeOffset;
    3855              :                     }
    3856              : 
    3857       783936 :                     Vector3<Real64> SUNCOS; // Sun direction cosines
    3858       783936 :                     CalculateSunDirectionCosines(
    3859              :                         state, CurTime, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle, SUNCOS);
    3860       783936 :                     Real64 CosZenith = SUNCOS.z; // Cosine of Zenith Angle of Sun
    3861       783936 :                     if (CosZenith < DataEnvironment::SunIsUpValue) {
    3862       389060 :                         BeamRad = 0.0;
    3863       389060 :                         DiffRad = 0.0;
    3864              :                     } else {
    3865       394876 :                         Real64 SinSolarAltitude = SUNCOS.z;
    3866              : 
    3867       394876 :                         switch (desDayInput.solarModel) {
    3868       374410 :                         case DesDaySolarModel::ASHRAE_ClearSky: {
    3869       374410 :                             Real64 Exponent = B / CosZenith;
    3870              :                             Real64 TotHoriz; // Total Radiation on Horizontal Surface
    3871       374410 :                             if (Exponent > 700.0) {
    3872           12 :                                 TotHoriz = 0.0;
    3873              :                             } else {
    3874       374398 :                                 TotHoriz = desDayInput.SkyClear * A * (C + CosZenith) * std::exp(-B / CosZenith);
    3875              :                             }
    3876              :                             // Radiation on an extraterrestial horizontal surface
    3877       374410 :                             Real64 HO = GlobalSolarConstant * AVSC * CosZenith;
    3878       374410 :                             Real64 KT = TotHoriz / HO; // Radiation ratio
    3879       374410 :                             KT = min(KT, 0.75);
    3880       374410 :                             DiffRad = TotHoriz * (1.0045 + KT * (0.04349 + KT * (-3.5227 + 2.6313 * KT)));
    3881       374410 :                             if (desDayInput.SkyClear > 0.70) {
    3882       224656 :                                 DiffRad = TotHoriz * C / (C + CosZenith);
    3883              :                             }
    3884       374410 :                             BeamRad = (TotHoriz - DiffRad) / CosZenith;
    3885       374410 :                             DiffRad = max(0.0, DiffRad);
    3886       374410 :                             BeamRad = max(0.0, BeamRad);
    3887              : 
    3888       374410 :                         } break;
    3889        20276 :                         case DesDaySolarModel::ASHRAE_Tau:
    3890              :                         case DesDaySolarModel::ASHRAE_Tau2017: {
    3891        20276 :                             Real64 ETR = GlobalSolarConstant * AVSC; // radiation of an extraterrestrial normal surface, W/m2
    3892              :                             Real64 GloHorzRad;
    3893        20276 :                             ASHRAETauModel(
    3894              :                                 state, desDayInput.solarModel, ETR, CosZenith, desDayInput.TauB, desDayInput.TauD, BeamRad, DiffRad, GloHorzRad);
    3895        20276 :                         } break;
    3896          190 :                         case DesDaySolarModel::Zhang_Huang: {
    3897          190 :                             int Hour3Ago = mod(hour + 20, 24) + 1; // hour 3 hours before
    3898          190 :                             Real64 const TotSkyCover = max(1.0 - desDayInput.SkyClear, 0.0);
    3899          380 :                             Real64 GloHorzRad = (ZHGlobalSolarConstant * SinSolarAltitude *
    3900          190 :                                                      (ZhangHuang_C0 + ZhangHuang_C1 * TotSkyCover + ZhangHuang_C2 * pow_2(TotSkyCover) +
    3901          380 :                                                       ZhangHuang_C3 * (tomorrowTs.OutDryBulbTemp -
    3902          190 :                                                                        state.dataWeather->wvarsHrTsTomorrow(ts, Hour3Ago).OutDryBulbTemp) +
    3903          190 :                                                       ZhangHuang_C4 * tomorrowTs.OutRelHum + ZhangHuang_C5 * tomorrowTs.WindSpeed) +
    3904              :                                                  ZhangHuang_D) /
    3905          190 :                                                 ZhangHuang_K;
    3906          190 :                             GloHorzRad = max(GloHorzRad, 0.0);
    3907          190 :                             Real64 ClearnessIndex_kt = GloHorzRad / (GlobalSolarConstant * SinSolarAltitude);
    3908              :                             //          ClearnessIndex_kt=DesDayInput(EnvrnNum)%SkyClear
    3909          190 :                             Real64 ClearnessIndex_ktc = 0.4268 + 0.1934 * SinSolarAltitude;
    3910              :                             Real64 ClearnessIndex_kds;
    3911          190 :                             if (ClearnessIndex_kt < ClearnessIndex_ktc) {
    3912           96 :                                 ClearnessIndex_kds = (3.996 - 3.862 * SinSolarAltitude + 1.54 * pow_2(SinSolarAltitude)) * pow_3(ClearnessIndex_kt);
    3913              :                             } else {
    3914          188 :                                 ClearnessIndex_kds = ClearnessIndex_kt - (1.107 + 0.03569 * SinSolarAltitude + 1.681 * pow_2(SinSolarAltitude)) *
    3915           94 :                                                                              pow_3(1.0 - ClearnessIndex_kt);
    3916              :                             }
    3917              :                             // Calculate direct normal radiation, W/m2
    3918          190 :                             BeamRad = ZHGlobalSolarConstant * SinSolarAltitude * ClearnessIndex_kds *
    3919          190 :                                       ((1.0 - ClearnessIndex_kt) / (1.0 - ClearnessIndex_kds));
    3920              :                             // Calculation diffuse horizontal radiation, W/m2
    3921          190 :                             DiffRad =
    3922          190 :                                 ZHGlobalSolarConstant * SinSolarAltitude * ((ClearnessIndex_kt - ClearnessIndex_kds) / (1.0 - ClearnessIndex_kds));
    3923              : 
    3924          190 :                         } break;
    3925            0 :                         default:
    3926            0 :                             break;
    3927              :                         }
    3928              :                     }
    3929       783936 :                 }
    3930              : 
    3931              :                 // override result to 0 per environment var (for testing)
    3932       784512 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreBeamRadiation) {
    3933            0 :                     BeamRad = 0.0;
    3934              :                 }
    3935       784512 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreDiffuseRadiation) {
    3936            0 :                     DiffRad = 0.0;
    3937              :                 }
    3938              : 
    3939       784512 :                 tomorrowTs.BeamSolarRad = BeamRad;
    3940       784512 :                 tomorrowTs.DifSolarRad = DiffRad;
    3941              : 
    3942              :             } // Timestep (TS) Loop
    3943              :         } // Hour Loop
    3944              : 
    3945              :         // back-fill hour values from timesteps
    3946              :         // hour values = integrated over hour ending at time of hour
    3947              :         // insurance: hourly values not known to be needed
    3948       149625 :         for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3949       143640 :             int Hour1Ago = mod(hour + 22, Constant::iHoursInDay) + 1;
    3950       143640 :             auto const &tomorrowHr = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->TimeStepsInHour, hour);
    3951       143640 :             auto const &tomorrowHr1Ago = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->TimeStepsInHour, Hour1Ago);
    3952              : 
    3953       143640 :             Real64 BeamRad = (tomorrowHr1Ago.BeamSolarRad + tomorrowHr.BeamSolarRad) / 2.0;
    3954       143640 :             Real64 DiffRad = (tomorrowHr1Ago.DifSolarRad + tomorrowHr.DifSolarRad) / 2.0;
    3955       143640 :             if (state.dataGlobal->TimeStepsInHour > 1) {
    3956       782976 :                 for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour - 1; ++iTS) {
    3957       640872 :                     BeamRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).BeamSolarRad;
    3958       640872 :                     DiffRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).DifSolarRad;
    3959              :                 }
    3960              :             }
    3961       143640 :             Wthr.BeamSolarRad(hour) = BeamRad / state.dataGlobal->TimeStepsInHour;
    3962       143640 :             Wthr.DifSolarRad(hour) = DiffRad / state.dataGlobal->TimeStepsInHour;
    3963              :         }
    3964              : 
    3965         5985 :         if (envCurr.WP_Type1 != 0) {
    3966              : 
    3967            2 :             switch (state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel) {
    3968            2 :             case SkyTempModel::ScheduleValue: {
    3969            2 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3970            2 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3971           50 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3972          240 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3973          192 :                         state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).SkyTemp = desDayModsEnvrn(ts + 1, hr + 1).SkyTemp =
    3974          192 :                             dayVals[hr * state.dataGlobal->TimeStepsInHour];
    3975              :                     }
    3976              :                 }
    3977            2 :             } break;
    3978              : 
    3979            0 :             case SkyTempModel::DryBulbDelta: {
    3980            0 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3981            0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3982            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3983            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3984            0 :                         auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3985            0 :                         desDayModsEnvrn(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3986            0 :                         tomorrowTS.SkyTemp = tomorrowTS.OutDryBulbTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3987              :                     }
    3988              :                 }
    3989            0 :             } break;
    3990              : 
    3991            0 :             case SkyTempModel::DewPointDelta: {
    3992            0 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3993            0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3994            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3995            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3996            0 :                         auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3997            0 :                         desDayModsEnvrn(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3998            0 :                         tomorrowTS.SkyTemp = tomorrowTS.OutDewPointTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3999              :                     }
    4000              :                 }
    4001            0 :             } break;
    4002              : 
    4003            0 :             default: {
    4004            0 :             } break;
    4005              :             } // switch (skyTempModel)
    4006              :         } // if (envCurr.WP_Type1 != 0)
    4007              : 
    4008         5985 :         state.dataGlobal->WarmupFlag = SaveWarmupFlag;
    4009         5985 :     }
    4010              : 
    4011        20276 :     Real64 AirMass(Real64 const CosZen) // COS( solar zenith), 0 - 1
    4012              :     {
    4013              : 
    4014              :         // SUBROUTINE INFORMATION:
    4015              :         //       AUTHOR         C Barnaby
    4016              :         //       DATE WRITTEN   Nov 2010
    4017              : 
    4018              :         // PURPOSE OF THIS SUBROUTINE:
    4019              :         // Calculate relative air mass using Kasten and Young approximation
    4020              : 
    4021              :         // METHODOLOGY EMPLOYED:
    4022              :         // Eqn (16), ASHRAE HOF 2009, p. 14.9
    4023              : 
    4024              :         // REFERENCES:
    4025              :         // ASHRAE HOF 2009 Chapter 14
    4026              :         // Kasten, F and T. Young.  1989.  Revised optical air mass tables
    4027              :         //   and approximating formula.  Applied Optics 28:4735-4738.
    4028              : 
    4029              :         Real64 AirMass;
    4030              :         Real64 SunAltD;
    4031              : 
    4032        20276 :         if (CosZen <= 0.001) {
    4033            6 :             AirMass = 37.07837343; // limit value calc'd with Excel
    4034              :                                    //  value increases little as CosZen -> 0
    4035        20270 :         } else if (CosZen >= 1.0) {
    4036            0 :             AirMass = 1.0;
    4037              :         } else {
    4038              :             // note: COS( Zen) = SIN( Alt)
    4039        20270 :             SunAltD = std::asin(CosZen) / Constant::DegToRad; // altitude, degrees
    4040        20270 :             AirMass = 1.0 / (CosZen + 0.50572 * std::pow(6.07995 + SunAltD, -1.6364));
    4041              :         }
    4042        20276 :         return AirMass;
    4043              :     }
    4044              : 
    4045              :     //------------------------------------------------------------------------------
    4046              : 
    4047        20276 :     void ASHRAETauModel([[maybe_unused]] EnergyPlusData &state,
    4048              :                         DesDaySolarModel const TauModel, // ASHRAETau solar model type ASHRAE_Tau or ASHRAE_Tau2017
    4049              :                         Real64 const ETR,                // extraterrestrial normal irradiance, W/m2
    4050              :                         Real64 const CosZen,             // COS( solar zenith angle), 0 - 1
    4051              :                         Real64 const TauB,               // beam tau factor
    4052              :                         Real64 const TauD,               // dif tau factor
    4053              :                         Real64 &IDirN,                   // returned: direct (beam) irradiance on normal surface, W/m2
    4054              :                         Real64 &IDifH,                   // returned: diffuse irradiance on horiz surface, W/m2
    4055              :                         Real64 &IGlbH                    // returned: global irradiance on horiz surface, W/m2
    4056              :     )
    4057              :     {
    4058              : 
    4059              :         // SUBROUTINE INFORMATION:
    4060              :         //       AUTHOR         C Barnaby
    4061              :         //       DATE WRITTEN   Nov 2010
    4062              : 
    4063              :         // PURPOSE OF THIS SUBROUTINE:
    4064              :         // Calculate clear-sky direct and diffuse irradiance using ASHRAE "tau" model
    4065              : 
    4066              :         // METHODOLOGY EMPLOYED:
    4067              :         // Eqns (17-18), ASHRAE HOF 2009, p. 14.9
    4068              :         // Eqns (19-20), ASHRAE HOF 2013 p. 14.9 and 2017 p. 14.10
    4069              : 
    4070              :         // REFERENCES:
    4071              :         // ASHRAE HOF 2009 Chapter 14
    4072              : 
    4073              :         Real64 AB; // air mass exponents
    4074              :         Real64 AD;
    4075              :         Real64 M; // air mass
    4076              : 
    4077        20276 :         if (CosZen < DataEnvironment::SunIsUpValue || TauB <= 0.0 || TauD <= 0.0) {
    4078            0 :             IDirN = 0.0;
    4079            0 :             IDifH = 0.0;
    4080            0 :             IGlbH = 0.0;
    4081              :         } else {
    4082        20276 :             if (TauModel == DesDaySolarModel::ASHRAE_Tau) {
    4083        20276 :                 AB = 1.219 - 0.043 * TauB - 0.151 * TauD - 0.204 * TauB * TauD;
    4084        20276 :                 AD = 0.202 + 0.852 * TauB - 0.007 * TauD - 0.357 * TauB * TauD;
    4085              :             } else {
    4086              :                 // TauModelType == ASHRAE_Tau2017
    4087            0 :                 AB = 1.454 - 0.406 * TauB - 0.268 * TauD + 0.021 * TauB * TauD;
    4088            0 :                 AD = 0.507 + 0.205 * TauB - 0.080 * TauD - 0.190 * TauB * TauD;
    4089              :             }
    4090        20276 :             M = AirMass(CosZen);
    4091        20276 :             IDirN = ETR * std::exp(-TauB * std::pow(M, AB));
    4092        20276 :             IDifH = ETR * std::exp(-TauD * std::pow(M, AD));
    4093        20276 :             IGlbH = IDirN * CosZen + IDifH;
    4094              :         }
    4095        20276 :     }
    4096              : 
    4097          801 :     void AllocateWeatherData(EnergyPlusData &state)
    4098              :     {
    4099              : 
    4100              :         // SUBROUTINE INFORMATION:
    4101              :         //       AUTHOR         Linda Lawrie
    4102              :         //       DATE WRITTEN   December 2000
    4103              : 
    4104              :         // PURPOSE OF THIS SUBROUTINE:
    4105              :         // This subroutine allocates the weather data structures (Today, Tomorrow,
    4106              :         // Design Day) to the proper number of "time steps in hour" requested by the user.
    4107              :         // Interpolation of data is done later after either setting up the design day (hourly
    4108              :         // data) or reading in hourly weather data.
    4109              : 
    4110          801 :         state.dataWeather->wvarsHrTsToday.allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    4111          801 :         state.dataWeather->wvarsHrTsTomorrow.allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    4112          801 :     }
    4113              : 
    4114        10209 :     void CalculateDailySolarCoeffs(EnergyPlusData const &state,
    4115              :                                    int const DayOfYear,           // Day of year (1 - 366)
    4116              :                                    Real64 &A,                     // ASHRAE "A" - Apparent solar irradiation at air mass = 0 [W/M**2]
    4117              :                                    Real64 &B,                     // ASHRAE "B" - Atmospheric extinction coefficient
    4118              :                                    Real64 &C,                     // ASHRAE "C" - Diffuse radiation factor
    4119              :                                    Real64 &AnnVarSolConstant,     // Annual variation in the solar constant
    4120              :                                    Real64 &EquationOfTime,        // Equation of Time
    4121              :                                    Real64 &SineSolarDeclination,  // Sine of Solar Declination
    4122              :                                    Real64 &CosineSolarDeclination // Cosine of Solar Declination
    4123              :     )
    4124              :     {
    4125              : 
    4126              :         // SUBROUTINE INFORMATION:
    4127              :         //       AUTHOR         George Walton
    4128              :         //       DATE WRITTEN   May 1985
    4129              :         //       MODIFIED       1999 for EnergyPlus
    4130              :         //       RE-ENGINEERED  2001; LKL; Remove need for English -> SI conversion
    4131              :         //                      Implement Tarp "fix" for Southern Hemisphere
    4132              : 
    4133              :         // PURPOSE OF THIS SUBROUTINE:
    4134              :         // This subroutine computes the daily solar coefficients used in other
    4135              :         // calculations.  Specifically, this routine computes values of the solar declination, equation
    4136              :         // of time, and ashrae sky coefficients a, b, and c for a given
    4137              :         // day of the year.
    4138              : 
    4139              :         // METHODOLOGY EMPLOYED:
    4140              :         // The method is the same as that recommended in the ASHRAE loads
    4141              :         // algorithms manual, except that the fourier series expressions
    4142              :         // have been extended by two terms for greater accuracy.
    4143              :         // coefficients for the new expressions were determined at USACERL
    4144              :         // using data from the cited references.
    4145              : 
    4146              :         // REFERENCES:
    4147              :         // J. L. Threlkeld, "Thermal Environmental Engineering", 1970,
    4148              :         // p.316, for declination and equation of time.
    4149              :         // "ASHRAE Handbook of Fundamentals", 1972, p.387 for sky
    4150              :         // coefficients a, b, and c.
    4151              :         // See SUN3 in SolarShading. See SUN2 in BLAST.  See SUN3 in Tarp.
    4152              : 
    4153        10209 :         Real64 const DayCorrection(Constant::Pi * 2.0 / 366.0);
    4154              : 
    4155              :         // Fitted coefficients of Fourier series | Sine of declination coefficients
    4156              :         static constexpr std::array<Real64, 9> SineSolDeclCoef = {
    4157              :             0.00561800, 0.0657911, -0.392779, 0.00064440, -0.00618495, -0.00010101, -0.00007951, -0.00011691, 0.00002096};
    4158              :         // Fitted coefficients of Fourier Series | Equation of Time coefficients
    4159              :         static constexpr std::array<Real64, 9> EqOfTimeCoef = {
    4160              :             0.00021971, -0.122649, 0.00762856, -0.156308, -0.0530028, -0.00388702, -0.00123978, -0.00270502, -0.00167992};
    4161              :         // Fitted coefficients of Fourier Series | ASHRAE A Factor coefficients
    4162              :         static constexpr std::array<Real64, 9> ASHRAE_A_Coef = {1161.6685, 1.1554, 77.3575, -0.5359, -3.7622, 0.9875, -3.3924, -1.7445, 1.1198};
    4163              :         // Fitted coefficients of Fourier Series | ASHRAE B Factor coefficients
    4164              :         static constexpr std::array<Real64, 9> ASHRAE_B_Coef = {
    4165              :             0.171631, -0.00400448, -0.0344923, 0.00000209, 0.00325428, -0.00085429, 0.00229562, 0.0009034, -0.0011867};
    4166              :         // Fitted coefficients of Fourier Series | ASHRAE C Factor coefficients
    4167              :         static constexpr std::array<Real64, 9> ASHRAE_C_Coef = {
    4168              :             0.0905151, -0.00322522, -0.0407966, 0.000104164, 0.00745899, -0.00086461, 0.0013111, 0.000808275, -0.00170515};
    4169              : 
    4170              :         // Day of Year in Radians (Computed from Input DayOfYear)
    4171        10209 :         Real64 X = DayCorrection * DayOfYear; // Convert Julian date (Day of Year) to angle X
    4172              : 
    4173              :         // Calculate sines and cosines of X
    4174        10209 :         Real64 SinX = std::sin(X);
    4175        10209 :         Real64 CosX = std::cos(X);
    4176              : 
    4177        10209 :         SineSolarDeclination = SineSolDeclCoef[0] + SineSolDeclCoef[1] * SinX + SineSolDeclCoef[2] * CosX + SineSolDeclCoef[3] * (SinX * CosX * 2.0) +
    4178        10209 :                                SineSolDeclCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    4179        10209 :                                SineSolDeclCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4180        10209 :                                SineSolDeclCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4181        10209 :                                SineSolDeclCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4182        10209 :                                SineSolDeclCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4183        10209 :         CosineSolarDeclination = std::sqrt(1.0 - pow_2(SineSolarDeclination));
    4184              : 
    4185        10209 :         EquationOfTime = EqOfTimeCoef[0] + EqOfTimeCoef[1] * SinX + EqOfTimeCoef[2] * CosX + EqOfTimeCoef[3] * (SinX * CosX * 2.0) +
    4186        10209 :                          EqOfTimeCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    4187        10209 :                          EqOfTimeCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4188        10209 :                          EqOfTimeCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4189        10209 :                          EqOfTimeCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4190        10209 :                          EqOfTimeCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4191              : 
    4192        10209 :         AnnVarSolConstant = 1.000047 + 0.000352615 * SinX + 0.0334454 * CosX;
    4193              : 
    4194        10209 :         A = ASHRAE_A_Coef[0] + ASHRAE_A_Coef[1] * SinX + ASHRAE_A_Coef[2] * CosX + ASHRAE_A_Coef[3] * (SinX * CosX * 2.0) +
    4195        10209 :             ASHRAE_A_Coef[4] * (pow_2(CosX) - pow_2(SinX)) + ASHRAE_A_Coef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4196        10209 :             ASHRAE_A_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4197        10209 :             ASHRAE_A_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4198        10209 :             ASHRAE_A_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4199              : 
    4200              :         // Compute B and C coefficients
    4201              : 
    4202        10209 :         if (state.dataEnvrn->Latitude < 0.0) {
    4203              :             // If in southern hemisphere, compute B and C with a six month time shift.
    4204            0 :             X -= Constant::Pi;
    4205            0 :             SinX = std::sin(X);
    4206            0 :             CosX = std::cos(X);
    4207              :         }
    4208              : 
    4209        10209 :         B = ASHRAE_B_Coef[0] + ASHRAE_B_Coef[1] * SinX + ASHRAE_B_Coef[2] * CosX + ASHRAE_B_Coef[3] * (SinX * CosX * 2.0) +
    4210        10209 :             ASHRAE_B_Coef[4] * (pow_2(CosX) - pow_2(SinX)) + ASHRAE_B_Coef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4211        10209 :             ASHRAE_B_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4212        10209 :             ASHRAE_B_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4213        10209 :             ASHRAE_B_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4214              : 
    4215        10209 :         C = ASHRAE_C_Coef[0] + ASHRAE_C_Coef[1] * SinX + ASHRAE_C_Coef[2] * CosX + ASHRAE_C_Coef[3] * (SinX * CosX * 2.0) +
    4216        10209 :             ASHRAE_C_Coef[4] * (pow_2(CosX) - pow_2(SinX)) + ASHRAE_C_Coef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4217        10209 :             ASHRAE_C_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4218        10209 :             ASHRAE_C_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4219        10209 :             ASHRAE_C_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4220        10209 :     }
    4221              : 
    4222       783936 :     void CalculateSunDirectionCosines(EnergyPlusData const &state,
    4223              :                                       Real64 const TimeValue,    // Current Time of Day
    4224              :                                       Real64 const EqOfTime,     // Equation of Time
    4225              :                                       Real64 const SinSolDeclin, // Sine of Solar Declination
    4226              :                                       Real64 const CosSolDeclin, // Cosine of Solar Declination
    4227              :                                       Vector3<Real64> &SUNCOS)
    4228              :     {
    4229              : 
    4230              :         // SUBROUTINE INFORMATION:
    4231              :         //       AUTHOR         George Walton
    4232              :         //       DATE WRITTEN   May 1975
    4233              :         //       MODIFIED       1999 for EnergyPlus
    4234              : 
    4235              :         // PURPOSE OF THIS SUBROUTINE:
    4236              :         // This routine computes the solar direction cosines for hourly
    4237              :         // radiation calculations.
    4238              : 
    4239              :         // REFERENCES:
    4240              :         // "NECAP Engineering Manual", 1974, p.3-117
    4241              : 
    4242       783936 :         EP_SIZE_CHECK(SUNCOS, 3); // NOLINT(misc-static-assert)
    4243              : 
    4244              :         // COMPUTE THE HOUR ANGLE
    4245       783936 :         Real64 H = (15.0 * (12.0 - (TimeValue + EqOfTime)) + (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude)) * Constant::DegToRad;
    4246       783936 :         Real64 COSH = std::cos(H);
    4247              :         // COMPUTE THE COSINE OF THE SOLAR ZENITH ANGLE.
    4248              :         // This is also the Sine of the Solar Altitude Angle
    4249              : 
    4250       783936 :         SUNCOS.z = SinSolDeclin * state.dataEnvrn->SinLatitude + CosSolDeclin * state.dataEnvrn->CosLatitude * COSH;
    4251              : 
    4252       783936 :         if (SUNCOS.z >= DataEnvironment::SunIsUpValue) { // If Sun above horizon, compute other direction cosines
    4253       394876 :             SUNCOS.y = SinSolDeclin * state.dataEnvrn->CosLatitude - CosSolDeclin * state.dataEnvrn->SinLatitude * COSH;
    4254       394876 :             SUNCOS.x = CosSolDeclin * std::sin(H);
    4255              :         } else { // Sun is down, set to 0.0
    4256       389060 :             SUNCOS.x = 0.0;
    4257       389060 :             SUNCOS.y = 0.0;
    4258              :         }
    4259       783936 :     }
    4260              : 
    4261      2925340 :     void DetermineSunUpDown(EnergyPlusData &state, Vector3<Real64> &SunCOS)
    4262              :     {
    4263              : 
    4264              :         // SUBROUTINE INFORMATION:
    4265              :         //       AUTHOR         Linda Lawrie
    4266              :         //       DATE WRITTEN   1999
    4267              : 
    4268              :         // PURPOSE OF THIS SUBROUTINE:
    4269              :         // This subroutine determines if the sun is up or down for the current
    4270              :         // hour/timestep.
    4271              : 
    4272              :         // REFERENCES:
    4273              :         // Sun routines from IBLAST, authored by Walton.
    4274              : 
    4275              :         // COMPUTE THE HOUR ANGLE
    4276      2925340 :         if (state.dataGlobal->TimeStepsInHour != 1) {
    4277      5807312 :             state.dataWeather->HrAngle = (15.0 * (12.0 - (state.dataGlobal->CurrentTime + state.dataWeather->TodayVariables.EquationOfTime)) +
    4278      2903656 :                                           (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4279              :         } else {
    4280        21684 :             state.dataWeather->HrAngle =
    4281        21684 :                 (15.0 *
    4282        21684 :                      (12.0 - ((state.dataGlobal->CurrentTime + state.dataEnvrn->TS1TimeOffset) + state.dataWeather->TodayVariables.EquationOfTime)) +
    4283        21684 :                  (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4284              :         }
    4285      2925340 :         Real64 H = state.dataWeather->HrAngle * Constant::DegToRad;
    4286              : 
    4287              :         // Compute the Cosine of the Solar Zenith (Altitude) Angle.
    4288      2925340 :         Real64 CosZenith = state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle +
    4289      2925340 :                            state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H);
    4290              : 
    4291      2925340 :         Real64 SolarZenith = std::acos(CosZenith);
    4292      2925340 :         Real64 SinAltitude = state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H) +
    4293      2925340 :                              state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    4294      2925340 :         Real64 SolarAltitude = std::asin(SinAltitude);
    4295      2925340 :         Real64 CosAzimuth = -(state.dataEnvrn->SinLatitude * CosZenith - state.dataWeather->TodayVariables.SinSolarDeclinAngle) /
    4296      2925340 :                             (state.dataEnvrn->CosLatitude * std::sin(SolarZenith));
    4297              :         // Following because above can yield invalid cos value.  (e.g. at south pole)
    4298      2925340 :         CosAzimuth = max(CosAzimuth, -1.0);
    4299      2925340 :         CosAzimuth = min(1.0, CosAzimuth);
    4300      2925340 :         Real64 SolarAzimuth = std::acos(CosAzimuth);
    4301              : 
    4302      2925340 :         state.dataWeather->SolarAltitudeAngle = SolarAltitude / Constant::DegToRad;
    4303      2925340 :         state.dataWeather->SolarAzimuthAngle = SolarAzimuth / Constant::DegToRad;
    4304      2925340 :         if (state.dataWeather->HrAngle < 0.0) {
    4305      1465180 :             state.dataWeather->SolarAzimuthAngle = 360.0 - state.dataWeather->SolarAzimuthAngle;
    4306              :         }
    4307              : 
    4308      2925340 :         SunCOS.z = CosZenith;
    4309      2925340 :         state.dataEnvrn->SunIsUpPrevTS = state.dataEnvrn->SunIsUp;
    4310      2925340 :         if (CosZenith < DataEnvironment::SunIsUpValue) {
    4311      1463062 :             state.dataEnvrn->SunIsUp = false;
    4312      1463062 :             SunCOS.y = 0.0;
    4313      1463062 :             SunCOS.x = 0.0;
    4314              :         } else {
    4315      1462278 :             state.dataEnvrn->SunIsUp = true;
    4316      1462278 :             SunCOS.y = state.dataWeather->TodayVariables.SinSolarDeclinAngle * state.dataEnvrn->CosLatitude -
    4317      1462278 :                        state.dataWeather->TodayVariables.CosSolarDeclinAngle * state.dataEnvrn->SinLatitude * std::cos(H);
    4318      1462278 :             SunCOS.x = state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::sin(H);
    4319              :         }
    4320      2925340 :     }
    4321              : 
    4322          801 :     void OpenWeatherFile(EnergyPlusData &state, bool &ErrorsFound)
    4323              :     {
    4324              : 
    4325              :         // SUBROUTINE INFORMATION:
    4326              :         //       AUTHOR         Linda Lawrie
    4327              :         //       DATE WRITTEN   June 1999
    4328              : 
    4329              :         // PURPOSE OF THIS SUBROUTINE:
    4330              :         // This subroutine checks to see if a weather file and what kind of weather file
    4331              :         // exists in the working directory and calls appropriate routines to
    4332              :         // open the files and set up for use.
    4333              : 
    4334          801 :         state.dataWeather->WeatherFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    4335          801 :         if (state.dataWeather->WeatherFileExists) {
    4336          793 :             OpenEPlusWeatherFile(state, ErrorsFound, true);
    4337              :         }
    4338          801 :     }
    4339              : 
    4340         4569 :     void OpenEPlusWeatherFile(EnergyPlusData &state,
    4341              :                               bool &ErrorsFound,       // Will be set to true if errors found
    4342              :                               bool const ProcessHeader // Set to true when headers should be processed (rather than just read)
    4343              :     )
    4344              :     {
    4345              : 
    4346              :         // SUBROUTINE INFORMATION:
    4347              :         //       AUTHOR         Linda K. Lawrie
    4348              :         //       DATE WRITTEN   June 1999
    4349              : 
    4350              :         // PURPOSE OF THIS SUBROUTINE:
    4351              :         // This subroutine opens the EnergyPlus Weather File (in.epw) and processes
    4352              :         // the initial header records.
    4353              : 
    4354              :         // METHODOLOGY EMPLOYED:
    4355              :         // List directed reads, as possible.
    4356              : 
    4357         4569 :         state.files.inputWeatherFile.close();
    4358         4569 :         state.files.inputWeatherFile.filePath = state.files.inputWeatherFilePath.filePath;
    4359         4569 :         state.files.inputWeatherFile.open();
    4360         4569 :         if (!state.files.inputWeatherFile.good()) {
    4361            0 :             ShowFatalError(state, "OpenWeatherFile: Could not OPEN EPW Weather File", OptionalOutputFileRef(state.files.eso));
    4362              :         }
    4363              : 
    4364         4569 :         if (ProcessHeader) {
    4365              :             // Read in Header Information
    4366              : 
    4367              :             // Headers should come in order
    4368         7137 :             for (int typeNum = static_cast<int>(EpwHeaderType::Location); typeNum < static_cast<int>(EpwHeaderType::Num); ++typeNum) {
    4369         6344 :                 auto Line = state.files.inputWeatherFile.readLine();
    4370         6344 :                 if (Line.eof) {
    4371            0 :                     ShowFatalError(
    4372              :                         state,
    4373            0 :                         format("OpenWeatherFile: Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}",
    4374            0 :                                epwHeaders[typeNum]),
    4375            0 :                         OptionalOutputFileRef(state.files.eso));
    4376              :                 }
    4377              : 
    4378         6344 :                 int endcol = len(Line.data);
    4379         6344 :                 if (endcol > 0) {
    4380         6344 :                     if (int(Line.data[endcol - 1]) == DataSystemVariables::iUnicode_end) {
    4381            0 :                         ShowSevereError(state,
    4382              :                                         "OpenWeatherFile: EPW Weather File appears to be a Unicode or binary file.",
    4383            0 :                                         OptionalOutputFileRef(state.files.eso));
    4384            0 :                         ShowContinueError(state, "...This file cannot be read by this program. Please save as PC or Unix file and try again");
    4385            0 :                         ShowFatalError(state, "Program terminates due to previous condition.");
    4386              :                     }
    4387              :                 }
    4388         6344 :                 std::string::size_type const Pos = FindNonSpace(Line.data);
    4389         6344 :                 std::string::size_type const HdPos = index(Line.data, epwHeaders[typeNum]);
    4390         6344 :                 if (Pos != HdPos) {
    4391            0 :                     continue;
    4392              :                 }
    4393         6344 :                 ProcessEPWHeader(state, static_cast<EpwHeaderType>(typeNum), Line.data, ErrorsFound);
    4394         6344 :             }
    4395              :         } else { // Header already processed, just read
    4396         3776 :             SkipEPlusWFHeader(state);
    4397              :         }
    4398         4569 :     }
    4399              : 
    4400        12154 :     void CloseWeatherFile(EnergyPlusData &state)
    4401              :     {
    4402        12154 :         state.files.inputWeatherFile.close();
    4403        12154 :     }
    4404              : 
    4405          801 :     void ResolveLocationInformation(EnergyPlusData &state, bool &ErrorsFound) // Set to true if no location evident
    4406              :     {
    4407              : 
    4408              :         // SUBROUTINE INFORMATION:
    4409              :         //       AUTHOR         Rick Strand
    4410              :         //       DATE WRITTEN   June 1997
    4411              : 
    4412              :         // PURPOSE OF THIS SUBROUTINE:
    4413              :         // This subroutine is currently the main interface between the old data
    4414              :         // structure on the BLAST Weather file and the new data structure contained
    4415              :         // in this module.  At some point, this subroutine will be converted
    4416              :         // to read information directly from the new input file.
    4417              : 
    4418         1577 :         if (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather &&
    4419          776 :             state.dataWeather->WeatherFileExists) {
    4420          768 :             if (state.dataWeather->LocationGathered) {
    4421              :                 // See if "matching" location
    4422          761 :                 if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4423         1471 :                     if (std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude) > 1.0 ||
    4424         1422 :                         std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude) > 1.0 ||
    4425         2182 :                         std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone) > 0.0 ||
    4426          711 :                         std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) / max(state.dataEnvrn->Elevation, 1.0) >
    4427              :                             0.10) {
    4428          142 :                         ShowWarningError(state, "Weather file location will be used rather than entered (IDF) Location object.");
    4429           71 :                         ShowContinueError(state, format("..Location object={}", state.dataWeather->LocationTitle));
    4430           71 :                         ShowContinueError(state, format("..Weather File Location={}", state.dataEnvrn->WeatherFileLocationTitle));
    4431          142 :                         ShowContinueError(
    4432              :                             state,
    4433          142 :                             format("..due to location differences, Latitude difference=[{:.2R}] degrees, Longitude difference=[{:.2R}] degrees.",
    4434           71 :                                    std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude),
    4435           71 :                                    std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude)));
    4436          142 :                         ShowContinueError(state,
    4437          142 :                                           format("..Time Zone difference=[{:.1R}] hour(s), Elevation difference=[{:.2R}] percent, [{:.2R}] meters.",
    4438           71 :                                                  std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone),
    4439          142 :                                                  std::abs((state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) /
    4440           71 :                                                           max(state.dataEnvrn->Elevation, 1.0) * 100.0),
    4441          142 :                                                  std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation)));
    4442              :                     }
    4443              :                 }
    4444              :             }
    4445          768 :             if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4446          767 :                 state.dataWeather->LocationTitle = state.dataEnvrn->WeatherFileLocationTitle;
    4447          767 :                 state.dataEnvrn->Latitude = state.dataWeather->WeatherFileLatitude;
    4448          767 :                 state.dataEnvrn->Longitude = state.dataWeather->WeatherFileLongitude;
    4449          767 :                 state.dataEnvrn->TimeZoneNumber = state.dataWeather->WeatherFileTimeZone;
    4450          767 :                 state.dataEnvrn->Elevation = state.dataWeather->WeatherFileElevation;
    4451              :             }
    4452           33 :         } else if (!state.dataWeather->LocationGathered) {
    4453            0 :             state.dataWeather->LocationTitle = "Not Entered";
    4454            0 :             ShowSevereError(state, "No Location given. Must have location information for simulation.");
    4455            0 :             ErrorsFound = true;
    4456              :         }
    4457              : 
    4458          801 :         if (!ErrorsFound) {
    4459          801 :             state.dataEnvrn->StdBaroPress = DataEnvironment::StdPressureSeaLevel * std::pow(1.0 - 2.25577e-05 * state.dataEnvrn->Elevation, 5.2559);
    4460         1602 :             state.dataEnvrn->StdRhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(
    4461          801 :                 state, state.dataEnvrn->StdBaroPress, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
    4462              :             // Write Final Location Information to the initialization output file
    4463              :             static constexpr std::string_view LocHdFormat(
    4464              :                 "! <Site:Location>, Location Name, Latitude {N+/S- Deg}, Longitude {E+/W- Deg},  Time Zone Number "
    4465              :                 "{GMT+/-}, Elevation {m},  Standard Pressure at Elevation {Pa}, Standard RhoAir at Elevation\n");
    4466          801 :             print(state.files.eio, "{}", LocHdFormat);
    4467              : 
    4468              :             static constexpr std::string_view LocFormat("Site:Location,{},{:.2R},{:.2R},{:.2R},{:.2R},{:.0R},{:.4R}\n");
    4469          801 :             print(state.files.eio,
    4470              :                   LocFormat,
    4471          801 :                   state.dataWeather->LocationTitle,
    4472          801 :                   state.dataEnvrn->Latitude,
    4473          801 :                   state.dataEnvrn->Longitude,
    4474          801 :                   state.dataEnvrn->TimeZoneNumber,
    4475          801 :                   state.dataEnvrn->Elevation,
    4476          801 :                   state.dataEnvrn->StdBaroPress,
    4477          801 :                   state.dataEnvrn->StdRhoAir);
    4478              :         }
    4479          801 :     }
    4480              : 
    4481         2145 :     void CheckLocationValidity(EnergyPlusData &state)
    4482              :     {
    4483              : 
    4484              :         // SUBROUTINE INFORMATION:
    4485              :         //       AUTHOR         Rick Strand
    4486              :         //       DATE WRITTEN   June 1997
    4487              : 
    4488              :         // PURPOSE OF THIS SUBROUTINE:
    4489              :         // This subroutine is checks to see whether the user specified location
    4490              :         // or the weather file location (if one exists) is valid.  The standard
    4491              :         // time meridian is also calculated and compared to the user supplied
    4492              :         // or weather file time zone number.
    4493              : 
    4494         2145 :         bool LocationError = false; // Set to true if there is a problem detected
    4495              : 
    4496         2145 :         if ((state.dataEnvrn->Latitude == -999.0) && (state.dataEnvrn->Longitude == -999.0) && (state.dataEnvrn->TimeZoneNumber != -999.0)) {
    4497            0 :             ShowSevereError(state, "No location specified");
    4498            0 :             LocationError = true;
    4499              :         }
    4500              : 
    4501         2145 :         if ((state.dataEnvrn->Latitude < -90.0) || (state.dataEnvrn->Latitude > 90.0)) {
    4502            0 :             ShowSevereError(state, format("Latitude must be between -90 and 90; Entered={:.2R}", state.dataEnvrn->Latitude));
    4503            0 :             LocationError = true;
    4504              :         }
    4505              : 
    4506         2145 :         if ((state.dataEnvrn->Longitude < -180.0) || (state.dataEnvrn->Longitude > 180.0)) {
    4507            0 :             ShowSevereError(state, format("Longitude must be between -180 and 180; Entered={:.2R}", state.dataEnvrn->Longitude));
    4508            0 :             LocationError = true;
    4509              :         }
    4510              : 
    4511         2145 :         if ((state.dataEnvrn->TimeZoneNumber < -12.00) || (state.dataEnvrn->TimeZoneNumber > 14.00)) {
    4512            0 :             ShowSevereError(state, format("Time Zone must be between -12 and +14; Entered={:.2R}", state.dataEnvrn->TimeZoneNumber));
    4513            0 :             LocationError = true;
    4514              :         }
    4515              : 
    4516         2145 :         Real64 const StdTimeMerid = GetSTM(state.dataEnvrn->Longitude); // Standard time meridian.
    4517              : 
    4518              :         // Compare the standard time meridian with the time zone number.  If
    4519              :         // different, notify the user.  If StdTimeMerid couldn't be calculated,
    4520              :         // produce an error message.
    4521              : 
    4522         2145 :         if (state.dataEnvrn->varyingLocationLatSched != nullptr || state.dataEnvrn->varyingLocationLongSched != nullptr) {
    4523              :             // don't do any warnings, the building is moving
    4524          801 :         } else if (StdTimeMerid >= -12.0 && StdTimeMerid <= 12.0) {
    4525          801 :             if (state.dataEnvrn->TimeZoneNumber != StdTimeMerid) {
    4526              :                 // Difference between Standard Time Meridian and TimeZone
    4527           10 :                 Real64 const DiffCalc = std::abs(state.dataEnvrn->TimeZoneNumber - StdTimeMerid);
    4528           10 :                 if (DiffCalc > 1.0 && DiffCalc < 24.0) {
    4529            0 :                     if (DiffCalc < 3.0) {
    4530            0 :                         ShowWarningError(state,
    4531            0 :                                          format("Standard Time Meridian and Time Zone differ by more than 1, Difference=\"{:.1R}\"", DiffCalc));
    4532            0 :                         ShowContinueError(state, "Solar Positions may be incorrect");
    4533              :                     } else {
    4534            0 :                         ShowSevereError(state, format("Standard Time Meridian and Time Zone differ by more than 2, Difference=\"{:.1R}\"", DiffCalc));
    4535            0 :                         ShowContinueError(state, "Solar Positions will be incorrect");
    4536              :                         //          LocationError=.TRUE.
    4537              :                     }
    4538              :                 }
    4539              :             }
    4540          801 :         } else {
    4541            0 :             ShowSevereError(state, "Unable to calculate the standard time meridian");
    4542            0 :             LocationError = true;
    4543              :         }
    4544              : 
    4545              :         // Error handling:  if there are any errors in the location information
    4546              :         // the simulation must be terminated
    4547              : 
    4548         2145 :         if (LocationError) {
    4549            0 :             ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4550              :         }
    4551              : 
    4552         2145 :         if (state.dataEnvrn->TimeZoneNumber <= 12.00) {
    4553         2145 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0;
    4554              :         } else {
    4555            0 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0 - 360.0;
    4556              :         }
    4557         2145 :         state.dataEnvrn->SinLatitude = std::sin(Constant::DegToRad * state.dataEnvrn->Latitude);
    4558         2145 :         state.dataEnvrn->CosLatitude = std::cos(Constant::DegToRad * state.dataEnvrn->Latitude);
    4559              : 
    4560         2145 :         if (state.dataEnvrn->Latitude == 0.0 && state.dataEnvrn->Longitude == 0.0 && state.dataEnvrn->TimeZoneNumber == 0.0) {
    4561            0 :             ShowWarningError(state,
    4562              :                              "Did you realize that you have Latitude=0.0, Longitude=0.0 and TimeZone=0.0?  Your building site is in the middle of "
    4563              :                              "the Atlantic Ocean.");
    4564              :         }
    4565         2145 :     }
    4566              : 
    4567          776 :     void CheckWeatherFileValidity(EnergyPlusData &state)
    4568              :     {
    4569              : 
    4570              :         // SUBROUTINE INFORMATION:
    4571              :         //       AUTHOR         Linda Lawrie
    4572              :         //       DATE WRITTEN   February 1977
    4573              :         //       MODIFIED       June 1997 (RKS)
    4574              : 
    4575              :         // PURPOSE OF THIS SUBROUTINE:
    4576              :         // This subroutine contains a portion of the legacy subroutine CKBLDE.
    4577              :         // The main purpose of this routine is to check the validity of the
    4578              :         // weather dates provided by the user and the attached weather file.
    4579              :         // These functions may eventually be pushed to an interface.  This
    4580              :         // routine also sends the weather file header information at the
    4581              :         // Environment derived type.
    4582              : 
    4583          776 :         if (!state.dataWeather->WeatherFileExists) { // No weather file exists but the user requested one--print error message
    4584              : 
    4585            8 :             if (state.dataGlobal->DoWeathSim) {
    4586            0 :                 ShowSevereError(state, "GetNextEnvironment: Weather Environment(s) requested, but no weather file found");
    4587            0 :                 ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4588              :             }
    4589              : 
    4590              :         } // ... end of WeatherFileExists IF-THEN
    4591          776 :     }
    4592              : 
    4593          801 :     void ReportOutputFileHeaders(EnergyPlusData &state)
    4594              :     {
    4595              : 
    4596              :         // SUBROUTINE INFORMATION:
    4597              :         //       AUTHOR         Rick Strand
    4598              :         //       DATE WRITTEN   June 1997
    4599              :         //       MODIFIED       December 2017; Jason DeGraw
    4600              : 
    4601              :         // PURPOSE OF THIS SUBROUTINE:
    4602              :         // This subroutine prints out the necessary header information required
    4603              :         // by the EnergyPlus output file format.  This subroutine can be
    4604              :         // replicated in any other modules which must send data to the output
    4605              :         // file.
    4606              : 
    4607              :         // METHODOLOGY EMPLOYED:
    4608              :         // For each report, the report flag integer must be saved from the
    4609              :         // global report number counter.  Then, the report counter must be
    4610              :         // incremented.  Finally, the header information for the report must
    4611              :         // be sent to the output file.
    4612              : 
    4613              :         using OutputProcessor::ReportFreq;
    4614              : 
    4615              :         static constexpr std::string_view EnvironmentString(",5,Environment Title[],Latitude[deg],Longitude[deg],Time Zone[],Elevation[m]");
    4616              : 
    4617              :         static constexpr std::array<std::string_view, (int)ReportFreq::Num> freqStrings = {
    4618              :             "", // No EachCall string
    4619              :             ",8,Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],Hour[],StartMinute[],EndMinute[],DayType",
    4620              :             "", // No Hour string
    4621              :             ",5,Cumulative Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],DayType  ! When Daily ",
    4622              :             ",2,Cumulative Days of Simulation[],Month[]  ! When Monthly ",
    4623              :             ",1,Cumulative Days of Simulation[] ! When Run Period ",
    4624              :             ",1,Calendar Year of Simulation[] ! When Annual "};
    4625              : 
    4626          801 :         auto &op = state.dataOutputProcessor;
    4627              : 
    4628          801 :         state.dataWeather->EnvironmentReportNbr = ++op->ReportNumberCounter;
    4629          801 :         if (state.dataWeather->EnvironmentReportNbr != 1) { //  problem
    4630            0 :             ShowFatalError(state, "ReportOutputFileHeaders: Assigned report number for Environment title is not 1.  Contact Support.");
    4631              :         }
    4632          801 :         state.dataWeather->EnvironmentReportChr = fmt::to_string(state.dataWeather->EnvironmentReportNbr);
    4633          801 :         strip(state.dataWeather->EnvironmentReportChr);
    4634          801 :         print(state.files.eso, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4635          801 :         print(state.files.mtr, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4636              : 
    4637              :         // TImeStep and Hour share a stamp
    4638          801 :         op->freqStampReportNums[(int)ReportFreq::Hour] = op->freqStampReportNums[(int)ReportFreq::TimeStep] = ++op->ReportNumberCounter;
    4639          801 :         print(state.files.eso, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4640          801 :         print(state.files.mtr, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4641              : 
    4642         4005 :         for (ReportFreq freq : {ReportFreq::Day, ReportFreq::Month, ReportFreq::Simulation, ReportFreq::Year}) {
    4643         3204 :             op->freqStampReportNums[(int)freq] = ++op->ReportNumberCounter;
    4644         3204 :             print(state.files.eso, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Report Variables Requested");
    4645         3204 :             print(state.files.mtr, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Meters Requested");
    4646              :         }
    4647          801 :     }
    4648              : 
    4649      2925340 :     void ReportWeatherAndTimeInformation(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    4650              :     {
    4651              : 
    4652              :         // SUBROUTINE INFORMATION:
    4653              :         //       AUTHOR         Rick Strand
    4654              :         //       DATE WRITTEN   June 1997
    4655              : 
    4656              :         // PURPOSE OF THIS SUBROUTINE:
    4657              :         // This subroutine is the main driver of the weather reporting.  This
    4658              :         // routine is also responsible for printing the time and environment
    4659              :         // stamps.
    4660              : 
    4661              :         // METHODOLOGY EMPLOYED:
    4662              :         // Reporting is only done for non-warmup days.  The environment stamp
    4663              :         // is only reported at the beginning of an environment, but after the
    4664              :         // warmup days (to allow all modules to print the report headers to the
    4665              :         // output file.  This is controlled by the PrintEnvrnStamp variable
    4666              :         // which is passed in and reset if necessary.
    4667              : 
    4668              :         // Report the time stamp and the current weather to the output file
    4669              : 
    4670      2925340 :         if (!state.dataGlobal->WarmupFlag && !state.dataWeather->RPReadAllWeatherData) { // Write the required output information
    4671              : 
    4672              :             // The first time through in a non-warmup day, the environment header
    4673              :             // must be printed.  This must be done here and not in the generic
    4674              :             // DataGlobals::BeginEnvrnFlag block above because other modules in the simulation
    4675              :             // must also print out header information.  This can be done during
    4676              :             // the simulation warmup if the environment stamp printing is delayed
    4677              :             // until the warmup is completed.  The stamp should only be printed once
    4678              :             // per environment (set/reset of PrintEnvrnStamp).  In addition, before
    4679              :             // the first environment, the end of the header block flag must also be
    4680              :             // sent to the output file.
    4681              : 
    4682       701160 :             if (printEnvrnStamp) {
    4683              : 
    4684       210986 :                 if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting) {
    4685              :                     static constexpr std::string_view EndOfHeaderString("End of Data Dictionary"); // End of data dictionary marker
    4686          796 :                     print(state.files.eso, "{}\n", EndOfHeaderString);
    4687          796 :                     print(state.files.mtr, "{}\n", EndOfHeaderString);
    4688          796 :                     state.dataReportFlag->PrintEndDataDictionary = false;
    4689              :                 }
    4690       210986 :                 if (state.dataGlobal->DoOutputReporting) {
    4691         1706 :                     std::string const &Title = state.dataWeather->Environment(state.dataWeather->Envrn).Title;
    4692              :                     static constexpr std::string_view EnvironmentStampFormatStr(
    4693              :                         "{},{},{:7.2F},{:7.2F},{:7.2F},{:7.2F}\n"); // Format descriptor for environ stamp
    4694         1706 :                     print(state.files.eso,
    4695              :                           EnvironmentStampFormatStr,
    4696         1706 :                           state.dataWeather->EnvironmentReportChr,
    4697              :                           Title,
    4698         1706 :                           state.dataEnvrn->Latitude,
    4699         1706 :                           state.dataEnvrn->Longitude,
    4700         1706 :                           state.dataEnvrn->TimeZoneNumber,
    4701         1706 :                           state.dataEnvrn->Elevation);
    4702         1706 :                     print(state.files.mtr,
    4703              :                           EnvironmentStampFormatStr,
    4704         1706 :                           state.dataWeather->EnvironmentReportChr,
    4705              :                           Title,
    4706         1706 :                           state.dataEnvrn->Latitude,
    4707         1706 :                           state.dataEnvrn->Longitude,
    4708         1706 :                           state.dataEnvrn->TimeZoneNumber,
    4709         1706 :                           state.dataEnvrn->Elevation);
    4710         1706 :                     printEnvrnStamp = false;
    4711              :                 }
    4712              :             }
    4713              :         } // ... end of .NOT.WarmupFlag IF-THEN block.
    4714      2925340 :     }
    4715              : 
    4716          801 :     void ReadUserWeatherInput(EnergyPlusData &state)
    4717              :     {
    4718              : 
    4719              :         // SUBROUTINE INFORMATION:
    4720              :         //       AUTHOR         Richard Liesen
    4721              :         //       DATE WRITTEN   September 1997
    4722              : 
    4723              :         // PURPOSE OF THIS SUBROUTINE:
    4724              :         // This subroutine is the main driver of the weather manager module.
    4725              :         // It controls the assignment of weather related global variables as
    4726              :         // well as the reads and writes for retrieving weather information.
    4727              : 
    4728              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4729          801 :         bool ErrorsFound(false);
    4730              : 
    4731              :         // Get the number of design days and annual runs from user inpout
    4732          801 :         state.dataEnvrn->TotDesDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:DesignDay");
    4733          801 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    4734          801 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    4735          801 :         state.dataWeather->TotRunPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriod");
    4736          801 :         state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4737          801 :         state.dataGlobal->WeathSimReq = state.dataWeather->TotRunPers > 0;
    4738          801 :         state.dataWeather->TotReportPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Output:Table:ReportPeriod");
    4739              : #ifdef GET_OUT
    4740              :         state.dataWeather->SPSiteScheduleNamePtr.allocate(state.dataEnvrn->TotDesDays * 5);
    4741              :         state.dataWeather->SPSiteScheduleUnits.allocate(state.dataEnvrn->TotDesDays * 5);
    4742              : 
    4743              :         state.dataWeather->SPSiteScheduleNamePtr = 0;
    4744              :         state.dataWeather->SPSiteScheduleUnits = "";
    4745              : #endif //
    4746              :        // Allocate the Design Day and Environment array to the # of DD's or/and
    4747              :        // Annual runs on input file
    4748          801 :         state.dataWeather->DesignDay.allocate(state.dataEnvrn->TotDesDays);
    4749          801 :         state.dataWeather->Environment.allocate(state.dataWeather->NumOfEnvrn);
    4750              : 
    4751              :         // Set all Environments to DesignDay and then the weather environment will be set
    4752              :         //  in the get annual run data subroutine
    4753         2478 :         for (int Env = 1; Env <= state.dataEnvrn->TotDesDays; ++Env) {
    4754         1677 :             state.dataWeather->Environment(Env).KindOfEnvrn = Constant::KindOfSim::DesignDay;
    4755              :         }
    4756          806 :         for (int Env = 1; Env <= RPD1 + RPD2; ++Env) {
    4757            5 :             if (!state.dataSysVars->DDOnly) {
    4758            0 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    4759              :             } else {
    4760            5 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4761              :             }
    4762              :         }
    4763         1992 :         for (int Env = 1; Env <= state.dataWeather->TotRunPers; ++Env) {
    4764         1191 :             state.dataWeather->Environment(state.dataEnvrn->TotDesDays + RPD1 + RPD2 + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4765              :         }
    4766              : 
    4767          801 :         if (state.dataEnvrn->TotDesDays >= 1) {
    4768          801 :             GetDesignDayData(state, state.dataEnvrn->TotDesDays, ErrorsFound);
    4769              :         }
    4770              : 
    4771          801 :         if (RPD1 >= 1 || RPD2 >= 1) {
    4772            3 :             GetRunPeriodDesignData(state, ErrorsFound);
    4773              :         }
    4774              : 
    4775              :         // the last environment(s) is designated the weather environment if an annual run
    4776              :         // is selected.  All of the design systems is done from the design day info
    4777              :         // which will have to be completed to run the annual run.
    4778          801 :         if (state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4779          776 :             GetRunPeriodData(state, state.dataWeather->TotRunPers, ErrorsFound);
    4780              :         }
    4781              : 
    4782          801 :         if (state.dataWeather->TotReportPers > 0) {
    4783            4 :             GetReportPeriodData(state, state.dataWeather->TotReportPers, ErrorsFound);
    4784            4 :             GroupReportPeriodByType(state, state.dataWeather->TotReportPers);
    4785              :         }
    4786              : 
    4787          801 :         if (state.dataSysVars->FullAnnualRun) {
    4788              :             // GetRunPeriodData may have reset the value of TotRunPers
    4789            7 :             state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4790              :         }
    4791              : 
    4792          801 :         if (RPD1 >= 1 || RPD2 >= 1 || state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4793          776 :             GetSpecialDayPeriodData(state, ErrorsFound);
    4794          776 :             GetDSTData(state, ErrorsFound);
    4795          776 :             if (state.dataWeather->IDFDaylightSaving) {
    4796          183 :                 state.dataWeather->DST = state.dataWeather->IDFDST;
    4797              :             }
    4798              :         }
    4799              : 
    4800          801 :         GetLocationInfo(state, ErrorsFound);
    4801              : 
    4802          801 :         GetGroundTemps(state);
    4803              : 
    4804          801 :         GetGroundReflectances(state, ErrorsFound);
    4805              : 
    4806          801 :         GetSnowGroundRefModifiers(state, ErrorsFound);
    4807              : 
    4808          801 :         GetWaterMainsTemperatures(state, ErrorsFound);
    4809              : 
    4810          801 :         GetWeatherStation(state, ErrorsFound);
    4811              : 
    4812          801 :         SetupEnvironmentTypes(state);
    4813              : 
    4814          801 :         GetWeatherProperties(state, ErrorsFound);
    4815              : #ifdef GET_OUT
    4816              :         // Deallocate ones used for schedule pointers
    4817              :         state.dataWeather->SPSiteScheduleNamePtr.deallocate();
    4818              :         state.dataWeather->SPSiteScheduleUnits.deallocate();
    4819              : #endif //
    4820          801 :         if (ErrorsFound) {
    4821            0 :             ShowFatalError(state, "GetWeatherInput: Above errors cause termination");
    4822              :         }
    4823          801 :     }
    4824              : 
    4825         1037 :     static int findYearForWeekday(int const month, int const day, Sched::DayType const weekday)
    4826              :     {
    4827              :         // Find a year that goes with a month/day and a weekday. A lookup table is used with the most recent year that includes
    4828              :         // the date with the weekday specified.
    4829              : 
    4830              :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4831              :         static std::array<int, 13> const defaultYear{{2013, 2014, 2015, 2010, 2011, 2017, 2007, 2013, 2014, 2015, 2010, 2011, 2017}};
    4832              : 
    4833         1037 :         int rem = calculateDayOfYear(month, day) % 7;
    4834         1037 :         return defaultYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4835              :     }
    4836              : 
    4837            0 :     static int findLeapYearForWeekday(int const month, int const day, Sched::DayType const weekday)
    4838              :     {
    4839              :         // Find a leap year that goes with a month/day and a weekday. A lookup table is used with the most recent year that includes
    4840              :         // the date with the weekday specified.
    4841              : 
    4842              :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4843              :         static std::array<int, 13> const defaultLeapYear{{2008, 1992, 2004, 2016, 2000, 2012, 1996, 2008, 1992, 2004, 2016, 2000, 2012}};
    4844              : 
    4845            0 :         int rem = calculateDayOfYear(month, day, true) % 7;
    4846            0 :         return defaultLeapYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4847              :     }
    4848              : 
    4849            4 :     void GetReportPeriodData(EnergyPlusData &state,
    4850              :                              int nReportPeriods, // Total number of Report Periods requested
    4851              :                              bool &ErrorsFound)
    4852              :     {
    4853            4 :         constexpr std::string_view routineName = "GetReportPeriodData";
    4854            4 :         state.dataWeather->ReportPeriodInput.allocate(nReportPeriods);
    4855              : 
    4856            4 :         auto const &ipsc = state.dataIPShortCut;
    4857            4 :         ipsc->cCurrentModuleObject = "Output:Table:ReportPeriod";
    4858            4 :         int Count = 0;
    4859              :         int NumAlpha;   // Number of alphas being input
    4860              :         int NumNumeric; // Number of numbers being input
    4861              :         int IOStat;     // IO Status when calling get input subroutine
    4862           13 :         for (int i = 1; i <= nReportPeriods; ++i) {
    4863           18 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4864            9 :                                                                      ipsc->cCurrentModuleObject,
    4865              :                                                                      i,
    4866            9 :                                                                      ipsc->cAlphaArgs,
    4867              :                                                                      NumAlpha,
    4868            9 :                                                                      ipsc->rNumericArgs,
    4869              :                                                                      NumNumeric,
    4870              :                                                                      IOStat,
    4871            9 :                                                                      ipsc->lNumericFieldBlanks,
    4872            9 :                                                                      ipsc->lAlphaFieldBlanks,
    4873            9 :                                                                      ipsc->cAlphaFieldNames,
    4874            9 :                                                                      ipsc->cNumericFieldNames);
    4875              : 
    4876            9 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    4877            9 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    4878              :             // A1, \field Name
    4879            9 :             if (std::find_if(state.dataWeather->ReportPeriodInput.begin(),
    4880            9 :                              state.dataWeather->ReportPeriodInput.end(),
    4881           48 :                              [&newName](ReportPeriodData const &rpd) { return newName == rpd.title; }) !=
    4882            9 :                 state.dataWeather->ReportPeriodInput.end()) {
    4883            0 :                 ShowSevereDuplicateName(state, eoh);
    4884            0 :                 ErrorsFound = true;
    4885              :             }
    4886              : 
    4887            9 :             ++Count;
    4888              : 
    4889            9 :             auto &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4890              :             // Loop = RP + Ptr;
    4891              :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "ReportPeriod 1" anyways
    4892              :             // which is fine for our reporting below
    4893            9 :             reportPeriodInput.title = newName;
    4894              :             // A2, \field Report Name
    4895            9 :             reportPeriodInput.reportName = ipsc->cAlphaArgs(2);
    4896              : 
    4897              :             // set the start and end day of month from user input
    4898              :             // N1, \field Begin Year
    4899              :             // N2, \field Begin Month
    4900              :             // N3, \field Begin Day of Month
    4901              :             // N4, \field Begin Hour of Day
    4902              :             // N5, \field End Year
    4903              :             // N6, \field End Month
    4904              :             // N7, \field End Day of Month
    4905              :             // N8; \field End Hour of Day
    4906            9 :             reportPeriodInput.startYear = int(ipsc->rNumericArgs(1));
    4907            9 :             reportPeriodInput.startMonth = int(ipsc->rNumericArgs(2));
    4908            9 :             reportPeriodInput.startDay = int(ipsc->rNumericArgs(3));
    4909            9 :             reportPeriodInput.startHour = int(ipsc->rNumericArgs(4));
    4910            9 :             reportPeriodInput.endYear = int(ipsc->rNumericArgs(5));
    4911            9 :             reportPeriodInput.endMonth = int(ipsc->rNumericArgs(6));
    4912            9 :             reportPeriodInput.endDay = int(ipsc->rNumericArgs(7));
    4913            9 :             reportPeriodInput.endHour = int(ipsc->rNumericArgs(8));
    4914              : 
    4915              :             // Validate year inputs
    4916            9 :             if (reportPeriodInput.startYear == 0) {
    4917            9 :                 if (reportPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    4918            0 :                     ShowSevereError(state,
    4919            0 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    4920            0 :                                            ipsc->cCurrentModuleObject,
    4921            0 :                                            reportPeriodInput.title));
    4922            0 :                     ErrorsFound = true;
    4923              :                 }
    4924            0 :             } else if (reportPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    4925            0 :                 ShowSevereError(state,
    4926            0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    4927            0 :                                        ipsc->cCurrentModuleObject,
    4928            0 :                                        reportPeriodInput.title,
    4929            0 :                                        reportPeriodInput.startYear));
    4930            0 :                 ErrorsFound = true;
    4931              :             }
    4932              : 
    4933            9 :             if (reportPeriodInput.endYear != 0 && reportPeriodInput.startYear > reportPeriodInput.endYear) {
    4934            0 :                 ShowSevereError(state,
    4935            0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    4936            0 :                                        ipsc->cCurrentModuleObject,
    4937            0 :                                        reportPeriodInput.title,
    4938            0 :                                        reportPeriodInput.startYear,
    4939            0 :                                        reportPeriodInput.endYear));
    4940            0 :                 ErrorsFound = true;
    4941              :             }
    4942              : 
    4943            9 :             reportPeriodInput.startJulianDate =
    4944            9 :                 computeJulianDate(reportPeriodInput.startYear, reportPeriodInput.startMonth, reportPeriodInput.startDay);
    4945            9 :             reportPeriodInput.endJulianDate = computeJulianDate(reportPeriodInput.endYear, reportPeriodInput.endMonth, reportPeriodInput.endDay);
    4946            9 :         }
    4947            4 :     }
    4948              : 
    4949            4 :     void GroupReportPeriodByType(EnergyPlusData &state, const int nReportPeriods)
    4950              :     {
    4951              :         // transfer data from the reporting period object to the corresponding report period type arrays
    4952              :         // ThermalResilienceSummary, CO2ResilienceSummary, VisualResilienceSummary, and AllResilienceSummaries
    4953           13 :         for (auto const &reportPeriodInput : state.dataWeather->ReportPeriodInput) {
    4954              : 
    4955            9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4956            4 :                 ++state.dataWeather->TotThermalReportPers;
    4957            5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4958            2 :                 ++state.dataWeather->TotCO2ReportPers;
    4959            3 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4960            2 :                 ++state.dataWeather->TotVisualReportPers;
    4961            1 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4962            1 :                 ++state.dataWeather->TotThermalReportPers;
    4963            1 :                 ++state.dataWeather->TotCO2ReportPers;
    4964            1 :                 ++state.dataWeather->TotVisualReportPers;
    4965              :             }
    4966              :         }
    4967              : 
    4968            4 :         state.dataWeather->ThermalReportPeriodInput.allocate(state.dataWeather->TotThermalReportPers);
    4969            4 :         state.dataWeather->CO2ReportPeriodInput.allocate(state.dataWeather->TotCO2ReportPers);
    4970            4 :         state.dataWeather->VisualReportPeriodInput.allocate(state.dataWeather->TotVisualReportPers);
    4971              : 
    4972           13 :         for (int i = 1, iThermal = 1, iVisual = 1, iCO2 = 1; i <= nReportPeriods; ++i) {
    4973            9 :             auto const &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4974            9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4975            4 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4976            4 :                 ++iThermal;
    4977            5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4978            2 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4979            2 :                 ++iCO2;
    4980            3 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4981            2 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4982            2 :                 ++iVisual;
    4983            1 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4984            1 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4985            1 :                 ++iThermal;
    4986            1 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4987            1 :                 ++iCO2;
    4988            1 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4989            1 :                 ++iVisual;
    4990              :             }
    4991              :         }
    4992            4 :     }
    4993              : 
    4994          776 :     void GetRunPeriodData(EnergyPlusData &state,
    4995              :                           int nRunPeriods, // Total number of Run Periods requested
    4996              :                           bool &ErrorsFound)
    4997              :     {
    4998              : 
    4999              :         // SUBROUTINE INFORMATION:
    5000              :         //       AUTHOR         Richard Liesen
    5001              :         //       DATE WRITTEN   October 1997
    5002              :         //       MODIFIED       February 1999, Add multiple run periods, Change name.
    5003              :         //                      March 2012, LKL, Add features to object; New "actual weather" object;
    5004              : 
    5005              :         // PURPOSE OF THIS SUBROUTINE:
    5006              :         // This subroutine gets the run period info from User input and the
    5007              :         //  simulation dates
    5008              : 
    5009          776 :         constexpr std::string_view routineName = "GetRunPeriodData";
    5010              :         // Call Input Get routine to retrieve annual run data
    5011          776 :         state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    5012              : 
    5013          776 :         auto const &ipsc = state.dataIPShortCut;
    5014          776 :         ipsc->cCurrentModuleObject = "RunPeriod";
    5015          776 :         int Count = 0;
    5016              :         int NumAlpha;   // Number of alphas being input
    5017              :         int NumNumeric; // Number of numbers being input
    5018              :         int IOStat;     // IO Status when calling get input subroutine
    5019         1967 :         for (int i = 1; i <= nRunPeriods; ++i) {
    5020         2382 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5021         1191 :                                                                      ipsc->cCurrentModuleObject,
    5022              :                                                                      i,
    5023         1191 :                                                                      ipsc->cAlphaArgs,
    5024              :                                                                      NumAlpha,
    5025         1191 :                                                                      ipsc->rNumericArgs,
    5026              :                                                                      NumNumeric,
    5027              :                                                                      IOStat,
    5028         1191 :                                                                      ipsc->lNumericFieldBlanks,
    5029         1191 :                                                                      ipsc->lAlphaFieldBlanks,
    5030         1191 :                                                                      ipsc->cAlphaFieldNames,
    5031         1191 :                                                                      ipsc->cNumericFieldNames);
    5032              : 
    5033              :             // A1, \field Name
    5034         1191 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5035         1191 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5036              : 
    5037         1191 :             if (std::find_if(state.dataWeather->RunPeriodInput.begin(),
    5038         1191 :                              state.dataWeather->RunPeriodInput.end(),
    5039         3410 :                              [&newName](RunPeriodData const &rpd) { return rpd.title == newName; }) != state.dataWeather->RunPeriodInput.end()) {
    5040            0 :                 ShowSevereDuplicateName(state, eoh);
    5041            0 :                 ErrorsFound = true;
    5042              :             }
    5043              : 
    5044         1191 :             ++Count;
    5045              :             // Loop = RP + Ptr;
    5046              :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "RUNPERIOD 1" anyways
    5047              :             // which is fine for our reporting below
    5048         1191 :             auto &runPeriodInput = state.dataWeather->RunPeriodInput(i);
    5049         1191 :             runPeriodInput.title = ipsc->cAlphaArgs(1);
    5050              : 
    5051              :             // set the start and end day of month from user input
    5052              :             // N1 , \field Begin Month
    5053              :             // N2 , \field Begin Day of Month
    5054              :             // N3,  \field Start Year
    5055              :             // N4 , \field End Month
    5056              :             // N5 , \field End Day of Month
    5057              :             // N6,  \field End Year
    5058         1191 :             runPeriodInput.startMonth = int(ipsc->rNumericArgs(1));
    5059         1191 :             runPeriodInput.startDay = int(ipsc->rNumericArgs(2));
    5060         1191 :             runPeriodInput.startYear = int(ipsc->rNumericArgs(3));
    5061         1191 :             runPeriodInput.endMonth = int(ipsc->rNumericArgs(4));
    5062         1191 :             runPeriodInput.endDay = int(ipsc->rNumericArgs(5));
    5063         1191 :             runPeriodInput.endYear = int(ipsc->rNumericArgs(6));
    5064         1191 :             runPeriodInput.TreatYearsAsConsecutive = true;
    5065              : 
    5066         1191 :             if (state.dataSysVars->FullAnnualRun && i == 1) {
    5067            7 :                 runPeriodInput.startMonth = 1;
    5068            7 :                 runPeriodInput.startDay = 1;
    5069            7 :                 runPeriodInput.endMonth = 12;
    5070            7 :                 runPeriodInput.endDay = 31;
    5071              :             }
    5072              : 
    5073              :             // Validate year inputs
    5074         1191 :             if (runPeriodInput.startYear == 0) {
    5075         1182 :                 if (runPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    5076            0 :                     ShowSevereError(state,
    5077            0 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    5078            0 :                                            ipsc->cCurrentModuleObject,
    5079            0 :                                            runPeriodInput.title));
    5080            0 :                     ErrorsFound = true;
    5081              :                 }
    5082            9 :             } else if (runPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    5083            0 :                 ShowSevereError(state,
    5084            0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    5085            0 :                                        ipsc->cCurrentModuleObject,
    5086            0 :                                        runPeriodInput.title,
    5087            0 :                                        runPeriodInput.startYear));
    5088            0 :                 ErrorsFound = true;
    5089              :             }
    5090              : 
    5091         1191 :             if (runPeriodInput.endYear != 0 && runPeriodInput.startYear > runPeriodInput.endYear) {
    5092            0 :                 ShowSevereError(state,
    5093            0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    5094            0 :                                        ipsc->cCurrentModuleObject,
    5095            0 :                                        runPeriodInput.title,
    5096            0 :                                        runPeriodInput.startYear,
    5097            0 :                                        runPeriodInput.endYear));
    5098            0 :                 ErrorsFound = true;
    5099              :             }
    5100              : 
    5101              :             // A2 , \field Day of Week for Start Day
    5102         1191 :             bool inputWeekday = false;
    5103         1191 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) { // Have input
    5104         1044 :                 int dayType = getEnumValue(Sched::dayTypeNamesUC, state.dataIPShortCut->cAlphaArgs(2));
    5105         1044 :                 if (dayType < 1) {
    5106            0 :                     ShowWarningError(state,
    5107            0 :                                      format("{}: object={}{} invalid (Day of Week) [{}] for Start is not valid, Sunday will be used.",
    5108            0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    5109            0 :                                             state.dataWeather->RunPeriodInput(i).title,
    5110            0 :                                             state.dataIPShortCut->cAlphaFieldNames(2),
    5111            0 :                                             state.dataIPShortCut->cAlphaArgs(2)));
    5112            0 :                     runPeriodInput.startWeekDay = Sched::DayType::Sunday;
    5113              :                 } else {
    5114         1044 :                     runPeriodInput.startWeekDay = static_cast<Sched::DayType>(dayType);
    5115         1044 :                     inputWeekday = true;
    5116              :                 }
    5117              :             } else { // No input, set the default as Sunday. This may get overriden below
    5118          147 :                 runPeriodInput.startWeekDay = Sched::DayType::Sunday;
    5119              :             }
    5120              : 
    5121              :             // Validate the dates now that the weekday field has been looked at
    5122         1191 :             if (runPeriodInput.startMonth == 2 && runPeriodInput.startDay == 29) {
    5123              :                 // Requested start date is a leap year
    5124            0 :                 if (runPeriodInput.startYear == 0) { // No input starting year
    5125            0 :                     if (inputWeekday) {
    5126            0 :                         runPeriodInput.startYear =
    5127            0 :                             findLeapYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    5128              :                     } else {
    5129              :                         // 2012 is the default year, 1/1 is a Sunday
    5130            0 :                         runPeriodInput.startYear = 2012;
    5131            0 :                         runPeriodInput.startWeekDay =
    5132            0 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5133              :                     }
    5134              :                 } else {                                         // Have an input start year
    5135            0 :                     if (!isLeapYear(runPeriodInput.startYear)) { // Start year is not a leap year
    5136            0 :                         ShowSevereError(state,
    5137            0 :                                         format("{}: object={}, start year ({}) is not a leap year but the requested start date is 2/29.",
    5138            0 :                                                ipsc->cCurrentModuleObject,
    5139            0 :                                                runPeriodInput.title,
    5140            0 :                                                runPeriodInput.startYear));
    5141            0 :                         ErrorsFound = true;
    5142              :                     } else { // Start year is a leap year
    5143              :                         Sched::DayType weekday =
    5144            0 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5145            0 :                         if (inputWeekday) { // Check for correctness of input
    5146            0 :                             if (weekday != runPeriodInput.startWeekDay) {
    5147            0 :                                 ShowWarningError(state,
    5148            0 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    5149            0 :                                                         ipsc->cCurrentModuleObject,
    5150            0 :                                                         runPeriodInput.title,
    5151            0 :                                                         ipsc->cAlphaArgs(2),
    5152            0 :                                                         runPeriodInput.startYear,
    5153            0 :                                                         Sched::dayTypeNamesUC[static_cast<int>(weekday)]));
    5154            0 :                                 runPeriodInput.startWeekDay = weekday;
    5155              :                             }
    5156              :                         } else { // Set the weekday if it was not input
    5157            0 :                             runPeriodInput.startWeekDay = weekday;
    5158              :                         }
    5159              :                     }
    5160              :                 }
    5161            0 :             } else {
    5162              :                 // Non leap-day start date
    5163         1191 :                 if (!validMonthDay(runPeriodInput.startMonth, runPeriodInput.startDay)) {
    5164            0 :                     ShowSevereError(state,
    5165            0 :                                     format("{}: object={}, Invalid input start month/day ({}/{})",
    5166            0 :                                            ipsc->cCurrentModuleObject,
    5167            0 :                                            runPeriodInput.title,
    5168            0 :                                            runPeriodInput.startMonth,
    5169            0 :                                            runPeriodInput.startDay));
    5170            0 :                     ErrorsFound = true;
    5171              :                 } else {                                 // Month/day is valid
    5172         1191 :                     if (runPeriodInput.startYear == 0) { // No input starting year
    5173         1182 :                         if (inputWeekday) {
    5174         1037 :                             runPeriodInput.startYear =
    5175         1037 :                                 findYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    5176              :                         } else {
    5177              :                             // 2017 is the default year, 1/1 is a Sunday
    5178          145 :                             runPeriodInput.startYear = 2017;
    5179          145 :                             runPeriodInput.startWeekDay =
    5180          145 :                                 calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5181              :                         }
    5182              :                     } else { // Have an input starting year
    5183              :                         Sched::DayType weekday =
    5184            9 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5185            9 :                         if (inputWeekday) { // Check for correctness of input
    5186            7 :                             if (weekday != runPeriodInput.startWeekDay) {
    5187            2 :                                 ShowWarningError(state,
    5188            3 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    5189            1 :                                                         ipsc->cCurrentModuleObject,
    5190            1 :                                                         runPeriodInput.title,
    5191            1 :                                                         ipsc->cAlphaArgs(2),
    5192            1 :                                                         runPeriodInput.startYear,
    5193            1 :                                                         Sched::dayTypeNamesUC[static_cast<int>(weekday)]));
    5194            1 :                                 runPeriodInput.startWeekDay = weekday;
    5195              :                             }
    5196              :                         } else { // Set the weekday if it was not input
    5197            2 :                             runPeriodInput.startWeekDay = weekday;
    5198              :                         }
    5199              :                     }
    5200              :                 }
    5201              :             }
    5202              : 
    5203              :             // Compute the Julian date of the start date
    5204         1191 :             runPeriodInput.startJulianDate = computeJulianDate(runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5205              : 
    5206              :             // Validate the end date
    5207         1191 :             if (runPeriodInput.endMonth == 2 && runPeriodInput.endDay == 29) {
    5208              :                 // Requested end date is a leap year
    5209            0 :                 if (runPeriodInput.endYear == 0) { // No input end year
    5210            0 :                     if (isLeapYear(runPeriodInput.startYear) && runPeriodInput.startMonth < 3) {
    5211              :                         // The run period is from some date on or before 2/29 through 2/29
    5212            0 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5213              :                     } else {
    5214              :                         // There might be a better approach here, but for now just loop forward for the next leap year
    5215            0 :                         for (int yr = runPeriodInput.startYear + 1; yr < runPeriodInput.startYear + 10; yr++) {
    5216            0 :                             if (isLeapYear(yr)) {
    5217            0 :                                 runPeriodInput.endYear = yr;
    5218            0 :                                 break;
    5219              :                             }
    5220              :                         }
    5221              :                     }
    5222              :                 } else {                                       // Have an input end year
    5223            0 :                     if (!isLeapYear(runPeriodInput.endYear)) { // End year is not a leap year
    5224            0 :                         ShowSevereError(state,
    5225            0 :                                         format("{}: object={}, end year ({}) is not a leap year but the requested end date is 2/29.",
    5226            0 :                                                ipsc->cCurrentModuleObject,
    5227            0 :                                                runPeriodInput.title,
    5228            0 :                                                runPeriodInput.startYear));
    5229            0 :                         ErrorsFound = true;
    5230              :                     } else {
    5231            0 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5232            0 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5233            0 :                             ShowSevereError(state,
    5234            0 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5235            0 :                                                    ipsc->cCurrentModuleObject,
    5236            0 :                                                    runPeriodInput.title,
    5237            0 :                                                    runPeriodInput.startJulianDate,
    5238            0 :                                                    runPeriodInput.endJulianDate));
    5239            0 :                             ErrorsFound = true;
    5240              :                         }
    5241              :                     }
    5242              :                 }
    5243            0 :             } else {
    5244              :                 // Non leap-day end date
    5245         1191 :                 if (!validMonthDay(runPeriodInput.endMonth, runPeriodInput.endDay)) {
    5246            0 :                     ShowSevereError(state,
    5247            0 :                                     format("{}: object={}, Invalid input end month/day ({}/{})",
    5248            0 :                                            ipsc->cCurrentModuleObject,
    5249            0 :                                            runPeriodInput.title,
    5250            0 :                                            runPeriodInput.startMonth,
    5251            0 :                                            runPeriodInput.startDay));
    5252            0 :                     ErrorsFound = true;
    5253              :                 } else {                               // Month/day is valid
    5254         1191 :                     if (runPeriodInput.endYear == 0) { // No input end year
    5255              :                         // Assume same year as start year
    5256         1182 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5257         1182 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5258         1182 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5259            5 :                             runPeriodInput.endJulianDate = 0; // Force recalculation later
    5260            5 :                             runPeriodInput.endYear += 1;
    5261              :                         }
    5262              :                     } else { // Have an input end year
    5263            9 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5264            9 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5265            0 :                             ShowSevereError(state,
    5266            0 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5267            0 :                                                    ipsc->cCurrentModuleObject,
    5268            0 :                                                    runPeriodInput.title,
    5269            0 :                                                    runPeriodInput.startJulianDate,
    5270            0 :                                                    runPeriodInput.endJulianDate));
    5271            0 :                             ErrorsFound = true;
    5272              :                         }
    5273              :                     }
    5274              :                 }
    5275              :             }
    5276              : 
    5277         1191 :             if (runPeriodInput.endJulianDate == 0) {
    5278            5 :                 runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5279              :             }
    5280              : 
    5281         1191 :             runPeriodInput.numSimYears = runPeriodInput.endYear - runPeriodInput.startYear + 1;
    5282              : 
    5283              :             // A3,  \field Use Weather File Holidays and Special Days
    5284              :             BooleanSwitch b;
    5285         1191 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5286            9 :                 runPeriodInput.useHolidays = true;
    5287         1182 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5288         1182 :                 runPeriodInput.useHolidays = static_cast<bool>(b);
    5289              :             } else {
    5290            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5291            0 :                 ErrorsFound = true;
    5292              :             }
    5293              : 
    5294              :             // A4,  \field Use Weather File Daylight Saving Period
    5295         1191 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5296            9 :                 runPeriodInput.useDST = true;
    5297         1182 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5298         1182 :                 runPeriodInput.useDST = static_cast<bool>(b);
    5299              :             } else {
    5300            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5301            0 :                 ErrorsFound = true;
    5302              :             }
    5303              : 
    5304              :             // A5,  \field Apply Weekend Holiday Rule
    5305         1191 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5306           18 :                 runPeriodInput.applyWeekendRule = true;
    5307         1173 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5308         1173 :                 runPeriodInput.applyWeekendRule = static_cast<bool>(b);
    5309              :             } else {
    5310            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5311            0 :                 ErrorsFound = true;
    5312              :             }
    5313              : 
    5314              :             // A6,  \field Use Weather File Rain Indicators
    5315         1191 :             if (ipsc->lAlphaFieldBlanks(6)) {
    5316           18 :                 runPeriodInput.useRain = true;
    5317         1173 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(6)))) != BooleanSwitch::Invalid) {
    5318         1173 :                 runPeriodInput.useRain = static_cast<bool>(b);
    5319              :             } else {
    5320            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6));
    5321            0 :                 ErrorsFound = true;
    5322              :             }
    5323              : 
    5324              :             // A7,  \field Use Weather File Snow Indicators
    5325         1191 :             if (ipsc->lAlphaFieldBlanks(7)) {
    5326           18 :                 runPeriodInput.useSnow = true;
    5327         1173 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    5328         1173 :                 runPeriodInput.useSnow = static_cast<bool>(b);
    5329              :             } else {
    5330            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7));
    5331            0 :                 ErrorsFound = true;
    5332              :             }
    5333              : 
    5334              :             // A8,  \field Treat Weather as Actual
    5335         1191 :             if (ipsc->lAlphaFieldBlanks(8)) {
    5336         1191 :                 runPeriodInput.actualWeather = false;
    5337            0 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    5338            0 :                 runPeriodInput.actualWeather = static_cast<bool>(b);
    5339              :             } else {
    5340            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8));
    5341            0 :                 ErrorsFound = true;
    5342              :             }
    5343              : 
    5344              :             // A9,  \field First Hour Interpolation Starting Values
    5345         1191 :             if (ipsc->lAlphaFieldBlanks(9) || Util::SameString(ipsc->cAlphaArgs(8), "Hour24")) {
    5346         1191 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5347            0 :             } else if (Util::SameString(ipsc->cAlphaArgs(9), "Hour1")) {
    5348            0 :                 runPeriodInput.firstHrInterpUsingHr1 = true;
    5349              :             } else {
    5350              :                 // fail-safe default
    5351            0 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5352              :             }
    5353              : 
    5354         1191 :             runPeriodInput.dayOfWeek = static_cast<int>(runPeriodInput.startWeekDay);
    5355         1191 :             runPeriodInput.isLeapYear = isLeapYear(runPeriodInput.startYear);
    5356              : 
    5357              :             // calculate the annual start and end days from the user inputted month and day
    5358         1191 :             runPeriodInput.monWeekDay = 0;
    5359         1191 :             if (runPeriodInput.dayOfWeek != 0 && !ErrorsFound) {
    5360         1191 :                 SetupWeekDaysByMonth(state, runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.dayOfWeek, runPeriodInput.monWeekDay);
    5361              :             }
    5362         1191 :         }
    5363              : 
    5364          776 :         if (nRunPeriods == 0 && state.dataSysVars->FullAnnualRun) {
    5365            0 :             ShowWarningError(state, "No Run Periods input but Full Annual Simulation selected.  Adding Run Period to 1/1 through 12/31.");
    5366            0 :             state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    5367            0 :             state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    5368            0 :             nRunPeriods = 1;
    5369            0 :             state.dataGlobal->WeathSimReq = true;
    5370            0 :             state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    5371            0 :             auto &runPerInput1 = state.dataWeather->RunPeriodInput(1);
    5372            0 :             runPerInput1.startJulianDate = General::OrdinalDay(runPerInput1.startMonth, runPerInput1.startDay, state.dataWeather->LeapYearAdd);
    5373            0 :             runPerInput1.endJulianDate = General::OrdinalDay(runPerInput1.endMonth, runPerInput1.endDay, state.dataWeather->LeapYearAdd);
    5374            0 :             runPerInput1.monWeekDay = 0;
    5375            0 :             if (runPerInput1.dayOfWeek != 0 && !ErrorsFound) {
    5376            0 :                 SetupWeekDaysByMonth(state, runPerInput1.startMonth, runPerInput1.startDay, runPerInput1.dayOfWeek, runPerInput1.monWeekDay);
    5377              :             }
    5378          776 :         } else if (nRunPeriods > 1 && state.dataSysVars->FullAnnualRun) {
    5379            0 :             nRunPeriods = 1;
    5380              :         }
    5381          776 :     }
    5382              : 
    5383            3 :     void GetRunPeriodDesignData(EnergyPlusData &state, bool &ErrorsFound)
    5384              :     {
    5385              : 
    5386              :         // SUBROUTINE INFORMATION:
    5387              :         //       AUTHOR         Linda Lawrie
    5388              :         //       DATE WRITTEN   March 2008
    5389              : 
    5390              :         // PURPOSE OF THIS SUBROUTINE:
    5391              :         // This subroutine gets the run period design info from User input and the
    5392              :         //  simulation dates
    5393              : 
    5394            3 :         constexpr std::string_view routineName = "GetRunPeriodDesignData";
    5395              :         // Call Input Get routine to retrieve annual run data
    5396            3 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    5397            3 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    5398            3 :         state.dataWeather->TotRunDesPers = RPD1 + RPD2;
    5399              : 
    5400            3 :         state.dataWeather->RunPeriodDesignInput.allocate(RPD1 + RPD2);
    5401              : 
    5402            3 :         int Count = 0;
    5403            3 :         auto const &ipsc = state.dataIPShortCut;
    5404            3 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileDays";
    5405            6 :         for (int i = 1; i <= RPD1; ++i) {
    5406              :             int NumAlphas;   // Number of alphas being input
    5407              :             int NumNumerics; // Number of Numerics being input
    5408              :             int IOStat;      // IO Status when calling get input subroutine
    5409            6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5410            3 :                                                                      ipsc->cCurrentModuleObject,
    5411              :                                                                      i,
    5412            3 :                                                                      ipsc->cAlphaArgs,
    5413              :                                                                      NumAlphas,
    5414            3 :                                                                      ipsc->rNumericArgs,
    5415              :                                                                      NumNumerics,
    5416              :                                                                      IOStat,
    5417            3 :                                                                      ipsc->lNumericFieldBlanks,
    5418            3 :                                                                      ipsc->lAlphaFieldBlanks,
    5419            3 :                                                                      ipsc->cAlphaFieldNames,
    5420            3 :                                                                      ipsc->cNumericFieldNames);
    5421              : 
    5422            3 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5423            3 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5424            6 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5425            6 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5426            8 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5427            6 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5428            0 :                 ShowSevereDuplicateName(state, eoh);
    5429            0 :                 ErrorsFound = true;
    5430              :             }
    5431              : 
    5432            3 :             ++Count;
    5433              : 
    5434            3 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5435            3 :             runPerDesInput.title = newName;
    5436            3 :             runPerDesInput.periodType = "User Selected WeatherFile RunPeriod (Design)";
    5437              : 
    5438              :             // set the start and end day of month from user input
    5439            3 :             runPerDesInput.startMonth = int(ipsc->rNumericArgs(1));
    5440            3 :             runPerDesInput.startDay = int(ipsc->rNumericArgs(2));
    5441            3 :             runPerDesInput.endMonth = int(ipsc->rNumericArgs(3));
    5442            3 :             runPerDesInput.endDay = int(ipsc->rNumericArgs(4));
    5443              : 
    5444            3 :             switch (runPerDesInput.startMonth) {
    5445            3 :             case 1:
    5446              :             case 3:
    5447              :             case 5:
    5448              :             case 7:
    5449              :             case 8:
    5450              :             case 10:
    5451              :             case 12: {
    5452            3 :                 if (runPerDesInput.startDay > 31) {
    5453            0 :                     ShowSevereError(state,
    5454            0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5455            0 :                                            ipsc->cCurrentModuleObject,
    5456            0 :                                            runPerDesInput.title,
    5457            0 :                                            ipsc->cNumericFieldNames(2),
    5458            0 :                                            runPerDesInput.startDay));
    5459            0 :                     ErrorsFound = true;
    5460              :                 }
    5461            3 :             } break;
    5462            0 :             case 4:
    5463              :             case 6:
    5464              :             case 9:
    5465              :             case 11: {
    5466            0 :                 if (runPerDesInput.startDay > 30) {
    5467            0 :                     ShowSevereError(state,
    5468            0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5469            0 :                                            ipsc->cCurrentModuleObject,
    5470            0 :                                            runPerDesInput.title,
    5471            0 :                                            ipsc->cNumericFieldNames(2),
    5472            0 :                                            runPerDesInput.startDay));
    5473            0 :                     ErrorsFound = true;
    5474              :                 }
    5475            0 :             } break;
    5476            0 :             case 2: {
    5477            0 :                 if (runPerDesInput.startDay > 28 + state.dataWeather->LeapYearAdd) {
    5478            0 :                     ShowSevereError(state,
    5479            0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5480            0 :                                            ipsc->cCurrentModuleObject,
    5481            0 :                                            runPerDesInput.title,
    5482            0 :                                            ipsc->cNumericFieldNames(2),
    5483            0 :                                            runPerDesInput.startDay));
    5484            0 :                     ErrorsFound = true;
    5485              :                 }
    5486            0 :             } break;
    5487            0 :             default: {
    5488            0 :                 ShowSevereError(state,
    5489            0 :                                 format("{}: object={} {} invalid (Month) [{}]",
    5490            0 :                                        ipsc->cCurrentModuleObject,
    5491            0 :                                        runPerDesInput.title,
    5492            0 :                                        ipsc->cNumericFieldNames(1),
    5493            0 :                                        runPerDesInput.startMonth));
    5494            0 :                 ErrorsFound = true;
    5495            0 :             } break;
    5496              :             } // switch
    5497              : 
    5498            3 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5499            0 :                 runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5500              :             } else {
    5501            3 :                 runPerDesInput.dayOfWeek = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    5502            3 :                 if (runPerDesInput.dayOfWeek < 1 || runPerDesInput.dayOfWeek == 8) {
    5503            0 :                     ShowWarningError(state,
    5504            0 :                                      format("{}: object={} {} invalid (Day of Week) [{} for Start is not Valid, Monday will be Used.",
    5505            0 :                                             ipsc->cCurrentModuleObject,
    5506            0 :                                             runPerDesInput.title,
    5507            0 :                                             ipsc->cAlphaFieldNames(1),
    5508            0 :                                             ipsc->cAlphaArgs(1)));
    5509            0 :                     runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5510              :                 }
    5511              :             }
    5512              : 
    5513              :             BooleanSwitch b;
    5514            3 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5515            0 :                 runPerDesInput.useDST = true;
    5516            3 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5517            3 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5518              :             } else {
    5519            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5520            0 :                 ErrorsFound = true;
    5521              :             }
    5522              : 
    5523            3 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5524            0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5525            3 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5526            3 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5527              :             } else {
    5528            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5529            0 :                 ErrorsFound = true;
    5530              :             }
    5531              : 
    5532              :             // calculate the annual start and end days from the user inputted month and day
    5533            3 :             runPerDesInput.startJulianDate = General::OrdinalDay(runPerDesInput.startMonth, runPerDesInput.startDay, state.dataWeather->LeapYearAdd);
    5534            3 :             runPerDesInput.endJulianDate = General::OrdinalDay(runPerDesInput.endMonth, runPerDesInput.endDay, state.dataWeather->LeapYearAdd);
    5535            3 :             if (runPerDesInput.startJulianDate <= runPerDesInput.endJulianDate) {
    5536            3 :                 runPerDesInput.totalDays = (runPerDesInput.endJulianDate - runPerDesInput.startJulianDate + 1) * runPerDesInput.numSimYears;
    5537              :             } else {
    5538            0 :                 runPerDesInput.totalDays = (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - runPerDesInput.startJulianDate + 1 +
    5539            0 :                                             runPerDesInput.endJulianDate) *
    5540            0 :                                            runPerDesInput.numSimYears;
    5541              :             }
    5542            3 :             runPerDesInput.monWeekDay = 0;
    5543            3 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5544            3 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5545            3 :                 SetupWeekDaysByMonth(state,
    5546              :                                      runPeriodDesignInput1.startMonth,
    5547              :                                      runPeriodDesignInput1.startDay,
    5548              :                                      runPeriodDesignInput1.dayOfWeek,
    5549            3 :                                      runPeriodDesignInput1.monWeekDay);
    5550              :             }
    5551            3 :         }
    5552              : 
    5553            3 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileConditionType";
    5554            5 :         for (int i = 1; i <= RPD2; ++i) {
    5555              :             int NumAlphas;   // Number of alphas being input
    5556              :             int NumNumerics; // Number of Numerics being input
    5557              :             int IOStat;      // IO Status when calling get input subroutine
    5558            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5559            2 :                                                                      ipsc->cCurrentModuleObject,
    5560              :                                                                      i,
    5561            2 :                                                                      ipsc->cAlphaArgs,
    5562              :                                                                      NumAlphas,
    5563            2 :                                                                      ipsc->rNumericArgs,
    5564              :                                                                      NumNumerics,
    5565              :                                                                      IOStat,
    5566            2 :                                                                      ipsc->lNumericFieldBlanks,
    5567            2 :                                                                      ipsc->lAlphaFieldBlanks,
    5568            2 :                                                                      ipsc->cAlphaFieldNames,
    5569            2 :                                                                      ipsc->cNumericFieldNames);
    5570            2 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5571              : 
    5572            2 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5573            4 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5574            4 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5575            6 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5576            4 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5577            0 :                 ShowSevereDuplicateName(state, eoh);
    5578            0 :                 ErrorsFound = true;
    5579              :             }
    5580              : 
    5581            2 :             ++Count;
    5582            2 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5583            2 :             runPerDesInput.title = ipsc->cAlphaArgs(1);
    5584            2 :             runPerDesInput.periodType = "User Selected WeatherFile Typical/Extreme Period (Design)=" + ipsc->cAlphaArgs(2);
    5585              : 
    5586              :             // Period Selection
    5587            2 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5588            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
    5589            0 :                 ErrorsFound = true;
    5590              :             } else {
    5591            2 :                 int WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue);
    5592            2 :                 if (WhichPeriod == 0) {
    5593            0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue1);
    5594              :                     if (WhichPeriod != 0) {
    5595              :                     }
    5596              :                 }
    5597            2 :                 if (WhichPeriod == 0) {
    5598            0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue2);
    5599            0 :                     if (WhichPeriod != 0) {
    5600            0 :                         ShowWarningError(state,
    5601            0 :                                          format("{}: object={} {}={} matched to {}",
    5602            0 :                                                 ipsc->cCurrentModuleObject,
    5603            0 :                                                 runPerDesInput.title,
    5604            0 :                                                 ipsc->cAlphaFieldNames(2),
    5605            0 :                                                 ipsc->cAlphaArgs(2),
    5606            0 :                                                 state.dataWeather->TypicalExtremePeriods(WhichPeriod).MatchValue2));
    5607              :                     }
    5608              :                 }
    5609            2 :                 if (WhichPeriod == 0) {
    5610            0 :                     ShowSevereError(state,
    5611            0 :                                     format("{}: object={} {} invalid (not on Weather File)={}",
    5612            0 :                                            ipsc->cCurrentModuleObject,
    5613            0 :                                            runPerDesInput.title,
    5614            0 :                                            ipsc->cAlphaFieldNames(2),
    5615            0 :                                            ipsc->cAlphaArgs(2)));
    5616            0 :                     ErrorsFound = true;
    5617              :                 } else {
    5618            2 :                     auto const &typicalExtPer = state.dataWeather->TypicalExtremePeriods(WhichPeriod);
    5619            2 :                     runPerDesInput.startDay = typicalExtPer.StartDay;
    5620            2 :                     runPerDesInput.startMonth = typicalExtPer.StartMonth;
    5621            2 :                     runPerDesInput.startJulianDate = typicalExtPer.StartJDay;
    5622            2 :                     runPerDesInput.endDay = typicalExtPer.EndDay;
    5623            2 :                     runPerDesInput.endMonth = typicalExtPer.EndMonth;
    5624            2 :                     runPerDesInput.endJulianDate = typicalExtPer.EndJDay;
    5625            2 :                     runPerDesInput.totalDays = typicalExtPer.TotalDays;
    5626              :                 }
    5627              :             }
    5628              : 
    5629            2 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5630            0 :                 runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5631              :             } else {
    5632            2 :                 runPerDesInput.dayOfWeek = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(3));
    5633            2 :                 if (runPerDesInput.dayOfWeek < (int)Sched::DayType::Sunday || runPerDesInput.dayOfWeek == (int)Sched::DayType::Holiday) {
    5634              :                     // Sunday-Saturday, SummerDesignDay, WinterDesignDay, CustomDay1, and CustomDay2 are all valid. Holiday is not valid.
    5635              :                     // The input processor should trap invalid key choices, so this should never trip.
    5636            0 :                     assert(false);
    5637              :                 }
    5638              :             }
    5639              : 
    5640              :             BooleanSwitch b;
    5641            2 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5642            0 :                 runPerDesInput.useDST = true;
    5643            2 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5644            2 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5645              :             } else {
    5646            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5647            0 :                 ErrorsFound = true;
    5648              :             }
    5649              : 
    5650            2 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5651            0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5652            2 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5653            2 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5654              :             } else {
    5655            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5656            0 :                 ErrorsFound = true;
    5657              :             }
    5658            2 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5659            2 :             runPeriodDesignInput1.monWeekDay = 0;
    5660            2 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5661            2 :                 SetupWeekDaysByMonth(state,
    5662              :                                      runPeriodDesignInput1.startMonth,
    5663              :                                      runPeriodDesignInput1.startDay,
    5664              :                                      runPeriodDesignInput1.dayOfWeek,
    5665            2 :                                      runPeriodDesignInput1.monWeekDay);
    5666              :             }
    5667            2 :         }
    5668            3 :     }
    5669              : 
    5670          776 :     void GetSpecialDayPeriodData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5671              :     {
    5672              : 
    5673              :         // SUBROUTINE INFORMATION:
    5674              :         //       AUTHOR         Linda Lawrie
    5675              :         //       DATE WRITTEN   June 2000
    5676              : 
    5677              :         // PURPOSE OF THIS SUBROUTINE:
    5678              :         // This subroutine reads any special day period data from the IDF and
    5679              :         // processes it into the data structure that will drive the values
    5680              :         // in the SpecialDayTypes array.
    5681              : 
    5682              :         // METHODOLOGY EMPLOYED:
    5683              :         // Processes the following IDD definition:
    5684              :         // SpecialDayPeriod,
    5685              :         //      \memo This object sets up holidays/special days to be used during weather file
    5686              :         //      \memo run periods.  (These are not used with DesignDay objects.)
    5687              :         //      \memo Depending on the value in the run period, days on the weather file may also
    5688              :         //      \memo be used.  However, the weather file specification will take precedence over
    5689              :         //      \memo any specification shown here.  (No error message on duplicate days or overlapping
    5690              :         //      \memo days).
    5691              :         //  A1, \field Holiday Name
    5692              :         //  A2, \field StartDate
    5693              :         //      \memo  Dates can be several formats:
    5694              :         //      \memo  <number>/<number>  (month/day)
    5695              :         //      \memo  <number> Month
    5696              :         //      \memo  Month <number>
    5697              :         //      \memo Months are January, February, March, April, May, June, July, August, September, October, November, December
    5698              :         //      \memo Months can be the first 3 letters of the month
    5699              :         //        \note will eventually allow: 3 Monday April (meaning 3rd Monday in April)
    5700              :         //  N1, \field duration (number of days)
    5701              :         //  A3; \field SpecialDayType
    5702              :         //        \note SpecialDayType selects the schedules appropriate for each day so labeled
    5703              :         //        \type choice
    5704              :         //        \key Holiday
    5705              :         //        \key SummerDesignDay
    5706              :         //        \key WinterDesignDay
    5707              :         //        \key CustomDay1
    5708              :         //        \key CustomDay2
    5709              : 
    5710          776 :         constexpr std::string_view routineName = "GetSpecialDayPeriodData";
    5711              : 
    5712          776 :         auto const &ipsc = state.dataIPShortCut;
    5713          776 :         ipsc->cCurrentModuleObject = "RunPeriodControl:SpecialDays";
    5714          776 :         int NumSpecDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5715              :         int Count;
    5716          776 :         if (allocated(state.dataWeather->SpecialDays)) { // EPW already allocated the array
    5717          768 :             Count = state.dataWeather->NumSpecialDays - NumSpecDays + 1;
    5718              :         } else {
    5719            8 :             state.dataWeather->SpecialDays.allocate(NumSpecDays);
    5720            8 :             state.dataWeather->NumSpecialDays = NumSpecDays;
    5721            8 :             Count = 1;
    5722              :         }
    5723              : 
    5724          776 :         Array1D_string AlphArray(3);
    5725              :         int NumAlphas;
    5726          776 :         Array1D<Real64> Duration(1);
    5727              :         int NumNumbers;
    5728              :         int IOStat;
    5729              : 
    5730         2085 :         for (int i = 1; i <= NumSpecDays; ++i, ++Count) {
    5731              : 
    5732         2618 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    5733         1309 :                 state, ipsc->cCurrentModuleObject, i, AlphArray, NumAlphas, Duration, NumNumbers, IOStat);
    5734              : 
    5735         1309 :             auto &specialDay = state.dataWeather->SpecialDays(Count);
    5736              : 
    5737         1309 :             specialDay.Name = AlphArray(1);
    5738         1309 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, specialDay.Name};
    5739              : 
    5740              :             int PMonth;
    5741              :             int PDay;
    5742              :             int PWeekDay;
    5743              :             DateType dateType;
    5744         1309 :             General::ProcessDateString(state, AlphArray(2), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    5745         1309 :             if (dateType == DateType::MonthDay) {
    5746          530 :                 specialDay.dateType = dateType;
    5747          530 :                 specialDay.Month = PMonth;
    5748          530 :                 specialDay.Day = PDay;
    5749          530 :                 specialDay.WeekDay = 0;
    5750          530 :                 specialDay.CompDate = PMonth * 32 + PDay;
    5751          530 :                 specialDay.WthrFile = false;
    5752          779 :             } else if (dateType != DateType::Invalid) {
    5753          779 :                 specialDay.dateType = dateType;
    5754          779 :                 specialDay.Month = PMonth;
    5755          779 :                 specialDay.Day = PDay;
    5756          779 :                 specialDay.WeekDay = PWeekDay;
    5757          779 :                 specialDay.CompDate = 0;
    5758          779 :                 specialDay.WthrFile = false;
    5759              :             } else {
    5760            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    5761            0 :                 ErrorsFound = true;
    5762              :             }
    5763              : 
    5764         1309 :             if (Duration(1) > 0) {
    5765         1309 :                 specialDay.Duration = int(Duration(1));
    5766              :             } else {
    5767            0 :                 ShowSevereError(
    5768            0 :                     state, format("{}: {} Invalid {}={:.0T}", ipsc->cCurrentModuleObject, AlphArray(1), ipsc->cNumericFieldNames(1), Duration(1)));
    5769            0 :                 ErrorsFound = true;
    5770              :             }
    5771              : 
    5772         1309 :             int DayType = getEnumValue(Sched::dayTypeNamesUC, AlphArray(3));
    5773         1309 :             if (DayType == 0) {
    5774            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), AlphArray(3));
    5775            0 :                 ErrorsFound = true;
    5776              :             } else {
    5777         1309 :                 specialDay.DayType = DayType;
    5778              :             }
    5779              :         }
    5780          776 :     }
    5781              : 
    5782            7 :     void CalcSpecialDayTypes(EnergyPlusData &state)
    5783              :     {
    5784              : 
    5785              :         // SUBROUTINE INFORMATION:
    5786              :         //       AUTHOR         Linda Lawrie
    5787              :         //       DATE WRITTEN   June 2000
    5788              : 
    5789              :         // PURPOSE OF THIS SUBROUTINE:
    5790              :         // This subroutine creates the array of Special Day types used during
    5791              :         // the simulation.
    5792              : 
    5793              :         // METHODOLOGY EMPLOYED:
    5794              :         // Sets up the SpecialDayTypes array that then is used during simulation.
    5795              : 
    5796            7 :         state.dataWeather->SpecialDayTypes = 0; // Initialize/Reset Special Day Types array
    5797              : 
    5798           37 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    5799           30 :             auto const &specialDay = state.dataWeather->SpecialDays(i);
    5800           30 :             if (specialDay.WthrFile) {
    5801            0 :                 continue;
    5802              :             }
    5803              : 
    5804           30 :             int Warn = 0;
    5805              : 
    5806           30 :             int JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd) - 1;
    5807              : 
    5808           60 :             for (int j = 1; j <= specialDay.Duration; ++j) {
    5809           30 :                 ++JDay;
    5810           30 :                 if (JDay > 366) {
    5811            0 :                     ShowWarningError(state, format("SpecialDay={} causes index of more than 366, ignoring those beyond 366", specialDay.Name));
    5812              :                 } else {
    5813           30 :                     if (state.dataWeather->SpecialDayTypes(JDay) != 0 && Warn == 0) {
    5814            0 :                         ShowWarningError(state, format("SpecialDay={} attempted overwrite of previous set special day", specialDay.Name));
    5815            0 :                         Warn = 1;
    5816           30 :                     } else if (state.dataWeather->SpecialDayTypes(JDay) == 0) {
    5817           30 :                         state.dataWeather->SpecialDayTypes(JDay) = specialDay.DayType;
    5818              :                     }
    5819              :                 }
    5820              :             }
    5821              :         }
    5822            7 :     }
    5823              : 
    5824          776 :     void GetDSTData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5825              :     {
    5826              : 
    5827              :         // SUBROUTINE INFORMATION:
    5828              :         //       AUTHOR         Linda Lawrie
    5829              :         //       DATE WRITTEN   August 2000
    5830              : 
    5831              :         // PURPOSE OF THIS SUBROUTINE:
    5832              :         // This subroutine gets a possible "Daylight Saving Period" from the IDF.  Using this
    5833              :         // will overwrite any prior DST data.
    5834              : 
    5835              :         // METHODOLOGY EMPLOYED:
    5836              :         // Processes the following IDD definition:
    5837              :         // DaylightSavingPeriod,
    5838              :         //      \memo This object sets up the Daylight Saving period for any RunPeriod.
    5839              :         //      \memo Ignores any DaylightSavingperiod values on the weather file and uses this definition.
    5840              :         //      \memo (These are not used with DesignDay objects.)
    5841              :         //  A1, \field StartDate
    5842              :         //  A2, \field EndDate
    5843              :         //      \memo  Dates can be several formats:
    5844              :         //      \memo  <number>/<number>  (month/day)
    5845              :         //      \memo  <number> <Month>
    5846              :         //      \memo  <Month> <number>
    5847              :         //      \memo <Nth> <Weekday> in <Month)
    5848              :         //      \memo Last <WeekDay> in <Month>
    5849              :         //      \memo <Month> can be January, February, March, April, May, June, July, August, September,
    5850              :         // October, November, December
    5851              :         //      \memo Months can be the first 3 letters of the month
    5852              :         //      \memo <Weekday> can be Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
    5853              :         //      \memo <Nth> can be 1 or 1st, 2 or 2nd, etc. up to 5(?)
    5854              : 
    5855          776 :         constexpr std::string_view routineName = "GetDSTData";
    5856              : 
    5857          776 :         auto const &ipsc = state.dataIPShortCut;
    5858          776 :         ipsc->cCurrentModuleObject = "RunPeriodControl:DaylightSavingTime";
    5859          776 :         int NumFound = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5860              : 
    5861          776 :         if (NumFound == 1) {
    5862              :             int NumAlphas;
    5863              :             int IOStat;
    5864              :             int NumNumbers;
    5865          366 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5866          183 :                                                                      ipsc->cCurrentModuleObject,
    5867              :                                                                      1,
    5868          183 :                                                                      ipsc->cAlphaArgs,
    5869              :                                                                      NumAlphas,
    5870          183 :                                                                      ipsc->rNumericArgs,
    5871              :                                                                      NumNumbers,
    5872              :                                                                      IOStat,
    5873          183 :                                                                      ipsc->lNumericFieldBlanks,
    5874          183 :                                                                      ipsc->lAlphaFieldBlanks,
    5875          183 :                                                                      ipsc->cAlphaFieldNames,
    5876          183 :                                                                      ipsc->cNumericFieldNames);
    5877              : 
    5878          183 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    5879              : 
    5880          183 :             if (NumAlphas != 2) {
    5881            0 :                 ShowSevereError(state, format("{}: Insufficient fields, must have Start AND End Dates", ipsc->cCurrentModuleObject));
    5882            0 :                 ErrorsFound = true;
    5883              :             } else { // Correct number of arguments
    5884          366 :                 General::ProcessDateString(state,
    5885          183 :                                            ipsc->cAlphaArgs(1),
    5886          183 :                                            state.dataWeather->IDFDST.StMon,
    5887          183 :                                            state.dataWeather->IDFDST.StDay,
    5888          183 :                                            state.dataWeather->IDFDST.StWeekDay,
    5889          183 :                                            state.dataWeather->IDFDST.StDateType,
    5890              :                                            ErrorsFound);
    5891          183 :                 if (state.dataWeather->IDFDST.StDateType == DateType::Invalid) {
    5892            0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    5893            0 :                     ErrorsFound = true;
    5894              :                 }
    5895          366 :                 General::ProcessDateString(state,
    5896          183 :                                            ipsc->cAlphaArgs(2),
    5897          183 :                                            state.dataWeather->IDFDST.EnMon,
    5898          183 :                                            state.dataWeather->IDFDST.EnDay,
    5899          183 :                                            state.dataWeather->IDFDST.EnWeekDay,
    5900          183 :                                            state.dataWeather->IDFDST.EnDateType,
    5901              :                                            ErrorsFound);
    5902          183 :                 if (state.dataWeather->IDFDST.EnDateType == DateType::Invalid) {
    5903            0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    5904            0 :                     ErrorsFound = true;
    5905              :                 }
    5906          183 :                 state.dataWeather->IDFDaylightSaving = true;
    5907              :             }
    5908          593 :         } else if (NumFound > 1) {
    5909            0 :             ShowSevereError(state, format("{}: Too many objects in Input File, only one allowed.", ipsc->cCurrentModuleObject));
    5910            0 :             ErrorsFound = true;
    5911              :         }
    5912          776 :     }
    5913              : 
    5914          801 :     void GetDesignDayData(EnergyPlusData &state,
    5915              :                           int TotDesDays, // Total number of Design days to Setup
    5916              :                           bool &ErrorsFound)
    5917              :     {
    5918              : 
    5919              :         // SUBROUTINE INFORMATION:
    5920              :         //       AUTHOR         Richard Liesen
    5921              :         //       DATE WRITTEN   September 1997
    5922              : 
    5923              :         // PURPOSE OF THIS SUBROUTINE:
    5924              :         // This subroutine retrieves the design day info from user input file
    5925              :         //  which is later to be used in the Setup Design Day Routine.
    5926              : 
    5927              :         // REFERENCES:
    5928              :         // SizingPeriod:DesignDay,
    5929              :         //   A1, \field Name
    5930              :         //   N1,  \field Month
    5931              :         //   N2,  \field Day of Month
    5932              :         //   A2,  \field Day Type
    5933              :         //   N3,  \field Maximum Dry-Bulb Temperature
    5934              :         //   N4,  \field Daily Dry-Bulb Temperature Range
    5935              :         //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    5936              :         //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    5937              :         //   A5,  \field Humidity Condition Type
    5938              :         //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    5939              :         //   A6,  \field Humidity Condition Day Schedule Name
    5940              :         //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    5941              :         //   N7,  \field Enthalpy at Maximum Dry-Bulb  !will require units transition.
    5942              :         //   N8,  \field Daily Wet-Bulb Temperature Range
    5943              :         //   N9,  \field Barometric Pressure
    5944              :         //   N10, \field Wind Speed
    5945              :         //   N11, \field Wind Direction
    5946              :         //   A7,  \field Rain Indicator
    5947              :         //   A8,  \field Snow Indicator
    5948              :         //   A9,  \field Daylight Saving Time Indicator
    5949              :         //   A10, \field Solar Model Indicator
    5950              :         //   A11, \field Beam Solar Day Schedule Name
    5951              :         //   A12, \field Diffuse Solar Day Schedule Name
    5952              :         //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    5953              :         //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    5954              :         //   N14; \field Sky Clearness
    5955              : 
    5956              :         static constexpr std::array<std::string_view, static_cast<int>(DesDayHumIndType::Num)> DesDayHumIndTypeStringRep = {
    5957              :             "Wetbulb [C]",
    5958              :             "Dewpoint [C]",
    5959              :             "Enthalpy [J/kg]",
    5960              :             "Humidity Ratio []",
    5961              :             "Schedule []",
    5962              :             "WetBulbProfileDefaultMultipliers []",
    5963              :             "WetBulbProfileDifferenceSchedule []",
    5964              :             "WetBulbProfileMultiplierSchedule []"};
    5965              : 
    5966              :         // Below are the 2009 fractions, HOF, Chap 14, Table 6
    5967              :         static constexpr std::array<Real64, 24> DefaultTempRangeMult = {0.88, 0.92, 0.95, 0.98, 1.0,  0.98, 0.91, 0.74, 0.55, 0.38, 0.23, 0.13,
    5968              :                                                                         0.05, 0.00, 0.00, 0.06, 0.14, 0.24, 0.39, 0.50, 0.59, 0.68, 0.75, 0.82};
    5969              : 
    5970              :         static constexpr std::string_view routineName = "GetDesignDayData";
    5971              : 
    5972              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5973              :         Constant::Units unitType;
    5974              : 
    5975          801 :         state.dataWeather->DesDayInput.allocate(TotDesDays); // Allocate the array to the # of DD's
    5976          801 :         state.dataWeather->desDayMods.allocate(TotDesDays);
    5977         2478 :         for (int iDD = 1; iDD <= TotDesDays; ++iDD) {
    5978         1677 :             state.dataWeather->desDayMods(iDD).allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    5979              :         }
    5980              : 
    5981          801 :         state.dataWeather->spSiteSchedules.dimension(TotDesDays, Weather::SPSiteSchedules());
    5982              : 
    5983          801 :         if (state.dataSysVars->ReverseDD && TotDesDays <= 1) {
    5984            0 :             ShowSevereError(state, "GetDesignDayData: Reverse Design Day requested but # Design Days <=1");
    5985              :         }
    5986              : 
    5987          801 :         auto const &ipsc = state.dataIPShortCut;
    5988          801 :         ipsc->cCurrentModuleObject = "SizingPeriod:DesignDay";
    5989         2478 :         for (int iDesDay = 1; iDesDay <= TotDesDays; ++iDesDay) {
    5990              : 
    5991              :             int EnvrnNum;
    5992         1677 :             if (!state.dataSysVars->ReverseDD) {
    5993         1677 :                 EnvrnNum = iDesDay;
    5994            0 :             } else if (iDesDay == 1 && TotDesDays > 1) {
    5995            0 :                 EnvrnNum = 2;
    5996            0 :             } else if (iDesDay == 2) {
    5997            0 :                 EnvrnNum = 1;
    5998              :             } else {
    5999            0 :                 EnvrnNum = iDesDay;
    6000              :             }
    6001              : 
    6002              :             // Call Input Get routine to retrieve design day data
    6003         1677 :             bool MaxDryBulbEntered = false;
    6004         1677 :             bool PressureEntered = false;
    6005              :             int NumAlpha;    // Number of material alpha names being passed
    6006              :             int NumNumerics; // Number of material properties being passed
    6007              :             int IOStat;      // IO Status when calling get input subroutine
    6008         3354 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6009         1677 :                                                                      ipsc->cCurrentModuleObject,
    6010              :                                                                      iDesDay,
    6011         1677 :                                                                      ipsc->cAlphaArgs,
    6012              :                                                                      NumAlpha,
    6013         1677 :                                                                      ipsc->rNumericArgs,
    6014              :                                                                      NumNumerics,
    6015              :                                                                      IOStat,
    6016         1677 :                                                                      ipsc->lNumericFieldBlanks,
    6017         1677 :                                                                      ipsc->lAlphaFieldBlanks,
    6018         1677 :                                                                      ipsc->cAlphaFieldNames,
    6019         1677 :                                                                      ipsc->cNumericFieldNames);
    6020              : 
    6021         1677 :             auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    6022         1677 :             auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    6023         1677 :             desDayInput.Title = ipsc->cAlphaArgs(1); // Environment name
    6024         1677 :             envCurr.Title = desDayInput.Title;
    6025              : 
    6026         1677 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, desDayInput.Title};
    6027              : 
    6028              :             //   N3,  \field Maximum Dry-Bulb Temperature
    6029              :             //   N4,  \field Daily Dry-Bulb Temperature Range
    6030              :             //   N9,  \field Barometric Pressure
    6031              :             //   N10, \field Wind Speed
    6032              :             //   N11, \field Wind Direction
    6033         1677 :             desDayInput.MaxDryBulb = ipsc->rNumericArgs(3); // Maximum Dry-Bulb Temperature (C)
    6034         1677 :             MaxDryBulbEntered = !ipsc->lNumericFieldBlanks(3);
    6035         1677 :             desDayInput.DailyDBRange = ipsc->rNumericArgs(4); // Daily dry-bulb temperature range (deltaC)
    6036         1677 :             desDayInput.PressBarom = ipsc->rNumericArgs(9);   // Atmospheric/Barometric Pressure (Pascals)
    6037         1677 :             PressureEntered = !ipsc->lNumericFieldBlanks(9);
    6038         1677 :             desDayInput.PressureEntered = PressureEntered;
    6039         1677 :             desDayInput.WindSpeed = ipsc->rNumericArgs(10);           // Wind Speed (m/s)
    6040         1677 :             desDayInput.WindDir = mod(ipsc->rNumericArgs(11), 360.0); // Wind Direction
    6041              :             // (degrees clockwise from North, N=0, E=90, S=180, W=270)
    6042              :             //   N1,  \field Month
    6043              :             //   N2,  \field Day of Month
    6044              :             //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    6045              :             //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    6046              :             //   N8,  \field Daily Wet-Bulb Temperature Range
    6047         1677 :             desDayInput.Month = int(ipsc->rNumericArgs(1));      // Month of Year ( 1 - 12 )
    6048         1677 :             desDayInput.DayOfMonth = int(ipsc->rNumericArgs(2)); // Day of Month ( 1 - 31 )
    6049         1677 :             desDayInput.TauB = ipsc->rNumericArgs(12);           // beam tau >= 0
    6050         1677 :             desDayInput.TauD = ipsc->rNumericArgs(13);           // diffuse tau >= 0
    6051         1677 :             desDayInput.DailyWBRange = ipsc->rNumericArgs(8);    // Daily wet-bulb temperature range (deltaC)
    6052              : 
    6053              :             //   N14; \field Sky Clearness
    6054         1677 :             desDayInput.SkyClear = ipsc->rNumericArgs(14); // Sky Clearness (0 to 1)
    6055              : 
    6056              :             //   N15, \field Maximum Warmup Days Between Sizing Periods
    6057         1677 :             if (ipsc->lNumericFieldBlanks(15)) {
    6058              :                 // Default to -1 if not input
    6059         1677 :                 desDayInput.maxWarmupDays = -1;
    6060              :             } else {
    6061            0 :                 desDayInput.maxWarmupDays = int(ipsc->rNumericArgs(15));
    6062              :             }
    6063              :             //   A13, \field Begin Environment Reset Mode
    6064         1677 :             if (ipsc->lAlphaFieldBlanks(13)) {
    6065         1677 :                 desDayInput.suppressBegEnvReset = false;
    6066              :             } else {
    6067            0 :                 if (Util::SameString(ipsc->cAlphaArgs(13), "FullResetAtBeginEnvironment")) {
    6068            0 :                     desDayInput.suppressBegEnvReset = false;
    6069            0 :                 } else if (Util::SameString(ipsc->cAlphaArgs(13), "SuppressThermalResetAtBeginEnvironment")) {
    6070            0 :                     desDayInput.suppressBegEnvReset = true;
    6071              :                 }
    6072              :             }
    6073              :             // for PerformancePrecisionTradeoffs
    6074         1677 :             if (state.dataEnvrn->forceBeginEnvResetSuppress) {
    6075            2 :                 desDayInput.suppressBegEnvReset = true;
    6076              :             }
    6077              :             //   A7,  \field Rain Indicator
    6078              :             BooleanSwitch b;
    6079              : 
    6080         1677 :             if (ipsc->lAlphaFieldBlanks(7)) {
    6081            6 :                 desDayInput.RainInd = 0;
    6082         1671 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    6083         1671 :                 desDayInput.RainInd = (int)b;
    6084              :             } else {
    6085            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7), "No");
    6086            0 :                 desDayInput.RainInd = 0;
    6087              :             }
    6088              : 
    6089              :             //   A8,  \field Snow Indicator
    6090         1677 :             if (ipsc->lAlphaFieldBlanks(8)) {
    6091            6 :                 desDayInput.SnowInd = 0;
    6092         1671 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    6093         1671 :                 desDayInput.SnowInd = (int)b;
    6094              :             } else {
    6095            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8), "No");
    6096            0 :                 desDayInput.SnowInd = 0;
    6097              :             }
    6098              : 
    6099              :             //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    6100              :             // check DB profile input
    6101         1677 :             if (ipsc->lAlphaFieldBlanks(3)) {
    6102         1541 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    6103          272 :             } else if ((desDayInput.dryBulbRangeType = static_cast<DesDayDryBulbRangeType>(
    6104          136 :                             getEnumValue(DesDayDryBulbRangeTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(3))))) != DesDayDryBulbRangeType::Invalid) {
    6105              :             } else {
    6106            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6107            0 :                 ErrorsFound = true;
    6108            0 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    6109              :             }
    6110              : 
    6111              :             // std::string units; // not used
    6112         1677 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    6113              :                 // units = "[]";
    6114            3 :                 unitType = Constant::Units::None;
    6115         1674 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    6116              :                 // units = "[deltaC]";
    6117            2 :                 unitType = Constant::Units::deltaC;
    6118         1672 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    6119              :                 // units = "[C]";
    6120            1 :                 unitType = Constant::Units::C;
    6121              :             }
    6122              : 
    6123         1677 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile && !MaxDryBulbEntered && ipsc->cAlphaArgs(3) != "invalid field") {
    6124            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(3), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6125            0 :                 ErrorsFound = true;
    6126              :             }
    6127              : 
    6128              :             // Assume either "multiplier" option will make full use of range...
    6129         1677 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Difference &&
    6130         1675 :                 desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    6131         1674 :                 Real64 testval = desDayInput.MaxDryBulb - desDayInput.DailyDBRange;
    6132         1674 :                 if (testval < -90.0 || testval > 70.0) {
    6133            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6134            0 :                     ShowContinueError(state, format("{} ({:.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(3), testval));
    6135            0 :                     ErrorsFound = true;
    6136              :                 }
    6137              :             }
    6138              : 
    6139              :             //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    6140         1677 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Default) {
    6141              :                 // Default dry-bulb temperature Range
    6142         1671 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    6143        41775 :                 for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    6144       269112 :                     for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    6145       229008 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    6146       229008 :                         Real64 WPrev = 1.0 - WNow;
    6147       229008 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutDryBulbTemp =
    6148       229008 :                             LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    6149              :                     }
    6150        40104 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    6151              :                 }
    6152              : 
    6153            6 :             } else if (ipsc->lAlphaFieldBlanks(4)) {
    6154            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaFieldNames(3), "SCHEDULE");
    6155            0 :                 ErrorsFound = true;
    6156            6 :             } else if ((desDayInput.tempRangeSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(4))) == nullptr) {
    6157            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    6158            0 :                 ErrorsFound = true;
    6159              : 
    6160              :             } else {
    6161            6 :                 std::vector<Real64> const &dayVals = desDayInput.tempRangeSched->getDayVals(state);
    6162            6 :                 auto &desDayModEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6163          150 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    6164          720 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    6165          576 :                         desDayModEnvrn(ts + 1, hr + 1).OutDryBulbTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6166              :                     }
    6167              :                 }
    6168              : 
    6169           12 :                 if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6170           12 :                               state.dataWeather->spSiteSchedNums.end(),
    6171           18 :                               desDayInput.tempRangeSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6172            4 :                     state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.tempRangeSched->Num);
    6173            8 :                     SetupOutputVariable(state,
    6174              :                                         "Sizing Period Site Drybulb Temperature Range Modifier Schedule Value",
    6175              :                                         unitType,
    6176            4 :                                         state.dataWeather->spSiteSchedules(EnvrnNum).OutDryBulbTemp,
    6177              :                                         OutputProcessor::TimeStepType::Zone,
    6178              :                                         OutputProcessor::StoreType::Average,
    6179            4 :                                         ipsc->cAlphaArgs(4));
    6180              :                 }
    6181              : 
    6182            6 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    6183            3 :                     if (!desDayInput.tempRangeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6184            0 :                         Sched::ShowSevereBadMinMax(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4), Clusive::In, 0.0, Clusive::In, 1.0);
    6185            0 :                         ErrorsFound = true;
    6186              :                     }
    6187            3 :                 } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) { // delta, must be > 0.0
    6188            2 :                     if (!desDayInput.tempRangeSched->checkMinVal(state, Clusive::In, 0.0)) {
    6189            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4), Clusive::In, 0.0);
    6190            0 :                         ErrorsFound = true;
    6191              :                     }
    6192              :                 }
    6193              : 
    6194            6 :                 auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6195            6 :                 Real64 testval = std::numeric_limits<Real64>::min();
    6196          150 :                 for (int iHr = 1; iHr <= Constant::iHoursInDay; ++iHr) {
    6197          720 :                     for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour; ++iTS) {
    6198          576 :                         if (desDayModsEnvrn(iTS, iHr).OutDryBulbTemp > testval) {
    6199           45 :                             testval = desDayModsEnvrn(iTS, iHr).OutDryBulbTemp;
    6200              :                         }
    6201              :                     }
    6202              :                 }
    6203              : 
    6204            6 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    6205            1 :                     if (MaxDryBulbEntered) {
    6206            0 :                         ShowWarningError(state, format("{}=\"{}\", data override.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6207            0 :                         ShowContinueError(state, format("..{}=[{:.2R}] will be overwritten.", ipsc->cNumericFieldNames(3), desDayInput.MaxDryBulb));
    6208            0 :                         ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3)));
    6209            0 :                         ShowContinueError(state, format("..with max value=[{:.2R}].", testval));
    6210              :                     }
    6211            1 :                     desDayInput.MaxDryBulb = testval;
    6212              :                 }
    6213              : 
    6214            6 :                 testval = desDayInput.MaxDryBulb - testval;
    6215            6 :                 if (testval < -90.0 || testval > 70.0) {
    6216            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6217              :                     // should this be cNumericFieldNames?
    6218            0 :                     ShowContinueError(state, format("{} = ({:.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(4), testval));
    6219            0 :                     ErrorsFound = true;
    6220              :                 }
    6221              :             }
    6222              : 
    6223              :             //   A5,  \field Humidity Condition Type
    6224         1677 :             desDayInput.HumIndType = static_cast<DesDayHumIndType>(getEnumValue(DesDayHumIndTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(5))));
    6225              : 
    6226         1677 :             switch (desDayInput.HumIndType) {
    6227         1651 :             case DesDayHumIndType::WetBulb: {
    6228              :                 //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    6229         1651 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6230            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6231            0 :                     ErrorsFound = true;
    6232              :                 } else {
    6233         1651 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6234              :                 }
    6235              : 
    6236         1651 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6237            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6238            0 :                     ShowContinueError(
    6239              :                         state,
    6240            0 :                         format("{} = {:.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - WetBulb", desDayInput.HumIndValue));
    6241            0 :                     ErrorsFound = true;
    6242              :                 }
    6243         1651 :             } break;
    6244              : 
    6245            5 :             case DesDayHumIndType::DewPoint: {
    6246            5 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6247            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6248            0 :                     ErrorsFound = true;
    6249              :                 } else {
    6250            5 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6251              :                 }
    6252              : 
    6253            5 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6254            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6255            0 :                     ShowContinueError(
    6256              :                         state,
    6257            0 :                         format("{} = {:.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - DewPoint", desDayInput.HumIndValue));
    6258            0 :                     ErrorsFound = true;
    6259              :                 }
    6260            5 :             } break;
    6261              : 
    6262            0 :             case DesDayHumIndType::HumRatio: {
    6263              :                 //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    6264            0 :                 if (ipsc->lNumericFieldBlanks(6)) {
    6265            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(6), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6266            0 :                     ErrorsFound = true;
    6267              :                 } else {
    6268            0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(6); // Humidity Indicating Conditions at Max Dry-Bulb
    6269              :                 }
    6270              : 
    6271            0 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 0.03) {
    6272            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6273            0 :                     ShowContinueError(
    6274              :                         state,
    6275            0 :                         format("{} = {:.2R} is out of range [0.0, 0.03]", ipsc->cAlphaFieldNames(5) + " - Humidity-Ratio", desDayInput.HumIndValue));
    6276            0 :                     ErrorsFound = true;
    6277              :                 }
    6278            0 :             } break;
    6279              : 
    6280            3 :             case DesDayHumIndType::Enthalpy: {
    6281              :                 //   N7,  \field Enthalpy at Maximum Dry-Bulb {J/kg}.
    6282            3 :                 if (ipsc->lNumericFieldBlanks(7)) {
    6283            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(7), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6284            0 :                     ErrorsFound = true;
    6285              :                 } else {
    6286            3 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(7); // Humidity Indicating Conditions at Max Dry-Bulb
    6287              :                 }
    6288              : 
    6289            3 :                 desDayInput.HumIndType = DesDayHumIndType::Enthalpy;
    6290            3 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 130000.0) {
    6291            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6292            0 :                     ShowContinueError(
    6293              :                         state,
    6294            0 :                         format("{} = {.0R} is out of range [0.0, 130000.0]", ipsc->cAlphaFieldNames(5) + " - Enthalpy", desDayInput.HumIndValue));
    6295            0 :                     ErrorsFound = true;
    6296              :                 }
    6297            3 :             } break;
    6298              : 
    6299            3 :             case DesDayHumIndType::RelHumSch: {
    6300              :                 // units = "[%]";
    6301            3 :                 unitType = Constant::Units::Perc;
    6302            3 :             } break;
    6303              : 
    6304            2 :             case DesDayHumIndType::WBProfMul: {
    6305              :                 // units = "[]";
    6306            2 :                 unitType = Constant::Units::None;
    6307            2 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6308            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6309            0 :                     ErrorsFound = true;
    6310              :                 } else {
    6311            2 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6312              :                 }
    6313            2 :             } break;
    6314              : 
    6315            1 :             case DesDayHumIndType::WBProfDif: {
    6316              :                 // units = "[]";
    6317            1 :                 unitType = Constant::Units::None;
    6318            1 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6319            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6320            0 :                     ErrorsFound = true;
    6321              :                 } else {
    6322            1 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6323              :                 }
    6324            1 :             } break;
    6325              : 
    6326           12 :             case DesDayHumIndType::WBProfDef: {
    6327           12 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6328            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6329            0 :                     ErrorsFound = true;
    6330              :                 } else {
    6331           12 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6332              :                 }
    6333           12 :             } break;
    6334              : 
    6335            0 :             default: {
    6336            0 :                 ShowWarningError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6337            0 :                 ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6338            0 :                 ShowContinueError(state, "WetBulb will be used. Maximum Dry Bulb will be used as WetBulb at Maximum Dry Bulb.");
    6339            0 :                 desDayInput.HumIndType = DesDayHumIndType::WetBulb;
    6340            0 :                 desDayInput.HumIndValue = ipsc->rNumericArgs(3);
    6341            0 :             } break;
    6342              :             } // switch (desDayInput.HumIndType)
    6343              : 
    6344              :             // resolve humidity schedule if needed
    6345              :             //   A6,  \field Humidity Condition Day Schedule Name
    6346         1677 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch || desDayInput.HumIndType == DesDayHumIndType::WBProfMul ||
    6347         1672 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6348            6 :                 if (ipsc->lAlphaFieldBlanks(6)) {
    6349            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6350            0 :                     ErrorsFound = true;
    6351            6 :                 } else if ((desDayInput.humIndSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(6))) == nullptr) {
    6352            0 :                     ShowWarningItemNotFound(state,
    6353              :                                             eoh,
    6354            0 :                                             ipsc->cAlphaFieldNames(6),
    6355            0 :                                             ipsc->cAlphaArgs(6),
    6356              :                                             "Default Humidity (constant for day using Humidity Indicator Temp).");
    6357              :                     // reset HumIndType ?
    6358              :                 } else {
    6359            6 :                     std::vector<Real64> const &dayVals = desDayInput.humIndSched->getDayVals(state);
    6360            6 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6361          150 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    6362          720 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    6363          576 :                             desDayModsEnvrn(ts + 1, hr + 1).OutRelHum = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6364              :                         }
    6365              :                     }
    6366              : 
    6367           12 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6368           12 :                                   state.dataWeather->spSiteSchedNums.end(),
    6369           18 :                                   desDayInput.humIndSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6370            5 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.humIndSched->Num);
    6371           10 :                         SetupOutputVariable(state,
    6372              :                                             "Sizing Period Site Humidity Condition Schedule Value",
    6373              :                                             unitType,
    6374            5 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).OutRelHum,
    6375              :                                             OutputProcessor::TimeStepType::Zone,
    6376              :                                             OutputProcessor::StoreType::Average,
    6377            5 :                                             ipsc->cAlphaArgs(6));
    6378              :                     }
    6379              : 
    6380            6 :                     switch (desDayInput.HumIndType) {
    6381            3 :                     case DesDayHumIndType::RelHumSch: {
    6382            3 :                         if (!desDayInput.humIndSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 100.0)) {
    6383            0 :                             Sched::ShowSevereBadMinMax(
    6384            0 :                                 state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 100.0);
    6385            0 :                             ErrorsFound = true;
    6386              :                         }
    6387            3 :                     } break;
    6388            2 :                     case DesDayHumIndType::WBProfMul: {
    6389              :                         // multiplier: use schedule value, check 0 <= v <= 1
    6390            2 :                         if (!desDayInput.humIndSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6391            0 :                             Sched::ShowSevereBadMinMax(
    6392            0 :                                 state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 1.0);
    6393            0 :                             ErrorsFound = true;
    6394              :                         }
    6395            2 :                     } break;
    6396            1 :                     case DesDayHumIndType::WBProfDif: {
    6397            1 :                         if (!desDayInput.humIndSched->checkMinVal(state, Clusive::In, 0.0)) {
    6398            0 :                             Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0);
    6399            0 :                             ErrorsFound = true;
    6400              :                         }
    6401            1 :                     } break;
    6402            0 :                     default: {
    6403            0 :                     } break;
    6404              :                     } // switch (desDayInput.HumIndType)
    6405              :                 } // if (desDayInput.HumIndSchPtr == 0)
    6406              : 
    6407         1677 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    6408              :                 // re WetBulbProfileDefaultMultipliers
    6409           12 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    6410          300 :                 for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    6411         1440 :                     for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    6412         1152 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    6413         1152 :                         Real64 WPrev = 1.0 - WNow;
    6414         1152 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutRelHum = LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    6415              :                     }
    6416          288 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    6417              :                 }
    6418              :             }
    6419              : 
    6420              :             // verify that design WB or DP <= design DB
    6421         1677 :             if (desDayInput.HumIndType == DesDayHumIndType::DewPoint || desDayInput.HumIndType == DesDayHumIndType::WetBulb ||
    6422           21 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::WBProfDef ||
    6423            7 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6424         1671 :                 if (desDayInput.HumIndValue > desDayInput.MaxDryBulb) {
    6425            0 :                     ShowWarningError(state, format("{}=\"{}\", range check data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6426            0 :                     ShowContinueError(state,
    6427            0 :                                       format("..Humidity Indicator Temperature at Max Temperature={:.1R} > Max DryBulb={:.1R}",
    6428            0 :                                              desDayInput.HumIndValue,
    6429            0 :                                              desDayInput.MaxDryBulb));
    6430            0 :                     ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6431            0 :                     ShowContinueError(state, "..Conditions for day will be set to Relative Humidity = 100%");
    6432            0 :                     if (desDayInput.HumIndType == DesDayHumIndType::DewPoint) {
    6433            0 :                         desDayInput.DewPointNeedsSet = true;
    6434              :                     } else {
    6435              :                         // wet-bulb
    6436            0 :                         desDayInput.HumIndValue = desDayInput.MaxDryBulb;
    6437              :                     }
    6438              :                 }
    6439              :             }
    6440              : 
    6441              :             //   A10, \field Solar Model Indicator
    6442         1677 :             if (ipsc->lAlphaFieldBlanks(10)) {
    6443            6 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6444         3342 :             } else if ((desDayInput.solarModel = static_cast<DesDaySolarModel>(
    6445         1671 :                             getEnumValue(DesDaySolarModelNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(10))))) != DesDaySolarModel::Invalid) {
    6446              :             } else {
    6447            0 :                 ShowWarningInvalidKey(state, eoh, ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "ASHRAE ClearSky");
    6448            0 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6449              :             }
    6450              : 
    6451         1677 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    6452              :                 //   A11, \field Beam Solar Day Schedule Name
    6453            3 :                 if (ipsc->lAlphaFieldBlanks(11)) {
    6454              :                     // should have entered beam schedule
    6455            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(11));
    6456            0 :                     ErrorsFound = true;
    6457            3 :                 } else if ((desDayInput.beamSolarSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(11))) == nullptr) {
    6458            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11));
    6459            0 :                     ErrorsFound = true;
    6460              :                 } else {
    6461            3 :                     std::vector<Real64> const &dayVals = desDayInput.beamSolarSched->getDayVals(state);
    6462            3 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6463           75 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    6464          360 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    6465          288 :                             desDayModsEnvrn(ts + 1, hr + 1).BeamSolarRad = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6466              :                         }
    6467              :                     }
    6468              : 
    6469            3 :                     unitType = Constant::Units::W_m2;
    6470              :                     // units = "[W/m2]";
    6471            6 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6472            6 :                                   state.dataWeather->spSiteSchedNums.end(),
    6473            9 :                                   desDayInput.beamSolarSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6474            3 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.beamSolarSched->Num);
    6475            6 :                         SetupOutputVariable(state,
    6476              :                                             "Sizing Period Site Beam Solar Schedule Value",
    6477              :                                             unitType,
    6478            3 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).BeamSolarRad,
    6479              :                                             OutputProcessor::TimeStepType::Zone,
    6480              :                                             OutputProcessor::StoreType::Average,
    6481            3 :                                             ipsc->cAlphaArgs(11));
    6482              :                     }
    6483              : 
    6484            3 :                     if (!desDayInput.beamSolarSched->checkMinVal(state, Clusive::In, 0.0)) {
    6485            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11), Clusive::In, 0.0);
    6486            0 :                         ErrorsFound = true;
    6487              :                     }
    6488              :                 }
    6489              : 
    6490              :                 //   A12, \field Diffuse Solar Day Schedule Name
    6491            3 :                 if (ipsc->lAlphaFieldBlanks(12)) {
    6492              :                     // should have entered diffuse schedule
    6493            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(12));
    6494            0 :                     ErrorsFound = true;
    6495            3 :                 } else if ((desDayInput.diffuseSolarSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(12))) == nullptr) {
    6496            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12));
    6497            0 :                     ErrorsFound = true;
    6498              :                 } else {
    6499            3 :                     std::vector<Real64> const &dayVals = desDayInput.diffuseSolarSched->getDayVals(state);
    6500            3 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6501           75 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    6502          360 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    6503          288 :                             desDayModsEnvrn(ts + 1, hr + 1).DifSolarRad = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6504              :                         }
    6505              :                     }
    6506              : 
    6507              :                     // units = "[W/m2]";
    6508            3 :                     unitType = Constant::Units::W_m2;
    6509            6 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6510            6 :                                   state.dataWeather->spSiteSchedNums.end(),
    6511            9 :                                   desDayInput.diffuseSolarSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6512            3 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.diffuseSolarSched->Num);
    6513            6 :                         SetupOutputVariable(state,
    6514              :                                             "Sizing Period Site Diffuse Solar Schedule Value",
    6515              :                                             unitType,
    6516            3 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).DifSolarRad,
    6517              :                                             OutputProcessor::TimeStepType::Zone,
    6518              :                                             OutputProcessor::StoreType::Average,
    6519            3 :                                             ipsc->cAlphaArgs(12));
    6520              :                     }
    6521            3 :                     if (!desDayInput.diffuseSolarSched->checkMinVal(state, Clusive::In, 0.0)) {
    6522            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12), Clusive::In, 0.0);
    6523            0 :                         ErrorsFound = true;
    6524              :                     }
    6525              :                 }
    6526              : 
    6527         1674 :             } else if (desDayInput.solarModel == DesDaySolarModel::ASHRAE_ClearSky) {
    6528         1584 :                 if (ipsc->lNumericFieldBlanks(14)) {
    6529            0 :                     ShowWarningEmptyField(
    6530            0 :                         state, eoh, ipsc->cNumericFieldNames(14), ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "Zero clear sky (no solar)");
    6531              :                 }
    6532              :             }
    6533              : 
    6534              :             // Validate Design Day Month
    6535              : 
    6536         1677 :             switch (desDayInput.Month) {
    6537         1654 :             case 1:
    6538              :             case 3:
    6539              :             case 5:
    6540              :             case 7:
    6541              :             case 8:
    6542              :             case 10:
    6543              :             case 12: {
    6544         1654 :                 if (desDayInput.DayOfMonth > 31) {
    6545            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6546            0 :                     ShowContinueError(
    6547              :                         state,
    6548            0 :                         format(".. invalid field: {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6549            0 :                     ErrorsFound = true;
    6550              :                 }
    6551         1654 :             } break;
    6552           21 :             case 4:
    6553              :             case 6:
    6554              :             case 9:
    6555              :             case 11: {
    6556           21 :                 if (desDayInput.DayOfMonth > 30) {
    6557            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6558            0 :                     ShowContinueError(
    6559            0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6560            0 :                     ErrorsFound = true;
    6561              :                 }
    6562           21 :             } break;
    6563            2 :             case 2: {
    6564            2 :                 if (desDayInput.DayOfMonth > 28) {
    6565            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6566            0 :                     ShowContinueError(
    6567            0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6568            0 :                     ErrorsFound = true;
    6569              :                 }
    6570            2 :             } break;
    6571            0 :             default: {
    6572            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6573            0 :                 ShowContinueError(state, format(".. invalid {} invalid (Month) [{}].", ipsc->cNumericFieldNames(1), desDayInput.Month));
    6574            0 :                 ErrorsFound = true;
    6575            0 :             } break;
    6576              :             } // switch (desDayInput.Month)
    6577              : 
    6578              :             //   A9,  \field Daylight Saving Time Indicator
    6579         1677 :             if (ipsc->lAlphaFieldBlanks(9)) {
    6580            6 :                 desDayInput.DSTIndicator = 0;
    6581         1671 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(9)))) != BooleanSwitch::Invalid) {
    6582         1671 :                 desDayInput.DSTIndicator = (int)b;
    6583              :             } else {
    6584            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(9), ipsc->cAlphaArgs(9), "No");
    6585            0 :                 desDayInput.DSTIndicator = 0;
    6586              :             }
    6587              : 
    6588              :             //   A2,  \field Day Type
    6589         1677 :             desDayInput.DayType = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    6590         1677 :             if (desDayInput.DayType <= 0) {
    6591            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    6592            0 :                 ErrorsFound = true;
    6593              :             }
    6594              : 
    6595         1677 :             auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    6596         1677 :             envCurr.Title = desDayInput.Title;
    6597         1677 :             envCurr.KindOfEnvrn = Constant::KindOfSim::DesignDay;
    6598         1677 :             envCurr.DesignDayNum = EnvrnNum;
    6599         1677 :             envCurr.RunPeriodDesignNum = 0;
    6600         1677 :             envCurr.TotalDays = 1;
    6601         1677 :             envCurr.StartMonth = desDayInput.Month;
    6602         1677 :             envCurr.StartDay = desDayInput.DayOfMonth;
    6603         1677 :             envCurr.EndMonth = envCurr.StartMonth;
    6604         1677 :             envCurr.EndDay = envCurr.StartDay;
    6605         1677 :             envCurr.DayOfWeek = 0;
    6606         1677 :             envCurr.UseDST = false;
    6607         1677 :             envCurr.UseHolidays = false;
    6608         1677 :             envCurr.StartJDay = designDay.DayOfYear;
    6609         1677 :             envCurr.EndJDay = envCurr.StartJDay;
    6610              : 
    6611              :             // create predefined report on design day
    6612         1677 :             std::string envTitle = desDayInput.Title;
    6613         1677 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDmaxDB, envTitle, desDayInput.MaxDryBulb);
    6614         1677 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDrange, envTitle, desDayInput.DailyDBRange);
    6615         1677 :             if (desDayInput.HumIndType != DesDayHumIndType::RelHumSch) {
    6616         1674 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, desDayInput.HumIndValue);
    6617              :             } else {
    6618            3 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, "N/A");
    6619              :             }
    6620         3354 :             OutputReportPredefined::PreDefTableEntry(
    6621         3354 :                 state, state.dataOutRptPredefined->pdchDDhumTyp, envTitle, DesDayHumIndTypeStringRep[(int)desDayInput.HumIndType]);
    6622         1677 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindSp, envTitle, desDayInput.WindSpeed);
    6623         1677 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindDr, envTitle, desDayInput.WindDir);
    6624              :         }
    6625          801 :     }
    6626              : 
    6627          801 :     void GetLocationInfo(EnergyPlusData &state, bool &ErrorsFound)
    6628              :     {
    6629              : 
    6630              :         // SUBROUTINE INFORMATION:
    6631              :         //       AUTHOR         Richard Liesen
    6632              :         //       DATE WRITTEN   October 1997
    6633              : 
    6634              :         // PURPOSE OF THIS SUBROUTINE:
    6635              :         // This subroutine gets the location info from the IDF file; latitude,
    6636              :         //  longitude and time zone number.
    6637              : 
    6638          801 :         auto const &ipsc = state.dataIPShortCut;
    6639          801 :         ipsc->cCurrentModuleObject = "Site:Location";
    6640          801 :         int const NumLocations = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6641              : 
    6642          801 :         if (NumLocations > 1) {
    6643            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6644            0 :             ErrorsFound = true;
    6645              :         }
    6646              : 
    6647          801 :         if (NumLocations == 1) {
    6648              :             int LocNumAlpha;             // Number of alpha names being passed
    6649              :             int LocNumProp;              // Number of properties being passed
    6650              :             int IOStat;                  // IO Status when calling get input subroutine
    6651          794 :             Array1D_string LocAlphas(2); // Temporary array to transfer location info (non-numerics)
    6652          794 :             Array1D<Real64> LocProps(4); // Temporary array to transfer location info (numerics)
    6653              :             // Call Input Get routine to retrieve Location information
    6654         1588 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    6655          794 :                 state, ipsc->cCurrentModuleObject, 1, LocAlphas, LocNumAlpha, LocProps, LocNumProp, IOStat);
    6656              : 
    6657              :             // set latitude, longitude, and time zone number variables
    6658          794 :             state.dataWeather->LocationTitle = LocAlphas(1);
    6659          794 :             state.dataEnvrn->Latitude = LocProps(1);
    6660          794 :             state.dataEnvrn->Longitude = LocProps(2);
    6661          794 :             state.dataEnvrn->TimeZoneNumber = LocProps(3);
    6662          794 :             state.dataEnvrn->Elevation = LocProps(4);
    6663          794 :             if (Util::SameString(LocAlphas(2), "Yes")) {
    6664            1 :                 state.dataWeather->keepUserSiteLocationDefinition = true;
    6665              :             }
    6666          794 :             state.dataWeather->LocationGathered = true;
    6667          794 :         }
    6668          801 :     }
    6669              : 
    6670          801 :     void GetWeatherProperties(EnergyPlusData &state, bool &ErrorsFound)
    6671              :     {
    6672              : 
    6673              :         // SUBROUTINE INFORMATION:
    6674              :         //       AUTHOR         Linda Lawrie
    6675              :         //       DATE WRITTEN   July 2009
    6676              : 
    6677              :         // PURPOSE OF THIS SUBROUTINE:
    6678              :         // Weather properties are an advanced concept for simulation.  Primarily, these properties are
    6679              :         // used in the test suite runs that have specific requirements for certain properties (such as
    6680              :         // sky temperature).
    6681              : 
    6682              :         // REFERENCES:
    6683              :         // WeatherProperty:SkyTemperature,
    6684              :         //        \memo This object is used to override internal sky temperature calculations.
    6685              :         //   A1,  \field Name
    6686              :         //        \reference DesignDays
    6687              :         //        \note leave blank for RunPeriods (until we name them)
    6688              :         //        \note This field references the applicable design day or runperiod(s) if left blank.
    6689              :         //   A2,  \field Calculation Type
    6690              :         //        \type choice
    6691              :         //        \key ScheduleValue
    6692              :         //        \key DifferenceScheduleDryBulbValue
    6693              :         //        \key DifferenceScheduleDewPointValue
    6694              :         //        \key AlgorithmA
    6695              :         //   A3;  \field Schedule Name
    6696              :         //        \type object-list
    6697              :         //        \object-list DayScheduleNames
    6698              :         //        \object-list ScheduleNames
    6699              : 
    6700              :         static constexpr std::string_view routineName = "GetWeatherProperties";
    6701              : 
    6702              :         int Found;
    6703              :         int envFound;
    6704              : 
    6705          801 :         auto const &ipsc = state.dataIPShortCut;
    6706          801 :         ipsc->cCurrentModuleObject = "WeatherProperty:SkyTemperature";
    6707          801 :         state.dataWeather->NumWPSkyTemperatures = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6708              : 
    6709          801 :         state.dataWeather->WPSkyTemperature.allocate(state.dataWeather->NumWPSkyTemperatures); // by default, not used.
    6710              : 
    6711          803 :         for (int i = 1; i <= state.dataWeather->NumWPSkyTemperatures; ++i) {
    6712              :             int IOStat;
    6713              :             int NumAlpha;
    6714              :             int NumNumerics;
    6715            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6716            2 :                                                                      ipsc->cCurrentModuleObject,
    6717              :                                                                      i,
    6718            2 :                                                                      ipsc->cAlphaArgs,
    6719              :                                                                      NumAlpha,
    6720            2 :                                                                      ipsc->rNumericArgs,
    6721              :                                                                      NumNumerics,
    6722              :                                                                      IOStat,
    6723            2 :                                                                      ipsc->lNumericFieldBlanks,
    6724            2 :                                                                      ipsc->lAlphaFieldBlanks,
    6725            2 :                                                                      ipsc->cAlphaFieldNames,
    6726            2 :                                                                      ipsc->cNumericFieldNames);
    6727              : 
    6728            2 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    6729            2 :             auto &wpSkyTemp = state.dataWeather->WPSkyTemperature(i);
    6730            2 :             if (ipsc->cAlphaArgs(1).empty()) {
    6731            1 :                 Found = 0;
    6732           14 :                 for (int j = 1; j <= state.dataWeather->NumOfEnvrn; ++j) {
    6733           13 :                     auto &environJ = state.dataWeather->Environment(j);
    6734           13 :                     if (environJ.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) {
    6735           12 :                         continue;
    6736              :                     }
    6737            1 :                     if (environJ.WP_Type1 != 0) {
    6738            0 :                         ShowSevereError(state,
    6739            0 :                                         format("{}: {}=\"{}\", indicated Environment Name already assigned.",
    6740              :                                                routineName,
    6741            0 :                                                ipsc->cCurrentModuleObject,
    6742            0 :                                                ipsc->cAlphaArgs(1)));
    6743            0 :                         if (!environJ.Title.empty()) {
    6744            0 :                             ShowContinueError(state,
    6745            0 :                                               format("...Environment=\"{}\", already using {}=\"{}\".",
    6746            0 :                                                      environJ.Title,
    6747            0 :                                                      ipsc->cCurrentModuleObject,
    6748            0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6749              :                         } else {
    6750            0 :                             ShowContinueError(state,
    6751            0 :                                               format("... Runperiod Environment, already using {}=\"{}\".",
    6752            0 :                                                      ipsc->cCurrentModuleObject,
    6753            0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6754              :                         }
    6755            0 :                         ErrorsFound = true;
    6756              :                     } else {
    6757            1 :                         environJ.WP_Type1 = i;
    6758            1 :                         Found = j;
    6759              :                     }
    6760              :                 }
    6761            1 :                 if (Found == 0) {
    6762            0 :                     ShowWarningError(state, "GetWeatherProperties: WeatherProperty:SkyTemperature=blank, no run periods found.");
    6763            0 :                     ShowContinueError(state, "...SkyTemperature will not be applied.");
    6764            0 :                     continue;
    6765              :                 }
    6766              :             } else { // really a name
    6767            1 :                 Found = Util::FindItemInList(ipsc->cAlphaArgs(1), state.dataWeather->Environment, &EnvironmentData::Title);
    6768            1 :                 envFound = Found;
    6769            1 :                 if (Found == 0) {
    6770            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    6771            0 :                     ErrorsFound = true;
    6772            0 :                     continue;
    6773              :                 }
    6774              : 
    6775            1 :                 auto &envrnFound = state.dataWeather->Environment(Found);
    6776            1 :                 if (envrnFound.WP_Type1 != 0) {
    6777            0 :                     ShowSevereError(state,
    6778            0 :                                     format("{}:{}=\"{}\", indicated Environment Name already assigned.",
    6779              :                                            routineName,
    6780            0 :                                            ipsc->cCurrentModuleObject,
    6781            0 :                                            ipsc->cAlphaArgs(1)));
    6782            0 :                     ShowContinueError(state,
    6783            0 :                                       format("...Environment=\"{}\", already using {}=\"{}\".",
    6784            0 :                                              envrnFound.Title,
    6785            0 :                                              ipsc->cCurrentModuleObject,
    6786            0 :                                              state.dataWeather->WPSkyTemperature(envrnFound.WP_Type1).Name));
    6787            0 :                     ErrorsFound = true;
    6788              :                 } else {
    6789            1 :                     state.dataWeather->Environment(Found).WP_Type1 = i;
    6790              :                 }
    6791              :             }
    6792              : 
    6793            3 :             wpSkyTemp.Name = !ipsc->lAlphaFieldBlanks(1) ? ipsc->cAlphaArgs(1) : "All RunPeriods";
    6794              : 
    6795              :             // Validate Calculation Type.
    6796              :             // std::string units;
    6797              :             Constant::Units unitType;
    6798            2 :             wpSkyTemp.skyTempModel = static_cast<SkyTempModel>(getEnumValue(Weather::SkyTempModelNamesUC, ipsc->cAlphaArgs(2)));
    6799              : 
    6800            2 :             switch (wpSkyTemp.skyTempModel) {
    6801            2 :             case SkyTempModel::ScheduleValue: {
    6802            2 :                 wpSkyTemp.IsSchedule = true;
    6803              :                 // units = "[C]";
    6804            2 :                 unitType = Constant::Units::C;
    6805            2 :             } break;
    6806            0 :             case SkyTempModel::DryBulbDelta:
    6807              :             case SkyTempModel::DewPointDelta: {
    6808            0 :                 wpSkyTemp.IsSchedule = true;
    6809              :                 // units = "[deltaC]";
    6810            0 :                 unitType = Constant::Units::deltaC;
    6811            0 :             } break;
    6812            0 :             case SkyTempModel::Brunt:
    6813              :             case SkyTempModel::Idso:
    6814              :             case SkyTempModel::BerdahlMartin:
    6815              :             case SkyTempModel::ClarkAllen: {
    6816            0 :                 wpSkyTemp.IsSchedule = false;
    6817            0 :             } break;
    6818            0 :             default: {
    6819              :                 // Bad inputs are trapped by input processor
    6820            0 :                 assert(false);
    6821              :             } break;
    6822              :             } // switch (skyTempModel)
    6823              : 
    6824            2 :             if (wpSkyTemp.IsSchedule) {
    6825            3 :                 if (state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather ||
    6826            1 :                     state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    6827              :                     // See if it's a schedule.
    6828            1 :                     if ((wpSkyTemp.sched = Sched::GetSchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
    6829            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6830            0 :                         ErrorsFound = true;
    6831              :                     } else {
    6832            1 :                         wpSkyTemp.IsSchedule = true;
    6833              :                     }
    6834              :                 } else { // See if it's a valid schedule.
    6835              :                     // How can a schedule be either a yearly schedule or a day schedule?
    6836            1 :                     if ((wpSkyTemp.sched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
    6837            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6838            0 :                         ErrorsFound = true;
    6839              :                     } else {
    6840            1 :                         if (envFound != 0) {
    6841            2 :                             if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6842            2 :                                           state.dataWeather->spSiteSchedNums.end(),
    6843            3 :                                           wpSkyTemp.sched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6844            1 :                                 state.dataWeather->spSiteSchedNums.emplace_back(wpSkyTemp.sched->Num);
    6845            2 :                                 SetupOutputVariable(state,
    6846              :                                                     "Sizing Period Site Sky Temperature Schedule Value",
    6847              :                                                     unitType,
    6848            1 :                                                     state.dataWeather->spSiteSchedules(envFound).SkyTemp,
    6849              :                                                     OutputProcessor::TimeStepType::Zone,
    6850              :                                                     OutputProcessor::StoreType::Average,
    6851            1 :                                                     ipsc->cAlphaArgs(3));
    6852              :                             }
    6853            1 :                             wpSkyTemp.IsSchedule = true;
    6854              :                         }
    6855              :                     }
    6856              :                 }
    6857              :             }
    6858              : 
    6859            2 :             if (!wpSkyTemp.IsSchedule && !ipsc->lAlphaFieldBlanks(4)) {
    6860            0 :                 if (BooleanSwitch b = getYesNoValue(ipsc->cAlphaArgs(4)); b != BooleanSwitch::Invalid) {
    6861            0 :                     wpSkyTemp.UseWeatherFileHorizontalIR = static_cast<bool>(b);
    6862              :                 } else {
    6863            0 :                     ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    6864            0 :                     ErrorsFound = true;
    6865              :                 }
    6866              :             } else {
    6867            2 :                 wpSkyTemp.UseWeatherFileHorizontalIR = true;
    6868              :             }
    6869              :         }
    6870         3674 :         for (auto &envCurr : state.dataWeather->Environment) {
    6871         2873 :             if (envCurr.WP_Type1 != 0 && state.dataWeather->NumWPSkyTemperatures >= envCurr.WP_Type1) {
    6872            2 :                 envCurr.skyTempModel = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel;
    6873            2 :                 envCurr.UseWeatherFileHorizontalIR = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).UseWeatherFileHorizontalIR;
    6874              :             }
    6875              :         }
    6876          801 :     }
    6877              : 
    6878          801 :     void GetGroundTemps(EnergyPlusData &state)
    6879              :     {
    6880              : 
    6881              :         // SUBROUTINE INFORMATION:
    6882              :         //       AUTHOR         Richard Liesen
    6883              :         //       DATE WRITTEN   October 1997
    6884              : 
    6885              :         // PURPOSE OF THIS SUBROUTINE:
    6886              :         // This file reads the Ground Temps from the input file and puts them
    6887              :         //  in a new variable.
    6888              : 
    6889              :         // Initialize Site:GroundTemperature:BuildingSurface object
    6890         1602 :         state.dataWeather->siteBuildingSurfaceGroundTempsPtr =
    6891         1602 :             GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteBuildingSurface, "");
    6892              : 
    6893              :         // Initialize Site:GroundTemperature:FCFactorMethod object
    6894         1602 :         state.dataWeather->siteFCFactorMethodGroundTempsPtr =
    6895         1602 :             GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteFCFactorMethod, "");
    6896              : 
    6897              :         // Initialize Site:GroundTemperature:Shallow object
    6898         1602 :         state.dataWeather->siteShallowGroundTempsPtr = GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteShallow, "");
    6899              : 
    6900              :         // Initialize Site:GroundTemperature:Deep object
    6901          801 :         state.dataWeather->siteDeepGroundTempsPtr = GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteDeep, "");
    6902          801 :     }
    6903              : 
    6904          801 :     void GetGroundReflectances(EnergyPlusData &state, bool &ErrorsFound)
    6905              :     {
    6906              : 
    6907              :         // SUBROUTINE INFORMATION:
    6908              :         //       AUTHOR         Linda Lawrie
    6909              :         //       DATE WRITTEN   March 2002
    6910              : 
    6911              :         // PURPOSE OF THIS SUBROUTINE:
    6912              :         // This file reads the Ground Reflectances from the input file (optional) and
    6913              :         // places them in the monthly array.
    6914              : 
    6915          801 :         auto const &ipsc = state.dataIPShortCut;
    6916          801 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance";
    6917          801 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6918          801 :         if (nObjs != 0) {
    6919            3 :             Array1D_string GndAlphas(1);  // Construction Alpha names defined
    6920            3 :             Array1D<Real64> GndProps(12); // Temporary array to transfer ground reflectances
    6921            3 :             if (nObjs == 1) {
    6922              :                 int GndNumAlpha; // Number of construction alpha names being passed
    6923              :                 int GndNumProp;  // dummy variable for properties being passed
    6924              :                 int IOStat;      // IO Status when calling get input subroutine
    6925              :                 // Get the object names for each construction from the input processor
    6926            6 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6927            3 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6928              : 
    6929            3 :                 if (GndNumProp < 12) {
    6930            0 :                     ShowSevereError(state, format("{}: Less than 12 values entered.", ipsc->cCurrentModuleObject));
    6931            0 :                     ErrorsFound = true;
    6932              :                 }
    6933              : 
    6934              :                 // Assign the ground reflectances to the variable
    6935            3 :                 state.dataWeather->GroundReflectances({1, 12}) = GndProps({1, 12});
    6936              : 
    6937              :             } else {
    6938            0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6939            0 :                 ErrorsFound = true;
    6940              :             }
    6941            3 :         }
    6942              : 
    6943              :         // Write Final Ground Reflectance Information to the initialization output file
    6944          801 :         print(state.files.eio,
    6945              :               "{}\n",
    6946              :               "! "
    6947              :               "<Site:GroundReflectance>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{dimensionless},"
    6948              :               "May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{dimensionless},Oct{"
    6949              :               "dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6950              : 
    6951          801 :         print(state.files.eio, " Site:GroundReflectance");
    6952        10413 :         for (int i = 1; i <= 12; ++i) {
    6953         9612 :             print(state.files.eio, ", {:5.2F}", state.dataWeather->GroundReflectances(i));
    6954              :         }
    6955          801 :         print(state.files.eio, "\n");
    6956          801 :     }
    6957              : 
    6958          801 :     void GetSnowGroundRefModifiers(EnergyPlusData &state, bool &ErrorsFound)
    6959              :     {
    6960              : 
    6961              :         // SUBROUTINE INFORMATION:
    6962              :         //       AUTHOR         Linda Lawrie
    6963              :         //       DATE WRITTEN   March 2002
    6964              : 
    6965              :         // PURPOSE OF THIS SUBROUTINE:
    6966              :         // This file reads the Snow Ground Reflectance Modifiers from the input file (optional) and
    6967              :         // places them in the variables.
    6968              : 
    6969          801 :         auto const &ipsc = state.dataIPShortCut;
    6970          801 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance:SnowModifier";
    6971          801 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6972          801 :         if (nObjs != 0) {
    6973            2 :             Array1D_string GndAlphas(1); // Construction Alpha names defined
    6974            2 :             Array1D<Real64> GndProps(2); // Temporary array to transfer ground reflectances
    6975            2 :             if (nObjs == 1) {
    6976              :                 int GndNumAlpha; // Number of construction alpha names being passed
    6977              :                 int GndNumProp;  // dummy variable for properties being passed
    6978              :                 int IOStat;      // IO Status when calling get input subroutine
    6979              :                 // Get the object names for each construction from the input processor
    6980            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6981            2 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6982              : 
    6983              :                 // Assign the ground reflectances to the variable
    6984            2 :                 state.dataWeather->SnowGndRefModifier = GndProps(1);
    6985            2 :                 state.dataWeather->SnowGndRefModifierForDayltg = GndProps(2);
    6986              : 
    6987              :             } else {
    6988            0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6989            0 :                 ErrorsFound = true;
    6990              :             }
    6991            2 :         }
    6992              : 
    6993              :         // Write Final Ground Reflectance Modifier Information to the initialization output file
    6994          801 :         print(state.files.eio, "{}\n", "! <Site:GroundReflectance:SnowModifier>, Normal, Daylighting {dimensionless}");
    6995              :         static constexpr std::string_view Format_720(" Site:GroundReflectance:SnowModifier, {:7.3F}, {:7.3F}\n");
    6996          801 :         print(state.files.eio, Format_720, state.dataWeather->SnowGndRefModifier, state.dataWeather->SnowGndRefModifierForDayltg);
    6997              : 
    6998          801 :         print(state.files.eio,
    6999              :               "{}\n",
    7000              :               "! "
    7001              :               "<Site:GroundReflectance:Snow>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    7002              :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    7003              :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    7004          801 :         print(state.files.eio, "{}", " Site:GroundReflectance:Snow");
    7005        10413 :         for (int i = 1; i <= 12; ++i) {
    7006         9612 :             print(state.files.eio, ", {:5.2F}", max(min(state.dataWeather->GroundReflectances(i) * state.dataWeather->SnowGndRefModifier, 1.0), 0.0));
    7007              :         }
    7008          801 :         print(state.files.eio, "\n");
    7009          801 :         print(state.files.eio,
    7010              :               "{}\n",
    7011              :               "! "
    7012              :               "<Site:GroundReflectance:Snow:Daylighting>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    7013              :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    7014              :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    7015          801 :         print(state.files.eio, " Site:GroundReflectance:Snow:Daylighting");
    7016        10413 :         for (nObjs = 1; nObjs <= 12; ++nObjs) {
    7017         9612 :             print(state.files.eio,
    7018              :                   ", {:5.2F}",
    7019        19224 :                   max(min(state.dataWeather->GroundReflectances(nObjs) * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0));
    7020              :         }
    7021          801 :         print(state.files.eio, "\n");
    7022          801 :     }
    7023              : 
    7024          801 :     void GetWaterMainsTemperatures(EnergyPlusData &state, bool &ErrorsFound)
    7025              :     {
    7026              : 
    7027              :         // SUBROUTINE INFORMATION:
    7028              :         //       AUTHOR         Peter Graham Ellis
    7029              :         //       DATE WRITTEN   January 2005
    7030              : 
    7031              :         // PURPOSE OF THIS SUBROUTINE:
    7032              :         // Reads the input data for the WATER MAINS TEMPERATURES object.
    7033              : 
    7034          801 :         constexpr std::string_view routineName = "GetWaterMainsTemperatures";
    7035              : 
    7036          801 :         auto const &ipsc = state.dataIPShortCut;
    7037          801 :         ipsc->cCurrentModuleObject = "Site:WaterMainsTemperature";
    7038          801 :         int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    7039              : 
    7040          801 :         if (NumObjects == 1) {
    7041              :             int NumAlphas;               // Number of elements in the alpha array
    7042              :             int NumNums;                 // Number of elements in the numeric array
    7043              :             int IOStat;                  // IO Status when calling get input subroutine
    7044          133 :             Array1D_string AlphArray(2); // Character string data
    7045          133 :             Array1D<Real64> NumArray(2); // Numeric data
    7046          399 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7047          133 :                                                                      ipsc->cCurrentModuleObject,
    7048              :                                                                      1,
    7049              :                                                                      AlphArray,
    7050              :                                                                      NumAlphas,
    7051              :                                                                      NumArray,
    7052              :                                                                      NumNums,
    7053              :                                                                      IOStat,
    7054          133 :                                                                      ipsc->lNumericFieldBlanks,
    7055          133 :                                                                      ipsc->lAlphaFieldBlanks,
    7056          133 :                                                                      ipsc->cAlphaFieldNames,
    7057          133 :                                                                      ipsc->cNumericFieldNames);
    7058              : 
    7059          133 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ""};
    7060              : 
    7061          266 :             state.dataWeather->WaterMainsTempsMethod =
    7062          133 :                 static_cast<Weather::WaterMainsTempCalcMethod>(getEnumValue(waterMainsCalcMethodNamesUC, AlphArray(1)));
    7063              : 
    7064          133 :             switch (state.dataWeather->WaterMainsTempsMethod) {
    7065            5 :             case WaterMainsTempCalcMethod::Schedule: {
    7066            5 :                 if (ipsc->lAlphaFieldBlanks(2)) {
    7067            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
    7068            0 :                     ErrorsFound = true;
    7069            5 :                 } else if ((state.dataWeather->waterMainsTempSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
    7070            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    7071            0 :                     ErrorsFound = true;
    7072              :                 }
    7073            5 :             } break;
    7074              : 
    7075          128 :             case WaterMainsTempCalcMethod::Correlation: {
    7076          128 :                 if (NumNums == 0) {
    7077            0 :                     ShowSevereError(state, format("{}: Missing Annual Average and Maximum Difference fields.", ipsc->cCurrentModuleObject));
    7078            0 :                     ErrorsFound = true;
    7079          128 :                 } else if (NumNums == 1) {
    7080            0 :                     ShowSevereError(state, format("{}: Missing Maximum Difference field.", ipsc->cCurrentModuleObject));
    7081            0 :                     ErrorsFound = true;
    7082              :                 } else {
    7083          128 :                     state.dataWeather->WaterMainsTempsAnnualAvgAirTemp = NumArray(1);
    7084          128 :                     state.dataWeather->WaterMainsTempsMaxDiffAirTemp = NumArray(2);
    7085              :                 }
    7086          128 :             } break;
    7087            0 :             case WaterMainsTempCalcMethod::CorrelationFromWeatherFile: {
    7088              :                 // No action
    7089            0 :             } break;
    7090            0 :             default: {
    7091            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), AlphArray(1));
    7092            0 :                 ErrorsFound = true;
    7093            0 :             } break;
    7094              :             } // switch
    7095              : 
    7096          801 :         } else if (NumObjects > 1) {
    7097            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    7098            0 :             ErrorsFound = true;
    7099              :         }
    7100          801 :     }
    7101              : 
    7102      2925340 :     void CalcWaterMainsTemp(EnergyPlusData &state)
    7103              :     {
    7104              : 
    7105              :         // SUBROUTINE INFORMATION:
    7106              :         //       AUTHOR         Peter Graham Ellis
    7107              :         //       DATE WRITTEN   January 2005
    7108              :         //       MODIFIED       June 2018, B. Nigusse
    7109              : 
    7110              :         // PURPOSE OF THIS SUBROUTINE:
    7111              :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    7112              : 
    7113              :         // METHODOLOGY EMPLOYED:
    7114              :         // Water mains temperature is either taken from a schedule or calculated by a correlation.  The correlation
    7115              :         // is fit to Fahrenheit units, so the air temperature values are first convert to F, then mains temperature
    7116              :         // is calculated and converted back to C.
    7117              : 
    7118      2925340 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    7119        16008 :         case WaterMainsTempCalcMethod::Schedule:
    7120        16008 :             state.dataEnvrn->WaterMainsTemp = state.dataWeather->waterMainsTempSched->getCurrentVal();
    7121        16008 :             break;
    7122       518326 :         case WaterMainsTempCalcMethod::Correlation:
    7123       518326 :             state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(
    7124       518326 :                 state, state.dataWeather->WaterMainsTempsAnnualAvgAirTemp, state.dataWeather->WaterMainsTempsMaxDiffAirTemp);
    7125       518326 :             break;
    7126            0 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    7127            0 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    7128            0 :                 state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(state,
    7129            0 :                                                                                 state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp,
    7130            0 :                                                                                 state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff);
    7131              :             } else {
    7132            0 :                 state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    7133              :             }
    7134            0 :             break;
    7135      2391006 :         default:
    7136      2391006 :             state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    7137      2391006 :             break;
    7138              :         }
    7139      2925340 :     }
    7140              : 
    7141              :     Real64
    7142       518326 :     WaterMainsTempFromCorrelation(EnergyPlusData const &state, Real64 const AnnualOAAvgDryBulbTemp, Real64 const MonthlyOAAvgDryBulbTempMaxDiff)
    7143              :     {
    7144              : 
    7145              :         // SUBROUTINE INFORMATION:
    7146              :         //       AUTHOR         Peter Graham Ellis
    7147              :         //       DATE WRITTEN   January 2005
    7148              :         //       MODIFIED       B Nigusse June 2018 (Refactored)
    7149              : 
    7150              :         // PURPOSE OF THIS SUBROUTINE:
    7151              :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    7152              : 
    7153              :         // METHODOLOGY EMPLOYED:
    7154              :         // Water mains temperature calculated by a correlation.  The correlation is fit to Fahrenheit units, so the
    7155              :         // air temperature values are first convert to F, then mains temperature is calculated and converted back to C.
    7156              :         // used for Calculated Method: 'Correlation' and 'CorrelationFromWeatherFile'.
    7157              : 
    7158              :         // REFERENCES:
    7159              :         // Correlation developed by Jay Burch and Craig Christensen at NREL, described in:
    7160              :         // Hendron, R., Anderson, R., Christensen, C., Eastment, M., and Reeves, P.  2004.  "Development of an Energy
    7161              :         // Savings Benchmark for All Residential End-Uses", Proceedings of SimBuild 2004, IBPSA-USA National Conference,
    7162              :         // Boulder, CO, August 4 - 6, 2004.
    7163              : 
    7164              :         // Annual Average Outdoor Air Temperature (F)
    7165       518326 :         Real64 const Tavg = AnnualOAAvgDryBulbTemp * (9.0 / 5.0) + 32.0;
    7166              :         // Maximum difference in monthly average outdoor air temperatures (deltaF)
    7167       518326 :         Real64 const Tdiff = MonthlyOAAvgDryBulbTempMaxDiff * (9.0 / 5.0);
    7168              : 
    7169       518326 :         Real64 const Ratio = 0.4 + 0.01 * (Tavg - 44.0);
    7170       518326 :         Real64 const Lag = 35.0 - 1.0 * (Tavg - 44.0);
    7171       518326 :         Real64 constexpr Offset = 6.0;
    7172       518326 :         int const latitude_sign = (state.dataEnvrn->Latitude >= 0) ? 1 : -1;
    7173              : 
    7174              :         // calculated water main temp (F)
    7175              :         Real64 CurrentWaterMainsTemp =
    7176       518326 :             Tavg + Offset +
    7177       518326 :             Ratio * (Tdiff / 2.0) * latitude_sign * std::sin((0.986 * (state.dataEnvrn->DayOfYear - 15.0 - Lag) - 90) * Constant::DegToRad);
    7178              : 
    7179       518326 :         if (CurrentWaterMainsTemp < 32.0) {
    7180         4338 :             CurrentWaterMainsTemp = 32.0;
    7181              :         }
    7182              : 
    7183              :         // Convert F to C
    7184       518326 :         return (CurrentWaterMainsTemp - 32.0) * (5.0 / 9.0);
    7185              :     }
    7186          801 :     void GetWeatherStation(EnergyPlusData &state, bool &ErrorsFound)
    7187              :     {
    7188              : 
    7189              :         // SUBROUTINE INFORMATION:
    7190              :         //       AUTHOR         Peter Graham Ellis
    7191              :         //       DATE WRITTEN   January 2006
    7192              : 
    7193              :         // PURPOSE OF THIS SUBROUTINE:
    7194              :         // Reads the input data for the WEATHER STATION object.
    7195              : 
    7196          801 :         auto const &ipsc = state.dataIPShortCut;
    7197          801 :         ipsc->cCurrentModuleObject = "Site:WeatherStation";
    7198          801 :         int const NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    7199              : 
    7200              :         // Default conditions for a weather station in an open field at a height of 10 m. (These should match the IDD defaults.)
    7201          801 :         Real64 WeatherFileWindSensorHeight = 10.0; // Height of the wind sensor at the weather station, i.e., weather file
    7202          801 :         Real64 WeatherFileWindExp = 0.14;          // Exponent for the wind velocity profile at the weather station
    7203          801 :         Real64 WeatherFileWindBLHeight = 270.0;    // Boundary layer height for the wind velocity profile at the weather station (m)
    7204          801 :         Real64 WeatherFileTempSensorHeight = 1.5;  // Height of the air temperature sensor at the weather station (m)
    7205              : 
    7206          801 :         if (NumObjects == 1) {
    7207              :             int NumAlphas;               // Number of elements in the alpha array
    7208              :             int NumNums;                 // Number of elements in the numeric array
    7209              :             int IOStat;                  // IO Status when calling get input subroutine
    7210            1 :             Array1D_string AlphArray(1); // Character string data
    7211            1 :             Array1D<Real64> NumArray(4); // Numeric data
    7212            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    7213            1 :                 state, ipsc->cCurrentModuleObject, 1, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    7214              : 
    7215            1 :             if (NumNums > 0) {
    7216            1 :                 WeatherFileWindSensorHeight = NumArray(1);
    7217              :             }
    7218            1 :             if (NumNums > 1) {
    7219            1 :                 WeatherFileWindExp = NumArray(2);
    7220              :             }
    7221            1 :             if (NumNums > 2) {
    7222            1 :                 WeatherFileWindBLHeight = NumArray(3);
    7223              :             }
    7224            1 :             if (NumNums > 3) {
    7225            1 :                 WeatherFileTempSensorHeight = NumArray(4);
    7226              :             }
    7227              : 
    7228          801 :         } else if (NumObjects > 1) {
    7229            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    7230            0 :             ErrorsFound = true;
    7231              :         }
    7232              : 
    7233          801 :         state.dataEnvrn->WeatherFileWindModCoeff = std::pow(WeatherFileWindBLHeight / WeatherFileWindSensorHeight, WeatherFileWindExp);
    7234         1602 :         state.dataEnvrn->WeatherFileTempModCoeff = DataEnvironment::AtmosphericTempGradient * DataEnvironment::EarthRadius *
    7235          801 :                                                    WeatherFileTempSensorHeight / (DataEnvironment::EarthRadius + WeatherFileTempSensorHeight);
    7236              : 
    7237              :         // Write to the initialization output file
    7238          801 :         print(state.files.eio,
    7239              :               "{}\n",
    7240              :               "! <Environment:Weather Station>,Wind Sensor Height Above Ground {m},Wind Speed Profile Exponent "
    7241              :               "{},Wind Speed Profile Boundary Layer Thickness {m},Air Temperature Sensor Height Above Ground {m},Wind "
    7242              :               "Speed Modifier Coefficient-Internal,Temperature Modifier Coefficient-Internal");
    7243              : 
    7244              :         // Formats
    7245              :         static constexpr std::string_view Format_720("Environment:Weather Station,{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7246          801 :         print(state.files.eio,
    7247              :               Format_720,
    7248              :               WeatherFileWindSensorHeight,
    7249              :               WeatherFileWindExp,
    7250              :               WeatherFileWindBLHeight,
    7251              :               WeatherFileTempSensorHeight,
    7252          801 :               state.dataEnvrn->WeatherFileWindModCoeff,
    7253          801 :               state.dataEnvrn->WeatherFileTempModCoeff);
    7254          801 :     }
    7255              : 
    7256      2925340 :     void DayltgCurrentExtHorizIllum(EnergyPlusData &state)
    7257              :     {
    7258              : 
    7259              :         // SUBROUTINE INFORMATION:
    7260              :         //       AUTHOR         Fred Winkelmann
    7261              :         //       DATE WRITTEN   July 1997
    7262              :         //       MODIFIED       Nov98 (FW); Nov 2000 (FW)
    7263              : 
    7264              :         // PURPOSE OF THIS SUBROUTINE:
    7265              :         // CALCULATES EXTERIOR DAYLIGHT ILLUMINANCE AND LUMINOUS EFFICACY
    7266              : 
    7267              :         // METHODOLOGY EMPLOYED:
    7268              :         // CALLED by SetCurrentWeather.
    7269              :         // CALCULATES THE CURRENT-TIME-STEP
    7270              :         // ILLUMINANCE ON AN UNOBSTRUCTED HORIZONTAL SURFACE FROM THE
    7271              :         // THE SKY AND FROM DIRECT SUN.
    7272              : 
    7273              :         // REFERENCES:
    7274              :         // Based on DOE-2.1E subroutine DEXTIL.
    7275              : 
    7276              :         // SOLCOS(3), below, is the cosine of the solar zenith angle.
    7277      2925340 :         if (state.dataEnvrn->SunIsUp) {
    7278              :             // Exterior horizontal beam irradiance (W/m2)
    7279      1462278 :             Real64 SDIRH = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z;
    7280              :             // Exterior horizontal sky diffuse irradiance (W/m2)
    7281      1462278 :             Real64 SDIFH = state.dataEnvrn->DifSolarRad;
    7282              :             // Fraction of sky covered by clouds
    7283      1462278 :             state.dataEnvrn->CloudFraction = pow_2(SDIFH / (SDIRH + SDIFH + 0.0001));
    7284              :             // Luminous efficacy of sky diffuse solar and beam solar (lumens/W);
    7285              :             // Horizontal illuminance from sky and horizontal beam illuminance (lux)
    7286              :             // obtained from solar quantities on weather file and luminous efficacy.
    7287              : 
    7288      1462278 :             DayltgLuminousEfficacy(state, state.dataEnvrn->PDIFLW, state.dataEnvrn->PDIRLW);
    7289      1462278 :             state.dataEnvrn->HISKF = SDIFH * state.dataEnvrn->PDIFLW;
    7290      1462278 :             state.dataEnvrn->HISUNF = SDIRH * state.dataEnvrn->PDIRLW;
    7291      1462278 :             state.dataEnvrn->HISUNFnorm = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->PDIRLW;
    7292              :         } else {
    7293      1463062 :             state.dataEnvrn->CloudFraction = 0.0;
    7294      1463062 :             state.dataEnvrn->PDIFLW = 0.0;
    7295      1463062 :             state.dataEnvrn->PDIRLW = 0.0;
    7296      1463062 :             state.dataEnvrn->HISKF = 0.0;
    7297      1463062 :             state.dataEnvrn->HISUNF = 0.0;
    7298      1463062 :             state.dataEnvrn->HISUNFnorm = 0.0;
    7299      1463062 :             state.dataEnvrn->SkyClearness = 0.0;
    7300      1463062 :             state.dataEnvrn->SkyBrightness = 0.0;
    7301              :         }
    7302      2925340 :     }
    7303              : 
    7304      1462278 :     void DayltgLuminousEfficacy(EnergyPlusData &state,
    7305              :                                 Real64 &DiffLumEff, // Luminous efficacy of sky diffuse solar radiation (lum/W)
    7306              :                                 Real64 &DirLumEff   // Luminous efficacy of beam solar radiation (lum/W)
    7307              :     )
    7308              :     {
    7309              :         // SUBROUTINE INFORMATION:
    7310              :         //       AUTHOR         Fred Winkelmann
    7311              :         //       DATE WRITTEN   July 1997
    7312              :         //       MODIFIED       August 2009, BG fixed upper bound for sky clearness bin 7
    7313              : 
    7314              :         // PURPOSE OF THIS SUBROUTINE:
    7315              :         // Uses diffuse horizontal solar irradiance, direct normal solar
    7316              :         // irradiance, atmospheric moisture and sun position
    7317              :         // to determine the luminous efficacy in lumens/watt
    7318              :         // of sky diffuse solar radiation and direct normal solar radiation.
    7319              :         // Based on an empirical method described in
    7320              :         // R. Perez, P. Ineichen, R. Seals, J. Michalsky and R. Stewart,
    7321              :         // "Modeling daylight availability and irradiance components from direct
    7322              :         // global irradiance components from direct and global irradiance,"
    7323              :         // Solar Energy 44 (1990) 271-289.
    7324              : 
    7325              :         // Diffuse luminous efficacy coefficients
    7326              :         static constexpr std::array<Real64, 8> ADiffLumEff = {97.24, 107.22, 104.97, 102.39, 100.71, 106.42, 141.88, 152.23};
    7327              :         static constexpr std::array<Real64, 8> BDiffLumEff = {-0.46, 1.15, 2.96, 5.59, 5.94, 3.83, 1.90, 0.35};
    7328              :         static constexpr std::array<Real64, 8> CDiffLumEff = {12.00, 0.59, -5.53, -13.95, -22.75, -36.15, -53.24, -45.27};
    7329              :         static constexpr std::array<Real64, 8> DDiffLumEff = {-8.91, -3.95, -8.77, -13.90, -23.74, -28.83, -14.03, -7.98};
    7330              :         // Direct luminous efficacy coefficients
    7331              :         static constexpr std::array<Real64, 8> ADirLumEff = {57.20, 98.99, 109.83, 110.34, 106.36, 107.19, 105.75, 101.18};
    7332              :         static constexpr std::array<Real64, 8> BDirLumEff = {-4.55, -3.46, -4.90, -5.84, -3.97, -1.25, 0.77, 1.58};
    7333              :         static constexpr std::array<Real64, 8> CDirLumEff = {-2.98, -1.21, -1.71, -1.99, -1.75, -1.51, -1.26, -1.10};
    7334              :         static constexpr std::array<Real64, 8> DDirLumEff = {117.12, 12.38, -8.81, -4.56, -6.16, -26.73, -34.44, -8.29};
    7335              :         // Monthly exterrestrial direct normal illuminance (lum/m2)
    7336              :         static constexpr std::array<Real64, 12> ExtraDirNormIll = {
    7337              :             131153.0, 130613.0, 128992.0, 126816.0, 124731.0, 123240.0, 122652.0, 123120.0, 124576.0, 126658.0, 128814.0, 130471.0};
    7338              : 
    7339      1462278 :         Real64 const SunZenith = std::acos(state.dataEnvrn->SOLCOS.z); // Solar zenith angle (radians)
    7340      1462278 :         Real64 const SunAltitude = Constant::PiOvr2 - SunZenith;       // Solar altitude angle (radians)
    7341      1462278 :         Real64 const SinSunAltitude = std::sin(SunAltitude);
    7342              :         // Clearness of sky. SkyClearness close to 1.0 corresponds to an overcast sky.
    7343              :         // SkyClearness > 6 is a clear sky.
    7344              :         // DifSolarRad is the diffuse horizontal irradiance.
    7345              :         // BeamSolarRad is the direct normal irradiance.
    7346      1462278 :         Real64 const Zeta = 1.041 * pow_3(SunZenith);
    7347      2924556 :         state.dataEnvrn->SkyClearness =
    7348      1462278 :             ((state.dataEnvrn->DifSolarRad + state.dataEnvrn->BeamSolarRad) / (state.dataEnvrn->DifSolarRad + 0.0001) + Zeta) / (1.0 + Zeta);
    7349              :         // Relative optical air mass
    7350              :         Real64 const relAirMass =
    7351      1462278 :             (1.0 - 0.1 * state.dataEnvrn->Elevation / 1000.0) / (SinSunAltitude + 0.15 / std::pow(SunAltitude / Constant::DegToRad + 3.885, 1.253));
    7352              :         // In the following, 93.73 is the extraterrestrial luminous efficacy
    7353      1462278 :         state.dataEnvrn->SkyBrightness = (state.dataEnvrn->DifSolarRad * 93.73) * relAirMass / ExtraDirNormIll[state.dataEnvrn->Month - 1];
    7354              :         int ISkyClearness; // Sky clearness bin
    7355      1462278 :         if (state.dataEnvrn->SkyClearness <= 1.065) {
    7356       548429 :             ISkyClearness = 0;
    7357       913849 :         } else if (state.dataEnvrn->SkyClearness <= 1.23) {
    7358        11742 :             ISkyClearness = 1;
    7359       902107 :         } else if (state.dataEnvrn->SkyClearness <= 1.50) {
    7360        15366 :             ISkyClearness = 2;
    7361       886741 :         } else if (state.dataEnvrn->SkyClearness <= 1.95) {
    7362        20863 :             ISkyClearness = 3;
    7363       865878 :         } else if (state.dataEnvrn->SkyClearness <= 2.80) {
    7364        99575 :             ISkyClearness = 4;
    7365       766303 :         } else if (state.dataEnvrn->SkyClearness <= 4.50) {
    7366       277987 :             ISkyClearness = 5;
    7367       488316 :         } else if (state.dataEnvrn->SkyClearness <= 6.20) {
    7368       177322 :             ISkyClearness = 6;
    7369              :         } else {
    7370       310994 :             ISkyClearness = 7;
    7371              :         }
    7372              : 
    7373              :         // Atmospheric moisture (cm of precipitable water)
    7374      1462278 :         Real64 const AtmosMoisture = std::exp(0.07 * state.dataEnvrn->OutDewPointTemp - 0.075);
    7375              :         // Sky diffuse luminous efficacy
    7376      1462278 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7377       505048 :             DiffLumEff = 0.0;
    7378              :         } else {
    7379       957230 :             DiffLumEff = ADiffLumEff[ISkyClearness] + BDiffLumEff[ISkyClearness] * AtmosMoisture +
    7380       957230 :                          CDiffLumEff[ISkyClearness] * state.dataEnvrn->SOLCOS.z +
    7381       957230 :                          DDiffLumEff[ISkyClearness] * std::log(state.dataEnvrn->SkyBrightness);
    7382              :         }
    7383              :         // Direct normal luminous efficacy
    7384      1462278 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7385       505048 :             DirLumEff = 0.0;
    7386              :         } else {
    7387       957230 :             DirLumEff =
    7388       957230 :                 max(0.0,
    7389       957230 :                     ADirLumEff[ISkyClearness] + BDirLumEff[ISkyClearness] * AtmosMoisture +
    7390       957230 :                         CDirLumEff[ISkyClearness] * std::exp(5.73 * SunZenith - 5.0) + DDirLumEff[ISkyClearness] * state.dataEnvrn->SkyBrightness);
    7391              :         }
    7392      1462278 :     }
    7393              : 
    7394         2145 :     Real64 GetSTM(Real64 const Longitude) // Longitude from user input
    7395              :     {
    7396              :         // FUNCTION INFORMATION:
    7397              :         //       AUTHOR         Linda K. Lawrie
    7398              :         //       DATE WRITTEN   August 2003
    7399              : 
    7400              :         // PURPOSE OF THIS FUNCTION:
    7401              :         // This function determines the "standard time meridian" from the input
    7402              :         // longitude. Calculates the proper Meridian from Longitude.  This
    7403              :         // value is needed for weather calculations so that the sun comes
    7404              :         // up and goes down at the right times.
    7405              : 
    7406              :         Real64 GetSTM;
    7407              : 
    7408         2145 :         Array1D<Real64> longl({-12, 12}); // Lower Longitude value for a Time Zone
    7409         2145 :         Array1D<Real64> longh({-12, 12}); // Upper Longitude value for a Time Zone
    7410              : 
    7411         2145 :         GetSTM = 0.0;
    7412              : 
    7413         2145 :         longl(0) = -7.5;
    7414         2145 :         longh(0) = 7.5;
    7415        27885 :         for (int i = 1; i <= 12; ++i) {
    7416        25740 :             longl(i) = longl(i - 1) + 15.0;
    7417        25740 :             longh(i) = longh(i - 1) + 15.0;
    7418              :         }
    7419        27885 :         for (int i = 1; i <= 12; ++i) {
    7420        25740 :             longl(-i) = longl(-i + 1) - 15.0;
    7421        25740 :             longh(-i) = longh(-i + 1) - 15.0;
    7422              :         }
    7423         2145 :         Real64 temp = mod(Longitude, 360.0);
    7424         2145 :         if (temp > 180.0) {
    7425            0 :             temp -= 180.0;
    7426              :         }
    7427              :         Real64 tz; // resultant tz meridian
    7428        13592 :         for (int i = -12; i <= 12; ++i) {
    7429        13592 :             if (temp > longl(i) && temp <= longh(i)) {
    7430         2145 :                 tz = mod(i, 24.0);
    7431         2145 :                 GetSTM = tz;
    7432         2145 :                 break;
    7433              :             }
    7434              :         }
    7435              : 
    7436         2145 :         return GetSTM;
    7437         2145 :     }
    7438              : 
    7439         6344 :     void ProcessEPWHeader(EnergyPlusData &state, EpwHeaderType const headerType, std::string &Line, bool &ErrorsFound)
    7440              :     {
    7441              : 
    7442              :         // SUBROUTINE INFORMATION:
    7443              :         //       AUTHOR         Linda Lawrie
    7444              :         //       DATE WRITTEN   December 1999
    7445              : 
    7446              :         // PURPOSE OF THIS SUBROUTINE:
    7447              :         // This subroutine processes each header line in the EPW weather file.
    7448              : 
    7449              :         // METHODOLOGY EMPLOYED:
    7450              :         // File is positioned to the correct line, then backspaced.  This routine
    7451              :         // reads in the line and processes as appropriate.
    7452              : 
    7453              :         Weather::DateType dateType;
    7454              :         int NumHdArgs;
    7455              : 
    7456              :         // Strip off Header value from Line
    7457         6344 :         std::string::size_type Pos = index(Line, ',');
    7458         6344 :         if ((Pos == std::string::npos) && !((headerType == EpwHeaderType::Comments1) || (headerType == EpwHeaderType::Comments2))) {
    7459            0 :             ShowSevereError(state, "Invalid Header line in in.epw -- no commas");
    7460            0 :             ShowContinueError(state, format("Line={}", Line));
    7461            0 :             ShowFatalError(state, "Previous conditions cause termination.");
    7462              :         }
    7463         6344 :         if (Pos != std::string::npos) {
    7464         6344 :             Line.erase(0, Pos + 1);
    7465              :         }
    7466              : 
    7467         6344 :         switch (headerType) {
    7468          793 :         case Weather::EpwHeaderType::Location: {
    7469              : 
    7470              :             // LOCATION, A1 [City], A2 [State/Province/Region], A3 [Country],
    7471              :             // A4 [Source], N1 [WMO], N2 [Latitude],
    7472              :             // N3 [Longitude], N4 [Time Zone], N5 [Elevation {m}]
    7473              : 
    7474          793 :             NumHdArgs = 9;
    7475         7930 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7476         7137 :                 strip(Line);
    7477         7137 :                 Pos = index(Line, ',');
    7478         7137 :                 if (Pos == std::string::npos) {
    7479          789 :                     if (len(Line) == 0) {
    7480            0 :                         while (Pos == std::string::npos) {
    7481            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7482            0 :                             strip(Line);
    7483            0 :                             uppercase(Line);
    7484            0 :                             Pos = index(Line, ',');
    7485              :                         }
    7486              :                     } else {
    7487          789 :                         Pos = len(Line);
    7488              :                     }
    7489              :                 }
    7490              : 
    7491         7137 :                 switch (i) {
    7492          793 :                 case 1:
    7493          793 :                     state.dataWeather->EPWHeaderTitle = stripped(Line.substr(0, Pos));
    7494          793 :                     break;
    7495         2379 :                 case 2:
    7496              :                 case 3:
    7497              :                 case 4:
    7498         2379 :                     state.dataWeather->EPWHeaderTitle = strip(state.dataWeather->EPWHeaderTitle) + ' ' + stripped(Line.substr(0, Pos));
    7499         2379 :                     break;
    7500          793 :                 case 5:
    7501          793 :                     state.dataWeather->EPWHeaderTitle += " WMO#=" + stripped(Line.substr(0, Pos));
    7502          793 :                     break;
    7503         3172 :                 case 6:
    7504              :                 case 7:
    7505              :                 case 8:
    7506              :                 case 9: {
    7507              :                     bool errFlag;
    7508         3172 :                     Real64 const Number = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7509         3172 :                     if (!errFlag) {
    7510         3172 :                         switch (i) {
    7511          793 :                         case 6:
    7512          793 :                             state.dataWeather->WeatherFileLatitude = Number;
    7513          793 :                             break;
    7514          793 :                         case 7:
    7515          793 :                             state.dataWeather->WeatherFileLongitude = Number;
    7516          793 :                             break;
    7517          793 :                         case 8:
    7518          793 :                             state.dataWeather->WeatherFileTimeZone = Number;
    7519          793 :                             break;
    7520          793 :                         case 9:
    7521          793 :                             state.dataWeather->WeatherFileElevation = Number;
    7522          793 :                             break;
    7523            0 :                         default:
    7524            0 :                             break;
    7525              :                         }
    7526              :                     }
    7527         3172 :                 } break;
    7528            0 :                 default:
    7529            0 :                     ShowSevereError(state, format("GetEPWHeader:LOCATION, invalid numeric={}", Line.substr(0, Pos)));
    7530            0 :                     ErrorsFound = true;
    7531            0 :                     break;
    7532              :                 }
    7533         7137 :                 Line.erase(0, Pos + 1);
    7534              :             }
    7535          793 :             state.dataEnvrn->WeatherFileLocationTitle = stripped(state.dataWeather->EPWHeaderTitle);
    7536          793 :         } break;
    7537          793 :         case Weather::EpwHeaderType::TypicalExtremePeriods: {
    7538          793 :             strip(Line);
    7539          793 :             Pos = index(Line, ',');
    7540          793 :             if (Pos == std::string::npos) {
    7541            0 :                 if (len(Line) == 0) {
    7542            0 :                     while (Pos == std::string::npos && len(Line) == 0) {
    7543            0 :                         Line = state.files.inputWeatherFile.readLine().data;
    7544            0 :                         strip(Line);
    7545            0 :                         Pos = index(Line, ',');
    7546              :                     }
    7547              :                 } else {
    7548            0 :                     Pos = len(Line);
    7549              :                 }
    7550              :             }
    7551              :             bool IOStatus;
    7552          793 :             state.dataWeather->NumEPWTypExtSets = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7553          793 :             Line.erase(0, Pos + 1);
    7554          793 :             state.dataWeather->TypicalExtremePeriods.allocate(state.dataWeather->NumEPWTypExtSets);
    7555          793 :             int TropExtremeCount = 0;
    7556         5422 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7557         4629 :                 strip(Line);
    7558         4629 :                 Pos = index(Line, ',');
    7559         4629 :                 if (Pos != std::string::npos) {
    7560         4629 :                     state.dataWeather->TypicalExtremePeriods(i).Title = Line.substr(0, Pos);
    7561         4629 :                     Line.erase(0, Pos + 1);
    7562              :                 } else {
    7563            0 :                     ShowWarningError(state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={}", Line.substr(0, Pos)));
    7564            0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7565            0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7566            0 :                     break;
    7567              :                 }
    7568         4629 :                 Pos = index(Line, ',');
    7569         4629 :                 if (Pos != std::string::npos) {
    7570         4629 :                     state.dataWeather->TypicalExtremePeriods(i).TEType = Line.substr(0, Pos);
    7571         4629 :                     Line.erase(0, Pos + 1);
    7572         4629 :                     if (Util::SameString(state.dataWeather->TypicalExtremePeriods(i).TEType, "EXTREME")) {
    7573         1586 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MAX")) {
    7574            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7575         1586 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MIN")) {
    7576            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7577         1586 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MAX")) {
    7578            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMax";
    7579         1586 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MIN")) {
    7580            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMin";
    7581              :                             // to account for problems earlier in weather files:
    7582         1586 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7583            0 :                             if (TropExtremeCount == 0) {
    7584            0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Max";
    7585            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7586            0 :                                 ++TropExtremeCount;
    7587            0 :                             } else if (TropExtremeCount == 1) {
    7588            0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Min";
    7589            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7590            0 :                                 ++TropExtremeCount;
    7591              :                             }
    7592              :                         } else { // make new short titles
    7593         1586 :                             if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7594          728 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7595          858 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7596          728 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7597          130 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7598           65 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7599           65 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7600           65 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7601            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7602            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7603            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7604            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7605            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7606            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7607            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7608            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7609            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7610            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7611            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7612            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7613              :                             }
    7614              :                         }
    7615              :                     } else { // not extreme
    7616         3043 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7617          728 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7618         2315 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7619          728 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7620         1587 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7621            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7622         1587 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7623            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7624         1587 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7625          728 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7626          859 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7627            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7628          859 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7629            1 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7630          858 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7631           65 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7632          793 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7633           65 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7634          728 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7635          728 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7636              :                         }
    7637              :                     }
    7638              :                 } else {
    7639            0 :                     ShowWarningError(state,
    7640            0 :                                      format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={} {}",
    7641            0 :                                             state.dataWeather->TypicalExtremePeriods(i).Title,
    7642            0 :                                             Line.substr(0, Pos)));
    7643            0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7644            0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7645            0 :                     break;
    7646              :                 }
    7647              :                 int PMonth;
    7648              :                 int PDay;
    7649              :                 int PWeekDay;
    7650         4629 :                 Pos = index(Line, ',');
    7651         4629 :                 if (Pos != std::string::npos) {
    7652         4629 :                     std::string dateStringUC = Line.substr(0, Pos);
    7653         4629 :                     dateStringUC = uppercase(dateStringUC);
    7654         4629 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7655         4629 :                     if (dateType != DateType::Invalid) {
    7656         4629 :                         if (PMonth != 0 && PDay != 0) {
    7657         4629 :                             state.dataWeather->TypicalExtremePeriods(i).StartMonth = PMonth;
    7658         4629 :                             state.dataWeather->TypicalExtremePeriods(i).StartDay = PDay;
    7659              :                         }
    7660              :                     } else {
    7661            0 :                         ShowSevereError(
    7662            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7663            0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7664            0 :                         ErrorsFound = true;
    7665              :                     }
    7666         4629 :                     Line.erase(0, Pos + 1);
    7667         4629 :                 }
    7668         4629 :                 Pos = index(Line, ',');
    7669         4629 :                 if (Pos != std::string::npos) {
    7670         3836 :                     std::string dateStringUC = Line.substr(0, Pos);
    7671         3836 :                     dateStringUC = uppercase(dateStringUC);
    7672         3836 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7673         3836 :                     if (dateType != DateType::Invalid) {
    7674         3836 :                         if (PMonth != 0 && PDay != 0) {
    7675         3836 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7676         3836 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7677              :                         }
    7678              :                     } else {
    7679            0 :                         ShowSevereError(
    7680            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7681            0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7682            0 :                         ErrorsFound = true;
    7683              :                     }
    7684         3836 :                     Line.erase(0, Pos + 1);
    7685         3836 :                 } else { // Pos=0, probably last one
    7686          793 :                     std::string const dateStringUC = uppercase(Line);
    7687          793 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7688          793 :                     if (dateType != DateType::Invalid) {
    7689          793 :                         if (PMonth != 0 && PDay != 0) {
    7690          793 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7691          793 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7692              :                         }
    7693              :                     } else {
    7694            0 :                         ShowSevereError(
    7695            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7696            0 :                         ErrorsFound = true;
    7697              :                     }
    7698          793 :                 }
    7699              :             }
    7700              :             // Process periods to set up other values.
    7701         5422 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7702         4629 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7703              :                 // JulianDay (Month,Day,LeapYearValue)
    7704         4629 :                 std::string const ExtremePeriodTitle = Util::makeUPPER(typicalExtPer.ShortTitle);
    7705         4629 :                 if (ExtremePeriodTitle == "SUMMER") {
    7706         1456 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7707          728 :                         typicalExtPer.MatchValue = "SummerExtreme";
    7708          728 :                         typicalExtPer.MatchValue1 = "TropicalHot";
    7709          728 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7710              :                     } else {
    7711          728 :                         typicalExtPer.MatchValue = "SummerTypical";
    7712              :                     }
    7713              : 
    7714         3173 :                 } else if (ExtremePeriodTitle == "WINTER") {
    7715         1456 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7716          728 :                         typicalExtPer.MatchValue = "WinterExtreme";
    7717          728 :                         typicalExtPer.MatchValue1 = "TropicalCold";
    7718          728 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7719              :                     } else {
    7720          728 :                         typicalExtPer.MatchValue = "WinterTypical";
    7721              :                     }
    7722              : 
    7723         1717 :                 } else if (ExtremePeriodTitle == "AUTUMN") {
    7724          728 :                     typicalExtPer.MatchValue = "AutumnTypical";
    7725              : 
    7726          989 :                 } else if (ExtremePeriodTitle == "SPRING") {
    7727          728 :                     typicalExtPer.MatchValue = "SpringTypical";
    7728              : 
    7729          261 :                 } else if (ExtremePeriodTitle == "WETSEASON") {
    7730           65 :                     typicalExtPer.MatchValue = "WetSeason";
    7731              : 
    7732          196 :                 } else if (ExtremePeriodTitle == "DRYSEASON") {
    7733           65 :                     typicalExtPer.MatchValue = "DrySeason";
    7734              : 
    7735          131 :                 } else if (ExtremePeriodTitle == "NOWETSEASON") {
    7736            1 :                     typicalExtPer.MatchValue = "NoWetSeason";
    7737              : 
    7738          130 :                 } else if (ExtremePeriodTitle == "NODRYSEASON") {
    7739            0 :                     typicalExtPer.MatchValue = "NoDrySeason";
    7740              : 
    7741          130 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMAX") || (ExtremePeriodTitle == "NOWETSEASONMAX")) {
    7742            0 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7743            0 :                     typicalExtPer.MatchValue1 = "TropicalHot";
    7744            0 :                     typicalExtPer.MatchValue2 = "SummerExtreme";
    7745              : 
    7746          130 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMIN") || (ExtremePeriodTitle == "NOWETSEASONMIN")) {
    7747            0 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7748            0 :                     typicalExtPer.MatchValue1 = "TropicalCold";
    7749            0 :                     typicalExtPer.MatchValue2 = "WinterExtreme";
    7750              : 
    7751          130 :                 } else if (ExtremePeriodTitle == "TROPICALHOT") {
    7752           65 :                     typicalExtPer.MatchValue = "TropicalHot";
    7753           65 :                     typicalExtPer.MatchValue1 = "SummerExtreme";
    7754           65 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7755              : 
    7756           65 :                 } else if (ExtremePeriodTitle == "TROPICALCOLD") {
    7757           65 :                     typicalExtPer.MatchValue = "TropicalCold";
    7758           65 :                     typicalExtPer.MatchValue1 = "WinterExtreme";
    7759           65 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7760              : 
    7761              :                 } else {
    7762            0 :                     typicalExtPer.MatchValue = "Invalid - no match";
    7763              :                 }
    7764         4629 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, 0);
    7765         4629 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, 0);
    7766         4629 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7767         4622 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7768              :                 } else {
    7769            7 :                     typicalExtPer.TotalDays =
    7770            7 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7771              :                 }
    7772         4629 :             }
    7773          793 :         } break;
    7774          793 :         case Weather::EpwHeaderType::GroundTemperatures: {
    7775              :             // Added for ground surfaces defined with F or c factor method. TH 7/2009
    7776              :             // Assume the 0.5 m set of ground temperatures
    7777              :             // or first set on a weather file, if any.
    7778          793 :             Pos = index(Line, ',');
    7779          793 :             if (Pos != std::string::npos) {
    7780              :                 bool errFlag;
    7781          793 :                 int NumGrndTemps = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7782          793 :                 if (!errFlag && NumGrndTemps >= 1) {
    7783          793 :                     Line.erase(0, Pos + 1);
    7784              :                     // skip depth, soil conductivity, soil density, soil specific heat
    7785         3965 :                     for (int i = 1; i <= 4; ++i) {
    7786         3172 :                         Pos = index(Line, ',');
    7787         3172 :                         if (Pos == std::string::npos) {
    7788            0 :                             Line.clear();
    7789            0 :                             break;
    7790              :                         }
    7791         3172 :                         Line.erase(0, Pos + 1);
    7792              :                     }
    7793          793 :                     state.dataWeather->GroundTempsFCFromEPWHeader = 0.0;
    7794          793 :                     int actcount = 0;
    7795        10309 :                     for (int i = 1; i <= 12; ++i) { // take the first set of ground temperatures.
    7796         9516 :                         Pos = index(Line, ',');
    7797         9516 :                         if (Pos != std::string::npos) {
    7798         9516 :                             state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7799         9516 :                             ++actcount;
    7800              :                         } else {
    7801            0 :                             if (len(Line) > 0) {
    7802            0 :                                 state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7803            0 :                                 ++actcount;
    7804              :                             }
    7805            0 :                             break;
    7806              :                         }
    7807         9516 :                         Line.erase(0, Pos + 1);
    7808              :                     }
    7809          793 :                     if (actcount == 12) {
    7810          793 :                         state.dataWeather->wthFCGroundTemps = true;
    7811              :                     }
    7812              :                 }
    7813              :             }
    7814          793 :         } break;
    7815          793 :         case Weather::EpwHeaderType::HolidaysDST: {
    7816              :             // A1, \field LeapYear Observed
    7817              :             // \type choice
    7818              :             // \key Yes
    7819              :             // \key No
    7820              :             // \note Yes if Leap Year will be observed for this file
    7821              :             // \note No if Leap Year days (29 Feb) should be ignored in this file
    7822              :             // A2, \field Daylight Saving Start Day
    7823              :             // A3, \field Daylight Saving End Day
    7824              :             // N1, \field Number of Holidays
    7825              :             // A4, \field Holiday 1 Name
    7826              :             // A5, \field Holiday 1 Day
    7827              :             // etc.
    7828              :             // Start with Minimum number of NumHdArgs
    7829          793 :             uppercase(Line);
    7830          793 :             NumHdArgs = 4;
    7831          793 :             int CurCount = 0;
    7832         3987 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7833         3194 :                 strip(Line);
    7834         3194 :                 Pos = index(Line, ',');
    7835         3194 :                 if (Pos == std::string::npos) {
    7836          789 :                     if (len(Line) == 0) {
    7837            0 :                         while (Pos == std::string::npos) {
    7838            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7839            0 :                             strip(Line);
    7840            0 :                             uppercase(Line);
    7841            0 :                             Pos = index(Line, ',');
    7842              :                         }
    7843              :                     } else {
    7844          789 :                         Pos = len(Line);
    7845              :                     }
    7846              :                 }
    7847              : 
    7848              :                 int PMonth;
    7849              :                 int PDay;
    7850              :                 int PWeekDay;
    7851              :                 bool IOStatus;
    7852         3194 :                 if (i == 1) {
    7853          793 :                     state.dataWeather->WFAllowsLeapYears = (Line[0] == 'Y');
    7854         2401 :                 } else if (i == 2) {
    7855              :                     // In this section, we call ProcessDateString, and if that fails, we can recover from it
    7856              :                     // by setting DST to false, so we don't affect ErrorsFound
    7857              : 
    7858              :                     // call ProcessDateString with local bool (unused)
    7859              :                     bool errflag1;
    7860          793 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, errflag1);
    7861          793 :                     if (dateType != DateType::Invalid) {
    7862              :                         // ErrorsFound is still false after ProcessDateString
    7863          793 :                         if (PMonth == 0 && PDay == 0) {
    7864          792 :                             state.dataWeather->EPWDaylightSaving = false;
    7865              :                         } else {
    7866            1 :                             state.dataWeather->EPWDaylightSaving = true;
    7867            1 :                             state.dataWeather->EPWDST.StDateType = dateType;
    7868            1 :                             state.dataWeather->EPWDST.StMon = PMonth;
    7869            1 :                             state.dataWeather->EPWDST.StDay = PDay;
    7870            1 :                             state.dataWeather->EPWDST.StWeekDay = PWeekDay;
    7871              :                         }
    7872              :                     } else {
    7873              :                         // ErrorsFound is untouched
    7874            0 :                         ShowContinueError(
    7875            0 :                             state, format("ProcessEPWHeader: Invalid Daylight Saving Period Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7876            0 :                         ShowContinueError(state, format("...invalid header={}", epwHeaders[static_cast<int>(headerType)]));
    7877            0 :                         ShowContinueError(state, "...Setting Weather File DST to false.");
    7878            0 :                         state.dataWeather->EPWDaylightSaving = false;
    7879              :                     }
    7880              : 
    7881         1608 :                 } else if (i == 3) {
    7882          793 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7883          793 :                     if (state.dataWeather->EPWDaylightSaving) {
    7884            1 :                         if (dateType != DateType::Invalid) {
    7885            1 :                             state.dataWeather->EPWDST.EnDateType = dateType;
    7886            1 :                             state.dataWeather->EPWDST.EnMon = PMonth;
    7887            1 :                             state.dataWeather->EPWDST.EnDay = PDay;
    7888            1 :                             state.dataWeather->EPWDST.EnWeekDay = PWeekDay;
    7889              :                         } else {
    7890            0 :                             ShowWarningError(
    7891              :                                 state,
    7892            0 :                                 format("ProcessEPWHeader: Invalid Daylight Saving Period End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7893            0 :                             ShowContinueError(state, "...Setting Weather File DST to false.");
    7894            0 :                             state.dataWeather->EPWDaylightSaving = false;
    7895              :                         }
    7896            1 :                         state.dataWeather->DST = state.dataWeather->EPWDST;
    7897              :                     }
    7898              : 
    7899          815 :                 } else if (i == 4) {
    7900          793 :                     int NumEPWHolidays = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7901         1586 :                     state.dataWeather->NumSpecialDays =
    7902          793 :                         NumEPWHolidays + state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriodControl:SpecialDays");
    7903          793 :                     state.dataWeather->SpecialDays.allocate(state.dataWeather->NumSpecialDays);
    7904          793 :                     NumHdArgs = 4 + NumEPWHolidays * 2;
    7905              : 
    7906           22 :                 } else if ((i >= 5)) {
    7907           22 :                     if (mod(i, 2) != 0) {
    7908           11 :                         ++CurCount;
    7909           11 :                         if (CurCount > state.dataWeather->NumSpecialDays) {
    7910            0 :                             ShowSevereError(state, "Too many SpecialDays");
    7911            0 :                             ErrorsFound = true;
    7912              :                         } else {
    7913           11 :                             state.dataWeather->SpecialDays(CurCount).Name = Line.substr(0, Pos);
    7914              :                         }
    7915              :                         // Process name
    7916              :                     } else {
    7917           11 :                         if (CurCount <= state.dataWeather->NumSpecialDays) {
    7918           11 :                             auto &specialDay = state.dataWeather->SpecialDays(CurCount);
    7919              :                             // Process date
    7920           11 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7921           11 :                             if (dateType == DateType::MonthDay) {
    7922            6 :                                 specialDay.dateType = dateType;
    7923            6 :                                 specialDay.Month = PMonth;
    7924            6 :                                 specialDay.Day = PDay;
    7925            6 :                                 specialDay.WeekDay = 0;
    7926            6 :                                 specialDay.CompDate = PMonth * 32 + PDay;
    7927            6 :                                 specialDay.Duration = 1;
    7928            6 :                                 specialDay.DayType = 1;
    7929            6 :                                 specialDay.WthrFile = true;
    7930            5 :                             } else if (dateType != DateType::Invalid) {
    7931            5 :                                 specialDay.dateType = dateType;
    7932            5 :                                 specialDay.Month = PMonth;
    7933            5 :                                 specialDay.Day = PDay;
    7934            5 :                                 specialDay.WeekDay = PWeekDay;
    7935            5 :                                 specialDay.CompDate = 0;
    7936            5 :                                 specialDay.Duration = 1;
    7937            5 :                                 specialDay.DayType = 1;
    7938            5 :                                 specialDay.WthrFile = true;
    7939              :                             } else {
    7940            0 :                                 ShowSevereError(state, format("Invalid SpecialDay Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7941            0 :                                 ErrorsFound = true;
    7942              :                             }
    7943              :                         }
    7944              :                     }
    7945              :                 }
    7946         3194 :                 Line.erase(0, Pos + 1);
    7947              :             }
    7948         5422 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7949              :                 // General::OrdinalDay (Month,Day,LeapYearValue)
    7950         4629 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7951         4629 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, state.dataWeather->LeapYearAdd);
    7952         4629 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, state.dataWeather->LeapYearAdd);
    7953         4629 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7954         4622 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7955              :                 } else {
    7956            7 :                     typicalExtPer.TotalDays =
    7957            7 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7958              :                 }
    7959              :             }
    7960          793 :         } break;
    7961         2379 :         case Weather::EpwHeaderType::Comments1:
    7962              :         case Weather::EpwHeaderType::Comments2:
    7963              :         case Weather::EpwHeaderType::DesignConditions: {
    7964              :             // no action
    7965         2379 :         } break;
    7966          793 :         case Weather::EpwHeaderType::DataPeriods: {
    7967              :             //     N1, \field Number of Data Periods
    7968              :             //     N2, \field Number of Records per hour
    7969              :             //     A1, \field Data Period 1 Name/Description
    7970              :             //     A2, \field Data Period 1 Start Day of Week
    7971              :             //       \type choice
    7972              :             //       \key  Sunday
    7973              :             //       \key  Monday
    7974              :             //       \key  Tuesday
    7975              :             //       \key  Wednesday
    7976              :             //       \key  Thursday
    7977              :             //       \key  Friday
    7978              :             //       \key  Saturday
    7979              :             //     A3, \field Data Period 1 Start Day
    7980              :             //     A4, \field Data Period 1 End Day
    7981          793 :             uppercase(Line);
    7982          793 :             NumHdArgs = 2;
    7983          793 :             int CurCount = 0;
    7984         5551 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7985         4758 :                 strip(Line);
    7986         4758 :                 Pos = index(Line, ',');
    7987         4758 :                 if (Pos == std::string::npos) {
    7988          793 :                     if (len(Line) == 0) {
    7989            0 :                         while (Pos == std::string::npos) {
    7990            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7991            0 :                             strip(Line);
    7992            0 :                             uppercase(Line);
    7993            0 :                             Pos = index(Line, ',');
    7994              :                         }
    7995              :                     } else {
    7996          793 :                         Pos = len(Line);
    7997              :                     }
    7998              :                 }
    7999              : 
    8000              :                 bool IOStatus;
    8001         4758 :                 if (i == 1) {
    8002          793 :                     state.dataWeather->NumDataPeriods = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    8003          793 :                     state.dataWeather->DataPeriods.allocate(state.dataWeather->NumDataPeriods);
    8004          793 :                     NumHdArgs += 4 * state.dataWeather->NumDataPeriods;
    8005          793 :                     if (state.dataWeather->NumDataPeriods > 0) {
    8006         1586 :                         for (auto &e : state.dataWeather->DataPeriods) {
    8007          793 :                             e.NumDays = 0;
    8008          793 :                         }
    8009              :                     }
    8010              : 
    8011         3965 :                 } else if (i == 2) {
    8012          793 :                     state.dataWeather->NumIntervalsPerHour = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    8013         3172 :                 } else if (i >= 3) {
    8014         3172 :                     int const CurOne = mod(i - 3, 4);
    8015              :                     int PMonth;
    8016              :                     int PDay;
    8017              :                     int PWeekDay;
    8018              :                     int PYear;
    8019         3172 :                     if (CurOne == 0) {
    8020              :                         // Description of Data Period
    8021          793 :                         ++CurCount;
    8022          793 :                         if (CurCount > state.dataWeather->NumDataPeriods) {
    8023            0 :                             ShowSevereError(state, "Too many data periods");
    8024            0 :                             ErrorsFound = true;
    8025              :                         } else {
    8026          793 :                             state.dataWeather->DataPeriods(CurCount).Name = Line.substr(0, Pos);
    8027              :                         }
    8028              : 
    8029         2379 :                     } else if (CurOne == 1) {
    8030              :                         // Start Day of Week
    8031          793 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    8032          793 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    8033          793 :                             dataPeriod.DayOfWeek = Line.substr(0, Pos);
    8034          793 :                             dataPeriod.WeekDay = getEnumValue(Sched::dayTypeNamesUC, dataPeriod.DayOfWeek);
    8035          793 :                             if (dataPeriod.WeekDay < 1 || dataPeriod.WeekDay > 7) {
    8036            0 :                                 ShowSevereError(state,
    8037            0 :                                                 fmt::format("Weather File -- Invalid Start Day of Week for Data Period #{}, Invalid day={}",
    8038              :                                                             CurCount,
    8039            0 :                                                             dataPeriod.DayOfWeek));
    8040            0 :                                 ErrorsFound = true;
    8041              :                             }
    8042              :                         }
    8043              : 
    8044         1586 :                     } else if (CurOne == 2) {
    8045              :                         // DataPeriod Start Day
    8046          793 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    8047          793 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    8048          793 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    8049          793 :                             if (dateType == DateType::MonthDay) {
    8050          793 :                                 dataPeriod.StMon = PMonth;
    8051          793 :                                 dataPeriod.StDay = PDay;
    8052          793 :                                 dataPeriod.StYear = PYear;
    8053          793 :                                 if (PYear != 0) {
    8054            0 :                                     dataPeriod.HasYearData = true;
    8055              :                                 }
    8056              :                             } else {
    8057            0 :                                 ShowSevereError(state,
    8058            0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day> (WeatherFile), found={}",
    8059            0 :                                                        Line.substr(0, Pos)));
    8060            0 :                                 ErrorsFound = true;
    8061              :                             }
    8062              :                         }
    8063              : 
    8064          793 :                     } else if (CurOne == 3) {
    8065          793 :                         auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    8066          793 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    8067          793 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    8068          793 :                             if (dateType == DateType::MonthDay) {
    8069          793 :                                 dataPeriod.EnMon = PMonth;
    8070          793 :                                 dataPeriod.EnDay = PDay;
    8071          793 :                                 dataPeriod.EnYear = PYear;
    8072          793 :                                 if (PYear == 0 && dataPeriod.HasYearData) {
    8073            0 :                                     ShowWarningError(state, "Data Period (WeatherFile) - Start Date contains year. End Date does not.");
    8074            0 :                                     ShowContinueError(state, "...Assuming same year as Start Date for this data.");
    8075            0 :                                     dataPeriod.EnYear = dataPeriod.StYear;
    8076              :                                 }
    8077              :                             } else {
    8078            0 :                                 ShowSevereError(state,
    8079            0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day>, (WeatherFile) found={}",
    8080            0 :                                                        Line.substr(0, Pos)));
    8081            0 :                                 ErrorsFound = true;
    8082              :                             }
    8083              :                         }
    8084          793 :                         if (dataPeriod.StYear == 0 || dataPeriod.EnYear == 0) {
    8085          793 :                             dataPeriod.DataStJDay = General::OrdinalDay(dataPeriod.StMon, dataPeriod.StDay, state.dataWeather->LeapYearAdd);
    8086          793 :                             dataPeriod.DataEnJDay = General::OrdinalDay(dataPeriod.EnMon, dataPeriod.EnDay, state.dataWeather->LeapYearAdd);
    8087          793 :                             if (dataPeriod.DataStJDay <= dataPeriod.DataEnJDay) {
    8088          793 :                                 dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    8089              :                             } else {
    8090            0 :                                 dataPeriod.NumDays = (365 - dataPeriod.DataStJDay + 1) + (dataPeriod.DataEnJDay - 1 + 1);
    8091              :                             }
    8092              :                         } else { // weather file has actual year(s)
    8093            0 :                             dataPeriod.DataStJDay = computeJulianDate(dataPeriod.StYear, dataPeriod.StMon, dataPeriod.StDay);
    8094            0 :                             dataPeriod.DataEnJDay = computeJulianDate(dataPeriod.EnYear, dataPeriod.EnMon, dataPeriod.EnDay);
    8095            0 :                             dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    8096              :                         }
    8097              :                         // Have processed the last item for this, can set up Weekdays for months
    8098          793 :                         dataPeriod.MonWeekDay = 0;
    8099          793 :                         if (!ErrorsFound) {
    8100         2379 :                             SetupWeekDaysByMonth(state,
    8101          793 :                                                  state.dataWeather->DataPeriods(CurCount).StMon,
    8102          793 :                                                  state.dataWeather->DataPeriods(CurCount).StDay,
    8103          793 :                                                  state.dataWeather->DataPeriods(CurCount).WeekDay,
    8104          793 :                                                  state.dataWeather->DataPeriods(CurCount).MonWeekDay);
    8105              :                         }
    8106              :                     }
    8107              :                 }
    8108         4758 :                 Line.erase(0, Pos + 1);
    8109              :             }
    8110          793 :         } break;
    8111            0 :         default: {
    8112              :             // Invalid header type
    8113            0 :             assert(false);
    8114              :         } break;
    8115              :         }
    8116         6344 :     }
    8117              : 
    8118         5009 :     void SkipEPlusWFHeader(EnergyPlusData &state)
    8119              :     {
    8120              : 
    8121              :         // SUBROUTINE INFORMATION:
    8122              :         //       AUTHOR         Linda K. Lawrie
    8123              :         //       DATE WRITTEN   August 2000
    8124              : 
    8125              :         // PURPOSE OF THIS SUBROUTINE:
    8126              :         // This subroutine skips the initial header records on the EnergyPlus Weather File (in.epw).
    8127              : 
    8128              :         static constexpr std::string_view Header("DATA PERIODS");
    8129              : 
    8130              :         // Read in Header Information
    8131        10018 :         InputFile::ReadResult<std::string> Line{"", true, false};
    8132              : 
    8133              :         // Headers should come in order
    8134              :         while (true) {
    8135        40072 :             Line = state.files.inputWeatherFile.readLine();
    8136        40072 :             if (Line.eof) {
    8137            0 :                 ShowFatalError(state,
    8138            0 :                                format("Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}", Header),
    8139            0 :                                OptionalOutputFileRef{state.files.eso});
    8140              :             }
    8141        40072 :             uppercase(Line.data);
    8142        40072 :             if (has(Line.data, Header)) {
    8143         5009 :                 break;
    8144              :             }
    8145              :         }
    8146              : 
    8147              :         // Dummy process Data Periods line
    8148              :         //  'DATA PERIODS'
    8149              :         //     N1, \field Number of Data Periods
    8150              :         //     N2, \field Number of Records per hour
    8151              :         //     A1, \field Data Period 1 Name/Description
    8152              :         //     A2, \field Data Period 1 Start Day of Week
    8153              :         //       \type choice
    8154              :         //       \key  Sunday
    8155              :         //       \key  Monday
    8156              :         //       \key  Tuesday
    8157              :         //       \key  Wednesday
    8158              :         //       \key  Thursday
    8159              :         //       \key  Friday
    8160              :         //       \key  Saturday
    8161              :         //     A3, \field Data Period 1 Start Day
    8162              :         //     A4, \field Data Period 1 End Day
    8163              : 
    8164         5009 :         int NumHdArgs = 2;
    8165         5009 :         int CurCount = 0;
    8166        15027 :         for (int i = 1; i <= NumHdArgs; ++i) {
    8167        10018 :             strip(Line.data);
    8168        10018 :             std::string::size_type Pos = index(Line.data, ',');
    8169        10018 :             if (Pos == std::string::npos) {
    8170            0 :                 if (len(Line.data) == 0) {
    8171            0 :                     while (Pos == std::string::npos) {
    8172            0 :                         Line = state.files.inputWeatherFile.readLine();
    8173            0 :                         strip(Line.data);
    8174            0 :                         uppercase(Line.data);
    8175            0 :                         Pos = index(Line.data, ',');
    8176              :                     }
    8177              :                 } else {
    8178            0 :                     Pos = len(Line.data);
    8179              :                 }
    8180              :             }
    8181              : 
    8182        10018 :             if (i == 1) {
    8183              :                 bool IOStatus;
    8184         5009 :                 int const NumPeriods = Util::ProcessNumber(Line.data.substr(0, Pos), IOStatus);
    8185         5009 :                 NumHdArgs += 4 * NumPeriods;
    8186         5009 :             } else if ((i >= 3)) {
    8187            0 :                 if (mod(i - 3, 4) == 0) {
    8188            0 :                     ++CurCount;
    8189              :                 }
    8190              :             }
    8191        10018 :             Line.data.erase(0, Pos + 1);
    8192              :         }
    8193         5009 :     }
    8194              : 
    8195         1233 :     void ReportMissing_RangeData(EnergyPlusData &state)
    8196              :     {
    8197              : 
    8198              :         // SUBROUTINE INFORMATION:
    8199              :         //       AUTHOR         Linda Lawrie
    8200              :         //       DATE WRITTEN   January 2002
    8201              : 
    8202              :         // PURPOSE OF THIS SUBROUTINE:
    8203              :         // This subroutine reports the counts of missing/out of range data
    8204              :         // for weather file environments.
    8205              : 
    8206              :         static constexpr std::string_view MissString("Missing Data Found on Weather Data File");
    8207              :         static constexpr std::string_view msFmt("Missing {}, Number of items={:5}");
    8208              :         static constexpr std::string_view InvString("Invalid Data Found on Weather Data File");
    8209              :         static constexpr std::string_view ivFmt("Invalid {}, Number of items={:5}");
    8210              :         static constexpr std::string_view RangeString("Out of Range Data Found on Weather Data File");
    8211              :         static constexpr std::string_view rgFmt("Out of Range {} [{},{}], Number of items={:5}");
    8212              : 
    8213         1233 :         if (!state.dataEnvrn->DisplayWeatherMissingDataWarnings) {
    8214         1233 :             return;
    8215              :         }
    8216              : 
    8217            0 :         bool MissedHeader = false;
    8218            0 :         auto missedHeaderCheck = [&](Real64 const value, std::string const &description) {
    8219            0 :             if (value > 0) {
    8220            0 :                 if (!MissedHeader) {
    8221            0 :                     ShowWarningError(state, std::string{MissString});
    8222            0 :                     MissedHeader = true;
    8223              :                 }
    8224            0 :                 ShowMessage(state, format(msFmt, "\"" + description + "\"", value));
    8225              :             }
    8226            0 :         };
    8227              : 
    8228            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDryBulbTemp, "Dry Bulb Temperature");
    8229            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutBaroPress, "Atmospheric Pressure");
    8230            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutRelHum, "Relative Humidity");
    8231            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDewPointTemp, "Dew Point Temperatures");
    8232            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindSpeed, "Wind Speed");
    8233            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindDir, "Wind Direction");
    8234            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.BeamSolarRad, "Direct Radiation");
    8235            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.DifSolarRad, "Diffuse Radiation");
    8236            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.TotalSkyCover, "Total Sky Cover");
    8237            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OpaqueSkyCover, "Opaque Sky Cover");
    8238            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.SnowDepth, "Snow Depth");
    8239            0 :         if (state.dataWeather->wvarsMissedCounts.WeathCodes > 0) {
    8240            0 :             ShowWarningError(state, std::string{InvString});
    8241            0 :             ShowMessage(state, format(ivFmt, "\"Weather Codes\" (not equal 9 digits)", state.dataWeather->wvarsMissedCounts.WeathCodes));
    8242              :         }
    8243            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.LiquidPrecip, "Liquid Precipitation Depth");
    8244              : 
    8245            0 :         bool OutOfRangeHeader = false;
    8246              :         auto outOfRangeHeaderCheck = // (AUTO_OK_LAMBDA)
    8247            0 :             [&](Real64 const value, std::string_view description, std::string_view rangeLow, std::string_view rangeHigh, std::string_view extraMsg) {
    8248            0 :                 if (value > 0) {
    8249            0 :                     if (!OutOfRangeHeader) {
    8250            0 :                         ShowWarningError(state, std::string{RangeString});
    8251            0 :                         OutOfRangeHeader = true;
    8252              :                     }
    8253            0 :                     ShowMessage(state, EnergyPlus::format(rgFmt, description, rangeLow, rangeHigh, value));
    8254            0 :                     if (!extraMsg.empty()) {
    8255            0 :                         ShowMessage(state, std::string{extraMsg});
    8256              :                     }
    8257              :                 }
    8258            0 :             };
    8259            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp, "Dry Bulb Temperatures", ">=-90", "<=70", "");
    8260            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress,
    8261              :                               "Atmospheric Pressure",
    8262              :                               ">31000",
    8263              :                               "<=120000",
    8264              :                               "Out of Range values set to last good value");
    8265            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutRelHum, "Relative Humidity", ">=0", "<=110", "");
    8266            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp, "Dew Point Temperatures", ">=-90", "<=70", "");
    8267            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindSpeed, "Wind Speed", ">=0", "<=40", "");
    8268            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindDir, "Wind Direction", ">=0", "<=360", "");
    8269            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad, "Direct Radiation", ">=0", "NoLimit", "");
    8270            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad, "Diffuse Radiation", ">=0", "NoLimit", "");
    8271              :     }
    8272              : 
    8273          801 :     void SetupInterpolationValues(EnergyPlusData &state)
    8274              :     {
    8275              : 
    8276              :         // SUBROUTINE INFORMATION:
    8277              :         //       AUTHOR         Linda Lawrie
    8278              :         //       DATE WRITTEN   November 2002
    8279              : 
    8280              :         // PURPOSE OF THIS SUBROUTINE:
    8281              :         // This subroutine creates the "interpolation" values / weights that are used for
    8282              :         // interpolating weather data from hourly down to the time step level.
    8283              : 
    8284              :         // METHODOLOGY EMPLOYED:
    8285              :         // Create arrays (InterpolationValues, SolarInterpolationValues) dependent on
    8286              :         // Number of Time Steps in Hour.  This will be used in the "SetCurrentWeather" procedure.
    8287              : 
    8288          801 :         state.dataWeather->Interpolation.allocate(state.dataGlobal->TimeStepsInHour);
    8289          801 :         state.dataWeather->SolarInterpolation.allocate(state.dataGlobal->TimeStepsInHour);
    8290          801 :         state.dataWeather->Interpolation = 0.0;
    8291          801 :         state.dataWeather->SolarInterpolation = 0.0;
    8292              : 
    8293         5390 :         for (int tloop = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop) {
    8294         4589 :             state.dataWeather->Interpolation(tloop) =
    8295         4589 :                 (state.dataGlobal->TimeStepsInHour == 1) ? 1.0 : min(1.0, (double(tloop) / double(state.dataGlobal->TimeStepsInHour)));
    8296              :         }
    8297              : 
    8298          801 :         if (mod(state.dataGlobal->TimeStepsInHour, 2) == 0) {
    8299              :             // even number of time steps.
    8300          786 :             int halfpoint = state.dataGlobal->TimeStepsInHour / 2;
    8301              : 
    8302          786 :             state.dataWeather->SolarInterpolation(halfpoint) = 1.0;
    8303          786 :             Real64 tweight = 1.0 / double(state.dataGlobal->TimeStepsInHour);
    8304         3073 :             for (int tloop = halfpoint + 1, hpoint = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop, ++hpoint) {
    8305         2287 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8306              :             }
    8307         2287 :             for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8308         1501 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8309              :             }
    8310              :         } else { // odd number of time steps
    8311           15 :             if (state.dataGlobal->TimeStepsInHour == 1) {
    8312           15 :                 state.dataWeather->SolarInterpolation(1) = 0.5;
    8313            0 :             } else if (state.dataGlobal->TimeStepsInHour == 3) {
    8314            0 :                 state.dataWeather->SolarInterpolation(1) = 5.0 / 6.0;
    8315            0 :                 state.dataWeather->SolarInterpolation(2) = 5.0 / 6.0;
    8316            0 :                 state.dataWeather->SolarInterpolation(3) = 0.5;
    8317              :             } else {
    8318            0 :                 Real64 tweight = 1.0 / double(state.dataGlobal->TimeStepsInHour);
    8319            0 :                 int halfpoint = state.dataGlobal->TimeStepsInHour / 2;
    8320            0 :                 Real64 tweight1 = 1.0 - tweight / 2.0;
    8321            0 :                 state.dataWeather->SolarInterpolation(halfpoint) = tweight1;
    8322            0 :                 state.dataWeather->SolarInterpolation(halfpoint + 1) = tweight1;
    8323            0 :                 for (int tloop = halfpoint + 2, hpoint = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop, ++hpoint) {
    8324            0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8325              :                 }
    8326            0 :                 for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8327            0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8328              :                 }
    8329              :             }
    8330              :         }
    8331          801 :     }
    8332              : 
    8333          802 :     void SetupEnvironmentTypes(EnergyPlusData &state)
    8334              :     {
    8335              : 
    8336              :         // SUBROUTINE INFORMATION:
    8337              :         //       AUTHOR         Linda Lawrie
    8338              :         //       DATE WRITTEN   October 2010
    8339              : 
    8340              :         // PURPOSE OF THIS SUBROUTINE:
    8341              :         // Make sure Environment derived type is set prior to getting
    8342              :         // Weather Properties
    8343              : 
    8344              :         // Transfer weather file information to the Environment derived type
    8345          802 :         state.dataWeather->Envrn = state.dataEnvrn->TotDesDays + 1;
    8346              : 
    8347              :         // Sizing Periods from Weather File
    8348          807 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunDesPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8349            5 :             auto const &runPer = state.dataWeather->RunPeriodDesignInput(iRunPer);
    8350            5 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8351              : 
    8352            5 :             envCurr.StartMonth = runPer.startMonth;
    8353            5 :             envCurr.StartDay = runPer.startDay;
    8354            5 :             envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, state.dataWeather->LeapYearAdd);
    8355            5 :             envCurr.TotalDays = runPer.totalDays;
    8356            5 :             envCurr.EndMonth = runPer.endMonth;
    8357            5 :             envCurr.EndDay = runPer.endDay;
    8358            5 :             envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, state.dataWeather->LeapYearAdd);
    8359            5 :             envCurr.NumSimYears = runPer.numSimYears;
    8360            5 :             if (envCurr.StartJDay <= envCurr.EndJDay) {
    8361            5 :                 envCurr.TotalDays = (envCurr.EndJDay - envCurr.StartJDay + 1) * envCurr.NumSimYears;
    8362              :             } else {
    8363            0 :                 envCurr.TotalDays =
    8364            0 :                     (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - envCurr.StartJDay + 1 + envCurr.EndJDay) * envCurr.NumSimYears;
    8365              :             }
    8366            5 :             state.dataEnvrn->TotRunDesPersDays += envCurr.TotalDays;
    8367            5 :             envCurr.UseDST = runPer.useDST;
    8368            5 :             envCurr.UseHolidays = runPer.useHolidays;
    8369            5 :             envCurr.Title = runPer.title;
    8370            5 :             envCurr.cKindOfEnvrn = runPer.periodType;
    8371            5 :             envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    8372            5 :             envCurr.DesignDayNum = 0;
    8373            5 :             envCurr.RunPeriodDesignNum = iRunPer;
    8374            5 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8375            5 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8376            5 :             envCurr.SetWeekDays = false;
    8377            5 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8378            5 :             envCurr.UseRain = runPer.useRain;
    8379            5 :             envCurr.UseSnow = runPer.useSnow;
    8380            5 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // this will just the default
    8381              :         }
    8382              : 
    8383              :         // RunPeriods from weather file
    8384         1995 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8385         1193 :             auto const &runPer = state.dataWeather->RunPeriodInput(iRunPer);
    8386         1193 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8387              : 
    8388         1193 :             envCurr.StartMonth = runPer.startMonth;
    8389         1193 :             envCurr.StartDay = runPer.startDay;
    8390         1193 :             envCurr.StartYear = runPer.startYear;
    8391         1193 :             envCurr.EndMonth = runPer.endMonth;
    8392         1193 :             envCurr.EndDay = runPer.endDay;
    8393         1193 :             envCurr.EndYear = runPer.endYear;
    8394         1193 :             envCurr.NumSimYears = runPer.numSimYears;
    8395         1193 :             envCurr.CurrentYear = runPer.startYear;
    8396         1193 :             envCurr.IsLeapYear = runPer.isLeapYear;
    8397         1193 :             envCurr.TreatYearsAsConsecutive = true;
    8398         1193 :             if (runPer.actualWeather) {
    8399              :                 // This will require leap years to be present, thus Julian days can be used for all the calculations
    8400            0 :                 envCurr.StartJDay = envCurr.StartDate = runPer.startJulianDate;
    8401            0 :                 envCurr.EndJDay = envCurr.EndDate = runPer.endJulianDate;
    8402            0 :                 envCurr.TotalDays = envCurr.EndDate - envCurr.StartDate + 1;
    8403            0 :                 envCurr.RawSimDays = envCurr.EndDate - envCurr.StartDate + 1;
    8404            0 :                 envCurr.MatchYear = true;
    8405            0 :                 envCurr.ActualWeather = true;
    8406              :             } else { // std RunPeriod
    8407         1193 :                 envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8408         1193 :                 if (envCurr.StartYear == envCurr.EndYear) {
    8409              :                     // Short-circuit all the calculations, we're in a single year
    8410              : 
    8411         1187 :                     envCurr.IsLeapYear = isLeapYear(envCurr.StartYear) && state.dataWeather->WFAllowsLeapYears;
    8412         1187 :                     int LocalLeapYearAdd = (int)envCurr.IsLeapYear;
    8413              : 
    8414         1187 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, LocalLeapYearAdd);
    8415         1187 :                     envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, LocalLeapYearAdd);
    8416         1187 :                     envCurr.RawSimDays = (envCurr.EndJDay - envCurr.StartJDay + 1);
    8417         1187 :                     envCurr.TotalDays = envCurr.RawSimDays;
    8418              :                 } else {
    8419              :                     // Environment crosses year boundaries
    8420            6 :                     envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8421            6 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, (int)runPer.isLeapYear);
    8422           12 :                     envCurr.EndJDay = General::OrdinalDay(
    8423            6 :                         runPer.endMonth, runPer.endDay, (int)(isLeapYear(runPer.endYear) && state.dataWeather->WFAllowsLeapYears));
    8424            6 :                     envCurr.TotalDays = 366 - envCurr.StartJDay + envCurr.EndJDay + 365 * std::max(envCurr.NumSimYears - 2, 0);
    8425            6 :                     if (state.dataWeather->WFAllowsLeapYears) {
    8426              :                         // First year
    8427            0 :                         if (envCurr.StartJDay < 59) {
    8428            0 :                             if (isLeapYear(envCurr.StartYear)) {
    8429            0 :                                 ++envCurr.TotalDays;
    8430              :                             }
    8431              :                         }
    8432              :                         // Middle years
    8433            0 :                         for (int yr = envCurr.StartYear + 1; yr < envCurr.EndYear; ++yr) {
    8434            0 :                             if (isLeapYear(yr)) {
    8435            0 :                                 ++envCurr.TotalDays;
    8436              :                             }
    8437              :                         }
    8438              :                         // Last year not needed, the end ordinal date will take this into account
    8439              :                     }
    8440            6 :                     envCurr.RawSimDays = envCurr.TotalDays;
    8441              :                 }
    8442              :             }
    8443         1193 :             envCurr.UseDST = runPer.useDST;
    8444         1193 :             envCurr.UseHolidays = runPer.useHolidays;
    8445         1193 :             if (runPer.title.empty()) {
    8446            1 :                 envCurr.Title = state.dataEnvrn->WeatherFileLocationTitle;
    8447              :             } else {
    8448         1192 :                 envCurr.Title = runPer.title;
    8449              :             }
    8450         1193 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::ReadAllWeatherData) {
    8451            1 :                 envCurr.cKindOfEnvrn = "ReadAllWeatherDataRunPeriod";
    8452              :             } else {
    8453         1192 :                 envCurr.cKindOfEnvrn = "WeatherFileRunPeriod";
    8454         1192 :                 envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    8455              :             }
    8456         1193 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8457         1193 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8458         1193 :             envCurr.SetWeekDays = false;
    8459         1193 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8460         1193 :             envCurr.UseRain = runPer.useRain;
    8461         1193 :             envCurr.UseSnow = runPer.useSnow;
    8462         1193 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // first hour interpolation choice
    8463              :         } // for (i)
    8464          802 :     }
    8465              : 
    8466         2384 :     bool isLeapYear(int const Year)
    8467              :     {
    8468              :         // true if it's a leap year, false if not.
    8469              : 
    8470         2384 :         if (mod(Year, 4) == 0) { // Potential Leap Year
    8471            2 :             if (!(mod(Year, 100) == 0 && mod(Year, 400) != 0)) {
    8472            2 :                 return true;
    8473              :             }
    8474              :         }
    8475         2382 :         return false;
    8476              :     }
    8477              : 
    8478         9317 :     int computeJulianDate(int const gyyyy, // input/output gregorian year, should be specified as 4 digits
    8479              :                           int const gmm,   // input/output gregorian month
    8480              :                           int const gdd    // input/output gregorian day
    8481              :     )
    8482              :     {
    8483              :         // SUBROUTINE INFORMATION:
    8484              :         //       AUTHOR         Jason DeGraw
    8485              :         //       DATE WRITTEN   10/25/2017
    8486              : 
    8487              :         // PURPOSE OF THIS SUBROUTINE:
    8488              :         // Split the former JGDate function in two. Convert a gregorian
    8489              :         // date to actual julian date.  the advantage of storing a julian date
    8490              :         // in the jdate format rather than a 5 digit format is that any
    8491              :         // number of days can be add or subtracted to jdate and
    8492              :         // that result is a proper julian date.
    8493              : 
    8494              :         // REFERENCES:
    8495              :         // for discussion of this algorithm,
    8496              :         // see cacm, vol 11, no 10, oct 1968, page 657
    8497              : 
    8498         9317 :         int tyyyy = gyyyy;
    8499         9317 :         int tmm = gmm;
    8500         9317 :         int tdd = gdd;
    8501         9317 :         int l = (tmm - 14) / 12;
    8502         9317 :         return tdd - 32075 + 1461 * (tyyyy + 4800 + l) / 4 + 367 * (tmm - 2 - l * 12) / 12 - 3 * ((tyyyy + 4900 + l) / 100) / 4;
    8503              :     }
    8504              : 
    8505            0 :     int computeJulianDate(GregorianDate const &gdate)
    8506              :     {
    8507            0 :         return computeJulianDate(gdate.year, gdate.month, gdate.day);
    8508              :     }
    8509              : 
    8510            0 :     GregorianDate computeGregorianDate(int const jdate)
    8511              :     {
    8512            0 :         int tdate = jdate;
    8513            0 :         int l = tdate + 68569;
    8514            0 :         int n = 4 * l / 146097;
    8515            0 :         l -= (146097 * n + 3) / 4;
    8516            0 :         int tyyyy = 4000 * (l + 1) / 1461001;
    8517            0 :         l = l - 1461 * tyyyy / 4 + 31;
    8518            0 :         int tmm = 80 * l / 2447;
    8519            0 :         int tdd = l - 2447 * tmm / 80;
    8520            0 :         l = tmm / 11;
    8521            0 :         tmm += 2 - 12 * l;
    8522            0 :         tyyyy += 100 * (n - 49) + l;
    8523            0 :         return {tyyyy, tmm, tdd};
    8524              :     }
    8525              : 
    8526          154 :     Sched::DayType calculateDayOfWeek(EnergyPlusData &state, int const year, int const month, int const day)
    8527              :     {
    8528              : 
    8529              :         // FUNCTION INFORMATION:
    8530              :         //       AUTHOR         Linda Lawrie
    8531              :         //       DATE WRITTEN   March 2012
    8532              :         //       MODIFIED       October 2017, Jason DeGraw
    8533              : 
    8534              :         // PURPOSE OF THIS FUNCTION:
    8535              :         // Calculate the correct day of week.
    8536              : 
    8537              :         // METHODOLOGY EMPLOYED:
    8538              :         // Zeller's algorithm.
    8539              : 
    8540              :         // REFERENCES:
    8541              :         // http://en.wikipedia.org/wiki/Zeller%27s_congruence
    8542              :         // and other references around the web.
    8543              : 
    8544          154 :         int Gyyyy(year); // Gregorian yyyy
    8545          154 :         int Gmm(month);  // Gregorian mm
    8546              : 
    8547              :         // Jan, Feb are 13, 14 months of previous year
    8548          154 :         if (Gmm < 3) {
    8549           91 :             Gmm += 12;
    8550           91 :             --Gyyyy;
    8551              :         }
    8552              : 
    8553          154 :         state.dataEnvrn->DayOfWeek = mod(day + (13 * (Gmm + 1) / 5) + Gyyyy + (Gyyyy / 4) + 6 * (Gyyyy / 100) + (Gyyyy / 400), 7);
    8554          154 :         if (state.dataEnvrn->DayOfWeek == 0) {
    8555           43 :             state.dataEnvrn->DayOfWeek = 7;
    8556              :         }
    8557              : 
    8558          154 :         return static_cast<Sched::DayType>(state.dataEnvrn->DayOfWeek);
    8559              :     }
    8560              : 
    8561         1037 :     int calculateDayOfYear(int const Month, int const Day, bool const leapYear)
    8562              :     {
    8563              : 
    8564              :         // FUNCTION INFORMATION:
    8565              :         //       AUTHOR         Jason DeGraw
    8566              :         //       DATE WRITTEN   October 10, 2017
    8567              : 
    8568              :         // PURPOSE OF THIS FUNCTION:
    8569              :         // Compute the day of the year for leap and non-leap years.
    8570              : 
    8571              :         static std::array<int, 12> const daysbefore{{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}};
    8572              :         static std::array<int, 12> const daysbeforeleap{{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
    8573              : 
    8574              :         // Could probably do some bounds checking here, but for now assume the month is in [1, 12]
    8575         1037 :         if (leapYear) {
    8576            0 :             return daysbeforeleap[Month - 1] + Day;
    8577              :         } else {
    8578         1037 :             return daysbefore[Month - 1] + Day;
    8579              :         }
    8580              :     }
    8581              : 
    8582         2382 :     bool validMonthDay(int const month, int const day, int const leapYearAdd)
    8583              :     {
    8584              : 
    8585              :         // FUNCTION INFORMATION:
    8586              :         //       AUTHOR         Jason DeGraw
    8587              :         //       DATE WRITTEN   October 31, 2017
    8588              : 
    8589              :         // PURPOSE OF THIS FUNCTION:
    8590              :         // Determine if a month/day+leapyear combination is valid.
    8591              : 
    8592         2382 :         switch (month) {
    8593         2222 :         case 1:
    8594              :         case 3:
    8595              :         case 5:
    8596              :         case 7:
    8597              :         case 8:
    8598              :         case 10:
    8599              :         case 12:
    8600         2222 :             if (day > 31) {
    8601            0 :                 return false;
    8602              :             }
    8603         2222 :             break;
    8604          119 :         case 4:
    8605              :         case 6:
    8606              :         case 9:
    8607              :         case 11:
    8608          119 :             if (day > 30) {
    8609            0 :                 return false;
    8610              :             }
    8611          119 :             break;
    8612           41 :         case 2:
    8613           41 :             if (day > 28 + leapYearAdd) {
    8614            0 :                 return false;
    8615              :             }
    8616           41 :             break;
    8617            0 :         default:
    8618            0 :             return false;
    8619              :         }
    8620         2382 :         return true;
    8621              :     }
    8622              : 
    8623            0 :     void AnnualMonthlyDryBulbWeatherData::CalcAnnualAndMonthlyDryBulbTemp(EnergyPlusData &state)
    8624              :     {
    8625              : 
    8626              :         // PURPOSE OF THIS SUBROUTINE:
    8627              :         // Calculates monthly daily average outdoor air drybulb temperature from
    8628              :         // either weather (*.EPW) file or reads monthly daily average outdoor air
    8629              :         // drybulb temperature from STAT (*.stat) for use to autosize main water
    8630              :         // temperature.
    8631              : 
    8632            0 :         Real64 MonthlyDailyDryBulbMin(200.0);               // monthly-daily minimum outside air dry-bulb temperature
    8633            0 :         Real64 MonthlyDailyDryBulbMax(-200.0);              // monthly-daily maximum outside air dry-bulb temperature
    8634            0 :         Real64 AnnualDailyAverageDryBulbTempSum(0.0);       // annual sum of daily average outside air dry-bulb temperature
    8635            0 :         Array1D<Real64> MonthlyAverageDryBulbTemp(12, 0.0); // monthly-daily average outside air temperature
    8636              : 
    8637            0 :         if (!this->OADryBulbWeatherDataProcessed) {
    8638            0 :             const bool statFileExists = FileSystem::fileExists(state.files.inStatFilePath.filePath);
    8639            0 :             const bool epwFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    8640            0 :             if (statFileExists) {
    8641            0 :                 auto statFile = state.files.inStatFilePath.try_open();
    8642            0 :                 if (!statFile.good()) {
    8643            0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", statFile.filePath));
    8644            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8645            0 :                     return;
    8646              :                 }
    8647              : 
    8648            0 :                 std::string lineAvg;
    8649            0 :                 while (statFile.good()) {
    8650            0 :                     auto lineIn = statFile.readLine();
    8651            0 :                     if (has(lineIn.data, "Monthly Statistics for Dry Bulb temperatures")) {
    8652            0 :                         for (int i = 1; i <= 7; ++i) {
    8653            0 :                             lineIn = statFile.readLine();
    8654              :                         }
    8655            0 :                         lineIn = statFile.readLine();
    8656            0 :                         lineAvg = lineIn.data;
    8657            0 :                         break;
    8658              :                     }
    8659            0 :                 }
    8660            0 :                 if (lineAvg.empty()) {
    8661            0 :                     ShowSevereError(
    8662              :                         state,
    8663            0 :                         format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have Monthly Statistics for Dry Bulb temperatures.",
    8664              :                                statFile.filePath));
    8665            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8666            0 :                     return;
    8667            0 :                 } else if (lineAvg.find("Daily Avg") == std::string::npos) {
    8668            0 :                     ShowSevereError(state,
    8669            0 :                                     format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have the 'Daily Avg' line in the Monthly "
    8670              :                                            "Statistics for Dry Bulb temperatures.",
    8671              :                                            statFile.filePath));
    8672            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8673            0 :                     return;
    8674              :                 } else {
    8675            0 :                     int AnnualNumberOfDays = 0;
    8676            0 :                     for (int i = 1; i <= 12; ++i) {
    8677            0 :                         MonthlyAverageDryBulbTemp(i) = OutputReportTabular::StrToReal(OutputReportTabular::GetColumnUsingTabs(lineAvg, i + 2));
    8678            0 :                         AnnualDailyAverageDryBulbTempSum += MonthlyAverageDryBulbTemp(i) * state.dataWeather->EndDayOfMonth(i);
    8679            0 :                         MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyAverageDryBulbTemp(i));
    8680            0 :                         MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyAverageDryBulbTemp(i));
    8681            0 :                         AnnualNumberOfDays += state.dataWeather->EndDayOfMonth(i);
    8682              :                     }
    8683            0 :                     this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8684            0 :                     this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8685            0 :                     this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8686            0 :                     this->OADryBulbWeatherDataProcessed = true;
    8687              :                 }
    8688            0 :             } else if (epwFileExists) {
    8689            0 :                 auto epwFile = state.files.inputWeatherFilePath.try_open();
    8690            0 :                 bool epwHasLeapYear(false);
    8691            0 :                 if (!epwFile.good()) {
    8692            0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", epwFile.filePath));
    8693            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8694            0 :                     return;
    8695              :                 }
    8696            0 :                 for (int i = 1; i <= 8; ++i) { // Headers
    8697            0 :                     auto epwLine = epwFile.readLine();
    8698              : 
    8699            0 :                     if (i == 5) {
    8700              :                         // HOLIDAYS/DAYLIGHT SAVINGS,Yes,0,0,0
    8701            0 :                         std::string::size_type pos = index(epwLine.data, ',');
    8702            0 :                         epwLine.data.erase(0, pos + 1);
    8703            0 :                         pos = index(epwLine.data, ',');
    8704            0 :                         std::string LeapYear = Util::makeUPPER(epwLine.data.substr(0, pos));
    8705            0 :                         if (LeapYear[0] == 'Y') {
    8706            0 :                             epwHasLeapYear = true;
    8707              :                         }
    8708            0 :                     }
    8709            0 :                 }
    8710            0 :                 Array1D<int> EndDayOfMonthLocal;
    8711            0 :                 EndDayOfMonthLocal = state.dataWeather->EndDayOfMonth;
    8712            0 :                 if (epwHasLeapYear) {
    8713              :                     // increase number of days for february by one day if weather data has leap year
    8714            0 :                     EndDayOfMonthLocal(2) = EndDayOfMonthLocal(2) + 1;
    8715              :                 }
    8716            0 :                 for (int i = 1; i <= 12; ++i) {
    8717            0 :                     Real64 MonthlyDailyDryBulbAvg = 0.0;
    8718            0 :                     int DaysCountOfMonth = EndDayOfMonthLocal(i);
    8719            0 :                     for (int DayNum = 1; DayNum <= DaysCountOfMonth; ++DayNum) {
    8720            0 :                         Real64 DailyAverageDryBulbTemp = 0.0;
    8721              :                         std::string::size_type pos;
    8722            0 :                         for (int j = 1; j <= 24; ++j) {
    8723            0 :                             auto epwLine = epwFile.readLine();
    8724            0 :                             for (int ind = 1; ind <= 6; ++ind) {
    8725            0 :                                 pos = index(epwLine.data, ',');
    8726            0 :                                 epwLine.data.erase(0, pos + 1);
    8727              :                             }
    8728            0 :                             pos = index(epwLine.data, ',');
    8729            0 :                             Real64 HourlyDryBulbTemp = OutputReportTabular::StrToReal(epwLine.data.substr(0, pos));
    8730            0 :                             DailyAverageDryBulbTemp += (HourlyDryBulbTemp / 24.0);
    8731            0 :                         }
    8732            0 :                         AnnualDailyAverageDryBulbTempSum += DailyAverageDryBulbTemp;
    8733            0 :                         MonthlyDailyDryBulbAvg += (DailyAverageDryBulbTemp / DaysCountOfMonth);
    8734              :                     }
    8735            0 :                     MonthlyAverageDryBulbTemp(i) = MonthlyDailyDryBulbAvg;
    8736            0 :                     MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyDailyDryBulbAvg);
    8737            0 :                     MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyDailyDryBulbAvg);
    8738              :                 }
    8739              :                 // calculate annual average outdoor air dry-bulb temperature and monthly daily average
    8740              :                 // outdoor air temperature maximum difference
    8741            0 :                 int AnnualNumberOfDays = 365;
    8742            0 :                 if (epwHasLeapYear) {
    8743            0 :                     AnnualNumberOfDays++;
    8744              :                 }
    8745            0 :                 this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8746            0 :                 this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8747            0 :                 this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8748            0 :                 this->OADryBulbWeatherDataProcessed = true;
    8749            0 :             } else {
    8750            0 :                 ShowSevereError(state, "CalcAnnualAndMonthlyDryBulbTemp: weather file or stat file does not exist.");
    8751            0 :                 ShowContinueError(state, format("Weather file: {}.", state.files.inputWeatherFilePath.filePath));
    8752            0 :                 ShowContinueError(state, format("Stat file: {}.", state.files.inStatFilePath.filePath));
    8753            0 :                 ShowContinueError(state, "Water Mains Monthly Temperature cannot be calculated using CorrelationFromWeatherFile method.");
    8754            0 :                 ShowContinueError(state, "Instead a fixed default value of 10.0 C will be used.");
    8755              :             }
    8756              :         }
    8757            0 :     }
    8758              : 
    8759          801 :     void ReportWaterMainsTempParameters(EnergyPlusData &state)
    8760              :     {
    8761              :         // PURPOSE OF THIS SUBROUTINE:
    8762              :         // report site water mains temperature object user inputs and/or parameters calculated
    8763              :         // from weather or stat file
    8764              : 
    8765          801 :         if (!state.files.eio.good()) {
    8766            0 :             return;
    8767              :         }
    8768              : 
    8769          801 :         std::stringstream ss;
    8770          801 :         auto *eiostream = &ss;
    8771              : 
    8772              :         // Write annual average OA temperature and maximum difference in monthly-daily average outdoor air temperature
    8773              :         *eiostream << "! <Site Water Mains Temperature Information>"
    8774              :                       ",Calculation Method{}"
    8775              :                       ",Water Mains Temperature Schedule Name{}"
    8776              :                       ",Annual Average Outdoor Air Temperature{C}"
    8777              :                       ",Maximum Difference In Monthly Average Outdoor Air Temperatures{deltaC}"
    8778          801 :                       ",Fixed Default Water Mains Temperature{C}\n";
    8779              : 
    8780          801 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    8781            5 :         case WaterMainsTempCalcMethod::Schedule:
    8782            5 :             *eiostream << "Site Water Mains Temperature Information,";
    8783            5 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8784           10 :                        << state.dataWeather->waterMainsTempSched->Name << ",";
    8785            5 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8786           10 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8787            5 :             *eiostream << "NA\n";
    8788            5 :             break;
    8789          128 :         case WaterMainsTempCalcMethod::Correlation:
    8790          128 :             *eiostream << "Site Water Mains Temperature Information,";
    8791          128 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << "," << "NA" << ",";
    8792          128 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8793          256 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8794          128 :             *eiostream << "NA\n";
    8795          128 :             break;
    8796            0 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    8797            0 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    8798            0 :                 *eiostream << "Site Water Mains Temperature Information,";
    8799            0 :                 *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << "," << "NA" << ",";
    8800            0 :                 *eiostream << format("{:.2R}", state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp) << ","
    8801            0 :                            << format("{:.2R}", state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff) << "," << "NA\n";
    8802              :             } else {
    8803            0 :                 *eiostream << "Site Water Mains Temperature Information,";
    8804            0 :                 *eiostream << "FixedDefault" << "," << "NA" << "," << "NA" << "," << "NA" << "," << format("{:.1R}", 10.0) << '\n';
    8805              :             }
    8806            0 :             break;
    8807          668 :         default:
    8808          668 :             *eiostream << "Site Water Mains Temperature Information,";
    8809          668 :             *eiostream << "FixedDefault" << "," << "NA" << "," << "NA" << "," << "NA" << "," << format("{:.1R}", 10.0) << '\n';
    8810          668 :             break;
    8811              :         }
    8812              : 
    8813          801 :         print(state.files.eio, "{}", ss.str());
    8814          801 :     }
    8815              : 
    8816       518592 :     void calcSky(EnergyPlusData &state,
    8817              :                  Real64 &HorizIRSky,
    8818              :                  Real64 &SkyTemp,
    8819              :                  Real64 OpaqueSkyCover,
    8820              :                  Real64 DryBulb,
    8821              :                  Real64 DewPoint,
    8822              :                  Real64 RelHum,
    8823              :                  Real64 IRHoriz)
    8824              :     {
    8825       518592 :         if (IRHoriz <= 0.0) {
    8826            0 :             IRHoriz = 9999.0;
    8827              :         }
    8828              : 
    8829       518592 :         auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8830       518592 :         if (!envCurr.UseWeatherFileHorizontalIR || IRHoriz >= 9999.0) {
    8831              :             // Missing or user defined to not use IRHoriz from weather, using sky cover and clear sky emissivity
    8832            0 :             Real64 ESky = CalcSkyEmissivity(state, envCurr.skyTempModel, OpaqueSkyCover, DryBulb, DewPoint, RelHum);
    8833            0 :             HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    8834            0 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8835            0 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8836            0 :                 SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    8837              :             } else {
    8838            0 :                 SkyTemp = 0.0; // dealt with later
    8839              :             }
    8840            0 :         } else {
    8841              :             // Valid IR from weather files
    8842       518592 :             HorizIRSky = IRHoriz;
    8843       518592 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8844       518592 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8845       518592 :                 SkyTemp = root_4(IRHoriz / Constant::StefanBoltzmann) - Constant::Kelvin;
    8846              :             } else {
    8847            0 :                 SkyTemp = 0.0; // dealt with later
    8848              :             }
    8849              :         }
    8850       518592 :     }
    8851              : 
    8852              : } // namespace Weather
    8853              : 
    8854              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1