LCOV - code coverage report
Current view: top level - EnergyPlus - WeatherManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 58.7 % 4529 2660
Test Date: 2025-05-22 16:09:37 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       326115 :     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       326115 :         InitializeWeather(state, state.dataWeather->PrintEnvrnStamp);
     145              : 
     146              :         // Cannot call this during sizing, because EMS will not initialize properly until after simulation kickoff
     147       326115 :         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     148       255311 :             bool anyEMSRan = false;
     149       255311 :             EMSManager::ManageEMS(state,
     150              :                                   EMSManager::EMSCallFrom::BeginZoneTimestepBeforeSetCurrentWeather,
     151              :                                   anyEMSRan,
     152       510622 :                                   ObjexxFCL::Optional_int_const()); // calling point
     153              :         }
     154       326115 :         SetCurrentWeather(state);
     155              : 
     156       326115 :         ReportWeatherAndTimeInformation(state, state.dataWeather->PrintEnvrnStamp);
     157       326115 :     }
     158              : 
     159          292 :     void ResetEnvironmentCounter(EnergyPlusData &state)
     160              :     {
     161          292 :         state.dataWeather->Envrn = 0;
     162          292 :     }
     163              : 
     164           67 :     bool CheckIfAnyUnderwaterBoundaries(EnergyPlusData &state)
     165              :     {
     166           67 :         bool errorsFound = false;
     167           67 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     168              : 
     169           67 :         constexpr std::string_view routineName = "CheckIfAnyUnderwaterBoundaries";
     170              : 
     171           67 :         auto const &ipsc = state.dataIPShortCut;
     172           67 :         ipsc->cCurrentModuleObject = "SurfaceProperty:Underwater";
     173           67 :         int Num = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
     174           69 :         for (int i = 1; i <= Num; i++) {
     175            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     176            2 :                                                                      ipsc->cCurrentModuleObject,
     177              :                                                                      i,
     178            2 :                                                                      ipsc->cAlphaArgs,
     179              :                                                                      NumAlpha,
     180            2 :                                                                      ipsc->rNumericArgs,
     181              :                                                                      NumNumber,
     182              :                                                                      IOStat,
     183            2 :                                                                      ipsc->lNumericFieldBlanks,
     184            2 :                                                                      ipsc->lAlphaFieldBlanks,
     185            2 :                                                                      ipsc->cAlphaFieldNames,
     186            2 :                                                                      ipsc->cNumericFieldNames);
     187            2 :             state.dataWeather->underwaterBoundaries.emplace_back();
     188            2 :             auto &underwaterBoundary = state.dataWeather->underwaterBoundaries[i - 1];
     189            2 :             underwaterBoundary.Name = ipsc->cAlphaArgs(1);
     190              : 
     191            2 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, underwaterBoundary.Name};
     192              : 
     193            2 :             underwaterBoundary.distanceFromLeadingEdge = ipsc->rNumericArgs(1);
     194            2 :             underwaterBoundary.OSCMIndex = Util::FindItemInList(underwaterBoundary.Name, state.dataSurface->OSCM);
     195            2 :             if (underwaterBoundary.OSCMIndex <= 0) {
     196            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
     197            0 :                 errorsFound = true;
     198              :             }
     199              : 
     200            2 :             if (ipsc->lAlphaFieldBlanks(2)) {
     201            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
     202            0 :                 errorsFound = true;
     203            2 :             } 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            2 :             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            2 :             if (errorsFound) break;
     215              :         }
     216           67 :         if (errorsFound) {
     217            0 :             ShowFatalError(state, "Previous input problems cause program termination");
     218              :         }
     219           67 :         return (Num > 0);
     220              :     }
     221              : 
     222              :     Real64
     223            5 :     calculateWaterBoundaryConvectionCoefficient(Real64 const curWaterTemp, Real64 const freeStreamVelocity, Real64 const distanceFromLeadingEdge)
     224              :     {
     225            5 :         Real64 constexpr waterKinematicViscosity = 1e-6; // m2/s
     226            5 :         Real64 constexpr waterPrandtlNumber = 6;         // -
     227            5 :         Real64 constexpr waterThermalConductivity = 0.6; // W/mK
     228              :         // do some calculation for forced convection from the leading edge of the ship
     229            5 :         Real64 const localReynoldsNumber = freeStreamVelocity * distanceFromLeadingEdge / waterKinematicViscosity;
     230            5 :         Real64 const localNusseltNumber = 0.0296 * pow(localReynoldsNumber, 0.8) * pow(waterPrandtlNumber, 1.0 / 3.0);
     231            5 :         Real64 const localConvectionCoeff = localNusseltNumber * waterThermalConductivity / distanceFromLeadingEdge;
     232              : 
     233              :         // do some calculations for natural convection from the bottom of the ship
     234            5 :         Real64 constexpr distanceFromBottomOfHull = 12; // meters, assumed for now
     235              :                                                         // this Prandtl correction is from Incropera & Dewitt, Intro to HT, eq 9.20
     236            5 :         Real64 const prandtlCorrection =
     237              :             (0.75 * pow(waterPrandtlNumber, 0.5)) / pow(0.609 + 1.221 * pow(waterPrandtlNumber, 0.5) + 1.238 * waterPrandtlNumber, 0.25);
     238              :         // calculate the Grashof number
     239            5 :         Real64 constexpr gravity = 9.81;          // m/s2
     240            5 :         Real64 constexpr beta = 0.000214;         // water thermal expansion coefficient, from engineeringtoolbox.com, 1/C
     241            5 :         Real64 constexpr assumedSurfaceTemp = 25; // Grashof requires a surface temp, this should suffice
     242              :         Real64 const localGrashofNumber =
     243            5 :             (gravity * beta * std::abs(assumedSurfaceTemp - curWaterTemp) * pow(distanceFromBottomOfHull, 3)) / pow(waterKinematicViscosity, 2);
     244            5 :         Real64 const localNusseltFreeConvection = pow(localGrashofNumber / 4, 0.25) * prandtlCorrection;
     245            5 :         Real64 const localConvectionCoeffFreeConv = localNusseltFreeConvection * waterThermalConductivity / distanceFromBottomOfHull;
     246            5 :         return max(localConvectionCoeff, localConvectionCoeffFreeConv);
     247              :     }
     248              : 
     249            0 :     void UpdateUnderwaterBoundaries(EnergyPlusData &state)
     250              :     {
     251            0 :         for (auto &thisBoundary : state.dataWeather->underwaterBoundaries) {
     252            0 :             Real64 const curWaterTemp = thisBoundary.waterTempSched->getCurrentVal(); // C
     253            0 :             Real64 freeStreamVelocity = 0;
     254            0 :             if (thisBoundary.velocitySched != nullptr) {
     255            0 :                 freeStreamVelocity = thisBoundary.velocitySched->getCurrentVal(); // m/s
     256              :             }
     257            0 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TConv = curWaterTemp;
     258            0 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HConv =
     259            0 :                 Weather::calculateWaterBoundaryConvectionCoefficient(curWaterTemp, freeStreamVelocity, thisBoundary.distanceFromLeadingEdge);
     260            0 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TRad = curWaterTemp;
     261            0 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HRad = 0.0;
     262              :         }
     263            0 :     }
     264              : 
     265           73 :     void ReadVariableLocationOrientation(EnergyPlusData &state)
     266              :     {
     267              :         static constexpr std::string_view routineName = "ReadVariableLocationOrientation";
     268              : 
     269           73 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     270           73 :         auto const &ipsc = state.dataIPShortCut;
     271              : 
     272           73 :         ipsc->cCurrentModuleObject = "Site:VariableLocation";
     273           73 :         if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject) == 0) return;
     274            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     275            0 :                                                                  ipsc->cCurrentModuleObject,
     276              :                                                                  1,
     277            0 :                                                                  ipsc->cAlphaArgs,
     278              :                                                                  NumAlpha,
     279            0 :                                                                  ipsc->rNumericArgs,
     280              :                                                                  NumNumber,
     281              :                                                                  IOStat,
     282            0 :                                                                  ipsc->lNumericFieldBlanks,
     283            0 :                                                                  ipsc->lAlphaFieldBlanks,
     284            0 :                                                                  ipsc->cAlphaFieldNames,
     285            0 :                                                                  ipsc->cNumericFieldNames);
     286              : 
     287            0 :         ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ""};
     288              : 
     289            0 :         if (ipsc->lAlphaFieldBlanks(1)) {
     290            0 :         } else if ((state.dataEnvrn->varyingLocationLatSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(1))) == nullptr) {
     291            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
     292              :         }
     293              : 
     294            0 :         if (ipsc->lAlphaFieldBlanks(2)) {
     295            0 :         } else if ((state.dataEnvrn->varyingLocationLongSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(2))) == nullptr) {
     296            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     297              :         }
     298              : 
     299            0 :         if (ipsc->lAlphaFieldBlanks(3)) {
     300            0 :         } else if ((state.dataEnvrn->varyingOrientationSched = Sched::GetSchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
     301            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     302              :         }
     303              :     }
     304              : 
     305            0 :     void UpdateLocationAndOrientation(EnergyPlusData &state)
     306              :     {
     307            0 :         if (state.dataEnvrn->varyingLocationLatSched != nullptr) {
     308            0 :             state.dataEnvrn->Latitude = state.dataEnvrn->varyingLocationLatSched->getCurrentVal();
     309              :         }
     310            0 :         if (state.dataEnvrn->varyingLocationLongSched != nullptr) {
     311            0 :             state.dataEnvrn->Longitude = state.dataEnvrn->varyingLocationLongSched->getCurrentVal();
     312              :         }
     313              : 
     314            0 :         CheckLocationValidity(state);
     315            0 :         if (state.dataEnvrn->varyingOrientationSched != nullptr) {
     316            0 :             state.dataHeatBal->BuildingAzimuth = mod(state.dataEnvrn->varyingOrientationSched->getCurrentVal(), 360.0);
     317            0 :             state.dataSurfaceGeometry->CosBldgRelNorth =
     318            0 :                 std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
     319            0 :             state.dataSurfaceGeometry->SinBldgRelNorth =
     320            0 :                 std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
     321            0 :             for (size_t SurfNum = 1; SurfNum < state.dataSurface->Surface.size(); ++SurfNum) {
     322            0 :                 auto &surf = state.dataSurface->Surface(SurfNum);
     323            0 :                 for (int n = 1; n <= surf.Sides; ++n) {
     324            0 :                     Real64 Xb = surf.Vertex(n).x;
     325            0 :                     Real64 Yb = surf.Vertex(n).y;
     326            0 :                     surf.NewVertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
     327            0 :                     surf.NewVertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
     328            0 :                     surf.NewVertex(n).z = surf.Vertex(n).z;
     329              :                 }
     330            0 :                 Vectors::CreateNewellSurfaceNormalVector(surf.NewVertex, surf.Sides, surf.NewellSurfaceNormalVector);
     331            0 :                 Real64 SurfWorldAz = 0.0;
     332            0 :                 Real64 SurfTilt = 0.0;
     333            0 :                 Vectors::DetermineAzimuthAndTilt(
     334            0 :                     surf.NewVertex, SurfWorldAz, SurfTilt, surf.lcsx, surf.lcsy, surf.lcsz, surf.NewellSurfaceNormalVector);
     335            0 :                 surf.Azimuth = SurfWorldAz;
     336            0 :                 surf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
     337            0 :                 surf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
     338            0 :                 surf.OutNormVec = surf.NewellSurfaceNormalVector;
     339              :             }
     340              :         }
     341            0 :     }
     342              : 
     343          851 :     bool GetNextEnvironment(EnergyPlusData &state, bool &Available, bool &ErrorsFound)
     344              :     {
     345              : 
     346              :         // SUBROUTINE INFORMATION:
     347              :         //       AUTHOR         Linda Lawrie
     348              :         //       DATE WRITTEN   August 2000
     349              : 
     350              :         // PURPOSE OF THIS SUBROUTINE:
     351              :         // This subroutine is called from the outer simulation manager and determines
     352              :         // if another environment is available in the "run list" or if the end has been
     353              :         // reached.
     354              : 
     355              :         static constexpr std::string_view RoutineName("GetNextEnvironment: ");
     356              :         static constexpr std::string_view EnvNameFormat("Environment,{},{},{},{},{},{},{},{},{},{},{},{},{}\n");
     357              :         static constexpr std::string_view EnvDSTNFormat("Environment:Daylight Saving,No,{}\n");
     358              :         static constexpr std::string_view EnvDSTYFormat("Environment:Daylight Saving,Yes,{},{},{}\n");
     359              :         static constexpr std::string_view DateFormat("{:02}/{:02}");
     360              :         static constexpr std::string_view DateFormatWithYear("{:02}/{:02}/{:04}");
     361              : 
     362          851 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->GetEnvironmentFirstCall) {
     363              : 
     364          107 :             state.dataReportFlag->PrintEndDataDictionary = true;
     365              : 
     366          107 :             ReportOutputFileHeaders(state); // Write the output file header information
     367              : 
     368              :             // Setup Output Variables, CurrentModuleObject='All Simulations'
     369              : 
     370          428 :             SetupOutputVariable(state,
     371              :                                 "Site Outdoor Air Drybulb Temperature",
     372              :                                 Constant::Units::C,
     373          107 :                                 state.dataEnvrn->OutDryBulbTemp,
     374              :                                 OutputProcessor::TimeStepType::Zone,
     375              :                                 OutputProcessor::StoreType::Average,
     376              :                                 "Environment");
     377          428 :             SetupOutputVariable(state,
     378              :                                 "Site Outdoor Air Dewpoint Temperature",
     379              :                                 Constant::Units::C,
     380          107 :                                 state.dataEnvrn->OutDewPointTemp,
     381              :                                 OutputProcessor::TimeStepType::Zone,
     382              :                                 OutputProcessor::StoreType::Average,
     383              :                                 "Environment");
     384          428 :             SetupOutputVariable(state,
     385              :                                 "Site Outdoor Air Wetbulb Temperature",
     386              :                                 Constant::Units::C,
     387          107 :                                 state.dataEnvrn->OutWetBulbTemp,
     388              :                                 OutputProcessor::TimeStepType::Zone,
     389              :                                 OutputProcessor::StoreType::Average,
     390              :                                 "Environment");
     391          428 :             SetupOutputVariable(state,
     392              :                                 "Site Outdoor Air Humidity Ratio",
     393              :                                 Constant::Units::kgWater_kgDryAir,
     394          107 :                                 state.dataEnvrn->OutHumRat,
     395              :                                 OutputProcessor::TimeStepType::Zone,
     396              :                                 OutputProcessor::StoreType::Average,
     397              :                                 "Environment");
     398          428 :             SetupOutputVariable(state,
     399              :                                 "Site Outdoor Air Relative Humidity",
     400              :                                 Constant::Units::Perc,
     401          107 :                                 state.dataEnvrn->OutRelHum,
     402              :                                 OutputProcessor::TimeStepType::Zone,
     403              :                                 OutputProcessor::StoreType::Average,
     404              :                                 "Environment");
     405          428 :             SetupOutputVariable(state,
     406              :                                 "Site Outdoor Air Barometric Pressure",
     407              :                                 Constant::Units::Pa,
     408          107 :                                 state.dataEnvrn->OutBaroPress,
     409              :                                 OutputProcessor::TimeStepType::Zone,
     410              :                                 OutputProcessor::StoreType::Average,
     411              :                                 "Environment");
     412          428 :             SetupOutputVariable(state,
     413              :                                 "Site Wind Speed",
     414              :                                 Constant::Units::m_s,
     415          107 :                                 state.dataEnvrn->WindSpeed,
     416              :                                 OutputProcessor::TimeStepType::Zone,
     417              :                                 OutputProcessor::StoreType::Average,
     418              :                                 "Environment");
     419          428 :             SetupOutputVariable(state,
     420              :                                 "Site Wind Direction",
     421              :                                 Constant::Units::deg,
     422          107 :                                 state.dataEnvrn->WindDir,
     423              :                                 OutputProcessor::TimeStepType::Zone,
     424              :                                 OutputProcessor::StoreType::Average,
     425              :                                 "Environment");
     426          428 :             SetupOutputVariable(state,
     427              :                                 "Site Sky Temperature",
     428              :                                 Constant::Units::C,
     429          107 :                                 state.dataEnvrn->SkyTemp,
     430              :                                 OutputProcessor::TimeStepType::Zone,
     431              :                                 OutputProcessor::StoreType::Average,
     432              :                                 "Environment");
     433          428 :             SetupOutputVariable(state,
     434              :                                 "Site Horizontal Infrared Radiation Rate per Area",
     435              :                                 Constant::Units::W_m2,
     436          107 :                                 state.dataWeather->HorizIRSky,
     437              :                                 OutputProcessor::TimeStepType::Zone,
     438              :                                 OutputProcessor::StoreType::Average,
     439              :                                 "Environment");
     440          428 :             SetupOutputVariable(state,
     441              :                                 "Site Diffuse Solar Radiation Rate per Area",
     442              :                                 Constant::Units::W_m2,
     443          107 :                                 state.dataEnvrn->DifSolarRad,
     444              :                                 OutputProcessor::TimeStepType::Zone,
     445              :                                 OutputProcessor::StoreType::Average,
     446              :                                 "Environment");
     447          428 :             SetupOutputVariable(state,
     448              :                                 "Site Direct Solar Radiation Rate per Area",
     449              :                                 Constant::Units::W_m2,
     450          107 :                                 state.dataEnvrn->BeamSolarRad,
     451              :                                 OutputProcessor::TimeStepType::Zone,
     452              :                                 OutputProcessor::StoreType::Average,
     453              :                                 "Environment");
     454          428 :             SetupOutputVariable(state,
     455              :                                 "Liquid Precipitation Depth",
     456              :                                 Constant::Units::m,
     457          107 :                                 state.dataEnvrn->LiquidPrecipitation,
     458              :                                 OutputProcessor::TimeStepType::Zone,
     459              :                                 OutputProcessor::StoreType::Sum,
     460              :                                 "Environment");
     461          428 :             SetupOutputVariable(state,
     462              :                                 "Site Precipitation Rate",
     463              :                                 Constant::Units::m_s,
     464          107 :                                 state.dataWaterData->RainFall.CurrentRate,
     465              :                                 OutputProcessor::TimeStepType::Zone,
     466              :                                 OutputProcessor::StoreType::Average,
     467              :                                 "Environment");
     468          428 :             SetupOutputVariable(state,
     469              :                                 "Site Precipitation Depth",
     470              :                                 Constant::Units::m,
     471          107 :                                 state.dataWaterData->RainFall.CurrentAmount,
     472              :                                 OutputProcessor::TimeStepType::Zone,
     473              :                                 OutputProcessor::StoreType::Sum,
     474              :                                 "Environment");
     475          428 :             SetupOutputVariable(state,
     476              :                                 "Site Ground Reflected Solar Radiation Rate per Area",
     477              :                                 Constant::Units::W_m2,
     478          107 :                                 state.dataEnvrn->GndSolarRad,
     479              :                                 OutputProcessor::TimeStepType::Zone,
     480              :                                 OutputProcessor::StoreType::Average,
     481              :                                 "Environment");
     482          428 :             SetupOutputVariable(state,
     483              :                                 "Site Ground Temperature",
     484              :                                 Constant::Units::C,
     485          107 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface],
     486              :                                 OutputProcessor::TimeStepType::Zone,
     487              :                                 OutputProcessor::StoreType::Average,
     488              :                                 "Environment");
     489          428 :             SetupOutputVariable(state,
     490              :                                 "Site Surface Ground Temperature",
     491              :                                 Constant::Units::C,
     492          107 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow],
     493              :                                 OutputProcessor::TimeStepType::Zone,
     494              :                                 OutputProcessor::StoreType::Average,
     495              :                                 "Environment");
     496          428 :             SetupOutputVariable(state,
     497              :                                 "Site Deep Ground Temperature",
     498              :                                 Constant::Units::C,
     499          107 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep],
     500              :                                 OutputProcessor::TimeStepType::Zone,
     501              :                                 OutputProcessor::StoreType::Average,
     502              :                                 "Environment");
     503          428 :             SetupOutputVariable(state,
     504              :                                 "Site Simple Factor Model Ground Temperature",
     505              :                                 Constant::Units::C,
     506          107 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod],
     507              :                                 OutputProcessor::TimeStepType::Zone,
     508              :                                 OutputProcessor::StoreType::Average,
     509              :                                 "Environment");
     510          428 :             SetupOutputVariable(state,
     511              :                                 "Site Total Sky Cover",
     512              :                                 Constant::Units::None,
     513          107 :                                 state.dataEnvrn->TotalCloudCover,
     514              :                                 OutputProcessor::TimeStepType::Zone,
     515              :                                 OutputProcessor::StoreType::Average,
     516              :                                 "Environment");
     517          428 :             SetupOutputVariable(state,
     518              :                                 "Site Opaque Sky Cover",
     519              :                                 Constant::Units::None,
     520          107 :                                 state.dataEnvrn->OpaqueCloudCover,
     521              :                                 OutputProcessor::TimeStepType::Zone,
     522              :                                 OutputProcessor::StoreType::Average,
     523              :                                 "Environment");
     524          428 :             SetupOutputVariable(state,
     525              :                                 "Site Outdoor Air Enthalpy",
     526              :                                 Constant::Units::J_kg,
     527          107 :                                 state.dataEnvrn->OutEnthalpy,
     528              :                                 OutputProcessor::TimeStepType::Zone,
     529              :                                 OutputProcessor::StoreType::Average,
     530              :                                 "Environment");
     531          428 :             SetupOutputVariable(state,
     532              :                                 "Site Outdoor Air Density",
     533              :                                 Constant::Units::kg_m3,
     534          107 :                                 state.dataEnvrn->OutAirDensity,
     535              :                                 OutputProcessor::TimeStepType::Zone,
     536              :                                 OutputProcessor::StoreType::Average,
     537              :                                 "Environment");
     538          428 :             SetupOutputVariable(state,
     539              :                                 "Site Solar Azimuth Angle",
     540              :                                 Constant::Units::deg,
     541          107 :                                 state.dataWeather->SolarAzimuthAngle,
     542              :                                 OutputProcessor::TimeStepType::Zone,
     543              :                                 OutputProcessor::StoreType::Average,
     544              :                                 "Environment");
     545          428 :             SetupOutputVariable(state,
     546              :                                 "Site Solar Altitude Angle",
     547              :                                 Constant::Units::deg,
     548          107 :                                 state.dataWeather->SolarAltitudeAngle,
     549              :                                 OutputProcessor::TimeStepType::Zone,
     550              :                                 OutputProcessor::StoreType::Average,
     551              :                                 "Environment");
     552          428 :             SetupOutputVariable(state,
     553              :                                 "Site Solar Hour Angle",
     554              :                                 Constant::Units::deg,
     555          107 :                                 state.dataWeather->HrAngle,
     556              :                                 OutputProcessor::TimeStepType::Zone,
     557              :                                 OutputProcessor::StoreType::Average,
     558              :                                 "Environment");
     559          321 :             SetupOutputVariable(state,
     560              :                                 "Site Rain Status",
     561              :                                 Constant::Units::None,
     562          107 :                                 state.dataWeather->RptIsRain,
     563              :                                 OutputProcessor::TimeStepType::Zone,
     564              :                                 OutputProcessor::StoreType::Average,
     565              :                                 "Environment");
     566          214 :             SetupOutputVariable(state,
     567              :                                 "Site Snow on Ground Status",
     568              :                                 Constant::Units::None,
     569          107 :                                 state.dataWeather->RptIsSnow,
     570              :                                 OutputProcessor::TimeStepType::Zone,
     571              :                                 OutputProcessor::StoreType::Average,
     572              :                                 "Environment");
     573          428 :             SetupOutputVariable(state,
     574              :                                 "Site Exterior Horizontal Sky Illuminance",
     575              :                                 Constant::Units::lux,
     576          107 :                                 state.dataEnvrn->HISKF,
     577              :                                 OutputProcessor::TimeStepType::Zone,
     578              :                                 OutputProcessor::StoreType::Average,
     579              :                                 "Environment");
     580          428 :             SetupOutputVariable(state,
     581              :                                 "Site Exterior Horizontal Beam Illuminance",
     582              :                                 Constant::Units::lux,
     583          107 :                                 state.dataEnvrn->HISUNF,
     584              :                                 OutputProcessor::TimeStepType::Zone,
     585              :                                 OutputProcessor::StoreType::Average,
     586              :                                 "Environment");
     587          428 :             SetupOutputVariable(state,
     588              :                                 "Site Exterior Beam Normal Illuminance",
     589              :                                 Constant::Units::lux,
     590          107 :                                 state.dataEnvrn->HISUNFnorm,
     591              :                                 OutputProcessor::TimeStepType::Zone,
     592              :                                 OutputProcessor::StoreType::Average,
     593              :                                 "Environment");
     594          428 :             SetupOutputVariable(state,
     595              :                                 "Site Sky Diffuse Solar Radiation Luminous Efficacy",
     596              :                                 Constant::Units::lum_W,
     597          107 :                                 state.dataEnvrn->PDIFLW,
     598              :                                 OutputProcessor::TimeStepType::Zone,
     599              :                                 OutputProcessor::StoreType::Average,
     600              :                                 "Environment");
     601          428 :             SetupOutputVariable(state,
     602              :                                 "Site Beam Solar Radiation Luminous Efficacy",
     603              :                                 Constant::Units::lum_W,
     604          107 :                                 state.dataEnvrn->PDIRLW,
     605              :                                 OutputProcessor::TimeStepType::Zone,
     606              :                                 OutputProcessor::StoreType::Average,
     607              :                                 "Environment");
     608          428 :             SetupOutputVariable(state,
     609              :                                 "Site Daylighting Model Sky Clearness",
     610              :                                 Constant::Units::None,
     611          107 :                                 state.dataEnvrn->SkyClearness,
     612              :                                 OutputProcessor::TimeStepType::Zone,
     613              :                                 OutputProcessor::StoreType::Average,
     614              :                                 "Environment");
     615          428 :             SetupOutputVariable(state,
     616              :                                 "Site Daylighting Model Sky Brightness",
     617              :                                 Constant::Units::None,
     618          107 :                                 state.dataEnvrn->SkyBrightness,
     619              :                                 OutputProcessor::TimeStepType::Zone,
     620              :                                 OutputProcessor::StoreType::Average,
     621              :                                 "Environment");
     622          321 :             SetupOutputVariable(state,
     623              :                                 "Site Daylight Saving Time Status",
     624              :                                 Constant::Units::None,
     625          107 :                                 state.dataEnvrn->DSTIndicator,
     626              :                                 OutputProcessor::TimeStepType::Zone,
     627              :                                 OutputProcessor::StoreType::Average,
     628              :                                 "Environment");
     629          214 :             SetupOutputVariable(state,
     630              :                                 "Site Day Type Index",
     631              :                                 Constant::Units::None,
     632          107 :                                 state.dataWeather->RptDayType,
     633              :                                 OutputProcessor::TimeStepType::Zone,
     634              :                                 OutputProcessor::StoreType::Average,
     635              :                                 "Environment");
     636          428 :             SetupOutputVariable(state,
     637              :                                 "Site Mains Water Temperature",
     638              :                                 Constant::Units::C,
     639          107 :                                 state.dataEnvrn->WaterMainsTemp,
     640              :                                 OutputProcessor::TimeStepType::Zone,
     641              :                                 OutputProcessor::StoreType::Average,
     642              :                                 "Environment");
     643              : 
     644          107 :             if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
     645           27 :                 SetupEMSActuator(state,
     646              :                                  "Weather Data",
     647              :                                  "Environment",
     648              :                                  "Outdoor Dry Bulb",
     649              :                                  "[C]",
     650           27 :                                  state.dataEnvrn->EMSOutDryBulbOverrideOn,
     651           27 :                                  state.dataEnvrn->EMSOutDryBulbOverrideValue);
     652           27 :                 SetupEMSActuator(state,
     653              :                                  "Weather Data",
     654              :                                  "Environment",
     655              :                                  "Outdoor Dew Point",
     656              :                                  "[C]",
     657           27 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideOn,
     658           27 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideValue);
     659           27 :                 SetupEMSActuator(state,
     660              :                                  "Weather Data",
     661              :                                  "Environment",
     662              :                                  "Outdoor Relative Humidity",
     663              :                                  "[%]",
     664           27 :                                  state.dataEnvrn->EMSOutRelHumOverrideOn,
     665           27 :                                  state.dataEnvrn->EMSOutRelHumOverrideValue);
     666           27 :                 SetupEMSActuator(state,
     667              :                                  "Weather Data",
     668              :                                  "Environment",
     669              :                                  "Diffuse Solar",
     670              :                                  "[W/m2]",
     671           27 :                                  state.dataEnvrn->EMSDifSolarRadOverrideOn,
     672           27 :                                  state.dataEnvrn->EMSDifSolarRadOverrideValue);
     673           27 :                 SetupEMSActuator(state,
     674              :                                  "Weather Data",
     675              :                                  "Environment",
     676              :                                  "Direct Solar",
     677              :                                  "[W/m2]",
     678           27 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideOn,
     679           27 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideValue);
     680           27 :                 SetupEMSActuator(state,
     681              :                                  "Weather Data",
     682              :                                  "Environment",
     683              :                                  "Wind Speed",
     684              :                                  "[m/s]",
     685           27 :                                  state.dataEnvrn->EMSWindSpeedOverrideOn,
     686           27 :                                  state.dataEnvrn->EMSWindSpeedOverrideValue);
     687           27 :                 SetupEMSActuator(state,
     688              :                                  "Weather Data",
     689              :                                  "Environment",
     690              :                                  "Wind Direction",
     691              :                                  "[deg]",
     692           27 :                                  state.dataEnvrn->EMSWindDirOverrideOn,
     693           27 :                                  state.dataEnvrn->EMSWindDirOverrideValue);
     694              :             }
     695          107 :             state.dataWeather->GetEnvironmentFirstCall = false;
     696              : 
     697              :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
     698              : 
     699          851 :         if (state.dataWeather->GetBranchInputOneTimeFlag) {
     700              : 
     701          111 :             SetupInterpolationValues(state);
     702          111 :             state.dataWeather->TimeStepFraction = 1.0 / double(state.dataGlobal->TimeStepsInHour);
     703          111 :             state.dataEnvrn->rhoAirSTP = Psychrometrics::PsyRhoAirFnPbTdbW(
     704              :                 state, DataEnvironment::StdPressureSeaLevel, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
     705          111 :             OpenWeatherFile(state, ErrorsFound); // moved here because of possibility of special days on EPW file
     706          111 :             CloseWeatherFile(state);
     707          111 :             ReadUserWeatherInput(state);
     708          111 :             AllocateWeatherData(state);
     709          111 :             if (state.dataWeather->NumIntervalsPerHour != 1) {
     710            0 :                 if (state.dataWeather->NumIntervalsPerHour != state.dataGlobal->TimeStepsInHour) {
     711            0 :                     ShowSevereError(
     712              :                         state,
     713            0 :                         format("{}Number of intervals per hour on Weather file does not match specified number of Time Steps Per Hour", RoutineName));
     714            0 :                     ErrorsFound = true;
     715              :                 }
     716              :             }
     717          111 :             state.dataWeather->GetBranchInputOneTimeFlag = false;
     718          111 :             state.dataWeather->Envrn = 0;
     719          111 :             if (state.dataWeather->NumOfEnvrn > 0) {
     720          110 :                 ResolveLocationInformation(state, ErrorsFound); // Obtain weather related info from input file
     721          110 :                 CheckLocationValidity(state);
     722          160 :                 if ((state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
     723           50 :                     (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
     724           50 :                     CheckWeatherFileValidity(state);
     725              :                 }
     726          109 :                 if (ErrorsFound) {
     727            1 :                     ShowSevereError(state, format("{}No location specified, program will terminate.", RoutineName));
     728              :                 }
     729              :             } else {
     730            1 :                 ErrorsFound = true;
     731            1 :                 ShowSevereError(state, format("{}No Design Days or Run Period(s) specified, program will terminate.", RoutineName));
     732              :             }
     733          110 :             if (state.dataSysVars->DDOnly && state.dataEnvrn->TotDesDays == 0) {
     734            1 :                 ErrorsFound = true;
     735            2 :                 ShowSevereError(
     736              :                     state,
     737            2 :                     format("{}Requested Design Days only (DataSystemVariables::DDOnly) but no Design Days specified, program will terminate.",
     738              :                            RoutineName));
     739              :             }
     740          110 :             if (state.dataSysVars->ReverseDD && state.dataEnvrn->TotDesDays == 1) {
     741            0 :                 ErrorsFound = true;
     742            0 :                 ShowSevereError(
     743              :                     state,
     744            0 :                     format(
     745              :                         "{}Requested Reverse Design Days (DataSystemVariables::ReverseDD) but only 1 Design Day specified, program will terminate.",
     746              :                         RoutineName));
     747              :             }
     748              : 
     749              :             // Throw a Fatal now that we have said it'll terminalte
     750          110 :             if (ErrorsFound) {
     751            2 :                 CloseWeatherFile(state); // will only close if opened.
     752            4 :                 ShowFatalError(state, format("{}Errors found in Weather Data Input. Program terminates.", RoutineName));
     753              :             }
     754              : 
     755          108 :             state.dataEnvrn->CurrentOverallSimDay = 0;
     756          108 :             state.dataEnvrn->TotalOverallSimDays = 0;
     757          108 :             state.dataEnvrn->MaxNumberSimYears = 1;
     758          336 :             for (int i = 1; i <= state.dataWeather->NumOfEnvrn; ++i) {
     759          228 :                 state.dataEnvrn->TotalOverallSimDays += state.dataWeather->Environment(i).TotalDays;
     760          228 :                 if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     761           52 :                     state.dataEnvrn->MaxNumberSimYears = max(state.dataEnvrn->MaxNumberSimYears, state.dataWeather->Environment(i).NumSimYears);
     762              :                 }
     763              :             }
     764          108 :             DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
     765              :         }
     766              : 
     767          848 :         CloseWeatherFile(state); // will only close if opened.
     768          848 :         ++state.dataWeather->Envrn;
     769          848 :         state.dataWeather->DatesShouldBeReset = false;
     770          848 :         if (state.dataWeather->Envrn > state.dataWeather->NumOfEnvrn) {
     771          208 :             Available = false;
     772          208 :             state.dataWeather->Envrn = 0;
     773          208 :             state.dataEnvrn->CurEnvirNum = 0;
     774              :         } else {
     775          640 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
     776          640 :             state.dataGlobal->KindOfSim = envCurr.KindOfEnvrn;
     777          640 :             state.dataEnvrn->DayOfYear = envCurr.StartJDay;
     778          640 :             state.dataEnvrn->DayOfMonth = envCurr.StartDay;
     779          640 :             state.dataGlobal->CalendarYear = envCurr.StartYear;
     780          640 :             state.dataGlobal->CalendarYearChr = fmt::to_string(state.dataGlobal->CalendarYear);
     781          640 :             state.dataEnvrn->Month = envCurr.StartMonth;
     782          640 :             state.dataGlobal->NumOfDayInEnvrn = envCurr.TotalDays; // Set day loop maximum from DataGlobals
     783              : 
     784          865 :             if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
     785          225 :                 (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
     786            0 :                 if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) {
     787            0 :                     if (state.dataGlobal->DoDesDaySim) {
     788            0 :                         ShowWarningError(state, format("{}Adaptive Comfort being reported during design day.", RoutineName));
     789            0 :                         Real64 GrossApproxAvgDryBulb = (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb +
     790            0 :                                                         (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb -
     791            0 :                                                          state.dataWeather->DesDayInput(state.dataWeather->Envrn).DailyDBRange)) /
     792            0 :                                                        2.0;
     793            0 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55)
     794            0 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, false, GrossApproxAvgDryBulb);
     795            0 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251)
     796            0 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, false, GrossApproxAvgDryBulb);
     797              :                     }
     798              :                 } else {
     799            0 :                     if (state.dataGlobal->DoWeathSim || state.dataGlobal->DoDesDaySim) {
     800            0 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55)
     801            0 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, true, 0.0);
     802            0 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251)
     803            0 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, true, 0.0);
     804              :                     }
     805              :                 }
     806              :             }
     807              : 
     808          640 :             if (state.dataWeather->Envrn > state.dataEnvrn->TotDesDays && state.dataWeather->WeatherFileExists) {
     809           44 :                 OpenEPlusWeatherFile(state, ErrorsFound, false);
     810              :             }
     811          640 :             Available = true;
     812          762 :             if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     813          122 :                 (!state.dataWeather->WeatherFileExists && state.dataGlobal->DoWeathSim)) {
     814            0 :                 if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     815            0 :                     ShowSevereError(state, "Weather Simulation requested, but no weather file attached.");
     816            0 :                     ErrorsFound = true;
     817              :                 }
     818            0 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) state.dataWeather->Envrn = 0;
     819            0 :                 Available = false;
     820          762 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     821          122 :                        (!state.dataWeather->WeatherFileExists && !state.dataGlobal->DoWeathSim)) {
     822           80 :                 Available = false;
     823           80 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) state.dataWeather->Envrn = 0;
     824          560 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoingSizing) {
     825            0 :                 Available = false;
     826            0 :                 state.dataWeather->Envrn = 0;
     827              :             }
     828              : 
     829          640 :             if (!ErrorsFound && Available && state.dataWeather->Envrn > 0) {
     830          560 :                 state.dataEnvrn->EnvironmentName = envCurr.Title;
     831          560 :                 state.dataEnvrn->CurEnvirNum = state.dataWeather->Envrn;
     832          560 :                 state.dataEnvrn->RunPeriodStartDayOfWeek = 0;
     833          665 :                 if ((state.dataGlobal->DoDesDaySim && (state.dataGlobal->KindOfSim != Constant::KindOfSim::RunPeriodWeather)) ||
     834          105 :                     ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoWeathSim)) {
     835          458 :                     if (state.dataWeather->PrntEnvHeaders && state.dataReportFlag->DoWeatherInitReporting) {
     836              :                         static constexpr std::string_view EnvironFormat(
     837              :                             "! <Environment>,Environment Name,Environment Type, Start Date, End Date, Start DayOfWeek, Duration {#days}, "
     838              :                             "Source:Start DayOfWeek,  Use Daylight Saving, Use Holidays, Apply Weekend Holiday Rule,  Use Rain Values, Use Snow "
     839              :                             "Values, Sky Temperature Model\n! <Environment:Special Days>, Special Day Name, Special Day Type, Source, Start Date, "
     840              :                             "Duration {#days}\n! "
     841              :                             "<Environment:Daylight Saving>, Daylight Saving Indicator, Source, Start Date, End Date\n! <Environment:WarmupDays>, "
     842              :                             "NumberofWarmupDays");
     843           65 :                         print(state.files.eio, "{}\n", EnvironFormat);
     844           65 :                         state.dataWeather->PrntEnvHeaders = false;
     845              :                     }
     846              : 
     847          458 :                     std::string StDate;
     848          458 :                     std::string EnDate;
     849          913 :                     if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) ||
     850          455 :                         (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign)) {
     851            3 :                         int DSTActStMon = 0;
     852            3 :                         int DSTActStDay = 0;
     853            3 :                         int DSTActEnMon = 0;
     854            3 :                         int DSTActEnDay = 0;
     855            3 :                         std::string kindOfRunPeriod = envCurr.cKindOfEnvrn;
     856            3 :                         state.dataEnvrn->RunPeriodEnvironment = state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather;
     857            3 :                         state.dataEnvrn->CurrentYearIsLeapYear = state.dataWeather->Environment(state.dataWeather->Envrn).IsLeapYear;
     858            3 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears) {
     859            0 :                             state.dataWeather->LeapYearAdd = 1;
     860              :                         } else {
     861            3 :                             state.dataWeather->LeapYearAdd = 0;
     862              :                         }
     863            3 :                         if (state.dataEnvrn->CurrentYearIsLeapYear) {
     864            0 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
     865              :                         }
     866            3 :                         state.dataWeather->UseDaylightSaving = envCurr.UseDST;
     867            3 :                         state.dataWeather->UseSpecialDays = envCurr.UseHolidays;
     868            3 :                         state.dataWeather->UseRainValues = envCurr.UseRain;
     869            3 :                         state.dataWeather->UseSnowValues = envCurr.UseSnow;
     870              : 
     871            3 :                         bool missingLeap(false); // Defer acting on anything found here until after the other range checks (see below)
     872              : 
     873            3 :                         if (envCurr.ActualWeather && !state.dataWeather->WFAllowsLeapYears) {
     874            0 :                             for (int year = envCurr.StartYear; year <= envCurr.EndYear; year++) {
     875            0 :                                 if (!isLeapYear(year)) continue;
     876              : 
     877            0 :                                 ShowSevereError(
     878              :                                     state,
     879            0 :                                     format("{}Weatherfile does not support leap years but runperiod includes a leap year ({})", RoutineName, year));
     880            0 :                                 missingLeap = true;
     881              :                             }
     882              :                         }
     883              : 
     884            3 :                         bool OkRun = false;
     885              : 
     886            3 :                         if (envCurr.ActualWeather) {
     887              :                             // Actual weather
     888            0 :                             for (auto const &dataperiod : state.dataWeather->DataPeriods) {
     889            0 :                                 int runStartJulian = dataperiod.DataStJDay;
     890            0 :                                 int runEndJulian = dataperiod.DataEnJDay;
     891            0 :                                 if (!dataperiod.HasYearData) {
     892            0 :                                     ShowSevereError(state,
     893            0 :                                                     format("{}Actual weather runperiod has been entered but weatherfile DATA PERIOD does not have "
     894              :                                                            "year included in start/end date.",
     895              :                                                            RoutineName));
     896            0 :                                     ShowContinueError(state, "...to match the RunPeriod, the DATA PERIOD should be mm/dd/yyyy for both, or");
     897            0 :                                     ShowContinueError(state, "(...set \"Treat Weather as Actual\" to \"No\".)");
     898              :                                 }
     899            0 :                                 if (!General::BetweenDates(envCurr.StartDate, runStartJulian, runEndJulian)) continue;
     900            0 :                                 if (!General::BetweenDates(envCurr.EndDate, runStartJulian, runEndJulian)) continue;
     901            0 :                                 OkRun = true;
     902            0 :                                 break;
     903              :                             }
     904              :                         } else {
     905              :                             // Typical (or just non-actual) weather
     906            3 :                             for (auto &dataperiod : state.dataWeather->DataPeriods) {
     907              :                                 // Since this is not actual weather, there may be issues with this calculation
     908              :                                 // Assume the weather data starts the same year as the simulation, so LeapYearAdd is what
     909              :                                 // should be used.
     910            3 :                                 int runStartOrdinal = General::OrdinalDay(dataperiod.StMon, dataperiod.StDay, state.dataWeather->LeapYearAdd);
     911              :                                 // This one is harder, leave as is for now. What about multiple years of data?
     912            3 :                                 int runEndOrdinal = General::OrdinalDay(dataperiod.EnMon, dataperiod.EnDay, state.dataWeather->LeapYearAdd);
     913            3 :                                 if (runStartOrdinal == 1 && (runEndOrdinal == 366 || runEndOrdinal == 365)) {
     914              :                                     // Complete year(s) of weather data, will wrap around
     915            3 :                                     OkRun = true;
     916            3 :                                     break;
     917              :                                 }
     918            0 :                                 if (!General::BetweenDates(envCurr.StartJDay, runStartOrdinal, runEndOrdinal)) continue;
     919            0 :                                 if (!General::BetweenDates(envCurr.EndJDay, runStartOrdinal, runEndOrdinal)) continue;
     920            0 :                                 OkRun = true;
     921              :                             }
     922              :                         }
     923              : 
     924            3 :                         if (!OkRun) {
     925            0 :                             if (!envCurr.ActualWeather) {
     926            0 :                                 StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     927            0 :                                 EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     928            0 :                                 ShowSevereError(state,
     929            0 :                                                 format("{}Runperiod [mm/dd] (Start={},End={}) requested not within Data Period(s) from Weather File",
     930              :                                                        RoutineName,
     931              :                                                        StDate,
     932              :                                                        EnDate));
     933              :                             } else {
     934            0 :                                 StDate = format(DateFormatWithYear, envCurr.StartMonth, envCurr.StartDay, envCurr.StartYear);
     935            0 :                                 EnDate = format(DateFormatWithYear, envCurr.EndMonth, envCurr.EndDay, envCurr.EndYear);
     936            0 :                                 ShowSevereError(
     937              :                                     state,
     938            0 :                                     format("{}Runperiod [mm/dd/yyyy] (Start={},End={}) requested not within Data Period(s) from Weather File",
     939              :                                            RoutineName,
     940              :                                            StDate,
     941              :                                            EnDate));
     942              :                             }
     943              : 
     944            0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
     945            0 :                             StDate = format(DateFormat, dataPeriod1.StMon, dataPeriod1.StDay);
     946            0 :                             EnDate = format(DateFormat, dataPeriod1.EnMon, dataPeriod1.EnDay);
     947            0 :                             if (dataPeriod1.StYear > 0) {
     948            0 :                                 StDate += format("/{}", dataPeriod1.StYear);
     949              :                             } else {
     950            0 :                                 StDate += "/<noyear>";
     951              :                             }
     952            0 :                             if (dataPeriod1.EnYear > 0) {
     953            0 :                                 EnDate += format("/{}", dataPeriod1.EnYear);
     954              :                             } else {
     955            0 :                                 EnDate += "/<noyear>";
     956              :                             }
     957            0 :                             if (state.dataWeather->NumDataPeriods == 1) {
     958            0 :                                 ShowContinueError(state, format("Weather Data Period (Start={},End={})", StDate, EnDate));
     959              :                             } else {
     960            0 :                                 ShowContinueError(state, format("Multiple Weather Data Periods 1st (Start={},End={})", StDate, EnDate));
     961              :                             }
     962            0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     963              :                         }
     964              : 
     965            3 :                         if (missingLeap) {
     966              :                             // Bail out now if we still need to
     967            0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     968              :                         }
     969              : 
     970              :                         // Following builds Environment start/end for ASHRAE 55 warnings
     971            3 :                         StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     972            3 :                         EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     973            3 :                         if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     974            3 :                             StDate += format("/{}", envCurr.StartYear);
     975            3 :                             EnDate += format("/{}", envCurr.EndYear);
     976              :                         }
     977            3 :                         state.dataEnvrn->EnvironmentStartEnd = StDate + " - " + EnDate;
     978            3 :                         state.dataEnvrn->StartYear = envCurr.StartYear;
     979            3 :                         state.dataEnvrn->EndYear = envCurr.EndYear;
     980              : 
     981            3 :                         int TWeekDay = (envCurr.DayOfWeek == 0) ? 1 : envCurr.DayOfWeek;
     982            3 :                         auto const &MonWeekDay = envCurr.MonWeekDay;
     983              : 
     984            3 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
     985            0 :                             std::string_view const AlpUseDST = (envCurr.UseDST) ? "Yes" : "No";
     986            0 :                             std::string_view const AlpUseSpec = (envCurr.UseHolidays) ? "Yes" : "No";
     987            0 :                             std::string_view const ApWkRule = (envCurr.ApplyWeekendRule) ? "Yes" : "No";
     988            0 :                             std::string_view const AlpUseRain = (envCurr.UseRain) ? "Yes" : "No";
     989            0 :                             std::string_view const AlpUseSnow = (envCurr.UseSnow) ? "Yes" : "No";
     990              : 
     991            0 :                             print(state.files.eio,
     992              :                                   EnvNameFormat,
     993            0 :                                   envCurr.Title,
     994              :                                   kindOfRunPeriod,
     995              :                                   StDate,
     996              :                                   EnDate,
     997            0 :                                   Sched::dayTypeNames[TWeekDay],
     998            0 :                                   fmt::to_string(envCurr.TotalDays),
     999              :                                   "Use RunPeriod Specified Day",
    1000              :                                   AlpUseDST,
    1001              :                                   AlpUseSpec,
    1002              :                                   ApWkRule,
    1003              :                                   AlpUseRain,
    1004              :                                   AlpUseSnow,
    1005            0 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
    1006              :                         }
    1007              : 
    1008            6 :                         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
    1009            9 :                             (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather && state.dataGlobal->DoWeathSim) &&
    1010            3 :                             (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
    1011            0 :                             if (state.dataWeather->WFAllowsLeapYears) {
    1012            0 :                                 ShowSevereError(
    1013              :                                     state,
    1014            0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with leap years in weather files.", RoutineName));
    1015            0 :                                 ErrorsFound = true;
    1016              :                             }
    1017            0 :                             if (state.dataWeather->NumDataPeriods != 1) {
    1018            0 :                                 ShowSevereError(
    1019              :                                     state,
    1020            0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with multiple dataperiods in weather files.",
    1021              :                                            RoutineName));
    1022            0 :                                 ErrorsFound = true;
    1023              :                             }
    1024            0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
    1025            0 :                             if (dataPeriod1.StMon == 1 && dataPeriod1.StDay == 1) {
    1026            0 :                                 int RunStJDay = General::OrdinalDay(dataPeriod1.StMon, dataPeriod1.StDay, state.dataWeather->LeapYearAdd);
    1027            0 :                                 int RunEnJDay = General::OrdinalDay(dataPeriod1.EnMon, dataPeriod1.EnDay, state.dataWeather->LeapYearAdd);
    1028            0 :                                 if (RunEnJDay - RunStJDay + 1 != 365) {
    1029            0 :                                     ShowSevereError(state,
    1030            0 :                                                     format("{}AdaptiveComfort Reporting does not work correctly with weather files that do "
    1031              :                                                            "not contain 365 days.",
    1032              :                                                            RoutineName));
    1033            0 :                                     ErrorsFound = true;
    1034              :                                 }
    1035            0 :                             } else {
    1036            0 :                                 ShowSevereError(state,
    1037            0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that do not "
    1038              :                                                        "start on 1 January.",
    1039              :                                                        RoutineName));
    1040            0 :                                 ErrorsFound = true;
    1041              :                             }
    1042            0 :                             if (state.dataWeather->NumIntervalsPerHour != 1) {
    1043            0 :                                 ShowSevereError(state,
    1044            0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that have "
    1045              :                                                        "multiple interval records per hour.",
    1046              :                                                        RoutineName));
    1047            0 :                                 ErrorsFound = true;
    1048              :                             }
    1049              :                         } // if
    1050              : 
    1051              :                         // Only need to set Week days for Run Days
    1052            3 :                         state.dataEnvrn->RunPeriodStartDayOfWeek = TWeekDay;
    1053            3 :                         state.dataWeather->WeekDayTypes = 0;
    1054            3 :                         int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1055            3 :                         int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1056              : 
    1057            3 :                         state.dataWeather->curSimDayForEndOfRunPeriod = envCurr.TotalDays;
    1058              : 
    1059            3 :                         int i = JDay5Start;
    1060              :                         while (true) {
    1061          426 :                             state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1062          426 :                             TWeekDay = mod(TWeekDay, 7) + 1;
    1063          426 :                             ++i;
    1064          426 :                             if (i > 366) i = 1;
    1065          426 :                             if (i == JDay5End) break;
    1066              :                         }
    1067              : 
    1068            3 :                         state.dataWeather->DaylightSavingIsActive =
    1069            3 :                             (state.dataWeather->UseDaylightSaving && state.dataWeather->EPWDaylightSaving) || state.dataWeather->IDFDaylightSaving;
    1070              : 
    1071            3 :                         envCurr.SetWeekDays = false;
    1072              : 
    1073            3 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1074            0 :                             SetDSTDateRanges(state, MonWeekDay, state.dataWeather->DSTIndex, DSTActStMon, DSTActStDay, DSTActEnMon, DSTActEnDay);
    1075              :                         }
    1076              : 
    1077            3 :                         SetSpecialDayDates(state, MonWeekDay);
    1078              : 
    1079            3 :                         if (envCurr.StartMonth != 1 || envCurr.StartDay != 1) {
    1080            1 :                             state.dataWeather->StartDatesCycleShouldBeReset = true;
    1081            1 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1082              :                         }
    1083              : 
    1084            3 :                         if (envCurr.StartMonth == 1 && envCurr.StartDay == 1) {
    1085            2 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1086            2 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1087              :                         }
    1088              : 
    1089            3 :                         if (envCurr.ActualWeather) {
    1090            0 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1091            0 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1092              :                         }
    1093              : 
    1094              :                         // Report Actual Dates for Daylight Saving and Special Days
    1095            3 :                         if (!state.dataGlobal->KickOffSimulation) {
    1096            3 :                             std::string Source;
    1097            3 :                             if (state.dataWeather->UseDaylightSaving) {
    1098            3 :                                 if (state.dataWeather->EPWDaylightSaving) {
    1099            0 :                                     Source = "WeatherFile";
    1100              :                                 }
    1101              :                             } else {
    1102            0 :                                 Source = "RunPeriod Object";
    1103              :                             }
    1104            3 :                             if (state.dataWeather->IDFDaylightSaving) {
    1105            0 :                                 Source = "InputFile";
    1106              :                             }
    1107            3 :                             if (state.dataWeather->DaylightSavingIsActive && state.dataReportFlag->DoWeatherInitReporting) {
    1108            0 :                                 StDate = format(DateFormat, DSTActStMon, DSTActStDay);
    1109            0 :                                 EnDate = format(DateFormat, DSTActEnMon, DSTActEnDay);
    1110            0 :                                 print(state.files.eio, EnvDSTYFormat, Source, StDate, EnDate);
    1111            3 :                             } else if (state.dataGlobal->DoOutputReporting) {
    1112            0 :                                 print(state.files.eio, EnvDSTNFormat, Source);
    1113              :                             }
    1114            3 :                             for (int k = 1; k <= state.dataWeather->NumSpecialDays; ++k) {
    1115            0 :                                 auto &specialDay = state.dataWeather->SpecialDays(k);
    1116              :                                 static constexpr std::string_view EnvSpDyFormat("Environment:Special Days,{},{},{},{},{:3}\n");
    1117            0 :                                 if (specialDay.WthrFile && state.dataWeather->UseSpecialDays && state.dataReportFlag->DoWeatherInitReporting) {
    1118            0 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1119            0 :                                     print(state.files.eio,
    1120              :                                           EnvSpDyFormat,
    1121            0 :                                           specialDay.Name,
    1122            0 :                                           Sched::dayTypeNames[specialDay.DayType],
    1123              :                                           "WeatherFile",
    1124              :                                           StDate,
    1125            0 :                                           specialDay.Duration);
    1126              :                                 }
    1127            0 :                                 if (!specialDay.WthrFile && state.dataReportFlag->DoWeatherInitReporting) {
    1128            0 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1129            0 :                                     print(state.files.eio,
    1130              :                                           EnvSpDyFormat,
    1131            0 :                                           specialDay.Name,
    1132            0 :                                           Sched::dayTypeNames[specialDay.DayType],
    1133              :                                           "InputFile",
    1134              :                                           StDate,
    1135            0 :                                           specialDay.Duration);
    1136              :                                 }
    1137              :                             }
    1138            3 :                         }
    1139              : 
    1140          460 :                     } else if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay ||
    1141            2 :                                state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay) { // Design Day
    1142          453 :                         auto const &desDayInput = state.dataWeather->DesDayInput(envCurr.DesignDayNum);
    1143          453 :                         state.dataEnvrn->RunPeriodEnvironment = false;
    1144          453 :                         StDate = format(DateFormat, desDayInput.Month, desDayInput.DayOfMonth);
    1145          453 :                         EnDate = StDate;
    1146          453 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
    1147          112 :                             print(state.files.eio,
    1148              :                                   EnvNameFormat,
    1149          112 :                                   envCurr.Title,
    1150              :                                   "SizingPeriod:DesignDay",
    1151              :                                   StDate,
    1152              :                                   EnDate,
    1153          112 :                                   Sched::dayTypeNames[desDayInput.DayType],
    1154              :                                   "1",
    1155              :                                   "N/A",
    1156              :                                   "N/A",
    1157              :                                   "N/A",
    1158              :                                   "N/A",
    1159              :                                   "N/A",
    1160              :                                   "N/A",
    1161          112 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
    1162              :                         }
    1163          453 :                         if (desDayInput.DSTIndicator == 0 && state.dataReportFlag->DoWeatherInitReporting) {
    1164          112 :                             print(state.files.eio, EnvDSTNFormat, "SizingPeriod:DesignDay");
    1165          341 :                         } else if (state.dataReportFlag->DoWeatherInitReporting) {
    1166            0 :                             print(state.files.eio, EnvDSTYFormat, "SizingPeriod:DesignDay", StDate, EnDate);
    1167              :                         }
    1168              :                     }
    1169          458 :                 }
    1170              :             } // ErrorsFound
    1171              :         }
    1172              : 
    1173          848 :         if (ErrorsFound && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    1174            0 :             ShowSevereError(state, format("{}Errors found in getting a new environment", RoutineName));
    1175            0 :             Available = false;
    1176          848 :         } else if (ErrorsFound) {
    1177            0 :             Available = false;
    1178              :         }
    1179          848 :         return Available && !ErrorsFound;
    1180              :     }
    1181              : 
    1182            4 :     void AddDesignSetToEnvironmentStruct(EnergyPlusData &state, int const HVACSizingIterCount)
    1183              :     {
    1184            4 :         int OrigNumOfEnvrn = state.dataWeather->NumOfEnvrn;
    1185              : 
    1186           14 :         for (int i = 1; i <= OrigNumOfEnvrn; ++i) {
    1187              :             // Gotcha: references may no longer be valid after a redimension! Cannot declare reference to Environment(i) here.
    1188           10 :             if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1189            8 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1190            8 :                 auto &envBase = state.dataWeather->Environment(i);
    1191            8 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1192            8 :                 envNew = envBase; // copy over seed data from current array element
    1193            8 :                 envNew.SeedEnvrnNum = i;
    1194            8 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeDesignDay;
    1195            8 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1196            8 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1197            2 :             } else if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    1198            2 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1199            2 :                 auto &envBase = state.dataWeather->Environment(i);
    1200            2 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1201            2 :                 envNew = envBase; // copy over seed data
    1202            2 :                 envNew.SeedEnvrnNum = i;
    1203            2 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeRunPeriodDesign;
    1204            2 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1205            2 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1206              :             }
    1207              :         } // for each loop over Environment data strucure
    1208            4 :     }
    1209              : 
    1210           93 :     void SetupWeekDaysByMonth(EnergyPlusData &state, int const StMon, int const StDay, int const StWeekDay, Array1D_int &WeekDays)
    1211              :     {
    1212              : 
    1213              :         // SUBROUTINE INFORMATION:
    1214              :         //       AUTHOR         Linda Lawrie
    1215              :         //       DATE WRITTEN   August 2000
    1216              : 
    1217              :         // PURPOSE OF THIS SUBROUTINE:
    1218              :         // This subroutine calculates the weekday for each month based on the start date and
    1219              :         // weekday specified for that date.
    1220              : 
    1221              :         // Argument array dimensioning
    1222           93 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1223              : 
    1224              :         // Set 1st day of Start Month
    1225           93 :         int CurWeekDay{StWeekDay};
    1226          256 :         for (int i = 1; i <= StDay - 1; ++i) {
    1227          163 :             --CurWeekDay;
    1228          163 :             if (CurWeekDay == 0) CurWeekDay = 7;
    1229              :         }
    1230              : 
    1231           93 :         WeekDays(StMon) = CurWeekDay;
    1232         1080 :         for (int i = StMon + 1; i <= 12; ++i) {
    1233              : 
    1234          987 :             if (i == 2) {
    1235           84 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1236          424 :                 while (CurWeekDay > 7) {
    1237          340 :                     CurWeekDay -= 7;
    1238              :                 }
    1239           84 :                 WeekDays(i) = CurWeekDay;
    1240          903 :             } else if (i == 3) {
    1241           88 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + state.dataWeather->LeapYearAdd;
    1242          440 :                 while (CurWeekDay > 7) {
    1243          352 :                     CurWeekDay -= 7;
    1244              :                 }
    1245           88 :                 WeekDays(i) = CurWeekDay;
    1246              :             } else {
    1247          815 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1248         4391 :                 while (CurWeekDay > 7) {
    1249         3576 :                     CurWeekDay -= 7;
    1250              :                 }
    1251          815 :                 WeekDays(i) = CurWeekDay;
    1252              :             }
    1253              :         }
    1254              : 
    1255           93 :         if (any_eq(WeekDays, 0)) {
    1256              :             // need to start at StMon and go backwards.
    1257              :             // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1258            9 :             CurWeekDay = StWeekDay;
    1259          146 :             for (int i = 1; i <= StDay - 1; ++i) {
    1260          137 :                 --CurWeekDay;
    1261          137 :                 if (CurWeekDay == 0) CurWeekDay = 7;
    1262              :             }
    1263              : 
    1264           45 :             for (int i = StMon - 1; i >= 1; --i) {
    1265              : 
    1266           36 :                 if (i == 1) {
    1267            9 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1268           49 :                     while (CurWeekDay <= 0) {
    1269           40 :                         CurWeekDay += 7;
    1270              :                     }
    1271            9 :                     WeekDays(i) = CurWeekDay;
    1272           27 :                 } else if (i == 2) {
    1273            5 :                     CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
    1274           25 :                     while (CurWeekDay <= 0) {
    1275           20 :                         CurWeekDay += 7;
    1276              :                     }
    1277            5 :                     WeekDays(i) = CurWeekDay;
    1278           22 :                 } else if ((i >= 3) && (i <= 12)) {
    1279           22 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1280          119 :                     while (CurWeekDay <= 0) {
    1281           97 :                         CurWeekDay += 7;
    1282              :                     }
    1283           22 :                     WeekDays(i) = CurWeekDay;
    1284              :                 }
    1285              :             }
    1286              :         }
    1287           93 :     }
    1288              : #pragma clang diagnostic pop
    1289              : 
    1290            0 :     void ResetWeekDaysByMonth(EnergyPlusData &state,
    1291              :                               Array1D_int &WeekDays,
    1292              :                               int const AddLeapYear,
    1293              :                               int const StartMonth,
    1294              :                               int const StartMonthDay,
    1295              :                               int const EndMonth,
    1296              :                               int const EndMonthDay,
    1297              :                               bool const Rollover,
    1298              :                               bool const MidSimReset)
    1299              :     {
    1300              : 
    1301              :         // SUBROUTINE INFORMATION:
    1302              :         //       AUTHOR         Linda Lawrie
    1303              :         //       DATE WRITTEN   March 2012
    1304              : 
    1305              :         // PURPOSE OF THIS SUBROUTINE:
    1306              :         // This subroutine resets the weekday for each month based on the current weekday
    1307              :         // and previous weekdays per month.
    1308              : 
    1309            0 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1310              : 
    1311            0 :         Array1D_int WeekDaysCopy(12);
    1312              :         int CurWeekDay;
    1313              : 
    1314            0 :         WeekDaysCopy = WeekDays;
    1315            0 :         if (!MidSimReset) {
    1316            0 :             if (Rollover) {
    1317            0 :                 if (StartMonth == 1) {
    1318            0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1319              :                 } else {
    1320            0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1321              :                 }
    1322              :             } else { // restart at same as before
    1323            0 :                 CurWeekDay = WeekDays(StartMonth);
    1324              :             }
    1325            0 :             while (CurWeekDay > 7) {
    1326            0 :                 CurWeekDay -= 7;
    1327              :             }
    1328              : 
    1329            0 :             WeekDays = 0;
    1330            0 :             WeekDays(StartMonth) = CurWeekDay;
    1331            0 :             for (int i = StartMonth + 1; i <= 12; ++i) {
    1332            0 :                 if (i == 2) {
    1333            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1334            0 :                     while (CurWeekDay > 7) {
    1335            0 :                         CurWeekDay -= 7;
    1336              :                     }
    1337            0 :                     WeekDays(i) = CurWeekDay;
    1338            0 :                 } else if (i == 3) {
    1339            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1340            0 :                     while (CurWeekDay > 7) {
    1341            0 :                         CurWeekDay -= 7;
    1342              :                     }
    1343            0 :                     WeekDays(i) = CurWeekDay;
    1344              :                 } else {
    1345            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1346            0 :                     while (CurWeekDay > 7) {
    1347            0 :                         CurWeekDay -= 7;
    1348              :                     }
    1349            0 :                     WeekDays(i) = CurWeekDay;
    1350              :                 }
    1351              :             }
    1352              : 
    1353            0 :             if (any_eq(WeekDays, 0)) {
    1354              :                 // need to start at StMon and go backwards.
    1355              :                 // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1356            0 :                 CurWeekDay = WeekDays(StartMonth);
    1357            0 :                 for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1358            0 :                     --CurWeekDay;
    1359            0 :                     if (CurWeekDay == 0) CurWeekDay = 7;
    1360              :                 }
    1361              : 
    1362            0 :                 for (int i = StartMonth - 1; i >= 1; --i) {
    1363              : 
    1364            0 :                     if (i == 1) {
    1365            0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1366            0 :                         while (CurWeekDay <= 0) {
    1367            0 :                             CurWeekDay += 7;
    1368              :                         }
    1369            0 :                         WeekDays(i) = CurWeekDay;
    1370            0 :                     } else if (i == 2) {
    1371            0 :                         CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1372            0 :                         while (CurWeekDay <= 0) {
    1373            0 :                             CurWeekDay += 7;
    1374              :                         }
    1375            0 :                         WeekDays(i) = CurWeekDay;
    1376            0 :                     } else if ((i >= 3) && (i <= 12)) {
    1377            0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1378            0 :                         while (CurWeekDay <= 0) {
    1379            0 :                             CurWeekDay += 7;
    1380              :                         }
    1381            0 :                         WeekDays(i) = CurWeekDay;
    1382              :                     }
    1383              :                 }
    1384              :             }
    1385              : 
    1386              :         } else {
    1387            0 :             if (Rollover) {
    1388            0 :                 if (StartMonth == 1) {
    1389            0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1390              :                 } else {
    1391            0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1392              :                 }
    1393              :             } else { // restart at same as before
    1394            0 :                 CurWeekDay = WeekDays(StartMonth);
    1395              :             }
    1396            0 :             while (CurWeekDay > 7) {
    1397            0 :                 CurWeekDay -= 7;
    1398              :             }
    1399            0 :             WeekDays = 0;
    1400            0 :             if (StartMonth != 1) {
    1401            0 :                 CurWeekDay = WeekDaysCopy(12) + state.dataWeather->EndDayOfMonth(12);
    1402            0 :                 while (CurWeekDay > 7) {
    1403            0 :                     CurWeekDay -= 7;
    1404              :                 }
    1405            0 :                 WeekDays(1) = CurWeekDay;
    1406            0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1407            0 :                 while (CurWeekDay > 7) {
    1408            0 :                     CurWeekDay -= 7;
    1409              :                 }
    1410            0 :                 WeekDays(2) = CurWeekDay;
    1411            0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1412            0 :                 while (CurWeekDay > 7) {
    1413            0 :                     CurWeekDay -= 7;
    1414              :                 }
    1415            0 :                 WeekDays(3) = CurWeekDay;
    1416            0 :                 for (int i = 4; i <= 12; ++i) {
    1417            0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1418            0 :                     while (CurWeekDay > 7) {
    1419            0 :                         CurWeekDay -= 7;
    1420              :                     }
    1421            0 :                     WeekDays(i) = CurWeekDay;
    1422              :                 }
    1423              :             } else {
    1424            0 :                 WeekDays = 0;
    1425            0 :                 WeekDays(StartMonth) = CurWeekDay;
    1426            0 :                 for (int i = StartMonth + 1; i <= 12; ++i) {
    1427            0 :                     if (i == 2) {
    1428            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1429            0 :                         while (CurWeekDay > 7) {
    1430            0 :                             CurWeekDay -= 7;
    1431              :                         }
    1432            0 :                         WeekDays(i) = CurWeekDay;
    1433            0 :                     } else if (i == 3) {
    1434            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1435            0 :                         while (CurWeekDay > 7) {
    1436            0 :                             CurWeekDay -= 7;
    1437              :                         }
    1438            0 :                         WeekDays(i) = CurWeekDay;
    1439              :                     } else {
    1440            0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1441            0 :                         while (CurWeekDay > 7) {
    1442            0 :                             CurWeekDay -= 7;
    1443              :                         }
    1444            0 :                         WeekDays(i) = CurWeekDay;
    1445              :                     }
    1446              :                 }
    1447              : 
    1448            0 :                 if (any_eq(WeekDays, 0)) {
    1449              :                     // need to start at StMon and go backwards.
    1450              :                     // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1451            0 :                     CurWeekDay = WeekDays(StartMonth);
    1452            0 :                     for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1453            0 :                         --CurWeekDay;
    1454            0 :                         if (CurWeekDay == 0) CurWeekDay = 7;
    1455              :                     }
    1456              : 
    1457            0 :                     for (int i = StartMonth - 1; i >= 1; --i) {
    1458              : 
    1459            0 :                         if (i == 1) {
    1460            0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1461            0 :                             while (CurWeekDay <= 0) {
    1462            0 :                                 CurWeekDay += 7;
    1463              :                             }
    1464            0 :                             WeekDays(i) = CurWeekDay;
    1465            0 :                         } else if (i == 2) {
    1466            0 :                             CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1467            0 :                             while (CurWeekDay <= 0) {
    1468            0 :                                 CurWeekDay += 7;
    1469              :                             }
    1470            0 :                             WeekDays(i) = CurWeekDay;
    1471            0 :                         } else if ((i >= 3) && (i <= 12)) {
    1472            0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1473            0 :                             while (CurWeekDay <= 0) {
    1474            0 :                                 CurWeekDay += 7;
    1475              :                             }
    1476            0 :                             WeekDays(i) = CurWeekDay;
    1477              :                         }
    1478              :                     }
    1479              :                 }
    1480              :             }
    1481              :         }
    1482            0 :     }
    1483              : 
    1484            0 :     void SetDSTDateRanges(EnergyPlusData &state,
    1485              :                           Array1D_int const &MonWeekDay, // Weekday of each day 1 of month
    1486              :                           Array1D_int &DSTIdx,           // DST Index for each julian day (1:366)
    1487              :                           ObjexxFCL::Optional_int DSTActStMon,
    1488              :                           ObjexxFCL::Optional_int DSTActStDay,
    1489              :                           ObjexxFCL::Optional_int DSTActEnMon,
    1490              :                           ObjexxFCL::Optional_int DSTActEnDay)
    1491              :     {
    1492              : 
    1493              :         // SUBROUTINE INFORMATION:
    1494              :         //       AUTHOR         Linda Lawrie
    1495              :         //       DATE WRITTEN   March 2012
    1496              : 
    1497              :         // PURPOSE OF THIS SUBROUTINE:
    1498              :         // With multiple year weather files (or repeating weather files that rollover day),
    1499              :         // need to set DST (Daylight Saving Time) dates at start of environment or year.
    1500              :         // DST is only projected for one year.
    1501              : 
    1502              :         static constexpr std::string_view RoutineName("SetDSTDateRanges: ");
    1503              : 
    1504              :         int ActStartMonth; // Actual Start Month
    1505              :         int ActStartDay;   // Actual Start Day of Month
    1506              :         int ActEndMonth;   // Actual End Month
    1507              :         int ActEndDay;     // Actual End Day of Month
    1508              : 
    1509            0 :         bool ErrorsFound = false;
    1510            0 :         if (state.dataWeather->DST.StDateType == DateType::MonthDay) {
    1511            0 :             ActStartMonth = state.dataWeather->DST.StMon;
    1512            0 :             ActStartDay = state.dataWeather->DST.StDay;
    1513            0 :         } else if (state.dataWeather->DST.StDateType == DateType::NthDayInMonth) {
    1514            0 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1515            0 :             while (ThisDay <= 0) {
    1516            0 :                 ThisDay += 7;
    1517              :             }
    1518            0 :             ThisDay += 7 * (state.dataWeather->DST.StDay - 1);
    1519            0 :             if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1520            0 :                 ShowSevereError(state, format("{}Determining DST: DST Start Date, Nth Day of Month, not enough Nths", RoutineName));
    1521            0 :                 ErrorsFound = true;
    1522              :             } else {
    1523            0 :                 ActStartMonth = state.dataWeather->DST.StMon;
    1524            0 :                 ActStartDay = ThisDay;
    1525              :             }
    1526              :         } else { // LastWeekDayInMonth
    1527            0 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1528            0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1529            0 :                 ThisDay += 7;
    1530              :             }
    1531            0 :             ActStartMonth = state.dataWeather->DST.StMon;
    1532            0 :             ActStartDay = ThisDay;
    1533              :         }
    1534              : 
    1535            0 :         if (state.dataWeather->DST.EnDateType == DateType::MonthDay) {
    1536            0 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1537            0 :             ActEndDay = state.dataWeather->DST.EnDay;
    1538            0 :         } else if (state.dataWeather->DST.EnDateType == DateType::NthDayInMonth) {
    1539            0 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1540            0 :             while (ThisDay <= 0) {
    1541            0 :                 ThisDay += 7;
    1542              :             }
    1543            0 :             ThisDay += 7 * (state.dataWeather->DST.EnDay - 1);
    1544            0 :             if (ThisDay >> state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1545            0 :                 ActEndMonth = 0; // Suppress uninitialized warning
    1546            0 :                 ActEndDay = 0;   // Suppress uninitialized warning
    1547            0 :                 ShowSevereError(state, format("{}Determining DST: DST End Date, Nth Day of Month, not enough Nths", RoutineName));
    1548            0 :                 ErrorsFound = true;
    1549              :             } else {
    1550            0 :                 ActEndMonth = state.dataWeather->DST.EnMon;
    1551            0 :                 ActEndDay = ThisDay;
    1552              :             }
    1553              :         } else { // LastWeekDayInMonth
    1554            0 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1555            0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1556            0 :                 ThisDay += 7;
    1557              :             }
    1558            0 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1559            0 :             ActEndDay = ThisDay;
    1560              :         }
    1561              : 
    1562            0 :         if (ErrorsFound) {
    1563            0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1564              :         }
    1565              : 
    1566            0 :         if (present(DSTActStMon)) {
    1567            0 :             DSTActStMon = ActStartMonth;
    1568            0 :             DSTActStDay = ActStartDay;
    1569            0 :             DSTActEnMon = ActEndMonth;
    1570            0 :             DSTActEnDay = ActEndDay;
    1571              :         }
    1572              : 
    1573            0 :         DSTIdx = 0;
    1574            0 :         int JDay = General::OrdinalDay(ActStartMonth, ActStartDay, state.dataWeather->LeapYearAdd);
    1575            0 :         int JDay1 = General::OrdinalDay(ActEndMonth, ActEndDay, state.dataWeather->LeapYearAdd);
    1576            0 :         if (JDay1 >= JDay) {
    1577            0 :             DSTIdx({JDay, JDay1}) = 1;
    1578              :         } else {
    1579            0 :             DSTIdx({JDay, 366}) = 1;
    1580            0 :             DSTIdx({1, JDay1}) = 1;
    1581              :         }
    1582            0 :     }
    1583              : 
    1584            9 :     void SetSpecialDayDates(EnergyPlusData &state, Array1D_int const &MonWeekDay) // Weekday of each day 1 of month
    1585              :     {
    1586              : 
    1587              :         // SUBROUTINE INFORMATION:
    1588              :         //       AUTHOR         Linda Lawrie
    1589              :         //       DATE WRITTEN   March 2012
    1590              : 
    1591              :         // PURPOSE OF THIS SUBROUTINE:
    1592              :         // With multiple year weather files (or repeating weather files that rollover day),
    1593              :         // need to set Special Day dates at start of environment or year.
    1594              :         // Special Days are only projected for one year.
    1595              : 
    1596              :         static constexpr std::string_view RoutineName("SetSpecialDayDates: ");
    1597              : 
    1598              :         int JDay;
    1599              : 
    1600            9 :         bool ErrorsFound = false;
    1601            9 :         state.dataWeather->SpecialDayTypes = 0;
    1602            9 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1603            0 :             auto &specialDay = state.dataWeather->SpecialDays(i);
    1604            0 :             if (specialDay.WthrFile && !state.dataWeather->UseSpecialDays) continue;
    1605            0 :             if (specialDay.dateType <= DateType::MonthDay) {
    1606            0 :                 JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd);
    1607            0 :                 if (specialDay.Duration == 1 && state.dataWeather->Environment(state.dataWeather->Envrn).ApplyWeekendRule) {
    1608            0 :                     if (state.dataWeather->WeekDayTypes(JDay) == static_cast<int>(Sched::DayType::Sunday)) {
    1609              :                         // Sunday, must go to Monday
    1610            0 :                         ++JDay;
    1611            0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1612            0 :                     } else if (state.dataWeather->WeekDayTypes(JDay) == (int)Sched::DayType::Saturday) {
    1613            0 :                         ++JDay;
    1614            0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1615            0 :                         ++JDay;
    1616            0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1617              :                     }
    1618              :                 }
    1619            0 :                 General::InvOrdinalDay(JDay, specialDay.ActStMon, specialDay.ActStDay, state.dataWeather->LeapYearAdd);
    1620            0 :             } else if (specialDay.dateType == DateType::NthDayInMonth) {
    1621            0 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1622            0 :                 if (specialDay.WeekDay < MonWeekDay(specialDay.Month)) {
    1623            0 :                     ThisDay += 7;
    1624              :                 }
    1625            0 :                 ThisDay += 7 * (specialDay.Day - 1);
    1626            0 :                 if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1627            0 :                     ShowSevereError(state,
    1628            0 :                                     format("{}Special Day Date, Nth Day of Month, not enough Nths, for SpecialDay={}", RoutineName, specialDay.Name));
    1629            0 :                     ErrorsFound = true;
    1630            0 :                     continue;
    1631              :                 }
    1632            0 :                 specialDay.ActStMon = specialDay.Month;
    1633            0 :                 specialDay.ActStDay = ThisDay;
    1634            0 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1635              :             } else { // LastWeekDayInMonth
    1636            0 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1637            0 :                 while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1638            0 :                     ThisDay += 7;
    1639              :                 }
    1640            0 :                 specialDay.ActStMon = specialDay.Month;
    1641            0 :                 specialDay.ActStDay = ThisDay;
    1642            0 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1643              :             }
    1644            0 :             if (state.dataWeather->SpecialDayTypes(JDay) != 0) {
    1645            0 :                 ShowWarningError(
    1646              :                     state,
    1647            0 :                     format("{}Special Day definition ({}) is overwriting previously entered special day period", RoutineName, specialDay.Name));
    1648            0 :                 if (state.dataWeather->UseSpecialDays) {
    1649            0 :                     ShowContinueError(state, "...This could be caused by definitions on the Weather File.");
    1650              :                 }
    1651            0 :                 ShowContinueError(state, "...This could be caused by duplicate definitions in the Input File.");
    1652              :             }
    1653            0 :             int JDay1 = JDay - 1;
    1654            0 :             for (int j = 0; j <= specialDay.Duration - 1; ++j) {
    1655            0 :                 ++JDay1;
    1656            0 :                 if (JDay1 == 366 && state.dataWeather->LeapYearAdd == 0) JDay1 = 1;
    1657            0 :                 if (JDay1 == 367) JDay1 = 1;
    1658            0 :                 state.dataWeather->SpecialDayTypes(JDay1) = specialDay.DayType;
    1659              :             }
    1660              :         }
    1661              : 
    1662            9 :         if (ErrorsFound) {
    1663            0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1664              :         }
    1665            9 :     }
    1666              : 
    1667       326115 :     void InitializeWeather(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    1668              :     {
    1669              : 
    1670              :         // SUBROUTINE INFORMATION:
    1671              :         //       AUTHOR         Rick Strand
    1672              :         //       DATE WRITTEN   June 1997
    1673              : 
    1674              :         // PURPOSE OF THIS SUBROUTINE:
    1675              :         // This subroutine is the main driver of the weather initializations.
    1676              :         // Most of the weather handling can be described as "initializations"
    1677              :         // so most of the work is done via this subroutine.
    1678              : 
    1679       326115 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->FirstCall) {
    1680              : 
    1681          103 :             state.dataWeather->FirstCall = false;
    1682          103 :             state.dataEnvrn->EndMonthFlag = false;
    1683              : 
    1684              :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
    1685              : 
    1686       326115 :         auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    1687       326115 :         if (state.dataGlobal->BeginEnvrnFlag) {
    1688              : 
    1689              :             // Call and setup the Design Day environment
    1690          538 :             if (envCurr.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) {
    1691          518 :                 if (envCurr.DesignDayNum > 0) {
    1692          516 :                     SetUpDesignDay(state, envCurr.DesignDayNum);
    1693          516 :                     state.dataEnvrn->EnvironmentName = envCurr.Title;
    1694              :                 }
    1695              :             }
    1696              : 
    1697              :             // Only used in Weather file environments
    1698              :             // Start over missing values with each environment
    1699          538 :             state.dataWeather->wvarsMissing.OutBaroPress = state.dataEnvrn->StdBaroPress; // Initial "missing" value
    1700          538 :             state.dataWeather->wvarsMissing.OutDryBulbTemp = 6.0;                         // Initial "missing" value
    1701          538 :             state.dataWeather->wvarsMissing.OutDewPointTemp = 3.0;                        // Initial "missing" value
    1702          538 :             state.dataWeather->wvarsMissing.OutRelHum = 50.0;                             // Initial "missing" value
    1703          538 :             state.dataWeather->wvarsMissing.WindSpeed = 2.5;                              // Initial "missing" value
    1704          538 :             state.dataWeather->wvarsMissing.WindDir = 180;                                // Initial "missing" value
    1705          538 :             state.dataWeather->wvarsMissing.TotalSkyCover = 5;                            // Initial "missing" value
    1706          538 :             state.dataWeather->wvarsMissing.OpaqueSkyCover = 5;                           // Initial "missing" value
    1707          538 :             state.dataWeather->wvarsMissing.Visibility = 777.7;                           // Initial "missing" value
    1708          538 :             state.dataWeather->wvarsMissing.Ceiling = 77777;                              // Initial "missing" value
    1709          538 :             state.dataWeather->wvarsMissing.AerOptDepth = 0.0;                            // Initial "missing" value
    1710          538 :             state.dataWeather->wvarsMissing.SnowDepth = 0;                                // Initial "missing" value
    1711          538 :             state.dataWeather->wvarsMissing.DaysLastSnow = 88;                            // Initial "missing" value
    1712          538 :             state.dataWeather->wvarsMissing.Albedo = 0.0;                                 // Initial "missing" value
    1713          538 :             state.dataWeather->wvarsMissing.LiquidPrecip = 0.0;                           // Initial "missing" value
    1714              :             // Counts set to 0 for each environment
    1715          538 :             state.dataWeather->wvarsMissedCounts = Weather::WeatherVarCounts();
    1716              : 
    1717              :             // Counts set to 0 for each environment
    1718          538 :             state.dataWeather->wvarsOutOfRangeCounts = Weather::WeatherVarCounts();
    1719              : 
    1720          538 :             state.dataWeather->IsRainThreshold = 0.8 / double(state.dataGlobal->TimeStepsInHour); // [mm]
    1721              : 
    1722          538 :             if (!state.dataWeather->RPReadAllWeatherData) {
    1723          536 :                 printEnvrnStamp = true; // Set this to true so that on first non-warmup day (only) the environment header will print out
    1724              :             }
    1725              : 
    1726          538 :             for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1727            0 :                 state.dataWeather->SpecialDays(i).Used = false;
    1728              :             }
    1729              : 
    1730          560 :             if ((state.dataGlobal->KindOfSim != Constant::KindOfSim::DesignDay) &&
    1731           22 :                 (state.dataGlobal->KindOfSim != Constant::KindOfSim::HVACSizeDesignDay)) {
    1732           22 :                 ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read first day's weather
    1733              :             } else {
    1734          516 :                 state.dataWeather->TomorrowVariables = state.dataWeather->DesignDay(envCurr.DesignDayNum);
    1735              :             }
    1736              : 
    1737              :         } // ... end of DataGlobals::BeginEnvrnFlag IF-THEN block.
    1738              : 
    1739       326115 :         if (state.dataGlobal->BeginDayFlag) {
    1740              : 
    1741              :             // Check Holidays, Daylight Saving Time, Ground Temperatures, etc.
    1742              : 
    1743         3083 :             UpdateWeatherData(state); // Update daily weather info
    1744              : 
    1745              :             // Read tomorrow's weather only if necessary.  This means that the
    1746              :             // simulation is out of warmup, is using a weather tape for this
    1747              :             // environment, and is not on the last day (day after last day is
    1748              :             // assumed to be equal to last day).
    1749              : 
    1750              :             // Following code checks whether the present day of simulation matches the start month and start day.
    1751              :             // In a multi year simulation with run period less than 365, we need to position the weather line
    1752              :             // appropriately.
    1753              : 
    1754         4084 :             if ((!state.dataGlobal->WarmupFlag) &&
    1755         1001 :                 ((envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) && (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay))) {
    1756          730 :                 if (state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) {
    1757          728 :                     if (state.dataGlobal->DayOfSim == state.dataWeather->curSimDayForEndOfRunPeriod) {
    1758            1 :                         state.dataWeather->curSimDayForEndOfRunPeriod += envCurr.RawSimDays;
    1759            1 :                         if (state.dataWeather->StartDatesCycleShouldBeReset) {
    1760            0 :                             ResetWeekDaysByMonth(state,
    1761            0 :                                                  envCurr.MonWeekDay,
    1762            0 :                                                  state.dataWeather->LeapYearAdd,
    1763              :                                                  envCurr.StartMonth,
    1764              :                                                  envCurr.StartDay,
    1765              :                                                  envCurr.EndMonth,
    1766              :                                                  envCurr.EndDay,
    1767            0 :                                                  envCurr.RollDayTypeOnRepeat);
    1768            0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1769            0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1770              :                             }
    1771            0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1772              :                         }
    1773            1 :                         ++state.dataWeather->YearOfSim;
    1774            1 :                         ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1775              :                     } else {
    1776          727 :                         ReadWeatherForDay(state, state.dataGlobal->DayOfSim + 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1777              :                     }
    1778              :                 }
    1779              :             }
    1780              : 
    1781         3083 :             state.dataEnvrn->EndYearFlag = false;
    1782         3083 :             if (state.dataEnvrn->DayOfMonth == state.dataWeather->EndDayOfMonthWithLeapDay(state.dataEnvrn->Month)) {
    1783           24 :                 state.dataEnvrn->EndMonthFlag = true;
    1784           24 :                 state.dataEnvrn->EndYearFlag = (state.dataEnvrn->Month == 12);
    1785              :             }
    1786              : 
    1787              :             // Set Tomorrow's date data
    1788         3083 :             state.dataEnvrn->MonthTomorrow = state.dataWeather->TomorrowVariables.Month;
    1789         3083 :             state.dataEnvrn->DayOfMonthTomorrow = state.dataWeather->TomorrowVariables.DayOfMonth;
    1790         3083 :             state.dataEnvrn->DayOfWeekTomorrow = state.dataWeather->TomorrowVariables.DayOfWeek;
    1791         3083 :             state.dataEnvrn->HolidayIndexTomorrow = state.dataWeather->TomorrowVariables.HolidayIndex;
    1792         3083 :             state.dataEnvrn->YearTomorrow = state.dataWeather->TomorrowVariables.Year;
    1793              : 
    1794         3083 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1795           20 :                 if (state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1 && envCurr.ActualWeather) {
    1796            0 :                     if (state.dataWeather->DatesShouldBeReset) {
    1797            0 :                         if (envCurr.TreatYearsAsConsecutive) {
    1798            0 :                             ++envCurr.CurrentYear;
    1799            0 :                             envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1800            0 :                             state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1801            0 :                             state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1802              : 
    1803              :                             // need to reset MonWeekDay and WeekDayTypes
    1804            0 :                             int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1805            0 :                             int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1806            0 :                             if (!envCurr.ActualWeather)
    1807            0 :                                 state.dataWeather->curSimDayForEndOfRunPeriod =
    1808            0 :                                     state.dataGlobal->DayOfSim + envCurr.RawSimDays + state.dataWeather->LeapYearAdd - 1;
    1809              : 
    1810              :                             {
    1811            0 :                                 int i = JDay5Start;
    1812            0 :                                 int TWeekDay = state.dataEnvrn->DayOfWeek;
    1813              :                                 while (true) {
    1814            0 :                                     state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1815            0 :                                     TWeekDay = mod(TWeekDay, 7) + 1;
    1816            0 :                                     ++i;
    1817            0 :                                     if (i > 366) i = 1;
    1818            0 :                                     if (i == JDay5End) break;
    1819              :                                 }
    1820              :                             }
    1821            0 :                             ResetWeekDaysByMonth(state,
    1822            0 :                                                  envCurr.MonWeekDay,
    1823            0 :                                                  state.dataWeather->LeapYearAdd,
    1824              :                                                  envCurr.StartMonth,
    1825              :                                                  envCurr.StartDay,
    1826              :                                                  envCurr.EndMonth,
    1827              :                                                  envCurr.EndDay,
    1828            0 :                                                  envCurr.RollDayTypeOnRepeat);
    1829            0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1830            0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1831              :                             }
    1832            0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1833              :                         }
    1834              :                     }
    1835           20 :                 } else if ((state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1) && state.dataWeather->DatesShouldBeReset &&
    1836            0 :                            (state.dataWeather->Jan1DatesShouldBeReset)) {
    1837            0 :                     if (envCurr.TreatYearsAsConsecutive) {
    1838            0 :                         ++envCurr.CurrentYear;
    1839            0 :                         envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1840            0 :                         state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1841            0 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && !state.dataWeather->WFAllowsLeapYears)
    1842            0 :                             state.dataEnvrn->CurrentYearIsLeapYear = false;
    1843            0 :                         if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod && state.dataEnvrn->CurrentYearIsLeapYear)
    1844            0 :                             ++state.dataWeather->curSimDayForEndOfRunPeriod;
    1845              :                     }
    1846              : 
    1847            0 :                     state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1848              : 
    1849            0 :                     if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod) {
    1850            0 :                         ResetWeekDaysByMonth(state,
    1851            0 :                                              envCurr.MonWeekDay,
    1852            0 :                                              state.dataWeather->LeapYearAdd,
    1853              :                                              envCurr.StartMonth,
    1854              :                                              envCurr.StartDay,
    1855              :                                              envCurr.EndMonth,
    1856              :                                              envCurr.EndDay,
    1857            0 :                                              envCurr.RollDayTypeOnRepeat,
    1858            0 :                                              envCurr.RollDayTypeOnRepeat || state.dataEnvrn->CurrentYearIsLeapYear);
    1859            0 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1860            0 :                             SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1861              :                         }
    1862            0 :                         SetSpecialDayDates(state, envCurr.MonWeekDay);
    1863              :                     }
    1864              :                 }
    1865              :             }
    1866              : 
    1867              :             // at the end of each day find the min/max weather used for DOAS sizing
    1868         3083 :             if (state.dataGlobal->AirLoopHVACDOASUsedInSim) {
    1869           68 :                 if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign || envCurr.KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1870         1700 :                     for (int iHr = 1; iHr <= Constant::iHoursInDay; ++iHr) {
    1871        11424 :                         for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour; ++iTS) {
    1872         9792 :                             Real64 Tdb = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDryBulbTemp;
    1873         9792 :                             Real64 Tdp = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDewPointTemp;
    1874         9792 :                             if (Tdb > envCurr.maxCoolingOATSizing) {
    1875           84 :                                 envCurr.maxCoolingOATSizing = Tdb;
    1876           84 :                                 envCurr.maxCoolingOADPSizing = Tdp;
    1877              :                             }
    1878         9792 :                             if (Tdb < envCurr.minHeatingOATSizing) {
    1879           62 :                                 envCurr.minHeatingOATSizing = Tdb;
    1880           62 :                                 envCurr.minHeatingOADPSizing = Tdp;
    1881              :                             }
    1882              :                         } // for (iTS)
    1883              :                     }     // for (iHr)
    1884              :                 }
    1885              :             }
    1886              : 
    1887              :         } // ... end of DataGlobals::BeginDayFlag IF-THEN block.
    1888              : 
    1889       649147 :         if (!state.dataGlobal->BeginDayFlag && !state.dataGlobal->WarmupFlag &&
    1890       103763 :             (state.dataEnvrn->Month != envCurr.StartMonth || state.dataEnvrn->DayOfMonth != envCurr.StartDay) &&
    1891       649147 :             !state.dataWeather->DatesShouldBeReset && envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1892            0 :             state.dataWeather->DatesShouldBeReset = true;
    1893              :         }
    1894              : 
    1895       326137 :         if (state.dataGlobal->EndEnvrnFlag && (envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
    1896           22 :             (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
    1897           22 :             state.files.inputWeatherFile.rewind();
    1898           22 :             SkipEPlusWFHeader(state);
    1899           22 :             ReportMissing_RangeData(state);
    1900              :         }
    1901              : 
    1902              :         // set the EndDesignDayEnvrnsFlag (dataGlobal)
    1903              :         // 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)
    1904       326115 :         state.dataGlobal->EndDesignDayEnvrnsFlag = false;
    1905       326115 :         if (state.dataGlobal->EndEnvrnFlag) {
    1906          535 :             if (state.dataWeather->Envrn < state.dataWeather->NumOfEnvrn) {
    1907          341 :                 if (envCurr.KindOfEnvrn != state.dataWeather->Environment(state.dataWeather->Envrn + 1).KindOfEnvrn) {
    1908          116 :                     state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1909              :                 }
    1910              :             } else {
    1911              :                 // if the last environment set the flag to true.
    1912          194 :                 state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1913              :             }
    1914              :         }
    1915              : 
    1916       326115 :         if (state.dataWeather->WaterMainsParameterReport) {
    1917              :             // this is done only once
    1918          103 :             if (state.dataWeather->WaterMainsTempsMethod == WaterMainsTempCalcMethod::CorrelationFromWeatherFile) {
    1919            0 :                 if (!state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    1920            0 :                     state.dataWeather->OADryBulbAverage.CalcAnnualAndMonthlyDryBulbTemp(state);
    1921              :                 }
    1922              :             }
    1923              :             // reports to eio file
    1924          103 :             ReportWaterMainsTempParameters(state);
    1925          103 :             state.dataWeather->WaterMainsParameterReport = false;
    1926              :         }
    1927       326115 :     }
    1928              : 
    1929         3083 :     void UpdateWeatherData(EnergyPlusData &state)
    1930              :     {
    1931              : 
    1932              :         // SUBROUTINE INFORMATION:
    1933              :         //       AUTHOR         Rick Strand
    1934              :         //       DATE WRITTEN   June 1997
    1935              : 
    1936              :         // PURPOSE OF THIS SUBROUTINE:
    1937              :         // This subroutine updates all of the daily weather data in the local
    1938              :         // module level variables and the global variables.
    1939              :         // This subroutine will temporarily transfer the weather data for the
    1940              :         // current day to the old data structure contained in envdat.inc until
    1941              :         // enough reengineering has taken place to eliminate the need for this
    1942              :         // include.
    1943              : 
    1944         3083 :         state.dataWeather->TodayVariables = state.dataWeather->TomorrowVariables; // Transfer Tomorrow's Daily Weather Variables to Today
    1945              : 
    1946         3083 :         if (state.dataGlobal->BeginEnvrnFlag) {
    1947          538 :             state.dataGlobal->PreviousHour = 24;
    1948              :         }
    1949              : 
    1950         3083 :         state.dataWeather->wvarsHrTsToday = state.dataWeather->wvarsHrTsTomorrow; // What a waste
    1951              : 
    1952              :         // Update Global Data
    1953              : 
    1954         3083 :         state.dataEnvrn->DayOfYear = state.dataWeather->TodayVariables.DayOfYear;
    1955         3083 :         state.dataEnvrn->Year = state.dataWeather->TodayVariables.Year;
    1956         3083 :         state.dataEnvrn->Month = state.dataWeather->TodayVariables.Month;
    1957         3083 :         state.dataEnvrn->DayOfMonth = state.dataWeather->TodayVariables.DayOfMonth;
    1958         3083 :         state.dataEnvrn->DayOfWeek = state.dataWeather->TodayVariables.DayOfWeek;
    1959         3083 :         state.dataEnvrn->HolidayIndex = state.dataWeather->TodayVariables.HolidayIndex;
    1960         3083 :         if (state.dataEnvrn->HolidayIndex > 0) {
    1961         2333 :             state.dataWeather->RptDayType = state.dataEnvrn->HolidayIndex;
    1962              :         } else {
    1963          750 :             state.dataWeather->RptDayType = state.dataEnvrn->DayOfWeek;
    1964              :         }
    1965         3083 :         state.dataEnvrn->DSTIndicator = state.dataWeather->TodayVariables.DaylightSavingIndex;
    1966         3083 :         state.dataEnvrn->EquationOfTime = state.dataWeather->TodayVariables.EquationOfTime;
    1967         3083 :         state.dataEnvrn->CosSolarDeclinAngle = state.dataWeather->TodayVariables.CosSolarDeclinAngle;
    1968         3083 :         state.dataEnvrn->SinSolarDeclinAngle = state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    1969         3083 :     }
    1970              : 
    1971       326120 :     void SetCurrentWeather(EnergyPlusData &state)
    1972              :     {
    1973              : 
    1974              :         // SUBROUTINE INFORMATION:
    1975              :         //       AUTHOR         Russ Taylor
    1976              :         //       DATE WRITTEN   March 1990
    1977              :         //       MODIFIED       Aug94 (LKL) Fixed improper weighting
    1978              :         //                      Nov98 (FCW) Added call to get exterior illuminances
    1979              :         //                      Jan02 (FCW) Changed how ground reflectance for daylighting is set
    1980              :         //                      Mar12 (LKL) Changed settings for leap years/ current years.
    1981              :         //       RE-ENGINEERED  Apr97,May97 (RKS)
    1982              : 
    1983              :         // PURPOSE OF THIS SUBROUTINE:
    1984              :         // The purpose of this subroutine is to interpolate the hourly
    1985              :         // environment data for the sub-hourly time steps in EnergyPlus.  In
    1986              :         // other words, this subroutine puts the current weather conditions
    1987              :         // into the proper variables.  Rather than using the same data for
    1988              :         // each time step, environment data is interpolated as a continuum
    1989              :         // throughout the day.
    1990              : 
    1991              :         // METHODOLOGY EMPLOYED:
    1992              :         // The current hour (DataGlobals::HourOfDay) as well as the next hour are used
    1993              :         // to come up with environment data per time step interval.  Method
    1994              :         // used is to assign a weighting for the current hour's data and
    1995              :         // (1-that weighting) to the next hour's data.  Actual method is:  if
    1996              :         // the current time step is 15 minutes into hour, the interpolated dry
    1997              :         // bulb temperature should be 3/4*dry bulb temperature of current hour
    1998              :         // and 1/4*dry bulb temperature of next environment hourly data.  At
    1999              :         // day boundary (current hour = 24), the next hour is hour 1 of next
    2000              :         // weather data day (Tomorrow%).
    2001              : 
    2002              :         static constexpr std::string_view RoutineName("SetCurrentWeather");
    2003              : 
    2004       326120 :         state.dataWeather->NextHour = state.dataGlobal->HourOfDay + 1;
    2005              : 
    2006       326120 :         if (state.dataGlobal->HourOfDay == 24) { // Should investigate whether EndDayFlag is always set here and use that instead
    2007        13821 :             state.dataWeather->NextHour = 1;
    2008              :         }
    2009              : 
    2010       326120 :         if (state.dataGlobal->HourOfDay == 1) { // Should investigate whether DataGlobals::BeginDayFlag is always set here and use that instead
    2011        14085 :             state.dataEnvrn->DayOfYear_Schedule = General::OrdinalDay(state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, 1);
    2012              :         }
    2013              : 
    2014       326120 :         Sched::UpdateScheduleVals(state);
    2015              : 
    2016       326120 :         state.dataEnvrn->CurMnDyHr =
    2017       652240 :             format("{:02d}/{:02d} {:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, (unsigned short)(state.dataGlobal->HourOfDay - 1));
    2018       326120 :         state.dataEnvrn->CurMnDy = format("{:02d}/{:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    2019       326120 :         state.dataEnvrn->CurMnDyYr =
    2020       652240 :             format("{:02d}/{:02d}/{:04d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, state.dataGlobal->CalendarYear);
    2021              : 
    2022       326120 :         state.dataGlobal->WeightNow = state.dataWeather->Interpolation(state.dataGlobal->TimeStep);
    2023       326120 :         state.dataGlobal->WeightPreviousHour = 1.0 - state.dataGlobal->WeightNow;
    2024              : 
    2025       326120 :         state.dataGlobal->CurrentTime = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * (state.dataWeather->TimeStepFraction);
    2026       326120 :         state.dataGlobal->SimTimeSteps = (state.dataGlobal->DayOfSim - 1) * 24 * state.dataGlobal->TimeStepsInHour +
    2027       326120 :                                          (state.dataGlobal->HourOfDay - 1) * state.dataGlobal->TimeStepsInHour + state.dataGlobal->TimeStep;
    2028              : 
    2029       326120 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] =
    2030       326120 :             state.dataWeather->siteBuildingSurfaceGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2031       326120 :         state.dataEnvrn->GroundTempKelvin = state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] + Constant::Kelvin;
    2032       326120 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod] =
    2033       326120 :             state.dataWeather->siteFCFactorMethodGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2034       326120 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow] =
    2035       326120 :             state.dataWeather->siteShallowGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2036       326120 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep] =
    2037       326120 :             state.dataWeather->siteDeepGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2038       326120 :         state.dataEnvrn->GndReflectance = state.dataWeather->GroundReflectances(state.dataEnvrn->Month);
    2039       326120 :         state.dataEnvrn->GndReflectanceForDayltg = state.dataEnvrn->GndReflectance;
    2040              : 
    2041       326120 :         CalcWaterMainsTemp(state);
    2042              : 
    2043              :         // Determine if Sun is up or down, set Solar Cosine values for time step.
    2044       326120 :         DetermineSunUpDown(state, state.dataEnvrn->SOLCOS);
    2045       326120 :         if (state.dataEnvrn->SunIsUp && state.dataWeather->SolarAltitudeAngle < 0.0) {
    2046            0 :             ShowFatalError(state, format("SetCurrentWeather: At {} Sun is Up but Solar Altitude Angle is < 0.0", state.dataEnvrn->CurMnDyHr));
    2047              :         }
    2048              : 
    2049       326120 :         auto const &today = state.dataWeather->wvarsHrTsToday(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2050       326120 :         state.dataEnvrn->OutDryBulbTemp = today.OutDryBulbTemp;
    2051       326120 :         if (state.dataEnvrn->EMSOutDryBulbOverrideOn) state.dataEnvrn->OutDryBulbTemp = state.dataEnvrn->EMSOutDryBulbOverrideValue;
    2052       326120 :         state.dataEnvrn->OutBaroPress = today.OutBaroPress;
    2053       326120 :         state.dataEnvrn->OutDewPointTemp = today.OutDewPointTemp;
    2054       326120 :         if (state.dataEnvrn->EMSOutDewPointTempOverrideOn) state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->EMSOutDewPointTempOverrideValue;
    2055       326120 :         state.dataEnvrn->OutRelHum = today.OutRelHum;
    2056       326120 :         state.dataEnvrn->OutRelHumValue = state.dataEnvrn->OutRelHum / 100.0;
    2057       326120 :         if (state.dataEnvrn->EMSOutRelHumOverrideOn) {
    2058            2 :             state.dataEnvrn->OutRelHumValue = state.dataEnvrn->EMSOutRelHumOverrideValue / 100.0;
    2059            2 :             state.dataEnvrn->OutRelHum = state.dataEnvrn->EMSOutRelHumOverrideValue;
    2060              :         }
    2061              : 
    2062              :         // Humidity Ratio and Wet Bulb are derived
    2063       326120 :         state.dataEnvrn->OutHumRat = Psychrometrics::PsyWFnTdbRhPb(
    2064       326120 :             state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutRelHumValue, state.dataEnvrn->OutBaroPress, RoutineName);
    2065       652240 :         state.dataEnvrn->OutWetBulbTemp =
    2066       326120 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
    2067       326120 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) {
    2068        29874 :             state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2069        59748 :             Real64 TempVal = Psychrometrics::PsyWFnTdbTwbPb(
    2070        29874 :                 state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutWetBulbTemp, state.dataEnvrn->OutBaroPress);
    2071        29874 :             state.dataEnvrn->OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, TempVal, state.dataEnvrn->OutBaroPress);
    2072              :         }
    2073              : 
    2074       326120 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) {
    2075        55473 :             state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2076              :         }
    2077              : 
    2078       396260 :         if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) ||
    2079        70140 :             (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay)) {
    2080              : 
    2081       751458 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2082       495478 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2083              :             }
    2084              : 
    2085       255980 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2086       255980 :             int const envrnDayNum = envCurr.DesignDayNum;
    2087       255980 :             auto const &desDayInput = state.dataWeather->DesDayInput(envrnDayNum);
    2088       255980 :             auto &spSiteSchedule = state.dataWeather->spSiteSchedules(envrnDayNum);
    2089       255980 :             auto const &desDayMod = state.dataWeather->desDayMods(envrnDayNum)(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2090              : 
    2091       255980 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Default) {
    2092            0 :                 spSiteSchedule.OutDryBulbTemp = desDayMod.OutDryBulbTemp;
    2093              :             }
    2094              : 
    2095       255980 :             if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    2096       255977 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    2097            3 :                 spSiteSchedule.OutRelHum = desDayMod.OutRelHum;
    2098              :             }
    2099       255980 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    2100            0 :                 spSiteSchedule.BeamSolarRad = desDayMod.BeamSolarRad;
    2101            0 :                 spSiteSchedule.DifSolarRad = desDayMod.DifSolarRad;
    2102              :             }
    2103              : 
    2104       255980 :             if (envCurr.skyTempModel == SkyTempModel::ScheduleValue || envCurr.skyTempModel == SkyTempModel::DryBulbDelta ||
    2105       255980 :                 envCurr.skyTempModel == SkyTempModel::DewPointDelta) {
    2106            0 :                 spSiteSchedule.SkyTemp = desDayMod.SkyTemp;
    2107              :             }
    2108        70140 :         } else if (state.dataEnvrn->TotDesDays > 0) {
    2109       105291 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2110        70194 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2111              :             }
    2112              :         }
    2113              : 
    2114       326120 :         state.dataEnvrn->WindSpeed = today.WindSpeed;
    2115       326120 :         if (state.dataEnvrn->EMSWindSpeedOverrideOn) state.dataEnvrn->WindSpeed = state.dataEnvrn->EMSWindSpeedOverrideValue;
    2116       326120 :         state.dataEnvrn->WindDir = today.WindDir;
    2117       326120 :         if (state.dataEnvrn->EMSWindDirOverrideOn) state.dataEnvrn->WindDir = state.dataEnvrn->EMSWindDirOverrideValue;
    2118       326120 :         state.dataWeather->HorizIRSky = today.HorizIRSky;
    2119       326120 :         state.dataEnvrn->SkyTemp = today.SkyTemp;
    2120       326120 :         state.dataEnvrn->SkyTempKelvin = state.dataEnvrn->SkyTemp + Constant::Kelvin;
    2121       326120 :         state.dataEnvrn->DifSolarRad = today.DifSolarRad;
    2122       326120 :         if (state.dataEnvrn->EMSDifSolarRadOverrideOn) state.dataEnvrn->DifSolarRad = state.dataEnvrn->EMSDifSolarRadOverrideValue;
    2123       326120 :         state.dataEnvrn->BeamSolarRad = today.BeamSolarRad;
    2124       326120 :         if (state.dataEnvrn->EMSBeamSolarRadOverrideOn) state.dataEnvrn->BeamSolarRad = state.dataEnvrn->EMSBeamSolarRadOverrideValue;
    2125       326120 :         state.dataEnvrn->LiquidPrecipitation = today.LiquidPrecip / 1000.0; // convert from mm to m
    2126       326120 :         if ((state.dataEnvrn->RunPeriodEnvironment) && (!state.dataGlobal->WarmupFlag)) {
    2127        35042 :             int month = state.dataEnvrn->Month;
    2128        35042 :             state.dataWaterData->RainFall.MonthlyTotalPrecInWeather.at(month - 1) += state.dataEnvrn->LiquidPrecipitation * 1000.0;
    2129        35042 :             if ((state.dataEnvrn->LiquidPrecipitation > 0) && (state.dataGlobal->TimeStep == 1)) {
    2130           43 :                 state.dataWaterData->RainFall.numRainyHoursInWeather.at(month - 1) += 1;
    2131              :             }
    2132              :         }
    2133              : 
    2134       326120 :         WaterManager::UpdatePrecipitation(state);
    2135              : 
    2136       326120 :         state.dataEnvrn->TotalCloudCover = today.TotalSkyCover;
    2137       326120 :         state.dataEnvrn->OpaqueCloudCover = today.OpaqueSkyCover;
    2138              : 
    2139       326120 :         if (state.dataWeather->UseRainValues) {
    2140              :             // It is set as LiquidPrecipitation >= .8 mm here: state.dataWeather->TomorrowLiquidPrecip(ts, hour) >=
    2141              :             // state.dataWeather->IsRainThreshold;
    2142       326120 :             state.dataEnvrn->IsRain = today.IsRain;
    2143       326120 :             if (state.dataWaterData->RainFall.ModeID == DataWater::RainfallMode::RainSchedDesign && state.dataEnvrn->RunPeriodEnvironment) {
    2144              :                 // CurrentAmount unit: m
    2145            1 :                 state.dataEnvrn->IsRain = state.dataWaterData->RainFall.CurrentAmount >= (state.dataWeather->IsRainThreshold / 1000.0);
    2146              :             }
    2147              :         } else {
    2148            0 :             state.dataEnvrn->IsRain = false;
    2149              :         }
    2150       326120 :         if (state.dataWeather->UseSnowValues) {
    2151       326120 :             state.dataEnvrn->IsSnow = today.IsSnow;
    2152              :         } else {
    2153            0 :             state.dataEnvrn->IsSnow = false;
    2154              :         }
    2155              : 
    2156       326120 :         if (state.dataEnvrn->IsSnow) {
    2157            0 :             state.dataEnvrn->GndReflectance = max(min(state.dataEnvrn->GndReflectance * state.dataWeather->SnowGndRefModifier, 1.0), 0.0);
    2158            0 :             state.dataEnvrn->GndReflectanceForDayltg =
    2159            0 :                 max(min(state.dataEnvrn->GndReflectanceForDayltg * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0);
    2160              :         }
    2161              : 
    2162       326120 :         state.dataEnvrn->GndSolarRad =
    2163       326120 :             max((state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z + state.dataEnvrn->DifSolarRad) * state.dataEnvrn->GndReflectance, 0.0);
    2164              : 
    2165       326120 :         if (!state.dataEnvrn->SunIsUp) {
    2166       166429 :             state.dataEnvrn->DifSolarRad = 0.0;
    2167       166429 :             state.dataEnvrn->BeamSolarRad = 0.0;
    2168       166429 :             state.dataEnvrn->GndSolarRad = 0.0;
    2169              :         }
    2170              : 
    2171       326120 :         state.dataEnvrn->OutEnthalpy = Psychrometrics::PsyHFnTdbW(state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2172       652240 :         state.dataEnvrn->OutAirDensity =
    2173       326120 :             Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2174              : 
    2175       326120 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2176       326120 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2177              : 
    2178       326120 :         DayltgCurrentExtHorizIllum(state);
    2179              : 
    2180       326120 :         if (!state.dataEnvrn->IsRain) {
    2181       325913 :             state.dataWeather->RptIsRain = 0;
    2182              :         } else {
    2183          207 :             state.dataWeather->RptIsRain = 1;
    2184              :         }
    2185              : 
    2186       326120 :         if (!state.dataEnvrn->IsSnow) {
    2187       326120 :             state.dataWeather->RptIsSnow = 0;
    2188              :         } else {
    2189            0 :             state.dataWeather->RptIsSnow = 1;
    2190              :         }
    2191       326120 :     }
    2192              : 
    2193          755 :     void ReadWeatherForDay(EnergyPlusData &state,
    2194              :                            int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2195              :                            int const Environ,            // Environment being simulated
    2196              :                            bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2197              :     )
    2198              :     {
    2199              : 
    2200              :         // SUBROUTINE INFORMATION:
    2201              :         //       AUTHOR         Linda K. Lawrie
    2202              :         //       DATE WRITTEN   April 1999
    2203              : 
    2204              :         // PURPOSE OF THIS SUBROUTINE:
    2205              :         // This subroutine is the driving routine behind reading the weather data.
    2206              :         // Theoretically, several kinds of weather files could be read here.  As
    2207              :         // distributed only EPW files are allowed.
    2208              : 
    2209          755 :         ReadEPlusWeatherForDay(state, DayToRead, Environ, BackSpaceAfterRead);
    2210          755 :     }
    2211              : 
    2212          755 :     void ReadEPlusWeatherForDay(EnergyPlusData &state,
    2213              :                                 int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2214              :                                 int const Environ,            // Environment being simulated
    2215              :                                 bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2216              :     )
    2217              :     {
    2218              : 
    2219              :         // SUBROUTINE INFORMATION:
    2220              :         //       AUTHOR         Linda K. Lawrie
    2221              :         //       DATE WRITTEN   April 1999
    2222              :         //       MODIFIED       March 2012; add actual weather read.
    2223              : 
    2224              :         // PURPOSE OF THIS SUBROUTINE:
    2225              :         // This subroutine reads the appropriate day of EPW weather data.
    2226              : 
    2227              :         int WYear;
    2228              :         int WMonth;
    2229              :         int WDay;
    2230              :         int WHour;
    2231              :         int WMinute;
    2232              :         Real64 DryBulb;
    2233              :         Real64 DewPoint;
    2234              :         Real64 RelHum;
    2235              :         Real64 AtmPress;
    2236              :         Real64 ETHoriz;
    2237              :         Real64 ETDirect;
    2238              :         Real64 IRHoriz;
    2239              :         Real64 GLBHoriz;
    2240              :         Real64 DirectRad;
    2241              :         Real64 DiffuseRad;
    2242              :         Real64 GLBHorizIllum;
    2243              :         Real64 DirectNrmIllum;
    2244              :         Real64 DiffuseHorizIllum;
    2245              :         Real64 ZenLum;
    2246              :         Real64 WindDir;
    2247              :         Real64 WindSpeed;
    2248              :         Real64 TotalSkyCover;
    2249              :         Real64 OpaqueSkyCover;
    2250              :         Real64 Visibility;
    2251              :         Real64 CeilHeight;
    2252              :         Real64 PrecipWater;
    2253              :         Real64 AerosolOptDepth;
    2254              :         Real64 SnowDepth;
    2255              :         Real64 DaysSinceLastSnow;
    2256              :         Real64 Albedo;
    2257              :         Real64 LiquidPrecip;
    2258              :         int PresWeathObs;
    2259          755 :         Array1D_int PresWeathConds(9);
    2260              : 
    2261          755 :         constexpr std::string_view routineName = "ReadEPlusWeatherForDay";
    2262              : 
    2263          755 :         Array1D<WeatherVars> wvarsHr = Array1D<WeatherVars>(Constant::iHoursInDay);
    2264              : 
    2265          755 :         auto &thisEnviron = state.dataWeather->Environment(Environ);
    2266              : 
    2267          755 :         if (DayToRead == 1) {
    2268              : 
    2269              :             // Checks whether Weather file contains just one year of data. If yes then rewind and position to first
    2270              :             // day of weather file. The rest of code appropriately positions to the start day.
    2271              : 
    2272           27 :             bool Ready = false;
    2273           27 :             int NumRewinds = 0;
    2274              :             //     Must position file to proper day
    2275              :             //     File already position to first data record
    2276              :             //          Set Current Day of Week to "start of Data Period"
    2277           27 :             state.dataWeather->ReadEPlusWeatherCurTime = 1.0 / double(state.dataWeather->NumIntervalsPerHour);
    2278           27 :             state.dataWeather->CurDayOfWeek = state.dataWeather->DataPeriods(1).WeekDay - 1;
    2279           27 :             WYear = 0;
    2280           27 :             WMonth = 0;
    2281           27 :             WDay = 0;
    2282           27 :             WHour = 0;
    2283           27 :             WMinute = 0;
    2284           27 :             state.dataWeather->LastHourSet = false;
    2285           27 :             InputFile::ReadResult<std::string> WeatherDataLine{"", true, false};
    2286          752 :             while (!Ready) {
    2287          725 :                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2288          725 :                 if (WeatherDataLine.good) {
    2289              :                     bool ErrorFound;
    2290          724 :                     InterpretWeatherDataLine(state,
    2291              :                                              WeatherDataLine.data,
    2292              :                                              ErrorFound,
    2293              :                                              WYear,
    2294              :                                              WMonth,
    2295              :                                              WDay,
    2296              :                                              WHour,
    2297              :                                              WMinute,
    2298              :                                              DryBulb,
    2299              :                                              DewPoint,
    2300              :                                              RelHum,
    2301              :                                              AtmPress,
    2302              :                                              ETHoriz,
    2303              :                                              ETDirect,
    2304              :                                              IRHoriz,
    2305              :                                              GLBHoriz,
    2306              :                                              DirectRad,
    2307              :                                              DiffuseRad,
    2308              :                                              GLBHorizIllum,
    2309              :                                              DirectNrmIllum,
    2310              :                                              DiffuseHorizIllum,
    2311              :                                              ZenLum,
    2312              :                                              WindDir,
    2313              :                                              WindSpeed,
    2314              :                                              TotalSkyCover,
    2315              :                                              OpaqueSkyCover,
    2316              :                                              Visibility,
    2317              :                                              CeilHeight,
    2318              :                                              PresWeathObs,
    2319              :                                              PresWeathConds,
    2320              :                                              PrecipWater,
    2321              :                                              AerosolOptDepth,
    2322              :                                              SnowDepth,
    2323              :                                              DaysSinceLastSnow,
    2324              :                                              Albedo,
    2325              :                                              LiquidPrecip);
    2326            1 :                 } else if (WeatherDataLine.eof) {
    2327            1 :                     if (NumRewinds > 0) {
    2328            0 :                         std::string date = fmt::to_string(thisEnviron.StartMonth) + '/' + fmt::to_string(thisEnviron.StartDay);
    2329            0 :                         if (thisEnviron.MatchYear) {
    2330            0 :                             date += '/' + fmt::to_string(thisEnviron.StartYear);
    2331              :                         }
    2332            0 :                         ShowSevereError(state, format("Multiple rewinds on EPW while searching for first day {}", date));
    2333            0 :                     } else {
    2334            1 :                         state.files.inputWeatherFile.rewind();
    2335            1 :                         ++NumRewinds;
    2336            1 :                         SkipEPlusWFHeader(state);
    2337            1 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2338              :                         bool ErrorFound;
    2339            1 :                         InterpretWeatherDataLine(state,
    2340              :                                                  WeatherDataLine.data,
    2341              :                                                  ErrorFound,
    2342              :                                                  WYear,
    2343              :                                                  WMonth,
    2344              :                                                  WDay,
    2345              :                                                  WHour,
    2346              :                                                  WMinute,
    2347              :                                                  DryBulb,
    2348              :                                                  DewPoint,
    2349              :                                                  RelHum,
    2350              :                                                  AtmPress,
    2351              :                                                  ETHoriz,
    2352              :                                                  ETDirect,
    2353              :                                                  IRHoriz,
    2354              :                                                  GLBHoriz,
    2355              :                                                  DirectRad,
    2356              :                                                  DiffuseRad,
    2357              :                                                  GLBHorizIllum,
    2358              :                                                  DirectNrmIllum,
    2359              :                                                  DiffuseHorizIllum,
    2360              :                                                  ZenLum,
    2361              :                                                  WindDir,
    2362              :                                                  WindSpeed,
    2363              :                                                  TotalSkyCover,
    2364              :                                                  OpaqueSkyCover,
    2365              :                                                  Visibility,
    2366              :                                                  CeilHeight,
    2367              :                                                  PresWeathObs,
    2368              :                                                  PresWeathConds,
    2369              :                                                  PrecipWater,
    2370              :                                                  AerosolOptDepth,
    2371              :                                                  SnowDepth,
    2372              :                                                  DaysSinceLastSnow,
    2373              :                                                  Albedo,
    2374              :                                                  LiquidPrecip);
    2375              :                     }
    2376              :                 }
    2377          725 :                 if (!WeatherDataLine.good) {
    2378            0 :                     ShowFatalError(state,
    2379            0 :                                    format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2380              :                                           WYear,
    2381              :                                           WMonth,
    2382              :                                           WDay,
    2383              :                                           WHour,
    2384              :                                           WMinute,
    2385            0 :                                           state.files.inputWeatherFile.error_state_to_string()),
    2386            0 :                                    OptionalOutputFileRef{state.files.eso});
    2387              :                 }
    2388          725 :                 if (state.dataWeather->CurDayOfWeek <= 7) {
    2389          725 :                     state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2390              :                 }
    2391          725 :                 bool RecordDateMatch =
    2392         1423 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && !thisEnviron.MatchYear) ||
    2393          698 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && thisEnviron.MatchYear && WYear == thisEnviron.StartYear);
    2394          725 :                 if (RecordDateMatch) {
    2395           27 :                     state.files.inputWeatherFile.backspace();
    2396           27 :                     Ready = true;
    2397           27 :                     if (state.dataWeather->CurDayOfWeek <= 7) {
    2398           27 :                         --state.dataWeather->CurDayOfWeek;
    2399              :                     }
    2400              :                     // Do the range checks on the first set of fields -- no others.
    2401           27 :                     bool ErrorsFound = false;
    2402           27 :                     if (DryBulb < 99.9 && (DryBulb < -90.0 || DryBulb > 70.0)) {
    2403            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2404            0 :                         ShowContinueError(state, format("DryBulb Temperature ({:.2R}) is out of range [-90.0, 70.0]", DryBulb));
    2405            0 :                         ErrorsFound = true;
    2406              :                     }
    2407              : 
    2408           27 :                     if (DewPoint < 99.9 && (DewPoint < -90.0 || DewPoint > 70.0)) {
    2409            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2410            0 :                         ShowContinueError(state, format("DewPoint Temperature ({:.2R}) is out of range [-90.0, 70.0]", DewPoint));
    2411            0 :                         ErrorsFound = true;
    2412              :                     }
    2413              : 
    2414           27 :                     if (RelHum < 999.0 && (RelHum < 0.0 || RelHum > 110.0)) {
    2415            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2416            0 :                         ShowContinueError(state, format("Relative Humidity ({:.2R}) is out of range [0.0, 100.0]", RelHum));
    2417            0 :                         ErrorsFound = true;
    2418              :                     }
    2419              : 
    2420           27 :                     if (AtmPress < 999999.0 && (AtmPress <= 31000.0 || AtmPress > 120000.0)) {
    2421            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2422            0 :                         ShowContinueError(state, format("Atmospheric Pressure ({:.0R}) is out of range [31000, 120000]", AtmPress));
    2423            0 :                         ErrorsFound = true;
    2424              :                     }
    2425              : 
    2426           27 :                     if (DirectRad < 0.0) {
    2427            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2428            0 :                         ShowContinueError(state, format("Direct Radiation ({:.2R}) is out of range [0.0, -]", DirectRad));
    2429            0 :                         ErrorsFound = true;
    2430              :                     }
    2431              : 
    2432           27 :                     if (DiffuseRad < 0.0) {
    2433            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2434            0 :                         ShowContinueError(state, format("Diffuse Radiation ({:.2R}) is out of range [0.0, -]", DiffuseRad));
    2435            0 :                         ErrorsFound = true;
    2436              :                     }
    2437              : 
    2438           27 :                     if (WindDir < 999.0 && (WindDir < 0.0 || WindDir > 360.0)) {
    2439            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2440            0 :                         ShowContinueError(state, format("Wind Direction ({:.2R}) is out of range [0.0, 360.0]", WindDir));
    2441            0 :                         ErrorsFound = true;
    2442              :                     }
    2443              : 
    2444           27 :                     if (WindSpeed < 999.0 && (WindSpeed < 0.0 || WindSpeed > 40.0)) {
    2445            0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2446            0 :                         ShowContinueError(state, format("Wind Speed ({:.2R}) is out of range [0.0, 40.0]", WindSpeed));
    2447            0 :                         ErrorsFound = true;
    2448              :                     }
    2449              : 
    2450           27 :                     if (ErrorsFound) {
    2451            0 :                         ShowSevereError(state, "Out of Range errors found with initial day of WeatherFile");
    2452              :                     }
    2453              :                 } else {
    2454              :                     //  Must skip this day
    2455          698 :                     for (int i = 2; i <= state.dataWeather->NumIntervalsPerHour; ++i) {
    2456            0 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2457            0 :                         if (!WeatherDataLine.good) {
    2458            0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2459            0 :                             ShowFatalError(state,
    2460            0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2461              :                                                   WYear,
    2462              :                                                   WMonth,
    2463              :                                                   WDay,
    2464              :                                                   WHour,
    2465              :                                                   WMinute,
    2466            0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2467            0 :                                            OptionalOutputFileRef{state.files.eso});
    2468              :                         }
    2469              :                     }
    2470        16752 :                     for (int i = 1; i <= 23 * state.dataWeather->NumIntervalsPerHour; ++i) {
    2471        16054 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2472        16054 :                         if (!WeatherDataLine.good) {
    2473            0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2474            0 :                             ShowFatalError(state,
    2475            0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2476              :                                                   WYear,
    2477              :                                                   WMonth,
    2478              :                                                   WDay,
    2479              :                                                   WHour,
    2480              :                                                   WMinute,
    2481            0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2482            0 :                                            OptionalOutputFileRef{state.files.eso});
    2483              :                         }
    2484              :                     }
    2485              :                 }
    2486              :             }
    2487              : 
    2488           27 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2489              :             // Why do some things here use state.dataWeather->Envrn and some the parameter Environ?
    2490              : 
    2491              :             // Positioned to proper day
    2492           36 :             if (!state.dataGlobal->KickOffSimulation && !state.dataGlobal->DoingSizing &&
    2493            9 :                 thisEnviron.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    2494            6 :                 ++thisEnviron.CurrentCycle;
    2495            6 :                 if (!thisEnviron.RollDayTypeOnRepeat) {
    2496            0 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2497            0 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2498            0 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2499              :                     }
    2500            0 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2501            6 :                 } else if (thisEnviron.CurrentCycle == 1) {
    2502            6 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2503            6 :                     thisEnviron.SetWeekDays = true;
    2504            6 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2505            0 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2506              :                     }
    2507            6 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2508              :                 } else {
    2509            0 :                     state.dataWeather->CurDayOfWeek = state.dataEnvrn->DayOfWeekTomorrow;
    2510              :                 }
    2511              :             } else {
    2512           21 :                 SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2513              :             }
    2514           27 :         }
    2515              : 
    2516          755 :         bool TryAgain = true;
    2517          755 :         bool SkipThisDay = false;
    2518              : 
    2519         1510 :         while (TryAgain) {
    2520              : 
    2521          755 :             TryAgain = false;
    2522              : 
    2523        18875 :             for (int hour = 1; hour <= 24; ++hour) {
    2524        36240 :                 for (int CurTimeStep = 1; CurTimeStep <= state.dataWeather->NumIntervalsPerHour; ++CurTimeStep) {
    2525        18120 :                     state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour) = WeatherVars();
    2526        18120 :                     auto WeatherDataLine = state.files.inputWeatherFile.readLine();
    2527        18120 :                     if (!WeatherDataLine.good) {
    2528            0 :                         WeatherDataLine.data.clear();
    2529              :                     }
    2530        18120 :                     if (WeatherDataLine.data.empty()) {
    2531            0 :                         if (hour == 1) {
    2532            0 :                             WeatherDataLine.eof = true;
    2533            0 :                             WeatherDataLine.good = false;
    2534              :                         } else {
    2535            0 :                             WeatherDataLine.good = false;
    2536              :                         }
    2537              :                     }
    2538        18120 :                     if (WeatherDataLine.good) {
    2539              :                         bool ErrorFound;
    2540        18120 :                         InterpretWeatherDataLine(state,
    2541              :                                                  WeatherDataLine.data,
    2542              :                                                  ErrorFound,
    2543              :                                                  WYear,
    2544              :                                                  WMonth,
    2545              :                                                  WDay,
    2546              :                                                  WHour,
    2547              :                                                  WMinute,
    2548              :                                                  DryBulb,
    2549              :                                                  DewPoint,
    2550              :                                                  RelHum,
    2551              :                                                  AtmPress,
    2552              :                                                  ETHoriz,
    2553              :                                                  ETDirect,
    2554              :                                                  IRHoriz,
    2555              :                                                  GLBHoriz,
    2556              :                                                  DirectRad,
    2557              :                                                  DiffuseRad,
    2558              :                                                  GLBHorizIllum,
    2559              :                                                  DirectNrmIllum,
    2560              :                                                  DiffuseHorizIllum,
    2561              :                                                  ZenLum,
    2562              :                                                  WindDir,
    2563              :                                                  WindSpeed,
    2564              :                                                  TotalSkyCover,
    2565              :                                                  OpaqueSkyCover,
    2566              :                                                  Visibility,
    2567              :                                                  CeilHeight,
    2568              :                                                  PresWeathObs,
    2569              :                                                  PresWeathConds,
    2570              :                                                  PrecipWater,
    2571              :                                                  AerosolOptDepth,
    2572              :                                                  SnowDepth,
    2573              :                                                  DaysSinceLastSnow,
    2574              :                                                  Albedo,
    2575              :                                                  LiquidPrecip);
    2576              :                     } else { // ReadStatus /=0
    2577            0 :                         if (WeatherDataLine.eof &&
    2578            0 :                             state.dataWeather->NumDataPeriods == 1) { // Standard End-of-file, rewind and position to first day...
    2579            0 :                             if (state.dataWeather->DataPeriods(1).NumDays >= state.dataWeather->NumDaysInYear) {
    2580            0 :                                 state.files.inputWeatherFile.rewind();
    2581            0 :                                 SkipEPlusWFHeader(state);
    2582            0 :                                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2583              :                                 bool ErrorFound;
    2584            0 :                                 InterpretWeatherDataLine(state,
    2585              :                                                          WeatherDataLine.data,
    2586              :                                                          ErrorFound,
    2587              :                                                          WYear,
    2588              :                                                          WMonth,
    2589              :                                                          WDay,
    2590              :                                                          WHour,
    2591              :                                                          WMinute,
    2592              :                                                          DryBulb,
    2593              :                                                          DewPoint,
    2594              :                                                          RelHum,
    2595              :                                                          AtmPress,
    2596              :                                                          ETHoriz,
    2597              :                                                          ETDirect,
    2598              :                                                          IRHoriz,
    2599              :                                                          GLBHoriz,
    2600              :                                                          DirectRad,
    2601              :                                                          DiffuseRad,
    2602              :                                                          GLBHorizIllum,
    2603              :                                                          DirectNrmIllum,
    2604              :                                                          DiffuseHorizIllum,
    2605              :                                                          ZenLum,
    2606              :                                                          WindDir,
    2607              :                                                          WindSpeed,
    2608              :                                                          TotalSkyCover,
    2609              :                                                          OpaqueSkyCover,
    2610              :                                                          Visibility,
    2611              :                                                          CeilHeight,
    2612              :                                                          PresWeathObs,
    2613              :                                                          PresWeathConds,
    2614              :                                                          PrecipWater,
    2615              :                                                          AerosolOptDepth,
    2616              :                                                          SnowDepth,
    2617              :                                                          DaysSinceLastSnow,
    2618              :                                                          Albedo,
    2619              :                                                          LiquidPrecip);
    2620              :                             } else {
    2621            0 :                                 ShowFatalError(state,
    2622            0 :                                                format("End-of-File encountered after {}/{}/{} {}:{}, starting from first day of Weather File would "
    2623              :                                                       "not be \"next day\"",
    2624              :                                                       WYear,
    2625              :                                                       WMonth,
    2626              :                                                       WDay,
    2627              :                                                       WHour,
    2628              :                                                       WMinute));
    2629              :                             }
    2630              :                         } else {
    2631            0 :                             ShowFatalError(state,
    2632            0 :                                            format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2633              :                                                   WYear,
    2634              :                                                   WMonth,
    2635              :                                                   WDay,
    2636              :                                                   WHour,
    2637              :                                                   WMinute),
    2638            0 :                                            OptionalOutputFileRef{state.files.eso});
    2639              :                         }
    2640              :                     }
    2641              : 
    2642        18120 :                     if (hour != WHour) {
    2643            0 :                         ShowFatalError(state,
    2644            0 :                                        format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2645              :                                               WYear,
    2646              :                                               WMonth,
    2647              :                                               WDay,
    2648              :                                               WHour,
    2649              :                                               WMinute),
    2650            0 :                                        OptionalOutputFileRef{state.files.eso});
    2651              :                     }
    2652              : 
    2653              :                     //         Set possible missing values
    2654        18120 :                     if (ETHoriz < 0.0) ETHoriz = 9999.0;
    2655        18120 :                     if (ETDirect < 0.0) ETDirect = 9999.0;
    2656        18120 :                     if (IRHoriz <= 0.0) IRHoriz = 9999.0;
    2657        18120 :                     if (GLBHoriz < 0.0) GLBHoriz = 9999.0;
    2658        18120 :                     if (state.dataEnvrn->DisplayWeatherMissingDataWarnings) {
    2659            0 :                         if (DirectRad >= 9999.0) {
    2660            0 :                             ++state.dataWeather->wvarsMissedCounts.BeamSolarRad;
    2661              :                         }
    2662            0 :                         if (DiffuseRad >= 9999.0) {
    2663            0 :                             state.dataWeather->wvarsMissedCounts.DifSolarRad = state.dataWeather->wvarsMissedCounts.BeamSolarRad + 1;
    2664              :                         }
    2665            0 :                         if (DirectRad < 0.0) {
    2666            0 :                             DirectRad = 9999.0;
    2667            0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad;
    2668              :                         }
    2669            0 :                         if (DiffuseRad < 0.0) {
    2670            0 :                             DiffuseRad = 9999.0;
    2671            0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad;
    2672              :                         }
    2673              :                     }
    2674        18120 :                     if (GLBHorizIllum < 0.0) GLBHorizIllum = 999999.0;
    2675        18120 :                     if (DirectNrmIllum < 0.0) DirectNrmIllum = 999999.0;
    2676        18120 :                     if (DiffuseHorizIllum < 0.0) DiffuseHorizIllum = 999999.0;
    2677        18120 :                     if (ZenLum < 0.0) ZenLum = 99999.0;
    2678        18120 :                     if (AtmPress < 0.0) AtmPress = 999999.0;
    2679        18120 :                     if (WindSpeed < 0.0) WindSpeed = 999.0;
    2680        18120 :                     if (WindDir < -360.0 || WindDir > 360.0) WindDir = 999.0;
    2681        18120 :                     if (TotalSkyCover < 0.0) TotalSkyCover = 99.0;
    2682        18120 :                     if (RelHum < 0.0) RelHum = 999.0;
    2683        18120 :                     if (OpaqueSkyCover < 0.0) OpaqueSkyCover = 99.0;
    2684        18120 :                     if (Visibility < 0.0) Visibility = 9999.0;
    2685        18120 :                     if (CeilHeight < 0.0) CeilHeight = 9999.0;
    2686        18120 :                     if (PresWeathObs < 0) PresWeathObs = 9;
    2687        18120 :                     if (PrecipWater < 0.0) PrecipWater = 999.0;
    2688        18120 :                     if (AerosolOptDepth < 0.0) AerosolOptDepth = 999.0;
    2689        18120 :                     if (SnowDepth < 0.0) SnowDepth = 999.0;
    2690        18120 :                     if (DaysSinceLastSnow < 0.0) DaysSinceLastSnow = 99.0;
    2691        18120 :                     if (Albedo < 0.0) Albedo = 999.0;
    2692        18120 :                     if (LiquidPrecip < 0.0) LiquidPrecip = 999.0;
    2693              : 
    2694        18120 :                     if (hour == 1 && CurTimeStep == 1) {
    2695          755 :                         if (WMonth == 2 && WDay == 29 && (!state.dataEnvrn->CurrentYearIsLeapYear || !state.dataWeather->WFAllowsLeapYears)) {
    2696            0 :                             state.dataWeather->EndDayOfMonth(2) = 28;
    2697            0 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = 28;
    2698            0 :                             SkipThisDay = true;
    2699            0 :                             TryAgain = true;
    2700            0 :                             ShowWarningError(state, "ReadEPlusWeatherForDay: Feb29 data encountered but will not be processed.");
    2701            0 :                             if (!state.dataWeather->WFAllowsLeapYears) {
    2702            0 :                                 ShowContinueError(
    2703              :                                     state, "...WeatherFile does not allow Leap Years. HOLIDAYS/DAYLIGHT SAVINGS header must indicate \"Yes\".");
    2704              :                             }
    2705            0 :                             continue;
    2706              :                         } else {
    2707          755 :                             TryAgain = false;
    2708          755 :                             SkipThisDay = false;
    2709              :                         }
    2710              : 
    2711          755 :                         if (thisEnviron.ActualWeather && state.dataEnvrn->CurrentYearIsLeapYear) {
    2712            0 :                             if (WMonth == 3 && WDay == 1 && state.dataEnvrn->Month == 2 && state.dataEnvrn->DayOfMonth == 28) {
    2713            0 :                                 ShowFatalError(state, "ReadEPlusWeatherForDay: Current year is a leap year, but Feb29 data is missing.");
    2714              :                             }
    2715              :                         }
    2716              : 
    2717          755 :                         state.dataWeather->TomorrowVariables.Year = WYear;
    2718          755 :                         state.dataWeather->TomorrowVariables.Month = WMonth;
    2719          755 :                         state.dataWeather->TomorrowVariables.DayOfMonth = WDay;
    2720          755 :                         state.dataWeather->TomorrowVariables.DayOfYear = General::OrdinalDay(WMonth, WDay, state.dataWeather->LeapYearAdd);
    2721          755 :                         state.dataWeather->TomorrowVariables.DayOfYear_Schedule = General::OrdinalDay(WMonth, WDay, 1);
    2722              :                         Real64 A;
    2723              :                         Real64 B;
    2724              :                         Real64 C;
    2725              :                         Real64 AVSC;
    2726          755 :                         CalculateDailySolarCoeffs(state,
    2727          755 :                                                   state.dataWeather->TomorrowVariables.DayOfYear,
    2728              :                                                   A,
    2729              :                                                   B,
    2730              :                                                   C,
    2731              :                                                   AVSC,
    2732          755 :                                                   state.dataWeather->TomorrowVariables.EquationOfTime,
    2733          755 :                                                   state.dataWeather->TomorrowVariables.SinSolarDeclinAngle,
    2734          755 :                                                   state.dataWeather->TomorrowVariables.CosSolarDeclinAngle);
    2735          755 :                         if (state.dataWeather->CurDayOfWeek <= 7) {
    2736          755 :                             state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2737              :                         }
    2738          755 :                         state.dataWeather->TomorrowVariables.DayOfWeek = state.dataWeather->CurDayOfWeek;
    2739         1510 :                         state.dataWeather->TomorrowVariables.DaylightSavingIndex =
    2740          755 :                             state.dataWeather->DSTIndex(state.dataWeather->TomorrowVariables.DayOfYear);
    2741          755 :                         state.dataWeather->TomorrowVariables.HolidayIndex =
    2742          755 :                             state.dataWeather->SpecialDayTypes(state.dataWeather->TomorrowVariables.DayOfYear);
    2743              :                     }
    2744              : 
    2745        18120 :                     if (SkipThisDay) continue;
    2746              : 
    2747              :                     // Check out missing values
    2748              : 
    2749        18120 :                     if (DryBulb >= 99.9) {
    2750            0 :                         DryBulb = state.dataWeather->wvarsMissing.OutDryBulbTemp;
    2751            0 :                         ++state.dataWeather->wvarsMissedCounts.OutDryBulbTemp;
    2752              :                     }
    2753        18120 :                     if (DryBulb < -90.0 || DryBulb > 70.0) {
    2754            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp;
    2755              :                     }
    2756              : 
    2757        18120 :                     if (DewPoint >= 99.9) {
    2758            0 :                         DewPoint = state.dataWeather->wvarsMissing.OutDewPointTemp;
    2759            0 :                         ++state.dataWeather->wvarsMissedCounts.OutDewPointTemp;
    2760              :                     }
    2761        18120 :                     if (DewPoint < -90.0 || DewPoint > 70.0) {
    2762            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp;
    2763              :                     }
    2764              : 
    2765        18120 :                     if (RelHum >= 999.0) {
    2766            0 :                         RelHum = state.dataWeather->wvarsMissing.OutRelHum;
    2767            0 :                         ++state.dataWeather->wvarsMissedCounts.OutRelHum;
    2768              :                     }
    2769        18120 :                     if (RelHum < 0.0 || RelHum > 110.0) {
    2770            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutRelHum;
    2771              :                     }
    2772              : 
    2773        18120 :                     if (AtmPress >= 999999.0) {
    2774            0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2775            0 :                         ++state.dataWeather->wvarsMissedCounts.OutBaroPress;
    2776              :                     }
    2777        18120 :                     if (AtmPress <= 31000.0 || AtmPress > 120000.0) {
    2778            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress;
    2779            0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2780              :                     }
    2781              : 
    2782        18120 :                     if (WindDir >= 999.0) {
    2783            0 :                         WindDir = state.dataWeather->wvarsMissing.WindDir;
    2784            0 :                         ++state.dataWeather->wvarsMissedCounts.WindDir;
    2785              :                     }
    2786        18120 :                     if (WindDir < 0.0 || WindDir > 360.0) {
    2787            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindDir;
    2788              :                     }
    2789              : 
    2790        18120 :                     if (WindSpeed >= 999.0) {
    2791            0 :                         WindSpeed = state.dataWeather->wvarsMissing.WindSpeed;
    2792            0 :                         ++state.dataWeather->wvarsMissedCounts.WindSpeed;
    2793              :                     }
    2794        18120 :                     if (WindSpeed < 0.0 || WindSpeed > 40.0) {
    2795            0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindSpeed;
    2796              :                     }
    2797              : 
    2798        18120 :                     if (TotalSkyCover >= 99.0) {
    2799            0 :                         TotalSkyCover = state.dataWeather->wvarsMissing.TotalSkyCover;
    2800            0 :                         ++state.dataWeather->wvarsMissedCounts.TotalSkyCover;
    2801              :                     }
    2802              : 
    2803        18120 :                     if (OpaqueSkyCover >= 99.0) {
    2804            0 :                         OpaqueSkyCover = state.dataWeather->wvarsMissing.OpaqueSkyCover;
    2805            0 :                         ++state.dataWeather->wvarsMissedCounts.OpaqueSkyCover;
    2806              :                     }
    2807              : 
    2808        18120 :                     if (SnowDepth >= 999.0) {
    2809            0 :                         SnowDepth = state.dataWeather->wvarsMissing.SnowDepth;
    2810            0 :                         ++state.dataWeather->wvarsMissedCounts.SnowDepth;
    2811              :                     }
    2812              : 
    2813        18120 :                     if (Albedo >= 999.0) {
    2814        16608 :                         Albedo = state.dataWeather->wvarsMissing.Albedo;
    2815        16608 :                         ++state.dataWeather->wvarsMissedCounts.Albedo;
    2816              :                     }
    2817              : 
    2818        18120 :                     if (LiquidPrecip >= 999.0) {
    2819        16641 :                         LiquidPrecip = state.dataWeather->wvarsMissing.LiquidPrecip;
    2820        16641 :                         ++state.dataWeather->wvarsMissedCounts.LiquidPrecip;
    2821              :                     }
    2822              : 
    2823        18120 :                     auto &tomorrow = state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour);
    2824        18120 :                     tomorrow.OutDryBulbTemp = DryBulb;
    2825        18120 :                     tomorrow.OutDewPointTemp = DewPoint;
    2826        18120 :                     tomorrow.OutBaroPress = AtmPress;
    2827        18120 :                     tomorrow.OutRelHum = RelHum;
    2828        18120 :                     RelHum *= 0.01;
    2829        18120 :                     tomorrow.WindSpeed = WindSpeed;
    2830        18120 :                     tomorrow.WindDir = WindDir;
    2831        18120 :                     tomorrow.LiquidPrecip = LiquidPrecip;
    2832        18120 :                     tomorrow.TotalSkyCover = TotalSkyCover;
    2833        18120 :                     tomorrow.OpaqueSkyCover = OpaqueSkyCover;
    2834              : 
    2835        18120 :                     calcSky(state, tomorrow.HorizIRSky, tomorrow.SkyTemp, OpaqueSkyCover, DryBulb, DewPoint, RelHum, IRHoriz);
    2836              : 
    2837        18120 :                     if (ETHoriz >= 9999.0) ETHoriz = 0.0;
    2838        18120 :                     if (ETDirect >= 9999.0) ETDirect = 0.0;
    2839        18120 :                     if (GLBHoriz >= 9999.0) GLBHoriz = 0.0;
    2840        18120 :                     if (DirectRad >= 9999.0) DirectRad = 0.0;
    2841        18120 :                     if (DiffuseRad >= 9999.0) DiffuseRad = 0.0;
    2842        18120 :                     if (GLBHorizIllum >= 999900.0) GLBHorizIllum = 0.0;
    2843        18120 :                     if (DirectNrmIllum >= 999900.0) DirectNrmIllum = 0.0;
    2844        18120 :                     if (DiffuseHorizIllum >= 999900.0) DiffuseHorizIllum = 0.0;
    2845        18120 :                     if (ZenLum >= 99990.0) ZenLum = 0.0;
    2846        18120 :                     if (state.dataEnvrn->IgnoreSolarRadiation) {
    2847            0 :                         GLBHoriz = 0.0;
    2848            0 :                         DirectRad = 0.0;
    2849            0 :                         DiffuseRad = 0.0;
    2850              :                     }
    2851        18120 :                     if (state.dataEnvrn->IgnoreBeamRadiation) {
    2852            0 :                         DirectRad = 0.0;
    2853              :                     }
    2854        18120 :                     if (state.dataEnvrn->IgnoreDiffuseRadiation) {
    2855            0 :                         DiffuseRad = 0.0;
    2856              :                     }
    2857              : 
    2858        18120 :                     tomorrow.BeamSolarRad = DirectRad;
    2859        18120 :                     tomorrow.DifSolarRad = DiffuseRad;
    2860              : 
    2861        18120 :                     tomorrow.IsRain = false;
    2862        18120 :                     if (PresWeathObs == 0) {
    2863            0 :                         if (PresWeathConds(1) < 9 || PresWeathConds(2) < 9 || PresWeathConds(3) < 9) tomorrow.IsRain = true;
    2864              :                     } else {
    2865        18120 :                         tomorrow.IsRain = false;
    2866              :                     }
    2867        18120 :                     tomorrow.IsSnow = (SnowDepth > 0.0);
    2868              : 
    2869              :                     // default if rain but none on weather file
    2870        18120 :                     if (tomorrow.IsRain && tomorrow.LiquidPrecip == 0.0) tomorrow.LiquidPrecip = 2.0; // 2mm in an hour ~ .08 inch
    2871              : 
    2872        18120 :                     state.dataWeather->wvarsMissing.OutDryBulbTemp = DryBulb;
    2873        18120 :                     state.dataWeather->wvarsMissing.OutDewPointTemp = DewPoint;
    2874        18120 :                     state.dataWeather->wvarsMissing.OutRelHum = static_cast<int>(std::round(RelHum * 100.0));
    2875        18120 :                     state.dataWeather->wvarsMissing.OutBaroPress = AtmPress;
    2876        18120 :                     state.dataWeather->wvarsMissing.WindDir = WindDir;
    2877        18120 :                     state.dataWeather->wvarsMissing.WindSpeed = WindSpeed;
    2878        18120 :                     state.dataWeather->wvarsMissing.TotalSkyCover = TotalSkyCover;
    2879        18120 :                     state.dataWeather->wvarsMissing.OpaqueSkyCover = OpaqueSkyCover;
    2880        18120 :                     state.dataWeather->wvarsMissing.Visibility = Visibility;
    2881        18120 :                     state.dataWeather->wvarsMissing.Ceiling = CeilHeight;
    2882        18120 :                     state.dataWeather->wvarsMissing.WaterPrecip = PrecipWater;
    2883        18120 :                     state.dataWeather->wvarsMissing.AerOptDepth = AerosolOptDepth;
    2884        18120 :                     state.dataWeather->wvarsMissing.SnowDepth = SnowDepth;
    2885        18120 :                     state.dataWeather->wvarsMissing.DaysLastSnow = DaysSinceLastSnow;
    2886        18120 :                     state.dataWeather->wvarsMissing.Albedo = Albedo;
    2887              : 
    2888        18120 :                 } // for (CurTimeStep)
    2889              : 
    2890              :             } // for (Hour)
    2891              : 
    2892              :         } // Try Again While Loop
    2893              : 
    2894          755 :         if (BackSpaceAfterRead) {
    2895            4 :             state.files.inputWeatherFile.backspace();
    2896              :         }
    2897              : 
    2898          755 :         if (state.dataWeather->NumIntervalsPerHour == 1 && state.dataGlobal->TimeStepsInHour > 1) {
    2899              :             // Create interpolated weather for timestep orientation
    2900              :             // First copy ts=1 (hourly) from data arrays to Wthr structure
    2901        18850 :             for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    2902        18096 :                 wvarsHr(hour) = state.dataWeather->wvarsHrTsTomorrow(1, hour);
    2903              :             }
    2904              : 
    2905          754 :             if (!state.dataWeather->LastHourSet) {
    2906              :                 // For first day of weather, all time steps of the first hour will be
    2907              :                 // equal to the first hour's value.
    2908              :                 // 2021-06: An additional input is added to here to allow the user to have chosen which hour to use
    2909           27 :                 int HrUsedtoInterp = thisEnviron.firstHrInterpUseHr1 ? 1 : 24;
    2910           27 :                 state.dataWeather->wvarsLastHr = wvarsHr(HrUsedtoInterp);
    2911           27 :                 state.dataWeather->LastHourSet = true;
    2912              :             }
    2913              : 
    2914        18850 :             for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    2915              : 
    2916        18096 :                 int NextHr = (hour == Constant::iHoursInDay) ? 1 : hour + 1;
    2917              : 
    2918        18096 :                 state.dataWeather->wvarsNextHr.BeamSolarRad = wvarsHr(NextHr).BeamSolarRad;
    2919        18096 :                 state.dataWeather->wvarsNextHr.DifSolarRad = wvarsHr(NextHr).DifSolarRad;
    2920        18096 :                 state.dataWeather->wvarsNextHr.LiquidPrecip = wvarsHr(NextHr).LiquidPrecip;
    2921              : 
    2922        90480 :                 for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    2923              : 
    2924        72384 :                     Real64 wgtCurrHr = state.dataWeather->Interpolation(ts);
    2925        72384 :                     Real64 wgtPrevHr = 1.0 - wgtCurrHr;
    2926              : 
    2927              :                     // Do Solar "weighting"
    2928              : 
    2929        72384 :                     Real64 wgtCurrHrSolar = state.dataWeather->SolarInterpolation(ts);
    2930              :                     Real64 wgtPrevHrSolar;
    2931              :                     Real64 wgtNextHrSolar;
    2932              : 
    2933        72384 :                     if (state.dataGlobal->TimeStepsInHour == 1) {
    2934            0 :                         wgtNextHrSolar = 1.0 - wgtCurrHr;
    2935            0 :                         wgtPrevHrSolar = 0.0;
    2936        72384 :                     } else if (wgtCurrHrSolar == 1.0) {
    2937              :                         //  It's at the half hour
    2938        18096 :                         wgtPrevHrSolar = 0.0;
    2939        18096 :                         wgtNextHrSolar = 0.0;
    2940        54288 :                     } else if (ts * state.dataWeather->TimeStepFraction < 0.5) {
    2941        18096 :                         wgtPrevHrSolar = 1.0 - wgtCurrHrSolar;
    2942        18096 :                         wgtNextHrSolar = 0.0;
    2943              :                     } else { // After the half hour
    2944        36192 :                         wgtPrevHrSolar = 0.0;
    2945        36192 :                         wgtNextHrSolar = 1.0 - wgtCurrHrSolar;
    2946              :                     }
    2947              : 
    2948        72384 :                     auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    2949        72384 :                     auto const &wvarsH = wvarsHr(hour);
    2950        72384 :                     tomorrowTs.OutDryBulbTemp = state.dataWeather->wvarsLastHr.OutDryBulbTemp * wgtPrevHr + wvarsH.OutDryBulbTemp * wgtCurrHr;
    2951        72384 :                     tomorrowTs.OutBaroPress = state.dataWeather->wvarsLastHr.OutBaroPress * wgtPrevHr + wvarsH.OutBaroPress * wgtCurrHr;
    2952        72384 :                     tomorrowTs.OutDewPointTemp = state.dataWeather->wvarsLastHr.OutDewPointTemp * wgtPrevHr + wvarsH.OutDewPointTemp * wgtCurrHr;
    2953        72384 :                     tomorrowTs.OutRelHum = state.dataWeather->wvarsLastHr.OutRelHum * wgtPrevHr + wvarsH.OutRelHum * wgtCurrHr;
    2954        72384 :                     tomorrowTs.WindSpeed = state.dataWeather->wvarsLastHr.WindSpeed * wgtPrevHr + wvarsH.WindSpeed * wgtCurrHr;
    2955        72384 :                     tomorrowTs.WindDir = interpolateWindDirection(state.dataWeather->wvarsLastHr.WindDir, wvarsH.WindDir, wgtCurrHr);
    2956        72384 :                     tomorrowTs.TotalSkyCover = state.dataWeather->wvarsLastHr.TotalSkyCover * wgtPrevHr + wvarsH.TotalSkyCover * wgtCurrHr;
    2957        72384 :                     tomorrowTs.OpaqueSkyCover = state.dataWeather->wvarsLastHr.OpaqueSkyCover * wgtPrevHr + wvarsH.OpaqueSkyCover * wgtCurrHr;
    2958              :                     // Sky emissivity now takes interpolated timestep inputs rather than interpolated calculation esky results
    2959        72384 :                     calcSky(state,
    2960        72384 :                             tomorrowTs.HorizIRSky,
    2961        72384 :                             tomorrowTs.SkyTemp,
    2962              :                             tomorrowTs.OpaqueSkyCover,
    2963              :                             tomorrowTs.OutDryBulbTemp,
    2964              :                             tomorrowTs.OutDewPointTemp,
    2965        72384 :                             tomorrowTs.OutRelHum * 0.01,
    2966        72384 :                             state.dataWeather->wvarsLastHr.HorizIRSky * wgtPrevHr + wvarsH.HorizIRSky * wgtCurrHr);
    2967              : 
    2968        72384 :                     tomorrowTs.DifSolarRad = state.dataWeather->wvarsLastHr.DifSolarRad * wgtPrevHrSolar + wvarsH.DifSolarRad * wgtCurrHrSolar +
    2969        72384 :                                              state.dataWeather->wvarsNextHr.DifSolarRad * wgtNextHrSolar;
    2970        72384 :                     tomorrowTs.BeamSolarRad = state.dataWeather->wvarsLastHr.BeamSolarRad * wgtPrevHrSolar + wvarsH.BeamSolarRad * wgtCurrHrSolar +
    2971        72384 :                                               state.dataWeather->wvarsNextHr.BeamSolarRad * wgtNextHrSolar;
    2972              : 
    2973        72384 :                     tomorrowTs.LiquidPrecip = state.dataWeather->wvarsLastHr.LiquidPrecip * wgtPrevHr + wvarsH.LiquidPrecip * wgtCurrHr;
    2974        72384 :                     tomorrowTs.LiquidPrecip /= double(state.dataGlobal->TimeStepsInHour);
    2975        72384 :                     tomorrowTs.IsRain = tomorrowTs.LiquidPrecip >= state.dataWeather->IsRainThreshold; // Wthr%IsRain
    2976        72384 :                     tomorrowTs.IsSnow = wvarsH.IsSnow;
    2977              :                 } // End of TS Loop
    2978              : 
    2979        18096 :                 state.dataWeather->wvarsLastHr = wvarsHr(hour);
    2980              :             } // End of Hour Loop
    2981              :         }
    2982              : 
    2983          755 :         if (thisEnviron.WP_Type1 != 0) {
    2984            0 :             switch (state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).skyTempModel) {
    2985            0 :             case SkyTempModel::ScheduleValue: {
    2986              :                 std::vector<Real64> const &dayVals =
    2987            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    2988            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    2989              : 
    2990            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    2991            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    2992            0 :                         state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    2993              :                     }
    2994              :                 }
    2995            0 :             } break;
    2996              : 
    2997            0 :             case SkyTempModel::DryBulbDelta: {
    2998              :                 std::vector<Real64> const &dayVals =
    2999            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    3000            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    3001              : 
    3002            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3003            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3004            0 :                         auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3005            0 :                         tomorrowTs.SkyTemp = tomorrowTs.OutDryBulbTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3006              :                     }
    3007              :                 }
    3008            0 :             } break;
    3009              : 
    3010            0 :             case SkyTempModel::DewPointDelta: {
    3011              :                 std::vector<Real64> const &dayVals =
    3012            0 :                     state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1)
    3013            0 :                         .sched->getDayVals(state, state.dataWeather->TomorrowVariables.DayOfYear_Schedule, state.dataWeather->CurDayOfWeek);
    3014              : 
    3015            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3016            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3017            0 :                         auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3018            0 :                         tomorrowTs.SkyTemp = tomorrowTs.OutDewPointTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3019              :                     }
    3020              :                 }
    3021            0 :             } break;
    3022              : 
    3023            0 :             default:
    3024            0 :                 break;
    3025              :             }
    3026              :         }
    3027          755 :     }
    3028              : 
    3029        72433 :     Real64 interpolateWindDirection(Real64 const prevHrWindDir, Real64 const curHrWindDir, Real64 const curHrWeight)
    3030              :     {
    3031              :         // adapted from http://stackoverflow.com/questions/2708476/rotation-interpolation
    3032        72433 :         Real64 curAng = curHrWindDir;
    3033        72433 :         Real64 prevAng = prevHrWindDir;
    3034        72433 :         Real64 diff = std::abs(curAng - prevAng);
    3035        72433 :         if (diff > 180.) {
    3036         4148 :             if (curAng > prevAng) {
    3037         1792 :                 prevAng += 360.;
    3038              :             } else {
    3039         2356 :                 curAng += 360.;
    3040              :             }
    3041              :         }
    3042        72433 :         Real64 interpAng = prevAng + (curAng - prevAng) * curHrWeight;
    3043        72433 :         return (fmod(interpAng, 360.)); // fmod is float modulus function
    3044              :     }
    3045              : 
    3046        68408 :     Real64 CalcSkyEmissivity(
    3047              :         EnergyPlusData &state, SkyTempModel const ESkyCalcType, Real64 const OSky, Real64 const DryBulb, Real64 const DewPoint, Real64 const RelHum)
    3048              :     {
    3049              :         // Calculate Sky Emissivity
    3050              :         // References:
    3051              :         // M. Li, Y. Jiang and C. F. M. Coimbra,
    3052              :         // "On the determination of atmospheric longwave irradiance under all-sky conditions,"
    3053              :         // Solar Energy 144, 2017, pp. 40–48,
    3054              :         // G. Clark and C. Allen, "The Estimation of Atmospheric Radiation for Clear and
    3055              :         // Cloudy Skies," Proc. 2nd National Passive Solar Conference (AS/ISES), 1978, pp. 675-678.
    3056              : 
    3057              :         Real64 ESky;
    3058              : 
    3059        68408 :         if (ESkyCalcType == SkyTempModel::Brunt) {
    3060            2 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3061            2 :             ESky = 0.618 + 0.056 * pow(PartialPress, 0.5);
    3062        68406 :         } else if (ESkyCalcType == SkyTempModel::Idso) {
    3063            2 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3064            2 :             ESky = 0.685 + 0.000032 * PartialPress * exp(1699 / (DryBulb + Constant::Kelvin));
    3065        68404 :         } else if (ESkyCalcType == SkyTempModel::BerdahlMartin) {
    3066            2 :             double const TDewC = min(DryBulb, DewPoint);
    3067            2 :             ESky = 0.758 + 0.521 * (TDewC / 100) + 0.625 * pow_2(TDewC / 100);
    3068              :         } else {
    3069        68402 :             ESky = 0.787 + 0.764 * std::log((min(DryBulb, DewPoint) + Constant::Kelvin) / Constant::Kelvin);
    3070              :         }
    3071        68408 :         return ESky * (1.0 + 0.0224 * OSky - 0.0035 * pow_2(OSky) + 0.00028 * pow_3(OSky));
    3072              :     }
    3073              : 
    3074           27 :     void SetDayOfWeekInitialValues(int const EnvironDayOfWeek, // Starting Day of Week for the (Weather) RunPeriod (User Input)
    3075              :                                    int &currentDayOfWeek       // Current Day of Week
    3076              :     )
    3077              :     {
    3078              : 
    3079              :         // SUBROUTINE INFORMATION:
    3080              :         //       AUTHOR         Linda Lawrie
    3081              :         //       DATE WRITTEN   March 2012
    3082              : 
    3083              :         // PURPOSE OF THIS SUBROUTINE:
    3084              :         // Set of begin day of week for an environment.  Similar sets but slightly different
    3085              :         // conditions.  Improve code readability by having three routine calls instead of three
    3086              :         // IF blocks.
    3087              : 
    3088           27 :         if (EnvironDayOfWeek != 0) {
    3089           27 :             if (EnvironDayOfWeek <= 7) {
    3090           27 :                 currentDayOfWeek = EnvironDayOfWeek - 1;
    3091              :             } else {
    3092            0 :                 currentDayOfWeek = EnvironDayOfWeek;
    3093              :             }
    3094              :         }
    3095           27 :     }
    3096              : 
    3097            0 :     void ErrorInterpretWeatherDataLine(EnergyPlusData &state,
    3098              :                                        int const WYear,
    3099              :                                        int const WMonth,
    3100              :                                        int const WDay,
    3101              :                                        int const WHour,
    3102              :                                        int const WMinute,
    3103              :                                        std::string_view SaveLine,
    3104              :                                        std::string_view Line)
    3105              :     {
    3106            0 :         ShowSevereError(state, fmt::format("Invalid Weather Line at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3107            0 :         ShowContinueError(state, fmt::format("Full Data Line={}", SaveLine));
    3108            0 :         ShowContinueError(state, fmt::format("Remainder of line={}", Line));
    3109            0 :         ShowFatalError(state, "Error in Reading Weather Data");
    3110            0 :     }
    3111              : 
    3112        27632 :     void InterpretWeatherDataLine(EnergyPlusData &state,
    3113              :                                   std::string_view Line,
    3114              :                                   bool &ErrorFound, // True if an error is found, false otherwise
    3115              :                                   int &WYear,
    3116              :                                   int &WMonth,
    3117              :                                   int &WDay,
    3118              :                                   int &WHour,
    3119              :                                   int &WMinute,
    3120              :                                   Real64 &DryBulb,
    3121              :                                   Real64 &DewPoint,
    3122              :                                   Real64 &RelHum,
    3123              :                                   Real64 &AtmPress,
    3124              :                                   Real64 &ETHoriz,
    3125              :                                   Real64 &ETDirect,
    3126              :                                   Real64 &IRHoriz,
    3127              :                                   Real64 &GLBHoriz,
    3128              :                                   Real64 &DirectRad,
    3129              :                                   Real64 &DiffuseRad,
    3130              :                                   Real64 &GLBHorizIllum,
    3131              :                                   Real64 &DirectNrmIllum,
    3132              :                                   Real64 &DiffuseHorizIllum,
    3133              :                                   Real64 &ZenLum,
    3134              :                                   Real64 &WindDir,
    3135              :                                   Real64 &WindSpeed,
    3136              :                                   Real64 &TotalSkyCover,
    3137              :                                   Real64 &OpaqueSkyCover,
    3138              :                                   Real64 &Visibility,
    3139              :                                   Real64 &CeilHeight,
    3140              :                                   int &WObs,              // PresWeathObs
    3141              :                                   Array1D_int &WCodesArr, // PresWeathConds
    3142              :                                   Real64 &PrecipWater,
    3143              :                                   Real64 &AerosolOptDepth,
    3144              :                                   Real64 &SnowDepth,
    3145              :                                   Real64 &DaysSinceLastSnow,
    3146              :                                   Real64 &Albedo,
    3147              :                                   Real64 &LiquidPrecip)
    3148              :     {
    3149              : 
    3150              :         // SUBROUTINE INFORMATION:
    3151              :         //       AUTHOR         Linda Lawrie
    3152              :         //       DATE WRITTEN   April 2001
    3153              : 
    3154              :         // PURPOSE OF THIS SUBROUTINE:
    3155              :         // This subroutine interprets the EPW weather data line because comma delimited fields
    3156              :         // may cause problems with some compilers.  (Particularly character variables in
    3157              :         // comma delimited lines.
    3158              : 
    3159              :         // METHODOLOGY EMPLOYED:
    3160              :         // Field by field interpretation, eliminating the "data source field" which is also
    3161              :         // likely to contain blanks.  Note that the "Weatherconditions" must be a 9 character
    3162              :         // alpha field with no intervening blanks.
    3163              : 
    3164        27632 :         EP_SIZE_CHECK(WCodesArr, 9); // NOLINT(misc-static-assert)
    3165              : 
    3166              :         static constexpr std::string_view ValidDigits("0123456789");
    3167              : 
    3168        27632 :         std::string_view::size_type pos = 0;
    3169        27632 :         std::string_view current_line = Line;
    3170              : 
    3171        27632 :         ErrorFound = false;
    3172              : 
    3173              :         // Do the first five.  (To get to the DataSource field)
    3174              :         {
    3175        27632 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 5); // Returns the position **after** the nth occurrence of ','
    3176        27632 :             const bool succeeded = readList(current_line.substr(pos, (nth_pos - 1) - pos), WYear, WMonth, WDay, WHour, WMinute);
    3177        27632 :             if (!succeeded) {
    3178            0 :                 ShowSevereError(state, "Invalid Date info in Weather Line");
    3179            0 :                 ShowContinueError(state, fmt::format("Entire Data Line={}", Line));
    3180            0 :                 ShowFatalError(state, "Error in Reading Weather Data");
    3181              :             }
    3182              :         }
    3183              : 
    3184        27632 :         bool DateInError = false;
    3185        27632 :         if (WMonth >= 1 && WMonth <= 12) {
    3186              :             // Month number is valid
    3187        27632 :             if (WMonth != 2) {
    3188        25560 :                 if (WDay > state.dataWeather->EndDayOfMonth(WMonth)) {
    3189            0 :                     DateInError = true;
    3190              :                 }
    3191         2072 :             } else if (WDay > state.dataWeather->EndDayOfMonth(WMonth) + 1) { // Whether actually used is determined by calling routine.
    3192            0 :                 DateInError = true;
    3193              :             }
    3194              :         } else {
    3195            0 :             DateInError = true;
    3196              :         }
    3197              : 
    3198        27632 :         if (DateInError) {
    3199            0 :             ShowSevereError(state, format("Reading Weather Data Line, Invalid Date, Year={}, Month={}, Day={}", WYear, WMonth, WDay));
    3200            0 :             ShowFatalError(state, "Program terminates due to previous condition.");
    3201              :         }
    3202              : 
    3203              :         // index, unlike nth_occurrence returns the position of the search char, not the position after it
    3204        27632 :         pos = index(Line, ','); // WYear
    3205        27632 :         if (pos == std::string::npos) {
    3206            0 :             ShowSevereError(
    3207            0 :                 state, format("Invalid Weather Line (no commas) at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3208            0 :             ShowContinueError(state, fmt::format("Full Data Line={}", Line));
    3209            0 :             ShowFatalError(state, "Error in Reading Weather Data");
    3210              :         }
    3211        27632 :         current_line.remove_prefix(nth_occurrence(Line, ',', 6)); // remove WYear,WMonth,WDay,WHour,WMinute,Data Source/Integrity
    3212              : 
    3213              :         // Now read more numerics with List Directed I/O (note there is another "character" field lurking)
    3214              :         Real64 RField21;
    3215              :         {
    3216        27632 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 21);
    3217              : 
    3218        27632 :             const bool succeeded = readList(current_line.substr(0, nth_pos - 1),
    3219              :                                             DryBulb,
    3220              :                                             DewPoint,
    3221              :                                             RelHum,
    3222              :                                             AtmPress,
    3223              :                                             ETHoriz,
    3224              :                                             ETDirect,
    3225              :                                             IRHoriz,
    3226              :                                             GLBHoriz,
    3227              :                                             DirectRad,
    3228              :                                             DiffuseRad,
    3229              :                                             GLBHorizIllum,
    3230              :                                             DirectNrmIllum,
    3231              :                                             DiffuseHorizIllum,
    3232              :                                             ZenLum,
    3233              :                                             WindDir,
    3234              :                                             WindSpeed,
    3235              :                                             TotalSkyCover,
    3236              :                                             OpaqueSkyCover,
    3237              :                                             Visibility,
    3238              :                                             CeilHeight,
    3239              :                                             RField21);
    3240              : 
    3241        27632 :             if (!succeeded) ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3242        27632 :             current_line.remove_prefix(nth_pos);
    3243              :         }
    3244        27632 :         pos = index(current_line, ',');
    3245        27632 :         std::string PresWeathCodes;
    3246        27632 :         if (pos != std::string::npos && pos != 0) {
    3247        27632 :             PresWeathCodes = current_line.substr(0, pos);
    3248              :         } else {
    3249            0 :             PresWeathCodes = "999999999";
    3250              :         }
    3251        27632 :         current_line.remove_prefix(pos + 1);
    3252              : 
    3253        27632 :         auto readNextNumber = // (AUTO_OK_LAMBDA)
    3254       165792 :             [reachedEndOfCommands = false, &state, &WYear, &WMonth, &WDay, &WHour, &WMinute, &Line, &current_line]() mutable -> Real64 {
    3255       165792 :             if (reachedEndOfCommands) {
    3256            4 :                 return 999.0;
    3257              :             }
    3258              :             Real64 target;
    3259       165788 :             std::string_view::size_type pos = index(current_line, ',');
    3260              :             // We found a comma
    3261       165788 :             if (pos != std::string::npos) {
    3262              :                 // Content is not empty
    3263       165787 :                 if (pos != 0) {
    3264       165787 :                     bool error = false;
    3265       165787 :                     target = Util::ProcessNumber(current_line.substr(0, pos), error);
    3266       165787 :                     if (error) {
    3267            0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3268              :                     }
    3269              :                 } else {
    3270            0 :                     target = 999.0;
    3271              :                 }
    3272       165787 :                 current_line.remove_prefix(pos + 1);
    3273              :             } else {
    3274              :                 // Couldn't find next comma, but we need to process the potential current number
    3275            1 :                 reachedEndOfCommands = true;
    3276            1 :                 if (current_line.empty()) {
    3277            0 :                     target = 999.0;
    3278              :                 } else {
    3279            1 :                     bool error = false;
    3280            1 :                     target = Util::ProcessNumber(current_line, error);
    3281            1 :                     if (error) {
    3282            0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3283              :                     }
    3284              :                 }
    3285              :             }
    3286       165788 :             return target;
    3287        27632 :         };
    3288              : 
    3289        27632 :         PrecipWater = readNextNumber();
    3290        27632 :         AerosolOptDepth = readNextNumber();
    3291        27632 :         SnowDepth = readNextNumber();
    3292        27632 :         DaysSinceLastSnow = readNextNumber();
    3293        27632 :         Albedo = readNextNumber();
    3294        27632 :         LiquidPrecip = readNextNumber();
    3295              : 
    3296        27632 :         WObs = nint(RField21);
    3297        27632 :         if (WObs == 0) { // Obs Indicator indicates Weather Codes valid
    3298              :             // Check for miscellaneous characters
    3299            2 :             pos = index(PresWeathCodes, '\'');
    3300            2 :             while (pos != std::string::npos) {
    3301            0 :                 PresWeathCodes[pos] = ' ';
    3302            0 :                 pos = index(PresWeathCodes, '\'');
    3303              :             }
    3304            2 :             pos = index(PresWeathCodes, '"');
    3305            2 :             while (pos != std::string::npos) {
    3306            0 :                 PresWeathCodes[pos] = ' ';
    3307            0 :                 pos = index(PresWeathCodes, '"');
    3308              :             }
    3309            2 :             strip(PresWeathCodes);
    3310            2 :             if (len(PresWeathCodes) == 9) {
    3311           20 :                 for (pos = 0; pos < 9; ++pos) {
    3312           18 :                     if (!has(ValidDigits, PresWeathCodes[pos])) PresWeathCodes[pos] = '9';
    3313              :                 }
    3314              : 
    3315              :                 // we are trying to read a string of 9 integers with no spaces, each
    3316              :                 // into its own integer, like:
    3317              :                 // "123456789"
    3318              :                 // becomes
    3319              :                 // std::vector<int>{1,2,3,4,5,6,7,8,9};
    3320            2 :                 std::stringstream reader = stringReader(PresWeathCodes);
    3321           20 :                 for (auto &value : WCodesArr) {
    3322           18 :                     char c[2] = {0, 0};   // a string of 2 characters, init both to 0
    3323           18 :                     reader >> c[0];       // read next char into the first byte
    3324           18 :                     value = std::atoi(c); // convert this short string into the appropriate int to read
    3325              :                 }
    3326            2 :             } else {
    3327            0 :                 ++state.dataWeather->wvarsMissedCounts.WeathCodes;
    3328            0 :                 WCodesArr = 9;
    3329              :             }
    3330              :         } else {
    3331        27630 :             WCodesArr = 9;
    3332              :         }
    3333        27632 :     }
    3334              : 
    3335          517 :     void SetUpDesignDay(EnergyPlusData &state, int const EnvrnNum) // Environment number passed into the routine
    3336              :     {
    3337              : 
    3338              :         // SUBROUTINE INFORMATION:
    3339              :         //       AUTHOR         Linda Lawrie
    3340              :         //       DATE WRITTEN   February 1977
    3341              :         //       MODIFIED       June 1997 (RKS); May 2013 (LKL) add temperature profile for drybulb.
    3342              :         //       RE-ENGINEERED  August 2003;LKL -- to generate timestep weather for design days.
    3343              : 
    3344              :         // PURPOSE OF THIS SUBROUTINE:
    3345              :         // This purpose of this subroutine is to convert the user supplied input
    3346              :         // values for the design day parameters into an entire weather day
    3347              :         // record.  This now bypasses any file I/O by keeping all of the
    3348              :         // weather day record information in the local module level derived type
    3349              :         // called DesignDay.
    3350              : 
    3351          517 :         constexpr Real64 GlobalSolarConstant = 1367.0;
    3352          517 :         constexpr Real64 ZHGlobalSolarConstant = 1355.0;
    3353              : 
    3354          517 :         Real64 constexpr ZhangHuang_C0 = 0.5598;   // 37.6865d0
    3355          517 :         Real64 constexpr ZhangHuang_C1 = 0.4982;   // 13.9263d0
    3356          517 :         Real64 constexpr ZhangHuang_C2 = -0.6762;  // -20.2354d0
    3357          517 :         Real64 constexpr ZhangHuang_C3 = 0.02842;  // 0.9695d0
    3358          517 :         Real64 constexpr ZhangHuang_C4 = -0.00317; // -0.2046d0
    3359          517 :         Real64 constexpr ZhangHuang_C5 = 0.014;    // -0.0980d0
    3360          517 :         Real64 constexpr ZhangHuang_D = -17.853;   // -10.8568d0
    3361          517 :         Real64 constexpr ZhangHuang_K = 0.843;     // 49.3112d0
    3362              :         static constexpr std::string_view RoutineNamePsyWFnTdbTwbPb("SetUpDesignDay:PsyWFnTdbTwbPb");
    3363              :         static constexpr std::string_view RoutineNamePsyWFnTdpPb("SetUpDesignDay:PsyWFnTdpPb");
    3364              :         static constexpr std::string_view RoutineNamePsyWFnTdbH("SetUpDesignDay:PsyWFnTdbH");
    3365              :         static constexpr std::string_view WeatherManager("WeatherManager");
    3366              :         static constexpr std::string_view RoutineNameLong("WeatherManager.cc subroutine SetUpDesignDay");
    3367              : 
    3368          517 :         std::string StringOut;
    3369              :         //     For reporting purposes, set year to current system year
    3370              : 
    3371              :         struct HourlyWeatherData
    3372              :         {
    3373              :             // Members
    3374              :             Array1D<Real64> BeamSolarRad = Array1D<Real64>(Constant::iHoursInDay, 0.0); // Hourly direct normal solar irradiance
    3375              :             Array1D<Real64> DifSolarRad = Array1D<Real64>(Constant::iHoursInDay, 0.0);  // Hourly sky diffuse horizontal solar irradiance
    3376              :         };
    3377              : 
    3378              :         // Object Data
    3379          517 :         HourlyWeatherData Wthr;
    3380              : 
    3381          517 :         auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    3382              : 
    3383          517 :         bool SaveWarmupFlag = state.dataGlobal->WarmupFlag;
    3384          517 :         state.dataGlobal->WarmupFlag = true;
    3385              : 
    3386          517 :         Array1D_int Date0(8);
    3387          517 :         date_and_time(_, _, _, Date0);
    3388          517 :         int CurrentYear = Date0(1);
    3389              : 
    3390          517 :         if (state.dataGlobal->BeginSimFlag) {
    3391          103 :             state.dataWeather->PrintDDHeader = true;
    3392              :         }
    3393              : 
    3394          517 :         auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    3395          517 :         auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    3396          517 :         designDay.Year = CurrentYear; // f90 date_and_time implemented. full 4 digit year !+ 1900
    3397          517 :         designDay.Month = desDayInput.Month;
    3398          517 :         designDay.DayOfMonth = desDayInput.DayOfMonth;
    3399          517 :         designDay.DayOfYear = General::OrdinalDay(designDay.Month, designDay.DayOfMonth, 0);
    3400              :         static constexpr std::string_view MnDyFmt("{:02}/{:02}");
    3401          517 :         state.dataEnvrn->CurMnDy = format(MnDyFmt, desDayInput.Month, desDayInput.DayOfMonth);
    3402              :         // EnvironmentName = DesDayInput( EnvrnNum ).Title;
    3403          517 :         state.dataEnvrn->RunPeriodEnvironment = false;
    3404              :         // Following builds Environment start/end for ASHRAE 55 warnings
    3405          517 :         state.dataEnvrn->EnvironmentStartEnd = state.dataEnvrn->CurMnDy + " - " + state.dataEnvrn->CurMnDy;
    3406              : 
    3407              :         // Check that barometric pressure is within range
    3408          517 :         if (desDayInput.PressureEntered) {
    3409          517 :             if (std::abs((desDayInput.PressBarom - state.dataEnvrn->StdBaroPress) / state.dataEnvrn->StdBaroPress) > 0.1) { // 10% off
    3410           68 :                 ShowWarningError(state,
    3411           68 :                                  format("SetUpDesignDay: Entered DesignDay Barometric Pressure={:.0R} differs by more than 10% from Standard "
    3412              :                                         "Barometric Pressure={:.0R}.",
    3413           34 :                                         desDayInput.PressBarom,
    3414           34 :                                         state.dataEnvrn->StdBaroPress));
    3415           68 :                 ShowContinueError(
    3416              :                     state,
    3417           68 :                     format("...occurs in DesignDay={}, Standard Pressure (based on elevation) will be used.", state.dataEnvrn->EnvironmentName));
    3418           34 :                 desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3419              :             }
    3420              :         } else {
    3421            0 :             desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3422              :         }
    3423              : 
    3424              :         // verify that design WB or DP <= design DB
    3425          517 :         if (desDayInput.HumIndType == DesDayHumIndType::DewPoint && desDayInput.DewPointNeedsSet) {
    3426              :             // dew-point
    3427            0 :             Real64 testval = Psychrometrics::PsyWFnTdbRhPb(state, desDayInput.MaxDryBulb, 1.0, desDayInput.PressBarom);
    3428            0 :             desDayInput.HumIndValue = Psychrometrics::PsyTdpFnWPb(state, testval, desDayInput.PressBarom);
    3429              :         }
    3430              : 
    3431              :         // Day of week defaults to Monday, if day type specified, then that is used.
    3432          517 :         designDay.DayOfWeek = 2;
    3433          517 :         if (desDayInput.DayType <= 7) designDay.DayOfWeek = desDayInput.DayType;
    3434              : 
    3435              :         // set Holiday as indicated by user input
    3436          517 :         designDay.HolidayIndex = 0;
    3437          517 :         if (desDayInput.DayType > 7) designDay.HolidayIndex = desDayInput.DayType;
    3438              : 
    3439          517 :         designDay.DaylightSavingIndex = desDayInput.DSTIndicator;
    3440              : 
    3441              :         //  Set up Solar parameters for day
    3442              :         Real64 A;    // Apparent solar irradiation at air mass = 0
    3443              :         Real64 B;    // Atmospheric extinction coefficient
    3444              :         Real64 C;    // ASHRAE diffuse radiation factor
    3445              :         Real64 AVSC; // Annual variation in the solar constant
    3446          517 :         CalculateDailySolarCoeffs(
    3447          517 :             state, designDay.DayOfYear, A, B, C, AVSC, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle);
    3448              : 
    3449          517 :         if (state.dataWeather->PrintDDHeader && state.dataReportFlag->DoWeatherInitReporting) {
    3450              :             static constexpr std::string_view EnvDDHdFormat(
    3451              :                 "! <Environment:Design Day Data>, Max Dry-Bulb Temp {C}, Temp Range {dC}, Temp Range Ind Type, "
    3452              :                 "Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units, Pressure {Pa}, Wind Direction {deg CW from N}, Wind "
    3453              :                 "Speed {m/s}, Clearness, Rain, Snow");
    3454           66 :             print(state.files.eio, "{}\n", EnvDDHdFormat);
    3455              :             static constexpr std::string_view DDayMiscHdFormat(
    3456              :                 "! <Environment:Design Day Misc>,DayOfYear,ASHRAE A Coeff,ASHRAE B Coeff,ASHRAE C Coeff,Solar "
    3457              :                 "Constant-Annual Variation,Eq of Time {minutes}, Solar Declination Angle {deg}, Solar Model");
    3458           66 :             print(state.files.eio, "{}\n", DDayMiscHdFormat);
    3459           66 :             state.dataWeather->PrintDDHeader = false;
    3460              :         }
    3461          517 :         if (state.dataReportFlag->DoWeatherInitReporting) {
    3462          113 :             std::string_view const AlpUseRain = (desDayInput.RainInd == 1) ? "Yes" : "No";
    3463          113 :             std::string_view const AlpUseSnow = (desDayInput.SnowInd == 1) ? "Yes" : "No";
    3464          113 :             print(state.files.eio, "Environment:Design Day Data,");
    3465          113 :             print(state.files.eio, "{:.2R},", desDayInput.MaxDryBulb);
    3466          113 :             print(state.files.eio, "{:.2R},", desDayInput.DailyDBRange);
    3467              : 
    3468              :             static constexpr std::array<std::string_view, (int)DesDayDryBulbRangeType::Num> DesDayDryBulbRangeTypeStrings = {
    3469              :                 "DefaultMultipliers,", "MultiplierSchedule,", "DifferenceSchedule,", "TemperatureProfile,"};
    3470              : 
    3471          113 :             print(state.files.eio, "{}", DesDayDryBulbRangeTypeStrings[(int)desDayInput.dryBulbRangeType]);
    3472              : 
    3473              :             static constexpr std::array<std::string_view, (int)DesDayHumIndType::Num> DesDayHumIndTypeStrings = {
    3474              :                 "Wetbulb,{:.2R},{{C}},",
    3475              :                 "Dewpoint,{:.2R},{{C}},",
    3476              :                 "Enthalpy,{:.2R},{{J/kgDryAir}},",
    3477              :                 "HumidityRatio,{:.4R},{{kgWater/kgDryAir}},",
    3478              :                 "Schedule,<schedule values from 0.0 to 100.0>,{{percent}},",
    3479              :                 "WetBulbProfileDefaultMultipliers,{:.2R},{{C}},",
    3480              :                 "WetBulbProfileDifferenceSchedule,{:.2R},{{C}},",
    3481              :                 "WetBulbProfileMultiplierSchedule,{:.2R},{{C}},"};
    3482              : 
    3483              :             // Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units
    3484          113 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    3485            0 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType]);
    3486          113 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    3487            0 :                 print(state.files.eio,
    3488            0 :                       DesDayHumIndTypeStrings[(int)desDayInput.HumIndType],
    3489            0 :                       state.dataWeather->DesDayInput(state.dataWeather->Envrn).HumIndValue);
    3490              :             } else {
    3491          113 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType], desDayInput.HumIndValue);
    3492              :             }
    3493              : 
    3494          113 :             print(state.files.eio, "{:.0R},", desDayInput.PressBarom);
    3495          113 :             print(state.files.eio, "{:.0R},", desDayInput.WindDir);
    3496          113 :             print(state.files.eio, "{:.1R},", desDayInput.WindSpeed);
    3497          113 :             print(state.files.eio, "{:.2R},", desDayInput.SkyClear);
    3498              : 
    3499          113 :             print(state.files.eio, "{},{}\n", AlpUseRain, AlpUseSnow);
    3500              : 
    3501              :             static constexpr std::string_view DDayMiscFormat("Environment:Design Day Misc,{:3},");
    3502          113 :             print(state.files.eio, DDayMiscFormat, designDay.DayOfYear);
    3503          113 :             print(state.files.eio, "{:.1R},", A);
    3504          113 :             print(state.files.eio, "{:.4R},", B);
    3505          113 :             print(state.files.eio, "{:.4R},", C);
    3506          113 :             print(state.files.eio, "{:.1R},", AVSC);
    3507          113 :             print(state.files.eio, "{:.2R},", designDay.EquationOfTime * 60.0);
    3508          113 :             print(state.files.eio, "{:.1R},", std::asin(designDay.SinSolarDeclinAngle) / Constant::DegToRad);
    3509              : 
    3510              :             // Why have a different string for "Schedule" here than the one used for input? Really, why?
    3511              :             static constexpr std::array<std::string_view, (int)DesDaySolarModel::Num> DesDaySolarModelStrings = {
    3512              :                 "ASHRAEClearSky", "ZhangHuang", "User supplied beam/diffuse from schedules", "ASHRAETau", "ASHRAETau2017"};
    3513              : 
    3514          113 :             print(state.files.eio, "{}\n", DesDaySolarModelStrings[(int)desDayInput.solarModel]);
    3515              :         }
    3516              : 
    3517              :         // Must set up weather values for Design Day.  User can specify the "humidity indicator" as
    3518              :         // Wetbulb, DewPoint or input the relative humidity schedule.  For both wetbulb and dewpoint indicators, the
    3519              :         // humidity for the day will be constant, using the drybulb (max) and humidity indicator temperature to
    3520              :         // set the values.  For the scheduled values, these are already set in the DDxxx array.
    3521              : 
    3522          517 :         state.dataGlobal->CurrentTime = 25.0;
    3523              :         Real64 HumidityRatio; // Humidity Ratio -- when constant for day
    3524              :         bool ConstantHumidityRatio;
    3525              : 
    3526          517 :         switch (desDayInput.HumIndType) {
    3527          514 :         case DesDayHumIndType::WetBulb: {
    3528          514 :             HumidityRatio = Psychrometrics::PsyWFnTdbTwbPb(
    3529              :                 state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdbTwbPb);
    3530          514 :             ConstantHumidityRatio = true;
    3531          514 :         } break;
    3532            0 :         case DesDayHumIndType::DewPoint: {
    3533            0 :             HumidityRatio = Psychrometrics::PsyWFnTdpPb(state, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdpPb);
    3534            0 :             ConstantHumidityRatio = true;
    3535            0 :         } break;
    3536            0 :         case DesDayHumIndType::HumRatio: {
    3537            0 :             HumidityRatio = desDayInput.HumIndValue;
    3538            0 :             ConstantHumidityRatio = true;
    3539            0 :         } break;
    3540            1 :         case DesDayHumIndType::Enthalpy: {
    3541              :             // HumIndValue is already in J/kg, so no conversions needed
    3542            1 :             HumidityRatio = Psychrometrics::PsyWFnTdbH(state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, RoutineNamePsyWFnTdbH);
    3543            1 :             ConstantHumidityRatio = true;
    3544            1 :         } break;
    3545            0 :         case DesDayHumIndType::RelHumSch: {
    3546              :             // nothing to do -- DDHumIndModifier already contains the scheduled Relative Humidity
    3547            0 :             ConstantHumidityRatio = false;
    3548            0 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr)
    3549            0 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts)
    3550            0 :                     state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).OutRelHum =
    3551            0 :                         state.dataWeather->desDayMods(EnvrnNum)(ts + 1, hr + 1).OutRelHum;
    3552            0 :         } break;
    3553            2 :         case DesDayHumIndType::WBProfDef:
    3554              :         case DesDayHumIndType::WBProfDif:
    3555              :         case DesDayHumIndType::WBProfMul: {
    3556            2 :             ConstantHumidityRatio = false;
    3557            2 :         } break;
    3558            0 :         default: {
    3559            0 :             ShowSevereError(state, "SetUpDesignDay: Invalid Humidity Indicator type");
    3560            0 :             ShowContinueError(state, format("Occurred in Design Day={}", desDayInput.Title));
    3561            0 :         } break;
    3562              :         } // switch
    3563              : 
    3564              :         int OSky; // Opaque Sky Cover (tenths)
    3565          517 :         if (desDayInput.RainInd != 0) {
    3566            0 :             OSky = 10;
    3567            0 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3568            0 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3569            0 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3570            0 :                     wvars.IsRain = true;
    3571            0 :                     wvars.LiquidPrecip = 3.0;
    3572              :                 }
    3573              :             }
    3574              :         } else {
    3575          517 :             OSky = 0;
    3576        12925 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3577        80424 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3578        68016 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3579        68016 :                     wvars.IsRain = false;
    3580        68016 :                     wvars.LiquidPrecip = 0.0;
    3581              :                 }
    3582              :             }
    3583              :         }
    3584              : 
    3585              :         Real64 GndReflet; // Ground Reflectivity
    3586          517 :         if (desDayInput.SnowInd == 0) {
    3587          517 :             GndReflet = 0.2;
    3588        12925 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3589        80424 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3590        68016 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3591        68016 :                     wvars.IsSnow = false;
    3592              :                 }
    3593              :             }
    3594              :         } else { // Snow
    3595            0 :             GndReflet = 0.7;
    3596            0 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3597            0 :                 for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3598            0 :                     auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3599            0 :                     wvars.IsSnow = true;
    3600              :                 }
    3601              :             }
    3602              :         }
    3603              : 
    3604              :         // Some values are constant
    3605              : 
    3606        12925 :         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3607        80424 :             for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3608        68016 :                 auto &wvars = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3609        68016 :                 wvars.OutBaroPress = desDayInput.PressBarom;
    3610        68016 :                 wvars.WindSpeed = desDayInput.WindSpeed;
    3611        68016 :                 wvars.WindDir = desDayInput.WindDir;
    3612        68016 :                 wvars.Albedo = 0.0;
    3613              :             }
    3614              :         }
    3615              : 
    3616              :         // resolve daily ranges
    3617              :         Real64 DBRange; // working copy of dry-bulb daily range, C (or 1 if input is difference)
    3618          517 :         if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    3619            0 :             DBRange = 1.0; // use unscaled multiplier values if difference
    3620          517 :         } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    3621            0 :             DBRange = 0.0;
    3622              :         } else {
    3623          517 :             DBRange = desDayInput.DailyDBRange;
    3624              :         }
    3625              :         Real64 WBRange; // working copy of wet-bulb daily range. C (or 1 if input is difference)
    3626          517 :         if (desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    3627            0 :             WBRange = 1.0; // use unscaled multiplier values if difference
    3628              :         } else {
    3629          517 :             WBRange = desDayInput.DailyWBRange;
    3630              :         }
    3631              : 
    3632          517 :         auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3633        12925 :         for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3634        80424 :             for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    3635        68016 :                 auto const &desDayModsTS = desDayModsEnvrn(ts, hour);
    3636        68016 :                 auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    3637        68016 :                 if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    3638              :                     // dry-bulb profile
    3639        68016 :                     tomorrowTs.OutDryBulbTemp = desDayInput.MaxDryBulb - desDayModsTS.OutDryBulbTemp * DBRange;
    3640              :                 } else { // DesDayInput(EnvrnNum)%DBTempRangeType == DesDayDryBulbRangeType::Profile
    3641            0 :                     tomorrowTs.OutDryBulbTemp = desDayModsTS.OutDryBulbTemp;
    3642              :                 }
    3643              : 
    3644              :                 // wet-bulb - generate from profile, humidity ratio, or dew point
    3645        68016 :                 if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    3646        67824 :                     desDayInput.HumIndType == DesDayHumIndType::WBProfMul) {
    3647          192 :                     Real64 WetBulb = desDayInput.HumIndValue - desDayModsTS.OutRelHum * WBRange;
    3648          192 :                     WetBulb = min(WetBulb, tomorrowTs.OutDryBulbTemp); // WB must be <= DB
    3649          192 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3650          192 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3651          192 :                     tomorrowTs.OutRelHum =
    3652          192 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3653        68016 :                 } else if (ConstantHumidityRatio) {
    3654              :                     //  Need Dew Point Temperature.  Use Relative Humidity to get Humidity Ratio, unless Humidity Ratio is constant
    3655              :                     // BG 9-26-07  moved following inside this IF statment; when HumIndType is 'Schedule' HumidityRatio wasn't being initialized
    3656              :                     Real64 WetBulb =
    3657        67824 :                         Psychrometrics::PsyTwbFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, RoutineNameLong);
    3658              : 
    3659        67824 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdpPb(state, tomorrowTs.OutDryBulbTemp, desDayInput.PressBarom);
    3660        67824 :                     if (HumidityRatio > OutHumRat) {
    3661        18445 :                         WetBulb = tomorrowTs.OutDryBulbTemp;
    3662              :                     } else {
    3663        49379 :                         OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3664              :                     }
    3665        67824 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3666        67824 :                     tomorrowTs.OutRelHum =
    3667        67824 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3668              :                 } else {
    3669              :                     HumidityRatio =
    3670            0 :                         Psychrometrics::PsyWFnTdbRhPb(state, tomorrowTs.OutDryBulbTemp, desDayModsTS.OutRelHum / 100.0, desDayInput.PressBarom);
    3671            0 :                     tomorrowTs.OutRelHum =
    3672            0 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, WeatherManager) *
    3673              :                         100.0;
    3674              :                     // TomorrowOutRelHum values set earlier
    3675            0 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, HumidityRatio, desDayInput.PressBarom);
    3676              :                 }
    3677              : 
    3678        68016 :                 double DryBulb = tomorrowTs.OutDryBulbTemp;
    3679        68016 :                 double RelHum = tomorrowTs.OutRelHum * 0.01;
    3680              :                 Real64 ESky =
    3681        68016 :                     CalcSkyEmissivity(state, envCurr.skyTempModel, OSky, DryBulb, tomorrowTs.OutDewPointTemp, RelHum); // Emissivitity of Sky
    3682        68016 :                 tomorrowTs.HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    3683              : 
    3684        68016 :                 if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    3685        68016 :                     envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    3686              :                     // Design day not scheduled
    3687        68016 :                     tomorrowTs.SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    3688              :                 }
    3689              :                 // Generate solar values for timestep
    3690              :                 //    working results = BeamRad and DiffRad
    3691              :                 //    stored to program globals at end of loop
    3692              :                 Real64 BeamRad;
    3693              :                 Real64 DiffRad;
    3694        68016 :                 if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    3695              :                     // scheduled: set value unconditionally (whether sun up or not)
    3696            0 :                     BeamRad = desDayModsTS.BeamSolarRad;
    3697            0 :                     DiffRad = desDayModsTS.DifSolarRad;
    3698              :                 } else {
    3699              : 
    3700              :                     // calc time = fractional hour of day
    3701              :                     Real64 CurTime;
    3702        68016 :                     if (state.dataGlobal->TimeStepsInHour != 1) {
    3703        67392 :                         CurTime = double(hour - 1) + double(ts) * state.dataWeather->TimeStepFraction;
    3704              :                     } else {
    3705          624 :                         CurTime = double(hour) + state.dataEnvrn->TS1TimeOffset;
    3706              :                     }
    3707              : 
    3708        68016 :                     Vector3<Real64> SUNCOS; // Sun direction cosines
    3709        68016 :                     CalculateSunDirectionCosines(
    3710              :                         state, CurTime, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle, SUNCOS);
    3711        68016 :                     Real64 CosZenith = SUNCOS.z; // Cosine of Zenith Angle of Sun
    3712        68016 :                     if (CosZenith < DataEnvironment::SunIsUpValue) {
    3713        34134 :                         BeamRad = 0.0;
    3714        34134 :                         DiffRad = 0.0;
    3715              :                     } else {
    3716        33882 :                         Real64 SinSolarAltitude = SUNCOS.z;
    3717              : 
    3718        33882 :                         switch (desDayInput.solarModel) {
    3719        31727 :                         case DesDaySolarModel::ASHRAE_ClearSky: {
    3720        31727 :                             Real64 Exponent = B / CosZenith;
    3721              :                             Real64 TotHoriz; // Total Radiation on Horizontal Surface
    3722        31727 :                             if (Exponent > 700.0) {
    3723            4 :                                 TotHoriz = 0.0;
    3724              :                             } else {
    3725        31723 :                                 TotHoriz = desDayInput.SkyClear * A * (C + CosZenith) * std::exp(-B / CosZenith);
    3726              :                             }
    3727              :                             // Radiation on an extraterrestial horizontal surface
    3728        31727 :                             Real64 HO = GlobalSolarConstant * AVSC * CosZenith;
    3729        31727 :                             Real64 KT = TotHoriz / HO; // Radiation ratio
    3730        31727 :                             KT = min(KT, 0.75);
    3731        31727 :                             DiffRad = TotHoriz * (1.0045 + KT * (0.04349 + KT * (-3.5227 + 2.6313 * KT)));
    3732        31727 :                             if (desDayInput.SkyClear > 0.70) DiffRad = TotHoriz * C / (C + CosZenith);
    3733        31727 :                             BeamRad = (TotHoriz - DiffRad) / CosZenith;
    3734        31727 :                             DiffRad = max(0.0, DiffRad);
    3735        31727 :                             BeamRad = max(0.0, BeamRad);
    3736              : 
    3737        31727 :                         } break;
    3738         2155 :                         case DesDaySolarModel::ASHRAE_Tau:
    3739              :                         case DesDaySolarModel::ASHRAE_Tau2017: {
    3740         2155 :                             Real64 ETR = GlobalSolarConstant * AVSC; // radiation of an extraterrestrial normal surface, W/m2
    3741              :                             Real64 GloHorzRad;
    3742         2155 :                             ASHRAETauModel(
    3743              :                                 state, desDayInput.solarModel, ETR, CosZenith, desDayInput.TauB, desDayInput.TauD, BeamRad, DiffRad, GloHorzRad);
    3744         2155 :                         } break;
    3745            0 :                         case DesDaySolarModel::Zhang_Huang: {
    3746            0 :                             int Hour3Ago = mod(hour + 20, 24) + 1; // hour 3 hours before
    3747            0 :                             Real64 const TotSkyCover = max(1.0 - desDayInput.SkyClear, 0.0);
    3748            0 :                             Real64 GloHorzRad = (ZHGlobalSolarConstant * SinSolarAltitude *
    3749            0 :                                                      (ZhangHuang_C0 + ZhangHuang_C1 * TotSkyCover + ZhangHuang_C2 * pow_2(TotSkyCover) +
    3750            0 :                                                       ZhangHuang_C3 * (tomorrowTs.OutDryBulbTemp -
    3751            0 :                                                                        state.dataWeather->wvarsHrTsTomorrow(ts, Hour3Ago).OutDryBulbTemp) +
    3752            0 :                                                       ZhangHuang_C4 * tomorrowTs.OutRelHum + ZhangHuang_C5 * tomorrowTs.WindSpeed) +
    3753              :                                                  ZhangHuang_D) /
    3754            0 :                                                 ZhangHuang_K;
    3755            0 :                             GloHorzRad = max(GloHorzRad, 0.0);
    3756            0 :                             Real64 ClearnessIndex_kt = GloHorzRad / (GlobalSolarConstant * SinSolarAltitude);
    3757              :                             //          ClearnessIndex_kt=DesDayInput(EnvrnNum)%SkyClear
    3758            0 :                             Real64 ClearnessIndex_ktc = 0.4268 + 0.1934 * SinSolarAltitude;
    3759              :                             Real64 ClearnessIndex_kds;
    3760            0 :                             if (ClearnessIndex_kt < ClearnessIndex_ktc) {
    3761            0 :                                 ClearnessIndex_kds = (3.996 - 3.862 * SinSolarAltitude + 1.54 * pow_2(SinSolarAltitude)) * pow_3(ClearnessIndex_kt);
    3762              :                             } else {
    3763            0 :                                 ClearnessIndex_kds = ClearnessIndex_kt - (1.107 + 0.03569 * SinSolarAltitude + 1.681 * pow_2(SinSolarAltitude)) *
    3764            0 :                                                                              pow_3(1.0 - ClearnessIndex_kt);
    3765              :                             }
    3766              :                             // Calculate direct normal radiation, W/m2
    3767            0 :                             BeamRad = ZHGlobalSolarConstant * SinSolarAltitude * ClearnessIndex_kds *
    3768            0 :                                       ((1.0 - ClearnessIndex_kt) / (1.0 - ClearnessIndex_kds));
    3769              :                             // Calculation diffuse horizontal radiation, W/m2
    3770            0 :                             DiffRad =
    3771            0 :                                 ZHGlobalSolarConstant * SinSolarAltitude * ((ClearnessIndex_kt - ClearnessIndex_kds) / (1.0 - ClearnessIndex_kds));
    3772              : 
    3773            0 :                         } break;
    3774            0 :                         default:
    3775            0 :                             break;
    3776              :                         }
    3777              :                     }
    3778        68016 :                 }
    3779              : 
    3780              :                 // override result to 0 per environment var (for testing)
    3781        68016 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreBeamRadiation) BeamRad = 0.0;
    3782        68016 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreDiffuseRadiation) DiffRad = 0.0;
    3783              : 
    3784        68016 :                 tomorrowTs.BeamSolarRad = BeamRad;
    3785        68016 :                 tomorrowTs.DifSolarRad = DiffRad;
    3786              : 
    3787              :             } // Timestep (TS) Loop
    3788              :         }     // Hour Loop
    3789              : 
    3790              :         // back-fill hour values from timesteps
    3791              :         // hour values = integrated over hour ending at time of hour
    3792              :         // insurance: hourly values not known to be needed
    3793        12925 :         for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    3794        12408 :             int Hour1Ago = mod(hour + 22, Constant::iHoursInDay) + 1;
    3795        12408 :             auto const &tomorrowHr = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->TimeStepsInHour, hour);
    3796        12408 :             auto const &tomorrowHr1Ago = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->TimeStepsInHour, Hour1Ago);
    3797              : 
    3798        12408 :             Real64 BeamRad = (tomorrowHr1Ago.BeamSolarRad + tomorrowHr.BeamSolarRad) / 2.0;
    3799        12408 :             Real64 DiffRad = (tomorrowHr1Ago.DifSolarRad + tomorrowHr.DifSolarRad) / 2.0;
    3800        12408 :             if (state.dataGlobal->TimeStepsInHour > 1) {
    3801        67392 :                 for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour - 1; ++iTS) {
    3802        55608 :                     BeamRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).BeamSolarRad;
    3803        55608 :                     DiffRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).DifSolarRad;
    3804              :                 }
    3805              :             }
    3806        12408 :             Wthr.BeamSolarRad(hour) = BeamRad / state.dataGlobal->TimeStepsInHour;
    3807        12408 :             Wthr.DifSolarRad(hour) = DiffRad / state.dataGlobal->TimeStepsInHour;
    3808              :         }
    3809              : 
    3810          517 :         if (envCurr.WP_Type1 != 0) {
    3811              : 
    3812            0 :             switch (state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel) {
    3813            0 :             case SkyTempModel::ScheduleValue: {
    3814            0 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3815            0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3816            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3817            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3818            0 :                         state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1).SkyTemp = desDayModsEnvrn(ts + 1, hr + 1).SkyTemp =
    3819            0 :                             dayVals[hr * state.dataGlobal->TimeStepsInHour];
    3820              :                     }
    3821              :                 }
    3822            0 :             } break;
    3823              : 
    3824            0 :             case SkyTempModel::DryBulbDelta: {
    3825            0 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3826            0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3827            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3828            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3829            0 :                         auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3830            0 :                         desDayModsEnvrn(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3831            0 :                         tomorrowTS.SkyTemp = tomorrowTS.OutDryBulbTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3832              :                     }
    3833              :                 }
    3834            0 :             } break;
    3835              : 
    3836            0 :             case SkyTempModel::DewPointDelta: {
    3837            0 :                 std::vector<Real64> const &dayVals = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).sched->getDayVals(state);
    3838            0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3839            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    3840            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    3841            0 :                         auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(ts + 1, hr + 1);
    3842            0 :                         desDayModsEnvrn(ts + 1, hr + 1).SkyTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3843            0 :                         tomorrowTS.SkyTemp = tomorrowTS.OutDewPointTemp - dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    3844              :                     }
    3845              :                 }
    3846            0 :             } break;
    3847              : 
    3848            0 :             default: {
    3849            0 :             } break;
    3850              :             } // switch (skyTempModel)
    3851              :         }     // if (envCurr.WP_Type1 != 0)
    3852              : 
    3853          517 :         state.dataGlobal->WarmupFlag = SaveWarmupFlag;
    3854          517 :     }
    3855              : 
    3856         2159 :     Real64 AirMass(Real64 const CosZen) // COS( solar zenith), 0 - 1
    3857              :     {
    3858              : 
    3859              :         // SUBROUTINE INFORMATION:
    3860              :         //       AUTHOR         C Barnaby
    3861              :         //       DATE WRITTEN   Nov 2010
    3862              : 
    3863              :         // PURPOSE OF THIS SUBROUTINE:
    3864              :         // Calculate relative air mass using Kasten and Young approximation
    3865              : 
    3866              :         // METHODOLOGY EMPLOYED:
    3867              :         // Eqn (16), ASHRAE HOF 2009, p. 14.9
    3868              : 
    3869              :         // REFERENCES:
    3870              :         // ASHRAE HOF 2009 Chapter 14
    3871              :         // Kasten, F and T. Young.  1989.  Revised optical air mass tables
    3872              :         //   and approximating formula.  Applied Optics 28:4735-4738.
    3873              : 
    3874              :         Real64 AirMass;
    3875              :         Real64 SunAltD;
    3876              : 
    3877         2159 :         if (CosZen <= 0.001) {
    3878            5 :             AirMass = 37.07837343; // limit value calc'd with Excel
    3879              :                                    //  value increases little as CosZen -> 0
    3880         2154 :         } else if (CosZen >= 1.0) {
    3881            4 :             AirMass = 1.0;
    3882              :         } else {
    3883              :             // note: COS( Zen) = SIN( Alt)
    3884         2150 :             SunAltD = std::asin(CosZen) / Constant::DegToRad; // altitude, degrees
    3885         2150 :             AirMass = 1.0 / (CosZen + 0.50572 * std::pow(6.07995 + SunAltD, -1.6364));
    3886              :         }
    3887         2159 :         return AirMass;
    3888              :     }
    3889              : 
    3890              :     //------------------------------------------------------------------------------
    3891              : 
    3892         2157 :     void ASHRAETauModel([[maybe_unused]] EnergyPlusData &state,
    3893              :                         DesDaySolarModel const TauModel, // ASHRAETau solar model type ASHRAE_Tau or ASHRAE_Tau2017
    3894              :                         Real64 const ETR,                // extraterrestrial normal irradiance, W/m2
    3895              :                         Real64 const CosZen,             // COS( solar zenith angle), 0 - 1
    3896              :                         Real64 const TauB,               // beam tau factor
    3897              :                         Real64 const TauD,               // dif tau factor
    3898              :                         Real64 &IDirN,                   // returned: direct (beam) irradiance on normal surface, W/m2
    3899              :                         Real64 &IDifH,                   // returned: diffuse irradiance on horiz surface, W/m2
    3900              :                         Real64 &IGlbH                    // returned: global irradiance on horiz surface, W/m2
    3901              :     )
    3902              :     {
    3903              : 
    3904              :         // SUBROUTINE INFORMATION:
    3905              :         //       AUTHOR         C Barnaby
    3906              :         //       DATE WRITTEN   Nov 2010
    3907              : 
    3908              :         // PURPOSE OF THIS SUBROUTINE:
    3909              :         // Calculate clear-sky direct and diffuse irradiance using ASHRAE "tau" model
    3910              : 
    3911              :         // METHODOLOGY EMPLOYED:
    3912              :         // Eqns (17-18), ASHRAE HOF 2009, p. 14.9
    3913              :         // Eqns (19-20), ASHRAE HOF 2013 p. 14.9 and 2017 p. 14.10
    3914              : 
    3915              :         // REFERENCES:
    3916              :         // ASHRAE HOF 2009 Chapter 14
    3917              : 
    3918              :         Real64 AB; // air mass exponents
    3919              :         Real64 AD;
    3920              :         Real64 M; // air mass
    3921              : 
    3922         2157 :         if (CosZen < DataEnvironment::SunIsUpValue || TauB <= 0.0 || TauD <= 0.0) {
    3923            0 :             IDirN = 0.0;
    3924            0 :             IDifH = 0.0;
    3925            0 :             IGlbH = 0.0;
    3926              :         } else {
    3927         2157 :             if (TauModel == DesDaySolarModel::ASHRAE_Tau) {
    3928         2045 :                 AB = 1.219 - 0.043 * TauB - 0.151 * TauD - 0.204 * TauB * TauD;
    3929         2045 :                 AD = 0.202 + 0.852 * TauB - 0.007 * TauD - 0.357 * TauB * TauD;
    3930              :             } else {
    3931              :                 // TauModelType == ASHRAE_Tau2017
    3932          112 :                 AB = 1.454 - 0.406 * TauB - 0.268 * TauD + 0.021 * TauB * TauD;
    3933          112 :                 AD = 0.507 + 0.205 * TauB - 0.080 * TauD - 0.190 * TauB * TauD;
    3934              :             }
    3935         2157 :             M = AirMass(CosZen);
    3936         2157 :             IDirN = ETR * std::exp(-TauB * std::pow(M, AB));
    3937         2157 :             IDifH = ETR * std::exp(-TauD * std::pow(M, AD));
    3938         2157 :             IGlbH = IDirN * CosZen + IDifH;
    3939              :         }
    3940         2157 :     }
    3941              : 
    3942          117 :     void AllocateWeatherData(EnergyPlusData &state)
    3943              :     {
    3944              : 
    3945              :         // SUBROUTINE INFORMATION:
    3946              :         //       AUTHOR         Linda Lawrie
    3947              :         //       DATE WRITTEN   December 2000
    3948              : 
    3949              :         // PURPOSE OF THIS SUBROUTINE:
    3950              :         // This subroutine allocates the weather data structures (Today, Tomorrow,
    3951              :         // Design Day) to the proper number of "time steps in hour" requested by the user.
    3952              :         // Interpolation of data is done later after either setting up the design day (hourly
    3953              :         // data) or reading in hourly weather data.
    3954              : 
    3955          117 :         state.dataWeather->wvarsHrTsToday.allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    3956          117 :         state.dataWeather->wvarsHrTsTomorrow.allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    3957          117 :     }
    3958              : 
    3959         1272 :     void CalculateDailySolarCoeffs(EnergyPlusData const &state,
    3960              :                                    int const DayOfYear,           // Day of year (1 - 366)
    3961              :                                    Real64 &A,                     // ASHRAE "A" - Apparent solar irradiation at air mass = 0 [W/M**2]
    3962              :                                    Real64 &B,                     // ASHRAE "B" - Atmospheric extinction coefficient
    3963              :                                    Real64 &C,                     // ASHRAE "C" - Diffuse radiation factor
    3964              :                                    Real64 &AnnVarSolConstant,     // Annual variation in the solar constant
    3965              :                                    Real64 &EquationOfTime,        // Equation of Time
    3966              :                                    Real64 &SineSolarDeclination,  // Sine of Solar Declination
    3967              :                                    Real64 &CosineSolarDeclination // Cosine of Solar Declination
    3968              :     )
    3969              :     {
    3970              : 
    3971              :         // SUBROUTINE INFORMATION:
    3972              :         //       AUTHOR         George Walton
    3973              :         //       DATE WRITTEN   May 1985
    3974              :         //       MODIFIED       1999 for EnergyPlus
    3975              :         //       RE-ENGINEERED  2001; LKL; Remove need for English -> SI conversion
    3976              :         //                      Implement Tarp "fix" for Southern Hemisphere
    3977              : 
    3978              :         // PURPOSE OF THIS SUBROUTINE:
    3979              :         // This subroutine computes the daily solar coefficients used in other
    3980              :         // calculations.  Specifically, this routine computes values of the solar declination, equation
    3981              :         // of time, and ashrae sky coefficients a, b, and c for a given
    3982              :         // day of the year.
    3983              : 
    3984              :         // METHODOLOGY EMPLOYED:
    3985              :         // The method is the same as that recommended in the ASHRAE loads
    3986              :         // algorithms manual, except that the fourier series expressions
    3987              :         // have been extended by two terms for greater accuracy.
    3988              :         // coefficients for the new expressions were determined at USACERL
    3989              :         // using data from the cited references.
    3990              : 
    3991              :         // REFERENCES:
    3992              :         // J. L. Threlkeld, "Thermal Environmental Engineering", 1970,
    3993              :         // p.316, for declination and equation of time.
    3994              :         // "ASHRAE Handbook of Fundamentals", 1972, p.387 for sky
    3995              :         // coefficients a, b, and c.
    3996              :         // See SUN3 in SolarShading. See SUN2 in BLAST.  See SUN3 in Tarp.
    3997              : 
    3998         1272 :         Real64 const DayCorrection(Constant::Pi * 2.0 / 366.0);
    3999              : 
    4000              :         // Fitted coefficients of Fourier series | Sine of declination coefficients
    4001              :         static constexpr std::array<Real64, 9> SineSolDeclCoef = {
    4002              :             0.00561800, 0.0657911, -0.392779, 0.00064440, -0.00618495, -0.00010101, -0.00007951, -0.00011691, 0.00002096};
    4003              :         // Fitted coefficients of Fourier Series | Equation of Time coefficients
    4004              :         static constexpr std::array<Real64, 9> EqOfTimeCoef = {
    4005              :             0.00021971, -0.122649, 0.00762856, -0.156308, -0.0530028, -0.00388702, -0.00123978, -0.00270502, -0.00167992};
    4006              :         // Fitted coefficients of Fourier Series | ASHRAE A Factor coefficients
    4007              :         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};
    4008              :         // Fitted coefficients of Fourier Series | ASHRAE B Factor coefficients
    4009              :         static constexpr std::array<Real64, 9> ASHRAE_B_Coef = {
    4010              :             0.171631, -0.00400448, -0.0344923, 0.00000209, 0.00325428, -0.00085429, 0.00229562, 0.0009034, -0.0011867};
    4011              :         // Fitted coefficients of Fourier Series | ASHRAE C Factor coefficients
    4012              :         static constexpr std::array<Real64, 9> ASHRAE_C_Coef = {
    4013              :             0.0905151, -0.00322522, -0.0407966, 0.000104164, 0.00745899, -0.00086461, 0.0013111, 0.000808275, -0.00170515};
    4014              : 
    4015              :         // Day of Year in Radians (Computed from Input DayOfYear)
    4016         1272 :         Real64 X = DayCorrection * DayOfYear; // Convert Julian date (Day of Year) to angle X
    4017              : 
    4018              :         // Calculate sines and cosines of X
    4019         1272 :         Real64 SinX = std::sin(X);
    4020         1272 :         Real64 CosX = std::cos(X);
    4021              : 
    4022         1272 :         SineSolarDeclination = SineSolDeclCoef[0] + SineSolDeclCoef[1] * SinX + SineSolDeclCoef[2] * CosX + SineSolDeclCoef[3] * (SinX * CosX * 2.0) +
    4023         1272 :                                SineSolDeclCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    4024         1272 :                                SineSolDeclCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4025         1272 :                                SineSolDeclCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4026         1272 :                                SineSolDeclCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4027         1272 :                                SineSolDeclCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4028         1272 :         CosineSolarDeclination = std::sqrt(1.0 - pow_2(SineSolarDeclination));
    4029              : 
    4030         1272 :         EquationOfTime = EqOfTimeCoef[0] + EqOfTimeCoef[1] * SinX + EqOfTimeCoef[2] * CosX + EqOfTimeCoef[3] * (SinX * CosX * 2.0) +
    4031         1272 :                          EqOfTimeCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    4032         1272 :                          EqOfTimeCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4033         1272 :                          EqOfTimeCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4034         1272 :                          EqOfTimeCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4035         1272 :                          EqOfTimeCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4036              : 
    4037         1272 :         AnnVarSolConstant = 1.000047 + 0.000352615 * SinX + 0.0334454 * CosX;
    4038              : 
    4039         1272 :         A = ASHRAE_A_Coef[0] + ASHRAE_A_Coef[1] * SinX + ASHRAE_A_Coef[2] * CosX + ASHRAE_A_Coef[3] * (SinX * CosX * 2.0) +
    4040         1272 :             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)) +
    4041         1272 :             ASHRAE_A_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4042         1272 :             ASHRAE_A_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4043         1272 :             ASHRAE_A_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4044              : 
    4045              :         // Compute B and C coefficients
    4046              : 
    4047         1272 :         if (state.dataEnvrn->Latitude < 0.0) {
    4048              :             // If in southern hemisphere, compute B and C with a six month time shift.
    4049            0 :             X -= Constant::Pi;
    4050            0 :             SinX = std::sin(X);
    4051            0 :             CosX = std::cos(X);
    4052              :         }
    4053              : 
    4054         1272 :         B = ASHRAE_B_Coef[0] + ASHRAE_B_Coef[1] * SinX + ASHRAE_B_Coef[2] * CosX + ASHRAE_B_Coef[3] * (SinX * CosX * 2.0) +
    4055         1272 :             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)) +
    4056         1272 :             ASHRAE_B_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4057         1272 :             ASHRAE_B_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4058         1272 :             ASHRAE_B_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4059              : 
    4060         1272 :         C = ASHRAE_C_Coef[0] + ASHRAE_C_Coef[1] * SinX + ASHRAE_C_Coef[2] * CosX + ASHRAE_C_Coef[3] * (SinX * CosX * 2.0) +
    4061         1272 :             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)) +
    4062         1272 :             ASHRAE_C_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4063         1272 :             ASHRAE_C_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4064         1272 :             ASHRAE_C_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4065         1272 :     }
    4066              : 
    4067        68016 :     void CalculateSunDirectionCosines(EnergyPlusData const &state,
    4068              :                                       Real64 const TimeValue,    // Current Time of Day
    4069              :                                       Real64 const EqOfTime,     // Equation of Time
    4070              :                                       Real64 const SinSolDeclin, // Sine of Solar Declination
    4071              :                                       Real64 const CosSolDeclin, // Cosine of Solar Declination
    4072              :                                       Vector3<Real64> &SUNCOS)
    4073              :     {
    4074              : 
    4075              :         // SUBROUTINE INFORMATION:
    4076              :         //       AUTHOR         George Walton
    4077              :         //       DATE WRITTEN   May 1975
    4078              :         //       MODIFIED       1999 for EnergyPlus
    4079              : 
    4080              :         // PURPOSE OF THIS SUBROUTINE:
    4081              :         // This routine computes the solar direction cosines for hourly
    4082              :         // radiation calculations.
    4083              : 
    4084              :         // REFERENCES:
    4085              :         // "NECAP Engineering Manual", 1974, p.3-117
    4086              : 
    4087        68016 :         EP_SIZE_CHECK(SUNCOS, 3); // NOLINT(misc-static-assert)
    4088              : 
    4089              :         // COMPUTE THE HOUR ANGLE
    4090        68016 :         Real64 H = (15.0 * (12.0 - (TimeValue + EqOfTime)) + (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude)) * Constant::DegToRad;
    4091        68016 :         Real64 COSH = std::cos(H);
    4092              :         // COMPUTE THE COSINE OF THE SOLAR ZENITH ANGLE.
    4093              :         // This is also the Sine of the Solar Altitude Angle
    4094              : 
    4095        68016 :         SUNCOS.z = SinSolDeclin * state.dataEnvrn->SinLatitude + CosSolDeclin * state.dataEnvrn->CosLatitude * COSH;
    4096              : 
    4097        68016 :         if (SUNCOS.z >= DataEnvironment::SunIsUpValue) { // If Sun above horizon, compute other direction cosines
    4098        33882 :             SUNCOS.y = SinSolDeclin * state.dataEnvrn->CosLatitude - CosSolDeclin * state.dataEnvrn->SinLatitude * COSH;
    4099        33882 :             SUNCOS.x = CosSolDeclin * std::sin(H);
    4100              :         } else { // Sun is down, set to 0.0
    4101        34134 :             SUNCOS.x = 0.0;
    4102        34134 :             SUNCOS.y = 0.0;
    4103              :         }
    4104        68016 :     }
    4105              : 
    4106       326122 :     void DetermineSunUpDown(EnergyPlusData &state, Vector3<Real64> &SunCOS)
    4107              :     {
    4108              : 
    4109              :         // SUBROUTINE INFORMATION:
    4110              :         //       AUTHOR         Linda Lawrie
    4111              :         //       DATE WRITTEN   1999
    4112              : 
    4113              :         // PURPOSE OF THIS SUBROUTINE:
    4114              :         // This subroutine determines if the sun is up or down for the current
    4115              :         // hour/timestep.
    4116              : 
    4117              :         // REFERENCES:
    4118              :         // Sun routines from IBLAST, authored by Walton.
    4119              : 
    4120              :         // COMPUTE THE HOUR ANGLE
    4121       326122 :         if (state.dataGlobal->TimeStepsInHour != 1) {
    4122       643576 :             state.dataWeather->HrAngle = (15.0 * (12.0 - (state.dataGlobal->CurrentTime + state.dataWeather->TodayVariables.EquationOfTime)) +
    4123       321788 :                                           (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4124              :         } else {
    4125         4334 :             state.dataWeather->HrAngle =
    4126         4334 :                 (15.0 *
    4127         4334 :                      (12.0 - ((state.dataGlobal->CurrentTime + state.dataEnvrn->TS1TimeOffset) + state.dataWeather->TodayVariables.EquationOfTime)) +
    4128         4334 :                  (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4129              :         }
    4130       326122 :         Real64 H = state.dataWeather->HrAngle * Constant::DegToRad;
    4131              : 
    4132              :         // Compute the Cosine of the Solar Zenith (Altitude) Angle.
    4133       326122 :         Real64 CosZenith = state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle +
    4134       326122 :                            state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H);
    4135              : 
    4136       326122 :         Real64 SolarZenith = std::acos(CosZenith);
    4137       326122 :         Real64 SinAltitude = state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H) +
    4138       326122 :                              state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    4139       326122 :         Real64 SolarAltitude = std::asin(SinAltitude);
    4140       326122 :         Real64 CosAzimuth = -(state.dataEnvrn->SinLatitude * CosZenith - state.dataWeather->TodayVariables.SinSolarDeclinAngle) /
    4141       326122 :                             (state.dataEnvrn->CosLatitude * std::sin(SolarZenith));
    4142              :         // Following because above can yield invalid cos value.  (e.g. at south pole)
    4143       326122 :         CosAzimuth = max(CosAzimuth, -1.0);
    4144       326122 :         CosAzimuth = min(1.0, CosAzimuth);
    4145       326122 :         Real64 SolarAzimuth = std::acos(CosAzimuth);
    4146              : 
    4147       326122 :         state.dataWeather->SolarAltitudeAngle = SolarAltitude / Constant::DegToRad;
    4148       326122 :         state.dataWeather->SolarAzimuthAngle = SolarAzimuth / Constant::DegToRad;
    4149       326122 :         if (state.dataWeather->HrAngle < 0.0) {
    4150       163219 :             state.dataWeather->SolarAzimuthAngle = 360.0 - state.dataWeather->SolarAzimuthAngle;
    4151              :         }
    4152              : 
    4153       326122 :         SunCOS.z = CosZenith;
    4154       326122 :         state.dataEnvrn->SunIsUpPrevTS = state.dataEnvrn->SunIsUp;
    4155       326122 :         if (CosZenith < DataEnvironment::SunIsUpValue) {
    4156       166429 :             state.dataEnvrn->SunIsUp = false;
    4157       166429 :             SunCOS.y = 0.0;
    4158       166429 :             SunCOS.x = 0.0;
    4159              :         } else {
    4160       159693 :             state.dataEnvrn->SunIsUp = true;
    4161       159693 :             SunCOS.y = state.dataWeather->TodayVariables.SinSolarDeclinAngle * state.dataEnvrn->CosLatitude -
    4162       159693 :                        state.dataWeather->TodayVariables.CosSolarDeclinAngle * state.dataEnvrn->SinLatitude * std::cos(H);
    4163       159693 :             SunCOS.x = state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::sin(H);
    4164              :         }
    4165       326122 :     }
    4166              : 
    4167          115 :     void OpenWeatherFile(EnergyPlusData &state, bool &ErrorsFound)
    4168              :     {
    4169              : 
    4170              :         // SUBROUTINE INFORMATION:
    4171              :         //       AUTHOR         Linda Lawrie
    4172              :         //       DATE WRITTEN   June 1999
    4173              : 
    4174              :         // PURPOSE OF THIS SUBROUTINE:
    4175              :         // This subroutine checks to see if a weather file and what kind of weather file
    4176              :         // exists in the working directory and calls appropriate routines to
    4177              :         // open the files and set up for use.
    4178              : 
    4179          115 :         state.dataWeather->WeatherFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    4180          115 :         if (state.dataWeather->WeatherFileExists) {
    4181           29 :             OpenEPlusWeatherFile(state, ErrorsFound, true);
    4182              :         }
    4183          115 :     }
    4184              : 
    4185           73 :     void OpenEPlusWeatherFile(EnergyPlusData &state,
    4186              :                               bool &ErrorsFound,       // Will be set to true if errors found
    4187              :                               bool const ProcessHeader // Set to true when headers should be processed (rather than just read)
    4188              :     )
    4189              :     {
    4190              : 
    4191              :         // SUBROUTINE INFORMATION:
    4192              :         //       AUTHOR         Linda K. Lawrie
    4193              :         //       DATE WRITTEN   June 1999
    4194              : 
    4195              :         // PURPOSE OF THIS SUBROUTINE:
    4196              :         // This subroutine opens the EnergyPlus Weather File (in.epw) and processes
    4197              :         // the initial header records.
    4198              : 
    4199              :         // METHODOLOGY EMPLOYED:
    4200              :         // List directed reads, as possible.
    4201              : 
    4202           73 :         state.files.inputWeatherFile.close();
    4203           73 :         state.files.inputWeatherFile.filePath = state.files.inputWeatherFilePath.filePath;
    4204           73 :         state.files.inputWeatherFile.open();
    4205           73 :         if (!state.files.inputWeatherFile.good()) {
    4206            0 :             ShowFatalError(state, "OpenWeatherFile: Could not OPEN EPW Weather File", OptionalOutputFileRef(state.files.eso));
    4207              :         }
    4208              : 
    4209           73 :         if (ProcessHeader) {
    4210              :             // Read in Header Information
    4211              : 
    4212              :             // Headers should come in order
    4213          261 :             for (int typeNum = static_cast<int>(EpwHeaderType::Location); typeNum < static_cast<int>(EpwHeaderType::Num); ++typeNum) {
    4214          232 :                 auto Line = state.files.inputWeatherFile.readLine();
    4215          232 :                 if (Line.eof) {
    4216            0 :                     ShowFatalError(
    4217              :                         state,
    4218            0 :                         format("OpenWeatherFile: Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}",
    4219            0 :                                epwHeaders[typeNum]),
    4220            0 :                         OptionalOutputFileRef(state.files.eso));
    4221              :                 }
    4222              : 
    4223          232 :                 int endcol = len(Line.data);
    4224          232 :                 if (endcol > 0) {
    4225          232 :                     if (int(Line.data[endcol - 1]) == DataSystemVariables::iUnicode_end) {
    4226            0 :                         ShowSevereError(state,
    4227              :                                         "OpenWeatherFile: EPW Weather File appears to be a Unicode or binary file.",
    4228            0 :                                         OptionalOutputFileRef(state.files.eso));
    4229            0 :                         ShowContinueError(state, "...This file cannot be read by this program. Please save as PC or Unix file and try again");
    4230            0 :                         ShowFatalError(state, "Program terminates due to previous condition.");
    4231              :                     }
    4232              :                 }
    4233          232 :                 std::string::size_type const Pos = FindNonSpace(Line.data);
    4234          232 :                 std::string::size_type const HdPos = index(Line.data, epwHeaders[typeNum]);
    4235          232 :                 if (Pos != HdPos) continue;
    4236          232 :                 ProcessEPWHeader(state, static_cast<EpwHeaderType>(typeNum), Line.data, ErrorsFound);
    4237          232 :             }
    4238              :         } else { // Header already processed, just read
    4239           44 :             SkipEPlusWFHeader(state);
    4240              :         }
    4241           73 :     }
    4242              : 
    4243          961 :     void CloseWeatherFile(EnergyPlusData &state)
    4244              :     {
    4245          961 :         state.files.inputWeatherFile.close();
    4246          961 :     }
    4247              : 
    4248          112 :     void ResolveLocationInformation(EnergyPlusData &state, bool &ErrorsFound) // Set to true if no location evident
    4249              :     {
    4250              : 
    4251              :         // SUBROUTINE INFORMATION:
    4252              :         //       AUTHOR         Rick Strand
    4253              :         //       DATE WRITTEN   June 1997
    4254              : 
    4255              :         // PURPOSE OF THIS SUBROUTINE:
    4256              :         // This subroutine is currently the main interface between the old data
    4257              :         // structure on the BLAST Weather file and the new data structure contained
    4258              :         // in this module.  At some point, this subroutine will be converted
    4259              :         // to read information directly from the new input file.
    4260              : 
    4261          164 :         if (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather &&
    4262           52 :             state.dataWeather->WeatherFileExists) {
    4263           27 :             if (state.dataWeather->LocationGathered) {
    4264              :                 // See if "matching" location
    4265           26 :                 if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4266           32 :                     if (std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude) > 1.0 ||
    4267           14 :                         std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude) > 1.0 ||
    4268           39 :                         std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone) > 0.0 ||
    4269            7 :                         std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) / max(state.dataEnvrn->Elevation, 1.0) >
    4270              :                             0.10) {
    4271           36 :                         ShowWarningError(state, "Weather file location will be used rather than entered (IDF) Location object.");
    4272           18 :                         ShowContinueError(state, format("..Location object={}", state.dataWeather->LocationTitle));
    4273           18 :                         ShowContinueError(state, format("..Weather File Location={}", state.dataEnvrn->WeatherFileLocationTitle));
    4274           36 :                         ShowContinueError(
    4275              :                             state,
    4276           36 :                             format("..due to location differences, Latitude difference=[{:.2R}] degrees, Longitude difference=[{:.2R}] degrees.",
    4277           18 :                                    std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude),
    4278           18 :                                    std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude)));
    4279           36 :                         ShowContinueError(state,
    4280           36 :                                           format("..Time Zone difference=[{:.1R}] hour(s), Elevation difference=[{:.2R}] percent, [{:.2R}] meters.",
    4281           18 :                                                  std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone),
    4282           36 :                                                  std::abs((state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) /
    4283           18 :                                                           max(state.dataEnvrn->Elevation, 1.0) * 100.0),
    4284           36 :                                                  std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation)));
    4285              :                     }
    4286              :                 }
    4287              :             }
    4288           27 :             if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4289           26 :                 state.dataWeather->LocationTitle = state.dataEnvrn->WeatherFileLocationTitle;
    4290           26 :                 state.dataEnvrn->Latitude = state.dataWeather->WeatherFileLatitude;
    4291           26 :                 state.dataEnvrn->Longitude = state.dataWeather->WeatherFileLongitude;
    4292           26 :                 state.dataEnvrn->TimeZoneNumber = state.dataWeather->WeatherFileTimeZone;
    4293           26 :                 state.dataEnvrn->Elevation = state.dataWeather->WeatherFileElevation;
    4294              :             }
    4295           85 :         } else if (!state.dataWeather->LocationGathered) {
    4296            1 :             state.dataWeather->LocationTitle = "Not Entered";
    4297            2 :             ShowSevereError(state, "No Location given. Must have location information for simulation.");
    4298            1 :             ErrorsFound = true;
    4299              :         }
    4300              : 
    4301          112 :         if (!ErrorsFound) {
    4302          111 :             state.dataEnvrn->StdBaroPress = DataEnvironment::StdPressureSeaLevel * std::pow(1.0 - 2.25577e-05 * state.dataEnvrn->Elevation, 5.2559);
    4303          222 :             state.dataEnvrn->StdRhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(
    4304          111 :                 state, state.dataEnvrn->StdBaroPress, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
    4305              :             // Write Final Location Information to the initialization output file
    4306              :             static constexpr std::string_view LocHdFormat(
    4307              :                 "! <Site:Location>, Location Name, Latitude {N+/S- Deg}, Longitude {E+/W- Deg},  Time Zone Number "
    4308              :                 "{GMT+/-}, Elevation {m},  Standard Pressure at Elevation {Pa}, Standard RhoAir at Elevation\n");
    4309          111 :             print(state.files.eio, "{}", LocHdFormat);
    4310              : 
    4311              :             static constexpr std::string_view LocFormat("Site:Location,{},{:.2R},{:.2R},{:.2R},{:.2R},{:.0R},{:.4R}\n");
    4312          111 :             print(state.files.eio,
    4313              :                   LocFormat,
    4314          111 :                   state.dataWeather->LocationTitle,
    4315          111 :                   state.dataEnvrn->Latitude,
    4316          111 :                   state.dataEnvrn->Longitude,
    4317          111 :                   state.dataEnvrn->TimeZoneNumber,
    4318          111 :                   state.dataEnvrn->Elevation,
    4319          111 :                   state.dataEnvrn->StdBaroPress,
    4320          111 :                   state.dataEnvrn->StdRhoAir);
    4321              :         }
    4322          112 :     }
    4323              : 
    4324          113 :     void CheckLocationValidity(EnergyPlusData &state)
    4325              :     {
    4326              : 
    4327              :         // SUBROUTINE INFORMATION:
    4328              :         //       AUTHOR         Rick Strand
    4329              :         //       DATE WRITTEN   June 1997
    4330              : 
    4331              :         // PURPOSE OF THIS SUBROUTINE:
    4332              :         // This subroutine is checks to see whether the user specified location
    4333              :         // or the weather file location (if one exists) is valid.  The standard
    4334              :         // time meridian is also calculated and compared to the user supplied
    4335              :         // or weather file time zone number.
    4336              : 
    4337          113 :         bool LocationError = false; // Set to true if there is a problem detected
    4338              : 
    4339          113 :         if ((state.dataEnvrn->Latitude == -999.0) && (state.dataEnvrn->Longitude == -999.0) && (state.dataEnvrn->TimeZoneNumber != -999.0)) {
    4340            0 :             ShowSevereError(state, "No location specified");
    4341            0 :             LocationError = true;
    4342              :         }
    4343              : 
    4344          113 :         if ((state.dataEnvrn->Latitude < -90.0) || (state.dataEnvrn->Latitude > 90.0)) {
    4345            0 :             ShowSevereError(state, format("Latitude must be between -90 and 90; Entered={:.2R}", state.dataEnvrn->Latitude));
    4346            0 :             LocationError = true;
    4347              :         }
    4348              : 
    4349          113 :         if ((state.dataEnvrn->Longitude < -180.0) || (state.dataEnvrn->Longitude > 180.0)) {
    4350            0 :             ShowSevereError(state, format("Longitude must be between -180 and 180; Entered={:.2R}", state.dataEnvrn->Longitude));
    4351            0 :             LocationError = true;
    4352              :         }
    4353              : 
    4354          113 :         if ((state.dataEnvrn->TimeZoneNumber < -12.00) || (state.dataEnvrn->TimeZoneNumber > 14.00)) {
    4355            0 :             ShowSevereError(state, format("Time Zone must be between -12 and +14; Entered={:.2R}", state.dataEnvrn->TimeZoneNumber));
    4356            0 :             LocationError = true;
    4357              :         }
    4358              : 
    4359          113 :         Real64 const StdTimeMerid = GetSTM(state.dataEnvrn->Longitude); // Standard time meridian.
    4360              : 
    4361              :         // Compare the standard time meridian with the time zone number.  If
    4362              :         // different, notify the user.  If StdTimeMerid couldn't be calculated,
    4363              :         // produce an error message.
    4364              : 
    4365          113 :         if (state.dataEnvrn->varyingLocationLatSched != nullptr || state.dataEnvrn->varyingLocationLongSched != nullptr) {
    4366              :             // don't do any warnings, the building is moving
    4367          113 :         } else if (StdTimeMerid >= -12.0 && StdTimeMerid <= 12.0) {
    4368          113 :             if (state.dataEnvrn->TimeZoneNumber != StdTimeMerid) {
    4369              :                 // Difference between Standard Time Meridian and TimeZone
    4370            6 :                 Real64 const DiffCalc = std::abs(state.dataEnvrn->TimeZoneNumber - StdTimeMerid);
    4371            6 :                 if (DiffCalc > 1.0 && DiffCalc < 24.0) {
    4372            0 :                     if (DiffCalc < 3.0) {
    4373            0 :                         ShowWarningError(state,
    4374            0 :                                          format("Standard Time Meridian and Time Zone differ by more than 1, Difference=\"{:.1R}\"", DiffCalc));
    4375            0 :                         ShowContinueError(state, "Solar Positions may be incorrect");
    4376              :                     } else {
    4377            0 :                         ShowSevereError(state, format("Standard Time Meridian and Time Zone differ by more than 2, Difference=\"{:.1R}\"", DiffCalc));
    4378            0 :                         ShowContinueError(state, "Solar Positions will be incorrect");
    4379              :                         //          LocationError=.TRUE.
    4380              :                     }
    4381              :                 }
    4382              :             }
    4383          113 :         } else {
    4384            0 :             ShowSevereError(state, "Unable to calculate the standard time meridian");
    4385            0 :             LocationError = true;
    4386              :         }
    4387              : 
    4388              :         // Error handling:  if there are any errors in the location information
    4389              :         // the simulation must be terminated
    4390              : 
    4391          113 :         if (LocationError) {
    4392            0 :             ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4393              :         }
    4394              : 
    4395          113 :         if (state.dataEnvrn->TimeZoneNumber <= 12.00) {
    4396          113 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0;
    4397              :         } else {
    4398            0 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0 - 360.0;
    4399              :         }
    4400          113 :         state.dataEnvrn->SinLatitude = std::sin(Constant::DegToRad * state.dataEnvrn->Latitude);
    4401          113 :         state.dataEnvrn->CosLatitude = std::cos(Constant::DegToRad * state.dataEnvrn->Latitude);
    4402              : 
    4403          113 :         if (state.dataEnvrn->Latitude == 0.0 && state.dataEnvrn->Longitude == 0.0 && state.dataEnvrn->TimeZoneNumber == 0.0) {
    4404            3 :             ShowWarningError(state,
    4405              :                              "Did you realize that you have Latitude=0.0, Longitude=0.0 and TimeZone=0.0?  Your building site is in the middle of "
    4406              :                              "the Atlantic Ocean.");
    4407              :         }
    4408          113 :     }
    4409              : 
    4410           50 :     void CheckWeatherFileValidity(EnergyPlusData &state)
    4411              :     {
    4412              : 
    4413              :         // SUBROUTINE INFORMATION:
    4414              :         //       AUTHOR         Linda Lawrie
    4415              :         //       DATE WRITTEN   February 1977
    4416              :         //       MODIFIED       June 1997 (RKS)
    4417              : 
    4418              :         // PURPOSE OF THIS SUBROUTINE:
    4419              :         // This subroutine contains a portion of the legacy subroutine CKBLDE.
    4420              :         // The main purpose of this routine is to check the validity of the
    4421              :         // weather dates provided by the user and the attached weather file.
    4422              :         // These functions may eventually be pushed to an interface.  This
    4423              :         // routine also sends the weather file header information at the
    4424              :         // Environment derived type.
    4425              : 
    4426           50 :         if (!state.dataWeather->WeatherFileExists) { // No weather file exists but the user requested one--print error message
    4427              : 
    4428           25 :             if (state.dataGlobal->DoWeathSim) {
    4429            2 :                 ShowSevereError(state, "GetNextEnvironment: Weather Environment(s) requested, but no weather file found");
    4430            3 :                 ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4431              :             }
    4432              : 
    4433              :         } // ... end of WeatherFileExists IF-THEN
    4434           49 :     }
    4435              : 
    4436          107 :     void ReportOutputFileHeaders(EnergyPlusData &state)
    4437              :     {
    4438              : 
    4439              :         // SUBROUTINE INFORMATION:
    4440              :         //       AUTHOR         Rick Strand
    4441              :         //       DATE WRITTEN   June 1997
    4442              :         //       MODIFIED       December 2017; Jason DeGraw
    4443              : 
    4444              :         // PURPOSE OF THIS SUBROUTINE:
    4445              :         // This subroutine prints out the necessary header information required
    4446              :         // by the EnergyPlus output file format.  This subroutine can be
    4447              :         // replicated in any other modules which must send data to the output
    4448              :         // file.
    4449              : 
    4450              :         // METHODOLOGY EMPLOYED:
    4451              :         // For each report, the report flag integer must be saved from the
    4452              :         // global report number counter.  Then, the report counter must be
    4453              :         // incremented.  Finally, the header information for the report must
    4454              :         // be sent to the output file.
    4455              : 
    4456              :         using OutputProcessor::ReportFreq;
    4457              : 
    4458              :         static constexpr std::string_view EnvironmentString(",5,Environment Title[],Latitude[deg],Longitude[deg],Time Zone[],Elevation[m]");
    4459              : 
    4460              :         static constexpr std::array<std::string_view, (int)ReportFreq::Num> freqStrings = {
    4461              :             "", // No EachCall string
    4462              :             ",8,Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],Hour[],StartMinute[],EndMinute[],DayType",
    4463              :             "", // No Hour string
    4464              :             ",5,Cumulative Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],DayType  ! When Daily ",
    4465              :             ",2,Cumulative Days of Simulation[],Month[]  ! When Monthly ",
    4466              :             ",1,Cumulative Days of Simulation[] ! When Run Period ",
    4467              :             ",1,Calendar Year of Simulation[] ! When Annual "};
    4468              : 
    4469          107 :         auto &op = state.dataOutputProcessor;
    4470              : 
    4471          107 :         state.dataWeather->EnvironmentReportNbr = ++op->ReportNumberCounter;
    4472          107 :         if (state.dataWeather->EnvironmentReportNbr != 1) { //  problem
    4473            0 :             ShowFatalError(state, "ReportOutputFileHeaders: Assigned report number for Environment title is not 1.  Contact Support.");
    4474              :         }
    4475          107 :         state.dataWeather->EnvironmentReportChr = fmt::to_string(state.dataWeather->EnvironmentReportNbr);
    4476          107 :         strip(state.dataWeather->EnvironmentReportChr);
    4477          107 :         print(state.files.eso, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4478          107 :         print(state.files.mtr, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4479              : 
    4480              :         // TImeStep and Hour share a stamp
    4481          107 :         op->freqStampReportNums[(int)ReportFreq::Hour] = op->freqStampReportNums[(int)ReportFreq::TimeStep] = ++op->ReportNumberCounter;
    4482          107 :         print(state.files.eso, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4483          107 :         print(state.files.mtr, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4484              : 
    4485          535 :         for (ReportFreq freq : {ReportFreq::Day, ReportFreq::Month, ReportFreq::Simulation, ReportFreq::Year}) {
    4486          428 :             op->freqStampReportNums[(int)freq] = ++op->ReportNumberCounter;
    4487          428 :             print(state.files.eso, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Report Variables Requested");
    4488          428 :             print(state.files.mtr, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Meters Requested");
    4489              :         }
    4490          107 :     }
    4491              : 
    4492       326115 :     void ReportWeatherAndTimeInformation(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    4493              :     {
    4494              : 
    4495              :         // SUBROUTINE INFORMATION:
    4496              :         //       AUTHOR         Rick Strand
    4497              :         //       DATE WRITTEN   June 1997
    4498              : 
    4499              :         // PURPOSE OF THIS SUBROUTINE:
    4500              :         // This subroutine is the main driver of the weather reporting.  This
    4501              :         // routine is also responsible for printing the time and environment
    4502              :         // stamps.
    4503              : 
    4504              :         // METHODOLOGY EMPLOYED:
    4505              :         // Reporting is only done for non-warmup days.  The environment stamp
    4506              :         // is only reported at the beginning of an environment, but after the
    4507              :         // warmup days (to allow all modules to print the report headers to the
    4508              :         // output file.  This is controlled by the PrintEnvrnStamp variable
    4509              :         // which is passed in and reset if necessary.
    4510              : 
    4511              :         // Report the time stamp and the current weather to the output file
    4512              : 
    4513       326115 :         if (!state.dataGlobal->WarmupFlag && !state.dataWeather->RPReadAllWeatherData) { // Write the required output information
    4514              : 
    4515              :             // The first time through in a non-warmup day, the environment header
    4516              :             // must be printed.  This must be done here and not in the generic
    4517              :             // DataGlobals::BeginEnvrnFlag block above because other modules in the simulation
    4518              :             // must also print out header information.  This can be done during
    4519              :             // the simulation warmup if the environment stamp printing is delayed
    4520              :             // until the warmup is completed.  The stamp should only be printed once
    4521              :             // per environment (set/reset of PrintEnvrnStamp).  In addition, before
    4522              :             // the first environment, the end of the header block flag must also be
    4523              :             // sent to the output file.
    4524              : 
    4525        34684 :             if (printEnvrnStamp) {
    4526              : 
    4527        16044 :                 if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting) {
    4528              :                     static constexpr std::string_view EndOfHeaderString("End of Data Dictionary"); // End of data dictionary marker
    4529           73 :                     print(state.files.eso, "{}\n", EndOfHeaderString);
    4530           73 :                     print(state.files.mtr, "{}\n", EndOfHeaderString);
    4531           73 :                     state.dataReportFlag->PrintEndDataDictionary = false;
    4532              :                 }
    4533        16044 :                 if (state.dataGlobal->DoOutputReporting) {
    4534          129 :                     std::string const &Title = state.dataWeather->Environment(state.dataWeather->Envrn).Title;
    4535              :                     static constexpr std::string_view EnvironmentStampFormatStr(
    4536              :                         "{},{},{:7.2F},{:7.2F},{:7.2F},{:7.2F}\n"); // Format descriptor for environ stamp
    4537          129 :                     print(state.files.eso,
    4538              :                           EnvironmentStampFormatStr,
    4539          129 :                           state.dataWeather->EnvironmentReportChr,
    4540              :                           Title,
    4541          129 :                           state.dataEnvrn->Latitude,
    4542          129 :                           state.dataEnvrn->Longitude,
    4543          129 :                           state.dataEnvrn->TimeZoneNumber,
    4544          129 :                           state.dataEnvrn->Elevation);
    4545          129 :                     print(state.files.mtr,
    4546              :                           EnvironmentStampFormatStr,
    4547          129 :                           state.dataWeather->EnvironmentReportChr,
    4548              :                           Title,
    4549          129 :                           state.dataEnvrn->Latitude,
    4550          129 :                           state.dataEnvrn->Longitude,
    4551          129 :                           state.dataEnvrn->TimeZoneNumber,
    4552          129 :                           state.dataEnvrn->Elevation);
    4553          129 :                     printEnvrnStamp = false;
    4554              :                 }
    4555              :             }
    4556              :         } // ... end of .NOT.WarmupFlag IF-THEN block.
    4557       326115 :     }
    4558              : 
    4559          111 :     void ReadUserWeatherInput(EnergyPlusData &state)
    4560              :     {
    4561              : 
    4562              :         // SUBROUTINE INFORMATION:
    4563              :         //       AUTHOR         Richard Liesen
    4564              :         //       DATE WRITTEN   September 1997
    4565              : 
    4566              :         // PURPOSE OF THIS SUBROUTINE:
    4567              :         // This subroutine is the main driver of the weather manager module.
    4568              :         // It controls the assignment of weather related global variables as
    4569              :         // well as the reads and writes for retrieving weather information.
    4570              : 
    4571              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4572          111 :         bool ErrorsFound(false);
    4573              : 
    4574              :         // Get the number of design days and annual runs from user inpout
    4575          111 :         state.dataEnvrn->TotDesDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:DesignDay");
    4576          111 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    4577          111 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    4578          111 :         state.dataWeather->TotRunPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriod");
    4579          111 :         state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4580          111 :         state.dataGlobal->WeathSimReq = state.dataWeather->TotRunPers > 0;
    4581          111 :         state.dataWeather->TotReportPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Output:Table:ReportPeriod");
    4582              : #ifdef GET_OUT
    4583              :         state.dataWeather->SPSiteScheduleNamePtr.allocate(state.dataEnvrn->TotDesDays * 5);
    4584              :         state.dataWeather->SPSiteScheduleUnits.allocate(state.dataEnvrn->TotDesDays * 5);
    4585              : 
    4586              :         state.dataWeather->SPSiteScheduleNamePtr = 0;
    4587              :         state.dataWeather->SPSiteScheduleUnits = "";
    4588              : #endif //
    4589              :        // Allocate the Design Day and Environment array to the # of DD's or/and
    4590              :        // Annual runs on input file
    4591          111 :         state.dataWeather->DesignDay.allocate(state.dataEnvrn->TotDesDays);
    4592          111 :         state.dataWeather->Environment.allocate(state.dataWeather->NumOfEnvrn);
    4593              : 
    4594              :         // Set all Environments to DesignDay and then the weather environment will be set
    4595              :         //  in the get annual run data subroutine
    4596          288 :         for (int Env = 1; Env <= state.dataEnvrn->TotDesDays; ++Env) {
    4597          177 :             state.dataWeather->Environment(Env).KindOfEnvrn = Constant::KindOfSim::DesignDay;
    4598              :         }
    4599          111 :         for (int Env = 1; Env <= RPD1 + RPD2; ++Env) {
    4600            0 :             if (!state.dataSysVars->DDOnly) {
    4601            0 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    4602              :             } else {
    4603            0 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4604              :             }
    4605              :         }
    4606          164 :         for (int Env = 1; Env <= state.dataWeather->TotRunPers; ++Env) {
    4607           53 :             state.dataWeather->Environment(state.dataEnvrn->TotDesDays + RPD1 + RPD2 + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4608              :         }
    4609              : 
    4610          111 :         if (state.dataEnvrn->TotDesDays >= 1) {
    4611          103 :             GetDesignDayData(state, state.dataEnvrn->TotDesDays, ErrorsFound);
    4612              :         }
    4613              : 
    4614          111 :         if (RPD1 >= 1 || RPD2 >= 1) {
    4615            0 :             GetRunPeriodDesignData(state, ErrorsFound);
    4616              :         }
    4617              : 
    4618              :         // the last environment(s) is designated the weather environment if an annual run
    4619              :         // is selected.  All of the design systems is done from the design day info
    4620              :         // which will have to be completed to run the annual run.
    4621          111 :         if (state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4622           50 :             GetRunPeriodData(state, state.dataWeather->TotRunPers, ErrorsFound);
    4623              :         }
    4624              : 
    4625          111 :         if (state.dataWeather->TotReportPers > 0) {
    4626            0 :             GetReportPeriodData(state, state.dataWeather->TotReportPers, ErrorsFound);
    4627            0 :             GroupReportPeriodByType(state, state.dataWeather->TotReportPers);
    4628              :         }
    4629              : 
    4630          111 :         if (state.dataSysVars->FullAnnualRun) {
    4631              :             // GetRunPeriodData may have reset the value of TotRunPers
    4632            0 :             state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4633              :         }
    4634              : 
    4635          111 :         if (RPD1 >= 1 || RPD2 >= 1 || state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4636           50 :             GetSpecialDayPeriodData(state, ErrorsFound);
    4637           50 :             GetDSTData(state, ErrorsFound);
    4638           50 :             if (state.dataWeather->IDFDaylightSaving) {
    4639            0 :                 state.dataWeather->DST = state.dataWeather->IDFDST;
    4640              :             }
    4641              :         }
    4642              : 
    4643          111 :         GetLocationInfo(state, ErrorsFound);
    4644              : 
    4645          111 :         GetGroundTemps(state);
    4646              : 
    4647          111 :         GetGroundReflectances(state, ErrorsFound);
    4648              : 
    4649          111 :         GetSnowGroundRefModifiers(state, ErrorsFound);
    4650              : 
    4651          111 :         GetWaterMainsTemperatures(state, ErrorsFound);
    4652              : 
    4653          111 :         GetWeatherStation(state, ErrorsFound);
    4654              : 
    4655          111 :         SetupEnvironmentTypes(state);
    4656              : 
    4657          111 :         GetWeatherProperties(state, ErrorsFound);
    4658              : #ifdef GET_OUT
    4659              :         // Deallocate ones used for schedule pointers
    4660              :         state.dataWeather->SPSiteScheduleNamePtr.deallocate();
    4661              :         state.dataWeather->SPSiteScheduleUnits.deallocate();
    4662              : #endif //
    4663          111 :         if (ErrorsFound) {
    4664            0 :             ShowFatalError(state, "GetWeatherInput: Above errors cause termination");
    4665              :         }
    4666          111 :     }
    4667              : 
    4668           55 :     static int findYearForWeekday(int const month, int const day, Sched::DayType const weekday)
    4669              :     {
    4670              :         // Find a year that goes with a month/day and a weekday. A lookup table is used with the most recent year that includes
    4671              :         // the date with the weekday specified.
    4672              : 
    4673              :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4674              :         static std::array<int, 13> const defaultYear{{2013, 2014, 2015, 2010, 2011, 2017, 2007, 2013, 2014, 2015, 2010, 2011, 2017}};
    4675              : 
    4676           55 :         int rem = calculateDayOfYear(month, day) % 7;
    4677           55 :         return defaultYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4678              :     }
    4679              : 
    4680            2 :     static int findLeapYearForWeekday(int const month, int const day, Sched::DayType const weekday)
    4681              :     {
    4682              :         // 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
    4683              :         // the date with the weekday specified.
    4684              : 
    4685              :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4686              :         static std::array<int, 13> const defaultLeapYear{{2008, 1992, 2004, 2016, 2000, 2012, 1996, 2008, 1992, 2004, 2016, 2000, 2012}};
    4687              : 
    4688            2 :         int rem = calculateDayOfYear(month, day, true) % 7;
    4689            2 :         return defaultLeapYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4690              :     }
    4691              : 
    4692            5 :     void GetReportPeriodData(EnergyPlusData &state,
    4693              :                              int nReportPeriods, // Total number of Report Periods requested
    4694              :                              bool &ErrorsFound)
    4695              :     {
    4696            5 :         constexpr std::string_view routineName = "GetReportPeriodData";
    4697            5 :         state.dataWeather->ReportPeriodInput.allocate(nReportPeriods);
    4698              : 
    4699            5 :         auto const &ipsc = state.dataIPShortCut;
    4700            5 :         ipsc->cCurrentModuleObject = "Output:Table:ReportPeriod";
    4701            5 :         int Count = 0;
    4702              :         int NumAlpha;   // Number of alphas being input
    4703              :         int NumNumeric; // Number of numbers being input
    4704              :         int IOStat;     // IO Status when calling get input subroutine
    4705           15 :         for (int i = 1; i <= nReportPeriods; ++i) {
    4706           20 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4707           10 :                                                                      ipsc->cCurrentModuleObject,
    4708              :                                                                      i,
    4709           10 :                                                                      ipsc->cAlphaArgs,
    4710              :                                                                      NumAlpha,
    4711           10 :                                                                      ipsc->rNumericArgs,
    4712              :                                                                      NumNumeric,
    4713              :                                                                      IOStat,
    4714           10 :                                                                      ipsc->lNumericFieldBlanks,
    4715           10 :                                                                      ipsc->lAlphaFieldBlanks,
    4716           10 :                                                                      ipsc->cAlphaFieldNames,
    4717           10 :                                                                      ipsc->cNumericFieldNames);
    4718              : 
    4719           10 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    4720           10 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    4721              :             // A1, \field Name
    4722           10 :             if (std::find_if(state.dataWeather->ReportPeriodInput.begin(),
    4723           10 :                              state.dataWeather->ReportPeriodInput.end(),
    4724           30 :                              [&newName](ReportPeriodData const &rpd) { return newName == rpd.title; }) !=
    4725           10 :                 state.dataWeather->ReportPeriodInput.end()) {
    4726            1 :                 ShowSevereDuplicateName(state, eoh);
    4727            1 :                 ErrorsFound = true;
    4728              :             }
    4729              : 
    4730           10 :             ++Count;
    4731              : 
    4732           10 :             auto &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4733              :             // Loop = RP + Ptr;
    4734              :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "ReportPeriod 1" anyways
    4735              :             // which is fine for our reporting below
    4736           10 :             reportPeriodInput.title = newName;
    4737              :             // A2, \field Report Name
    4738           10 :             reportPeriodInput.reportName = ipsc->cAlphaArgs(2);
    4739              : 
    4740              :             // set the start and end day of month from user input
    4741              :             // N1, \field Begin Year
    4742              :             // N2, \field Begin Month
    4743              :             // N3, \field Begin Day of Month
    4744              :             // N4, \field Begin Hour of Day
    4745              :             // N5, \field End Year
    4746              :             // N6, \field End Month
    4747              :             // N7, \field End Day of Month
    4748              :             // N8; \field End Hour of Day
    4749           10 :             reportPeriodInput.startYear = int(ipsc->rNumericArgs(1));
    4750           10 :             reportPeriodInput.startMonth = int(ipsc->rNumericArgs(2));
    4751           10 :             reportPeriodInput.startDay = int(ipsc->rNumericArgs(3));
    4752           10 :             reportPeriodInput.startHour = int(ipsc->rNumericArgs(4));
    4753           10 :             reportPeriodInput.endYear = int(ipsc->rNumericArgs(5));
    4754           10 :             reportPeriodInput.endMonth = int(ipsc->rNumericArgs(6));
    4755           10 :             reportPeriodInput.endDay = int(ipsc->rNumericArgs(7));
    4756           10 :             reportPeriodInput.endHour = int(ipsc->rNumericArgs(8));
    4757              : 
    4758              :             // Validate year inputs
    4759           10 :             if (reportPeriodInput.startYear == 0) {
    4760           10 :                 if (reportPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    4761            0 :                     ShowSevereError(state,
    4762            0 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    4763            0 :                                            ipsc->cCurrentModuleObject,
    4764            0 :                                            reportPeriodInput.title));
    4765            0 :                     ErrorsFound = true;
    4766              :                 }
    4767            0 :             } else if (reportPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    4768            0 :                 ShowSevereError(state,
    4769            0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    4770            0 :                                        ipsc->cCurrentModuleObject,
    4771            0 :                                        reportPeriodInput.title,
    4772            0 :                                        reportPeriodInput.startYear));
    4773            0 :                 ErrorsFound = true;
    4774              :             }
    4775              : 
    4776           10 :             if (reportPeriodInput.endYear != 0 && reportPeriodInput.startYear > reportPeriodInput.endYear) {
    4777            0 :                 ShowSevereError(state,
    4778            0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    4779            0 :                                        ipsc->cCurrentModuleObject,
    4780            0 :                                        reportPeriodInput.title,
    4781            0 :                                        reportPeriodInput.startYear,
    4782            0 :                                        reportPeriodInput.endYear));
    4783            0 :                 ErrorsFound = true;
    4784              :             }
    4785              : 
    4786           10 :             reportPeriodInput.startJulianDate =
    4787           10 :                 computeJulianDate(reportPeriodInput.startYear, reportPeriodInput.startMonth, reportPeriodInput.startDay);
    4788           10 :             reportPeriodInput.endJulianDate = computeJulianDate(reportPeriodInput.endYear, reportPeriodInput.endMonth, reportPeriodInput.endDay);
    4789           10 :         }
    4790            5 :     }
    4791              : 
    4792            4 :     void GroupReportPeriodByType(EnergyPlusData &state, const int nReportPeriods)
    4793              :     {
    4794              :         // transfer data from the reporting period object to the corresponding report period type arrays
    4795              :         // ThermalResilienceSummary, CO2ResilienceSummary, VisualResilienceSummary, and AllResilienceSummaries
    4796           13 :         for (auto const &reportPeriodInput : state.dataWeather->ReportPeriodInput) {
    4797              : 
    4798            9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4799            4 :                 ++state.dataWeather->TotThermalReportPers;
    4800            5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4801            3 :                 ++state.dataWeather->TotCO2ReportPers;
    4802            2 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4803            2 :                 ++state.dataWeather->TotVisualReportPers;
    4804            0 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4805            0 :                 ++state.dataWeather->TotThermalReportPers;
    4806            0 :                 ++state.dataWeather->TotCO2ReportPers;
    4807            0 :                 ++state.dataWeather->TotVisualReportPers;
    4808              :             }
    4809              :         }
    4810              : 
    4811            4 :         state.dataWeather->ThermalReportPeriodInput.allocate(state.dataWeather->TotThermalReportPers);
    4812            4 :         state.dataWeather->CO2ReportPeriodInput.allocate(state.dataWeather->TotCO2ReportPers);
    4813            4 :         state.dataWeather->VisualReportPeriodInput.allocate(state.dataWeather->TotVisualReportPers);
    4814              : 
    4815           13 :         for (int i = 1, iThermal = 1, iVisual = 1, iCO2 = 1; i <= nReportPeriods; ++i) {
    4816            9 :             auto const &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4817            9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4818            4 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4819            4 :                 ++iThermal;
    4820            5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4821            3 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4822            3 :                 ++iCO2;
    4823            2 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4824            2 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4825            2 :                 ++iVisual;
    4826            0 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4827            0 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4828            0 :                 ++iThermal;
    4829            0 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4830            0 :                 ++iCO2;
    4831            0 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4832            0 :                 ++iVisual;
    4833              :             }
    4834              :         }
    4835            4 :     }
    4836              : 
    4837           55 :     void GetRunPeriodData(EnergyPlusData &state,
    4838              :                           int nRunPeriods, // Total number of Run Periods requested
    4839              :                           bool &ErrorsFound)
    4840              :     {
    4841              : 
    4842              :         // SUBROUTINE INFORMATION:
    4843              :         //       AUTHOR         Richard Liesen
    4844              :         //       DATE WRITTEN   October 1997
    4845              :         //       MODIFIED       February 1999, Add multiple run periods, Change name.
    4846              :         //                      March 2012, LKL, Add features to object; New "actual weather" object;
    4847              : 
    4848              :         // PURPOSE OF THIS SUBROUTINE:
    4849              :         // This subroutine gets the run period info from User input and the
    4850              :         //  simulation dates
    4851              : 
    4852           55 :         constexpr std::string_view routineName = "GetRunPeriodData";
    4853              :         // Call Input Get routine to retrieve annual run data
    4854           55 :         state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    4855              : 
    4856           55 :         auto const &ipsc = state.dataIPShortCut;
    4857           55 :         ipsc->cCurrentModuleObject = "RunPeriod";
    4858           55 :         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          119 :         for (int i = 1; i <= nRunPeriods; ++i) {
    4863          128 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4864           64 :                                                                      ipsc->cCurrentModuleObject,
    4865              :                                                                      i,
    4866           64 :                                                                      ipsc->cAlphaArgs,
    4867              :                                                                      NumAlpha,
    4868           64 :                                                                      ipsc->rNumericArgs,
    4869              :                                                                      NumNumeric,
    4870              :                                                                      IOStat,
    4871           64 :                                                                      ipsc->lNumericFieldBlanks,
    4872           64 :                                                                      ipsc->lAlphaFieldBlanks,
    4873           64 :                                                                      ipsc->cAlphaFieldNames,
    4874           64 :                                                                      ipsc->cNumericFieldNames);
    4875              : 
    4876              :             // A1, \field Name
    4877           64 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    4878           64 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    4879              : 
    4880           64 :             if (std::find_if(state.dataWeather->RunPeriodInput.begin(),
    4881           64 :                              state.dataWeather->RunPeriodInput.end(),
    4882          178 :                              [&newName](RunPeriodData const &rpd) { return rpd.title == newName; }) != state.dataWeather->RunPeriodInput.end()) {
    4883            0 :                 ShowSevereDuplicateName(state, eoh);
    4884            0 :                 ErrorsFound = true;
    4885              :             }
    4886              : 
    4887           64 :             ++Count;
    4888              :             // Loop = RP + Ptr;
    4889              :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "RUNPERIOD 1" anyways
    4890              :             // which is fine for our reporting below
    4891           64 :             auto &runPeriodInput = state.dataWeather->RunPeriodInput(i);
    4892           64 :             runPeriodInput.title = ipsc->cAlphaArgs(1);
    4893              : 
    4894              :             // set the start and end day of month from user input
    4895              :             // N1 , \field Begin Month
    4896              :             // N2 , \field Begin Day of Month
    4897              :             // N3,  \field Start Year
    4898              :             // N4 , \field End Month
    4899              :             // N5 , \field End Day of Month
    4900              :             // N6,  \field End Year
    4901           64 :             runPeriodInput.startMonth = int(ipsc->rNumericArgs(1));
    4902           64 :             runPeriodInput.startDay = int(ipsc->rNumericArgs(2));
    4903           64 :             runPeriodInput.startYear = int(ipsc->rNumericArgs(3));
    4904           64 :             runPeriodInput.endMonth = int(ipsc->rNumericArgs(4));
    4905           64 :             runPeriodInput.endDay = int(ipsc->rNumericArgs(5));
    4906           64 :             runPeriodInput.endYear = int(ipsc->rNumericArgs(6));
    4907           64 :             runPeriodInput.TreatYearsAsConsecutive = true;
    4908              : 
    4909           64 :             if (state.dataSysVars->FullAnnualRun && i == 1) {
    4910            0 :                 runPeriodInput.startMonth = 1;
    4911            0 :                 runPeriodInput.startDay = 1;
    4912            0 :                 runPeriodInput.endMonth = 12;
    4913            0 :                 runPeriodInput.endDay = 31;
    4914              :             }
    4915              : 
    4916              :             // Validate year inputs
    4917           64 :             if (runPeriodInput.startYear == 0) {
    4918           58 :                 if (runPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    4919            2 :                     ShowSevereError(state,
    4920            2 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    4921            1 :                                            ipsc->cCurrentModuleObject,
    4922            1 :                                            runPeriodInput.title));
    4923            1 :                     ErrorsFound = true;
    4924              :                 }
    4925            6 :             } else if (runPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    4926            0 :                 ShowSevereError(state,
    4927            0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    4928            0 :                                        ipsc->cCurrentModuleObject,
    4929            0 :                                        runPeriodInput.title,
    4930            0 :                                        runPeriodInput.startYear));
    4931            0 :                 ErrorsFound = true;
    4932              :             }
    4933              : 
    4934           64 :             if (runPeriodInput.endYear != 0 && runPeriodInput.startYear > runPeriodInput.endYear) {
    4935            0 :                 ShowSevereError(state,
    4936            0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    4937            0 :                                        ipsc->cCurrentModuleObject,
    4938            0 :                                        runPeriodInput.title,
    4939            0 :                                        runPeriodInput.startYear,
    4940            0 :                                        runPeriodInput.endYear));
    4941            0 :                 ErrorsFound = true;
    4942              :             }
    4943              : 
    4944              :             // A2 , \field Day of Week for Start Day
    4945           64 :             bool inputWeekday = false;
    4946           64 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) { // Have input
    4947           61 :                 int dayType = getEnumValue(Sched::dayTypeNamesUC, state.dataIPShortCut->cAlphaArgs(2));
    4948           61 :                 if (dayType < 1) {
    4949            0 :                     ShowWarningError(state,
    4950            0 :                                      format("{}: object={}{} invalid (Day of Week) [{}] for Start is not valid, Sunday will be used.",
    4951            0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    4952            0 :                                             state.dataWeather->RunPeriodInput(i).title,
    4953            0 :                                             state.dataIPShortCut->cAlphaFieldNames(2),
    4954            0 :                                             state.dataIPShortCut->cAlphaArgs(2)));
    4955            0 :                     runPeriodInput.startWeekDay = Sched::DayType::Sunday;
    4956              :                 } else {
    4957           61 :                     runPeriodInput.startWeekDay = static_cast<Sched::DayType>(dayType);
    4958           61 :                     inputWeekday = true;
    4959              :                 }
    4960              :             } else { // No input, set the default as Sunday. This may get overriden below
    4961            3 :                 runPeriodInput.startWeekDay = Sched::DayType::Sunday;
    4962              :             }
    4963              : 
    4964              :             // Validate the dates now that the weekday field has been looked at
    4965           64 :             if (runPeriodInput.startMonth == 2 && runPeriodInput.startDay == 29) {
    4966              :                 // Requested start date is a leap year
    4967            4 :                 if (runPeriodInput.startYear == 0) { // No input starting year
    4968            2 :                     if (inputWeekday) {
    4969            2 :                         runPeriodInput.startYear =
    4970            2 :                             findLeapYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    4971              :                     } else {
    4972              :                         // 2012 is the default year, 1/1 is a Sunday
    4973            0 :                         runPeriodInput.startYear = 2012;
    4974            0 :                         runPeriodInput.startWeekDay =
    4975            0 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4976              :                     }
    4977              :                 } else {                                         // Have an input start year
    4978            2 :                     if (!isLeapYear(runPeriodInput.startYear)) { // Start year is not a leap year
    4979            2 :                         ShowSevereError(state,
    4980            2 :                                         format("{}: object={}, start year ({}) is not a leap year but the requested start date is 2/29.",
    4981            1 :                                                ipsc->cCurrentModuleObject,
    4982            1 :                                                runPeriodInput.title,
    4983            1 :                                                runPeriodInput.startYear));
    4984            1 :                         ErrorsFound = true;
    4985              :                     } else { // Start year is a leap year
    4986              :                         Sched::DayType weekday =
    4987            1 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4988            1 :                         if (inputWeekday) { // Check for correctness of input
    4989            1 :                             if (weekday != runPeriodInput.startWeekDay) {
    4990            0 :                                 ShowWarningError(state,
    4991            0 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    4992            0 :                                                         ipsc->cCurrentModuleObject,
    4993            0 :                                                         runPeriodInput.title,
    4994            0 :                                                         ipsc->cAlphaArgs(2),
    4995            0 :                                                         runPeriodInput.startYear,
    4996            0 :                                                         Sched::dayTypeNamesUC[static_cast<int>(weekday)]));
    4997            0 :                                 runPeriodInput.startWeekDay = weekday;
    4998              :                             }
    4999              :                         } else { // Set the weekday if it was not input
    5000            0 :                             runPeriodInput.startWeekDay = weekday;
    5001              :                         }
    5002              :                     }
    5003              :                 }
    5004            4 :             } else {
    5005              :                 // Non leap-day start date
    5006           60 :                 if (!validMonthDay(runPeriodInput.startMonth, runPeriodInput.startDay)) {
    5007            0 :                     ShowSevereError(state,
    5008            0 :                                     format("{}: object={}, Invalid input start month/day ({}/{})",
    5009            0 :                                            ipsc->cCurrentModuleObject,
    5010            0 :                                            runPeriodInput.title,
    5011            0 :                                            runPeriodInput.startMonth,
    5012            0 :                                            runPeriodInput.startDay));
    5013            0 :                     ErrorsFound = true;
    5014              :                 } else {                                 // Month/day is valid
    5015           60 :                     if (runPeriodInput.startYear == 0) { // No input starting year
    5016           56 :                         if (inputWeekday) {
    5017           55 :                             runPeriodInput.startYear =
    5018           55 :                                 findYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    5019              :                         } else {
    5020              :                             // 2017 is the default year, 1/1 is a Sunday
    5021            1 :                             runPeriodInput.startYear = 2017;
    5022            1 :                             runPeriodInput.startWeekDay =
    5023            1 :                                 calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5024              :                         }
    5025              :                     } else { // Have an input starting year
    5026              :                         Sched::DayType weekday =
    5027            4 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5028            4 :                         if (inputWeekday) { // Check for correctness of input
    5029            2 :                             if (weekday != runPeriodInput.startWeekDay) {
    5030            2 :                                 ShowWarningError(state,
    5031            3 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    5032            1 :                                                         ipsc->cCurrentModuleObject,
    5033            1 :                                                         runPeriodInput.title,
    5034            1 :                                                         ipsc->cAlphaArgs(2),
    5035            1 :                                                         runPeriodInput.startYear,
    5036            1 :                                                         Sched::dayTypeNamesUC[static_cast<int>(weekday)]));
    5037            1 :                                 runPeriodInput.startWeekDay = weekday;
    5038              :                             }
    5039              :                         } else { // Set the weekday if it was not input
    5040            2 :                             runPeriodInput.startWeekDay = weekday;
    5041              :                         }
    5042              :                     }
    5043              :                 }
    5044              :             }
    5045              : 
    5046              :             // Compute the Julian date of the start date
    5047           64 :             runPeriodInput.startJulianDate = computeJulianDate(runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5048              : 
    5049              :             // Validate the end date
    5050           64 :             if (runPeriodInput.endMonth == 2 && runPeriodInput.endDay == 29) {
    5051              :                 // Requested end date is a leap year
    5052            0 :                 if (runPeriodInput.endYear == 0) { // No input end year
    5053            0 :                     if (isLeapYear(runPeriodInput.startYear) && runPeriodInput.startMonth < 3) {
    5054              :                         // The run period is from some date on or before 2/29 through 2/29
    5055            0 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5056              :                     } else {
    5057              :                         // There might be a better approach here, but for now just loop forward for the next leap year
    5058            0 :                         for (int yr = runPeriodInput.startYear + 1; yr < runPeriodInput.startYear + 10; yr++) {
    5059            0 :                             if (isLeapYear(yr)) {
    5060            0 :                                 runPeriodInput.endYear = yr;
    5061            0 :                                 break;
    5062              :                             }
    5063              :                         }
    5064              :                     }
    5065              :                 } else {                                       // Have an input end year
    5066            0 :                     if (!isLeapYear(runPeriodInput.endYear)) { // End year is not a leap year
    5067            0 :                         ShowSevereError(state,
    5068            0 :                                         format("{}: object={}, end year ({}) is not a leap year but the requested end date is 2/29.",
    5069            0 :                                                ipsc->cCurrentModuleObject,
    5070            0 :                                                runPeriodInput.title,
    5071            0 :                                                runPeriodInput.startYear));
    5072            0 :                         ErrorsFound = true;
    5073              :                     } else {
    5074            0 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5075            0 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5076            0 :                             ShowSevereError(state,
    5077            0 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5078            0 :                                                    ipsc->cCurrentModuleObject,
    5079            0 :                                                    runPeriodInput.title,
    5080            0 :                                                    runPeriodInput.startJulianDate,
    5081            0 :                                                    runPeriodInput.endJulianDate));
    5082            0 :                             ErrorsFound = true;
    5083              :                         }
    5084              :                     }
    5085              :                 }
    5086            0 :             } else {
    5087              :                 // Non leap-day end date
    5088           64 :                 if (!validMonthDay(runPeriodInput.endMonth, runPeriodInput.endDay)) {
    5089            0 :                     ShowSevereError(state,
    5090            0 :                                     format("{}: object={}, Invalid input end month/day ({}/{})",
    5091            0 :                                            ipsc->cCurrentModuleObject,
    5092            0 :                                            runPeriodInput.title,
    5093            0 :                                            runPeriodInput.startMonth,
    5094            0 :                                            runPeriodInput.startDay));
    5095            0 :                     ErrorsFound = true;
    5096              :                 } else {                               // Month/day is valid
    5097           64 :                     if (runPeriodInput.endYear == 0) { // No input end year
    5098              :                         // Assume same year as start year
    5099           61 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5100           61 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5101           61 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5102            0 :                             runPeriodInput.endJulianDate = 0; // Force recalculation later
    5103            0 :                             runPeriodInput.endYear += 1;
    5104              :                         }
    5105              :                     } else { // Have an input end year
    5106            3 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5107            3 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5108            2 :                             ShowSevereError(state,
    5109            2 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5110            1 :                                                    ipsc->cCurrentModuleObject,
    5111            1 :                                                    runPeriodInput.title,
    5112            1 :                                                    runPeriodInput.startJulianDate,
    5113            1 :                                                    runPeriodInput.endJulianDate));
    5114            1 :                             ErrorsFound = true;
    5115              :                         }
    5116              :                     }
    5117              :                 }
    5118              :             }
    5119              : 
    5120           64 :             if (runPeriodInput.endJulianDate == 0) {
    5121            0 :                 runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5122              :             }
    5123              : 
    5124           64 :             runPeriodInput.numSimYears = runPeriodInput.endYear - runPeriodInput.startYear + 1;
    5125              : 
    5126              :             // A3,  \field Use Weather File Holidays and Special Days
    5127              :             BooleanSwitch b;
    5128           64 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5129            0 :                 runPeriodInput.useHolidays = true;
    5130           64 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5131           64 :                 runPeriodInput.useHolidays = static_cast<bool>(b);
    5132              :             } else {
    5133            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5134            0 :                 ErrorsFound = true;
    5135              :             }
    5136              : 
    5137              :             // A4,  \field Use Weather File Daylight Saving Period
    5138           64 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5139            0 :                 runPeriodInput.useDST = true;
    5140           64 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5141           64 :                 runPeriodInput.useDST = static_cast<bool>(b);
    5142              :             } else {
    5143            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5144            0 :                 ErrorsFound = true;
    5145              :             }
    5146              : 
    5147              :             // A5,  \field Apply Weekend Holiday Rule
    5148           64 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5149            0 :                 runPeriodInput.applyWeekendRule = true;
    5150           64 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5151           64 :                 runPeriodInput.applyWeekendRule = static_cast<bool>(b);
    5152              :             } else {
    5153            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5154            0 :                 ErrorsFound = true;
    5155              :             }
    5156              : 
    5157              :             // A6,  \field Use Weather File Rain Indicators
    5158           64 :             if (ipsc->lAlphaFieldBlanks(6)) {
    5159            0 :                 runPeriodInput.useRain = true;
    5160           64 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(6)))) != BooleanSwitch::Invalid) {
    5161           64 :                 runPeriodInput.useRain = static_cast<bool>(b);
    5162              :             } else {
    5163            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6));
    5164            0 :                 ErrorsFound = true;
    5165              :             }
    5166              : 
    5167              :             // A7,  \field Use Weather File Snow Indicators
    5168           64 :             if (ipsc->lAlphaFieldBlanks(7)) {
    5169            0 :                 runPeriodInput.useSnow = true;
    5170           64 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    5171           64 :                 runPeriodInput.useSnow = static_cast<bool>(b);
    5172              :             } else {
    5173            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7));
    5174            0 :                 ErrorsFound = true;
    5175              :             }
    5176              : 
    5177              :             // A8,  \field Treat Weather as Actual
    5178           64 :             if (ipsc->lAlphaFieldBlanks(8)) {
    5179           62 :                 runPeriodInput.actualWeather = false;
    5180            2 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    5181            2 :                 runPeriodInput.actualWeather = static_cast<bool>(b);
    5182              :             } else {
    5183            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8));
    5184            0 :                 ErrorsFound = true;
    5185              :             }
    5186              : 
    5187              :             // A9,  \field First Hour Interpolation Starting Values
    5188           64 :             if (ipsc->lAlphaFieldBlanks(9) || Util::SameString(ipsc->cAlphaArgs(8), "Hour24")) {
    5189           62 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5190            2 :             } else if (Util::SameString(ipsc->cAlphaArgs(9), "Hour1")) {
    5191            2 :                 runPeriodInput.firstHrInterpUsingHr1 = true;
    5192              :             } else {
    5193              :                 // fail-safe default
    5194            0 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5195              :             }
    5196              : 
    5197           64 :             runPeriodInput.dayOfWeek = static_cast<int>(runPeriodInput.startWeekDay);
    5198           64 :             runPeriodInput.isLeapYear = isLeapYear(runPeriodInput.startYear);
    5199              : 
    5200              :             // calculate the annual start and end days from the user inputted month and day
    5201           64 :             runPeriodInput.monWeekDay = 0;
    5202           64 :             if (runPeriodInput.dayOfWeek != 0 && !ErrorsFound) {
    5203           62 :                 SetupWeekDaysByMonth(state, runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.dayOfWeek, runPeriodInput.monWeekDay);
    5204              :             }
    5205           64 :         }
    5206              : 
    5207           55 :         if (nRunPeriods == 0 && state.dataSysVars->FullAnnualRun) {
    5208            0 :             ShowWarningError(state, "No Run Periods input but Full Annual Simulation selected.  Adding Run Period to 1/1 through 12/31.");
    5209            0 :             state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    5210            0 :             state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    5211            0 :             nRunPeriods = 1;
    5212            0 :             state.dataGlobal->WeathSimReq = true;
    5213            0 :             state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    5214            0 :             auto &runPerInput1 = state.dataWeather->RunPeriodInput(1);
    5215            0 :             runPerInput1.startJulianDate = General::OrdinalDay(runPerInput1.startMonth, runPerInput1.startDay, state.dataWeather->LeapYearAdd);
    5216            0 :             runPerInput1.endJulianDate = General::OrdinalDay(runPerInput1.endMonth, runPerInput1.endDay, state.dataWeather->LeapYearAdd);
    5217            0 :             runPerInput1.monWeekDay = 0;
    5218            0 :             if (runPerInput1.dayOfWeek != 0 && !ErrorsFound) {
    5219            0 :                 SetupWeekDaysByMonth(state, runPerInput1.startMonth, runPerInput1.startDay, runPerInput1.dayOfWeek, runPerInput1.monWeekDay);
    5220              :             }
    5221           55 :         } else if (nRunPeriods > 1 && state.dataSysVars->FullAnnualRun) {
    5222            0 :             nRunPeriods = 1;
    5223              :         }
    5224           55 :     }
    5225              : 
    5226            1 :     void GetRunPeriodDesignData(EnergyPlusData &state, bool &ErrorsFound)
    5227              :     {
    5228              : 
    5229              :         // SUBROUTINE INFORMATION:
    5230              :         //       AUTHOR         Linda Lawrie
    5231              :         //       DATE WRITTEN   March 2008
    5232              : 
    5233              :         // PURPOSE OF THIS SUBROUTINE:
    5234              :         // This subroutine gets the run period design info from User input and the
    5235              :         //  simulation dates
    5236              : 
    5237            1 :         constexpr std::string_view routineName = "GetRunPeriodDesignData";
    5238              :         // Call Input Get routine to retrieve annual run data
    5239            1 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    5240            1 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    5241            1 :         state.dataWeather->TotRunDesPers = RPD1 + RPD2;
    5242              : 
    5243            1 :         state.dataWeather->RunPeriodDesignInput.allocate(RPD1 + RPD2);
    5244              : 
    5245            1 :         int Count = 0;
    5246            1 :         auto const &ipsc = state.dataIPShortCut;
    5247            1 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileDays";
    5248            2 :         for (int i = 1; i <= RPD1; ++i) {
    5249              :             int NumAlphas;   // Number of alphas being input
    5250              :             int NumNumerics; // Number of Numerics being input
    5251              :             int IOStat;      // IO Status when calling get input subroutine
    5252            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5253            1 :                                                                      ipsc->cCurrentModuleObject,
    5254              :                                                                      i,
    5255            1 :                                                                      ipsc->cAlphaArgs,
    5256              :                                                                      NumAlphas,
    5257            1 :                                                                      ipsc->rNumericArgs,
    5258              :                                                                      NumNumerics,
    5259              :                                                                      IOStat,
    5260            1 :                                                                      ipsc->lNumericFieldBlanks,
    5261            1 :                                                                      ipsc->lAlphaFieldBlanks,
    5262            1 :                                                                      ipsc->cAlphaFieldNames,
    5263            1 :                                                                      ipsc->cNumericFieldNames);
    5264              : 
    5265            1 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5266            1 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5267            1 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5268            1 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5269            2 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5270            2 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5271            0 :                 ShowSevereDuplicateName(state, eoh);
    5272            0 :                 ErrorsFound = true;
    5273              :             }
    5274              : 
    5275            1 :             ++Count;
    5276              : 
    5277            1 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5278            1 :             runPerDesInput.title = newName;
    5279            1 :             runPerDesInput.periodType = "User Selected WeatherFile RunPeriod (Design)";
    5280              : 
    5281              :             // set the start and end day of month from user input
    5282            1 :             runPerDesInput.startMonth = int(ipsc->rNumericArgs(1));
    5283            1 :             runPerDesInput.startDay = int(ipsc->rNumericArgs(2));
    5284            1 :             runPerDesInput.endMonth = int(ipsc->rNumericArgs(3));
    5285            1 :             runPerDesInput.endDay = int(ipsc->rNumericArgs(4));
    5286              : 
    5287            1 :             switch (runPerDesInput.startMonth) {
    5288            0 :             case 1:
    5289              :             case 3:
    5290              :             case 5:
    5291              :             case 7:
    5292              :             case 8:
    5293              :             case 10:
    5294              :             case 12: {
    5295            0 :                 if (runPerDesInput.startDay > 31) {
    5296            0 :                     ShowSevereError(state,
    5297            0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5298            0 :                                            ipsc->cCurrentModuleObject,
    5299            0 :                                            runPerDesInput.title,
    5300            0 :                                            ipsc->cNumericFieldNames(2),
    5301            0 :                                            runPerDesInput.startDay));
    5302            0 :                     ErrorsFound = true;
    5303              :                 }
    5304            0 :             } break;
    5305            1 :             case 4:
    5306              :             case 6:
    5307              :             case 9:
    5308              :             case 11: {
    5309            1 :                 if (runPerDesInput.startDay > 30) {
    5310            2 :                     ShowSevereError(state,
    5311            3 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5312            1 :                                            ipsc->cCurrentModuleObject,
    5313            1 :                                            runPerDesInput.title,
    5314            1 :                                            ipsc->cNumericFieldNames(2),
    5315            1 :                                            runPerDesInput.startDay));
    5316            1 :                     ErrorsFound = true;
    5317              :                 }
    5318            1 :             } break;
    5319            0 :             case 2: {
    5320            0 :                 if (runPerDesInput.startDay > 28 + state.dataWeather->LeapYearAdd) {
    5321            0 :                     ShowSevereError(state,
    5322            0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5323            0 :                                            ipsc->cCurrentModuleObject,
    5324            0 :                                            runPerDesInput.title,
    5325            0 :                                            ipsc->cNumericFieldNames(2),
    5326            0 :                                            runPerDesInput.startDay));
    5327            0 :                     ErrorsFound = true;
    5328              :                 }
    5329            0 :             } break;
    5330            0 :             default: {
    5331            0 :                 ShowSevereError(state,
    5332            0 :                                 format("{}: object={} {} invalid (Month) [{}]",
    5333            0 :                                        ipsc->cCurrentModuleObject,
    5334            0 :                                        runPerDesInput.title,
    5335            0 :                                        ipsc->cNumericFieldNames(1),
    5336            0 :                                        runPerDesInput.startMonth));
    5337            0 :                 ErrorsFound = true;
    5338            0 :             } break;
    5339              :             } // switch
    5340              : 
    5341            1 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5342            0 :                 runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5343              :             } else {
    5344            1 :                 runPerDesInput.dayOfWeek = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    5345            1 :                 if (runPerDesInput.dayOfWeek < 1 || runPerDesInput.dayOfWeek == 8) {
    5346            0 :                     ShowWarningError(state,
    5347            0 :                                      format("{}: object={} {} invalid (Day of Week) [{} for Start is not Valid, Monday will be Used.",
    5348            0 :                                             ipsc->cCurrentModuleObject,
    5349            0 :                                             runPerDesInput.title,
    5350            0 :                                             ipsc->cAlphaFieldNames(1),
    5351            0 :                                             ipsc->cAlphaArgs(1)));
    5352            0 :                     runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5353              :                 }
    5354              :             }
    5355              : 
    5356              :             BooleanSwitch b;
    5357            1 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5358            0 :                 runPerDesInput.useDST = true;
    5359            1 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5360            1 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5361              :             } else {
    5362            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5363            0 :                 ErrorsFound = true;
    5364              :             }
    5365              : 
    5366            1 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5367            0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5368            1 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5369            1 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5370              :             } else {
    5371            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5372            0 :                 ErrorsFound = true;
    5373              :             }
    5374              : 
    5375              :             // calculate the annual start and end days from the user inputted month and day
    5376            1 :             runPerDesInput.startJulianDate = General::OrdinalDay(runPerDesInput.startMonth, runPerDesInput.startDay, state.dataWeather->LeapYearAdd);
    5377            1 :             runPerDesInput.endJulianDate = General::OrdinalDay(runPerDesInput.endMonth, runPerDesInput.endDay, state.dataWeather->LeapYearAdd);
    5378            1 :             if (runPerDesInput.startJulianDate <= runPerDesInput.endJulianDate) {
    5379            1 :                 runPerDesInput.totalDays = (runPerDesInput.endJulianDate - runPerDesInput.startJulianDate + 1) * runPerDesInput.numSimYears;
    5380              :             } else {
    5381            0 :                 runPerDesInput.totalDays = (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - runPerDesInput.startJulianDate + 1 +
    5382            0 :                                             runPerDesInput.endJulianDate) *
    5383            0 :                                            runPerDesInput.numSimYears;
    5384              :             }
    5385            1 :             runPerDesInput.monWeekDay = 0;
    5386            1 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5387            1 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5388            0 :                 SetupWeekDaysByMonth(state,
    5389              :                                      runPeriodDesignInput1.startMonth,
    5390              :                                      runPeriodDesignInput1.startDay,
    5391              :                                      runPeriodDesignInput1.dayOfWeek,
    5392            0 :                                      runPeriodDesignInput1.monWeekDay);
    5393              :             }
    5394            1 :         }
    5395              : 
    5396            1 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileConditionType";
    5397            1 :         for (int i = 1; i <= RPD2; ++i) {
    5398              :             int NumAlphas;   // Number of alphas being input
    5399              :             int NumNumerics; // Number of Numerics being input
    5400              :             int IOStat;      // IO Status when calling get input subroutine
    5401            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5402            0 :                                                                      ipsc->cCurrentModuleObject,
    5403              :                                                                      i,
    5404            0 :                                                                      ipsc->cAlphaArgs,
    5405              :                                                                      NumAlphas,
    5406            0 :                                                                      ipsc->rNumericArgs,
    5407              :                                                                      NumNumerics,
    5408              :                                                                      IOStat,
    5409            0 :                                                                      ipsc->lNumericFieldBlanks,
    5410            0 :                                                                      ipsc->lAlphaFieldBlanks,
    5411            0 :                                                                      ipsc->cAlphaFieldNames,
    5412            0 :                                                                      ipsc->cNumericFieldNames);
    5413            0 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5414              : 
    5415            0 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5416            0 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5417            0 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5418            0 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5419            0 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5420            0 :                 ShowSevereDuplicateName(state, eoh);
    5421            0 :                 ErrorsFound = true;
    5422              :             }
    5423              : 
    5424            0 :             ++Count;
    5425            0 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5426            0 :             runPerDesInput.title = ipsc->cAlphaArgs(1);
    5427            0 :             runPerDesInput.periodType = "User Selected WeatherFile Typical/Extreme Period (Design)=" + ipsc->cAlphaArgs(2);
    5428              : 
    5429              :             // Period Selection
    5430            0 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5431            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
    5432            0 :                 ErrorsFound = true;
    5433              :             } else {
    5434            0 :                 int WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue);
    5435            0 :                 if (WhichPeriod == 0) {
    5436            0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue1);
    5437              :                     if (WhichPeriod != 0) {
    5438              :                     }
    5439              :                 }
    5440            0 :                 if (WhichPeriod == 0) {
    5441            0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue2);
    5442            0 :                     if (WhichPeriod != 0) {
    5443            0 :                         ShowWarningError(state,
    5444            0 :                                          format("{}: object={} {}={} matched to {}",
    5445            0 :                                                 ipsc->cCurrentModuleObject,
    5446            0 :                                                 runPerDesInput.title,
    5447            0 :                                                 ipsc->cAlphaFieldNames(2),
    5448            0 :                                                 ipsc->cAlphaArgs(2),
    5449            0 :                                                 state.dataWeather->TypicalExtremePeriods(WhichPeriod).MatchValue2));
    5450              :                     }
    5451              :                 }
    5452            0 :                 if (WhichPeriod == 0) {
    5453            0 :                     ShowSevereError(state,
    5454            0 :                                     format("{}: object={} {} invalid (not on Weather File)={}",
    5455            0 :                                            ipsc->cCurrentModuleObject,
    5456            0 :                                            runPerDesInput.title,
    5457            0 :                                            ipsc->cAlphaFieldNames(2),
    5458            0 :                                            ipsc->cAlphaArgs(2)));
    5459            0 :                     ErrorsFound = true;
    5460              :                 } else {
    5461            0 :                     auto const &typicalExtPer = state.dataWeather->TypicalExtremePeriods(WhichPeriod);
    5462            0 :                     runPerDesInput.startDay = typicalExtPer.StartDay;
    5463            0 :                     runPerDesInput.startMonth = typicalExtPer.StartMonth;
    5464            0 :                     runPerDesInput.startJulianDate = typicalExtPer.StartJDay;
    5465            0 :                     runPerDesInput.endDay = typicalExtPer.EndDay;
    5466            0 :                     runPerDesInput.endMonth = typicalExtPer.EndMonth;
    5467            0 :                     runPerDesInput.endJulianDate = typicalExtPer.EndJDay;
    5468            0 :                     runPerDesInput.totalDays = typicalExtPer.TotalDays;
    5469              :                 }
    5470              :             }
    5471              : 
    5472            0 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5473            0 :                 runPerDesInput.dayOfWeek = (int)Sched::DayType::Monday; // Defaults to Monday
    5474              :             } else {
    5475            0 :                 runPerDesInput.dayOfWeek = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(3));
    5476            0 :                 if (runPerDesInput.dayOfWeek < (int)Sched::DayType::Sunday || runPerDesInput.dayOfWeek == (int)Sched::DayType::Holiday) {
    5477              :                     // Sunday-Saturday, SummerDesignDay, WinterDesignDay, CustomDay1, and CustomDay2 are all valid. Holiday is not valid.
    5478              :                     // The input processor should trap invalid key choices, so this should never trip.
    5479            0 :                     assert(false);
    5480              :                 }
    5481              :             }
    5482              : 
    5483              :             BooleanSwitch b;
    5484            0 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5485            0 :                 runPerDesInput.useDST = true;
    5486            0 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5487            0 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5488              :             } else {
    5489            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5490            0 :                 ErrorsFound = true;
    5491              :             }
    5492              : 
    5493            0 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5494            0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5495            0 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5496            0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5497              :             } else {
    5498            0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5499            0 :                 ErrorsFound = true;
    5500              :             }
    5501            0 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5502            0 :             runPeriodDesignInput1.monWeekDay = 0;
    5503            0 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5504            0 :                 SetupWeekDaysByMonth(state,
    5505              :                                      runPeriodDesignInput1.startMonth,
    5506              :                                      runPeriodDesignInput1.startDay,
    5507              :                                      runPeriodDesignInput1.dayOfWeek,
    5508            0 :                                      runPeriodDesignInput1.monWeekDay);
    5509              :             }
    5510            0 :         }
    5511            1 :     }
    5512              : 
    5513           50 :     void GetSpecialDayPeriodData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5514              :     {
    5515              : 
    5516              :         // SUBROUTINE INFORMATION:
    5517              :         //       AUTHOR         Linda Lawrie
    5518              :         //       DATE WRITTEN   June 2000
    5519              : 
    5520              :         // PURPOSE OF THIS SUBROUTINE:
    5521              :         // This subroutine reads any special day period data from the IDF and
    5522              :         // processes it into the data structure that will drive the values
    5523              :         // in the SpecialDayTypes array.
    5524              : 
    5525              :         // METHODOLOGY EMPLOYED:
    5526              :         // Processes the following IDD definition:
    5527              :         // SpecialDayPeriod,
    5528              :         //      \memo This object sets up holidays/special days to be used during weather file
    5529              :         //      \memo run periods.  (These are not used with DesignDay objects.)
    5530              :         //      \memo Depending on the value in the run period, days on the weather file may also
    5531              :         //      \memo be used.  However, the weather file specification will take precedence over
    5532              :         //      \memo any specification shown here.  (No error message on duplicate days or overlapping
    5533              :         //      \memo days).
    5534              :         //  A1, \field Holiday Name
    5535              :         //  A2, \field StartDate
    5536              :         //      \memo  Dates can be several formats:
    5537              :         //      \memo  <number>/<number>  (month/day)
    5538              :         //      \memo  <number> Month
    5539              :         //      \memo  Month <number>
    5540              :         //      \memo Months are January, February, March, April, May, June, July, August, September, October, November, December
    5541              :         //      \memo Months can be the first 3 letters of the month
    5542              :         //        \note will eventually allow: 3 Monday April (meaning 3rd Monday in April)
    5543              :         //  N1, \field duration (number of days)
    5544              :         //  A3; \field SpecialDayType
    5545              :         //        \note SpecialDayType selects the schedules appropriate for each day so labeled
    5546              :         //        \type choice
    5547              :         //        \key Holiday
    5548              :         //        \key SummerDesignDay
    5549              :         //        \key WinterDesignDay
    5550              :         //        \key CustomDay1
    5551              :         //        \key CustomDay2
    5552              : 
    5553           50 :         constexpr std::string_view routineName = "GetSpecialDayPeriodData";
    5554              : 
    5555           50 :         auto const &ipsc = state.dataIPShortCut;
    5556           50 :         ipsc->cCurrentModuleObject = "RunPeriodControl:SpecialDays";
    5557           50 :         int NumSpecDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5558              :         int Count;
    5559           50 :         if (allocated(state.dataWeather->SpecialDays)) { // EPW already allocated the array
    5560           25 :             Count = state.dataWeather->NumSpecialDays - NumSpecDays + 1;
    5561              :         } else {
    5562           25 :             state.dataWeather->SpecialDays.allocate(NumSpecDays);
    5563           25 :             state.dataWeather->NumSpecialDays = NumSpecDays;
    5564           25 :             Count = 1;
    5565              :         }
    5566              : 
    5567           50 :         Array1D_string AlphArray(3);
    5568              :         int NumAlphas;
    5569           50 :         Array1D<Real64> Duration(1);
    5570              :         int NumNumbers;
    5571              :         int IOStat;
    5572              : 
    5573           50 :         for (int i = 1; i <= NumSpecDays; ++i, ++Count) {
    5574              : 
    5575            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    5576            0 :                 state, ipsc->cCurrentModuleObject, i, AlphArray, NumAlphas, Duration, NumNumbers, IOStat);
    5577              : 
    5578            0 :             auto &specialDay = state.dataWeather->SpecialDays(Count);
    5579              : 
    5580            0 :             specialDay.Name = AlphArray(1);
    5581            0 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, specialDay.Name};
    5582              : 
    5583              :             int PMonth;
    5584              :             int PDay;
    5585              :             int PWeekDay;
    5586              :             DateType dateType;
    5587            0 :             General::ProcessDateString(state, AlphArray(2), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    5588            0 :             if (dateType == DateType::MonthDay) {
    5589            0 :                 specialDay.dateType = dateType;
    5590            0 :                 specialDay.Month = PMonth;
    5591            0 :                 specialDay.Day = PDay;
    5592            0 :                 specialDay.WeekDay = 0;
    5593            0 :                 specialDay.CompDate = PMonth * 32 + PDay;
    5594            0 :                 specialDay.WthrFile = false;
    5595            0 :             } else if (dateType != DateType::Invalid) {
    5596            0 :                 specialDay.dateType = dateType;
    5597            0 :                 specialDay.Month = PMonth;
    5598            0 :                 specialDay.Day = PDay;
    5599            0 :                 specialDay.WeekDay = PWeekDay;
    5600            0 :                 specialDay.CompDate = 0;
    5601            0 :                 specialDay.WthrFile = false;
    5602              :             } else {
    5603            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    5604            0 :                 ErrorsFound = true;
    5605              :             }
    5606              : 
    5607            0 :             if (Duration(1) > 0) {
    5608            0 :                 specialDay.Duration = int(Duration(1));
    5609              :             } else {
    5610            0 :                 ShowSevereError(
    5611            0 :                     state, format("{}: {} Invalid {}={:.0T}", ipsc->cCurrentModuleObject, AlphArray(1), ipsc->cNumericFieldNames(1), Duration(1)));
    5612            0 :                 ErrorsFound = true;
    5613              :             }
    5614              : 
    5615            0 :             int DayType = getEnumValue(Sched::dayTypeNamesUC, AlphArray(3));
    5616            0 :             if (DayType == 0) {
    5617            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), AlphArray(3));
    5618            0 :                 ErrorsFound = true;
    5619              :             } else {
    5620            0 :                 specialDay.DayType = DayType;
    5621              :             }
    5622              :         }
    5623           50 :     }
    5624              : 
    5625            5 :     void CalcSpecialDayTypes(EnergyPlusData &state)
    5626              :     {
    5627              : 
    5628              :         // SUBROUTINE INFORMATION:
    5629              :         //       AUTHOR         Linda Lawrie
    5630              :         //       DATE WRITTEN   June 2000
    5631              : 
    5632              :         // PURPOSE OF THIS SUBROUTINE:
    5633              :         // This subroutine creates the array of Special Day types used during
    5634              :         // the simulation.
    5635              : 
    5636              :         // METHODOLOGY EMPLOYED:
    5637              :         // Sets up the SpecialDayTypes array that then is used during simulation.
    5638              : 
    5639            5 :         state.dataWeather->SpecialDayTypes = 0; // Initialize/Reset Special Day Types array
    5640              : 
    5641            5 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    5642            0 :             auto const &specialDay = state.dataWeather->SpecialDays(i);
    5643            0 :             if (specialDay.WthrFile) continue;
    5644              : 
    5645            0 :             int Warn = 0;
    5646              : 
    5647            0 :             int JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd) - 1;
    5648              : 
    5649            0 :             for (int j = 1; j <= specialDay.Duration; ++j) {
    5650            0 :                 ++JDay;
    5651            0 :                 if (JDay > 366) {
    5652            0 :                     ShowWarningError(state, format("SpecialDay={} causes index of more than 366, ignoring those beyond 366", specialDay.Name));
    5653              :                 } else {
    5654            0 :                     if (state.dataWeather->SpecialDayTypes(JDay) != 0 && Warn == 0) {
    5655            0 :                         ShowWarningError(state, format("SpecialDay={} attempted overwrite of previous set special day", specialDay.Name));
    5656            0 :                         Warn = 1;
    5657            0 :                     } else if (state.dataWeather->SpecialDayTypes(JDay) == 0) {
    5658            0 :                         state.dataWeather->SpecialDayTypes(JDay) = specialDay.DayType;
    5659              :                     }
    5660              :                 }
    5661              :             }
    5662              :         }
    5663            5 :     }
    5664              : 
    5665           50 :     void GetDSTData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5666              :     {
    5667              : 
    5668              :         // SUBROUTINE INFORMATION:
    5669              :         //       AUTHOR         Linda Lawrie
    5670              :         //       DATE WRITTEN   August 2000
    5671              : 
    5672              :         // PURPOSE OF THIS SUBROUTINE:
    5673              :         // This subroutine gets a possible "Daylight Saving Period" from the IDF.  Using this
    5674              :         // will overwrite any prior DST data.
    5675              : 
    5676              :         // METHODOLOGY EMPLOYED:
    5677              :         // Processes the following IDD definition:
    5678              :         // DaylightSavingPeriod,
    5679              :         //      \memo This object sets up the Daylight Saving period for any RunPeriod.
    5680              :         //      \memo Ignores any DaylightSavingperiod values on the weather file and uses this definition.
    5681              :         //      \memo (These are not used with DesignDay objects.)
    5682              :         //  A1, \field StartDate
    5683              :         //  A2, \field EndDate
    5684              :         //      \memo  Dates can be several formats:
    5685              :         //      \memo  <number>/<number>  (month/day)
    5686              :         //      \memo  <number> <Month>
    5687              :         //      \memo  <Month> <number>
    5688              :         //      \memo <Nth> <Weekday> in <Month)
    5689              :         //      \memo Last <WeekDay> in <Month>
    5690              :         //      \memo <Month> can be January, February, March, April, May, June, July, August, September,
    5691              :         // October, November, December
    5692              :         //      \memo Months can be the first 3 letters of the month
    5693              :         //      \memo <Weekday> can be Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
    5694              :         //      \memo <Nth> can be 1 or 1st, 2 or 2nd, etc. up to 5(?)
    5695              : 
    5696           50 :         constexpr std::string_view routineName = "GetDSTData";
    5697              : 
    5698           50 :         auto const &ipsc = state.dataIPShortCut;
    5699           50 :         ipsc->cCurrentModuleObject = "RunPeriodControl:DaylightSavingTime";
    5700           50 :         int NumFound = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5701              : 
    5702           50 :         if (NumFound == 1) {
    5703              :             int NumAlphas;
    5704              :             int IOStat;
    5705              :             int NumNumbers;
    5706            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5707            0 :                                                                      ipsc->cCurrentModuleObject,
    5708              :                                                                      1,
    5709            0 :                                                                      ipsc->cAlphaArgs,
    5710              :                                                                      NumAlphas,
    5711            0 :                                                                      ipsc->rNumericArgs,
    5712              :                                                                      NumNumbers,
    5713              :                                                                      IOStat,
    5714            0 :                                                                      ipsc->lNumericFieldBlanks,
    5715            0 :                                                                      ipsc->lAlphaFieldBlanks,
    5716            0 :                                                                      ipsc->cAlphaFieldNames,
    5717            0 :                                                                      ipsc->cNumericFieldNames);
    5718              : 
    5719            0 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    5720              : 
    5721            0 :             if (NumAlphas != 2) {
    5722            0 :                 ShowSevereError(state, format("{}: Insufficient fields, must have Start AND End Dates", ipsc->cCurrentModuleObject));
    5723            0 :                 ErrorsFound = true;
    5724              :             } else { // Correct number of arguments
    5725            0 :                 General::ProcessDateString(state,
    5726            0 :                                            ipsc->cAlphaArgs(1),
    5727            0 :                                            state.dataWeather->IDFDST.StMon,
    5728            0 :                                            state.dataWeather->IDFDST.StDay,
    5729            0 :                                            state.dataWeather->IDFDST.StWeekDay,
    5730            0 :                                            state.dataWeather->IDFDST.StDateType,
    5731              :                                            ErrorsFound);
    5732            0 :                 if (state.dataWeather->IDFDST.StDateType == DateType::Invalid) {
    5733            0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    5734            0 :                     ErrorsFound = true;
    5735              :                 }
    5736            0 :                 General::ProcessDateString(state,
    5737            0 :                                            ipsc->cAlphaArgs(2),
    5738            0 :                                            state.dataWeather->IDFDST.EnMon,
    5739            0 :                                            state.dataWeather->IDFDST.EnDay,
    5740            0 :                                            state.dataWeather->IDFDST.EnWeekDay,
    5741            0 :                                            state.dataWeather->IDFDST.EnDateType,
    5742              :                                            ErrorsFound);
    5743            0 :                 if (state.dataWeather->IDFDST.EnDateType == DateType::Invalid) {
    5744            0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    5745            0 :                     ErrorsFound = true;
    5746              :                 }
    5747            0 :                 state.dataWeather->IDFDaylightSaving = true;
    5748              :             }
    5749           50 :         } else if (NumFound > 1) {
    5750            0 :             ShowSevereError(state, format("{}: Too many objects in Input File, only one allowed.", ipsc->cCurrentModuleObject));
    5751            0 :             ErrorsFound = true;
    5752              :         }
    5753           50 :     }
    5754              : 
    5755          106 :     void GetDesignDayData(EnergyPlusData &state,
    5756              :                           int TotDesDays, // Total number of Design days to Setup
    5757              :                           bool &ErrorsFound)
    5758              :     {
    5759              : 
    5760              :         // SUBROUTINE INFORMATION:
    5761              :         //       AUTHOR         Richard Liesen
    5762              :         //       DATE WRITTEN   September 1997
    5763              : 
    5764              :         // PURPOSE OF THIS SUBROUTINE:
    5765              :         // This subroutine retrieves the design day info from user input file
    5766              :         //  which is later to be used in the Setup Design Day Routine.
    5767              : 
    5768              :         // REFERENCES:
    5769              :         // SizingPeriod:DesignDay,
    5770              :         //   A1, \field Name
    5771              :         //   N1,  \field Month
    5772              :         //   N2,  \field Day of Month
    5773              :         //   A2,  \field Day Type
    5774              :         //   N3,  \field Maximum Dry-Bulb Temperature
    5775              :         //   N4,  \field Daily Dry-Bulb Temperature Range
    5776              :         //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    5777              :         //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    5778              :         //   A5,  \field Humidity Condition Type
    5779              :         //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    5780              :         //   A6,  \field Humidity Condition Day Schedule Name
    5781              :         //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    5782              :         //   N7,  \field Enthalpy at Maximum Dry-Bulb  !will require units transition.
    5783              :         //   N8,  \field Daily Wet-Bulb Temperature Range
    5784              :         //   N9,  \field Barometric Pressure
    5785              :         //   N10, \field Wind Speed
    5786              :         //   N11, \field Wind Direction
    5787              :         //   A7,  \field Rain Indicator
    5788              :         //   A8,  \field Snow Indicator
    5789              :         //   A9,  \field Daylight Saving Time Indicator
    5790              :         //   A10, \field Solar Model Indicator
    5791              :         //   A11, \field Beam Solar Day Schedule Name
    5792              :         //   A12, \field Diffuse Solar Day Schedule Name
    5793              :         //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    5794              :         //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    5795              :         //   N14; \field Sky Clearness
    5796              : 
    5797              :         static constexpr std::array<std::string_view, static_cast<int>(DesDayHumIndType::Num)> DesDayHumIndTypeStringRep = {
    5798              :             "Wetbulb [C]",
    5799              :             "Dewpoint [C]",
    5800              :             "Enthalpy [J/kg]",
    5801              :             "Humidity Ratio []",
    5802              :             "Schedule []",
    5803              :             "WetBulbProfileDefaultMultipliers []",
    5804              :             "WetBulbProfileDifferenceSchedule []",
    5805              :             "WetBulbProfileMultiplierSchedule []"};
    5806              : 
    5807              :         // Below are the 2009 fractions, HOF, Chap 14, Table 6
    5808              :         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,
    5809              :                                                                         0.05, 0.00, 0.00, 0.06, 0.14, 0.24, 0.39, 0.50, 0.59, 0.68, 0.75, 0.82};
    5810              : 
    5811              :         static constexpr std::string_view routineName = "GetDesignDayData";
    5812              : 
    5813              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5814              :         Constant::Units unitType;
    5815              : 
    5816          106 :         state.dataWeather->DesDayInput.allocate(TotDesDays); // Allocate the array to the # of DD's
    5817          106 :         state.dataWeather->desDayMods.allocate(TotDesDays);
    5818          288 :         for (int iDD = 1; iDD <= TotDesDays; ++iDD)
    5819          182 :             state.dataWeather->desDayMods(iDD).allocate(state.dataGlobal->TimeStepsInHour, Constant::iHoursInDay);
    5820              : 
    5821          106 :         state.dataWeather->spSiteSchedules.dimension(TotDesDays, Weather::SPSiteSchedules());
    5822              : 
    5823          106 :         if (state.dataSysVars->ReverseDD && TotDesDays <= 1) {
    5824            0 :             ShowSevereError(state, "GetDesignDayData: Reverse Design Day requested but # Design Days <=1");
    5825              :         }
    5826              : 
    5827          106 :         auto const &ipsc = state.dataIPShortCut;
    5828          106 :         ipsc->cCurrentModuleObject = "SizingPeriod:DesignDay";
    5829          288 :         for (int iDesDay = 1; iDesDay <= TotDesDays; ++iDesDay) {
    5830              : 
    5831              :             int EnvrnNum;
    5832          182 :             if (!state.dataSysVars->ReverseDD) {
    5833          182 :                 EnvrnNum = iDesDay;
    5834            0 :             } else if (iDesDay == 1 && TotDesDays > 1) {
    5835            0 :                 EnvrnNum = 2;
    5836            0 :             } else if (iDesDay == 2) {
    5837            0 :                 EnvrnNum = 1;
    5838              :             } else {
    5839            0 :                 EnvrnNum = iDesDay;
    5840              :             }
    5841              : 
    5842              :             // Call Input Get routine to retrieve design day data
    5843          182 :             bool MaxDryBulbEntered = false;
    5844          182 :             bool PressureEntered = false;
    5845              :             int NumAlpha;    // Number of material alpha names being passed
    5846              :             int NumNumerics; // Number of material properties being passed
    5847              :             int IOStat;      // IO Status when calling get input subroutine
    5848          364 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5849          182 :                                                                      ipsc->cCurrentModuleObject,
    5850              :                                                                      iDesDay,
    5851          182 :                                                                      ipsc->cAlphaArgs,
    5852              :                                                                      NumAlpha,
    5853          182 :                                                                      ipsc->rNumericArgs,
    5854              :                                                                      NumNumerics,
    5855              :                                                                      IOStat,
    5856          182 :                                                                      ipsc->lNumericFieldBlanks,
    5857          182 :                                                                      ipsc->lAlphaFieldBlanks,
    5858          182 :                                                                      ipsc->cAlphaFieldNames,
    5859          182 :                                                                      ipsc->cNumericFieldNames);
    5860              : 
    5861          182 :             auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    5862          182 :             auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    5863          182 :             desDayInput.Title = ipsc->cAlphaArgs(1); // Environment name
    5864          182 :             envCurr.Title = desDayInput.Title;
    5865              : 
    5866          182 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, desDayInput.Title};
    5867              : 
    5868              :             //   N3,  \field Maximum Dry-Bulb Temperature
    5869              :             //   N4,  \field Daily Dry-Bulb Temperature Range
    5870              :             //   N9,  \field Barometric Pressure
    5871              :             //   N10, \field Wind Speed
    5872              :             //   N11, \field Wind Direction
    5873          182 :             desDayInput.MaxDryBulb = ipsc->rNumericArgs(3); // Maximum Dry-Bulb Temperature (C)
    5874          182 :             MaxDryBulbEntered = !ipsc->lNumericFieldBlanks(3);
    5875          182 :             desDayInput.DailyDBRange = ipsc->rNumericArgs(4); // Daily dry-bulb temperature range (deltaC)
    5876          182 :             desDayInput.PressBarom = ipsc->rNumericArgs(9);   // Atmospheric/Barometric Pressure (Pascals)
    5877          182 :             PressureEntered = !ipsc->lNumericFieldBlanks(9);
    5878          182 :             desDayInput.PressureEntered = PressureEntered;
    5879          182 :             desDayInput.WindSpeed = ipsc->rNumericArgs(10);           // Wind Speed (m/s)
    5880          182 :             desDayInput.WindDir = mod(ipsc->rNumericArgs(11), 360.0); // Wind Direction
    5881              :             // (degrees clockwise from North, N=0, E=90, S=180, W=270)
    5882              :             //   N1,  \field Month
    5883              :             //   N2,  \field Day of Month
    5884              :             //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    5885              :             //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    5886              :             //   N8,  \field Daily Wet-Bulb Temperature Range
    5887          182 :             desDayInput.Month = int(ipsc->rNumericArgs(1));      // Month of Year ( 1 - 12 )
    5888          182 :             desDayInput.DayOfMonth = int(ipsc->rNumericArgs(2)); // Day of Month ( 1 - 31 )
    5889          182 :             desDayInput.TauB = ipsc->rNumericArgs(12);           // beam tau >= 0
    5890          182 :             desDayInput.TauD = ipsc->rNumericArgs(13);           // diffuse tau >= 0
    5891          182 :             desDayInput.DailyWBRange = ipsc->rNumericArgs(8);    // Daily wet-bulb temperature range (deltaC)
    5892              : 
    5893              :             //   N14; \field Sky Clearness
    5894          182 :             desDayInput.SkyClear = ipsc->rNumericArgs(14); // Sky Clearness (0 to 1)
    5895              : 
    5896              :             //   N15, \field Maximum Warmup Days Between Sizing Periods
    5897          182 :             if (ipsc->lNumericFieldBlanks(15)) {
    5898              :                 // Default to -1 if not input
    5899          182 :                 desDayInput.maxWarmupDays = -1;
    5900              :             } else {
    5901            0 :                 desDayInput.maxWarmupDays = int(ipsc->rNumericArgs(15));
    5902              :             }
    5903              :             //   A13, \field Begin Environment Reset Mode
    5904          182 :             if (ipsc->lAlphaFieldBlanks(13)) {
    5905          180 :                 desDayInput.suppressBegEnvReset = false;
    5906              :             } else {
    5907            2 :                 if (Util::SameString(ipsc->cAlphaArgs(13), "FullResetAtBeginEnvironment")) {
    5908            2 :                     desDayInput.suppressBegEnvReset = false;
    5909            0 :                 } else if (Util::SameString(ipsc->cAlphaArgs(13), "SuppressThermalResetAtBeginEnvironment")) {
    5910            0 :                     desDayInput.suppressBegEnvReset = true;
    5911              :                 }
    5912              :             }
    5913              :             // for PerformancePrecisionTradeoffs
    5914          182 :             if (state.dataEnvrn->forceBeginEnvResetSuppress) {
    5915            0 :                 desDayInput.suppressBegEnvReset = true;
    5916              :             }
    5917              :             //   A7,  \field Rain Indicator
    5918              :             BooleanSwitch b;
    5919              : 
    5920          182 :             if (ipsc->lAlphaFieldBlanks(7)) {
    5921            0 :                 desDayInput.RainInd = 0;
    5922          182 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    5923          182 :                 desDayInput.RainInd = (int)b;
    5924              :             } else {
    5925            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7), "No");
    5926            0 :                 desDayInput.RainInd = 0;
    5927              :             }
    5928              : 
    5929              :             //   A8,  \field Snow Indicator
    5930          182 :             if (ipsc->lAlphaFieldBlanks(8)) {
    5931            0 :                 desDayInput.SnowInd = 0;
    5932          182 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    5933          182 :                 desDayInput.SnowInd = (int)b;
    5934              :             } else {
    5935            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8), "No");
    5936            0 :                 desDayInput.SnowInd = 0;
    5937              :             }
    5938              : 
    5939              :             //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    5940              :             // check DB profile input
    5941          182 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5942          166 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    5943           32 :             } else if ((desDayInput.dryBulbRangeType = static_cast<DesDayDryBulbRangeType>(
    5944           16 :                             getEnumValue(DesDayDryBulbRangeTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(3))))) != DesDayDryBulbRangeType::Invalid) {
    5945              :             } else {
    5946            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5947            0 :                 ErrorsFound = true;
    5948            0 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    5949              :             }
    5950              : 
    5951              :             // std::string units; // not used
    5952          182 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    5953              :                 // units = "[]";
    5954            0 :                 unitType = Constant::Units::None;
    5955          182 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    5956              :                 // units = "[deltaC]";
    5957            0 :                 unitType = Constant::Units::deltaC;
    5958          182 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    5959              :                 // units = "[C]";
    5960            0 :                 unitType = Constant::Units::C;
    5961              :             }
    5962              : 
    5963          182 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile && !MaxDryBulbEntered && ipsc->cAlphaArgs(3) != "invalid field") {
    5964            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(3), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5965            0 :                 ErrorsFound = true;
    5966              :             }
    5967              : 
    5968              :             // Assume either "multiplier" option will make full use of range...
    5969          182 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Difference &&
    5970          182 :                 desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    5971          182 :                 Real64 testval = desDayInput.MaxDryBulb - desDayInput.DailyDBRange;
    5972          182 :                 if (testval < -90.0 || testval > 70.0) {
    5973            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    5974            0 :                     ShowContinueError(state, format("{} ({:.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(3), testval));
    5975            0 :                     ErrorsFound = true;
    5976              :                 }
    5977              :             }
    5978              : 
    5979              :             //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    5980          182 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Default) {
    5981              :                 // Default dry-bulb temperature Range
    5982          182 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    5983         4550 :                 for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    5984        29208 :                     for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    5985        24840 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    5986        24840 :                         Real64 WPrev = 1.0 - WNow;
    5987        24840 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutDryBulbTemp =
    5988        24840 :                             LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    5989              :                     }
    5990         4368 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    5991              :                 }
    5992              : 
    5993            0 :             } else if (ipsc->lAlphaFieldBlanks(4)) {
    5994            0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaFieldNames(3), "SCHEDULE");
    5995            0 :                 ErrorsFound = true;
    5996            0 :             } else if ((desDayInput.tempRangeSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(4))) == nullptr) {
    5997            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5998            0 :                 ErrorsFound = true;
    5999              : 
    6000              :             } else {
    6001            0 :                 std::vector<Real64> const &dayVals = desDayInput.tempRangeSched->getDayVals(state);
    6002            0 :                 auto &desDayModEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6003            0 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    6004            0 :                     for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts) {
    6005            0 :                         desDayModEnvrn(ts + 1, hr + 1).OutDryBulbTemp = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6006              :                     }
    6007              :                 }
    6008              : 
    6009            0 :                 if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6010            0 :                               state.dataWeather->spSiteSchedNums.end(),
    6011            0 :                               desDayInput.tempRangeSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6012            0 :                     state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.tempRangeSched->Num);
    6013            0 :                     SetupOutputVariable(state,
    6014              :                                         "Sizing Period Site Drybulb Temperature Range Modifier Schedule Value",
    6015              :                                         unitType,
    6016            0 :                                         state.dataWeather->spSiteSchedules(EnvrnNum).OutDryBulbTemp,
    6017              :                                         OutputProcessor::TimeStepType::Zone,
    6018              :                                         OutputProcessor::StoreType::Average,
    6019            0 :                                         ipsc->cAlphaArgs(4));
    6020              :                 }
    6021              : 
    6022            0 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    6023            0 :                     if (!desDayInput.tempRangeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6024            0 :                         Sched::ShowSevereBadMinMax(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4), Clusive::In, 0.0, Clusive::In, 1.0);
    6025            0 :                         ErrorsFound = true;
    6026              :                     }
    6027            0 :                 } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) { // delta, must be > 0.0
    6028            0 :                     if (!desDayInput.tempRangeSched->checkMinVal(state, Clusive::In, 0.0)) {
    6029            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4), Clusive::In, 0.0);
    6030            0 :                         ErrorsFound = true;
    6031              :                     }
    6032              :                 }
    6033              : 
    6034            0 :                 auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6035            0 :                 Real64 testval = std::numeric_limits<Real64>::min();
    6036            0 :                 for (int iHr = 1; iHr <= Constant::iHoursInDay; ++iHr) {
    6037            0 :                     for (int iTS = 1; iTS <= state.dataGlobal->TimeStepsInHour; ++iTS) {
    6038            0 :                         if (desDayModsEnvrn(iTS, iHr).OutDryBulbTemp > testval) testval = desDayModsEnvrn(iTS, iHr).OutDryBulbTemp;
    6039              :                     }
    6040              :                 }
    6041              : 
    6042            0 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    6043            0 :                     if (MaxDryBulbEntered) {
    6044            0 :                         ShowWarningError(state, format("{}=\"{}\", data override.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6045            0 :                         ShowContinueError(state, format("..{}=[{:.2R}] will be overwritten.", ipsc->cNumericFieldNames(3), desDayInput.MaxDryBulb));
    6046            0 :                         ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3)));
    6047            0 :                         ShowContinueError(state, format("..with max value=[{:.2R}].", testval));
    6048              :                     }
    6049            0 :                     desDayInput.MaxDryBulb = testval;
    6050              :                 }
    6051              : 
    6052            0 :                 testval = desDayInput.MaxDryBulb - testval;
    6053            0 :                 if (testval < -90.0 || testval > 70.0) {
    6054            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6055              :                     // should this be cNumericFieldNames?
    6056            0 :                     ShowContinueError(state, format("{} = ({:.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(4), testval));
    6057            0 :                     ErrorsFound = true;
    6058              :                 }
    6059              :             }
    6060              : 
    6061              :             //   A5,  \field Humidity Condition Type
    6062          182 :             desDayInput.HumIndType = static_cast<DesDayHumIndType>(getEnumValue(DesDayHumIndTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(5))));
    6063              : 
    6064          182 :             switch (desDayInput.HumIndType) {
    6065          174 :             case DesDayHumIndType::WetBulb: {
    6066              :                 //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    6067          174 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6068            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6069            0 :                     ErrorsFound = true;
    6070              :                 } else {
    6071          174 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6072              :                 }
    6073              : 
    6074          174 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6075            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6076            0 :                     ShowContinueError(
    6077              :                         state,
    6078            0 :                         format("{} = {:.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - WetBulb", desDayInput.HumIndValue));
    6079            0 :                     ErrorsFound = true;
    6080              :                 }
    6081          174 :             } break;
    6082              : 
    6083            0 :             case DesDayHumIndType::DewPoint: {
    6084            0 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6085            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6086            0 :                     ErrorsFound = true;
    6087              :                 } else {
    6088            0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6089              :                 }
    6090              : 
    6091            0 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6092            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6093            0 :                     ShowContinueError(
    6094              :                         state,
    6095            0 :                         format("{} = {:.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - DewPoint", desDayInput.HumIndValue));
    6096            0 :                     ErrorsFound = true;
    6097              :                 }
    6098            0 :             } break;
    6099              : 
    6100            0 :             case DesDayHumIndType::HumRatio: {
    6101              :                 //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    6102            0 :                 if (ipsc->lNumericFieldBlanks(6)) {
    6103            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(6), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6104            0 :                     ErrorsFound = true;
    6105              :                 } else {
    6106            0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(6); // Humidity Indicating Conditions at Max Dry-Bulb
    6107              :                 }
    6108              : 
    6109            0 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 0.03) {
    6110            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6111            0 :                     ShowContinueError(
    6112              :                         state,
    6113            0 :                         format("{} = {:.2R} is out of range [0.0, 0.03]", ipsc->cAlphaFieldNames(5) + " - Humidity-Ratio", desDayInput.HumIndValue));
    6114            0 :                     ErrorsFound = true;
    6115              :                 }
    6116            0 :             } break;
    6117              : 
    6118            1 :             case DesDayHumIndType::Enthalpy: {
    6119              :                 //   N7,  \field Enthalpy at Maximum Dry-Bulb {J/kg}.
    6120            1 :                 if (ipsc->lNumericFieldBlanks(7)) {
    6121            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(7), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6122            0 :                     ErrorsFound = true;
    6123              :                 } else {
    6124            1 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(7); // Humidity Indicating Conditions at Max Dry-Bulb
    6125              :                 }
    6126              : 
    6127            1 :                 desDayInput.HumIndType = DesDayHumIndType::Enthalpy;
    6128            1 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 130000.0) {
    6129            0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6130            0 :                     ShowContinueError(
    6131              :                         state,
    6132            0 :                         format("{} = {.0R} is out of range [0.0, 130000.0]", ipsc->cAlphaFieldNames(5) + " - Enthalpy", desDayInput.HumIndValue));
    6133            0 :                     ErrorsFound = true;
    6134              :                 }
    6135            1 :             } break;
    6136              : 
    6137            0 :             case DesDayHumIndType::RelHumSch: {
    6138              :                 // units = "[%]";
    6139            0 :                 unitType = Constant::Units::Perc;
    6140            0 :             } break;
    6141              : 
    6142            0 :             case DesDayHumIndType::WBProfMul: {
    6143              :                 // units = "[]";
    6144            0 :                 unitType = Constant::Units::None;
    6145            0 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6146            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6147            0 :                     ErrorsFound = true;
    6148              :                 } else {
    6149            0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6150              :                 }
    6151            0 :             } break;
    6152              : 
    6153            0 :             case DesDayHumIndType::WBProfDif: {
    6154              :                 // units = "[]";
    6155            0 :                 unitType = Constant::Units::None;
    6156            0 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6157            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6158            0 :                     ErrorsFound = true;
    6159              :                 } else {
    6160            0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6161              :                 }
    6162            0 :             } break;
    6163              : 
    6164            7 :             case DesDayHumIndType::WBProfDef: {
    6165            7 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6166            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6167            0 :                     ErrorsFound = true;
    6168              :                 } else {
    6169            7 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6170              :                 }
    6171            7 :             } break;
    6172              : 
    6173            0 :             default: {
    6174            0 :                 ShowWarningError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6175            0 :                 ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6176            0 :                 ShowContinueError(state, "WetBulb will be used. Maximum Dry Bulb will be used as WetBulb at Maximum Dry Bulb.");
    6177            0 :                 desDayInput.HumIndType = DesDayHumIndType::WetBulb;
    6178            0 :                 desDayInput.HumIndValue = ipsc->rNumericArgs(3);
    6179            0 :             } break;
    6180              :             } // switch (desDayInput.HumIndType)
    6181              : 
    6182              :             // resolve humidity schedule if needed
    6183              :             //   A6,  \field Humidity Condition Day Schedule Name
    6184          182 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch || desDayInput.HumIndType == DesDayHumIndType::WBProfMul ||
    6185          182 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6186            0 :                 if (ipsc->lAlphaFieldBlanks(6)) {
    6187            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6188            0 :                     ErrorsFound = true;
    6189            0 :                 } else if ((desDayInput.humIndSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(6))) == nullptr) {
    6190            0 :                     ShowWarningItemNotFound(state,
    6191              :                                             eoh,
    6192            0 :                                             ipsc->cAlphaFieldNames(6),
    6193            0 :                                             ipsc->cAlphaArgs(6),
    6194              :                                             "Default Humidity (constant for day using Humidity Indicator Temp).");
    6195              :                     // reset HumIndType ?
    6196              :                 } else {
    6197            0 :                     std::vector<Real64> const &dayVals = desDayInput.humIndSched->getDayVals(state);
    6198            0 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6199            0 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr)
    6200            0 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts)
    6201            0 :                             desDayModsEnvrn(ts + 1, hr + 1).OutRelHum = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6202              : 
    6203            0 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6204            0 :                                   state.dataWeather->spSiteSchedNums.end(),
    6205            0 :                                   desDayInput.humIndSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6206            0 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.humIndSched->Num);
    6207            0 :                         SetupOutputVariable(state,
    6208              :                                             "Sizing Period Site Humidity Condition Schedule Value",
    6209              :                                             unitType,
    6210            0 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).OutRelHum,
    6211              :                                             OutputProcessor::TimeStepType::Zone,
    6212              :                                             OutputProcessor::StoreType::Average,
    6213            0 :                                             ipsc->cAlphaArgs(6));
    6214              :                     }
    6215              : 
    6216            0 :                     switch (desDayInput.HumIndType) {
    6217            0 :                     case DesDayHumIndType::RelHumSch: {
    6218            0 :                         if (!desDayInput.humIndSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 100.0)) {
    6219            0 :                             Sched::ShowSevereBadMinMax(
    6220            0 :                                 state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 100.0);
    6221            0 :                             ErrorsFound = true;
    6222              :                         }
    6223            0 :                     } break;
    6224            0 :                     case DesDayHumIndType::WBProfMul: {
    6225              :                         // multiplier: use schedule value, check 0 <= v <= 1
    6226            0 :                         if (!desDayInput.humIndSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6227            0 :                             Sched::ShowSevereBadMinMax(
    6228            0 :                                 state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 1.0);
    6229            0 :                             ErrorsFound = true;
    6230              :                         }
    6231            0 :                     } break;
    6232            0 :                     case DesDayHumIndType::WBProfDif: {
    6233            0 :                         if (!desDayInput.humIndSched->checkMinVal(state, Clusive::In, 0.0)) {
    6234            0 :                             Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6), Clusive::In, 0.0);
    6235            0 :                             ErrorsFound = true;
    6236              :                         }
    6237            0 :                     } break;
    6238            0 :                     default: {
    6239            0 :                     } break;
    6240              :                     } // switch (desDayInput.HumIndType)
    6241              :                 }     // if (desDayInput.HumIndSchPtr == 0)
    6242              : 
    6243          182 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    6244              :                 // re WetBulbProfileDefaultMultipliers
    6245            7 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    6246          175 :                 for (int hour = 1; hour <= Constant::iHoursInDay; ++hour) {
    6247          456 :                     for (int ts = 1; ts <= state.dataGlobal->TimeStepsInHour; ++ts) {
    6248          288 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    6249          288 :                         Real64 WPrev = 1.0 - WNow;
    6250          288 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutRelHum = LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    6251              :                     }
    6252          168 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    6253              :                 }
    6254              :             }
    6255              : 
    6256              :             // verify that design WB or DP <= design DB
    6257          182 :             if (desDayInput.HumIndType == DesDayHumIndType::DewPoint || desDayInput.HumIndType == DesDayHumIndType::WetBulb ||
    6258            8 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::WBProfDef ||
    6259            1 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6260          181 :                 if (desDayInput.HumIndValue > desDayInput.MaxDryBulb) {
    6261            0 :                     ShowWarningError(state, format("{}=\"{}\", range check data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6262            0 :                     ShowContinueError(state,
    6263            0 :                                       format("..Humidity Indicator Temperature at Max Temperature={:.1R} > Max DryBulb={:.1R}",
    6264            0 :                                              desDayInput.HumIndValue,
    6265            0 :                                              desDayInput.MaxDryBulb));
    6266            0 :                     ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6267            0 :                     ShowContinueError(state, "..Conditions for day will be set to Relative Humidity = 100%");
    6268            0 :                     if (desDayInput.HumIndType == DesDayHumIndType::DewPoint) {
    6269            0 :                         desDayInput.DewPointNeedsSet = true;
    6270              :                     } else {
    6271              :                         // wet-bulb
    6272            0 :                         desDayInput.HumIndValue = desDayInput.MaxDryBulb;
    6273              :                     }
    6274              :                 }
    6275              :             }
    6276              : 
    6277              :             //   A10, \field Solar Model Indicator
    6278          182 :             if (ipsc->lAlphaFieldBlanks(10)) {
    6279            0 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6280          364 :             } else if ((desDayInput.solarModel = static_cast<DesDaySolarModel>(
    6281          182 :                             getEnumValue(DesDaySolarModelNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(10))))) != DesDaySolarModel::Invalid) {
    6282              :             } else {
    6283            0 :                 ShowWarningInvalidKey(state, eoh, ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "ASHRAE ClearSky");
    6284            0 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6285              :             }
    6286              : 
    6287          182 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    6288              :                 //   A11, \field Beam Solar Day Schedule Name
    6289            0 :                 if (ipsc->lAlphaFieldBlanks(11)) {
    6290              :                     // should have entered beam schedule
    6291            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(11));
    6292            0 :                     ErrorsFound = true;
    6293            0 :                 } else if ((desDayInput.beamSolarSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(11))) == nullptr) {
    6294            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11));
    6295            0 :                     ErrorsFound = true;
    6296              :                 } else {
    6297            0 :                     std::vector<Real64> const &dayVals = desDayInput.beamSolarSched->getDayVals(state);
    6298            0 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6299            0 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr)
    6300            0 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts)
    6301            0 :                             desDayModsEnvrn(ts + 1, hr + 1).BeamSolarRad = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6302              : 
    6303            0 :                     unitType = Constant::Units::W_m2;
    6304              :                     // units = "[W/m2]";
    6305            0 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6306            0 :                                   state.dataWeather->spSiteSchedNums.end(),
    6307            0 :                                   desDayInput.beamSolarSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6308            0 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.beamSolarSched->Num);
    6309            0 :                         SetupOutputVariable(state,
    6310              :                                             "Sizing Period Site Beam Solar Schedule Value",
    6311              :                                             unitType,
    6312            0 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).BeamSolarRad,
    6313              :                                             OutputProcessor::TimeStepType::Zone,
    6314              :                                             OutputProcessor::StoreType::Average,
    6315            0 :                                             ipsc->cAlphaArgs(11));
    6316              :                     }
    6317              : 
    6318            0 :                     if (!desDayInput.beamSolarSched->checkMinVal(state, Clusive::In, 0.0)) {
    6319            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11), Clusive::In, 0.0);
    6320            0 :                         ErrorsFound = true;
    6321              :                     }
    6322              :                 }
    6323              : 
    6324              :                 //   A12, \field Diffuse Solar Day Schedule Name
    6325            0 :                 if (ipsc->lAlphaFieldBlanks(12)) {
    6326              :                     // should have entered diffuse schedule
    6327            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(12));
    6328            0 :                     ErrorsFound = true;
    6329            0 :                 } else if ((desDayInput.diffuseSolarSched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(12))) == nullptr) {
    6330            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12));
    6331            0 :                     ErrorsFound = true;
    6332              :                 } else {
    6333            0 :                     std::vector<Real64> const &dayVals = desDayInput.diffuseSolarSched->getDayVals(state);
    6334            0 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6335            0 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr)
    6336            0 :                         for (int ts = 0; ts < state.dataGlobal->TimeStepsInHour; ++ts)
    6337            0 :                             desDayModsEnvrn(ts + 1, hr + 1).DifSolarRad = dayVals[hr * state.dataGlobal->TimeStepsInHour + ts];
    6338              : 
    6339              :                     // units = "[W/m2]";
    6340            0 :                     unitType = Constant::Units::W_m2;
    6341            0 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6342            0 :                                   state.dataWeather->spSiteSchedNums.end(),
    6343            0 :                                   desDayInput.diffuseSolarSched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6344            0 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.diffuseSolarSched->Num);
    6345            0 :                         SetupOutputVariable(state,
    6346              :                                             "Sizing Period Site Diffuse Solar Schedule Value",
    6347              :                                             unitType,
    6348            0 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).DifSolarRad,
    6349              :                                             OutputProcessor::TimeStepType::Zone,
    6350              :                                             OutputProcessor::StoreType::Average,
    6351            0 :                                             ipsc->cAlphaArgs(12));
    6352              :                     }
    6353            0 :                     if (!desDayInput.diffuseSolarSched->checkMinVal(state, Clusive::In, 0.0)) {
    6354            0 :                         Sched::ShowSevereBadMin(state, eoh, ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12), Clusive::In, 0.0);
    6355            0 :                         ErrorsFound = true;
    6356              :                     }
    6357              :                 }
    6358              : 
    6359          182 :             } else if (desDayInput.solarModel == DesDaySolarModel::ASHRAE_ClearSky) {
    6360          167 :                 if (ipsc->lNumericFieldBlanks(14)) {
    6361            0 :                     ShowWarningEmptyField(
    6362            0 :                         state, eoh, ipsc->cNumericFieldNames(14), ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "Zero clear sky (no solar)");
    6363              :                 }
    6364              :             }
    6365              : 
    6366              :             // Validate Design Day Month
    6367              : 
    6368          182 :             switch (desDayInput.Month) {
    6369          179 :             case 1:
    6370              :             case 3:
    6371              :             case 5:
    6372              :             case 7:
    6373              :             case 8:
    6374              :             case 10:
    6375              :             case 12: {
    6376          179 :                 if (desDayInput.DayOfMonth > 31) {
    6377            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6378            0 :                     ShowContinueError(
    6379              :                         state,
    6380            0 :                         format(".. invalid field: {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6381            0 :                     ErrorsFound = true;
    6382              :                 }
    6383          179 :             } break;
    6384            1 :             case 4:
    6385              :             case 6:
    6386              :             case 9:
    6387              :             case 11: {
    6388            1 :                 if (desDayInput.DayOfMonth > 30) {
    6389            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6390            0 :                     ShowContinueError(
    6391            0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6392            0 :                     ErrorsFound = true;
    6393              :                 }
    6394            1 :             } break;
    6395            2 :             case 2: {
    6396            2 :                 if (desDayInput.DayOfMonth > 28) {
    6397            0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6398            0 :                     ShowContinueError(
    6399            0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6400            0 :                     ErrorsFound = true;
    6401              :                 }
    6402            2 :             } break;
    6403            0 :             default: {
    6404            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6405            0 :                 ShowContinueError(state, format(".. invalid {} invalid (Month) [{}].", ipsc->cNumericFieldNames(1), desDayInput.Month));
    6406            0 :                 ErrorsFound = true;
    6407            0 :             } break;
    6408              :             } // switch (desDayInput.Month)
    6409              : 
    6410              :             //   A9,  \field Daylight Saving Time Indicator
    6411          182 :             if (ipsc->lAlphaFieldBlanks(9)) {
    6412            0 :                 desDayInput.DSTIndicator = 0;
    6413          182 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(9)))) != BooleanSwitch::Invalid) {
    6414          182 :                 desDayInput.DSTIndicator = (int)b;
    6415              :             } else {
    6416            0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(9), ipsc->cAlphaArgs(9), "No");
    6417            0 :                 desDayInput.DSTIndicator = 0;
    6418              :             }
    6419              : 
    6420              :             //   A2,  \field Day Type
    6421          182 :             desDayInput.DayType = getEnumValue(Sched::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    6422          182 :             if (desDayInput.DayType <= 0) {
    6423            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    6424            0 :                 ErrorsFound = true;
    6425              :             }
    6426              : 
    6427          182 :             auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    6428          182 :             envCurr.Title = desDayInput.Title;
    6429          182 :             envCurr.KindOfEnvrn = Constant::KindOfSim::DesignDay;
    6430          182 :             envCurr.DesignDayNum = EnvrnNum;
    6431          182 :             envCurr.RunPeriodDesignNum = 0;
    6432          182 :             envCurr.TotalDays = 1;
    6433          182 :             envCurr.StartMonth = desDayInput.Month;
    6434          182 :             envCurr.StartDay = desDayInput.DayOfMonth;
    6435          182 :             envCurr.EndMonth = envCurr.StartMonth;
    6436          182 :             envCurr.EndDay = envCurr.StartDay;
    6437          182 :             envCurr.DayOfWeek = 0;
    6438          182 :             envCurr.UseDST = false;
    6439          182 :             envCurr.UseHolidays = false;
    6440          182 :             envCurr.StartJDay = designDay.DayOfYear;
    6441          182 :             envCurr.EndJDay = envCurr.StartJDay;
    6442              : 
    6443              :             // create predefined report on design day
    6444          182 :             std::string envTitle = desDayInput.Title;
    6445          182 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDmaxDB, envTitle, desDayInput.MaxDryBulb);
    6446          182 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDrange, envTitle, desDayInput.DailyDBRange);
    6447          182 :             if (desDayInput.HumIndType != DesDayHumIndType::RelHumSch) {
    6448          182 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, desDayInput.HumIndValue);
    6449              :             } else {
    6450            0 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, "N/A");
    6451              :             }
    6452          364 :             OutputReportPredefined::PreDefTableEntry(
    6453          364 :                 state, state.dataOutRptPredefined->pdchDDhumTyp, envTitle, DesDayHumIndTypeStringRep[(int)desDayInput.HumIndType]);
    6454          182 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindSp, envTitle, desDayInput.WindSpeed);
    6455          182 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindDr, envTitle, desDayInput.WindDir);
    6456              :         }
    6457          106 :     }
    6458              : 
    6459          115 :     void GetLocationInfo(EnergyPlusData &state, bool &ErrorsFound)
    6460              :     {
    6461              : 
    6462              :         // SUBROUTINE INFORMATION:
    6463              :         //       AUTHOR         Richard Liesen
    6464              :         //       DATE WRITTEN   October 1997
    6465              : 
    6466              :         // PURPOSE OF THIS SUBROUTINE:
    6467              :         // This subroutine gets the location info from the IDF file; latitude,
    6468              :         //  longitude and time zone number.
    6469              : 
    6470          115 :         auto const &ipsc = state.dataIPShortCut;
    6471          115 :         ipsc->cCurrentModuleObject = "Site:Location";
    6472          115 :         int const NumLocations = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6473              : 
    6474          115 :         if (NumLocations > 1) {
    6475            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6476            0 :             ErrorsFound = true;
    6477              :         }
    6478              : 
    6479          115 :         if (NumLocations == 1) {
    6480              :             int LocNumAlpha;             // Number of alpha names being passed
    6481              :             int LocNumProp;              // Number of properties being passed
    6482              :             int IOStat;                  // IO Status when calling get input subroutine
    6483          112 :             Array1D_string LocAlphas(2); // Temporary array to transfer location info (non-numerics)
    6484          112 :             Array1D<Real64> LocProps(4); // Temporary array to transfer location info (numerics)
    6485              :             // Call Input Get routine to retrieve Location information
    6486          224 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    6487          112 :                 state, ipsc->cCurrentModuleObject, 1, LocAlphas, LocNumAlpha, LocProps, LocNumProp, IOStat);
    6488              : 
    6489              :             // set latitude, longitude, and time zone number variables
    6490          112 :             state.dataWeather->LocationTitle = LocAlphas(1);
    6491          112 :             state.dataEnvrn->Latitude = LocProps(1);
    6492          112 :             state.dataEnvrn->Longitude = LocProps(2);
    6493          112 :             state.dataEnvrn->TimeZoneNumber = LocProps(3);
    6494          112 :             state.dataEnvrn->Elevation = LocProps(4);
    6495          112 :             if (Util::SameString(LocAlphas(2), "Yes")) state.dataWeather->keepUserSiteLocationDefinition = true;
    6496          112 :             state.dataWeather->LocationGathered = true;
    6497          112 :         }
    6498          115 :     }
    6499              : 
    6500          111 :     void GetWeatherProperties(EnergyPlusData &state, bool &ErrorsFound)
    6501              :     {
    6502              : 
    6503              :         // SUBROUTINE INFORMATION:
    6504              :         //       AUTHOR         Linda Lawrie
    6505              :         //       DATE WRITTEN   July 2009
    6506              : 
    6507              :         // PURPOSE OF THIS SUBROUTINE:
    6508              :         // Weather properties are an advanced concept for simulation.  Primarily, these properties are
    6509              :         // used in the test suite runs that have specific requirements for certain properties (such as
    6510              :         // sky temperature).
    6511              : 
    6512              :         // REFERENCES:
    6513              :         // WeatherProperty:SkyTemperature,
    6514              :         //        \memo This object is used to override internal sky temperature calculations.
    6515              :         //   A1,  \field Name
    6516              :         //        \reference DesignDays
    6517              :         //        \note leave blank for RunPeriods (until we name them)
    6518              :         //        \note This field references the applicable design day or runperiod(s) if left blank.
    6519              :         //   A2,  \field Calculation Type
    6520              :         //        \type choice
    6521              :         //        \key ScheduleValue
    6522              :         //        \key DifferenceScheduleDryBulbValue
    6523              :         //        \key DifferenceScheduleDewPointValue
    6524              :         //        \key AlgorithmA
    6525              :         //   A3;  \field Schedule Name
    6526              :         //        \type object-list
    6527              :         //        \object-list DayScheduleNames
    6528              :         //        \object-list ScheduleNames
    6529              : 
    6530              :         static constexpr std::string_view routineName = "GetWeatherProperties";
    6531              : 
    6532              :         int Found;
    6533              :         int envFound;
    6534              : 
    6535          111 :         auto const &ipsc = state.dataIPShortCut;
    6536          111 :         ipsc->cCurrentModuleObject = "WeatherProperty:SkyTemperature";
    6537          111 :         state.dataWeather->NumWPSkyTemperatures = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6538              : 
    6539          111 :         state.dataWeather->WPSkyTemperature.allocate(state.dataWeather->NumWPSkyTemperatures); // by default, not used.
    6540              : 
    6541          111 :         for (int i = 1; i <= state.dataWeather->NumWPSkyTemperatures; ++i) {
    6542              :             int IOStat;
    6543              :             int NumAlpha;
    6544              :             int NumNumerics;
    6545            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6546            0 :                                                                      ipsc->cCurrentModuleObject,
    6547              :                                                                      i,
    6548            0 :                                                                      ipsc->cAlphaArgs,
    6549              :                                                                      NumAlpha,
    6550            0 :                                                                      ipsc->rNumericArgs,
    6551              :                                                                      NumNumerics,
    6552              :                                                                      IOStat,
    6553            0 :                                                                      ipsc->lNumericFieldBlanks,
    6554            0 :                                                                      ipsc->lAlphaFieldBlanks,
    6555            0 :                                                                      ipsc->cAlphaFieldNames,
    6556            0 :                                                                      ipsc->cNumericFieldNames);
    6557              : 
    6558            0 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    6559            0 :             auto &wpSkyTemp = state.dataWeather->WPSkyTemperature(i);
    6560            0 :             if (ipsc->cAlphaArgs(1).empty()) {
    6561            0 :                 Found = 0;
    6562            0 :                 for (int j = 1; j <= state.dataWeather->NumOfEnvrn; ++j) {
    6563            0 :                     auto &environJ = state.dataWeather->Environment(j);
    6564            0 :                     if (environJ.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) continue;
    6565            0 :                     if (environJ.WP_Type1 != 0) {
    6566            0 :                         ShowSevereError(state,
    6567            0 :                                         format("{}: {}=\"{}\", indicated Environment Name already assigned.",
    6568              :                                                routineName,
    6569            0 :                                                ipsc->cCurrentModuleObject,
    6570            0 :                                                ipsc->cAlphaArgs(1)));
    6571            0 :                         if (!environJ.Title.empty()) {
    6572            0 :                             ShowContinueError(state,
    6573            0 :                                               format("...Environment=\"{}\", already using {}=\"{}\".",
    6574            0 :                                                      environJ.Title,
    6575            0 :                                                      ipsc->cCurrentModuleObject,
    6576            0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6577              :                         } else {
    6578            0 :                             ShowContinueError(state,
    6579            0 :                                               format("... Runperiod Environment, already using {}=\"{}\".",
    6580            0 :                                                      ipsc->cCurrentModuleObject,
    6581            0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6582              :                         }
    6583            0 :                         ErrorsFound = true;
    6584              :                     } else {
    6585            0 :                         environJ.WP_Type1 = i;
    6586            0 :                         Found = j;
    6587              :                     }
    6588              :                 }
    6589            0 :                 if (Found == 0) {
    6590            0 :                     ShowWarningError(state, "GetWeatherProperties: WeatherProperty:SkyTemperature=blank, no run periods found.");
    6591            0 :                     ShowContinueError(state, "...SkyTemperature will not be applied.");
    6592            0 :                     continue;
    6593              :                 }
    6594              :             } else { // really a name
    6595            0 :                 Found = Util::FindItemInList(ipsc->cAlphaArgs(1), state.dataWeather->Environment, &EnvironmentData::Title);
    6596            0 :                 envFound = Found;
    6597            0 :                 if (Found == 0) {
    6598            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    6599            0 :                     ErrorsFound = true;
    6600            0 :                     continue;
    6601              :                 }
    6602              : 
    6603            0 :                 auto &envrnFound = state.dataWeather->Environment(Found);
    6604            0 :                 if (envrnFound.WP_Type1 != 0) {
    6605            0 :                     ShowSevereError(state,
    6606            0 :                                     format("{}:{}=\"{}\", indicated Environment Name already assigned.",
    6607              :                                            routineName,
    6608            0 :                                            ipsc->cCurrentModuleObject,
    6609            0 :                                            ipsc->cAlphaArgs(1)));
    6610            0 :                     ShowContinueError(state,
    6611            0 :                                       format("...Environment=\"{}\", already using {}=\"{}\".",
    6612            0 :                                              envrnFound.Title,
    6613            0 :                                              ipsc->cCurrentModuleObject,
    6614            0 :                                              state.dataWeather->WPSkyTemperature(envrnFound.WP_Type1).Name));
    6615            0 :                     ErrorsFound = true;
    6616              :                 } else {
    6617            0 :                     state.dataWeather->Environment(Found).WP_Type1 = i;
    6618              :                 }
    6619              :             }
    6620              : 
    6621            0 :             wpSkyTemp.Name = !ipsc->lAlphaFieldBlanks(1) ? ipsc->cAlphaArgs(1) : "All RunPeriods";
    6622              : 
    6623              :             // Validate Calculation Type.
    6624              :             // std::string units;
    6625              :             Constant::Units unitType;
    6626            0 :             wpSkyTemp.skyTempModel = static_cast<SkyTempModel>(getEnumValue(Weather::SkyTempModelNamesUC, ipsc->cAlphaArgs(2)));
    6627              : 
    6628            0 :             switch (wpSkyTemp.skyTempModel) {
    6629            0 :             case SkyTempModel::ScheduleValue: {
    6630            0 :                 wpSkyTemp.IsSchedule = true;
    6631              :                 // units = "[C]";
    6632            0 :                 unitType = Constant::Units::C;
    6633            0 :             } break;
    6634            0 :             case SkyTempModel::DryBulbDelta:
    6635              :             case SkyTempModel::DewPointDelta: {
    6636            0 :                 wpSkyTemp.IsSchedule = true;
    6637              :                 // units = "[deltaC]";
    6638            0 :                 unitType = Constant::Units::deltaC;
    6639            0 :             } break;
    6640            0 :             case SkyTempModel::Brunt:
    6641              :             case SkyTempModel::Idso:
    6642              :             case SkyTempModel::BerdahlMartin:
    6643              :             case SkyTempModel::ClarkAllen: {
    6644            0 :                 wpSkyTemp.IsSchedule = false;
    6645            0 :             } break;
    6646            0 :             default: {
    6647              :                 // Bad inputs are trapped by input processor
    6648            0 :                 assert(false);
    6649              :             } break;
    6650              :             } // switch (skyTempModel)
    6651              : 
    6652            0 :             if (wpSkyTemp.IsSchedule) {
    6653            0 :                 if (state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather ||
    6654            0 :                     state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    6655              :                     // See if it's a schedule.
    6656            0 :                     if ((wpSkyTemp.sched = Sched::GetSchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
    6657            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6658            0 :                         ErrorsFound = true;
    6659              :                     } else {
    6660            0 :                         wpSkyTemp.IsSchedule = true;
    6661              :                     }
    6662              :                 } else { // See if it's a valid schedule.
    6663              :                     // How can a schedule be either a yearly schedule or a day schedule?
    6664            0 :                     if ((wpSkyTemp.sched = Sched::GetDaySchedule(state, ipsc->cAlphaArgs(3))) == nullptr) {
    6665            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6666            0 :                         ErrorsFound = true;
    6667              :                     } else {
    6668            0 :                         if (envFound != 0) {
    6669            0 :                             if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6670            0 :                                           state.dataWeather->spSiteSchedNums.end(),
    6671            0 :                                           wpSkyTemp.sched->Num) == state.dataWeather->spSiteSchedNums.end()) {
    6672            0 :                                 state.dataWeather->spSiteSchedNums.emplace_back(wpSkyTemp.sched->Num);
    6673            0 :                                 SetupOutputVariable(state,
    6674              :                                                     "Sizing Period Site Sky Temperature Schedule Value",
    6675              :                                                     unitType,
    6676            0 :                                                     state.dataWeather->spSiteSchedules(envFound).SkyTemp,
    6677              :                                                     OutputProcessor::TimeStepType::Zone,
    6678              :                                                     OutputProcessor::StoreType::Average,
    6679            0 :                                                     ipsc->cAlphaArgs(3));
    6680              :                             }
    6681            0 :                             wpSkyTemp.IsSchedule = true;
    6682              :                         }
    6683              :                     }
    6684              :                 }
    6685              :             }
    6686              : 
    6687            0 :             if (!wpSkyTemp.IsSchedule && !ipsc->lAlphaFieldBlanks(4)) {
    6688            0 :                 if (BooleanSwitch b = getYesNoValue(ipsc->cAlphaArgs(4)); b != BooleanSwitch::Invalid) {
    6689            0 :                     wpSkyTemp.UseWeatherFileHorizontalIR = static_cast<bool>(b);
    6690              :                 } else {
    6691            0 :                     ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    6692            0 :                     ErrorsFound = true;
    6693              :                 }
    6694              :             } else {
    6695            0 :                 wpSkyTemp.UseWeatherFileHorizontalIR = true;
    6696              :             }
    6697              :         }
    6698          341 :         for (auto &envCurr : state.dataWeather->Environment) {
    6699          230 :             if (envCurr.WP_Type1 != 0 && state.dataWeather->NumWPSkyTemperatures >= envCurr.WP_Type1) {
    6700            0 :                 envCurr.skyTempModel = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel;
    6701            0 :                 envCurr.UseWeatherFileHorizontalIR = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).UseWeatherFileHorizontalIR;
    6702              :             }
    6703              :         }
    6704          111 :     }
    6705              : 
    6706          111 :     void GetGroundTemps(EnergyPlusData &state)
    6707              :     {
    6708              : 
    6709              :         // SUBROUTINE INFORMATION:
    6710              :         //       AUTHOR         Richard Liesen
    6711              :         //       DATE WRITTEN   October 1997
    6712              : 
    6713              :         // PURPOSE OF THIS SUBROUTINE:
    6714              :         // This file reads the Ground Temps from the input file and puts them
    6715              :         //  in a new variable.
    6716              : 
    6717              :         // Initialize Site:GroundTemperature:BuildingSurface object
    6718          222 :         state.dataWeather->siteBuildingSurfaceGroundTempsPtr =
    6719          222 :             GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteBuildingSurface, "");
    6720              : 
    6721              :         // Initialize Site:GroundTemperature:FCFactorMethod object
    6722          222 :         state.dataWeather->siteFCFactorMethodGroundTempsPtr =
    6723          222 :             GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteFCFactorMethod, "");
    6724              : 
    6725              :         // Initialize Site:GroundTemperature:Shallow object
    6726          222 :         state.dataWeather->siteShallowGroundTempsPtr = GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteShallow, "");
    6727              : 
    6728              :         // Initialize Site:GroundTemperature:Deep object
    6729          111 :         state.dataWeather->siteDeepGroundTempsPtr = GroundTemp::GetGroundTempModelAndInit(state, GroundTemp::ModelType::SiteDeep, "");
    6730          111 :     }
    6731              : 
    6732          111 :     void GetGroundReflectances(EnergyPlusData &state, bool &ErrorsFound)
    6733              :     {
    6734              : 
    6735              :         // SUBROUTINE INFORMATION:
    6736              :         //       AUTHOR         Linda Lawrie
    6737              :         //       DATE WRITTEN   March 2002
    6738              : 
    6739              :         // PURPOSE OF THIS SUBROUTINE:
    6740              :         // This file reads the Ground Reflectances from the input file (optional) and
    6741              :         // places them in the monthly array.
    6742              : 
    6743          111 :         auto const &ipsc = state.dataIPShortCut;
    6744          111 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance";
    6745          111 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6746          111 :         if (nObjs != 0) {
    6747            0 :             Array1D_string GndAlphas(1);  // Construction Alpha names defined
    6748            0 :             Array1D<Real64> GndProps(12); // Temporary array to transfer ground reflectances
    6749            0 :             if (nObjs == 1) {
    6750              :                 int GndNumAlpha; // Number of construction alpha names being passed
    6751              :                 int GndNumProp;  // dummy variable for properties being passed
    6752              :                 int IOStat;      // IO Status when calling get input subroutine
    6753              :                 // Get the object names for each construction from the input processor
    6754            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6755            0 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6756              : 
    6757            0 :                 if (GndNumProp < 12) {
    6758            0 :                     ShowSevereError(state, format("{}: Less than 12 values entered.", ipsc->cCurrentModuleObject));
    6759            0 :                     ErrorsFound = true;
    6760              :                 }
    6761              : 
    6762              :                 // Assign the ground reflectances to the variable
    6763            0 :                 state.dataWeather->GroundReflectances({1, 12}) = GndProps({1, 12});
    6764              : 
    6765              :             } else {
    6766            0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6767            0 :                 ErrorsFound = true;
    6768              :             }
    6769            0 :         }
    6770              : 
    6771              :         // Write Final Ground Reflectance Information to the initialization output file
    6772          111 :         print(state.files.eio,
    6773              :               "{}\n",
    6774              :               "! "
    6775              :               "<Site:GroundReflectance>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{dimensionless},"
    6776              :               "May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{dimensionless},Oct{"
    6777              :               "dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6778              : 
    6779          111 :         print(state.files.eio, " Site:GroundReflectance");
    6780         1443 :         for (int i = 1; i <= 12; ++i) {
    6781         1332 :             print(state.files.eio, ", {:5.2F}", state.dataWeather->GroundReflectances(i));
    6782              :         }
    6783          111 :         print(state.files.eio, "\n");
    6784          111 :     }
    6785              : 
    6786          111 :     void GetSnowGroundRefModifiers(EnergyPlusData &state, bool &ErrorsFound)
    6787              :     {
    6788              : 
    6789              :         // SUBROUTINE INFORMATION:
    6790              :         //       AUTHOR         Linda Lawrie
    6791              :         //       DATE WRITTEN   March 2002
    6792              : 
    6793              :         // PURPOSE OF THIS SUBROUTINE:
    6794              :         // This file reads the Snow Ground Reflectance Modifiers from the input file (optional) and
    6795              :         // places them in the variables.
    6796              : 
    6797          111 :         auto const &ipsc = state.dataIPShortCut;
    6798          111 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance:SnowModifier";
    6799          111 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6800          111 :         if (nObjs != 0) {
    6801            0 :             Array1D_string GndAlphas(1); // Construction Alpha names defined
    6802            0 :             Array1D<Real64> GndProps(2); // Temporary array to transfer ground reflectances
    6803            0 :             if (nObjs == 1) {
    6804              :                 int GndNumAlpha; // Number of construction alpha names being passed
    6805              :                 int GndNumProp;  // dummy variable for properties being passed
    6806              :                 int IOStat;      // IO Status when calling get input subroutine
    6807              :                 // Get the object names for each construction from the input processor
    6808            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6809            0 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6810              : 
    6811              :                 // Assign the ground reflectances to the variable
    6812            0 :                 state.dataWeather->SnowGndRefModifier = GndProps(1);
    6813            0 :                 state.dataWeather->SnowGndRefModifierForDayltg = GndProps(2);
    6814              : 
    6815              :             } else {
    6816            0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6817            0 :                 ErrorsFound = true;
    6818              :             }
    6819            0 :         }
    6820              : 
    6821              :         // Write Final Ground Reflectance Modifier Information to the initialization output file
    6822          111 :         print(state.files.eio, "{}\n", "! <Site:GroundReflectance:SnowModifier>, Normal, Daylighting {dimensionless}");
    6823              :         static constexpr std::string_view Format_720(" Site:GroundReflectance:SnowModifier, {:7.3F}, {:7.3F}\n");
    6824          111 :         print(state.files.eio, Format_720, state.dataWeather->SnowGndRefModifier, state.dataWeather->SnowGndRefModifierForDayltg);
    6825              : 
    6826          111 :         print(state.files.eio,
    6827              :               "{}\n",
    6828              :               "! "
    6829              :               "<Site:GroundReflectance:Snow>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    6830              :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    6831              :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6832          111 :         print(state.files.eio, "{}", " Site:GroundReflectance:Snow");
    6833         1443 :         for (int i = 1; i <= 12; ++i) {
    6834         1332 :             print(state.files.eio, ", {:5.2F}", max(min(state.dataWeather->GroundReflectances(i) * state.dataWeather->SnowGndRefModifier, 1.0), 0.0));
    6835              :         }
    6836          111 :         print(state.files.eio, "\n");
    6837          111 :         print(state.files.eio,
    6838              :               "{}\n",
    6839              :               "! "
    6840              :               "<Site:GroundReflectance:Snow:Daylighting>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    6841              :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    6842              :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6843          111 :         print(state.files.eio, " Site:GroundReflectance:Snow:Daylighting");
    6844         1443 :         for (nObjs = 1; nObjs <= 12; ++nObjs) {
    6845         1332 :             print(state.files.eio,
    6846              :                   ", {:5.2F}",
    6847         2664 :                   max(min(state.dataWeather->GroundReflectances(nObjs) * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0));
    6848              :         }
    6849          111 :         print(state.files.eio, "\n");
    6850          111 :     }
    6851              : 
    6852          117 :     void GetWaterMainsTemperatures(EnergyPlusData &state, bool &ErrorsFound)
    6853              :     {
    6854              : 
    6855              :         // SUBROUTINE INFORMATION:
    6856              :         //       AUTHOR         Peter Graham Ellis
    6857              :         //       DATE WRITTEN   January 2005
    6858              : 
    6859              :         // PURPOSE OF THIS SUBROUTINE:
    6860              :         // Reads the input data for the WATER MAINS TEMPERATURES object.
    6861              : 
    6862          117 :         constexpr std::string_view routineName = "GetWaterMainsTemperatures";
    6863              : 
    6864          117 :         auto const &ipsc = state.dataIPShortCut;
    6865          117 :         ipsc->cCurrentModuleObject = "Site:WaterMainsTemperature";
    6866          117 :         int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6867              : 
    6868          117 :         if (NumObjects == 1) {
    6869              :             int NumAlphas;               // Number of elements in the alpha array
    6870              :             int NumNums;                 // Number of elements in the numeric array
    6871              :             int IOStat;                  // IO Status when calling get input subroutine
    6872           12 :             Array1D_string AlphArray(2); // Character string data
    6873           12 :             Array1D<Real64> NumArray(2); // Numeric data
    6874           36 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6875           12 :                                                                      ipsc->cCurrentModuleObject,
    6876              :                                                                      1,
    6877              :                                                                      AlphArray,
    6878              :                                                                      NumAlphas,
    6879              :                                                                      NumArray,
    6880              :                                                                      NumNums,
    6881              :                                                                      IOStat,
    6882           12 :                                                                      ipsc->lNumericFieldBlanks,
    6883           12 :                                                                      ipsc->lAlphaFieldBlanks,
    6884           12 :                                                                      ipsc->cAlphaFieldNames,
    6885           12 :                                                                      ipsc->cNumericFieldNames);
    6886              : 
    6887           12 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ""};
    6888              : 
    6889           24 :             state.dataWeather->WaterMainsTempsMethod =
    6890           12 :                 static_cast<Weather::WaterMainsTempCalcMethod>(getEnumValue(waterMainsCalcMethodNamesUC, AlphArray(1)));
    6891              : 
    6892           12 :             switch (state.dataWeather->WaterMainsTempsMethod) {
    6893            0 :             case WaterMainsTempCalcMethod::Schedule: {
    6894            0 :                 if (ipsc->lAlphaFieldBlanks(2)) {
    6895            0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
    6896            0 :                     ErrorsFound = true;
    6897            0 :                 } else if ((state.dataWeather->waterMainsTempSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
    6898            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    6899            0 :                     ErrorsFound = true;
    6900              :                 }
    6901            0 :             } break;
    6902              : 
    6903            6 :             case WaterMainsTempCalcMethod::Correlation: {
    6904            6 :                 if (NumNums == 0) {
    6905            0 :                     ShowSevereError(state, format("{}: Missing Annual Average and Maximum Difference fields.", ipsc->cCurrentModuleObject));
    6906            0 :                     ErrorsFound = true;
    6907            6 :                 } else if (NumNums == 1) {
    6908            0 :                     ShowSevereError(state, format("{}: Missing Maximum Difference field.", ipsc->cCurrentModuleObject));
    6909            0 :                     ErrorsFound = true;
    6910              :                 } else {
    6911            6 :                     state.dataWeather->WaterMainsTempsAnnualAvgAirTemp = NumArray(1);
    6912            6 :                     state.dataWeather->WaterMainsTempsMaxDiffAirTemp = NumArray(2);
    6913              :                 }
    6914            6 :             } break;
    6915            6 :             case WaterMainsTempCalcMethod::CorrelationFromWeatherFile: {
    6916              :                 // No action
    6917            6 :             } break;
    6918            0 :             default: {
    6919            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), AlphArray(1));
    6920            0 :                 ErrorsFound = true;
    6921            0 :             } break;
    6922              :             } // switch
    6923              : 
    6924          117 :         } else if (NumObjects > 1) {
    6925            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6926            0 :             ErrorsFound = true;
    6927              :         }
    6928          117 :     }
    6929              : 
    6930       326128 :     void CalcWaterMainsTemp(EnergyPlusData &state)
    6931              :     {
    6932              : 
    6933              :         // SUBROUTINE INFORMATION:
    6934              :         //       AUTHOR         Peter Graham Ellis
    6935              :         //       DATE WRITTEN   January 2005
    6936              :         //       MODIFIED       June 2018, B. Nigusse
    6937              : 
    6938              :         // PURPOSE OF THIS SUBROUTINE:
    6939              :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    6940              : 
    6941              :         // METHODOLOGY EMPLOYED:
    6942              :         // Water mains temperature is either taken from a schedule or calculated by a correlation.  The correlation
    6943              :         // is fit to Fahrenheit units, so the air temperature values are first convert to F, then mains temperature
    6944              :         // is calculated and converted back to C.
    6945              : 
    6946       326128 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    6947            0 :         case WaterMainsTempCalcMethod::Schedule:
    6948            0 :             state.dataEnvrn->WaterMainsTemp = state.dataWeather->waterMainsTempSched->getCurrentVal();
    6949            0 :             break;
    6950        19946 :         case WaterMainsTempCalcMethod::Correlation:
    6951        19946 :             state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(
    6952        19946 :                 state, state.dataWeather->WaterMainsTempsAnnualAvgAirTemp, state.dataWeather->WaterMainsTempsMaxDiffAirTemp);
    6953        19946 :             break;
    6954            6 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    6955            6 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    6956            6 :                 state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(state,
    6957            6 :                                                                                 state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp,
    6958            6 :                                                                                 state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff);
    6959              :             } else {
    6960            0 :                 state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    6961              :             }
    6962            6 :             break;
    6963       306176 :         default:
    6964       306176 :             state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    6965       306176 :             break;
    6966              :         }
    6967       326128 :     }
    6968              : 
    6969              :     Real64
    6970        19952 :     WaterMainsTempFromCorrelation(EnergyPlusData const &state, Real64 const AnnualOAAvgDryBulbTemp, Real64 const MonthlyOAAvgDryBulbTempMaxDiff)
    6971              :     {
    6972              : 
    6973              :         // SUBROUTINE INFORMATION:
    6974              :         //       AUTHOR         Peter Graham Ellis
    6975              :         //       DATE WRITTEN   January 2005
    6976              :         //       MODIFIED       B Nigusse June 2018 (Refactored)
    6977              : 
    6978              :         // PURPOSE OF THIS SUBROUTINE:
    6979              :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    6980              : 
    6981              :         // METHODOLOGY EMPLOYED:
    6982              :         // Water mains temperature calculated by a correlation.  The correlation is fit to Fahrenheit units, so the
    6983              :         // air temperature values are first convert to F, then mains temperature is calculated and converted back to C.
    6984              :         // used for Calculated Method: 'Correlation' and 'CorrelationFromWeatherFile'.
    6985              : 
    6986              :         // REFERENCES:
    6987              :         // Correlation developed by Jay Burch and Craig Christensen at NREL, described in:
    6988              :         // Hendron, R., Anderson, R., Christensen, C., Eastment, M., and Reeves, P.  2004.  "Development of an Energy
    6989              :         // Savings Benchmark for All Residential End-Uses", Proceedings of SimBuild 2004, IBPSA-USA National Conference,
    6990              :         // Boulder, CO, August 4 - 6, 2004.
    6991              : 
    6992              :         // Annual Average Outdoor Air Temperature (F)
    6993        19952 :         Real64 const Tavg = AnnualOAAvgDryBulbTemp * (9.0 / 5.0) + 32.0;
    6994              :         // Maximum difference in monthly average outdoor air temperatures (deltaF)
    6995        19952 :         Real64 const Tdiff = MonthlyOAAvgDryBulbTempMaxDiff * (9.0 / 5.0);
    6996              : 
    6997        19952 :         Real64 const Ratio = 0.4 + 0.01 * (Tavg - 44.0);
    6998        19952 :         Real64 const Lag = 35.0 - 1.0 * (Tavg - 44.0);
    6999        19952 :         Real64 constexpr Offset = 6.0;
    7000        19952 :         int const latitude_sign = (state.dataEnvrn->Latitude >= 0) ? 1 : -1;
    7001              : 
    7002              :         // calculated water main temp (F)
    7003              :         Real64 CurrentWaterMainsTemp =
    7004        19952 :             Tavg + Offset +
    7005        19952 :             Ratio * (Tdiff / 2.0) * latitude_sign * std::sin((0.986 * (state.dataEnvrn->DayOfYear - 15.0 - Lag) - 90) * Constant::DegToRad);
    7006              : 
    7007        19952 :         if (CurrentWaterMainsTemp < 32.0) CurrentWaterMainsTemp = 32.0;
    7008              : 
    7009              :         // Convert F to C
    7010        19952 :         return (CurrentWaterMainsTemp - 32.0) * (5.0 / 9.0);
    7011              :     }
    7012          111 :     void GetWeatherStation(EnergyPlusData &state, bool &ErrorsFound)
    7013              :     {
    7014              : 
    7015              :         // SUBROUTINE INFORMATION:
    7016              :         //       AUTHOR         Peter Graham Ellis
    7017              :         //       DATE WRITTEN   January 2006
    7018              : 
    7019              :         // PURPOSE OF THIS SUBROUTINE:
    7020              :         // Reads the input data for the WEATHER STATION object.
    7021              : 
    7022          111 :         auto const &ipsc = state.dataIPShortCut;
    7023          111 :         ipsc->cCurrentModuleObject = "Site:WeatherStation";
    7024          111 :         int const NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    7025              : 
    7026              :         // Default conditions for a weather station in an open field at a height of 10 m. (These should match the IDD defaults.)
    7027          111 :         Real64 WeatherFileWindSensorHeight = 10.0; // Height of the wind sensor at the weather station, i.e., weather file
    7028          111 :         Real64 WeatherFileWindExp = 0.14;          // Exponent for the wind velocity profile at the weather station
    7029          111 :         Real64 WeatherFileWindBLHeight = 270.0;    // Boundary layer height for the wind velocity profile at the weather station (m)
    7030          111 :         Real64 WeatherFileTempSensorHeight = 1.5;  // Height of the air temperature sensor at the weather station (m)
    7031              : 
    7032          111 :         if (NumObjects == 1) {
    7033              :             int NumAlphas;               // Number of elements in the alpha array
    7034              :             int NumNums;                 // Number of elements in the numeric array
    7035              :             int IOStat;                  // IO Status when calling get input subroutine
    7036            0 :             Array1D_string AlphArray(1); // Character string data
    7037            0 :             Array1D<Real64> NumArray(4); // Numeric data
    7038            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    7039            0 :                 state, ipsc->cCurrentModuleObject, 1, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    7040              : 
    7041            0 :             if (NumNums > 0) WeatherFileWindSensorHeight = NumArray(1);
    7042            0 :             if (NumNums > 1) WeatherFileWindExp = NumArray(2);
    7043            0 :             if (NumNums > 2) WeatherFileWindBLHeight = NumArray(3);
    7044            0 :             if (NumNums > 3) WeatherFileTempSensorHeight = NumArray(4);
    7045              : 
    7046          111 :         } else if (NumObjects > 1) {
    7047            0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    7048            0 :             ErrorsFound = true;
    7049              :         }
    7050              : 
    7051          111 :         state.dataEnvrn->WeatherFileWindModCoeff = std::pow(WeatherFileWindBLHeight / WeatherFileWindSensorHeight, WeatherFileWindExp);
    7052          222 :         state.dataEnvrn->WeatherFileTempModCoeff = DataEnvironment::AtmosphericTempGradient * DataEnvironment::EarthRadius *
    7053          111 :                                                    WeatherFileTempSensorHeight / (DataEnvironment::EarthRadius + WeatherFileTempSensorHeight);
    7054              : 
    7055              :         // Write to the initialization output file
    7056          111 :         print(state.files.eio,
    7057              :               "{}\n",
    7058              :               "! <Environment:Weather Station>,Wind Sensor Height Above Ground {m},Wind Speed Profile Exponent "
    7059              :               "{},Wind Speed Profile Boundary Layer Thickness {m},Air Temperature Sensor Height Above Ground {m},Wind "
    7060              :               "Speed Modifier Coefficient-Internal,Temperature Modifier Coefficient-Internal");
    7061              : 
    7062              :         // Formats
    7063              :         static constexpr std::string_view Format_720("Environment:Weather Station,{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7064          111 :         print(state.files.eio,
    7065              :               Format_720,
    7066              :               WeatherFileWindSensorHeight,
    7067              :               WeatherFileWindExp,
    7068              :               WeatherFileWindBLHeight,
    7069              :               WeatherFileTempSensorHeight,
    7070          111 :               state.dataEnvrn->WeatherFileWindModCoeff,
    7071          111 :               state.dataEnvrn->WeatherFileTempModCoeff);
    7072          111 :     }
    7073              : 
    7074       326120 :     void DayltgCurrentExtHorizIllum(EnergyPlusData &state)
    7075              :     {
    7076              : 
    7077              :         // SUBROUTINE INFORMATION:
    7078              :         //       AUTHOR         Fred Winkelmann
    7079              :         //       DATE WRITTEN   July 1997
    7080              :         //       MODIFIED       Nov98 (FW); Nov 2000 (FW)
    7081              : 
    7082              :         // PURPOSE OF THIS SUBROUTINE:
    7083              :         // CALCULATES EXTERIOR DAYLIGHT ILLUMINANCE AND LUMINOUS EFFICACY
    7084              : 
    7085              :         // METHODOLOGY EMPLOYED:
    7086              :         // CALLED by SetCurrentWeather.
    7087              :         // CALCULATES THE CURRENT-TIME-STEP
    7088              :         // ILLUMINANCE ON AN UNOBSTRUCTED HORIZONTAL SURFACE FROM THE
    7089              :         // THE SKY AND FROM DIRECT SUN.
    7090              : 
    7091              :         // REFERENCES:
    7092              :         // Based on DOE-2.1E subroutine DEXTIL.
    7093              : 
    7094              :         // SOLCOS(3), below, is the cosine of the solar zenith angle.
    7095       326120 :         if (state.dataEnvrn->SunIsUp) {
    7096              :             // Exterior horizontal beam irradiance (W/m2)
    7097       159691 :             Real64 SDIRH = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z;
    7098              :             // Exterior horizontal sky diffuse irradiance (W/m2)
    7099       159691 :             Real64 SDIFH = state.dataEnvrn->DifSolarRad;
    7100              :             // Fraction of sky covered by clouds
    7101       159691 :             state.dataEnvrn->CloudFraction = pow_2(SDIFH / (SDIRH + SDIFH + 0.0001));
    7102              :             // Luminous efficacy of sky diffuse solar and beam solar (lumens/W);
    7103              :             // Horizontal illuminance from sky and horizontal beam illuminance (lux)
    7104              :             // obtained from solar quantities on weather file and luminous efficacy.
    7105              : 
    7106       159691 :             DayltgLuminousEfficacy(state, state.dataEnvrn->PDIFLW, state.dataEnvrn->PDIRLW);
    7107       159691 :             state.dataEnvrn->HISKF = SDIFH * state.dataEnvrn->PDIFLW;
    7108       159691 :             state.dataEnvrn->HISUNF = SDIRH * state.dataEnvrn->PDIRLW;
    7109       159691 :             state.dataEnvrn->HISUNFnorm = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->PDIRLW;
    7110              :         } else {
    7111       166429 :             state.dataEnvrn->CloudFraction = 0.0;
    7112       166429 :             state.dataEnvrn->PDIFLW = 0.0;
    7113       166429 :             state.dataEnvrn->PDIRLW = 0.0;
    7114       166429 :             state.dataEnvrn->HISKF = 0.0;
    7115       166429 :             state.dataEnvrn->HISUNF = 0.0;
    7116       166429 :             state.dataEnvrn->HISUNFnorm = 0.0;
    7117       166429 :             state.dataEnvrn->SkyClearness = 0.0;
    7118       166429 :             state.dataEnvrn->SkyBrightness = 0.0;
    7119              :         }
    7120       326120 :     }
    7121              : 
    7122       159691 :     void DayltgLuminousEfficacy(EnergyPlusData &state,
    7123              :                                 Real64 &DiffLumEff, // Luminous efficacy of sky diffuse solar radiation (lum/W)
    7124              :                                 Real64 &DirLumEff   // Luminous efficacy of beam solar radiation (lum/W)
    7125              :     )
    7126              :     {
    7127              :         // SUBROUTINE INFORMATION:
    7128              :         //       AUTHOR         Fred Winkelmann
    7129              :         //       DATE WRITTEN   July 1997
    7130              :         //       MODIFIED       August 2009, BG fixed upper bound for sky clearness bin 7
    7131              : 
    7132              :         // PURPOSE OF THIS SUBROUTINE:
    7133              :         // Uses diffuse horizontal solar irradiance, direct normal solar
    7134              :         // irradiance, atmospheric moisture and sun position
    7135              :         // to determine the luminous efficacy in lumens/watt
    7136              :         // of sky diffuse solar radiation and direct normal solar radiation.
    7137              :         // Based on an empirical method described in
    7138              :         // R. Perez, P. Ineichen, R. Seals, J. Michalsky and R. Stewart,
    7139              :         // "Modeling daylight availability and irradiance components from direct
    7140              :         // global irradiance components from direct and global irradiance,"
    7141              :         // Solar Energy 44 (1990) 271-289.
    7142              : 
    7143              :         // Diffuse luminous efficacy coefficients
    7144              :         static constexpr std::array<Real64, 8> ADiffLumEff = {97.24, 107.22, 104.97, 102.39, 100.71, 106.42, 141.88, 152.23};
    7145              :         static constexpr std::array<Real64, 8> BDiffLumEff = {-0.46, 1.15, 2.96, 5.59, 5.94, 3.83, 1.90, 0.35};
    7146              :         static constexpr std::array<Real64, 8> CDiffLumEff = {12.00, 0.59, -5.53, -13.95, -22.75, -36.15, -53.24, -45.27};
    7147              :         static constexpr std::array<Real64, 8> DDiffLumEff = {-8.91, -3.95, -8.77, -13.90, -23.74, -28.83, -14.03, -7.98};
    7148              :         // Direct luminous efficacy coefficients
    7149              :         static constexpr std::array<Real64, 8> ADirLumEff = {57.20, 98.99, 109.83, 110.34, 106.36, 107.19, 105.75, 101.18};
    7150              :         static constexpr std::array<Real64, 8> BDirLumEff = {-4.55, -3.46, -4.90, -5.84, -3.97, -1.25, 0.77, 1.58};
    7151              :         static constexpr std::array<Real64, 8> CDirLumEff = {-2.98, -1.21, -1.71, -1.99, -1.75, -1.51, -1.26, -1.10};
    7152              :         static constexpr std::array<Real64, 8> DDirLumEff = {117.12, 12.38, -8.81, -4.56, -6.16, -26.73, -34.44, -8.29};
    7153              :         // Monthly exterrestrial direct normal illuminance (lum/m2)
    7154              :         static constexpr std::array<Real64, 12> ExtraDirNormIll = {
    7155              :             131153.0, 130613.0, 128992.0, 126816.0, 124731.0, 123240.0, 122652.0, 123120.0, 124576.0, 126658.0, 128814.0, 130471.0};
    7156              : 
    7157       159691 :         Real64 const SunZenith = std::acos(state.dataEnvrn->SOLCOS.z); // Solar zenith angle (radians)
    7158       159691 :         Real64 const SunAltitude = Constant::PiOvr2 - SunZenith;       // Solar altitude angle (radians)
    7159       159691 :         Real64 const SinSunAltitude = std::sin(SunAltitude);
    7160              :         // Clearness of sky. SkyClearness close to 1.0 corresponds to an overcast sky.
    7161              :         // SkyClearness > 6 is a clear sky.
    7162              :         // DifSolarRad is the diffuse horizontal irradiance.
    7163              :         // BeamSolarRad is the direct normal irradiance.
    7164       159691 :         Real64 const Zeta = 1.041 * pow_3(SunZenith);
    7165       319382 :         state.dataEnvrn->SkyClearness =
    7166       159691 :             ((state.dataEnvrn->DifSolarRad + state.dataEnvrn->BeamSolarRad) / (state.dataEnvrn->DifSolarRad + 0.0001) + Zeta) / (1.0 + Zeta);
    7167              :         // Relative optical air mass
    7168              :         Real64 const relAirMass =
    7169       159691 :             (1.0 - 0.1 * state.dataEnvrn->Elevation / 1000.0) / (SinSunAltitude + 0.15 / std::pow(SunAltitude / Constant::DegToRad + 3.885, 1.253));
    7170              :         // In the following, 93.73 is the extraterrestrial luminous efficacy
    7171       159691 :         state.dataEnvrn->SkyBrightness = (state.dataEnvrn->DifSolarRad * 93.73) * relAirMass / ExtraDirNormIll[state.dataEnvrn->Month - 1];
    7172              :         int ISkyClearness; // Sky clearness bin
    7173       159691 :         if (state.dataEnvrn->SkyClearness <= 1.065) {
    7174        62364 :             ISkyClearness = 0;
    7175        97327 :         } else if (state.dataEnvrn->SkyClearness <= 1.23) {
    7176         2739 :             ISkyClearness = 1;
    7177        94588 :         } else if (state.dataEnvrn->SkyClearness <= 1.50) {
    7178         3360 :             ISkyClearness = 2;
    7179        91228 :         } else if (state.dataEnvrn->SkyClearness <= 1.95) {
    7180         4314 :             ISkyClearness = 3;
    7181        86914 :         } else if (state.dataEnvrn->SkyClearness <= 2.80) {
    7182        12286 :             ISkyClearness = 4;
    7183        74628 :         } else if (state.dataEnvrn->SkyClearness <= 4.50) {
    7184        28260 :             ISkyClearness = 5;
    7185        46368 :         } else if (state.dataEnvrn->SkyClearness <= 6.20) {
    7186        17161 :             ISkyClearness = 6;
    7187              :         } else {
    7188        29207 :             ISkyClearness = 7;
    7189              :         }
    7190              : 
    7191              :         // Atmospheric moisture (cm of precipitable water)
    7192       159691 :         Real64 const AtmosMoisture = std::exp(0.07 * state.dataEnvrn->OutDewPointTemp - 0.075);
    7193              :         // Sky diffuse luminous efficacy
    7194       159691 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7195        51559 :             DiffLumEff = 0.0;
    7196              :         } else {
    7197       108132 :             DiffLumEff = ADiffLumEff[ISkyClearness] + BDiffLumEff[ISkyClearness] * AtmosMoisture +
    7198       108132 :                          CDiffLumEff[ISkyClearness] * state.dataEnvrn->SOLCOS.z +
    7199       108132 :                          DDiffLumEff[ISkyClearness] * std::log(state.dataEnvrn->SkyBrightness);
    7200              :         }
    7201              :         // Direct normal luminous efficacy
    7202       159691 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7203        51559 :             DirLumEff = 0.0;
    7204              :         } else {
    7205       108132 :             DirLumEff =
    7206       108132 :                 max(0.0,
    7207       108132 :                     ADirLumEff[ISkyClearness] + BDirLumEff[ISkyClearness] * AtmosMoisture +
    7208       108132 :                         CDirLumEff[ISkyClearness] * std::exp(5.73 * SunZenith - 5.0) + DDirLumEff[ISkyClearness] * state.dataEnvrn->SkyBrightness);
    7209              :         }
    7210       159691 :     }
    7211              : 
    7212          113 :     Real64 GetSTM(Real64 const Longitude) // Longitude from user input
    7213              :     {
    7214              :         // FUNCTION INFORMATION:
    7215              :         //       AUTHOR         Linda K. Lawrie
    7216              :         //       DATE WRITTEN   August 2003
    7217              : 
    7218              :         // PURPOSE OF THIS FUNCTION:
    7219              :         // This function determines the "standard time meridian" from the input
    7220              :         // longitude. Calculates the proper Meridian from Longitude.  This
    7221              :         // value is needed for weather calculations so that the sun comes
    7222              :         // up and goes down at the right times.
    7223              : 
    7224              :         Real64 GetSTM;
    7225              : 
    7226          113 :         Array1D<Real64> longl({-12, 12}); // Lower Longitude value for a Time Zone
    7227          113 :         Array1D<Real64> longh({-12, 12}); // Upper Longitude value for a Time Zone
    7228              : 
    7229          113 :         GetSTM = 0.0;
    7230              : 
    7231          113 :         longl(0) = -7.5;
    7232          113 :         longh(0) = 7.5;
    7233         1469 :         for (int i = 1; i <= 12; ++i) {
    7234         1356 :             longl(i) = longl(i - 1) + 15.0;
    7235         1356 :             longh(i) = longh(i - 1) + 15.0;
    7236              :         }
    7237         1469 :         for (int i = 1; i <= 12; ++i) {
    7238         1356 :             longl(-i) = longl(-i + 1) - 15.0;
    7239         1356 :             longh(-i) = longh(-i + 1) - 15.0;
    7240              :         }
    7241          113 :         Real64 temp = mod(Longitude, 360.0);
    7242          113 :         if (temp > 180.0) temp -= 180.0;
    7243              :         Real64 tz; // resultant tz meridian
    7244          808 :         for (int i = -12; i <= 12; ++i) {
    7245          808 :             if (temp > longl(i) && temp <= longh(i)) {
    7246          113 :                 tz = mod(i, 24.0);
    7247          113 :                 GetSTM = tz;
    7248          113 :                 break;
    7249              :             }
    7250              :         }
    7251              : 
    7252          113 :         return GetSTM;
    7253          113 :     }
    7254              : 
    7255          241 :     void ProcessEPWHeader(EnergyPlusData &state, EpwHeaderType const headerType, std::string &Line, bool &ErrorsFound)
    7256              :     {
    7257              : 
    7258              :         // SUBROUTINE INFORMATION:
    7259              :         //       AUTHOR         Linda Lawrie
    7260              :         //       DATE WRITTEN   December 1999
    7261              : 
    7262              :         // PURPOSE OF THIS SUBROUTINE:
    7263              :         // This subroutine processes each header line in the EPW weather file.
    7264              : 
    7265              :         // METHODOLOGY EMPLOYED:
    7266              :         // File is positioned to the correct line, then backspaced.  This routine
    7267              :         // reads in the line and processes as appropriate.
    7268              : 
    7269              :         Weather::DateType dateType;
    7270              :         int NumHdArgs;
    7271              : 
    7272              :         // Strip off Header value from Line
    7273          241 :         std::string::size_type Pos = index(Line, ',');
    7274          241 :         if ((Pos == std::string::npos) && !((headerType == EpwHeaderType::Comments1) || (headerType == EpwHeaderType::Comments2))) {
    7275            0 :             ShowSevereError(state, "Invalid Header line in in.epw -- no commas");
    7276            0 :             ShowContinueError(state, format("Line={}", Line));
    7277            0 :             ShowFatalError(state, "Previous conditions cause termination.");
    7278              :         }
    7279          241 :         if (Pos != std::string::npos) Line.erase(0, Pos + 1);
    7280              : 
    7281          241 :         switch (headerType) {
    7282           30 :         case Weather::EpwHeaderType::Location: {
    7283              : 
    7284              :             // LOCATION, A1 [City], A2 [State/Province/Region], A3 [Country],
    7285              :             // A4 [Source], N1 [WMO], N2 [Latitude],
    7286              :             // N3 [Longitude], N4 [Time Zone], N5 [Elevation {m}]
    7287              : 
    7288           30 :             NumHdArgs = 9;
    7289          300 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7290          270 :                 strip(Line);
    7291          270 :                 Pos = index(Line, ',');
    7292          270 :                 if (Pos == std::string::npos) {
    7293           29 :                     if (len(Line) == 0) {
    7294            0 :                         while (Pos == std::string::npos) {
    7295            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7296            0 :                             strip(Line);
    7297            0 :                             uppercase(Line);
    7298            0 :                             Pos = index(Line, ',');
    7299              :                         }
    7300              :                     } else {
    7301           29 :                         Pos = len(Line);
    7302              :                     }
    7303              :                 }
    7304              : 
    7305          270 :                 switch (i) {
    7306           30 :                 case 1:
    7307           30 :                     state.dataWeather->EPWHeaderTitle = stripped(Line.substr(0, Pos));
    7308           30 :                     break;
    7309           90 :                 case 2:
    7310              :                 case 3:
    7311              :                 case 4:
    7312           90 :                     state.dataWeather->EPWHeaderTitle = strip(state.dataWeather->EPWHeaderTitle) + ' ' + stripped(Line.substr(0, Pos));
    7313           90 :                     break;
    7314           30 :                 case 5:
    7315           30 :                     state.dataWeather->EPWHeaderTitle += " WMO#=" + stripped(Line.substr(0, Pos));
    7316           30 :                     break;
    7317          120 :                 case 6:
    7318              :                 case 7:
    7319              :                 case 8:
    7320              :                 case 9: {
    7321              :                     bool errFlag;
    7322          120 :                     Real64 const Number = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7323          120 :                     if (!errFlag) {
    7324          120 :                         switch (i) {
    7325           30 :                         case 6:
    7326           30 :                             state.dataWeather->WeatherFileLatitude = Number;
    7327           30 :                             break;
    7328           30 :                         case 7:
    7329           30 :                             state.dataWeather->WeatherFileLongitude = Number;
    7330           30 :                             break;
    7331           30 :                         case 8:
    7332           30 :                             state.dataWeather->WeatherFileTimeZone = Number;
    7333           30 :                             break;
    7334           30 :                         case 9:
    7335           30 :                             state.dataWeather->WeatherFileElevation = Number;
    7336           30 :                             break;
    7337            0 :                         default:
    7338            0 :                             break;
    7339              :                         }
    7340              :                     }
    7341          120 :                 } break;
    7342            0 :                 default:
    7343            0 :                     ShowSevereError(state, format("GetEPWHeader:LOCATION, invalid numeric={}", Line.substr(0, Pos)));
    7344            0 :                     ErrorsFound = true;
    7345            0 :                     break;
    7346              :                 }
    7347          270 :                 Line.erase(0, Pos + 1);
    7348              :             }
    7349           30 :             state.dataEnvrn->WeatherFileLocationTitle = stripped(state.dataWeather->EPWHeaderTitle);
    7350           30 :         } break;
    7351           30 :         case Weather::EpwHeaderType::TypicalExtremePeriods: {
    7352           30 :             strip(Line);
    7353           30 :             Pos = index(Line, ',');
    7354           30 :             if (Pos == std::string::npos) {
    7355            0 :                 if (len(Line) == 0) {
    7356            0 :                     while (Pos == std::string::npos && len(Line) == 0) {
    7357            0 :                         Line = state.files.inputWeatherFile.readLine().data;
    7358            0 :                         strip(Line);
    7359            0 :                         Pos = index(Line, ',');
    7360              :                     }
    7361              :                 } else {
    7362            0 :                     Pos = len(Line);
    7363              :                 }
    7364              :             }
    7365              :             bool IOStatus;
    7366           30 :             state.dataWeather->NumEPWTypExtSets = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7367           30 :             Line.erase(0, Pos + 1);
    7368           30 :             state.dataWeather->TypicalExtremePeriods.allocate(state.dataWeather->NumEPWTypExtSets);
    7369           30 :             int TropExtremeCount = 0;
    7370          207 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7371          177 :                 strip(Line);
    7372          177 :                 Pos = index(Line, ',');
    7373          177 :                 if (Pos != std::string::npos) {
    7374          177 :                     state.dataWeather->TypicalExtremePeriods(i).Title = Line.substr(0, Pos);
    7375          177 :                     Line.erase(0, Pos + 1);
    7376              :                 } else {
    7377            0 :                     ShowWarningError(state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={}", Line.substr(0, Pos)));
    7378            0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7379            0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7380            0 :                     break;
    7381              :                 }
    7382          177 :                 Pos = index(Line, ',');
    7383          177 :                 if (Pos != std::string::npos) {
    7384          177 :                     state.dataWeather->TypicalExtremePeriods(i).TEType = Line.substr(0, Pos);
    7385          177 :                     Line.erase(0, Pos + 1);
    7386          177 :                     if (Util::SameString(state.dataWeather->TypicalExtremePeriods(i).TEType, "EXTREME")) {
    7387           60 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MAX")) {
    7388            1 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7389           59 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MIN")) {
    7390            1 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7391           58 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MAX")) {
    7392            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMax";
    7393           58 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MIN")) {
    7394            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMin";
    7395              :                             // to account for problems earlier in weather files:
    7396           58 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7397            0 :                             if (TropExtremeCount == 0) {
    7398            0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Max";
    7399            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7400            0 :                                 ++TropExtremeCount;
    7401            0 :                             } else if (TropExtremeCount == 1) {
    7402            0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Min";
    7403            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7404            0 :                                 ++TropExtremeCount;
    7405              :                             }
    7406              :                         } else { // make new short titles
    7407           58 :                             if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7408           29 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7409           29 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7410           29 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7411            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7412            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7413            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7414            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7415            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7416            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7417            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7418            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7419            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7420            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7421            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7422            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7423            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7424            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7425            0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7426            0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7427              :                             }
    7428              :                         }
    7429              :                     } else { // not extreme
    7430          117 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7431           29 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7432           88 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7433           29 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7434           59 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7435            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7436           59 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7437            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7438           59 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7439           29 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7440           30 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7441            1 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7442           29 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7443            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7444           29 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7445            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7446           29 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7447            0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7448           29 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7449           29 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7450              :                         }
    7451              :                     }
    7452              :                 } else {
    7453            0 :                     ShowWarningError(state,
    7454            0 :                                      format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={} {}",
    7455            0 :                                             state.dataWeather->TypicalExtremePeriods(i).Title,
    7456            0 :                                             Line.substr(0, Pos)));
    7457            0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7458            0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7459            0 :                     break;
    7460              :                 }
    7461              :                 int PMonth;
    7462              :                 int PDay;
    7463              :                 int PWeekDay;
    7464          177 :                 Pos = index(Line, ',');
    7465          177 :                 if (Pos != std::string::npos) {
    7466          177 :                     std::string dateStringUC = Line.substr(0, Pos);
    7467          177 :                     dateStringUC = uppercase(dateStringUC);
    7468          177 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7469          177 :                     if (dateType != DateType::Invalid) {
    7470          177 :                         if (PMonth != 0 && PDay != 0) {
    7471          177 :                             state.dataWeather->TypicalExtremePeriods(i).StartMonth = PMonth;
    7472          177 :                             state.dataWeather->TypicalExtremePeriods(i).StartDay = PDay;
    7473              :                         }
    7474              :                     } else {
    7475            0 :                         ShowSevereError(
    7476            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7477            0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7478            0 :                         ErrorsFound = true;
    7479              :                     }
    7480          177 :                     Line.erase(0, Pos + 1);
    7481          177 :                 }
    7482          177 :                 Pos = index(Line, ',');
    7483          177 :                 if (Pos != std::string::npos) {
    7484          148 :                     std::string dateStringUC = Line.substr(0, Pos);
    7485          148 :                     dateStringUC = uppercase(dateStringUC);
    7486          148 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7487          148 :                     if (dateType != DateType::Invalid) {
    7488          148 :                         if (PMonth != 0 && PDay != 0) {
    7489          148 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7490          148 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7491              :                         }
    7492              :                     } else {
    7493            0 :                         ShowSevereError(
    7494            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7495            0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7496            0 :                         ErrorsFound = true;
    7497              :                     }
    7498          148 :                     Line.erase(0, Pos + 1);
    7499          148 :                 } else { // Pos=0, probably last one
    7500           29 :                     std::string const dateStringUC = uppercase(Line);
    7501           29 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7502           29 :                     if (dateType != DateType::Invalid) {
    7503           29 :                         if (PMonth != 0 && PDay != 0) {
    7504           29 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7505           29 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7506              :                         }
    7507              :                     } else {
    7508            0 :                         ShowSevereError(
    7509            0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7510            0 :                         ErrorsFound = true;
    7511              :                     }
    7512           29 :                 }
    7513              :             }
    7514              :             // Process periods to set up other values.
    7515          207 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7516          177 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7517              :                 // JulianDay (Month,Day,LeapYearValue)
    7518          177 :                 std::string const ExtremePeriodTitle = Util::makeUPPER(typicalExtPer.ShortTitle);
    7519          177 :                 if (ExtremePeriodTitle == "SUMMER") {
    7520           58 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7521           29 :                         typicalExtPer.MatchValue = "SummerExtreme";
    7522           29 :                         typicalExtPer.MatchValue1 = "TropicalHot";
    7523           29 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7524              :                     } else {
    7525           29 :                         typicalExtPer.MatchValue = "SummerTypical";
    7526              :                     }
    7527              : 
    7528          119 :                 } else if (ExtremePeriodTitle == "WINTER") {
    7529           58 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7530           29 :                         typicalExtPer.MatchValue = "WinterExtreme";
    7531           29 :                         typicalExtPer.MatchValue1 = "TropicalCold";
    7532           29 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7533              :                     } else {
    7534           29 :                         typicalExtPer.MatchValue = "WinterTypical";
    7535              :                     }
    7536              : 
    7537           61 :                 } else if (ExtremePeriodTitle == "AUTUMN") {
    7538           29 :                     typicalExtPer.MatchValue = "AutumnTypical";
    7539              : 
    7540           32 :                 } else if (ExtremePeriodTitle == "SPRING") {
    7541           29 :                     typicalExtPer.MatchValue = "SpringTypical";
    7542              : 
    7543            3 :                 } else if (ExtremePeriodTitle == "WETSEASON") {
    7544            0 :                     typicalExtPer.MatchValue = "WetSeason";
    7545              : 
    7546            3 :                 } else if (ExtremePeriodTitle == "DRYSEASON") {
    7547            0 :                     typicalExtPer.MatchValue = "DrySeason";
    7548              : 
    7549            3 :                 } else if (ExtremePeriodTitle == "NOWETSEASON") {
    7550            0 :                     typicalExtPer.MatchValue = "NoWetSeason";
    7551              : 
    7552            3 :                 } else if (ExtremePeriodTitle == "NODRYSEASON") {
    7553            1 :                     typicalExtPer.MatchValue = "NoDrySeason";
    7554              : 
    7555            2 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMAX") || (ExtremePeriodTitle == "NOWETSEASONMAX")) {
    7556            1 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7557            1 :                     typicalExtPer.MatchValue1 = "TropicalHot";
    7558            1 :                     typicalExtPer.MatchValue2 = "SummerExtreme";
    7559              : 
    7560            1 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMIN") || (ExtremePeriodTitle == "NOWETSEASONMIN")) {
    7561            1 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7562            1 :                     typicalExtPer.MatchValue1 = "TropicalCold";
    7563            1 :                     typicalExtPer.MatchValue2 = "WinterExtreme";
    7564              : 
    7565            0 :                 } else if (ExtremePeriodTitle == "TROPICALHOT") {
    7566            0 :                     typicalExtPer.MatchValue = "TropicalHot";
    7567            0 :                     typicalExtPer.MatchValue1 = "SummerExtreme";
    7568            0 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7569              : 
    7570            0 :                 } else if (ExtremePeriodTitle == "TROPICALCOLD") {
    7571            0 :                     typicalExtPer.MatchValue = "TropicalCold";
    7572            0 :                     typicalExtPer.MatchValue1 = "WinterExtreme";
    7573            0 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7574              : 
    7575              :                 } else {
    7576            0 :                     typicalExtPer.MatchValue = "Invalid - no match";
    7577              :                 }
    7578          177 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, 0);
    7579          177 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, 0);
    7580          177 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7581          176 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7582              :                 } else {
    7583            1 :                     typicalExtPer.TotalDays =
    7584            1 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7585              :                 }
    7586          177 :             }
    7587           30 :         } break;
    7588           30 :         case Weather::EpwHeaderType::GroundTemperatures: {
    7589              :             // Added for ground surfaces defined with F or c factor method. TH 7/2009
    7590              :             // Assume the 0.5 m set of ground temperatures
    7591              :             // or first set on a weather file, if any.
    7592           30 :             Pos = index(Line, ',');
    7593           30 :             if (Pos != std::string::npos) {
    7594              :                 bool errFlag;
    7595           30 :                 int NumGrndTemps = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7596           30 :                 if (!errFlag && NumGrndTemps >= 1) {
    7597           30 :                     Line.erase(0, Pos + 1);
    7598              :                     // skip depth, soil conductivity, soil density, soil specific heat
    7599          150 :                     for (int i = 1; i <= 4; ++i) {
    7600          120 :                         Pos = index(Line, ',');
    7601          120 :                         if (Pos == std::string::npos) {
    7602            0 :                             Line.clear();
    7603            0 :                             break;
    7604              :                         }
    7605          120 :                         Line.erase(0, Pos + 1);
    7606              :                     }
    7607           30 :                     state.dataWeather->GroundTempsFCFromEPWHeader = 0.0;
    7608           30 :                     int actcount = 0;
    7609          390 :                     for (int i = 1; i <= 12; ++i) { // take the first set of ground temperatures.
    7610          360 :                         Pos = index(Line, ',');
    7611          360 :                         if (Pos != std::string::npos) {
    7612          360 :                             state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7613          360 :                             ++actcount;
    7614              :                         } else {
    7615            0 :                             if (len(Line) > 0) {
    7616            0 :                                 state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7617            0 :                                 ++actcount;
    7618              :                             }
    7619            0 :                             break;
    7620              :                         }
    7621          360 :                         Line.erase(0, Pos + 1);
    7622              :                     }
    7623           30 :                     if (actcount == 12) state.dataWeather->wthFCGroundTemps = true;
    7624              :                 }
    7625              :             }
    7626           30 :         } break;
    7627           31 :         case Weather::EpwHeaderType::HolidaysDST: {
    7628              :             // A1, \field LeapYear Observed
    7629              :             // \type choice
    7630              :             // \key Yes
    7631              :             // \key No
    7632              :             // \note Yes if Leap Year will be observed for this file
    7633              :             // \note No if Leap Year days (29 Feb) should be ignored in this file
    7634              :             // A2, \field Daylight Saving Start Day
    7635              :             // A3, \field Daylight Saving End Day
    7636              :             // N1, \field Number of Holidays
    7637              :             // A4, \field Holiday 1 Name
    7638              :             // A5, \field Holiday 1 Day
    7639              :             // etc.
    7640              :             // Start with Minimum number of NumHdArgs
    7641           31 :             uppercase(Line);
    7642           31 :             NumHdArgs = 4;
    7643           31 :             int CurCount = 0;
    7644          155 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7645          124 :                 strip(Line);
    7646          124 :                 Pos = index(Line, ',');
    7647          124 :                 if (Pos == std::string::npos) {
    7648           30 :                     if (len(Line) == 0) {
    7649            0 :                         while (Pos == std::string::npos) {
    7650            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7651            0 :                             strip(Line);
    7652            0 :                             uppercase(Line);
    7653            0 :                             Pos = index(Line, ',');
    7654              :                         }
    7655              :                     } else {
    7656           30 :                         Pos = len(Line);
    7657              :                     }
    7658              :                 }
    7659              : 
    7660              :                 int PMonth;
    7661              :                 int PDay;
    7662              :                 int PWeekDay;
    7663              :                 bool IOStatus;
    7664          124 :                 if (i == 1) {
    7665           31 :                     state.dataWeather->WFAllowsLeapYears = (Line[0] == 'Y');
    7666           93 :                 } else if (i == 2) {
    7667              :                     // In this section, we call ProcessDateString, and if that fails, we can recover from it
    7668              :                     // by setting DST to false, so we don't affect ErrorsFound
    7669              : 
    7670              :                     // call ProcessDateString with local bool (unused)
    7671              :                     bool errflag1;
    7672           31 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, errflag1);
    7673           31 :                     if (dateType != DateType::Invalid) {
    7674              :                         // ErrorsFound is still false after ProcessDateString
    7675           31 :                         if (PMonth == 0 && PDay == 0) {
    7676           30 :                             state.dataWeather->EPWDaylightSaving = false;
    7677              :                         } else {
    7678            1 :                             state.dataWeather->EPWDaylightSaving = true;
    7679            1 :                             state.dataWeather->EPWDST.StDateType = dateType;
    7680            1 :                             state.dataWeather->EPWDST.StMon = PMonth;
    7681            1 :                             state.dataWeather->EPWDST.StDay = PDay;
    7682            1 :                             state.dataWeather->EPWDST.StWeekDay = PWeekDay;
    7683              :                         }
    7684              :                     } else {
    7685              :                         // ErrorsFound is untouched
    7686            0 :                         ShowContinueError(
    7687            0 :                             state, format("ProcessEPWHeader: Invalid Daylight Saving Period Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7688            0 :                         ShowContinueError(state, format("...invalid header={}", epwHeaders[static_cast<int>(headerType)]));
    7689            0 :                         ShowContinueError(state, "...Setting Weather File DST to false.");
    7690            0 :                         state.dataWeather->EPWDaylightSaving = false;
    7691              :                     }
    7692              : 
    7693           62 :                 } else if (i == 3) {
    7694           31 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7695           31 :                     if (state.dataWeather->EPWDaylightSaving) {
    7696            1 :                         if (dateType != DateType::Invalid) {
    7697            1 :                             state.dataWeather->EPWDST.EnDateType = dateType;
    7698            1 :                             state.dataWeather->EPWDST.EnMon = PMonth;
    7699            1 :                             state.dataWeather->EPWDST.EnDay = PDay;
    7700            1 :                             state.dataWeather->EPWDST.EnWeekDay = PWeekDay;
    7701              :                         } else {
    7702            0 :                             ShowWarningError(
    7703              :                                 state,
    7704            0 :                                 format("ProcessEPWHeader: Invalid Daylight Saving Period End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7705            0 :                             ShowContinueError(state, "...Setting Weather File DST to false.");
    7706            0 :                             state.dataWeather->EPWDaylightSaving = false;
    7707              :                         }
    7708            1 :                         state.dataWeather->DST = state.dataWeather->EPWDST;
    7709              :                     }
    7710              : 
    7711           31 :                 } else if (i == 4) {
    7712           31 :                     int NumEPWHolidays = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7713           62 :                     state.dataWeather->NumSpecialDays =
    7714           31 :                         NumEPWHolidays + state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriodControl:SpecialDays");
    7715           31 :                     state.dataWeather->SpecialDays.allocate(state.dataWeather->NumSpecialDays);
    7716           31 :                     NumHdArgs = 4 + NumEPWHolidays * 2;
    7717              : 
    7718            0 :                 } else if ((i >= 5)) {
    7719            0 :                     if (mod(i, 2) != 0) {
    7720            0 :                         ++CurCount;
    7721            0 :                         if (CurCount > state.dataWeather->NumSpecialDays) {
    7722            0 :                             ShowSevereError(state, "Too many SpecialDays");
    7723            0 :                             ErrorsFound = true;
    7724              :                         } else {
    7725            0 :                             state.dataWeather->SpecialDays(CurCount).Name = Line.substr(0, Pos);
    7726              :                         }
    7727              :                         // Process name
    7728              :                     } else {
    7729            0 :                         if (CurCount <= state.dataWeather->NumSpecialDays) {
    7730            0 :                             auto &specialDay = state.dataWeather->SpecialDays(CurCount);
    7731              :                             // Process date
    7732            0 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7733            0 :                             if (dateType == DateType::MonthDay) {
    7734            0 :                                 specialDay.dateType = dateType;
    7735            0 :                                 specialDay.Month = PMonth;
    7736            0 :                                 specialDay.Day = PDay;
    7737            0 :                                 specialDay.WeekDay = 0;
    7738            0 :                                 specialDay.CompDate = PMonth * 32 + PDay;
    7739            0 :                                 specialDay.Duration = 1;
    7740            0 :                                 specialDay.DayType = 1;
    7741            0 :                                 specialDay.WthrFile = true;
    7742            0 :                             } else if (dateType != DateType::Invalid) {
    7743            0 :                                 specialDay.dateType = dateType;
    7744            0 :                                 specialDay.Month = PMonth;
    7745            0 :                                 specialDay.Day = PDay;
    7746            0 :                                 specialDay.WeekDay = PWeekDay;
    7747            0 :                                 specialDay.CompDate = 0;
    7748            0 :                                 specialDay.Duration = 1;
    7749            0 :                                 specialDay.DayType = 1;
    7750            0 :                                 specialDay.WthrFile = true;
    7751              :                             } else {
    7752            0 :                                 ShowSevereError(state, format("Invalid SpecialDay Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7753            0 :                                 ErrorsFound = true;
    7754              :                             }
    7755              :                         }
    7756              :                     }
    7757              :                 }
    7758          124 :                 Line.erase(0, Pos + 1);
    7759              :             }
    7760          211 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7761              :                 // General::OrdinalDay (Month,Day,LeapYearValue)
    7762          180 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7763          180 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, state.dataWeather->LeapYearAdd);
    7764          180 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, state.dataWeather->LeapYearAdd);
    7765          180 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7766          179 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7767              :                 } else {
    7768            1 :                     typicalExtPer.TotalDays =
    7769            1 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7770              :                 }
    7771              :             }
    7772           31 :         } break;
    7773           90 :         case Weather::EpwHeaderType::Comments1:
    7774              :         case Weather::EpwHeaderType::Comments2:
    7775              :         case Weather::EpwHeaderType::DesignConditions: {
    7776              :             // no action
    7777           90 :         } break;
    7778           30 :         case Weather::EpwHeaderType::DataPeriods: {
    7779              :             //     N1, \field Number of Data Periods
    7780              :             //     N2, \field Number of Records per hour
    7781              :             //     A1, \field Data Period 1 Name/Description
    7782              :             //     A2, \field Data Period 1 Start Day of Week
    7783              :             //       \type choice
    7784              :             //       \key  Sunday
    7785              :             //       \key  Monday
    7786              :             //       \key  Tuesday
    7787              :             //       \key  Wednesday
    7788              :             //       \key  Thursday
    7789              :             //       \key  Friday
    7790              :             //       \key  Saturday
    7791              :             //     A3, \field Data Period 1 Start Day
    7792              :             //     A4, \field Data Period 1 End Day
    7793           30 :             uppercase(Line);
    7794           30 :             NumHdArgs = 2;
    7795           30 :             int CurCount = 0;
    7796          214 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7797          184 :                 strip(Line);
    7798          184 :                 Pos = index(Line, ',');
    7799          184 :                 if (Pos == std::string::npos) {
    7800           29 :                     if (len(Line) == 0) {
    7801            0 :                         while (Pos == std::string::npos) {
    7802            0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7803            0 :                             strip(Line);
    7804            0 :                             uppercase(Line);
    7805            0 :                             Pos = index(Line, ',');
    7806              :                         }
    7807              :                     } else {
    7808           29 :                         Pos = len(Line);
    7809              :                     }
    7810              :                 }
    7811              : 
    7812              :                 bool IOStatus;
    7813          184 :                 if (i == 1) {
    7814           30 :                     state.dataWeather->NumDataPeriods = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7815           30 :                     state.dataWeather->DataPeriods.allocate(state.dataWeather->NumDataPeriods);
    7816           30 :                     NumHdArgs += 4 * state.dataWeather->NumDataPeriods;
    7817           30 :                     if (state.dataWeather->NumDataPeriods > 0) {
    7818           61 :                         for (auto &e : state.dataWeather->DataPeriods)
    7819           31 :                             e.NumDays = 0;
    7820              :                     }
    7821              : 
    7822          154 :                 } else if (i == 2) {
    7823           30 :                     state.dataWeather->NumIntervalsPerHour = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7824          124 :                 } else if (i >= 3) {
    7825          124 :                     int const CurOne = mod(i - 3, 4);
    7826              :                     int PMonth;
    7827              :                     int PDay;
    7828              :                     int PWeekDay;
    7829              :                     int PYear;
    7830          124 :                     if (CurOne == 0) {
    7831              :                         // Description of Data Period
    7832           31 :                         ++CurCount;
    7833           31 :                         if (CurCount > state.dataWeather->NumDataPeriods) {
    7834            0 :                             ShowSevereError(state, "Too many data periods");
    7835            0 :                             ErrorsFound = true;
    7836              :                         } else {
    7837           31 :                             state.dataWeather->DataPeriods(CurCount).Name = Line.substr(0, Pos);
    7838              :                         }
    7839              : 
    7840           93 :                     } else if (CurOne == 1) {
    7841              :                         // Start Day of Week
    7842           31 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7843           31 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7844           31 :                             dataPeriod.DayOfWeek = Line.substr(0, Pos);
    7845           31 :                             dataPeriod.WeekDay = getEnumValue(Sched::dayTypeNamesUC, dataPeriod.DayOfWeek);
    7846           31 :                             if (dataPeriod.WeekDay < 1 || dataPeriod.WeekDay > 7) {
    7847            0 :                                 ShowSevereError(state,
    7848            0 :                                                 fmt::format("Weather File -- Invalid Start Day of Week for Data Period #{}, Invalid day={}",
    7849              :                                                             CurCount,
    7850            0 :                                                             dataPeriod.DayOfWeek));
    7851            0 :                                 ErrorsFound = true;
    7852              :                             }
    7853              :                         }
    7854              : 
    7855           62 :                     } else if (CurOne == 2) {
    7856              :                         // DataPeriod Start Day
    7857           31 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7858           31 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7859           31 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    7860           31 :                             if (dateType == DateType::MonthDay) {
    7861           31 :                                 dataPeriod.StMon = PMonth;
    7862           31 :                                 dataPeriod.StDay = PDay;
    7863           31 :                                 dataPeriod.StYear = PYear;
    7864           31 :                                 if (PYear != 0) dataPeriod.HasYearData = true;
    7865              :                             } else {
    7866            0 :                                 ShowSevereError(state,
    7867            0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day> (WeatherFile), found={}",
    7868            0 :                                                        Line.substr(0, Pos)));
    7869            0 :                                 ErrorsFound = true;
    7870              :                             }
    7871              :                         }
    7872              : 
    7873           31 :                     } else if (CurOne == 3) {
    7874           31 :                         auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7875           31 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7876           31 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    7877           31 :                             if (dateType == DateType::MonthDay) {
    7878           31 :                                 dataPeriod.EnMon = PMonth;
    7879           31 :                                 dataPeriod.EnDay = PDay;
    7880           31 :                                 dataPeriod.EnYear = PYear;
    7881           31 :                                 if (PYear == 0 && dataPeriod.HasYearData) {
    7882            0 :                                     ShowWarningError(state, "Data Period (WeatherFile) - Start Date contains year. End Date does not.");
    7883            0 :                                     ShowContinueError(state, "...Assuming same year as Start Date for this data.");
    7884            0 :                                     dataPeriod.EnYear = dataPeriod.StYear;
    7885              :                                 }
    7886              :                             } else {
    7887            0 :                                 ShowSevereError(state,
    7888            0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day>, (WeatherFile) found={}",
    7889            0 :                                                        Line.substr(0, Pos)));
    7890            0 :                                 ErrorsFound = true;
    7891              :                             }
    7892              :                         }
    7893           31 :                         if (dataPeriod.StYear == 0 || dataPeriod.EnYear == 0) {
    7894           30 :                             dataPeriod.DataStJDay = General::OrdinalDay(dataPeriod.StMon, dataPeriod.StDay, state.dataWeather->LeapYearAdd);
    7895           30 :                             dataPeriod.DataEnJDay = General::OrdinalDay(dataPeriod.EnMon, dataPeriod.EnDay, state.dataWeather->LeapYearAdd);
    7896           30 :                             if (dataPeriod.DataStJDay <= dataPeriod.DataEnJDay) {
    7897           30 :                                 dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    7898              :                             } else {
    7899            0 :                                 dataPeriod.NumDays = (365 - dataPeriod.DataStJDay + 1) + (dataPeriod.DataEnJDay - 1 + 1);
    7900              :                             }
    7901              :                         } else { // weather file has actual year(s)
    7902            1 :                             dataPeriod.DataStJDay = computeJulianDate(dataPeriod.StYear, dataPeriod.StMon, dataPeriod.StDay);
    7903            1 :                             dataPeriod.DataEnJDay = computeJulianDate(dataPeriod.EnYear, dataPeriod.EnMon, dataPeriod.EnDay);
    7904            1 :                             dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    7905              :                         }
    7906              :                         // Have processed the last item for this, can set up Weekdays for months
    7907           31 :                         dataPeriod.MonWeekDay = 0;
    7908           31 :                         if (!ErrorsFound) {
    7909           93 :                             SetupWeekDaysByMonth(state,
    7910           31 :                                                  state.dataWeather->DataPeriods(CurCount).StMon,
    7911           31 :                                                  state.dataWeather->DataPeriods(CurCount).StDay,
    7912           31 :                                                  state.dataWeather->DataPeriods(CurCount).WeekDay,
    7913           31 :                                                  state.dataWeather->DataPeriods(CurCount).MonWeekDay);
    7914              :                         }
    7915              :                     }
    7916              :                 }
    7917          184 :                 Line.erase(0, Pos + 1);
    7918              :             }
    7919           30 :         } break;
    7920            0 :         default: {
    7921              :             // Invalid header type
    7922            0 :             assert(false);
    7923              :         } break;
    7924              :         }
    7925          241 :     }
    7926              : 
    7927           67 :     void SkipEPlusWFHeader(EnergyPlusData &state)
    7928              :     {
    7929              : 
    7930              :         // SUBROUTINE INFORMATION:
    7931              :         //       AUTHOR         Linda K. Lawrie
    7932              :         //       DATE WRITTEN   August 2000
    7933              : 
    7934              :         // PURPOSE OF THIS SUBROUTINE:
    7935              :         // This subroutine skips the initial header records on the EnergyPlus Weather File (in.epw).
    7936              : 
    7937              :         static constexpr std::string_view Header("DATA PERIODS");
    7938              : 
    7939              :         // Read in Header Information
    7940          134 :         InputFile::ReadResult<std::string> Line{"", true, false};
    7941              : 
    7942              :         // Headers should come in order
    7943              :         while (true) {
    7944          536 :             Line = state.files.inputWeatherFile.readLine();
    7945          536 :             if (Line.eof) {
    7946            0 :                 ShowFatalError(state,
    7947            0 :                                format("Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}", Header),
    7948            0 :                                OptionalOutputFileRef{state.files.eso});
    7949              :             }
    7950          536 :             uppercase(Line.data);
    7951          536 :             if (has(Line.data, Header)) break;
    7952              :         }
    7953              : 
    7954              :         // Dummy process Data Periods line
    7955              :         //  'DATA PERIODS'
    7956              :         //     N1, \field Number of Data Periods
    7957              :         //     N2, \field Number of Records per hour
    7958              :         //     A1, \field Data Period 1 Name/Description
    7959              :         //     A2, \field Data Period 1 Start Day of Week
    7960              :         //       \type choice
    7961              :         //       \key  Sunday
    7962              :         //       \key  Monday
    7963              :         //       \key  Tuesday
    7964              :         //       \key  Wednesday
    7965              :         //       \key  Thursday
    7966              :         //       \key  Friday
    7967              :         //       \key  Saturday
    7968              :         //     A3, \field Data Period 1 Start Day
    7969              :         //     A4, \field Data Period 1 End Day
    7970              : 
    7971           67 :         int NumHdArgs = 2;
    7972           67 :         int CurCount = 0;
    7973          201 :         for (int i = 1; i <= NumHdArgs; ++i) {
    7974          134 :             strip(Line.data);
    7975          134 :             std::string::size_type Pos = index(Line.data, ',');
    7976          134 :             if (Pos == std::string::npos) {
    7977            0 :                 if (len(Line.data) == 0) {
    7978            0 :                     while (Pos == std::string::npos) {
    7979            0 :                         Line = state.files.inputWeatherFile.readLine();
    7980            0 :                         strip(Line.data);
    7981            0 :                         uppercase(Line.data);
    7982            0 :                         Pos = index(Line.data, ',');
    7983              :                     }
    7984              :                 } else {
    7985            0 :                     Pos = len(Line.data);
    7986              :                 }
    7987              :             }
    7988              : 
    7989          134 :             if (i == 1) {
    7990              :                 bool IOStatus;
    7991           67 :                 int const NumPeriods = Util::ProcessNumber(Line.data.substr(0, Pos), IOStatus);
    7992           67 :                 NumHdArgs += 4 * NumPeriods;
    7993           67 :             } else if ((i >= 3)) {
    7994            0 :                 if (mod(i - 3, 4) == 0) ++CurCount;
    7995              :             }
    7996          134 :             Line.data.erase(0, Pos + 1);
    7997              :         }
    7998           67 :     }
    7999              : 
    8000           22 :     void ReportMissing_RangeData(EnergyPlusData &state)
    8001              :     {
    8002              : 
    8003              :         // SUBROUTINE INFORMATION:
    8004              :         //       AUTHOR         Linda Lawrie
    8005              :         //       DATE WRITTEN   January 2002
    8006              : 
    8007              :         // PURPOSE OF THIS SUBROUTINE:
    8008              :         // This subroutine reports the counts of missing/out of range data
    8009              :         // for weather file environments.
    8010              : 
    8011              :         static constexpr std::string_view MissString("Missing Data Found on Weather Data File");
    8012              :         static constexpr std::string_view msFmt("Missing {}, Number of items={:5}");
    8013              :         static constexpr std::string_view InvString("Invalid Data Found on Weather Data File");
    8014              :         static constexpr std::string_view ivFmt("Invalid {}, Number of items={:5}");
    8015              :         static constexpr std::string_view RangeString("Out of Range Data Found on Weather Data File");
    8016              :         static constexpr std::string_view rgFmt("Out of Range {} [{},{}], Number of items={:5}");
    8017              : 
    8018           22 :         if (!state.dataEnvrn->DisplayWeatherMissingDataWarnings) return;
    8019              : 
    8020            0 :         bool MissedHeader = false;
    8021            0 :         auto missedHeaderCheck = [&](Real64 const value, std::string const &description) {
    8022            0 :             if (value > 0) {
    8023            0 :                 if (!MissedHeader) {
    8024            0 :                     ShowWarningError(state, std::string{MissString});
    8025            0 :                     MissedHeader = true;
    8026              :                 }
    8027            0 :                 ShowMessage(state, format(msFmt, "\"" + description + "\"", value));
    8028              :             }
    8029            0 :         };
    8030              : 
    8031            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDryBulbTemp, "Dry Bulb Temperature");
    8032            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutBaroPress, "Atmospheric Pressure");
    8033            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutRelHum, "Relative Humidity");
    8034            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDewPointTemp, "Dew Point Temperatures");
    8035            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindSpeed, "Wind Speed");
    8036            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindDir, "Wind Direction");
    8037            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.BeamSolarRad, "Direct Radiation");
    8038            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.DifSolarRad, "Diffuse Radiation");
    8039            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.TotalSkyCover, "Total Sky Cover");
    8040            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OpaqueSkyCover, "Opaque Sky Cover");
    8041            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.SnowDepth, "Snow Depth");
    8042            0 :         if (state.dataWeather->wvarsMissedCounts.WeathCodes > 0) {
    8043            0 :             ShowWarningError(state, std::string{InvString});
    8044            0 :             ShowMessage(state, format(ivFmt, "\"Weather Codes\" (not equal 9 digits)", state.dataWeather->wvarsMissedCounts.WeathCodes));
    8045              :         }
    8046            0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.LiquidPrecip, "Liquid Precipitation Depth");
    8047              : 
    8048            0 :         bool OutOfRangeHeader = false;
    8049              :         auto outOfRangeHeaderCheck = // (AUTO_OK_LAMBDA)
    8050            0 :             [&](Real64 const value, std::string_view description, std::string_view rangeLow, std::string_view rangeHigh, std::string_view extraMsg) {
    8051            0 :                 if (value > 0) {
    8052            0 :                     if (!OutOfRangeHeader) {
    8053            0 :                         ShowWarningError(state, std::string{RangeString});
    8054            0 :                         OutOfRangeHeader = true;
    8055              :                     }
    8056            0 :                     ShowMessage(state, EnergyPlus::format(rgFmt, description, rangeLow, rangeHigh, value));
    8057            0 :                     if (!extraMsg.empty()) ShowMessage(state, std::string{extraMsg});
    8058              :                 }
    8059            0 :             };
    8060            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp, "Dry Bulb Temperatures", ">=-90", "<=70", "");
    8061            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress,
    8062              :                               "Atmospheric Pressure",
    8063              :                               ">31000",
    8064              :                               "<=120000",
    8065              :                               "Out of Range values set to last good value");
    8066            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutRelHum, "Relative Humidity", ">=0", "<=110", "");
    8067            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp, "Dew Point Temperatures", ">=-90", "<=70", "");
    8068            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindSpeed, "Wind Speed", ">=0", "<=40", "");
    8069            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindDir, "Wind Direction", ">=0", "<=360", "");
    8070            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad, "Direct Radiation", ">=0", "NoLimit", "");
    8071            0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad, "Diffuse Radiation", ">=0", "NoLimit", "");
    8072              :     }
    8073              : 
    8074          112 :     void SetupInterpolationValues(EnergyPlusData &state)
    8075              :     {
    8076              : 
    8077              :         // SUBROUTINE INFORMATION:
    8078              :         //       AUTHOR         Linda Lawrie
    8079              :         //       DATE WRITTEN   November 2002
    8080              : 
    8081              :         // PURPOSE OF THIS SUBROUTINE:
    8082              :         // This subroutine creates the "interpolation" values / weights that are used for
    8083              :         // interpolating weather data from hourly down to the time step level.
    8084              : 
    8085              :         // METHODOLOGY EMPLOYED:
    8086              :         // Create arrays (InterpolationValues, SolarInterpolationValues) dependent on
    8087              :         // Number of Time Steps in Hour.  This will be used in the "SetCurrentWeather" procedure.
    8088              : 
    8089          112 :         state.dataWeather->Interpolation.allocate(state.dataGlobal->TimeStepsInHour);
    8090          112 :         state.dataWeather->SolarInterpolation.allocate(state.dataGlobal->TimeStepsInHour);
    8091          112 :         state.dataWeather->Interpolation = 0.0;
    8092          112 :         state.dataWeather->SolarInterpolation = 0.0;
    8093              : 
    8094          716 :         for (int tloop = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop) {
    8095          604 :             state.dataWeather->Interpolation(tloop) =
    8096          604 :                 (state.dataGlobal->TimeStepsInHour == 1) ? 1.0 : min(1.0, (double(tloop) / double(state.dataGlobal->TimeStepsInHour)));
    8097              :         }
    8098              : 
    8099          112 :         if (mod(state.dataGlobal->TimeStepsInHour, 2) == 0) {
    8100              :             // even number of time steps.
    8101          102 :             int halfpoint = state.dataGlobal->TimeStepsInHour / 2;
    8102              : 
    8103          102 :             state.dataWeather->SolarInterpolation(halfpoint) = 1.0;
    8104          102 :             Real64 tweight = 1.0 / double(state.dataGlobal->TimeStepsInHour);
    8105          399 :             for (int tloop = halfpoint + 1, hpoint = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop, ++hpoint) {
    8106          297 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8107              :             }
    8108          297 :             for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8109          195 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8110              :             }
    8111              :         } else { // odd number of time steps
    8112           10 :             if (state.dataGlobal->TimeStepsInHour == 1) {
    8113           10 :                 state.dataWeather->SolarInterpolation(1) = 0.5;
    8114            0 :             } else if (state.dataGlobal->TimeStepsInHour == 3) {
    8115            0 :                 state.dataWeather->SolarInterpolation(1) = 5.0 / 6.0;
    8116            0 :                 state.dataWeather->SolarInterpolation(2) = 5.0 / 6.0;
    8117            0 :                 state.dataWeather->SolarInterpolation(3) = 0.5;
    8118              :             } else {
    8119            0 :                 Real64 tweight = 1.0 / double(state.dataGlobal->TimeStepsInHour);
    8120            0 :                 int halfpoint = state.dataGlobal->TimeStepsInHour / 2;
    8121            0 :                 Real64 tweight1 = 1.0 - tweight / 2.0;
    8122            0 :                 state.dataWeather->SolarInterpolation(halfpoint) = tweight1;
    8123            0 :                 state.dataWeather->SolarInterpolation(halfpoint + 1) = tweight1;
    8124            0 :                 for (int tloop = halfpoint + 2, hpoint = 1; tloop <= state.dataGlobal->TimeStepsInHour; ++tloop, ++hpoint) {
    8125            0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8126              :                 }
    8127            0 :                 for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8128            0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8129              :                 }
    8130              :             }
    8131              :         }
    8132          112 :     }
    8133              : 
    8134          114 :     void SetupEnvironmentTypes(EnergyPlusData &state)
    8135              :     {
    8136              : 
    8137              :         // SUBROUTINE INFORMATION:
    8138              :         //       AUTHOR         Linda Lawrie
    8139              :         //       DATE WRITTEN   October 2010
    8140              : 
    8141              :         // PURPOSE OF THIS SUBROUTINE:
    8142              :         // Make sure Environment derived type is set prior to getting
    8143              :         // Weather Properties
    8144              : 
    8145              :         // Transfer weather file information to the Environment derived type
    8146          114 :         state.dataWeather->Envrn = state.dataEnvrn->TotDesDays + 1;
    8147              : 
    8148              :         // Sizing Periods from Weather File
    8149          114 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunDesPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8150            0 :             auto const &runPer = state.dataWeather->RunPeriodDesignInput(iRunPer);
    8151            0 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8152              : 
    8153            0 :             envCurr.StartMonth = runPer.startMonth;
    8154            0 :             envCurr.StartDay = runPer.startDay;
    8155            0 :             envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, state.dataWeather->LeapYearAdd);
    8156            0 :             envCurr.TotalDays = runPer.totalDays;
    8157            0 :             envCurr.EndMonth = runPer.endMonth;
    8158            0 :             envCurr.EndDay = runPer.endDay;
    8159            0 :             envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, state.dataWeather->LeapYearAdd);
    8160            0 :             envCurr.NumSimYears = runPer.numSimYears;
    8161            0 :             if (envCurr.StartJDay <= envCurr.EndJDay) {
    8162            0 :                 envCurr.TotalDays = (envCurr.EndJDay - envCurr.StartJDay + 1) * envCurr.NumSimYears;
    8163              :             } else {
    8164            0 :                 envCurr.TotalDays =
    8165            0 :                     (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - envCurr.StartJDay + 1 + envCurr.EndJDay) * envCurr.NumSimYears;
    8166              :             }
    8167            0 :             state.dataEnvrn->TotRunDesPersDays += envCurr.TotalDays;
    8168            0 :             envCurr.UseDST = runPer.useDST;
    8169            0 :             envCurr.UseHolidays = runPer.useHolidays;
    8170            0 :             envCurr.Title = runPer.title;
    8171            0 :             envCurr.cKindOfEnvrn = runPer.periodType;
    8172            0 :             envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    8173            0 :             envCurr.DesignDayNum = 0;
    8174            0 :             envCurr.RunPeriodDesignNum = iRunPer;
    8175            0 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8176            0 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8177            0 :             envCurr.SetWeekDays = false;
    8178            0 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8179            0 :             envCurr.UseRain = runPer.useRain;
    8180            0 :             envCurr.UseSnow = runPer.useSnow;
    8181            0 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // this will just the default
    8182              :         }
    8183              : 
    8184              :         // RunPeriods from weather file
    8185          172 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8186           58 :             auto const &runPer = state.dataWeather->RunPeriodInput(iRunPer);
    8187           58 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8188              : 
    8189           58 :             envCurr.StartMonth = runPer.startMonth;
    8190           58 :             envCurr.StartDay = runPer.startDay;
    8191           58 :             envCurr.StartYear = runPer.startYear;
    8192           58 :             envCurr.EndMonth = runPer.endMonth;
    8193           58 :             envCurr.EndDay = runPer.endDay;
    8194           58 :             envCurr.EndYear = runPer.endYear;
    8195           58 :             envCurr.NumSimYears = runPer.numSimYears;
    8196           58 :             envCurr.CurrentYear = runPer.startYear;
    8197           58 :             envCurr.IsLeapYear = runPer.isLeapYear;
    8198           58 :             envCurr.TreatYearsAsConsecutive = true;
    8199           58 :             if (runPer.actualWeather) {
    8200              :                 // This will require leap years to be present, thus Julian days can be used for all the calculations
    8201            0 :                 envCurr.StartJDay = envCurr.StartDate = runPer.startJulianDate;
    8202            0 :                 envCurr.EndJDay = envCurr.EndDate = runPer.endJulianDate;
    8203            0 :                 envCurr.TotalDays = envCurr.EndDate - envCurr.StartDate + 1;
    8204            0 :                 envCurr.RawSimDays = envCurr.EndDate - envCurr.StartDate + 1;
    8205            0 :                 envCurr.MatchYear = true;
    8206            0 :                 envCurr.ActualWeather = true;
    8207              :             } else { // std RunPeriod
    8208           58 :                 envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8209           58 :                 if (envCurr.StartYear == envCurr.EndYear) {
    8210              :                     // Short-circuit all the calculations, we're in a single year
    8211              : 
    8212           58 :                     envCurr.IsLeapYear = isLeapYear(envCurr.StartYear) && state.dataWeather->WFAllowsLeapYears;
    8213           58 :                     int LocalLeapYearAdd = (int)envCurr.IsLeapYear;
    8214              : 
    8215           58 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, LocalLeapYearAdd);
    8216           58 :                     envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, LocalLeapYearAdd);
    8217           58 :                     envCurr.RawSimDays = (envCurr.EndJDay - envCurr.StartJDay + 1);
    8218           58 :                     envCurr.TotalDays = envCurr.RawSimDays;
    8219              :                 } else {
    8220              :                     // Environment crosses year boundaries
    8221            0 :                     envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8222            0 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, (int)runPer.isLeapYear);
    8223            0 :                     envCurr.EndJDay = General::OrdinalDay(
    8224            0 :                         runPer.endMonth, runPer.endDay, (int)(isLeapYear(runPer.endYear) && state.dataWeather->WFAllowsLeapYears));
    8225            0 :                     envCurr.TotalDays = 366 - envCurr.StartJDay + envCurr.EndJDay + 365 * std::max(envCurr.NumSimYears - 2, 0);
    8226            0 :                     if (state.dataWeather->WFAllowsLeapYears) {
    8227              :                         // First year
    8228            0 :                         if (envCurr.StartJDay < 59) {
    8229            0 :                             if (isLeapYear(envCurr.StartYear)) {
    8230            0 :                                 ++envCurr.TotalDays;
    8231              :                             }
    8232              :                         }
    8233              :                         // Middle years
    8234            0 :                         for (int yr = envCurr.StartYear + 1; yr < envCurr.EndYear; ++yr) {
    8235            0 :                             if (isLeapYear(yr)) {
    8236            0 :                                 ++envCurr.TotalDays;
    8237              :                             }
    8238              :                         }
    8239              :                         // Last year not needed, the end ordinal date will take this into account
    8240              :                     }
    8241            0 :                     envCurr.RawSimDays = envCurr.TotalDays;
    8242              :                 }
    8243              :             }
    8244           58 :             envCurr.UseDST = runPer.useDST;
    8245           58 :             envCurr.UseHolidays = runPer.useHolidays;
    8246           58 :             if (runPer.title.empty()) {
    8247            2 :                 envCurr.Title = state.dataEnvrn->WeatherFileLocationTitle;
    8248              :             } else {
    8249           56 :                 envCurr.Title = runPer.title;
    8250              :             }
    8251           58 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::ReadAllWeatherData) {
    8252            2 :                 envCurr.cKindOfEnvrn = "ReadAllWeatherDataRunPeriod";
    8253              :             } else {
    8254           56 :                 envCurr.cKindOfEnvrn = "WeatherFileRunPeriod";
    8255           56 :                 envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    8256              :             }
    8257           58 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8258           58 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8259           58 :             envCurr.SetWeekDays = false;
    8260           58 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8261           58 :             envCurr.UseRain = runPer.useRain;
    8262           58 :             envCurr.UseSnow = runPer.useSnow;
    8263           58 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // first hour interpolation choice
    8264              :         }                                                               // for (i)
    8265          114 :     }
    8266              : 
    8267          124 :     bool isLeapYear(int const Year)
    8268              :     {
    8269              :         // true if it's a leap year, false if not.
    8270              : 
    8271          124 :         if (mod(Year, 4) == 0) { // Potential Leap Year
    8272            5 :             if (!(mod(Year, 100) == 0 && mod(Year, 400) != 0)) {
    8273            5 :                 return true;
    8274              :             }
    8275              :         }
    8276          119 :         return false;
    8277              :     }
    8278              : 
    8279          320 :     int computeJulianDate(int const gyyyy, // input/output gregorian year, should be specified as 4 digits
    8280              :                           int const gmm,   // input/output gregorian month
    8281              :                           int const gdd    // input/output gregorian day
    8282              :     )
    8283              :     {
    8284              :         // SUBROUTINE INFORMATION:
    8285              :         //       AUTHOR         Jason DeGraw
    8286              :         //       DATE WRITTEN   10/25/2017
    8287              : 
    8288              :         // PURPOSE OF THIS SUBROUTINE:
    8289              :         // Split the former JGDate function in two. Convert a gregorian
    8290              :         // date to actual julian date.  the advantage of storing a julian date
    8291              :         // in the jdate format rather than a 5 digit format is that any
    8292              :         // number of days can be add or subtracted to jdate and
    8293              :         // that result is a proper julian date.
    8294              : 
    8295              :         // REFERENCES:
    8296              :         // for discussion of this algorithm,
    8297              :         // see cacm, vol 11, no 10, oct 1968, page 657
    8298              : 
    8299          320 :         int tyyyy = gyyyy;
    8300          320 :         int tmm = gmm;
    8301          320 :         int tdd = gdd;
    8302          320 :         int l = (tmm - 14) / 12;
    8303          320 :         return tdd - 32075 + 1461 * (tyyyy + 4800 + l) / 4 + 367 * (tmm - 2 - l * 12) / 12 - 3 * ((tyyyy + 4900 + l) / 100) / 4;
    8304              :     }
    8305              : 
    8306            4 :     int computeJulianDate(GregorianDate const &gdate)
    8307              :     {
    8308            4 :         return computeJulianDate(gdate.year, gdate.month, gdate.day);
    8309              :     }
    8310              : 
    8311            4 :     GregorianDate computeGregorianDate(int const jdate)
    8312              :     {
    8313            4 :         int tdate = jdate;
    8314            4 :         int l = tdate + 68569;
    8315            4 :         int n = 4 * l / 146097;
    8316            4 :         l -= (146097 * n + 3) / 4;
    8317            4 :         int tyyyy = 4000 * (l + 1) / 1461001;
    8318            4 :         l = l - 1461 * tyyyy / 4 + 31;
    8319            4 :         int tmm = 80 * l / 2447;
    8320            4 :         int tdd = l - 2447 * tmm / 80;
    8321            4 :         l = tmm / 11;
    8322            4 :         tmm += 2 - 12 * l;
    8323            4 :         tyyyy += 100 * (n - 49) + l;
    8324            4 :         return {tyyyy, tmm, tdd};
    8325              :     }
    8326              : 
    8327            6 :     Sched::DayType calculateDayOfWeek(EnergyPlusData &state, int const year, int const month, int const day)
    8328              :     {
    8329              : 
    8330              :         // FUNCTION INFORMATION:
    8331              :         //       AUTHOR         Linda Lawrie
    8332              :         //       DATE WRITTEN   March 2012
    8333              :         //       MODIFIED       October 2017, Jason DeGraw
    8334              : 
    8335              :         // PURPOSE OF THIS FUNCTION:
    8336              :         // Calculate the correct day of week.
    8337              : 
    8338              :         // METHODOLOGY EMPLOYED:
    8339              :         // Zeller's algorithm.
    8340              : 
    8341              :         // REFERENCES:
    8342              :         // http://en.wikipedia.org/wiki/Zeller%27s_congruence
    8343              :         // and other references around the web.
    8344              : 
    8345            6 :         int Gyyyy(year); // Gregorian yyyy
    8346            6 :         int Gmm(month);  // Gregorian mm
    8347              : 
    8348              :         // Jan, Feb are 13, 14 months of previous year
    8349            6 :         if (Gmm < 3) {
    8350            6 :             Gmm += 12;
    8351            6 :             --Gyyyy;
    8352              :         }
    8353              : 
    8354            6 :         state.dataEnvrn->DayOfWeek = mod(day + (13 * (Gmm + 1) / 5) + Gyyyy + (Gyyyy / 4) + 6 * (Gyyyy / 100) + (Gyyyy / 400), 7);
    8355            6 :         if (state.dataEnvrn->DayOfWeek == 0) state.dataEnvrn->DayOfWeek = 7;
    8356              : 
    8357            6 :         return static_cast<Sched::DayType>(state.dataEnvrn->DayOfWeek);
    8358              :     }
    8359              : 
    8360           57 :     int calculateDayOfYear(int const Month, int const Day, bool const leapYear)
    8361              :     {
    8362              : 
    8363              :         // FUNCTION INFORMATION:
    8364              :         //       AUTHOR         Jason DeGraw
    8365              :         //       DATE WRITTEN   October 10, 2017
    8366              : 
    8367              :         // PURPOSE OF THIS FUNCTION:
    8368              :         // Compute the day of the year for leap and non-leap years.
    8369              : 
    8370              :         static std::array<int, 12> const daysbefore{{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}};
    8371              :         static std::array<int, 12> const daysbeforeleap{{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
    8372              : 
    8373              :         // Could probably do some bounds checking here, but for now assume the month is in [1, 12]
    8374           57 :         if (leapYear) {
    8375            2 :             return daysbeforeleap[Month - 1] + Day;
    8376              :         } else {
    8377           55 :             return daysbefore[Month - 1] + Day;
    8378              :         }
    8379              :     }
    8380              : 
    8381          124 :     bool validMonthDay(int const month, int const day, int const leapYearAdd)
    8382              :     {
    8383              : 
    8384              :         // FUNCTION INFORMATION:
    8385              :         //       AUTHOR         Jason DeGraw
    8386              :         //       DATE WRITTEN   October 31, 2017
    8387              : 
    8388              :         // PURPOSE OF THIS FUNCTION:
    8389              :         // Determine if a month/day+leapyear combination is valid.
    8390              : 
    8391          124 :         switch (month) {
    8392          123 :         case 1:
    8393              :         case 3:
    8394              :         case 5:
    8395              :         case 7:
    8396              :         case 8:
    8397              :         case 10:
    8398              :         case 12:
    8399          123 :             if (day > 31) {
    8400            0 :                 return false;
    8401              :             }
    8402          123 :             break;
    8403            0 :         case 4:
    8404              :         case 6:
    8405              :         case 9:
    8406              :         case 11:
    8407            0 :             if (day > 30) {
    8408            0 :                 return false;
    8409              :             }
    8410            0 :             break;
    8411            1 :         case 2:
    8412            1 :             if (day > 28 + leapYearAdd) {
    8413            0 :                 return false;
    8414              :             }
    8415            1 :             break;
    8416            0 :         default:
    8417            0 :             return false;
    8418              :         }
    8419          124 :         return true;
    8420              :     }
    8421              : 
    8422            3 :     void AnnualMonthlyDryBulbWeatherData::CalcAnnualAndMonthlyDryBulbTemp(EnergyPlusData &state)
    8423              :     {
    8424              : 
    8425              :         // PURPOSE OF THIS SUBROUTINE:
    8426              :         // Calculates monthly daily average outdoor air drybulb temperature from
    8427              :         // either weather (*.EPW) file or reads monthly daily average outdoor air
    8428              :         // drybulb temperature from STAT (*.stat) for use to autosize main water
    8429              :         // temperature.
    8430              : 
    8431            3 :         Real64 MonthlyDailyDryBulbMin(200.0);               // monthly-daily minimum outside air dry-bulb temperature
    8432            3 :         Real64 MonthlyDailyDryBulbMax(-200.0);              // monthly-daily maximum outside air dry-bulb temperature
    8433            3 :         Real64 AnnualDailyAverageDryBulbTempSum(0.0);       // annual sum of daily average outside air dry-bulb temperature
    8434            3 :         Array1D<Real64> MonthlyAverageDryBulbTemp(12, 0.0); // monthly-daily average outside air temperature
    8435              : 
    8436            3 :         if (!this->OADryBulbWeatherDataProcessed) {
    8437            3 :             const bool statFileExists = FileSystem::fileExists(state.files.inStatFilePath.filePath);
    8438            3 :             const bool epwFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    8439            3 :             if (statFileExists) {
    8440            2 :                 auto statFile = state.files.inStatFilePath.try_open();
    8441            2 :                 if (!statFile.good()) {
    8442            0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", statFile.filePath));
    8443            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8444            0 :                     return;
    8445              :                 }
    8446              : 
    8447            2 :                 std::string lineAvg;
    8448          136 :                 while (statFile.good()) {
    8449          135 :                     auto lineIn = statFile.readLine();
    8450          135 :                     if (has(lineIn.data, "Monthly Statistics for Dry Bulb temperatures")) {
    8451            8 :                         for (int i = 1; i <= 7; ++i) {
    8452            7 :                             lineIn = statFile.readLine();
    8453              :                         }
    8454            1 :                         lineIn = statFile.readLine();
    8455            1 :                         lineAvg = lineIn.data;
    8456            1 :                         break;
    8457              :                     }
    8458          135 :                 }
    8459            2 :                 if (lineAvg.empty()) {
    8460            2 :                     ShowSevereError(
    8461              :                         state,
    8462            2 :                         format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have Monthly Statistics for Dry Bulb temperatures.",
    8463              :                                statFile.filePath));
    8464            2 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8465            1 :                     return;
    8466            1 :                 } else if (lineAvg.find("Daily Avg") == std::string::npos) {
    8467            0 :                     ShowSevereError(state,
    8468            0 :                                     format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have the 'Daily Avg' line in the Monthly "
    8469              :                                            "Statistics for Dry Bulb temperatures.",
    8470              :                                            statFile.filePath));
    8471            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8472            0 :                     return;
    8473              :                 } else {
    8474            1 :                     int AnnualNumberOfDays = 0;
    8475           13 :                     for (int i = 1; i <= 12; ++i) {
    8476           12 :                         MonthlyAverageDryBulbTemp(i) = OutputReportTabular::StrToReal(OutputReportTabular::GetColumnUsingTabs(lineAvg, i + 2));
    8477           12 :                         AnnualDailyAverageDryBulbTempSum += MonthlyAverageDryBulbTemp(i) * state.dataWeather->EndDayOfMonth(i);
    8478           12 :                         MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyAverageDryBulbTemp(i));
    8479           12 :                         MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyAverageDryBulbTemp(i));
    8480           12 :                         AnnualNumberOfDays += state.dataWeather->EndDayOfMonth(i);
    8481              :                     }
    8482            1 :                     this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8483            1 :                     this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8484            1 :                     this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8485            1 :                     this->OADryBulbWeatherDataProcessed = true;
    8486              :                 }
    8487            4 :             } else if (epwFileExists) {
    8488            1 :                 auto epwFile = state.files.inputWeatherFilePath.try_open();
    8489            1 :                 bool epwHasLeapYear(false);
    8490            1 :                 if (!epwFile.good()) {
    8491            0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", epwFile.filePath));
    8492            0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8493            0 :                     return;
    8494              :                 }
    8495            9 :                 for (int i = 1; i <= 8; ++i) { // Headers
    8496            8 :                     auto epwLine = epwFile.readLine();
    8497              : 
    8498            8 :                     if (i == 5) {
    8499              :                         // HOLIDAYS/DAYLIGHT SAVINGS,Yes,0,0,0
    8500            1 :                         std::string::size_type pos = index(epwLine.data, ',');
    8501            1 :                         epwLine.data.erase(0, pos + 1);
    8502            1 :                         pos = index(epwLine.data, ',');
    8503            1 :                         std::string LeapYear = Util::makeUPPER(epwLine.data.substr(0, pos));
    8504            1 :                         if (LeapYear[0] == 'Y') {
    8505            0 :                             epwHasLeapYear = true;
    8506              :                         }
    8507            1 :                     }
    8508            8 :                 }
    8509            1 :                 Array1D<int> EndDayOfMonthLocal;
    8510            1 :                 EndDayOfMonthLocal = state.dataWeather->EndDayOfMonth;
    8511            1 :                 if (epwHasLeapYear) {
    8512              :                     // increase number of days for february by one day if weather data has leap year
    8513            0 :                     EndDayOfMonthLocal(2) = EndDayOfMonthLocal(2) + 1;
    8514              :                 }
    8515           13 :                 for (int i = 1; i <= 12; ++i) {
    8516           12 :                     Real64 MonthlyDailyDryBulbAvg = 0.0;
    8517           12 :                     int DaysCountOfMonth = EndDayOfMonthLocal(i);
    8518          377 :                     for (int DayNum = 1; DayNum <= DaysCountOfMonth; ++DayNum) {
    8519          365 :                         Real64 DailyAverageDryBulbTemp = 0.0;
    8520              :                         std::string::size_type pos;
    8521         9125 :                         for (int j = 1; j <= 24; ++j) {
    8522         8760 :                             auto epwLine = epwFile.readLine();
    8523        61320 :                             for (int ind = 1; ind <= 6; ++ind) {
    8524        52560 :                                 pos = index(epwLine.data, ',');
    8525        52560 :                                 epwLine.data.erase(0, pos + 1);
    8526              :                             }
    8527         8760 :                             pos = index(epwLine.data, ',');
    8528         8760 :                             Real64 HourlyDryBulbTemp = OutputReportTabular::StrToReal(epwLine.data.substr(0, pos));
    8529         8760 :                             DailyAverageDryBulbTemp += (HourlyDryBulbTemp / 24.0);
    8530         8760 :                         }
    8531          365 :                         AnnualDailyAverageDryBulbTempSum += DailyAverageDryBulbTemp;
    8532          365 :                         MonthlyDailyDryBulbAvg += (DailyAverageDryBulbTemp / DaysCountOfMonth);
    8533              :                     }
    8534           12 :                     MonthlyAverageDryBulbTemp(i) = MonthlyDailyDryBulbAvg;
    8535           12 :                     MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyDailyDryBulbAvg);
    8536           12 :                     MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyDailyDryBulbAvg);
    8537              :                 }
    8538              :                 // calculate annual average outdoor air dry-bulb temperature and monthly daily average
    8539              :                 // outdoor air temperature maximum difference
    8540            1 :                 int AnnualNumberOfDays = 365;
    8541            1 :                 if (epwHasLeapYear) AnnualNumberOfDays++;
    8542            1 :                 this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8543            1 :                 this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8544            1 :                 this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8545            1 :                 this->OADryBulbWeatherDataProcessed = true;
    8546            1 :             } else {
    8547            0 :                 ShowSevereError(state, "CalcAnnualAndMonthlyDryBulbTemp: weather file or stat file does not exist.");
    8548            0 :                 ShowContinueError(state, format("Weather file: {}.", state.files.inputWeatherFilePath.filePath));
    8549            0 :                 ShowContinueError(state, format("Stat file: {}.", state.files.inStatFilePath.filePath));
    8550            0 :                 ShowContinueError(state, "Water Mains Monthly Temperature cannot be calculated using CorrelationFromWeatherFile method.");
    8551            0 :                 ShowContinueError(state, "Instead a fixed default value of 10.0 C will be used.");
    8552              :             }
    8553              :         }
    8554            3 :     }
    8555              : 
    8556          104 :     void ReportWaterMainsTempParameters(EnergyPlusData &state)
    8557              :     {
    8558              :         // PURPOSE OF THIS SUBROUTINE:
    8559              :         // report site water mains temperature object user inputs and/or parameters calculated
    8560              :         // from weather or stat file
    8561              : 
    8562          104 :         if (!state.files.eio.good()) {
    8563            0 :             return;
    8564              :         }
    8565              : 
    8566          104 :         std::stringstream ss;
    8567          104 :         auto *eiostream = &ss;
    8568              : 
    8569              :         // Write annual average OA temperature and maximum difference in monthly-daily average outdoor air temperature
    8570              :         *eiostream << "! <Site Water Mains Temperature Information>"
    8571              :                       ",Calculation Method{}"
    8572              :                       ",Water Mains Temperature Schedule Name{}"
    8573              :                       ",Annual Average Outdoor Air Temperature{C}"
    8574              :                       ",Maximum Difference In Monthly Average Outdoor Air Temperatures{deltaC}"
    8575          104 :                       ",Fixed Default Water Mains Temperature{C}\n";
    8576              : 
    8577          104 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    8578            0 :         case WaterMainsTempCalcMethod::Schedule:
    8579            0 :             *eiostream << "Site Water Mains Temperature Information,";
    8580            0 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8581            0 :                        << state.dataWeather->waterMainsTempSched->Name << ",";
    8582            0 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8583            0 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8584            0 :             *eiostream << "NA\n";
    8585            0 :             break;
    8586            6 :         case WaterMainsTempCalcMethod::Correlation:
    8587            6 :             *eiostream << "Site Water Mains Temperature Information,";
    8588            6 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8589              :                        << "NA"
    8590           12 :                        << ",";
    8591            6 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8592           12 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8593            6 :             *eiostream << "NA\n";
    8594            6 :             break;
    8595            1 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    8596            1 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    8597            1 :                 *eiostream << "Site Water Mains Temperature Information,";
    8598            1 :                 *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8599              :                            << "NA"
    8600            2 :                            << ",";
    8601            2 :                 *eiostream << format("{:.2R}", state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp) << ","
    8602            2 :                            << format("{:.2R}", state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff) << ","
    8603            3 :                            << "NA\n";
    8604              :             } else {
    8605            0 :                 *eiostream << "Site Water Mains Temperature Information,";
    8606              :                 *eiostream << "FixedDefault"
    8607              :                            << ","
    8608              :                            << "NA"
    8609              :                            << ","
    8610              :                            << "NA"
    8611              :                            << ","
    8612              :                            << "NA"
    8613            0 :                            << "," << format("{:.1R}", 10.0) << '\n';
    8614              :             }
    8615            1 :             break;
    8616           97 :         default:
    8617           97 :             *eiostream << "Site Water Mains Temperature Information,";
    8618              :             *eiostream << "FixedDefault"
    8619              :                        << ","
    8620              :                        << "NA"
    8621              :                        << ","
    8622              :                        << "NA"
    8623              :                        << ","
    8624              :                        << "NA"
    8625           97 :                        << "," << format("{:.1R}", 10.0) << '\n';
    8626           97 :             break;
    8627              :         }
    8628              : 
    8629          104 :         print(state.files.eio, "{}", ss.str());
    8630          104 :     }
    8631              : 
    8632        90504 :     void calcSky(EnergyPlusData &state,
    8633              :                  Real64 &HorizIRSky,
    8634              :                  Real64 &SkyTemp,
    8635              :                  Real64 OpaqueSkyCover,
    8636              :                  Real64 DryBulb,
    8637              :                  Real64 DewPoint,
    8638              :                  Real64 RelHum,
    8639              :                  Real64 IRHoriz)
    8640              :     {
    8641        90504 :         if (IRHoriz <= 0.0) IRHoriz = 9999.0;
    8642              : 
    8643        90504 :         auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8644        90504 :         if (!envCurr.UseWeatherFileHorizontalIR || IRHoriz >= 9999.0) {
    8645              :             // Missing or user defined to not use IRHoriz from weather, using sky cover and clear sky emissivity
    8646          384 :             Real64 ESky = CalcSkyEmissivity(state, envCurr.skyTempModel, OpaqueSkyCover, DryBulb, DewPoint, RelHum);
    8647          384 :             HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    8648          384 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8649          384 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8650          384 :                 SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    8651              :             } else {
    8652            0 :                 SkyTemp = 0.0; // dealt with later
    8653              :             }
    8654          384 :         } else {
    8655              :             // Valid IR from weather files
    8656        90120 :             HorizIRSky = IRHoriz;
    8657        90120 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8658        90120 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8659        90120 :                 SkyTemp = root_4(IRHoriz / Constant::StefanBoltzmann) - Constant::Kelvin;
    8660              :             } else {
    8661            0 :                 SkyTemp = 0.0; // dealt with later
    8662              :             }
    8663              :         }
    8664        90504 :     }
    8665              : 
    8666              : } // namespace Weather
    8667              : 
    8668              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1