LCOV - code coverage report
Current view: top level - EnergyPlus - WeatherManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 3123 4580 68.2 %
Date: 2024-08-24 18:31:18 Functions: 81 94 86.2 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <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/Fmath.hh>
      58             : #include <ObjexxFCL/string.functions.hh>
      59             : #include <ObjexxFCL/time.hh>
      60             : 
      61             : // EnergyPlus Headers
      62             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      63             : #include <EnergyPlus/DataEnvironment.hh>
      64             : #include <EnergyPlus/DataHeatBalance.hh>
      65             : #include <EnergyPlus/DataIPShortCuts.hh>
      66             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      67             : #include <EnergyPlus/DataReportingFlags.hh>
      68             : #include <EnergyPlus/DataSurfaces.hh>
      69             : #include <EnergyPlus/DataSystemVariables.hh>
      70             : #include <EnergyPlus/DataWater.hh>
      71             : #include <EnergyPlus/DisplayRoutines.hh>
      72             : #include <EnergyPlus/EMSManager.hh>
      73             : #include <EnergyPlus/FileSystem.hh>
      74             : #include <EnergyPlus/General.hh>
      75             : #include <EnergyPlus/GlobalNames.hh>
      76             : #include <EnergyPlus/GroundTemperatureModeling/GroundTemperatureModelManager.hh>
      77             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      78             : #include <EnergyPlus/OutputProcessor.hh>
      79             : #include <EnergyPlus/OutputReportPredefined.hh>
      80             : #include <EnergyPlus/OutputReportTabular.hh>
      81             : #include <EnergyPlus/Psychrometrics.hh>
      82             : #include <EnergyPlus/ScheduleManager.hh>
      83             : #include <EnergyPlus/StringUtilities.hh>
      84             : #include <EnergyPlus/SurfaceGeometry.hh>
      85             : #include <EnergyPlus/ThermalComfort.hh>
      86             : #include <EnergyPlus/UtilityRoutines.hh>
      87             : #include <EnergyPlus/Vectors.hh>
      88             : #include <EnergyPlus/WaterManager.hh>
      89             : #include <EnergyPlus/WeatherManager.hh>
      90             : 
      91             : namespace EnergyPlus {
      92             : 
      93             : namespace Weather {
      94             : 
      95             :     // MODULE INFORMATION:
      96             :     //       AUTHOR         Rick Strand
      97             :     //       DATE WRITTEN   May 1997
      98             :     //       MODIFIED       December 1998, FW; December 1999, LKL.
      99             : 
     100             :     // PURPOSE OF THIS MODULE:
     101             :     // This module contains all of the weather handling routines for
     102             :     // EnergyPlus.  That includes getting user input, defining design day
     103             :     // weather, retrieving data from weather files, and supplying the
     104             :     // outdoor environment for each time step.
     105             : 
     106             :     constexpr std::array<std::string_view, (int)EpwHeaderType::Num> epwHeaders = {"LOCATION",
     107             :                                                                                   "DESIGN CONDITIONS",
     108             :                                                                                   "TYPICAL/EXTREME PERIODS",
     109             :                                                                                   "GROUND TEMPERATURES",
     110             :                                                                                   "HOLIDAYS/DAYLIGHT SAVING",
     111             :                                                                                   "COMMENTS 1",
     112             :                                                                                   "COMMENTS 2",
     113             :                                                                                   "DATA PERIODS"};
     114             : 
     115             :     static constexpr std::array<std::string_view, (int)WaterMainsTempCalcMethod::Num> waterMainsCalcMethodNames{
     116             :         "Schedule", "Correlation", "CorrelationFromWeatherFile", "FixedDefault"};
     117             : 
     118             :     static constexpr std::array<std::string_view, (int)WaterMainsTempCalcMethod::Num> waterMainsCalcMethodNamesUC{
     119             :         "SCHEDULE", "CORRELATION", "CORRELATIONFROMWEATHERFILE", "FIXEDDEFAULT"};
     120             : 
     121             :     static constexpr std::array<std::string_view, (int)SkyTempModel::Num> SkyTempModelNamesUC{
     122             :         "CLARKALLEN", "SCHEDULEVALUE", "DIFFERENCESCHEDULEDRYBULBVALUE", "DIFFERENCESCHEDULEDEWPOINTVALUE", "BRUNT", "IDSO", "BERDAHLMARTIN"};
     123             : 
     124             :     static constexpr std::array<std::string_view, (int)SkyTempModel::Num> SkyTempModelNames{"Clark and Allen",
     125             :                                                                                             "Schedule Value",
     126             :                                                                                             "DryBulb Difference Schedule Value",
     127             :                                                                                             "Dewpoint Difference Schedule Value",
     128             :                                                                                             "Brunt",
     129             :                                                                                             "Idso",
     130             :                                                                                             "Berdahl and Martin"};
     131             : 
     132     2900842 :     void ManageWeather(EnergyPlusData &state)
     133             :     {
     134             : 
     135             :         // SUBROUTINE INFORMATION:
     136             :         //       AUTHOR         Rick Strand
     137             :         //       DATE WRITTEN   May 1997
     138             :         //       MODIFIED       June 1997 (general clean-up)
     139             : 
     140             :         // PURPOSE OF THIS SUBROUTINE:
     141             :         // This subroutine is the main driver of the weather manager module.
     142             :         // It controls the assignment of weather related global variables as
     143             :         // well as the reads and writes for weather information.
     144             : 
     145     2900842 :         InitializeWeather(state, state.dataWeather->PrintEnvrnStamp);
     146             : 
     147     2900842 :         bool anyEMSRan = false;
     148             :         // Cannot call this during sizing, because EMS will not initialize properly until after simulation kickoff
     149     2900842 :         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     150     1976977 :             EMSManager::ManageEMS(state,
     151             :                                   EMSManager::EMSCallFrom::BeginZoneTimestepBeforeSetCurrentWeather,
     152             :                                   anyEMSRan,
     153     3953954 :                                   ObjexxFCL::Optional_int_const()); // calling point
     154             :         }
     155     2900842 :         SetCurrentWeather(state);
     156             : 
     157     2900842 :         ReportWeatherAndTimeInformation(state, state.dataWeather->PrintEnvrnStamp);
     158     2900842 :     }
     159             : 
     160        2834 :     void ResetEnvironmentCounter(EnergyPlusData &state)
     161             :     {
     162        2834 :         state.dataWeather->Envrn = 0;
     163        2834 :     }
     164             : 
     165         794 :     bool CheckIfAnyUnderwaterBoundaries(EnergyPlusData &state)
     166             :     {
     167         794 :         bool errorsFound = false;
     168         794 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     169             : 
     170         794 :         constexpr std::string_view routineName = "CheckIfAnyUnderwaterBoundaries";
     171             : 
     172         794 :         auto const &ipsc = state.dataIPShortCut;
     173         794 :         ipsc->cCurrentModuleObject = "SurfaceProperty:Underwater";
     174         794 :         int Num = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
     175         795 :         for (int i = 1; i <= Num; i++) {
     176           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     177           1 :                                                                      ipsc->cCurrentModuleObject,
     178             :                                                                      i,
     179           1 :                                                                      ipsc->cAlphaArgs,
     180             :                                                                      NumAlpha,
     181           1 :                                                                      ipsc->rNumericArgs,
     182             :                                                                      NumNumber,
     183             :                                                                      IOStat,
     184           1 :                                                                      ipsc->lNumericFieldBlanks,
     185           1 :                                                                      ipsc->lAlphaFieldBlanks,
     186           1 :                                                                      ipsc->cAlphaFieldNames,
     187           1 :                                                                      ipsc->cNumericFieldNames);
     188           1 :             state.dataWeather->underwaterBoundaries.emplace_back();
     189           1 :             auto &underwaterBoundary = state.dataWeather->underwaterBoundaries[i - 1];
     190           1 :             underwaterBoundary.Name = ipsc->cAlphaArgs(1);
     191             : 
     192           1 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, underwaterBoundary.Name};
     193             : 
     194           1 :             underwaterBoundary.distanceFromLeadingEdge = ipsc->rNumericArgs(1);
     195           1 :             underwaterBoundary.OSCMIndex = Util::FindItemInList(underwaterBoundary.Name, state.dataSurface->OSCM);
     196           1 :             if (underwaterBoundary.OSCMIndex <= 0) {
     197           0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
     198           0 :                 errorsFound = true;
     199             :             }
     200           1 :             underwaterBoundary.WaterTempScheduleIndex = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(2));
     201           1 :             if (underwaterBoundary.WaterTempScheduleIndex == 0) {
     202           0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     203           0 :                 errorsFound = true;
     204             :             }
     205             : 
     206           1 :             if (ipsc->lAlphaFieldBlanks(3)) {
     207             :                 // that's OK, we can have a blank schedule, the water will just have no free stream velocity
     208           0 :                 underwaterBoundary.VelocityScheduleIndex = 0;
     209           1 :             } else if ((underwaterBoundary.VelocityScheduleIndex = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(3))) == 0) {
     210           0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     211           0 :                 errorsFound = true;
     212             :             }
     213           1 :             if (errorsFound) break;
     214             :         }
     215         794 :         if (errorsFound) {
     216           0 :             ShowFatalError(state, "Previous input problems cause program termination");
     217             :         }
     218         794 :         return (Num > 0);
     219             :     }
     220             : 
     221             :     Real64
     222        1343 :     calculateWaterBoundaryConvectionCoefficient(Real64 const curWaterTemp, Real64 const freeStreamVelocity, Real64 const distanceFromLeadingEdge)
     223             :     {
     224        1343 :         Real64 constexpr waterKinematicViscosity = 1e-6; // m2/s
     225        1343 :         Real64 constexpr waterPrandtlNumber = 6;         // -
     226        1343 :         Real64 constexpr waterThermalConductivity = 0.6; // W/mK
     227             :         // do some calculation for forced convection from the leading edge of the ship
     228        1343 :         Real64 const localReynoldsNumber = freeStreamVelocity * distanceFromLeadingEdge / waterKinematicViscosity;
     229        1343 :         Real64 const localNusseltNumber = 0.0296 * pow(localReynoldsNumber, 0.8) * pow(waterPrandtlNumber, 1.0 / 3.0);
     230        1343 :         Real64 const localConvectionCoeff = localNusseltNumber * waterThermalConductivity / distanceFromLeadingEdge;
     231             : 
     232             :         // do some calculations for natural convection from the bottom of the ship
     233        1343 :         Real64 constexpr distanceFromBottomOfHull = 12; // meters, assumed for now
     234             :                                                         // this Prandtl correction is from Incropera & Dewitt, Intro to HT, eq 9.20
     235        1343 :         Real64 const prandtlCorrection =
     236             :             (0.75 * pow(waterPrandtlNumber, 0.5)) / pow(0.609 + 1.221 * pow(waterPrandtlNumber, 0.5) + 1.238 * waterPrandtlNumber, 0.25);
     237             :         // calculate the Grashof number
     238        1343 :         Real64 constexpr gravity = 9.81;          // m/s2
     239        1343 :         Real64 constexpr beta = 0.000214;         // water thermal expansion coefficient, from engineeringtoolbox.com, 1/C
     240        1343 :         Real64 constexpr assumedSurfaceTemp = 25; // Grashof requires a surface temp, this should suffice
     241             :         Real64 const localGrashofNumber =
     242        1343 :             (gravity * beta * std::abs(assumedSurfaceTemp - curWaterTemp) * pow(distanceFromBottomOfHull, 3)) / pow(waterKinematicViscosity, 2);
     243        1343 :         Real64 const localNusseltFreeConvection = pow(localGrashofNumber / 4, 0.25) * prandtlCorrection;
     244        1343 :         Real64 const localConvectionCoeffFreeConv = localNusseltFreeConvection * waterThermalConductivity / distanceFromBottomOfHull;
     245        1343 :         return max(localConvectionCoeff, localConvectionCoeffFreeConv);
     246             :     }
     247             : 
     248        1343 :     void UpdateUnderwaterBoundaries(EnergyPlusData &state)
     249             :     {
     250        2686 :         for (auto &thisBoundary : state.dataWeather->underwaterBoundaries) {
     251        1343 :             Real64 const curWaterTemp = ScheduleManager::GetCurrentScheduleValue(state, thisBoundary.WaterTempScheduleIndex); // C
     252        1343 :             Real64 freeStreamVelocity = 0;
     253        1343 :             if (thisBoundary.VelocityScheduleIndex > 0) {
     254        1343 :                 freeStreamVelocity = ScheduleManager::GetCurrentScheduleValue(state, thisBoundary.VelocityScheduleIndex); // m/s
     255             :             }
     256        1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TConv = curWaterTemp;
     257        1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HConv =
     258        1343 :                 Weather::calculateWaterBoundaryConvectionCoefficient(curWaterTemp, freeStreamVelocity, thisBoundary.distanceFromLeadingEdge);
     259        1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).TRad = curWaterTemp;
     260        1343 :             state.dataSurface->OSCM(thisBoundary.OSCMIndex).HRad = 0.0;
     261        1343 :         }
     262        1343 :     }
     263             : 
     264         795 :     void ReadVariableLocationOrientation(EnergyPlusData &state)
     265             :     {
     266         795 :         int NumAlpha = 0, NumNumber = 0, IOStat = 0;
     267         795 :         auto const &ipsc = state.dataIPShortCut;
     268             : 
     269         795 :         ipsc->cCurrentModuleObject = "Site:VariableLocation";
     270         795 :         if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject) == 0) return;
     271           2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     272           1 :                                                                  ipsc->cCurrentModuleObject,
     273             :                                                                  1,
     274           1 :                                                                  ipsc->cAlphaArgs,
     275             :                                                                  NumAlpha,
     276           1 :                                                                  ipsc->rNumericArgs,
     277             :                                                                  NumNumber,
     278             :                                                                  IOStat,
     279           1 :                                                                  ipsc->lNumericFieldBlanks,
     280           1 :                                                                  ipsc->lAlphaFieldBlanks,
     281           1 :                                                                  ipsc->cAlphaFieldNames,
     282           1 :                                                                  ipsc->cNumericFieldNames);
     283           1 :         state.dataEnvrn->varyingLocationSchedIndexLat = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(1));
     284           1 :         state.dataEnvrn->varyingLocationSchedIndexLong = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(2));
     285           1 :         state.dataEnvrn->varyingOrientationSchedIndex = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(3));
     286             :     }
     287             : 
     288        1344 :     void UpdateLocationAndOrientation(EnergyPlusData &state)
     289             :     {
     290        1344 :         if (state.dataEnvrn->varyingLocationSchedIndexLat > 0) {
     291        1344 :             state.dataEnvrn->Latitude = ScheduleManager::GetCurrentScheduleValue(state, state.dataEnvrn->varyingLocationSchedIndexLat);
     292             :         }
     293        1344 :         if (state.dataEnvrn->varyingLocationSchedIndexLong > 0) {
     294        1344 :             state.dataEnvrn->Longitude = ScheduleManager::GetCurrentScheduleValue(state, state.dataEnvrn->varyingLocationSchedIndexLong);
     295             :         }
     296        1344 :         CheckLocationValidity(state);
     297        1344 :         if (state.dataEnvrn->varyingOrientationSchedIndex > 0) {
     298        1344 :             state.dataHeatBal->BuildingAzimuth =
     299        1344 :                 mod(ScheduleManager::GetCurrentScheduleValue(state, state.dataEnvrn->varyingOrientationSchedIndex), 360.0);
     300        2688 :             state.dataSurfaceGeometry->CosBldgRelNorth =
     301        1344 :                 std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRadians);
     302        2688 :             state.dataSurfaceGeometry->SinBldgRelNorth =
     303        1344 :                 std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRadians);
     304        8064 :             for (size_t SurfNum = 1; SurfNum < state.dataSurface->Surface.size(); ++SurfNum) {
     305        6720 :                 auto &surf = state.dataSurface->Surface(SurfNum);
     306       33600 :                 for (int n = 1; n <= surf.Sides; ++n) {
     307       26880 :                     Real64 Xb = surf.Vertex(n).x;
     308       26880 :                     Real64 Yb = surf.Vertex(n).y;
     309       26880 :                     surf.NewVertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
     310       26880 :                     surf.NewVertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
     311       26880 :                     surf.NewVertex(n).z = surf.Vertex(n).z;
     312             :                 }
     313        6720 :                 Vectors::CreateNewellSurfaceNormalVector(surf.NewVertex, surf.Sides, surf.NewellSurfaceNormalVector);
     314        6720 :                 Real64 SurfWorldAz = 0.0;
     315        6720 :                 Real64 SurfTilt = 0.0;
     316        6720 :                 Vectors::DetermineAzimuthAndTilt(
     317        6720 :                     surf.NewVertex, SurfWorldAz, SurfTilt, surf.lcsx, surf.lcsy, surf.lcsz, surf.NewellSurfaceNormalVector);
     318        6720 :                 surf.Azimuth = SurfWorldAz;
     319        6720 :                 surf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRadians);
     320        6720 :                 surf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRadians);
     321        6720 :                 surf.OutNormVec = surf.NewellSurfaceNormalVector;
     322             :             }
     323             :         }
     324        1344 :     }
     325             : 
     326       11261 :     bool GetNextEnvironment(EnergyPlusData &state, bool &Available, bool &ErrorsFound)
     327             :     {
     328             : 
     329             :         // SUBROUTINE INFORMATION:
     330             :         //       AUTHOR         Linda Lawrie
     331             :         //       DATE WRITTEN   August 2000
     332             : 
     333             :         // PURPOSE OF THIS SUBROUTINE:
     334             :         // This subroutine is called from the outer simulation manager and determines
     335             :         // if another environment is available in the "run list" or if the end has been
     336             :         // reached.
     337             : 
     338             :         static constexpr std::string_view RoutineName("GetNextEnvironment: ");
     339             :         static constexpr std::string_view EnvNameFormat("Environment,{},{},{},{},{},{},{},{},{},{},{},{},{}\n");
     340             :         static constexpr std::string_view EnvDSTNFormat("Environment:Daylight Saving,No,{}\n");
     341             :         static constexpr std::string_view EnvDSTYFormat("Environment:Daylight Saving,Yes,{},{},{}\n");
     342             :         static constexpr std::string_view DateFormat("{:02}/{:02}");
     343             :         static constexpr std::string_view DateFormatWithYear("{:02}/{:02}/{:04}");
     344       11261 :         std::string StDate;
     345       11261 :         std::string EnDate;
     346             :         int DSTActStMon;
     347             :         int DSTActStDay;
     348             :         int DSTActEnMon;
     349             :         int DSTActEnDay;
     350             : 
     351       11261 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->GetEnvironmentFirstCall) {
     352             : 
     353         796 :             state.dataReportFlag->PrintEndDataDictionary = true;
     354             : 
     355         796 :             ReportOutputFileHeaders(state); // Write the output file header information
     356             : 
     357             :             // Setup Output Variables, CurrentModuleObject='All Simulations'
     358             : 
     359        1592 :             SetupOutputVariable(state,
     360             :                                 "Site Outdoor Air Drybulb Temperature",
     361             :                                 Constant::Units::C,
     362         796 :                                 state.dataEnvrn->OutDryBulbTemp,
     363             :                                 OutputProcessor::TimeStepType::Zone,
     364             :                                 OutputProcessor::StoreType::Average,
     365             :                                 "Environment");
     366        1592 :             SetupOutputVariable(state,
     367             :                                 "Site Outdoor Air Dewpoint Temperature",
     368             :                                 Constant::Units::C,
     369         796 :                                 state.dataEnvrn->OutDewPointTemp,
     370             :                                 OutputProcessor::TimeStepType::Zone,
     371             :                                 OutputProcessor::StoreType::Average,
     372             :                                 "Environment");
     373        1592 :             SetupOutputVariable(state,
     374             :                                 "Site Outdoor Air Wetbulb Temperature",
     375             :                                 Constant::Units::C,
     376         796 :                                 state.dataEnvrn->OutWetBulbTemp,
     377             :                                 OutputProcessor::TimeStepType::Zone,
     378             :                                 OutputProcessor::StoreType::Average,
     379             :                                 "Environment");
     380        1592 :             SetupOutputVariable(state,
     381             :                                 "Site Outdoor Air Humidity Ratio",
     382             :                                 Constant::Units::kgWater_kgDryAir,
     383         796 :                                 state.dataEnvrn->OutHumRat,
     384             :                                 OutputProcessor::TimeStepType::Zone,
     385             :                                 OutputProcessor::StoreType::Average,
     386             :                                 "Environment");
     387        1592 :             SetupOutputVariable(state,
     388             :                                 "Site Outdoor Air Relative Humidity",
     389             :                                 Constant::Units::Perc,
     390         796 :                                 state.dataEnvrn->OutRelHum,
     391             :                                 OutputProcessor::TimeStepType::Zone,
     392             :                                 OutputProcessor::StoreType::Average,
     393             :                                 "Environment");
     394        1592 :             SetupOutputVariable(state,
     395             :                                 "Site Outdoor Air Barometric Pressure",
     396             :                                 Constant::Units::Pa,
     397         796 :                                 state.dataEnvrn->OutBaroPress,
     398             :                                 OutputProcessor::TimeStepType::Zone,
     399             :                                 OutputProcessor::StoreType::Average,
     400             :                                 "Environment");
     401        1592 :             SetupOutputVariable(state,
     402             :                                 "Site Wind Speed",
     403             :                                 Constant::Units::m_s,
     404         796 :                                 state.dataEnvrn->WindSpeed,
     405             :                                 OutputProcessor::TimeStepType::Zone,
     406             :                                 OutputProcessor::StoreType::Average,
     407             :                                 "Environment");
     408        1592 :             SetupOutputVariable(state,
     409             :                                 "Site Wind Direction",
     410             :                                 Constant::Units::deg,
     411         796 :                                 state.dataEnvrn->WindDir,
     412             :                                 OutputProcessor::TimeStepType::Zone,
     413             :                                 OutputProcessor::StoreType::Average,
     414             :                                 "Environment");
     415        1592 :             SetupOutputVariable(state,
     416             :                                 "Site Sky Temperature",
     417             :                                 Constant::Units::C,
     418         796 :                                 state.dataEnvrn->SkyTemp,
     419             :                                 OutputProcessor::TimeStepType::Zone,
     420             :                                 OutputProcessor::StoreType::Average,
     421             :                                 "Environment");
     422        1592 :             SetupOutputVariable(state,
     423             :                                 "Site Horizontal Infrared Radiation Rate per Area",
     424             :                                 Constant::Units::W_m2,
     425         796 :                                 state.dataWeather->HorizIRSky,
     426             :                                 OutputProcessor::TimeStepType::Zone,
     427             :                                 OutputProcessor::StoreType::Average,
     428             :                                 "Environment");
     429        1592 :             SetupOutputVariable(state,
     430             :                                 "Site Diffuse Solar Radiation Rate per Area",
     431             :                                 Constant::Units::W_m2,
     432         796 :                                 state.dataEnvrn->DifSolarRad,
     433             :                                 OutputProcessor::TimeStepType::Zone,
     434             :                                 OutputProcessor::StoreType::Average,
     435             :                                 "Environment");
     436        1592 :             SetupOutputVariable(state,
     437             :                                 "Site Direct Solar Radiation Rate per Area",
     438             :                                 Constant::Units::W_m2,
     439         796 :                                 state.dataEnvrn->BeamSolarRad,
     440             :                                 OutputProcessor::TimeStepType::Zone,
     441             :                                 OutputProcessor::StoreType::Average,
     442             :                                 "Environment");
     443        1592 :             SetupOutputVariable(state,
     444             :                                 "Liquid Precipitation Depth",
     445             :                                 Constant::Units::m,
     446         796 :                                 state.dataEnvrn->LiquidPrecipitation,
     447             :                                 OutputProcessor::TimeStepType::Zone,
     448             :                                 OutputProcessor::StoreType::Sum,
     449             :                                 "Environment");
     450        1592 :             SetupOutputVariable(state,
     451             :                                 "Site Precipitation Rate",
     452             :                                 Constant::Units::m_s,
     453         796 :                                 state.dataWaterData->RainFall.CurrentRate,
     454             :                                 OutputProcessor::TimeStepType::Zone,
     455             :                                 OutputProcessor::StoreType::Average,
     456             :                                 "Environment");
     457        1592 :             SetupOutputVariable(state,
     458             :                                 "Site Precipitation Depth",
     459             :                                 Constant::Units::m,
     460         796 :                                 state.dataWaterData->RainFall.CurrentAmount,
     461             :                                 OutputProcessor::TimeStepType::Zone,
     462             :                                 OutputProcessor::StoreType::Sum,
     463             :                                 "Environment");
     464        1592 :             SetupOutputVariable(state,
     465             :                                 "Site Ground Reflected Solar Radiation Rate per Area",
     466             :                                 Constant::Units::W_m2,
     467         796 :                                 state.dataEnvrn->GndSolarRad,
     468             :                                 OutputProcessor::TimeStepType::Zone,
     469             :                                 OutputProcessor::StoreType::Average,
     470             :                                 "Environment");
     471        1592 :             SetupOutputVariable(state,
     472             :                                 "Site Ground Temperature",
     473             :                                 Constant::Units::C,
     474         796 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface],
     475             :                                 OutputProcessor::TimeStepType::Zone,
     476             :                                 OutputProcessor::StoreType::Average,
     477             :                                 "Environment");
     478        1592 :             SetupOutputVariable(state,
     479             :                                 "Site Surface Ground Temperature",
     480             :                                 Constant::Units::C,
     481         796 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow],
     482             :                                 OutputProcessor::TimeStepType::Zone,
     483             :                                 OutputProcessor::StoreType::Average,
     484             :                                 "Environment");
     485        1592 :             SetupOutputVariable(state,
     486             :                                 "Site Deep Ground Temperature",
     487             :                                 Constant::Units::C,
     488         796 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep],
     489             :                                 OutputProcessor::TimeStepType::Zone,
     490             :                                 OutputProcessor::StoreType::Average,
     491             :                                 "Environment");
     492        1592 :             SetupOutputVariable(state,
     493             :                                 "Site Simple Factor Model Ground Temperature",
     494             :                                 Constant::Units::C,
     495         796 :                                 state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod],
     496             :                                 OutputProcessor::TimeStepType::Zone,
     497             :                                 OutputProcessor::StoreType::Average,
     498             :                                 "Environment");
     499        1592 :             SetupOutputVariable(state,
     500             :                                 "Site Total Sky Cover",
     501             :                                 Constant::Units::None,
     502         796 :                                 state.dataEnvrn->TotalCloudCover,
     503             :                                 OutputProcessor::TimeStepType::Zone,
     504             :                                 OutputProcessor::StoreType::Average,
     505             :                                 "Environment");
     506        1592 :             SetupOutputVariable(state,
     507             :                                 "Site Opaque Sky Cover",
     508             :                                 Constant::Units::None,
     509         796 :                                 state.dataEnvrn->OpaqueCloudCover,
     510             :                                 OutputProcessor::TimeStepType::Zone,
     511             :                                 OutputProcessor::StoreType::Average,
     512             :                                 "Environment");
     513        1592 :             SetupOutputVariable(state,
     514             :                                 "Site Outdoor Air Enthalpy",
     515             :                                 Constant::Units::J_kg,
     516         796 :                                 state.dataEnvrn->OutEnthalpy,
     517             :                                 OutputProcessor::TimeStepType::Zone,
     518             :                                 OutputProcessor::StoreType::Average,
     519             :                                 "Environment");
     520        1592 :             SetupOutputVariable(state,
     521             :                                 "Site Outdoor Air Density",
     522             :                                 Constant::Units::kg_m3,
     523         796 :                                 state.dataEnvrn->OutAirDensity,
     524             :                                 OutputProcessor::TimeStepType::Zone,
     525             :                                 OutputProcessor::StoreType::Average,
     526             :                                 "Environment");
     527        1592 :             SetupOutputVariable(state,
     528             :                                 "Site Solar Azimuth Angle",
     529             :                                 Constant::Units::deg,
     530         796 :                                 state.dataWeather->SolarAzimuthAngle,
     531             :                                 OutputProcessor::TimeStepType::Zone,
     532             :                                 OutputProcessor::StoreType::Average,
     533             :                                 "Environment");
     534        1592 :             SetupOutputVariable(state,
     535             :                                 "Site Solar Altitude Angle",
     536             :                                 Constant::Units::deg,
     537         796 :                                 state.dataWeather->SolarAltitudeAngle,
     538             :                                 OutputProcessor::TimeStepType::Zone,
     539             :                                 OutputProcessor::StoreType::Average,
     540             :                                 "Environment");
     541        1592 :             SetupOutputVariable(state,
     542             :                                 "Site Solar Hour Angle",
     543             :                                 Constant::Units::deg,
     544         796 :                                 state.dataWeather->HrAngle,
     545             :                                 OutputProcessor::TimeStepType::Zone,
     546             :                                 OutputProcessor::StoreType::Average,
     547             :                                 "Environment");
     548        1592 :             SetupOutputVariable(state,
     549             :                                 "Site Rain Status",
     550             :                                 Constant::Units::None,
     551         796 :                                 state.dataWeather->RptIsRain,
     552             :                                 OutputProcessor::TimeStepType::Zone,
     553             :                                 OutputProcessor::StoreType::Average,
     554             :                                 "Environment");
     555        1592 :             SetupOutputVariable(state,
     556             :                                 "Site Snow on Ground Status",
     557             :                                 Constant::Units::None,
     558         796 :                                 state.dataWeather->RptIsSnow,
     559             :                                 OutputProcessor::TimeStepType::Zone,
     560             :                                 OutputProcessor::StoreType::Average,
     561             :                                 "Environment");
     562        1592 :             SetupOutputVariable(state,
     563             :                                 "Site Exterior Horizontal Sky Illuminance",
     564             :                                 Constant::Units::lux,
     565         796 :                                 state.dataEnvrn->HISKF,
     566             :                                 OutputProcessor::TimeStepType::Zone,
     567             :                                 OutputProcessor::StoreType::Average,
     568             :                                 "Environment");
     569        1592 :             SetupOutputVariable(state,
     570             :                                 "Site Exterior Horizontal Beam Illuminance",
     571             :                                 Constant::Units::lux,
     572         796 :                                 state.dataEnvrn->HISUNF,
     573             :                                 OutputProcessor::TimeStepType::Zone,
     574             :                                 OutputProcessor::StoreType::Average,
     575             :                                 "Environment");
     576        1592 :             SetupOutputVariable(state,
     577             :                                 "Site Exterior Beam Normal Illuminance",
     578             :                                 Constant::Units::lux,
     579         796 :                                 state.dataEnvrn->HISUNFnorm,
     580             :                                 OutputProcessor::TimeStepType::Zone,
     581             :                                 OutputProcessor::StoreType::Average,
     582             :                                 "Environment");
     583        1592 :             SetupOutputVariable(state,
     584             :                                 "Site Sky Diffuse Solar Radiation Luminous Efficacy",
     585             :                                 Constant::Units::lum_W,
     586         796 :                                 state.dataEnvrn->PDIFLW,
     587             :                                 OutputProcessor::TimeStepType::Zone,
     588             :                                 OutputProcessor::StoreType::Average,
     589             :                                 "Environment");
     590        1592 :             SetupOutputVariable(state,
     591             :                                 "Site Beam Solar Radiation Luminous Efficacy",
     592             :                                 Constant::Units::lum_W,
     593         796 :                                 state.dataEnvrn->PDIRLW,
     594             :                                 OutputProcessor::TimeStepType::Zone,
     595             :                                 OutputProcessor::StoreType::Average,
     596             :                                 "Environment");
     597        1592 :             SetupOutputVariable(state,
     598             :                                 "Site Daylighting Model Sky Clearness",
     599             :                                 Constant::Units::None,
     600         796 :                                 state.dataEnvrn->SkyClearness,
     601             :                                 OutputProcessor::TimeStepType::Zone,
     602             :                                 OutputProcessor::StoreType::Average,
     603             :                                 "Environment");
     604        1592 :             SetupOutputVariable(state,
     605             :                                 "Site Daylighting Model Sky Brightness",
     606             :                                 Constant::Units::None,
     607         796 :                                 state.dataEnvrn->SkyBrightness,
     608             :                                 OutputProcessor::TimeStepType::Zone,
     609             :                                 OutputProcessor::StoreType::Average,
     610             :                                 "Environment");
     611        1592 :             SetupOutputVariable(state,
     612             :                                 "Site Daylight Saving Time Status",
     613             :                                 Constant::Units::None,
     614         796 :                                 state.dataEnvrn->DSTIndicator,
     615             :                                 OutputProcessor::TimeStepType::Zone,
     616             :                                 OutputProcessor::StoreType::Average,
     617             :                                 "Environment");
     618        1592 :             SetupOutputVariable(state,
     619             :                                 "Site Day Type Index",
     620             :                                 Constant::Units::None,
     621         796 :                                 state.dataWeather->RptDayType,
     622             :                                 OutputProcessor::TimeStepType::Zone,
     623             :                                 OutputProcessor::StoreType::Average,
     624             :                                 "Environment");
     625        1592 :             SetupOutputVariable(state,
     626             :                                 "Site Mains Water Temperature",
     627             :                                 Constant::Units::C,
     628         796 :                                 state.dataEnvrn->WaterMainsTemp,
     629             :                                 OutputProcessor::TimeStepType::Zone,
     630             :                                 OutputProcessor::StoreType::Average,
     631             :                                 "Environment");
     632             : 
     633         796 :             if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
     634          73 :                 SetupEMSActuator(state,
     635             :                                  "Weather Data",
     636             :                                  "Environment",
     637             :                                  "Outdoor Dry Bulb",
     638             :                                  "[C]",
     639          73 :                                  state.dataEnvrn->EMSOutDryBulbOverrideOn,
     640          73 :                                  state.dataEnvrn->EMSOutDryBulbOverrideValue);
     641          73 :                 SetupEMSActuator(state,
     642             :                                  "Weather Data",
     643             :                                  "Environment",
     644             :                                  "Outdoor Dew Point",
     645             :                                  "[C]",
     646          73 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideOn,
     647          73 :                                  state.dataEnvrn->EMSOutDewPointTempOverrideValue);
     648          73 :                 SetupEMSActuator(state,
     649             :                                  "Weather Data",
     650             :                                  "Environment",
     651             :                                  "Outdoor Relative Humidity",
     652             :                                  "[%]",
     653          73 :                                  state.dataEnvrn->EMSOutRelHumOverrideOn,
     654          73 :                                  state.dataEnvrn->EMSOutRelHumOverrideValue);
     655          73 :                 SetupEMSActuator(state,
     656             :                                  "Weather Data",
     657             :                                  "Environment",
     658             :                                  "Diffuse Solar",
     659             :                                  "[W/m2]",
     660          73 :                                  state.dataEnvrn->EMSDifSolarRadOverrideOn,
     661          73 :                                  state.dataEnvrn->EMSDifSolarRadOverrideValue);
     662          73 :                 SetupEMSActuator(state,
     663             :                                  "Weather Data",
     664             :                                  "Environment",
     665             :                                  "Direct Solar",
     666             :                                  "[W/m2]",
     667          73 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideOn,
     668          73 :                                  state.dataEnvrn->EMSBeamSolarRadOverrideValue);
     669          73 :                 SetupEMSActuator(state,
     670             :                                  "Weather Data",
     671             :                                  "Environment",
     672             :                                  "Wind Speed",
     673             :                                  "[m/s]",
     674          73 :                                  state.dataEnvrn->EMSWindSpeedOverrideOn,
     675          73 :                                  state.dataEnvrn->EMSWindSpeedOverrideValue);
     676          73 :                 SetupEMSActuator(state,
     677             :                                  "Weather Data",
     678             :                                  "Environment",
     679             :                                  "Wind Direction",
     680             :                                  "[deg]",
     681          73 :                                  state.dataEnvrn->EMSWindDirOverrideOn,
     682          73 :                                  state.dataEnvrn->EMSWindDirOverrideValue);
     683             :             }
     684         796 :             state.dataWeather->GetEnvironmentFirstCall = false;
     685             : 
     686             :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
     687             : 
     688       11261 :         if (state.dataWeather->GetBranchInputOneTimeFlag) {
     689             : 
     690         796 :             SetupInterpolationValues(state);
     691         796 :             state.dataWeather->TimeStepFraction = 1.0 / double(state.dataGlobal->NumOfTimeStepInHour);
     692         796 :             state.dataEnvrn->rhoAirSTP = Psychrometrics::PsyRhoAirFnPbTdbW(
     693             :                 state, DataEnvironment::StdPressureSeaLevel, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
     694         796 :             OpenWeatherFile(state, ErrorsFound); // moved here because of possibility of special days on EPW file
     695         796 :             CloseWeatherFile(state);
     696         796 :             ReadUserWeatherInput(state);
     697         796 :             AllocateWeatherData(state);
     698         796 :             if (state.dataWeather->NumIntervalsPerHour != 1) {
     699           0 :                 if (state.dataWeather->NumIntervalsPerHour != state.dataGlobal->NumOfTimeStepInHour) {
     700           0 :                     ShowSevereError(
     701             :                         state,
     702           0 :                         format("{}Number of intervals per hour on Weather file does not match specified number of Time Steps Per Hour", RoutineName));
     703           0 :                     ErrorsFound = true;
     704             :                 }
     705             :             }
     706         796 :             state.dataWeather->GetBranchInputOneTimeFlag = false;
     707         796 :             state.dataWeather->Envrn = 0;
     708         796 :             if (state.dataWeather->NumOfEnvrn > 0) {
     709         796 :                 ResolveLocationInformation(state, ErrorsFound); // Obtain weather related info from input file
     710         796 :                 CheckLocationValidity(state);
     711        1567 :                 if ((state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
     712         771 :                     (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
     713         771 :                     CheckWeatherFileValidity(state);
     714             :                 }
     715         796 :                 if (ErrorsFound) {
     716           0 :                     ShowSevereError(state, format("{}No location specified, program will terminate.", RoutineName));
     717             :                 }
     718             :             } else {
     719           0 :                 ErrorsFound = true;
     720           0 :                 ShowSevereError(state, format("{}No Design Days or Run Period(s) specified, program will terminate.", RoutineName));
     721             :             }
     722         796 :             if (state.dataSysVars->DDOnly && state.dataEnvrn->TotDesDays == 0) {
     723           0 :                 ErrorsFound = true;
     724           0 :                 ShowSevereError(
     725             :                     state,
     726           0 :                     format("{}Requested Design Days only (DataSystemVariables::DDOnly) but no Design Days specified, program will terminate.",
     727             :                            RoutineName));
     728             :             }
     729         796 :             if (state.dataSysVars->ReverseDD && state.dataEnvrn->TotDesDays == 1) {
     730           0 :                 ErrorsFound = true;
     731           0 :                 ShowSevereError(
     732             :                     state,
     733           0 :                     format(
     734             :                         "{}Requested Reverse Design Days (DataSystemVariables::ReverseDD) but only 1 Design Day specified, program will terminate.",
     735             :                         RoutineName));
     736             :             }
     737             : 
     738             :             // Throw a Fatal now that we have said it'll terminalte
     739         796 :             if (ErrorsFound) {
     740           0 :                 CloseWeatherFile(state); // will only close if opened.
     741           0 :                 ShowFatalError(state, format("{}Errors found in Weather Data Input. Program terminates.", RoutineName));
     742             :             }
     743             : 
     744         796 :             state.dataEnvrn->CurrentOverallSimDay = 0;
     745         796 :             state.dataEnvrn->TotalOverallSimDays = 0;
     746         796 :             state.dataEnvrn->MaxNumberSimYears = 1;
     747        3652 :             for (int i = 1; i <= state.dataWeather->NumOfEnvrn; ++i) {
     748        2856 :                 state.dataEnvrn->TotalOverallSimDays += state.dataWeather->Environment(i).TotalDays;
     749        2856 :                 if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     750        1185 :                     state.dataEnvrn->MaxNumberSimYears = max(state.dataEnvrn->MaxNumberSimYears, state.dataWeather->Environment(i).NumSimYears);
     751             :                 }
     752             :             }
     753         796 :             DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
     754             :         }
     755             : 
     756       11261 :         CloseWeatherFile(state); // will only close if opened.
     757       11261 :         ++state.dataWeather->Envrn;
     758       11261 :         state.dataWeather->DatesShouldBeReset = false;
     759       11261 :         if (state.dataWeather->Envrn > state.dataWeather->NumOfEnvrn) {
     760        1593 :             Available = false;
     761        1593 :             state.dataWeather->Envrn = 0;
     762        1593 :             state.dataEnvrn->CurEnvirNum = 0;
     763             :         } else {
     764        9668 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
     765        9668 :             state.dataGlobal->KindOfSim = envCurr.KindOfEnvrn;
     766        9668 :             state.dataEnvrn->DayOfYear = envCurr.StartJDay;
     767        9668 :             state.dataEnvrn->DayOfMonth = envCurr.StartDay;
     768        9668 :             state.dataGlobal->CalendarYear = envCurr.StartYear;
     769        9668 :             state.dataGlobal->CalendarYearChr = fmt::to_string(state.dataGlobal->CalendarYear);
     770        9668 :             state.dataEnvrn->Month = envCurr.StartMonth;
     771        9668 :             state.dataGlobal->NumOfDayInEnvrn = envCurr.TotalDays; // Set day loop maximum from DataGlobals
     772             : 
     773       12655 :             if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
     774        2987 :                 (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
     775          13 :                 if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) {
     776           8 :                     if (state.dataGlobal->DoDesDaySim) {
     777           8 :                         ShowWarningError(state, format("{}Adaptive Comfort being reported during design day.", RoutineName));
     778           8 :                         Real64 GrossApproxAvgDryBulb = (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb +
     779           8 :                                                         (state.dataWeather->DesDayInput(state.dataWeather->Envrn).MaxDryBulb -
     780           8 :                                                          state.dataWeather->DesDayInput(state.dataWeather->Envrn).DailyDBRange)) /
     781           8 :                                                        2.0;
     782           8 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55)
     783           8 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, false, GrossApproxAvgDryBulb);
     784           8 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251)
     785           2 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, false, GrossApproxAvgDryBulb);
     786             :                     }
     787             :                 } else {
     788           5 :                     if (state.dataGlobal->DoWeathSim || state.dataGlobal->DoDesDaySim) {
     789           5 :                         if (state.dataHeatBal->AdaptiveComfortRequested_ASH55)
     790           5 :                             ThermalComfort::CalcThermalComfortAdaptiveASH55(state, true, true, 0.0);
     791           5 :                         if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251)
     792           1 :                             ThermalComfort::CalcThermalComfortAdaptiveCEN15251(state, true, true, 0.0);
     793             :                     }
     794             :                 }
     795             :             }
     796             : 
     797        9668 :             if (state.dataWeather->Envrn > state.dataEnvrn->TotDesDays && state.dataWeather->WeatherFileExists) {
     798        3749 :                 OpenEPlusWeatherFile(state, ErrorsFound, false);
     799             :             }
     800        9668 :             Available = true;
     801       13289 :             if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     802        3621 :                 (!state.dataWeather->WeatherFileExists && state.dataGlobal->DoWeathSim)) {
     803           0 :                 if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     804           0 :                     ShowSevereError(state, "Weather Simulation requested, but no weather file attached.");
     805           0 :                     ErrorsFound = true;
     806             :                 }
     807           0 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) state.dataWeather->Envrn = 0;
     808           0 :                 Available = false;
     809       13289 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) &&
     810        3621 :                        (!state.dataWeather->WeatherFileExists && !state.dataGlobal->DoWeathSim)) {
     811          20 :                 Available = false;
     812          20 :                 if (!state.dataGlobal->DoingHVACSizingSimulations) state.dataWeather->Envrn = 0;
     813        9648 :             } else if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoingSizing) {
     814        1208 :                 Available = false;
     815        1208 :                 state.dataWeather->Envrn = 0;
     816             :             }
     817             : 
     818        9668 :             if (!ErrorsFound && Available && state.dataWeather->Envrn > 0) {
     819        8440 :                 state.dataEnvrn->EnvironmentName = envCurr.Title;
     820        8440 :                 state.dataEnvrn->CurEnvirNum = state.dataWeather->Envrn;
     821        8440 :                 state.dataEnvrn->RunPeriodStartDayOfWeek = 0;
     822       10879 :                 if ((state.dataGlobal->DoDesDaySim && (state.dataGlobal->KindOfSim != Constant::KindOfSim::RunPeriodWeather)) ||
     823        2439 :                     ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) && state.dataGlobal->DoWeathSim)) {
     824        6013 :                     if (state.dataWeather->PrntEnvHeaders && state.dataReportFlag->DoWeatherInitReporting) {
     825             :                         static constexpr std::string_view EnvironFormat(
     826             :                             "! <Environment>,Environment Name,Environment Type, Start Date, End Date, Start DayOfWeek, Duration {#days}, "
     827             :                             "Source:Start DayOfWeek,  Use Daylight Saving, Use Holidays, Apply Weekend Holiday Rule,  Use Rain Values, Use Snow "
     828             :                             "Values, Sky Temperature Model\n! <Environment:Special Days>, Special Day Name, Special Day Type, Source, Start Date, "
     829             :                             "Duration {#days}\n! "
     830             :                             "<Environment:Daylight Saving>, Daylight Saving Indicator, Source, Start Date, End Date\n! <Environment:WarmupDays>, "
     831             :                             "NumberofWarmupDays");
     832         795 :                         print(state.files.eio, "{}\n", EnvironFormat);
     833         795 :                         state.dataWeather->PrntEnvHeaders = false;
     834             :                     }
     835             : 
     836       12014 :                     if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) ||
     837        6001 :                         (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign)) {
     838          34 :                         std::string kindOfRunPeriod = envCurr.cKindOfEnvrn;
     839          34 :                         state.dataEnvrn->RunPeriodEnvironment = state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather;
     840          34 :                         state.dataEnvrn->CurrentYearIsLeapYear = state.dataWeather->Environment(state.dataWeather->Envrn).IsLeapYear;
     841          34 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears) {
     842           2 :                             state.dataWeather->LeapYearAdd = 1;
     843             :                         } else {
     844          32 :                             state.dataWeather->LeapYearAdd = 0;
     845             :                         }
     846          34 :                         if (state.dataEnvrn->CurrentYearIsLeapYear) {
     847           2 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
     848             :                         }
     849          34 :                         state.dataWeather->UseDaylightSaving = envCurr.UseDST;
     850          34 :                         state.dataWeather->UseSpecialDays = envCurr.UseHolidays;
     851          34 :                         state.dataWeather->UseRainValues = envCurr.UseRain;
     852          34 :                         state.dataWeather->UseSnowValues = envCurr.UseSnow;
     853             : 
     854          34 :                         bool missingLeap(false); // Defer acting on anything found here until after the other range checks (see below)
     855             : 
     856          34 :                         if (envCurr.ActualWeather && !state.dataWeather->WFAllowsLeapYears) {
     857           0 :                             for (int year = envCurr.StartYear; year <= envCurr.EndYear; year++) {
     858           0 :                                 if (!isLeapYear(year)) continue;
     859             : 
     860           0 :                                 ShowSevereError(
     861             :                                     state,
     862           0 :                                     format("{}Weatherfile does not support leap years but runperiod includes a leap year ({})", RoutineName, year));
     863           0 :                                 missingLeap = true;
     864             :                             }
     865             :                         }
     866             : 
     867          34 :                         bool OkRun = false;
     868             : 
     869          34 :                         if (envCurr.ActualWeather) {
     870             :                             // Actual weather
     871           0 :                             for (auto &dataperiod : state.dataWeather->DataPeriods) {
     872           0 :                                 int runStartJulian = dataperiod.DataStJDay;
     873           0 :                                 int runEndJulian = dataperiod.DataEnJDay;
     874           0 :                                 if (!dataperiod.HasYearData) {
     875           0 :                                     ShowSevereError(state,
     876           0 :                                                     format("{}Actual weather runperiod has been entered but weatherfile DATA PERIOD does not have "
     877             :                                                            "year included in start/end date.",
     878             :                                                            RoutineName));
     879           0 :                                     ShowContinueError(state, "...to match the RunPeriod, the DATA PERIOD should be mm/dd/yyyy for both, or");
     880           0 :                                     ShowContinueError(state, "(...set \"Treat Weather as Actual\" to \"No\".)");
     881             :                                 }
     882           0 :                                 if (!General::BetweenDates(envCurr.StartDate, runStartJulian, runEndJulian)) continue;
     883           0 :                                 if (!General::BetweenDates(envCurr.EndDate, runStartJulian, runEndJulian)) continue;
     884           0 :                                 OkRun = true;
     885           0 :                                 break;
     886           0 :                             }
     887             :                         } else {
     888             :                             // Typical (or just non-actual) weather
     889          34 :                             for (auto &dataperiod : state.dataWeather->DataPeriods) {
     890             :                                 // Since this is not actual weather, there may be issues with this calculation
     891             :                                 // Assume the weather data starts the same year as the simulation, so LeapYearAdd is what
     892             :                                 // should be used.
     893          34 :                                 int runStartOrdinal = General::OrdinalDay(dataperiod.StMon, dataperiod.StDay, state.dataWeather->LeapYearAdd);
     894             :                                 // This one is harder, leave as is for now. What about multiple years of data?
     895          34 :                                 int runEndOrdinal = General::OrdinalDay(dataperiod.EnMon, dataperiod.EnDay, state.dataWeather->LeapYearAdd);
     896          34 :                                 if (runStartOrdinal == 1 && (runEndOrdinal == 366 || runEndOrdinal == 365)) {
     897             :                                     // Complete year(s) of weather data, will wrap around
     898          34 :                                     OkRun = true;
     899          34 :                                     break;
     900             :                                 }
     901           0 :                                 if (!General::BetweenDates(envCurr.StartJDay, runStartOrdinal, runEndOrdinal)) continue;
     902           0 :                                 if (!General::BetweenDates(envCurr.EndJDay, runStartOrdinal, runEndOrdinal)) continue;
     903           0 :                                 OkRun = true;
     904          34 :                             }
     905             :                         }
     906             : 
     907          34 :                         if (!OkRun) {
     908           0 :                             if (!envCurr.ActualWeather) {
     909           0 :                                 StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     910           0 :                                 EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     911           0 :                                 ShowSevereError(state,
     912           0 :                                                 format("{}Runperiod [mm/dd] (Start={},End={}) requested not within Data Period(s) from Weather File",
     913             :                                                        RoutineName,
     914             :                                                        StDate,
     915             :                                                        EnDate));
     916             :                             } else {
     917           0 :                                 StDate = format(DateFormatWithYear, envCurr.StartMonth, envCurr.StartDay, envCurr.StartYear);
     918           0 :                                 EnDate = format(DateFormatWithYear, envCurr.EndMonth, envCurr.EndDay, envCurr.EndYear);
     919           0 :                                 ShowSevereError(
     920             :                                     state,
     921           0 :                                     format("{}Runperiod [mm/dd/yyyy] (Start={},End={}) requested not within Data Period(s) from Weather File",
     922             :                                            RoutineName,
     923             :                                            StDate,
     924             :                                            EnDate));
     925             :                             }
     926             : 
     927           0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
     928           0 :                             StDate = format(DateFormat, dataPeriod1.StMon, dataPeriod1.StDay);
     929           0 :                             EnDate = format(DateFormat, dataPeriod1.EnMon, dataPeriod1.EnDay);
     930           0 :                             if (dataPeriod1.StYear > 0) {
     931           0 :                                 StDate += format("/{}", dataPeriod1.StYear);
     932             :                             } else {
     933           0 :                                 StDate += "/<noyear>";
     934             :                             }
     935           0 :                             if (dataPeriod1.EnYear > 0) {
     936           0 :                                 EnDate += format("/{}", dataPeriod1.EnYear);
     937             :                             } else {
     938           0 :                                 EnDate += "/<noyear>";
     939             :                             }
     940           0 :                             if (state.dataWeather->NumDataPeriods == 1) {
     941           0 :                                 ShowContinueError(state, format("Weather Data Period (Start={},End={})", StDate, EnDate));
     942             :                             } else {
     943           0 :                                 ShowContinueError(state, format("Multiple Weather Data Periods 1st (Start={},End={})", StDate, EnDate));
     944             :                             }
     945           0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     946             :                         }
     947             : 
     948          34 :                         if (missingLeap) {
     949             :                             // Bail out now if we still need to
     950           0 :                             ShowFatalError(state, format("{}Program terminates due to preceding condition.", RoutineName));
     951             :                         }
     952             : 
     953             :                         // Following builds Environment start/end for ASHRAE 55 warnings
     954          34 :                         StDate = format(DateFormat, envCurr.StartMonth, envCurr.StartDay);
     955          34 :                         EnDate = format(DateFormat, envCurr.EndMonth, envCurr.EndDay);
     956          34 :                         if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
     957          12 :                             StDate += format("/{}", envCurr.StartYear);
     958          12 :                             EnDate += format("/{}", envCurr.EndYear);
     959             :                         }
     960          34 :                         state.dataEnvrn->EnvironmentStartEnd = StDate + " - " + EnDate;
     961          34 :                         state.dataEnvrn->StartYear = envCurr.StartYear;
     962          34 :                         state.dataEnvrn->EndYear = envCurr.EndYear;
     963             : 
     964          34 :                         int TWeekDay = (envCurr.DayOfWeek == 0) ? 1 : envCurr.DayOfWeek;
     965          34 :                         auto const &MonWeekDay = envCurr.MonWeekDay;
     966             : 
     967          34 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
     968          11 :                             std::string_view const AlpUseDST = (envCurr.UseDST) ? "Yes" : "No";
     969          11 :                             std::string_view const AlpUseSpec = (envCurr.UseHolidays) ? "Yes" : "No";
     970          11 :                             std::string_view const ApWkRule = (envCurr.ApplyWeekendRule) ? "Yes" : "No";
     971          11 :                             std::string_view const AlpUseRain = (envCurr.UseRain) ? "Yes" : "No";
     972          11 :                             std::string_view const AlpUseSnow = (envCurr.UseSnow) ? "Yes" : "No";
     973             : 
     974          11 :                             print(state.files.eio,
     975             :                                   EnvNameFormat,
     976          11 :                                   envCurr.Title,
     977             :                                   kindOfRunPeriod,
     978             :                                   StDate,
     979             :                                   EnDate,
     980          11 :                                   ScheduleManager::dayTypeNames[TWeekDay],
     981          22 :                                   fmt::to_string(envCurr.TotalDays),
     982             :                                   "Use RunPeriod Specified Day",
     983             :                                   AlpUseDST,
     984             :                                   AlpUseSpec,
     985             :                                   ApWkRule,
     986             :                                   AlpUseRain,
     987             :                                   AlpUseSnow,
     988          11 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
     989             :                         }
     990             : 
     991          56 :                         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation &&
     992          62 :                             (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather && state.dataGlobal->DoWeathSim) &&
     993           6 :                             (state.dataHeatBal->AdaptiveComfortRequested_ASH55 || state.dataHeatBal->AdaptiveComfortRequested_CEN15251)) {
     994           0 :                             if (state.dataWeather->WFAllowsLeapYears) {
     995           0 :                                 ShowSevereError(
     996             :                                     state,
     997           0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with leap years in weather files.", RoutineName));
     998           0 :                                 ErrorsFound = true;
     999             :                             }
    1000           0 :                             if (state.dataWeather->NumDataPeriods != 1) {
    1001           0 :                                 ShowSevereError(
    1002             :                                     state,
    1003           0 :                                     format("{}AdaptiveComfort Reporting does not work correctly with multiple dataperiods in weather files.",
    1004             :                                            RoutineName));
    1005           0 :                                 ErrorsFound = true;
    1006             :                             }
    1007           0 :                             auto const &dataPeriod1 = state.dataWeather->DataPeriods(1);
    1008           0 :                             if (dataPeriod1.StMon == 1 && dataPeriod1.StDay == 1) {
    1009           0 :                                 int RunStJDay = General::OrdinalDay(dataPeriod1.StMon, dataPeriod1.StDay, state.dataWeather->LeapYearAdd);
    1010           0 :                                 int RunEnJDay = General::OrdinalDay(dataPeriod1.EnMon, dataPeriod1.EnDay, state.dataWeather->LeapYearAdd);
    1011           0 :                                 if (RunEnJDay - RunStJDay + 1 != 365) {
    1012           0 :                                     ShowSevereError(state,
    1013           0 :                                                     format("{}AdaptiveComfort Reporting does not work correctly with weather files that do "
    1014             :                                                            "not contain 365 days.",
    1015             :                                                            RoutineName));
    1016           0 :                                     ErrorsFound = true;
    1017             :                                 }
    1018           0 :                             } else {
    1019           0 :                                 ShowSevereError(state,
    1020           0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that do not "
    1021             :                                                        "start on 1 January.",
    1022             :                                                        RoutineName));
    1023           0 :                                 ErrorsFound = true;
    1024             :                             }
    1025           0 :                             if (state.dataWeather->NumIntervalsPerHour != 1) {
    1026           0 :                                 ShowSevereError(state,
    1027           0 :                                                 format("{}AdaptiveComfort Reporting does not work correctly with weather files that have "
    1028             :                                                        "multiple interval records per hour.",
    1029             :                                                        RoutineName));
    1030           0 :                                 ErrorsFound = true;
    1031             :                             }
    1032             :                         } // if
    1033             : 
    1034             :                         // Only need to set Week days for Run Days
    1035          34 :                         state.dataEnvrn->RunPeriodStartDayOfWeek = TWeekDay;
    1036          34 :                         state.dataWeather->WeekDayTypes = 0;
    1037          34 :                         int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1038          34 :                         int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1039             : 
    1040          34 :                         state.dataWeather->curSimDayForEndOfRunPeriod = envCurr.TotalDays;
    1041             : 
    1042          34 :                         int i = JDay5Start;
    1043             :                         while (true) {
    1044        4514 :                             state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1045        4514 :                             TWeekDay = mod(TWeekDay, 7) + 1;
    1046        4514 :                             ++i;
    1047        4514 :                             if (i > 366) i = 1;
    1048        4514 :                             if (i == JDay5End) break;
    1049             :                         }
    1050             : 
    1051          34 :                         state.dataWeather->DaylightSavingIsActive =
    1052          34 :                             (state.dataWeather->UseDaylightSaving && state.dataWeather->EPWDaylightSaving) || state.dataWeather->IDFDaylightSaving;
    1053             : 
    1054          34 :                         envCurr.SetWeekDays = false;
    1055             : 
    1056          34 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1057           2 :                             SetDSTDateRanges(state, MonWeekDay, state.dataWeather->DSTIndex, DSTActStMon, DSTActStDay, DSTActEnMon, DSTActEnDay);
    1058             :                         }
    1059             : 
    1060          34 :                         SetSpecialDayDates(state, MonWeekDay);
    1061             : 
    1062          34 :                         if (envCurr.StartMonth != 1 || envCurr.StartDay != 1) {
    1063          22 :                             state.dataWeather->StartDatesCycleShouldBeReset = true;
    1064          22 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1065             :                         }
    1066             : 
    1067          34 :                         if (envCurr.StartMonth == 1 && envCurr.StartDay == 1) {
    1068          12 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1069          12 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1070             :                         }
    1071             : 
    1072          34 :                         if (envCurr.ActualWeather) {
    1073           0 :                             state.dataWeather->StartDatesCycleShouldBeReset = false;
    1074           0 :                             state.dataWeather->Jan1DatesShouldBeReset = true;
    1075             :                         }
    1076             : 
    1077             :                         // Report Actual Dates for Daylight Saving and Special Days
    1078          34 :                         if (!state.dataGlobal->KickOffSimulation) {
    1079          23 :                             std::string Source;
    1080          23 :                             if (state.dataWeather->UseDaylightSaving) {
    1081           6 :                                 if (state.dataWeather->EPWDaylightSaving) {
    1082           1 :                                     Source = "WeatherFile";
    1083             :                                 }
    1084             :                             } else {
    1085          17 :                                 Source = "RunPeriod Object";
    1086             :                             }
    1087          23 :                             if (state.dataWeather->IDFDaylightSaving) {
    1088           0 :                                 Source = "InputFile";
    1089             :                             }
    1090          23 :                             if (state.dataWeather->DaylightSavingIsActive && state.dataReportFlag->DoWeatherInitReporting) {
    1091           1 :                                 StDate = format(DateFormat, DSTActStMon, DSTActStDay);
    1092           1 :                                 EnDate = format(DateFormat, DSTActEnMon, DSTActEnDay);
    1093           1 :                                 print(state.files.eio, EnvDSTYFormat, Source, StDate, EnDate);
    1094          22 :                             } else if (state.dataGlobal->DoOutputReporting) {
    1095          10 :                                 print(state.files.eio, EnvDSTNFormat, Source);
    1096             :                             }
    1097          44 :                             for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1098          21 :                                 auto &specialDay = state.dataWeather->SpecialDays(i);
    1099             :                                 static constexpr std::string_view EnvSpDyFormat("Environment:Special Days,{},{},{},{},{:3}\n");
    1100          21 :                                 if (specialDay.WthrFile && state.dataWeather->UseSpecialDays && state.dataReportFlag->DoWeatherInitReporting) {
    1101          11 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1102          11 :                                     print(state.files.eio,
    1103             :                                           EnvSpDyFormat,
    1104          11 :                                           specialDay.Name,
    1105          11 :                                           ScheduleManager::dayTypeNames[specialDay.DayType],
    1106             :                                           "WeatherFile",
    1107             :                                           StDate,
    1108          11 :                                           specialDay.Duration);
    1109             :                                 }
    1110          21 :                                 if (!specialDay.WthrFile && state.dataReportFlag->DoWeatherInitReporting) {
    1111          10 :                                     StDate = format(DateFormat, specialDay.ActStMon, specialDay.ActStDay);
    1112          10 :                                     print(state.files.eio,
    1113             :                                           EnvSpDyFormat,
    1114          10 :                                           specialDay.Name,
    1115          10 :                                           ScheduleManager::dayTypeNames[specialDay.DayType],
    1116             :                                           "InputFile",
    1117             :                                           StDate,
    1118          10 :                                           specialDay.Duration);
    1119             :                                 }
    1120             :                             }
    1121          23 :                         }
    1122             : 
    1123        6139 :                     } else if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay ||
    1124         126 :                                state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay) { // Design Day
    1125        5978 :                         auto const &desDayInput = state.dataWeather->DesDayInput(envCurr.DesignDayNum);
    1126        5978 :                         state.dataEnvrn->RunPeriodEnvironment = false;
    1127        5978 :                         StDate = format(DateFormat, desDayInput.Month, desDayInput.DayOfMonth);
    1128        5978 :                         EnDate = StDate;
    1129        5978 :                         if (state.dataReportFlag->DoWeatherInitReporting) {
    1130        1846 :                             print(state.files.eio,
    1131             :                                   EnvNameFormat,
    1132        1846 :                                   envCurr.Title,
    1133             :                                   "SizingPeriod:DesignDay",
    1134             :                                   StDate,
    1135             :                                   EnDate,
    1136        1846 :                                   ScheduleManager::dayTypeNames[desDayInput.DayType],
    1137             :                                   "1",
    1138             :                                   "N/A",
    1139             :                                   "N/A",
    1140             :                                   "N/A",
    1141             :                                   "N/A",
    1142             :                                   "N/A",
    1143             :                                   "N/A",
    1144        1846 :                                   SkyTempModelNames[(int)envCurr.skyTempModel]);
    1145             :                         }
    1146        5978 :                         if (desDayInput.DSTIndicator == 0 && state.dataReportFlag->DoWeatherInitReporting) {
    1147        1846 :                             print(state.files.eio, EnvDSTNFormat, "SizingPeriod:DesignDay");
    1148        4132 :                         } else if (state.dataReportFlag->DoWeatherInitReporting) {
    1149           0 :                             print(state.files.eio, EnvDSTYFormat, "SizingPeriod:DesignDay", StDate, EnDate);
    1150             :                         }
    1151             :                     }
    1152             :                 }
    1153             :             } // ErrorsFound
    1154             :         }
    1155             : 
    1156       11261 :         if (ErrorsFound && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    1157           0 :             ShowSevereError(state, format("{}Errors found in getting a new environment", RoutineName));
    1158           0 :             Available = false;
    1159       11261 :         } else if (ErrorsFound) {
    1160           0 :             Available = false;
    1161             :         }
    1162       22522 :         return Available && !ErrorsFound;
    1163       11261 :     }
    1164             : 
    1165          17 :     void AddDesignSetToEnvironmentStruct(EnergyPlusData &state, int const HVACSizingIterCount)
    1166             :     {
    1167          17 :         int OrigNumOfEnvrn = state.dataWeather->NumOfEnvrn;
    1168             : 
    1169          84 :         for (int i = 1; i <= OrigNumOfEnvrn; ++i) {
    1170             :             // Gotcha: references may no longer be valid after a redimension! Cannot declare reference to Environment(i) here.
    1171          67 :             if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1172          35 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1173          35 :                 auto &envBase = state.dataWeather->Environment(i);
    1174          35 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1175          35 :                 envNew = envBase; // copy over seed data from current array element
    1176          35 :                 envNew.SeedEnvrnNum = i;
    1177          35 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeDesignDay;
    1178          35 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1179          35 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1180          32 :             } else if (state.dataWeather->Environment(i).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    1181           0 :                 state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    1182           0 :                 auto &envBase = state.dataWeather->Environment(i);
    1183           0 :                 auto &envNew = state.dataWeather->Environment(state.dataWeather->NumOfEnvrn);
    1184           0 :                 envNew = envBase; // copy over seed data
    1185           0 :                 envNew.SeedEnvrnNum = i;
    1186           0 :                 envNew.KindOfEnvrn = Constant::KindOfSim::HVACSizeRunPeriodDesign;
    1187           0 :                 envNew.Title = format("{} HVAC Sizing Pass {}", envBase.Title, HVACSizingIterCount);
    1188           0 :                 envNew.HVACSizingIterationNum = HVACSizingIterCount;
    1189             :             }
    1190             :         } // for each loop over Environment data strucure
    1191          17 :     }
    1192             : 
    1193        1978 :     void SetupWeekDaysByMonth(EnergyPlusData &state, int const StMon, int const StDay, int const StWeekDay, Array1D_int &WeekDays)
    1194             :     {
    1195             : 
    1196             :         // SUBROUTINE INFORMATION:
    1197             :         //       AUTHOR         Linda Lawrie
    1198             :         //       DATE WRITTEN   August 2000
    1199             : 
    1200             :         // PURPOSE OF THIS SUBROUTINE:
    1201             :         // This subroutine calculates the weekday for each month based on the start date and
    1202             :         // weekday specified for that date.
    1203             : 
    1204             :         // Argument array dimensioning
    1205        1978 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1206             : 
    1207             :         // Set 1st day of Start Month
    1208        1978 :         int CurWeekDay{StWeekDay};
    1209        8168 :         for (int i = 1; i <= StDay - 1; ++i) {
    1210        6190 :             --CurWeekDay;
    1211        6190 :             if (CurWeekDay == 0) CurWeekDay = 7;
    1212             :         }
    1213             : 
    1214        1978 :         WeekDays(StMon) = CurWeekDay;
    1215       20940 :         for (int i = StMon + 1; i <= 12; ++i) {
    1216             : 
    1217       18962 :             if (i == 2) {
    1218        1473 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1219        7377 :                 while (CurWeekDay > 7) {
    1220        5904 :                     CurWeekDay -= 7;
    1221             :                 }
    1222        1473 :                 WeekDays(i) = CurWeekDay;
    1223       17489 :             } else if (i == 3) {
    1224        1489 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + state.dataWeather->LeapYearAdd;
    1225        7445 :                 while (CurWeekDay > 7) {
    1226        5956 :                     CurWeekDay -= 7;
    1227             :                 }
    1228        1489 :                 WeekDays(i) = CurWeekDay;
    1229       16000 :             } else if ((i >= 4) && (i <= 12)) {
    1230       16000 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1231       85906 :                 while (CurWeekDay > 7) {
    1232       69906 :                     CurWeekDay -= 7;
    1233             :                 }
    1234       16000 :                 WeekDays(i) = CurWeekDay;
    1235             :             }
    1236             :         }
    1237             : 
    1238        1978 :         if (any_eq(WeekDays, 0)) {
    1239             :             // need to start at StMon and go backwards.
    1240             :             // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1241         504 :             CurWeekDay = StWeekDay;
    1242        3125 :             for (int i = 1; i <= StDay - 1; ++i) {
    1243        2621 :                 --CurWeekDay;
    1244        2621 :                 if (CurWeekDay == 0) CurWeekDay = 7;
    1245             :             }
    1246             : 
    1247        3294 :             for (int i = StMon - 1; i >= 1; --i) {
    1248             : 
    1249        2790 :                 if (i == 1) {
    1250         504 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1251        2796 :                     while (CurWeekDay <= 0) {
    1252        2292 :                         CurWeekDay += 7;
    1253             :                     }
    1254         504 :                     WeekDays(i) = CurWeekDay;
    1255        2286 :                 } else if (i == 2) {
    1256         488 :                     CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + state.dataWeather->LeapYearAdd;
    1257        2440 :                     while (CurWeekDay <= 0) {
    1258        1952 :                         CurWeekDay += 7;
    1259             :                     }
    1260         488 :                     WeekDays(i) = CurWeekDay;
    1261        1798 :                 } else if ((i >= 3) && (i <= 12)) {
    1262        1798 :                     CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1263        9602 :                     while (CurWeekDay <= 0) {
    1264        7804 :                         CurWeekDay += 7;
    1265             :                     }
    1266        1798 :                     WeekDays(i) = CurWeekDay;
    1267             :                 }
    1268             :             }
    1269             :         }
    1270        1978 :     }
    1271             : #pragma clang diagnostic pop
    1272             : 
    1273           0 :     void ResetWeekDaysByMonth(EnergyPlusData &state,
    1274             :                               Array1D_int &WeekDays,
    1275             :                               int const AddLeapYear,
    1276             :                               int const StartMonth,
    1277             :                               int const StartMonthDay,
    1278             :                               int const EndMonth,
    1279             :                               int const EndMonthDay,
    1280             :                               bool const Rollover,
    1281             :                               bool const MidSimReset)
    1282             :     {
    1283             : 
    1284             :         // SUBROUTINE INFORMATION:
    1285             :         //       AUTHOR         Linda Lawrie
    1286             :         //       DATE WRITTEN   March 2012
    1287             : 
    1288             :         // PURPOSE OF THIS SUBROUTINE:
    1289             :         // This subroutine resets the weekday for each month based on the current weekday
    1290             :         // and previous weekdays per month.
    1291             : 
    1292           0 :         EP_SIZE_CHECK(WeekDays, 12); // NOLINT(misc-static-assert)
    1293             : 
    1294           0 :         Array1D_int WeekDaysCopy(12);
    1295             :         int CurWeekDay;
    1296             : 
    1297           0 :         WeekDaysCopy = WeekDays;
    1298           0 :         if (!MidSimReset) {
    1299           0 :             if (Rollover) {
    1300           0 :                 if (StartMonth == 1) {
    1301           0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1302             :                 } else {
    1303           0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1304             :                 }
    1305             :             } else { // restart at same as before
    1306           0 :                 CurWeekDay = WeekDays(StartMonth);
    1307             :             }
    1308           0 :             while (CurWeekDay > 7) {
    1309           0 :                 CurWeekDay -= 7;
    1310             :             }
    1311             : 
    1312           0 :             WeekDays = 0;
    1313           0 :             WeekDays(StartMonth) = CurWeekDay;
    1314           0 :             for (int i = StartMonth + 1; i <= 12; ++i) {
    1315           0 :                 if (i == 2) {
    1316           0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1317           0 :                     while (CurWeekDay > 7) {
    1318           0 :                         CurWeekDay -= 7;
    1319             :                     }
    1320           0 :                     WeekDays(i) = CurWeekDay;
    1321           0 :                 } else if (i == 3) {
    1322           0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1323           0 :                     while (CurWeekDay > 7) {
    1324           0 :                         CurWeekDay -= 7;
    1325             :                     }
    1326           0 :                     WeekDays(i) = CurWeekDay;
    1327           0 :                 } else if ((i >= 4) && (i <= 12)) {
    1328           0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1329           0 :                     while (CurWeekDay > 7) {
    1330           0 :                         CurWeekDay -= 7;
    1331             :                     }
    1332           0 :                     WeekDays(i) = CurWeekDay;
    1333             :                 }
    1334             :             }
    1335             : 
    1336           0 :             if (any_eq(WeekDays, 0)) {
    1337             :                 // need to start at StMon and go backwards.
    1338             :                 // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1339           0 :                 CurWeekDay = WeekDays(StartMonth);
    1340           0 :                 for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1341           0 :                     --CurWeekDay;
    1342           0 :                     if (CurWeekDay == 0) CurWeekDay = 7;
    1343             :                 }
    1344             : 
    1345           0 :                 for (int i = StartMonth - 1; i >= 1; --i) {
    1346             : 
    1347           0 :                     if (i == 1) {
    1348           0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1349           0 :                         while (CurWeekDay <= 0) {
    1350           0 :                             CurWeekDay += 7;
    1351             :                         }
    1352           0 :                         WeekDays(i) = CurWeekDay;
    1353           0 :                     } else if (i == 2) {
    1354           0 :                         CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1355           0 :                         while (CurWeekDay <= 0) {
    1356           0 :                             CurWeekDay += 7;
    1357             :                         }
    1358           0 :                         WeekDays(i) = CurWeekDay;
    1359           0 :                     } else if ((i >= 3) && (i <= 12)) {
    1360           0 :                         CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1361           0 :                         while (CurWeekDay <= 0) {
    1362           0 :                             CurWeekDay += 7;
    1363             :                         }
    1364           0 :                         WeekDays(i) = CurWeekDay;
    1365             :                     }
    1366             :                 }
    1367             :             }
    1368             : 
    1369             :         } else {
    1370           0 :             if (Rollover) {
    1371           0 :                 if (StartMonth == 1) {
    1372           0 :                     CurWeekDay = WeekDays(12) + state.dataWeather->EndDayOfMonth(12) + StartMonthDay - 1;
    1373             :                 } else {
    1374           0 :                     CurWeekDay = WeekDays(EndMonth) + EndMonthDay;
    1375             :                 }
    1376             :             } else { // restart at same as before
    1377           0 :                 CurWeekDay = WeekDays(StartMonth);
    1378             :             }
    1379           0 :             while (CurWeekDay > 7) {
    1380           0 :                 CurWeekDay -= 7;
    1381             :             }
    1382           0 :             WeekDays = 0;
    1383           0 :             if (StartMonth != 1) {
    1384           0 :                 CurWeekDay = WeekDaysCopy(12) + state.dataWeather->EndDayOfMonth(12);
    1385           0 :                 while (CurWeekDay > 7) {
    1386           0 :                     CurWeekDay -= 7;
    1387             :                 }
    1388           0 :                 WeekDays(1) = CurWeekDay;
    1389           0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1390           0 :                 while (CurWeekDay > 7) {
    1391           0 :                     CurWeekDay -= 7;
    1392             :                 }
    1393           0 :                 WeekDays(2) = CurWeekDay;
    1394           0 :                 CurWeekDay += state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1395           0 :                 while (CurWeekDay > 7) {
    1396           0 :                     CurWeekDay -= 7;
    1397             :                 }
    1398           0 :                 WeekDays(3) = CurWeekDay;
    1399           0 :                 for (int i = 4; i <= 12; ++i) {
    1400           0 :                     CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1401           0 :                     while (CurWeekDay > 7) {
    1402           0 :                         CurWeekDay -= 7;
    1403             :                     }
    1404           0 :                     WeekDays(i) = CurWeekDay;
    1405             :                 }
    1406             :             } else {
    1407           0 :                 WeekDays = 0;
    1408           0 :                 WeekDays(StartMonth) = CurWeekDay;
    1409           0 :                 for (int i = StartMonth + 1; i <= 12; ++i) {
    1410           0 :                     if (i == 2) {
    1411           0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(1);
    1412           0 :                         while (CurWeekDay > 7) {
    1413           0 :                             CurWeekDay -= 7;
    1414             :                         }
    1415           0 :                         WeekDays(i) = CurWeekDay;
    1416           0 :                     } else if (i == 3) {
    1417           0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1) + AddLeapYear;
    1418           0 :                         while (CurWeekDay > 7) {
    1419           0 :                             CurWeekDay -= 7;
    1420             :                         }
    1421           0 :                         WeekDays(i) = CurWeekDay;
    1422           0 :                     } else if ((i >= 4) && (i <= 12)) {
    1423           0 :                         CurWeekDay += state.dataWeather->EndDayOfMonth(i - 1);
    1424           0 :                         while (CurWeekDay > 7) {
    1425           0 :                             CurWeekDay -= 7;
    1426             :                         }
    1427           0 :                         WeekDays(i) = CurWeekDay;
    1428             :                     }
    1429             :                 }
    1430             : 
    1431           0 :                 if (any_eq(WeekDays, 0)) {
    1432             :                     // need to start at StMon and go backwards.
    1433             :                     // EndDayOfMonth is also "days" in month.  (without leapyear day in February)
    1434           0 :                     CurWeekDay = WeekDays(StartMonth);
    1435           0 :                     for (int i = 1; i <= StartMonthDay - 1; ++i) {
    1436           0 :                         --CurWeekDay;
    1437           0 :                         if (CurWeekDay == 0) CurWeekDay = 7;
    1438             :                     }
    1439             : 
    1440           0 :                     for (int i = StartMonth - 1; i >= 1; --i) {
    1441             : 
    1442           0 :                         if (i == 1) {
    1443           0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(1);
    1444           0 :                             while (CurWeekDay <= 0) {
    1445           0 :                                 CurWeekDay += 7;
    1446             :                             }
    1447           0 :                             WeekDays(i) = CurWeekDay;
    1448           0 :                         } else if (i == 2) {
    1449           0 :                             CurWeekDay = CurWeekDay - state.dataWeather->EndDayOfMonth(2) + AddLeapYear;
    1450           0 :                             while (CurWeekDay <= 0) {
    1451           0 :                                 CurWeekDay += 7;
    1452             :                             }
    1453           0 :                             WeekDays(i) = CurWeekDay;
    1454           0 :                         } else if ((i >= 3) && (i <= 12)) {
    1455           0 :                             CurWeekDay -= state.dataWeather->EndDayOfMonth(i);
    1456           0 :                             while (CurWeekDay <= 0) {
    1457           0 :                                 CurWeekDay += 7;
    1458             :                             }
    1459           0 :                             WeekDays(i) = CurWeekDay;
    1460             :                         }
    1461             :                     }
    1462             :                 }
    1463             :             }
    1464             :         }
    1465           0 :     }
    1466             : 
    1467           3 :     void SetDSTDateRanges(EnergyPlusData &state,
    1468             :                           Array1D_int const &MonWeekDay, // Weekday of each day 1 of month
    1469             :                           Array1D_int &DSTIdx,           // DST Index for each julian day (1:366)
    1470             :                           ObjexxFCL::Optional_int DSTActStMon,
    1471             :                           ObjexxFCL::Optional_int DSTActStDay,
    1472             :                           ObjexxFCL::Optional_int DSTActEnMon,
    1473             :                           ObjexxFCL::Optional_int DSTActEnDay)
    1474             :     {
    1475             : 
    1476             :         // SUBROUTINE INFORMATION:
    1477             :         //       AUTHOR         Linda Lawrie
    1478             :         //       DATE WRITTEN   March 2012
    1479             : 
    1480             :         // PURPOSE OF THIS SUBROUTINE:
    1481             :         // With multiple year weather files (or repeating weather files that rollover day),
    1482             :         // need to set DST (Daylight Saving Time) dates at start of environment or year.
    1483             :         // DST is only projected for one year.
    1484             : 
    1485             :         static constexpr std::string_view RoutineName("SetDSTDateRanges: ");
    1486             : 
    1487             :         int ActStartMonth; // Actual Start Month
    1488             :         int ActStartDay;   // Actual Start Day of Month
    1489             :         int ActEndMonth;   // Actual End Month
    1490             :         int ActEndDay;     // Actual End Day of Month
    1491             : 
    1492           3 :         bool ErrorsFound = false;
    1493           3 :         if (state.dataWeather->DST.StDateType == DateType::MonthDay) {
    1494           0 :             ActStartMonth = state.dataWeather->DST.StMon;
    1495           0 :             ActStartDay = state.dataWeather->DST.StDay;
    1496           3 :         } else if (state.dataWeather->DST.StDateType == DateType::NthDayInMonth) {
    1497           3 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1498           6 :             while (ThisDay <= 0) {
    1499           3 :                 ThisDay += 7;
    1500             :             }
    1501           3 :             ThisDay += 7 * (state.dataWeather->DST.StDay - 1);
    1502           3 :             if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1503           0 :                 ShowSevereError(state, format("{}Determining DST: DST Start Date, Nth Day of Month, not enough Nths", RoutineName));
    1504           0 :                 ErrorsFound = true;
    1505             :             } else {
    1506           3 :                 ActStartMonth = state.dataWeather->DST.StMon;
    1507           3 :                 ActStartDay = ThisDay;
    1508             :             }
    1509             :         } else { // LastWeekDayInMonth
    1510           0 :             int ThisDay = state.dataWeather->DST.StWeekDay - MonWeekDay(state.dataWeather->DST.StMon) + 1;
    1511           0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.StMon)) {
    1512           0 :                 ThisDay += 7;
    1513             :             }
    1514           0 :             ActStartMonth = state.dataWeather->DST.StMon;
    1515           0 :             ActStartDay = ThisDay;
    1516             :         }
    1517             : 
    1518           3 :         if (state.dataWeather->DST.EnDateType == DateType::MonthDay) {
    1519           0 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1520           0 :             ActEndDay = state.dataWeather->DST.EnDay;
    1521           3 :         } else if (state.dataWeather->DST.EnDateType == DateType::NthDayInMonth) {
    1522           3 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1523           6 :             while (ThisDay <= 0) {
    1524           3 :                 ThisDay += 7;
    1525             :             }
    1526           3 :             ThisDay += 7 * (state.dataWeather->DST.EnDay - 1);
    1527           3 :             if (ThisDay >> state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1528           0 :                 ActEndMonth = 0; // Suppress uninitialized warning
    1529           0 :                 ActEndDay = 0;   // Suppress uninitialized warning
    1530           0 :                 ShowSevereError(state, format("{}Determining DST: DST End Date, Nth Day of Month, not enough Nths", RoutineName));
    1531           0 :                 ErrorsFound = true;
    1532             :             } else {
    1533           3 :                 ActEndMonth = state.dataWeather->DST.EnMon;
    1534           3 :                 ActEndDay = ThisDay;
    1535             :             }
    1536             :         } else { // LastWeekDayInMonth
    1537           0 :             int ThisDay = state.dataWeather->DST.EnWeekDay - MonWeekDay(state.dataWeather->DST.EnMon) + 1;
    1538           0 :             while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(state.dataWeather->DST.EnMon)) {
    1539           0 :                 ThisDay += 7;
    1540             :             }
    1541           0 :             ActEndMonth = state.dataWeather->DST.EnMon;
    1542           0 :             ActEndDay = ThisDay;
    1543             :         }
    1544             : 
    1545           3 :         if (ErrorsFound) {
    1546           0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1547             :         }
    1548             : 
    1549           3 :         if (present(DSTActStMon)) {
    1550           2 :             DSTActStMon = ActStartMonth;
    1551           2 :             DSTActStDay = ActStartDay;
    1552           2 :             DSTActEnMon = ActEndMonth;
    1553           2 :             DSTActEnDay = ActEndDay;
    1554             :         }
    1555             : 
    1556           3 :         DSTIdx = 0;
    1557           3 :         int JDay = General::OrdinalDay(ActStartMonth, ActStartDay, state.dataWeather->LeapYearAdd);
    1558           3 :         int JDay1 = General::OrdinalDay(ActEndMonth, ActEndDay, state.dataWeather->LeapYearAdd);
    1559           3 :         if (JDay1 >= JDay) {
    1560           3 :             DSTIdx({JDay, JDay1}) = 1;
    1561             :         } else {
    1562           0 :             DSTIdx({JDay, 366}) = 1;
    1563           0 :             DSTIdx({1, JDay1}) = 1;
    1564             :         }
    1565           3 :     }
    1566             : 
    1567          40 :     void SetSpecialDayDates(EnergyPlusData &state, Array1D_int const &MonWeekDay) // Weekday of each day 1 of month
    1568             :     {
    1569             : 
    1570             :         // SUBROUTINE INFORMATION:
    1571             :         //       AUTHOR         Linda Lawrie
    1572             :         //       DATE WRITTEN   March 2012
    1573             : 
    1574             :         // PURPOSE OF THIS SUBROUTINE:
    1575             :         // With multiple year weather files (or repeating weather files that rollover day),
    1576             :         // need to set Special Day dates at start of environment or year.
    1577             :         // Special Days are only projected for one year.
    1578             : 
    1579             :         static constexpr std::string_view RoutineName("SetSpecialDayDates: ");
    1580             : 
    1581             :         int JDay;
    1582             : 
    1583          40 :         bool ErrorsFound = false;
    1584          40 :         state.dataWeather->SpecialDayTypes = 0;
    1585         103 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1586          63 :             auto &specialDay = state.dataWeather->SpecialDays(i);
    1587          63 :             if (specialDay.WthrFile && !state.dataWeather->UseSpecialDays) continue;
    1588          63 :             if (specialDay.dateType <= DateType::MonthDay) {
    1589          30 :                 JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd);
    1590          30 :                 if (specialDay.Duration == 1 && state.dataWeather->Environment(state.dataWeather->Envrn).ApplyWeekendRule) {
    1591          18 :                     if (state.dataWeather->WeekDayTypes(JDay) == static_cast<int>(ScheduleManager::DayType::Sunday)) {
    1592             :                         // Sunday, must go to Monday
    1593           6 :                         ++JDay;
    1594           6 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1595          12 :                     } else if (state.dataWeather->WeekDayTypes(JDay) == (int)ScheduleManager::DayType::Saturday) {
    1596           0 :                         ++JDay;
    1597           0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1598           0 :                         ++JDay;
    1599           0 :                         if (JDay == 366 && state.dataWeather->LeapYearAdd == 0) JDay = 1;
    1600             :                     }
    1601             :                 }
    1602          30 :                 General::InvOrdinalDay(JDay, specialDay.ActStMon, specialDay.ActStDay, state.dataWeather->LeapYearAdd);
    1603          33 :             } else if (specialDay.dateType == DateType::NthDayInMonth) {
    1604          27 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1605          27 :                 if (specialDay.WeekDay < MonWeekDay(specialDay.Month)) {
    1606          18 :                     ThisDay += 7;
    1607             :                 }
    1608          27 :                 ThisDay += 7 * (specialDay.Day - 1);
    1609          27 :                 if (ThisDay > state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1610           0 :                     ShowSevereError(state,
    1611           0 :                                     format("{}Special Day Date, Nth Day of Month, not enough Nths, for SpecialDay={}", RoutineName, specialDay.Name));
    1612           0 :                     ErrorsFound = true;
    1613           0 :                     continue;
    1614             :                 }
    1615          27 :                 specialDay.ActStMon = specialDay.Month;
    1616          27 :                 specialDay.ActStDay = ThisDay;
    1617          27 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1618             :             } else { // LastWeekDayInMonth
    1619           6 :                 int ThisDay = specialDay.WeekDay - MonWeekDay(specialDay.Month) + 1;
    1620          33 :                 while (ThisDay + 7 <= state.dataWeather->EndDayOfMonthWithLeapDay(specialDay.Month)) {
    1621          27 :                     ThisDay += 7;
    1622             :                 }
    1623           6 :                 specialDay.ActStMon = specialDay.Month;
    1624           6 :                 specialDay.ActStDay = ThisDay;
    1625           6 :                 JDay = General::OrdinalDay(specialDay.Month, ThisDay, state.dataWeather->LeapYearAdd);
    1626             :             }
    1627          63 :             if (state.dataWeather->SpecialDayTypes(JDay) != 0) {
    1628           0 :                 ShowWarningError(
    1629             :                     state,
    1630           0 :                     format("{}Special Day definition ({}) is overwriting previously entered special day period", RoutineName, specialDay.Name));
    1631           0 :                 if (state.dataWeather->UseSpecialDays) {
    1632           0 :                     ShowContinueError(state, "...This could be caused by definitions on the Weather File.");
    1633             :                 }
    1634           0 :                 ShowContinueError(state, "...This could be caused by duplicate definitions in the Input File.");
    1635             :             }
    1636          63 :             int JDay1 = JDay - 1;
    1637         126 :             for (int j = 0; j <= specialDay.Duration - 1; ++j) {
    1638          63 :                 ++JDay1;
    1639          63 :                 if (JDay1 == 366 && state.dataWeather->LeapYearAdd == 0) JDay1 = 1;
    1640          63 :                 if (JDay1 == 367) JDay1 = 1;
    1641          63 :                 state.dataWeather->SpecialDayTypes(JDay1) = specialDay.DayType;
    1642             :             }
    1643             :         }
    1644             : 
    1645          40 :         if (ErrorsFound) {
    1646           0 :             ShowFatalError(state, format("{}Program terminates due to preceding condition(s).", RoutineName));
    1647             :         }
    1648          40 :     }
    1649             : 
    1650     2900842 :     void InitializeWeather(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    1651             :     {
    1652             : 
    1653             :         // SUBROUTINE INFORMATION:
    1654             :         //       AUTHOR         Rick Strand
    1655             :         //       DATE WRITTEN   June 1997
    1656             : 
    1657             :         // PURPOSE OF THIS SUBROUTINE:
    1658             :         // This subroutine is the main driver of the weather initializations.
    1659             :         // Most of the weather handling can be described as "initializations"
    1660             :         // so most of the work is done via this subroutine.
    1661             : 
    1662     2900842 :         if (state.dataGlobal->BeginSimFlag && state.dataWeather->FirstCall) {
    1663             : 
    1664         796 :             state.dataWeather->FirstCall = false;
    1665         796 :             state.dataEnvrn->EndMonthFlag = false;
    1666             : 
    1667             :         } // ... end of DataGlobals::BeginSimFlag IF-THEN block.
    1668             : 
    1669     2900842 :         auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    1670     2900842 :         if (state.dataGlobal->BeginEnvrnFlag) {
    1671             : 
    1672             :             // Call and setup the Design Day environment
    1673        7158 :             if (envCurr.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) {
    1674        5955 :                 if (envCurr.DesignDayNum > 0) {
    1675        5932 :                     SetUpDesignDay(state, envCurr.DesignDayNum);
    1676        5932 :                     state.dataEnvrn->EnvironmentName = envCurr.Title;
    1677             :                 }
    1678             :             }
    1679             : 
    1680             :             // Only used in Weather file environments
    1681             :             // Start over missing values with each environment
    1682        7158 :             state.dataWeather->wvarsMissing.OutBaroPress = state.dataEnvrn->StdBaroPress; // Initial "missing" value
    1683        7158 :             state.dataWeather->wvarsMissing.OutDryBulbTemp = 6.0;                         // Initial "missing" value
    1684        7158 :             state.dataWeather->wvarsMissing.OutDewPointTemp = 3.0;                        // Initial "missing" value
    1685        7158 :             state.dataWeather->wvarsMissing.OutRelHum = 50.0;                             // Initial "missing" value
    1686        7158 :             state.dataWeather->wvarsMissing.WindSpeed = 2.5;                              // Initial "missing" value
    1687        7158 :             state.dataWeather->wvarsMissing.WindDir = 180;                                // Initial "missing" value
    1688        7158 :             state.dataWeather->wvarsMissing.TotalSkyCover = 5;                            // Initial "missing" value
    1689        7158 :             state.dataWeather->wvarsMissing.OpaqueSkyCover = 5;                           // Initial "missing" value
    1690        7158 :             state.dataWeather->wvarsMissing.Visibility = 777.7;                           // Initial "missing" value
    1691        7158 :             state.dataWeather->wvarsMissing.Ceiling = 77777;                              // Initial "missing" value
    1692        7158 :             state.dataWeather->wvarsMissing.AerOptDepth = 0.0;                            // Initial "missing" value
    1693        7158 :             state.dataWeather->wvarsMissing.SnowDepth = 0;                                // Initial "missing" value
    1694        7158 :             state.dataWeather->wvarsMissing.DaysLastSnow = 88;                            // Initial "missing" value
    1695        7158 :             state.dataWeather->wvarsMissing.Albedo = 0.0;                                 // Initial "missing" value
    1696        7158 :             state.dataWeather->wvarsMissing.LiquidPrecip = 0.0;                           // Initial "missing" value
    1697             :             // Counts set to 0 for each environment
    1698        7158 :             state.dataWeather->wvarsMissedCounts = Weather::WeatherVarCounts();
    1699             : 
    1700             :             // Counts set to 0 for each environment
    1701        7158 :             state.dataWeather->wvarsOutOfRangeCounts = Weather::WeatherVarCounts();
    1702             : 
    1703        7158 :             state.dataWeather->IsRainThreshold = 0.8 / double(state.dataGlobal->NumOfTimeStepInHour); // [mm]
    1704             : 
    1705        7158 :             if (!state.dataWeather->RPReadAllWeatherData) {
    1706        7157 :                 printEnvrnStamp = true; // Set this to true so that on first non-warmup day (only) the environment header will print out
    1707             :             }
    1708             : 
    1709       23296 :             for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    1710       16138 :                 state.dataWeather->SpecialDays(i).Used = false;
    1711             :             }
    1712             : 
    1713        8464 :             if ((state.dataGlobal->KindOfSim != Constant::KindOfSim::DesignDay) &&
    1714        1306 :                 (state.dataGlobal->KindOfSim != Constant::KindOfSim::HVACSizeDesignDay)) {
    1715        1226 :                 ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read first day's weather
    1716             :             } else {
    1717        5932 :                 state.dataWeather->TomorrowVariables = state.dataWeather->DesignDay(envCurr.DesignDayNum);
    1718             :             }
    1719             : 
    1720             :         } // ... end of DataGlobals::BeginEnvrnFlag IF-THEN block.
    1721             : 
    1722     2900842 :         if (state.dataGlobal->BeginDayFlag) {
    1723             : 
    1724             :             // Check Holidays, Daylight Saving Time, Ground Temperatures, etc.
    1725             : 
    1726       26502 :             UpdateWeatherData(state); // Update daily weather info
    1727             : 
    1728             :             // Read tomorrow's weather only if necessary.  This means that the
    1729             :             // simulation is out of warmup, is using a weather tape for this
    1730             :             // environment, and is not on the last day (day after last day is
    1731             :             // assumed to be equal to last day).
    1732             : 
    1733             :             // Following code checks whether the present day of simulation matches the start month and start day.
    1734             :             // In a multi year simulation with run period less than 365, we need to position the weather line
    1735             :             // appropriately.
    1736             : 
    1737       32467 :             if ((!state.dataGlobal->WarmupFlag) &&
    1738        5965 :                 ((envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) && (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay))) {
    1739        2646 :                 if (state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) {
    1740        2627 :                     if (state.dataGlobal->DayOfSim == state.dataWeather->curSimDayForEndOfRunPeriod) {
    1741           0 :                         state.dataWeather->curSimDayForEndOfRunPeriod += envCurr.RawSimDays;
    1742           0 :                         if (state.dataWeather->StartDatesCycleShouldBeReset) {
    1743           0 :                             ResetWeekDaysByMonth(state,
    1744           0 :                                                  envCurr.MonWeekDay,
    1745           0 :                                                  state.dataWeather->LeapYearAdd,
    1746             :                                                  envCurr.StartMonth,
    1747             :                                                  envCurr.StartDay,
    1748             :                                                  envCurr.EndMonth,
    1749             :                                                  envCurr.EndDay,
    1750           0 :                                                  envCurr.RollDayTypeOnRepeat);
    1751           0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1752           0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1753             :                             }
    1754           0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1755             :                         }
    1756           0 :                         ++state.dataWeather->YearOfSim;
    1757           0 :                         ReadWeatherForDay(state, 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1758             :                     } else {
    1759        2627 :                         ReadWeatherForDay(state, state.dataGlobal->DayOfSim + 1, state.dataWeather->Envrn, false); // Read tomorrow's weather
    1760             :                     }
    1761             :                 }
    1762             :             }
    1763             : 
    1764       26502 :             state.dataEnvrn->EndYearFlag = false;
    1765       26502 :             if (state.dataEnvrn->DayOfMonth == state.dataWeather->EndDayOfMonthWithLeapDay(state.dataEnvrn->Month)) {
    1766          91 :                 state.dataEnvrn->EndMonthFlag = true;
    1767          91 :                 state.dataEnvrn->EndYearFlag = (state.dataEnvrn->Month == 12);
    1768             :             }
    1769             : 
    1770             :             // Set Tomorrow's date data
    1771       26502 :             state.dataEnvrn->MonthTomorrow = state.dataWeather->TomorrowVariables.Month;
    1772       26502 :             state.dataEnvrn->DayOfMonthTomorrow = state.dataWeather->TomorrowVariables.DayOfMonth;
    1773       26502 :             state.dataEnvrn->DayOfWeekTomorrow = state.dataWeather->TomorrowVariables.DayOfWeek;
    1774       26502 :             state.dataEnvrn->HolidayIndexTomorrow = state.dataWeather->TomorrowVariables.HolidayIndex;
    1775       26502 :             state.dataEnvrn->YearTomorrow = state.dataWeather->TomorrowVariables.Year;
    1776             : 
    1777       26502 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1778        3435 :                 if (state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1 && envCurr.ActualWeather) {
    1779           0 :                     if (state.dataWeather->DatesShouldBeReset) {
    1780           0 :                         if (envCurr.TreatYearsAsConsecutive) {
    1781           0 :                             ++envCurr.CurrentYear;
    1782           0 :                             envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1783           0 :                             state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1784           0 :                             state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1785             : 
    1786             :                             // need to reset MonWeekDay and WeekDayTypes
    1787           0 :                             int JDay5Start = General::OrdinalDay(envCurr.StartMonth, envCurr.StartDay, state.dataWeather->LeapYearAdd);
    1788           0 :                             int JDay5End = General::OrdinalDay(envCurr.EndMonth, envCurr.EndDay, state.dataWeather->LeapYearAdd);
    1789           0 :                             if (!envCurr.ActualWeather)
    1790           0 :                                 state.dataWeather->curSimDayForEndOfRunPeriod =
    1791           0 :                                     state.dataGlobal->DayOfSim + envCurr.RawSimDays + state.dataWeather->LeapYearAdd - 1;
    1792             : 
    1793             :                             {
    1794           0 :                                 int i = JDay5Start;
    1795           0 :                                 int TWeekDay = state.dataEnvrn->DayOfWeek;
    1796             :                                 while (true) {
    1797           0 :                                     state.dataWeather->WeekDayTypes(i) = TWeekDay;
    1798           0 :                                     TWeekDay = mod(TWeekDay, 7) + 1;
    1799           0 :                                     ++i;
    1800           0 :                                     if (i > 366) i = 1;
    1801           0 :                                     if (i == JDay5End) break;
    1802             :                                 }
    1803             :                             }
    1804           0 :                             ResetWeekDaysByMonth(state,
    1805           0 :                                                  envCurr.MonWeekDay,
    1806           0 :                                                  state.dataWeather->LeapYearAdd,
    1807             :                                                  envCurr.StartMonth,
    1808             :                                                  envCurr.StartDay,
    1809             :                                                  envCurr.EndMonth,
    1810             :                                                  envCurr.EndDay,
    1811           0 :                                                  envCurr.RollDayTypeOnRepeat);
    1812           0 :                             if (state.dataWeather->DaylightSavingIsActive) {
    1813           0 :                                 SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1814             :                             }
    1815           0 :                             SetSpecialDayDates(state, envCurr.MonWeekDay);
    1816             :                         }
    1817             :                     }
    1818        3435 :                 } else if ((state.dataEnvrn->Month == 1 && state.dataEnvrn->DayOfMonth == 1) && state.dataWeather->DatesShouldBeReset &&
    1819           0 :                            (state.dataWeather->Jan1DatesShouldBeReset)) {
    1820           0 :                     if (envCurr.TreatYearsAsConsecutive) {
    1821           0 :                         ++envCurr.CurrentYear;
    1822           0 :                         envCurr.IsLeapYear = isLeapYear(envCurr.CurrentYear);
    1823           0 :                         state.dataEnvrn->CurrentYearIsLeapYear = envCurr.IsLeapYear;
    1824           0 :                         if (state.dataEnvrn->CurrentYearIsLeapYear && !state.dataWeather->WFAllowsLeapYears)
    1825           0 :                             state.dataEnvrn->CurrentYearIsLeapYear = false;
    1826           0 :                         if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod && state.dataEnvrn->CurrentYearIsLeapYear)
    1827           0 :                             ++state.dataWeather->curSimDayForEndOfRunPeriod;
    1828             :                     }
    1829             : 
    1830           0 :                     state.dataWeather->LeapYearAdd = (int)(state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeather->WFAllowsLeapYears);
    1831             : 
    1832           0 :                     if (state.dataGlobal->DayOfSim < state.dataWeather->curSimDayForEndOfRunPeriod) {
    1833           0 :                         ResetWeekDaysByMonth(state,
    1834           0 :                                              envCurr.MonWeekDay,
    1835           0 :                                              state.dataWeather->LeapYearAdd,
    1836             :                                              envCurr.StartMonth,
    1837             :                                              envCurr.StartDay,
    1838             :                                              envCurr.EndMonth,
    1839             :                                              envCurr.EndDay,
    1840           0 :                                              envCurr.RollDayTypeOnRepeat,
    1841           0 :                                              envCurr.RollDayTypeOnRepeat || state.dataEnvrn->CurrentYearIsLeapYear);
    1842           0 :                         if (state.dataWeather->DaylightSavingIsActive) {
    1843           0 :                             SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    1844             :                         }
    1845           0 :                         SetSpecialDayDates(state, envCurr.MonWeekDay);
    1846             :                     }
    1847             :                 }
    1848             :             }
    1849             : 
    1850             :             // at the end of each day find the min/max weather used for DOAS sizing
    1851       26502 :             if (state.dataGlobal->AirLoopHVACDOASUsedInSim) {
    1852          35 :                 if (envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign || envCurr.KindOfEnvrn == Constant::KindOfSim::DesignDay) {
    1853         850 :                     for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr) {
    1854        5712 :                         for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS) {
    1855        4896 :                             Real64 Tdb = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDryBulbTemp;
    1856        4896 :                             Real64 Tdp = state.dataWeather->wvarsHrTsToday(iTS, iHr).OutDewPointTemp;
    1857        4896 :                             if (Tdb > envCurr.maxCoolingOATSizing) {
    1858          42 :                                 envCurr.maxCoolingOATSizing = Tdb;
    1859          42 :                                 envCurr.maxCoolingOADPSizing = Tdp;
    1860             :                             }
    1861        4896 :                             if (Tdb < envCurr.minHeatingOATSizing) {
    1862          31 :                                 envCurr.minHeatingOATSizing = Tdb;
    1863          31 :                                 envCurr.minHeatingOADPSizing = Tdp;
    1864             :                             }
    1865             :                         } // for (iTS)
    1866             :                     }     // for (iHr)
    1867             :                 }
    1868             :             }
    1869             : 
    1870             :         } // ... end of DataGlobals::BeginDayFlag IF-THEN block.
    1871             : 
    1872     5775182 :         if (!state.dataGlobal->BeginDayFlag && !state.dataGlobal->WarmupFlag &&
    1873      691979 :             (state.dataEnvrn->Month != envCurr.StartMonth || state.dataEnvrn->DayOfMonth != envCurr.StartDay) &&
    1874     5775182 :             !state.dataWeather->DatesShouldBeReset && envCurr.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    1875           6 :             state.dataWeather->DatesShouldBeReset = true;
    1876             :         }
    1877             : 
    1878     2902148 :         if (state.dataGlobal->EndEnvrnFlag && (envCurr.KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
    1879        1306 :             (envCurr.KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
    1880        1226 :             state.files.inputWeatherFile.rewind();
    1881        1226 :             SkipEPlusWFHeader(state);
    1882        1226 :             ReportMissing_RangeData(state);
    1883             :         }
    1884             : 
    1885             :         // set the EndDesignDayEnvrnsFlag (dataGlobal)
    1886             :         // 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)
    1887     2900842 :         state.dataGlobal->EndDesignDayEnvrnsFlag = false;
    1888     2900842 :         if (state.dataGlobal->EndEnvrnFlag) {
    1889        7157 :             if (state.dataWeather->Envrn < state.dataWeather->NumOfEnvrn) {
    1890        6301 :                 if (envCurr.KindOfEnvrn != state.dataWeather->Environment(state.dataWeather->Envrn + 1).KindOfEnvrn) {
    1891        2792 :                     state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1892             :                 }
    1893             :             } else {
    1894             :                 // if the last environment set the flag to true.
    1895         856 :                 state.dataGlobal->EndDesignDayEnvrnsFlag = true;
    1896             :             }
    1897             :         }
    1898             : 
    1899     2900842 :         if (state.dataWeather->WaterMainsParameterReport) {
    1900             :             // this is done only once
    1901         796 :             if (state.dataWeather->WaterMainsTempsMethod == WaterMainsTempCalcMethod::CorrelationFromWeatherFile) {
    1902           0 :                 if (!state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    1903           0 :                     state.dataWeather->OADryBulbAverage.CalcAnnualAndMonthlyDryBulbTemp(state);
    1904             :                 }
    1905             :             }
    1906             :             // reports to eio file
    1907         796 :             ReportWaterMainsTempParameters(state);
    1908         796 :             state.dataWeather->WaterMainsParameterReport = false;
    1909             :         }
    1910     2900842 :     }
    1911             : 
    1912       26502 :     void UpdateWeatherData(EnergyPlusData &state)
    1913             :     {
    1914             : 
    1915             :         // SUBROUTINE INFORMATION:
    1916             :         //       AUTHOR         Rick Strand
    1917             :         //       DATE WRITTEN   June 1997
    1918             : 
    1919             :         // PURPOSE OF THIS SUBROUTINE:
    1920             :         // This subroutine updates all of the daily weather data in the local
    1921             :         // module level variables and the global variables.
    1922             :         // This subroutine will temporarily transfer the weather data for the
    1923             :         // current day to the old data structure contained in envdat.inc until
    1924             :         // enough reengineering has taken place to eliminate the need for this
    1925             :         // include.
    1926             : 
    1927       26502 :         state.dataWeather->TodayVariables = state.dataWeather->TomorrowVariables; // Transfer Tomorrow's Daily Weather Variables to Today
    1928             : 
    1929       26502 :         if (state.dataGlobal->BeginEnvrnFlag) {
    1930        7158 :             state.dataGlobal->PreviousHour = 24;
    1931             :         }
    1932             : 
    1933       26502 :         state.dataWeather->wvarsHrTsToday = state.dataWeather->wvarsHrTsTomorrow; // What a waste
    1934             : 
    1935             :         // Update Global Data
    1936             : 
    1937       26502 :         state.dataEnvrn->DayOfYear = state.dataWeather->TodayVariables.DayOfYear;
    1938       26502 :         state.dataEnvrn->Year = state.dataWeather->TodayVariables.Year;
    1939       26502 :         state.dataEnvrn->Month = state.dataWeather->TodayVariables.Month;
    1940       26502 :         state.dataEnvrn->DayOfMonth = state.dataWeather->TodayVariables.DayOfMonth;
    1941       26502 :         state.dataEnvrn->DayOfWeek = state.dataWeather->TodayVariables.DayOfWeek;
    1942       26502 :         state.dataEnvrn->HolidayIndex = state.dataWeather->TodayVariables.HolidayIndex;
    1943       26502 :         if (state.dataEnvrn->HolidayIndex > 0) {
    1944       22375 :             state.dataWeather->RptDayType = state.dataEnvrn->HolidayIndex;
    1945             :         } else {
    1946        4127 :             state.dataWeather->RptDayType = state.dataEnvrn->DayOfWeek;
    1947             :         }
    1948       26502 :         state.dataEnvrn->DSTIndicator = state.dataWeather->TodayVariables.DaylightSavingIndex;
    1949       26502 :         state.dataEnvrn->EquationOfTime = state.dataWeather->TodayVariables.EquationOfTime;
    1950       26502 :         state.dataEnvrn->CosSolarDeclinAngle = state.dataWeather->TodayVariables.CosSolarDeclinAngle;
    1951       26502 :         state.dataEnvrn->SinSolarDeclinAngle = state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    1952       26502 :     }
    1953             : 
    1954     2900842 :     void SetCurrentWeather(EnergyPlusData &state)
    1955             :     {
    1956             : 
    1957             :         // SUBROUTINE INFORMATION:
    1958             :         //       AUTHOR         Russ Taylor
    1959             :         //       DATE WRITTEN   March 1990
    1960             :         //       MODIFIED       Aug94 (LKL) Fixed improper weighting
    1961             :         //                      Nov98 (FCW) Added call to get exterior illuminances
    1962             :         //                      Jan02 (FCW) Changed how ground reflectance for daylighting is set
    1963             :         //                      Mar12 (LKL) Changed settings for leap years/ current years.
    1964             :         //       RE-ENGINEERED  Apr97,May97 (RKS)
    1965             : 
    1966             :         // PURPOSE OF THIS SUBROUTINE:
    1967             :         // The purpose of this subroutine is to interpolate the hourly
    1968             :         // environment data for the sub-hourly time steps in EnergyPlus.  In
    1969             :         // other words, this subroutine puts the current weather conditions
    1970             :         // into the proper variables.  Rather than using the same data for
    1971             :         // each time step, environment data is interpolated as a continuum
    1972             :         // throughout the day.
    1973             : 
    1974             :         // METHODOLOGY EMPLOYED:
    1975             :         // The current hour (DataGlobals::HourOfDay) as well as the next hour are used
    1976             :         // to come up with environment data per time step interval.  Method
    1977             :         // used is to assign a weighting for the current hour's data and
    1978             :         // (1-that weighting) to the next hour's data.  Actual method is:  if
    1979             :         // the current time step is 15 minutes into hour, the interpolated dry
    1980             :         // bulb temperature should be 3/4*dry bulb temperature of current hour
    1981             :         // and 1/4*dry bulb temperature of next environment hourly data.  At
    1982             :         // day boundary (current hour = 24), the next hour is hour 1 of next
    1983             :         // weather data day (Tomorrow%).
    1984             : 
    1985             :         static constexpr std::string_view RoutineName("SetCurrentWeather");
    1986             : 
    1987     2900842 :         state.dataWeather->NextHour = state.dataGlobal->HourOfDay + 1;
    1988             : 
    1989     2900842 :         if (state.dataGlobal->HourOfDay == 24) { // Should investigate whether EndDayFlag is always set here and use that instead
    1990      124210 :             state.dataWeather->NextHour = 1;
    1991             :         }
    1992             : 
    1993     2900842 :         if (state.dataGlobal->HourOfDay == 1) { // Should investigate whether DataGlobals::BeginDayFlag is always set here and use that instead
    1994      128030 :             state.dataEnvrn->DayOfYear_Schedule = General::OrdinalDay(state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, 1);
    1995             :         }
    1996             : 
    1997     2900842 :         ScheduleManager::UpdateScheduleValues(state);
    1998             : 
    1999     2900842 :         state.dataEnvrn->CurMnDyHr =
    2000     5801684 :             format("{:02d}/{:02d} {:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, (unsigned short)(state.dataGlobal->HourOfDay - 1));
    2001     2900842 :         state.dataEnvrn->CurMnDy = format("{:02d}/{:02d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
    2002     2900842 :         state.dataEnvrn->CurMnDyYr =
    2003     5801684 :             format("{:02d}/{:02d}/{:04d}", state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, state.dataGlobal->CalendarYear);
    2004             : 
    2005     2900842 :         state.dataGlobal->WeightNow = state.dataWeather->Interpolation(state.dataGlobal->TimeStep);
    2006     2900842 :         state.dataGlobal->WeightPreviousHour = 1.0 - state.dataGlobal->WeightNow;
    2007             : 
    2008     2900842 :         state.dataGlobal->CurrentTime = (state.dataGlobal->HourOfDay - 1) + state.dataGlobal->TimeStep * (state.dataWeather->TimeStepFraction);
    2009     2900842 :         state.dataGlobal->SimTimeSteps = (state.dataGlobal->DayOfSim - 1) * 24 * state.dataGlobal->NumOfTimeStepInHour +
    2010     2900842 :                                          (state.dataGlobal->HourOfDay - 1) * state.dataGlobal->NumOfTimeStepInHour + state.dataGlobal->TimeStep;
    2011             : 
    2012     2900842 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] =
    2013     2900842 :             state.dataWeather->siteBuildingSurfaceGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2014     2900842 :         state.dataEnvrn->GroundTempKelvin = state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface] + Constant::Kelvin;
    2015     2900842 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::FCFactorMethod] =
    2016     2900842 :             state.dataWeather->siteFCFactorMethodGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2017     2900842 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Shallow] =
    2018     2900842 :             state.dataWeather->siteShallowGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2019     2900842 :         state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::Deep] =
    2020     2900842 :             state.dataWeather->siteDeepGroundTempsPtr->getGroundTempAtTimeInMonths(state, 0, state.dataEnvrn->Month);
    2021     2900842 :         state.dataEnvrn->GndReflectance = state.dataWeather->GroundReflectances(state.dataEnvrn->Month);
    2022     2900842 :         state.dataEnvrn->GndReflectanceForDayltg = state.dataEnvrn->GndReflectance;
    2023             : 
    2024     2900842 :         CalcWaterMainsTemp(state);
    2025             : 
    2026             :         // Determine if Sun is up or down, set Solar Cosine values for time step.
    2027     2900842 :         DetermineSunUpDown(state, state.dataEnvrn->SOLCOS);
    2028     2900842 :         if (state.dataEnvrn->SunIsUp && state.dataWeather->SolarAltitudeAngle < 0.0) {
    2029           0 :             ShowFatalError(state, format("SetCurrentWeather: At {} Sun is Up but Solar Altitude Angle is < 0.0", state.dataEnvrn->CurMnDyHr));
    2030             :         }
    2031             : 
    2032     2900842 :         auto const &today = state.dataWeather->wvarsHrTsToday(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2033     2900842 :         state.dataEnvrn->OutDryBulbTemp = today.OutDryBulbTemp;
    2034     2900842 :         if (state.dataEnvrn->EMSOutDryBulbOverrideOn) state.dataEnvrn->OutDryBulbTemp = state.dataEnvrn->EMSOutDryBulbOverrideValue;
    2035     2900842 :         state.dataEnvrn->OutBaroPress = today.OutBaroPress;
    2036     2900842 :         state.dataEnvrn->OutDewPointTemp = today.OutDewPointTemp;
    2037     2900842 :         if (state.dataEnvrn->EMSOutDewPointTempOverrideOn) state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->EMSOutDewPointTempOverrideValue;
    2038     2900842 :         state.dataEnvrn->OutRelHum = today.OutRelHum;
    2039     2900842 :         state.dataEnvrn->OutRelHumValue = state.dataEnvrn->OutRelHum / 100.0;
    2040     2900842 :         if (state.dataEnvrn->EMSOutRelHumOverrideOn) {
    2041           0 :             state.dataEnvrn->OutRelHumValue = state.dataEnvrn->EMSOutRelHumOverrideValue / 100.0;
    2042           0 :             state.dataEnvrn->OutRelHum = state.dataEnvrn->EMSOutRelHumOverrideValue;
    2043             :         }
    2044             : 
    2045             :         // Humidity Ratio and Wet Bulb are derived
    2046     2900842 :         state.dataEnvrn->OutHumRat = Psychrometrics::PsyWFnTdbRhPb(
    2047     2900842 :             state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutRelHumValue, state.dataEnvrn->OutBaroPress, RoutineName);
    2048     5801684 :         state.dataEnvrn->OutWetBulbTemp =
    2049     2900842 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
    2050     2900842 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) {
    2051      950305 :             state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2052     1900610 :             Real64 TempVal = Psychrometrics::PsyWFnTdbTwbPb(
    2053      950305 :                 state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutWetBulbTemp, state.dataEnvrn->OutBaroPress);
    2054      950305 :             state.dataEnvrn->OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, TempVal, state.dataEnvrn->OutBaroPress);
    2055             :         }
    2056             : 
    2057     2900842 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) {
    2058      993179 :             state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2059             :         }
    2060             : 
    2061     3218014 :         if ((state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) ||
    2062      317172 :             (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay)) {
    2063             : 
    2064     9262737 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2065     6646340 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2066             :             }
    2067             : 
    2068     2616397 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2069     2616397 :             int const envrnDayNum = envCurr.DesignDayNum;
    2070     2616397 :             auto &desDayInput = state.dataWeather->DesDayInput(envrnDayNum);
    2071     2616397 :             auto &spSiteSchedule = state.dataWeather->spSiteSchedules(envrnDayNum);
    2072     2616397 :             auto &desDayMod = state.dataWeather->desDayMods(envrnDayNum)(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay);
    2073             : 
    2074     2616397 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Default) {
    2075        9234 :                 spSiteSchedule.OutDryBulbTemp = desDayMod.OutDryBulbTemp;
    2076             :             }
    2077             : 
    2078     2616397 :             if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    2079     2607622 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    2080       15606 :                 spSiteSchedule.OutRelHum = desDayMod.OutRelHum;
    2081             :             }
    2082     2616397 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    2083        5289 :                 spSiteSchedule.BeamSolarRad = desDayMod.BeamSolarRad;
    2084        5289 :                 spSiteSchedule.DifSolarRad = desDayMod.DifSolarRad;
    2085             :             }
    2086             : 
    2087     2616397 :             if (envCurr.skyTempModel == SkyTempModel::ScheduleValue || envCurr.skyTempModel == SkyTempModel::DryBulbDelta ||
    2088     2614570 :                 envCurr.skyTempModel == SkyTempModel::DewPointDelta) {
    2089        1827 :                 spSiteSchedule.SkyTemp = desDayMod.SkyTemp;
    2090             :             }
    2091      284445 :         } else if (state.dataEnvrn->TotDesDays > 0) {
    2092      853500 :             for (int iDD = 1; iDD <= state.dataEnvrn->TotDesDays; ++iDD) {
    2093      569055 :                 state.dataWeather->spSiteSchedules(iDD) = {-999.0, -999.0, -999.0, -999.0, -999.0};
    2094             :             }
    2095             :         }
    2096             : 
    2097     2900842 :         state.dataEnvrn->WindSpeed = today.WindSpeed;
    2098     2900842 :         if (state.dataEnvrn->EMSWindSpeedOverrideOn) state.dataEnvrn->WindSpeed = state.dataEnvrn->EMSWindSpeedOverrideValue;
    2099     2900842 :         state.dataEnvrn->WindDir = today.WindDir;
    2100     2900842 :         if (state.dataEnvrn->EMSWindDirOverrideOn) state.dataEnvrn->WindDir = state.dataEnvrn->EMSWindDirOverrideValue;
    2101     2900842 :         state.dataWeather->HorizIRSky = today.HorizIRSky;
    2102     2900842 :         state.dataEnvrn->SkyTemp = today.SkyTemp;
    2103     2900842 :         state.dataEnvrn->SkyTempKelvin = state.dataEnvrn->SkyTemp + Constant::Kelvin;
    2104     2900842 :         state.dataEnvrn->DifSolarRad = today.DifSolarRad;
    2105     2900842 :         if (state.dataEnvrn->EMSDifSolarRadOverrideOn) state.dataEnvrn->DifSolarRad = state.dataEnvrn->EMSDifSolarRadOverrideValue;
    2106     2900842 :         state.dataEnvrn->BeamSolarRad = today.BeamSolarRad;
    2107     2900842 :         if (state.dataEnvrn->EMSBeamSolarRadOverrideOn) state.dataEnvrn->BeamSolarRad = state.dataEnvrn->EMSBeamSolarRadOverrideValue;
    2108     2900842 :         state.dataEnvrn->LiquidPrecipitation = today.LiquidPrecip / 1000.0; // convert from mm to m
    2109     2900842 :         if ((state.dataEnvrn->RunPeriodEnvironment) && (!state.dataGlobal->WarmupFlag)) {
    2110      245376 :             int month = state.dataEnvrn->Month;
    2111      245376 :             state.dataWaterData->RainFall.MonthlyTotalPrecInWeather.at(month - 1) += state.dataEnvrn->LiquidPrecipitation * 1000.0;
    2112      245376 :             if ((state.dataEnvrn->LiquidPrecipitation > 0) && (state.dataGlobal->TimeStep == 1)) {
    2113         425 :                 state.dataWaterData->RainFall.numRainyHoursInWeather.at(month - 1) += 1;
    2114             :             }
    2115             :         }
    2116             : 
    2117     2900842 :         WaterManager::UpdatePrecipitation(state);
    2118             : 
    2119     2900842 :         state.dataEnvrn->TotalCloudCover = today.TotalSkyCover;
    2120     2900842 :         state.dataEnvrn->OpaqueCloudCover = today.OpaqueSkyCover;
    2121             : 
    2122     2900842 :         if (state.dataWeather->UseRainValues) {
    2123             :             // It is set as LiquidPrecipitation >= .8 mm here: state.dataWeather->TomorrowLiquidPrecip(ts, hour) >=
    2124             :             // state.dataWeather->IsRainThreshold;
    2125     2866795 :             state.dataEnvrn->IsRain = today.IsRain;
    2126     2866795 :             if (state.dataWaterData->RainFall.ModeID == DataWater::RainfallMode::RainSchedDesign && state.dataEnvrn->RunPeriodEnvironment) {
    2127             :                 // CurrentAmount unit: m
    2128           0 :                 state.dataEnvrn->IsRain = state.dataWaterData->RainFall.CurrentAmount >= (state.dataWeather->IsRainThreshold / 1000.0);
    2129             :             }
    2130             :         } else {
    2131       34047 :             state.dataEnvrn->IsRain = false;
    2132             :         }
    2133     2900842 :         if (state.dataWeather->UseSnowValues) {
    2134     2866795 :             state.dataEnvrn->IsSnow = today.IsSnow;
    2135             :         } else {
    2136       34047 :             state.dataEnvrn->IsSnow = false;
    2137             :         }
    2138             : 
    2139     2900842 :         if (state.dataEnvrn->IsSnow) {
    2140           0 :             state.dataEnvrn->GndReflectance = max(min(state.dataEnvrn->GndReflectance * state.dataWeather->SnowGndRefModifier, 1.0), 0.0);
    2141           0 :             state.dataEnvrn->GndReflectanceForDayltg =
    2142           0 :                 max(min(state.dataEnvrn->GndReflectanceForDayltg * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0);
    2143             :         }
    2144             : 
    2145     2900842 :         state.dataEnvrn->GndSolarRad =
    2146     2900842 :             max((state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z + state.dataEnvrn->DifSolarRad) * state.dataEnvrn->GndReflectance, 0.0);
    2147             : 
    2148     2900842 :         if (!state.dataEnvrn->SunIsUp) {
    2149     1450870 :             state.dataEnvrn->DifSolarRad = 0.0;
    2150     1450870 :             state.dataEnvrn->BeamSolarRad = 0.0;
    2151     1450870 :             state.dataEnvrn->GndSolarRad = 0.0;
    2152             :         }
    2153             : 
    2154     2900842 :         state.dataEnvrn->OutEnthalpy = Psychrometrics::PsyHFnTdbW(state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2155     5801684 :         state.dataEnvrn->OutAirDensity =
    2156     2900842 :             Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
    2157             : 
    2158     2900842 :         if (state.dataEnvrn->OutDryBulbTemp < state.dataEnvrn->OutWetBulbTemp) state.dataEnvrn->OutWetBulbTemp = state.dataEnvrn->OutDryBulbTemp;
    2159     2900842 :         if (state.dataEnvrn->OutDewPointTemp > state.dataEnvrn->OutWetBulbTemp) state.dataEnvrn->OutDewPointTemp = state.dataEnvrn->OutWetBulbTemp;
    2160             : 
    2161     2900842 :         DayltgCurrentExtHorizIllum(state);
    2162             : 
    2163     2900842 :         if (!state.dataEnvrn->IsRain) {
    2164     2899514 :             state.dataWeather->RptIsRain = 0;
    2165             :         } else {
    2166        1328 :             state.dataWeather->RptIsRain = 1;
    2167             :         }
    2168             : 
    2169     2900842 :         if (!state.dataEnvrn->IsSnow) {
    2170     2900842 :             state.dataWeather->RptIsSnow = 0;
    2171             :         } else {
    2172           0 :             state.dataWeather->RptIsSnow = 1;
    2173             :         }
    2174     2900842 :     }
    2175             : 
    2176        3853 :     void ReadWeatherForDay(EnergyPlusData &state,
    2177             :                            int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2178             :                            int const Environ,            // Environment being simulated
    2179             :                            bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2180             :     )
    2181             :     {
    2182             : 
    2183             :         // SUBROUTINE INFORMATION:
    2184             :         //       AUTHOR         Linda K. Lawrie
    2185             :         //       DATE WRITTEN   April 1999
    2186             : 
    2187             :         // PURPOSE OF THIS SUBROUTINE:
    2188             :         // This subroutine is the driving routine behind reading the weather data.
    2189             :         // Theoretically, several kinds of weather files could be read here.  As
    2190             :         // distributed only EPW files are allowed.
    2191             : 
    2192        3853 :         ReadEPlusWeatherForDay(state, DayToRead, Environ, BackSpaceAfterRead);
    2193        3853 :     }
    2194             : 
    2195        3853 :     void ReadEPlusWeatherForDay(EnergyPlusData &state,
    2196             :                                 int const DayToRead,          // =1 when starting out, otherwise signifies next day
    2197             :                                 int const Environ,            // Environment being simulated
    2198             :                                 bool const BackSpaceAfterRead // True if weather file is to be backspaced after read
    2199             :     )
    2200             :     {
    2201             : 
    2202             :         // SUBROUTINE INFORMATION:
    2203             :         //       AUTHOR         Linda K. Lawrie
    2204             :         //       DATE WRITTEN   April 1999
    2205             :         //       MODIFIED       March 2012; add actual weather read.
    2206             : 
    2207             :         // PURPOSE OF THIS SUBROUTINE:
    2208             :         // This subroutine reads the appropriate day of EPW weather data.
    2209             : 
    2210             :         int WYear;
    2211             :         int WMonth;
    2212             :         int WDay;
    2213             :         int WHour;
    2214             :         int WMinute;
    2215             :         Real64 DryBulb;
    2216             :         Real64 DewPoint;
    2217             :         Real64 RelHum;
    2218             :         Real64 AtmPress;
    2219             :         Real64 ETHoriz;
    2220             :         Real64 ETDirect;
    2221             :         Real64 IRHoriz;
    2222             :         Real64 GLBHoriz;
    2223             :         Real64 DirectRad;
    2224             :         Real64 DiffuseRad;
    2225             :         Real64 GLBHorizIllum;
    2226             :         Real64 DirectNrmIllum;
    2227             :         Real64 DiffuseHorizIllum;
    2228             :         Real64 ZenLum;
    2229             :         Real64 WindDir;
    2230             :         Real64 WindSpeed;
    2231             :         Real64 TotalSkyCover;
    2232             :         Real64 OpaqueSkyCover;
    2233             :         Real64 Visibility;
    2234             :         Real64 CeilHeight;
    2235             :         Real64 PrecipWater;
    2236             :         Real64 AerosolOptDepth;
    2237             :         Real64 SnowDepth;
    2238             :         Real64 DaysSinceLastSnow;
    2239             :         Real64 Albedo;
    2240             :         Real64 LiquidPrecip;
    2241             :         int PresWeathObs;
    2242        3853 :         Array1D_int PresWeathConds(9);
    2243             : 
    2244        3853 :         constexpr std::string_view routineName = "ReadEPlusWeatherForDay";
    2245             : 
    2246        3853 :         Array1D<WeatherVars> wvarsHr = Array1D<WeatherVars>(Constant::HoursInDay);
    2247             : 
    2248        3853 :         auto &thisEnviron = state.dataWeather->Environment(Environ);
    2249             : 
    2250        3853 :         if (DayToRead == 1) {
    2251             : 
    2252             :             // Checks whether Weather file contains just one year of data. If yes then rewind and position to first
    2253             :             // day of weather file. The rest of code appropriately positions to the start day.
    2254             : 
    2255        1226 :             bool Ready = false;
    2256        1226 :             int NumRewinds = 0;
    2257             :             //     Must position file to proper day
    2258             :             //     File already position to first data record
    2259             :             //          Set Current Day of Week to "start of Data Period"
    2260        1226 :             state.dataWeather->ReadEPlusWeatherCurTime = 1.0 / double(state.dataWeather->NumIntervalsPerHour);
    2261        1226 :             state.dataWeather->CurDayOfWeek = state.dataWeather->DataPeriods(1).WeekDay - 1;
    2262        1226 :             WYear = 0;
    2263        1226 :             WMonth = 0;
    2264        1226 :             WDay = 0;
    2265        1226 :             WHour = 0;
    2266        1226 :             WMinute = 0;
    2267        1226 :             state.dataWeather->LastHourSet = false;
    2268        2452 :             InputFile::ReadResult<std::string> WeatherDataLine{"", true, false};
    2269       95989 :             while (!Ready) {
    2270       94763 :                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2271       94763 :                 if (WeatherDataLine.good) {
    2272             :                     bool ErrorFound;
    2273       94763 :                     InterpretWeatherDataLine(state,
    2274             :                                              WeatherDataLine.data,
    2275             :                                              ErrorFound,
    2276             :                                              WYear,
    2277             :                                              WMonth,
    2278             :                                              WDay,
    2279             :                                              WHour,
    2280             :                                              WMinute,
    2281             :                                              DryBulb,
    2282             :                                              DewPoint,
    2283             :                                              RelHum,
    2284             :                                              AtmPress,
    2285             :                                              ETHoriz,
    2286             :                                              ETDirect,
    2287             :                                              IRHoriz,
    2288             :                                              GLBHoriz,
    2289             :                                              DirectRad,
    2290             :                                              DiffuseRad,
    2291             :                                              GLBHorizIllum,
    2292             :                                              DirectNrmIllum,
    2293             :                                              DiffuseHorizIllum,
    2294             :                                              ZenLum,
    2295             :                                              WindDir,
    2296             :                                              WindSpeed,
    2297             :                                              TotalSkyCover,
    2298             :                                              OpaqueSkyCover,
    2299             :                                              Visibility,
    2300             :                                              CeilHeight,
    2301             :                                              PresWeathObs,
    2302             :                                              PresWeathConds,
    2303             :                                              PrecipWater,
    2304             :                                              AerosolOptDepth,
    2305             :                                              SnowDepth,
    2306             :                                              DaysSinceLastSnow,
    2307             :                                              Albedo,
    2308             :                                              LiquidPrecip);
    2309           0 :                 } else if (WeatherDataLine.eof) {
    2310           0 :                     if (NumRewinds > 0) {
    2311           0 :                         std::string date = fmt::to_string(thisEnviron.StartMonth) + '/' + fmt::to_string(thisEnviron.StartDay);
    2312           0 :                         if (thisEnviron.MatchYear) {
    2313           0 :                             date += '/' + fmt::to_string(thisEnviron.StartYear);
    2314             :                         }
    2315           0 :                         ShowSevereError(state, format("Multiple rewinds on EPW while searching for first day {}", date));
    2316           0 :                     } else {
    2317           0 :                         state.files.inputWeatherFile.rewind();
    2318           0 :                         ++NumRewinds;
    2319           0 :                         SkipEPlusWFHeader(state);
    2320           0 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2321             :                         bool ErrorFound;
    2322           0 :                         InterpretWeatherDataLine(state,
    2323             :                                                  WeatherDataLine.data,
    2324             :                                                  ErrorFound,
    2325             :                                                  WYear,
    2326             :                                                  WMonth,
    2327             :                                                  WDay,
    2328             :                                                  WHour,
    2329             :                                                  WMinute,
    2330             :                                                  DryBulb,
    2331             :                                                  DewPoint,
    2332             :                                                  RelHum,
    2333             :                                                  AtmPress,
    2334             :                                                  ETHoriz,
    2335             :                                                  ETDirect,
    2336             :                                                  IRHoriz,
    2337             :                                                  GLBHoriz,
    2338             :                                                  DirectRad,
    2339             :                                                  DiffuseRad,
    2340             :                                                  GLBHorizIllum,
    2341             :                                                  DirectNrmIllum,
    2342             :                                                  DiffuseHorizIllum,
    2343             :                                                  ZenLum,
    2344             :                                                  WindDir,
    2345             :                                                  WindSpeed,
    2346             :                                                  TotalSkyCover,
    2347             :                                                  OpaqueSkyCover,
    2348             :                                                  Visibility,
    2349             :                                                  CeilHeight,
    2350             :                                                  PresWeathObs,
    2351             :                                                  PresWeathConds,
    2352             :                                                  PrecipWater,
    2353             :                                                  AerosolOptDepth,
    2354             :                                                  SnowDepth,
    2355             :                                                  DaysSinceLastSnow,
    2356             :                                                  Albedo,
    2357             :                                                  LiquidPrecip);
    2358             :                     }
    2359             :                 }
    2360       94763 :                 if (!WeatherDataLine.good) {
    2361           0 :                     ShowFatalError(state,
    2362           0 :                                    format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2363             :                                           WYear,
    2364             :                                           WMonth,
    2365             :                                           WDay,
    2366             :                                           WHour,
    2367             :                                           WMinute,
    2368           0 :                                           state.files.inputWeatherFile.error_state_to_string()),
    2369           0 :                                    OptionalOutputFileRef{state.files.eso});
    2370             :                 }
    2371       94763 :                 if (state.dataWeather->CurDayOfWeek <= 7) {
    2372       94763 :                     state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2373             :                 }
    2374       94763 :                 bool RecordDateMatch =
    2375      188300 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && !thisEnviron.MatchYear) ||
    2376       93537 :                     (WMonth == thisEnviron.StartMonth && WDay == thisEnviron.StartDay && thisEnviron.MatchYear && WYear == thisEnviron.StartYear);
    2377       94763 :                 if (RecordDateMatch) {
    2378        1226 :                     state.files.inputWeatherFile.backspace();
    2379        1226 :                     Ready = true;
    2380        1226 :                     if (state.dataWeather->CurDayOfWeek <= 7) {
    2381        1226 :                         --state.dataWeather->CurDayOfWeek;
    2382             :                     }
    2383             :                     // Do the range checks on the first set of fields -- no others.
    2384        1226 :                     bool ErrorsFound = false;
    2385        1226 :                     if (DryBulb < 99.9 && (DryBulb < -90.0 || DryBulb > 70.0)) {
    2386           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2387           0 :                         ShowContinueError(state, format("DryBulb Temperature ({:.2R}) is out of range [-90.0, 70.0]", DryBulb));
    2388           0 :                         ErrorsFound = true;
    2389             :                     }
    2390             : 
    2391        1226 :                     if (DewPoint < 99.9 && (DewPoint < -90.0 || DewPoint > 70.0)) {
    2392           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2393           0 :                         ShowContinueError(state, format("DewPoint Temperature ({:.2R}) is out of range [-90.0, 70.0]", DewPoint));
    2394           0 :                         ErrorsFound = true;
    2395             :                     }
    2396             : 
    2397        1226 :                     if (RelHum < 999.0 && (RelHum < 0.0 || RelHum > 110.0)) {
    2398           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2399           0 :                         ShowContinueError(state, format("Relative Humidity ({:.2R}) is out of range [0.0, 100.0]", RelHum));
    2400           0 :                         ErrorsFound = true;
    2401             :                     }
    2402             : 
    2403        1226 :                     if (AtmPress < 999999.0 && (AtmPress <= 31000.0 || AtmPress > 120000.0)) {
    2404           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2405           0 :                         ShowContinueError(state, format("Atmospheric Pressure ({:.0R}) is out of range [31000, 120000]", AtmPress));
    2406           0 :                         ErrorsFound = true;
    2407             :                     }
    2408             : 
    2409        1226 :                     if (DirectRad < 9999.0 && DirectRad < 0.0) {
    2410           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2411           0 :                         ShowContinueError(state, format("Direct Radiation ({:.2R}) is out of range [0.0, -]", DirectRad));
    2412           0 :                         ErrorsFound = true;
    2413             :                     }
    2414             : 
    2415        1226 :                     if (DiffuseRad < 9999.0 && DiffuseRad < 0.0) {
    2416           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2417           0 :                         ShowContinueError(state, format("Diffuse Radiation ({:.2R}) is out of range [0.0, -]", DiffuseRad));
    2418           0 :                         ErrorsFound = true;
    2419             :                     }
    2420             : 
    2421        1226 :                     if (WindDir < 999.0 && (WindDir < 0.0 || WindDir > 360.0)) {
    2422           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2423           0 :                         ShowContinueError(state, format("Wind Direction ({:.2R}) is out of range [0.0, 360.0]", WindDir));
    2424           0 :                         ErrorsFound = true;
    2425             :                     }
    2426             : 
    2427        1226 :                     if (WindSpeed < 999.0 && (WindSpeed < 0.0 || WindSpeed > 40.0)) {
    2428           0 :                         ShowSevereError(state, format("{}: {}", routineName, state.dataEnvrn->WeatherFileLocationTitle));
    2429           0 :                         ShowContinueError(state, format("Wind Speed ({:.2R}) is out of range [0.0, 40.0]", WindSpeed));
    2430           0 :                         ErrorsFound = true;
    2431             :                     }
    2432             : 
    2433        1226 :                     if (ErrorsFound) {
    2434           0 :                         ShowSevereError(state, "Out of Range errors found with initial day of WeatherFile");
    2435             :                     }
    2436             :                 } else {
    2437             :                     //  Must skip this day
    2438       93537 :                     for (int i = 2; i <= state.dataWeather->NumIntervalsPerHour; ++i) {
    2439           0 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2440           0 :                         if (!WeatherDataLine.good) {
    2441           0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2442           0 :                             ShowFatalError(state,
    2443           0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2444             :                                                   WYear,
    2445             :                                                   WMonth,
    2446             :                                                   WDay,
    2447             :                                                   WHour,
    2448             :                                                   WMinute,
    2449           0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2450           0 :                                            OptionalOutputFileRef{state.files.eso});
    2451             :                         }
    2452             :                     }
    2453     2244888 :                     for (int i = 1; i <= 23 * state.dataWeather->NumIntervalsPerHour; ++i) {
    2454     2151351 :                         WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2455     2151351 :                         if (!WeatherDataLine.good) {
    2456           0 :                             readList(WeatherDataLine.data, WYear, WMonth, WDay, WHour, WMinute);
    2457           0 :                             ShowFatalError(state,
    2458           0 :                                            format("Error occurred on EPW while searching for first day, stopped at {}/{}/{} {}:{} IO Error='{}'",
    2459             :                                                   WYear,
    2460             :                                                   WMonth,
    2461             :                                                   WDay,
    2462             :                                                   WHour,
    2463             :                                                   WMinute,
    2464           0 :                                                   state.files.inputWeatherFile.error_state_to_string()),
    2465           0 :                                            OptionalOutputFileRef{state.files.eso});
    2466             :                         }
    2467             :                     }
    2468             :                 }
    2469             :             }
    2470             : 
    2471        1226 :             auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    2472             :             // Why do some things here use state.dataWeather->Envrn and some the parameter Environ?
    2473             : 
    2474             :             // Positioned to proper day
    2475        1237 :             if (!state.dataGlobal->KickOffSimulation && !state.dataGlobal->DoingSizing &&
    2476          11 :                 thisEnviron.KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather) {
    2477           6 :                 ++thisEnviron.CurrentCycle;
    2478           6 :                 if (!thisEnviron.RollDayTypeOnRepeat) {
    2479           0 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2480           0 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2481           0 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2482             :                     }
    2483           0 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2484           6 :                 } else if (thisEnviron.CurrentCycle == 1) {
    2485           6 :                     SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2486           6 :                     thisEnviron.SetWeekDays = true;
    2487           6 :                     if (state.dataWeather->DaylightSavingIsActive) {
    2488           1 :                         SetDSTDateRanges(state, envCurr.MonWeekDay, state.dataWeather->DSTIndex);
    2489             :                     }
    2490           6 :                     SetSpecialDayDates(state, envCurr.MonWeekDay);
    2491             :                 } else {
    2492           0 :                     state.dataWeather->CurDayOfWeek = state.dataEnvrn->DayOfWeekTomorrow;
    2493             :                 }
    2494             :             } else {
    2495        1220 :                 SetDayOfWeekInitialValues(thisEnviron.DayOfWeek, state.dataWeather->CurDayOfWeek);
    2496             :             }
    2497        1226 :         }
    2498             : 
    2499        3853 :         bool TryAgain = true;
    2500        3853 :         bool SkipThisDay = false;
    2501             : 
    2502        7706 :         while (TryAgain) {
    2503             : 
    2504        3853 :             TryAgain = false;
    2505             : 
    2506       96325 :             for (int hour = 1; hour <= 24; ++hour) {
    2507      184944 :                 for (int CurTimeStep = 1; CurTimeStep <= state.dataWeather->NumIntervalsPerHour; ++CurTimeStep) {
    2508       92472 :                     state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour) = WeatherVars();
    2509       92472 :                     auto WeatherDataLine = state.files.inputWeatherFile.readLine();
    2510       92472 :                     if (!WeatherDataLine.good) {
    2511           0 :                         WeatherDataLine.data.clear();
    2512             :                     }
    2513       92472 :                     if (WeatherDataLine.data.empty()) {
    2514           0 :                         if (hour == 1) {
    2515           0 :                             WeatherDataLine.eof = true;
    2516           0 :                             WeatherDataLine.good = false;
    2517             :                         } else {
    2518           0 :                             WeatherDataLine.good = false;
    2519             :                         }
    2520             :                     }
    2521       92472 :                     if (WeatherDataLine.good) {
    2522             :                         bool ErrorFound;
    2523       92472 :                         InterpretWeatherDataLine(state,
    2524             :                                                  WeatherDataLine.data,
    2525             :                                                  ErrorFound,
    2526             :                                                  WYear,
    2527             :                                                  WMonth,
    2528             :                                                  WDay,
    2529             :                                                  WHour,
    2530             :                                                  WMinute,
    2531             :                                                  DryBulb,
    2532             :                                                  DewPoint,
    2533             :                                                  RelHum,
    2534             :                                                  AtmPress,
    2535             :                                                  ETHoriz,
    2536             :                                                  ETDirect,
    2537             :                                                  IRHoriz,
    2538             :                                                  GLBHoriz,
    2539             :                                                  DirectRad,
    2540             :                                                  DiffuseRad,
    2541             :                                                  GLBHorizIllum,
    2542             :                                                  DirectNrmIllum,
    2543             :                                                  DiffuseHorizIllum,
    2544             :                                                  ZenLum,
    2545             :                                                  WindDir,
    2546             :                                                  WindSpeed,
    2547             :                                                  TotalSkyCover,
    2548             :                                                  OpaqueSkyCover,
    2549             :                                                  Visibility,
    2550             :                                                  CeilHeight,
    2551             :                                                  PresWeathObs,
    2552             :                                                  PresWeathConds,
    2553             :                                                  PrecipWater,
    2554             :                                                  AerosolOptDepth,
    2555             :                                                  SnowDepth,
    2556             :                                                  DaysSinceLastSnow,
    2557             :                                                  Albedo,
    2558             :                                                  LiquidPrecip);
    2559             :                     } else { // ReadStatus /=0
    2560           0 :                         if (WeatherDataLine.eof &&
    2561           0 :                             state.dataWeather->NumDataPeriods == 1) { // Standard End-of-file, rewind and position to first day...
    2562           0 :                             if (state.dataWeather->DataPeriods(1).NumDays >= state.dataWeather->NumDaysInYear) {
    2563           0 :                                 state.files.inputWeatherFile.rewind();
    2564           0 :                                 SkipEPlusWFHeader(state);
    2565           0 :                                 WeatherDataLine.update(state.files.inputWeatherFile.readLine());
    2566             :                                 bool ErrorFound;
    2567           0 :                                 InterpretWeatherDataLine(state,
    2568             :                                                          WeatherDataLine.data,
    2569             :                                                          ErrorFound,
    2570             :                                                          WYear,
    2571             :                                                          WMonth,
    2572             :                                                          WDay,
    2573             :                                                          WHour,
    2574             :                                                          WMinute,
    2575             :                                                          DryBulb,
    2576             :                                                          DewPoint,
    2577             :                                                          RelHum,
    2578             :                                                          AtmPress,
    2579             :                                                          ETHoriz,
    2580             :                                                          ETDirect,
    2581             :                                                          IRHoriz,
    2582             :                                                          GLBHoriz,
    2583             :                                                          DirectRad,
    2584             :                                                          DiffuseRad,
    2585             :                                                          GLBHorizIllum,
    2586             :                                                          DirectNrmIllum,
    2587             :                                                          DiffuseHorizIllum,
    2588             :                                                          ZenLum,
    2589             :                                                          WindDir,
    2590             :                                                          WindSpeed,
    2591             :                                                          TotalSkyCover,
    2592             :                                                          OpaqueSkyCover,
    2593             :                                                          Visibility,
    2594             :                                                          CeilHeight,
    2595             :                                                          PresWeathObs,
    2596             :                                                          PresWeathConds,
    2597             :                                                          PrecipWater,
    2598             :                                                          AerosolOptDepth,
    2599             :                                                          SnowDepth,
    2600             :                                                          DaysSinceLastSnow,
    2601             :                                                          Albedo,
    2602             :                                                          LiquidPrecip);
    2603             :                             } else {
    2604           0 :                                 ShowFatalError(state,
    2605           0 :                                                format("End-of-File encountered after {}/{}/{} {}:{}, starting from first day of Weather File would "
    2606             :                                                       "not be \"next day\"",
    2607             :                                                       WYear,
    2608             :                                                       WMonth,
    2609             :                                                       WDay,
    2610             :                                                       WHour,
    2611             :                                                       WMinute));
    2612             :                             }
    2613             :                         } else {
    2614           0 :                             ShowFatalError(state,
    2615           0 :                                            format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2616             :                                                   WYear,
    2617             :                                                   WMonth,
    2618             :                                                   WDay,
    2619             :                                                   WHour,
    2620             :                                                   WMinute),
    2621           0 :                                            OptionalOutputFileRef{state.files.eso});
    2622             :                         }
    2623             :                     }
    2624             : 
    2625       92472 :                     if (hour != WHour) {
    2626           0 :                         ShowFatalError(state,
    2627           0 :                                        format("Unexpected error condition in middle of reading EPW file, stopped at {}/{}/{} {}:{}",
    2628             :                                               WYear,
    2629             :                                               WMonth,
    2630             :                                               WDay,
    2631             :                                               WHour,
    2632             :                                               WMinute),
    2633           0 :                                        OptionalOutputFileRef{state.files.eso});
    2634             :                     }
    2635             : 
    2636             :                     //         Set possible missing values
    2637       92472 :                     if (ETHoriz < 0.0) ETHoriz = 9999.0;
    2638       92472 :                     if (ETDirect < 0.0) ETDirect = 9999.0;
    2639       92472 :                     if (IRHoriz <= 0.0) IRHoriz = 9999.0;
    2640       92472 :                     if (GLBHoriz < 0.0) GLBHoriz = 9999.0;
    2641       92472 :                     if (state.dataEnvrn->DisplayWeatherMissingDataWarnings) {
    2642           0 :                         if (DirectRad >= 9999.0) {
    2643           0 :                             ++state.dataWeather->wvarsMissedCounts.BeamSolarRad;
    2644             :                         }
    2645           0 :                         if (DiffuseRad >= 9999.0) {
    2646           0 :                             state.dataWeather->wvarsMissedCounts.DifSolarRad = state.dataWeather->wvarsMissedCounts.BeamSolarRad + 1;
    2647             :                         }
    2648           0 :                         if (DirectRad < 0.0) {
    2649           0 :                             DirectRad = 9999.0;
    2650           0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad;
    2651             :                         }
    2652           0 :                         if (DiffuseRad < 0.0) {
    2653           0 :                             DiffuseRad = 9999.0;
    2654           0 :                             ++state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad;
    2655             :                         }
    2656             :                     }
    2657       92472 :                     if (GLBHorizIllum < 0.0) GLBHorizIllum = 999999.0;
    2658       92472 :                     if (DirectNrmIllum < 0.0) DirectNrmIllum = 999999.0;
    2659       92472 :                     if (DiffuseHorizIllum < 0.0) DiffuseHorizIllum = 999999.0;
    2660       92472 :                     if (ZenLum < 0.0) ZenLum = 99999.0;
    2661       92472 :                     if (AtmPress < 0.0) AtmPress = 999999.0;
    2662       92472 :                     if (WindSpeed < 0.0) WindSpeed = 999.0;
    2663       92472 :                     if (WindDir < -360.0 || WindDir > 360.0) WindDir = 999.0;
    2664       92472 :                     if (TotalSkyCover < 0.0) TotalSkyCover = 99.0;
    2665       92472 :                     if (RelHum < 0.0) RelHum = 999.0;
    2666       92472 :                     if (OpaqueSkyCover < 0.0) OpaqueSkyCover = 99.0;
    2667       92472 :                     if (Visibility < 0.0) Visibility = 9999.0;
    2668       92472 :                     if (CeilHeight < 0.0) CeilHeight = 9999.0;
    2669       92472 :                     if (PresWeathObs < 0) PresWeathObs = 9;
    2670       92472 :                     if (PrecipWater < 0.0) PrecipWater = 999.0;
    2671       92472 :                     if (AerosolOptDepth < 0.0) AerosolOptDepth = 999.0;
    2672       92472 :                     if (SnowDepth < 0.0) SnowDepth = 999.0;
    2673       92472 :                     if (DaysSinceLastSnow < 0.0) DaysSinceLastSnow = 99.0;
    2674       92472 :                     if (Albedo < 0.0) Albedo = 999.0;
    2675       92472 :                     if (LiquidPrecip < 0.0) LiquidPrecip = 999.0;
    2676             : 
    2677       92472 :                     if (hour == 1 && CurTimeStep == 1) {
    2678        3853 :                         if (WMonth == 2 && WDay == 29 && (!state.dataEnvrn->CurrentYearIsLeapYear || !state.dataWeather->WFAllowsLeapYears)) {
    2679           0 :                             state.dataWeather->EndDayOfMonth(2) = 28;
    2680           0 :                             state.dataWeather->EndDayOfMonthWithLeapDay(2) = 28;
    2681           0 :                             SkipThisDay = true;
    2682           0 :                             TryAgain = true;
    2683           0 :                             ShowWarningError(state, "ReadEPlusWeatherForDay: Feb29 data encountered but will not be processed.");
    2684           0 :                             if (!state.dataWeather->WFAllowsLeapYears) {
    2685           0 :                                 ShowContinueError(
    2686             :                                     state, "...WeatherFile does not allow Leap Years. HOLIDAYS/DAYLIGHT SAVINGS header must indicate \"Yes\".");
    2687             :                             }
    2688           0 :                             continue;
    2689             :                         } else {
    2690        3853 :                             TryAgain = false;
    2691        3853 :                             SkipThisDay = false;
    2692             :                         }
    2693             : 
    2694        3853 :                         if (thisEnviron.ActualWeather && state.dataEnvrn->CurrentYearIsLeapYear) {
    2695           0 :                             if (WMonth == 3 && WDay == 1 && state.dataEnvrn->Month == 2 && state.dataEnvrn->DayOfMonth == 28) {
    2696           0 :                                 ShowFatalError(state, "ReadEPlusWeatherForDay: Current year is a leap year, but Feb29 data is missing.");
    2697             :                             }
    2698             :                         }
    2699             : 
    2700        3853 :                         state.dataWeather->TomorrowVariables.Year = WYear;
    2701        3853 :                         state.dataWeather->TomorrowVariables.Month = WMonth;
    2702        3853 :                         state.dataWeather->TomorrowVariables.DayOfMonth = WDay;
    2703        3853 :                         state.dataWeather->TomorrowVariables.DayOfYear = General::OrdinalDay(WMonth, WDay, state.dataWeather->LeapYearAdd);
    2704        3853 :                         state.dataWeather->TomorrowVariables.DayOfYear_Schedule = General::OrdinalDay(WMonth, WDay, 1);
    2705             :                         Real64 A;
    2706             :                         Real64 B;
    2707             :                         Real64 C;
    2708             :                         Real64 AVSC;
    2709        3853 :                         CalculateDailySolarCoeffs(state,
    2710        3853 :                                                   state.dataWeather->TomorrowVariables.DayOfYear,
    2711             :                                                   A,
    2712             :                                                   B,
    2713             :                                                   C,
    2714             :                                                   AVSC,
    2715        3853 :                                                   state.dataWeather->TomorrowVariables.EquationOfTime,
    2716        3853 :                                                   state.dataWeather->TomorrowVariables.SinSolarDeclinAngle,
    2717        3853 :                                                   state.dataWeather->TomorrowVariables.CosSolarDeclinAngle);
    2718        3853 :                         if (state.dataWeather->CurDayOfWeek <= 7) {
    2719        3753 :                             state.dataWeather->CurDayOfWeek = mod(state.dataWeather->CurDayOfWeek, 7) + 1;
    2720             :                         }
    2721        3853 :                         state.dataWeather->TomorrowVariables.DayOfWeek = state.dataWeather->CurDayOfWeek;
    2722        7706 :                         state.dataWeather->TomorrowVariables.DaylightSavingIndex =
    2723        3853 :                             state.dataWeather->DSTIndex(state.dataWeather->TomorrowVariables.DayOfYear);
    2724        3853 :                         state.dataWeather->TomorrowVariables.HolidayIndex =
    2725        3853 :                             state.dataWeather->SpecialDayTypes(state.dataWeather->TomorrowVariables.DayOfYear);
    2726             :                     }
    2727             : 
    2728       92472 :                     if (SkipThisDay) continue;
    2729             : 
    2730             :                     // Check out missing values
    2731             : 
    2732       92472 :                     if (DryBulb >= 99.9) {
    2733           0 :                         DryBulb = state.dataWeather->wvarsMissing.OutDryBulbTemp;
    2734           0 :                         ++state.dataWeather->wvarsMissedCounts.OutDryBulbTemp;
    2735             :                     }
    2736       92472 :                     if (DryBulb < -90.0 || DryBulb > 70.0) {
    2737           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp;
    2738             :                     }
    2739             : 
    2740       92472 :                     if (DewPoint >= 99.9) {
    2741           0 :                         DewPoint = state.dataWeather->wvarsMissing.OutDewPointTemp;
    2742           0 :                         ++state.dataWeather->wvarsMissedCounts.OutDewPointTemp;
    2743             :                     }
    2744       92472 :                     if (DewPoint < -90.0 || DewPoint > 70.0) {
    2745           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp;
    2746             :                     }
    2747             : 
    2748       92472 :                     if (RelHum >= 999.0) {
    2749           0 :                         RelHum = state.dataWeather->wvarsMissing.OutRelHum;
    2750           0 :                         ++state.dataWeather->wvarsMissedCounts.OutRelHum;
    2751             :                     }
    2752       92472 :                     if (RelHum < 0.0 || RelHum > 110.0) {
    2753           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutRelHum;
    2754             :                     }
    2755             : 
    2756       92472 :                     if (AtmPress >= 999999.0) {
    2757           0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2758           0 :                         ++state.dataWeather->wvarsMissedCounts.OutBaroPress;
    2759             :                     }
    2760       92472 :                     if (AtmPress <= 31000.0 || AtmPress > 120000.0) {
    2761           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress;
    2762           0 :                         AtmPress = state.dataWeather->wvarsMissing.OutBaroPress;
    2763             :                     }
    2764             : 
    2765       92472 :                     if (WindDir >= 999.0) {
    2766           0 :                         WindDir = state.dataWeather->wvarsMissing.WindDir;
    2767           0 :                         ++state.dataWeather->wvarsMissedCounts.WindDir;
    2768             :                     }
    2769       92472 :                     if (WindDir < 0.0 || WindDir > 360.0) {
    2770           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindDir;
    2771             :                     }
    2772             : 
    2773       92472 :                     if (WindSpeed >= 999.0) {
    2774           0 :                         WindSpeed = state.dataWeather->wvarsMissing.WindSpeed;
    2775           0 :                         ++state.dataWeather->wvarsMissedCounts.WindSpeed;
    2776             :                     }
    2777       92472 :                     if (WindSpeed < 0.0 || WindSpeed > 40.0) {
    2778           0 :                         ++state.dataWeather->wvarsOutOfRangeCounts.WindSpeed;
    2779             :                     }
    2780             : 
    2781       92472 :                     if (TotalSkyCover >= 99.0) {
    2782           0 :                         TotalSkyCover = state.dataWeather->wvarsMissing.TotalSkyCover;
    2783           0 :                         ++state.dataWeather->wvarsMissedCounts.TotalSkyCover;
    2784             :                     }
    2785             : 
    2786       92472 :                     if (OpaqueSkyCover >= 99.0) {
    2787           0 :                         OpaqueSkyCover = state.dataWeather->wvarsMissing.OpaqueSkyCover;
    2788           0 :                         ++state.dataWeather->wvarsMissedCounts.OpaqueSkyCover;
    2789             :                     }
    2790             : 
    2791       92472 :                     if (SnowDepth >= 999.0) {
    2792          72 :                         SnowDepth = state.dataWeather->wvarsMissing.SnowDepth;
    2793          72 :                         ++state.dataWeather->wvarsMissedCounts.SnowDepth;
    2794             :                     }
    2795             : 
    2796       92472 :                     if (Albedo >= 999.0) {
    2797       73920 :                         Albedo = state.dataWeather->wvarsMissing.Albedo;
    2798       73920 :                         ++state.dataWeather->wvarsMissedCounts.Albedo;
    2799             :                     }
    2800             : 
    2801       92472 :                     if (LiquidPrecip >= 999.0) {
    2802       74625 :                         LiquidPrecip = state.dataWeather->wvarsMissing.LiquidPrecip;
    2803       74625 :                         ++state.dataWeather->wvarsMissedCounts.LiquidPrecip;
    2804             :                     }
    2805             : 
    2806       92472 :                     auto &tomorrow = state.dataWeather->wvarsHrTsTomorrow(CurTimeStep, hour);
    2807       92472 :                     tomorrow.OutDryBulbTemp = DryBulb;
    2808       92472 :                     tomorrow.OutDewPointTemp = DewPoint;
    2809       92472 :                     tomorrow.OutBaroPress = AtmPress;
    2810       92472 :                     tomorrow.OutRelHum = RelHum;
    2811       92472 :                     RelHum *= 0.01;
    2812       92472 :                     tomorrow.WindSpeed = WindSpeed;
    2813       92472 :                     tomorrow.WindDir = WindDir;
    2814       92472 :                     tomorrow.LiquidPrecip = LiquidPrecip;
    2815       92472 :                     tomorrow.TotalSkyCover = TotalSkyCover;
    2816       92472 :                     tomorrow.OpaqueSkyCover = OpaqueSkyCover;
    2817             : 
    2818       92472 :                     calcSky(state, tomorrow.HorizIRSky, tomorrow.SkyTemp, OpaqueSkyCover, DryBulb, DewPoint, RelHum, IRHoriz);
    2819             : 
    2820       92472 :                     if (ETHoriz >= 9999.0) ETHoriz = 0.0;
    2821       92472 :                     if (ETDirect >= 9999.0) ETDirect = 0.0;
    2822       92472 :                     if (GLBHoriz >= 9999.0) GLBHoriz = 0.0;
    2823       92472 :                     if (DirectRad >= 9999.0) DirectRad = 0.0;
    2824       92472 :                     if (DiffuseRad >= 9999.0) DiffuseRad = 0.0;
    2825       92472 :                     if (GLBHorizIllum >= 999900.0) GLBHorizIllum = 0.0;
    2826       92472 :                     if (DirectNrmIllum >= 999900.0) DirectNrmIllum = 0.0;
    2827       92472 :                     if (DiffuseHorizIllum >= 999900.0) DiffuseHorizIllum = 0.0;
    2828       92472 :                     if (ZenLum >= 99990.0) ZenLum = 0.0;
    2829       92472 :                     if (state.dataEnvrn->IgnoreSolarRadiation) {
    2830           0 :                         GLBHoriz = 0.0;
    2831           0 :                         DirectRad = 0.0;
    2832           0 :                         DiffuseRad = 0.0;
    2833             :                     }
    2834       92472 :                     if (state.dataEnvrn->IgnoreBeamRadiation) {
    2835           0 :                         DirectRad = 0.0;
    2836             :                     }
    2837       92472 :                     if (state.dataEnvrn->IgnoreDiffuseRadiation) {
    2838           0 :                         DiffuseRad = 0.0;
    2839             :                     }
    2840             : 
    2841       92472 :                     tomorrow.BeamSolarRad = DirectRad;
    2842       92472 :                     tomorrow.DifSolarRad = DiffuseRad;
    2843             : 
    2844       92472 :                     tomorrow.IsRain = false;
    2845       92472 :                     if (PresWeathObs == 0) {
    2846         144 :                         if (PresWeathConds(1) < 9 || PresWeathConds(2) < 9 || PresWeathConds(3) < 9) tomorrow.IsRain = true;
    2847             :                     } else {
    2848       92328 :                         tomorrow.IsRain = false;
    2849             :                     }
    2850       92472 :                     tomorrow.IsSnow = (SnowDepth > 0.0);
    2851             : 
    2852             :                     // default if rain but none on weather file
    2853       92472 :                     if (tomorrow.IsRain && tomorrow.LiquidPrecip == 0.0) tomorrow.LiquidPrecip = 2.0; // 2mm in an hour ~ .08 inch
    2854             : 
    2855       92472 :                     state.dataWeather->wvarsMissing.OutDryBulbTemp = DryBulb;
    2856       92472 :                     state.dataWeather->wvarsMissing.OutDewPointTemp = DewPoint;
    2857       92472 :                     state.dataWeather->wvarsMissing.OutRelHum = static_cast<int>(std::round(RelHum * 100.0));
    2858       92472 :                     state.dataWeather->wvarsMissing.OutBaroPress = AtmPress;
    2859       92472 :                     state.dataWeather->wvarsMissing.WindDir = WindDir;
    2860       92472 :                     state.dataWeather->wvarsMissing.WindSpeed = WindSpeed;
    2861       92472 :                     state.dataWeather->wvarsMissing.TotalSkyCover = TotalSkyCover;
    2862       92472 :                     state.dataWeather->wvarsMissing.OpaqueSkyCover = OpaqueSkyCover;
    2863       92472 :                     state.dataWeather->wvarsMissing.Visibility = Visibility;
    2864       92472 :                     state.dataWeather->wvarsMissing.Ceiling = CeilHeight;
    2865       92472 :                     state.dataWeather->wvarsMissing.WaterPrecip = PrecipWater;
    2866       92472 :                     state.dataWeather->wvarsMissing.AerOptDepth = AerosolOptDepth;
    2867       92472 :                     state.dataWeather->wvarsMissing.SnowDepth = SnowDepth;
    2868       92472 :                     state.dataWeather->wvarsMissing.DaysLastSnow = DaysSinceLastSnow;
    2869       92472 :                     state.dataWeather->wvarsMissing.Albedo = Albedo;
    2870             : 
    2871       92472 :                 } // for (CurTimeStep)
    2872             : 
    2873             :             } // for (Hour)
    2874             : 
    2875             :         } // Try Again While Loop
    2876             : 
    2877        3853 :         if (BackSpaceAfterRead) {
    2878           0 :             state.files.inputWeatherFile.backspace();
    2879             :         }
    2880             : 
    2881        3853 :         if (state.dataWeather->NumIntervalsPerHour == 1 && state.dataGlobal->NumOfTimeStepInHour > 1) {
    2882             :             // Create interpolated weather for timestep orientation
    2883             :             // First copy ts=1 (hourly) from data arrays to Wthr structure
    2884       86950 :             for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    2885       83472 :                 wvarsHr(hour) = state.dataWeather->wvarsHrTsTomorrow(1, hour);
    2886             :             }
    2887             : 
    2888        3478 :             if (!state.dataWeather->LastHourSet) {
    2889             :                 // For first day of weather, all time steps of the first hour will be
    2890             :                 // equal to the first hour's value.
    2891             :                 // 2021-06: An additional input is added to here to allow the user to have chosen which hour to use
    2892        1215 :                 int HrUsedtoInterp = thisEnviron.firstHrInterpUseHr1 ? 1 : 24;
    2893        1215 :                 state.dataWeather->wvarsLastHr = wvarsHr(HrUsedtoInterp);
    2894        1215 :                 state.dataWeather->LastHourSet = true;
    2895             :             }
    2896             : 
    2897       86950 :             for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    2898             : 
    2899       83472 :                 int NextHr = (hour == Constant::HoursInDay) ? 1 : hour + 1;
    2900             : 
    2901       83472 :                 state.dataWeather->wvarsNextHr.BeamSolarRad = wvarsHr(NextHr).BeamSolarRad;
    2902       83472 :                 state.dataWeather->wvarsNextHr.DifSolarRad = wvarsHr(NextHr).DifSolarRad;
    2903       83472 :                 state.dataWeather->wvarsNextHr.LiquidPrecip = wvarsHr(NextHr).LiquidPrecip;
    2904             : 
    2905      500256 :                 for (int ts = 1; ts <= state.dataGlobal->NumOfTimeStepInHour; ++ts) {
    2906             : 
    2907      416784 :                     Real64 wgtCurrHr = state.dataWeather->Interpolation(ts);
    2908      416784 :                     Real64 wgtPrevHr = 1.0 - wgtCurrHr;
    2909             : 
    2910             :                     // Do Solar "weighting"
    2911             : 
    2912      416784 :                     Real64 wgtCurrHrSolar = state.dataWeather->SolarInterpolation(ts);
    2913             :                     Real64 wgtPrevHrSolar;
    2914             :                     Real64 wgtNextHrSolar;
    2915             : 
    2916      416784 :                     if (state.dataGlobal->NumOfTimeStepInHour == 1) {
    2917           0 :                         wgtNextHrSolar = 1.0 - wgtCurrHr;
    2918           0 :                         wgtPrevHrSolar = 0.0;
    2919      416784 :                     } else if (wgtCurrHrSolar == 1.0) {
    2920             :                         //  It's at the half hour
    2921       83472 :                         wgtPrevHrSolar = 0.0;
    2922       83472 :                         wgtNextHrSolar = 0.0;
    2923      333312 :                     } else if (ts * state.dataWeather->TimeStepFraction < 0.5) {
    2924      124920 :                         wgtPrevHrSolar = 1.0 - wgtCurrHrSolar;
    2925      124920 :                         wgtNextHrSolar = 0.0;
    2926             :                     } else { // After the half hour
    2927      208392 :                         wgtPrevHrSolar = 0.0;
    2928      208392 :                         wgtNextHrSolar = 1.0 - wgtCurrHrSolar;
    2929             :                     }
    2930             : 
    2931      416784 :                     auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    2932      416784 :                     auto const &wvarsH = wvarsHr(hour);
    2933      416784 :                     tomorrowTs.OutDryBulbTemp = state.dataWeather->wvarsLastHr.OutDryBulbTemp * wgtPrevHr + wvarsH.OutDryBulbTemp * wgtCurrHr;
    2934      416784 :                     tomorrowTs.OutBaroPress = state.dataWeather->wvarsLastHr.OutBaroPress * wgtPrevHr + wvarsH.OutBaroPress * wgtCurrHr;
    2935      416784 :                     tomorrowTs.OutDewPointTemp = state.dataWeather->wvarsLastHr.OutDewPointTemp * wgtPrevHr + wvarsH.OutDewPointTemp * wgtCurrHr;
    2936      416784 :                     tomorrowTs.OutRelHum = state.dataWeather->wvarsLastHr.OutRelHum * wgtPrevHr + wvarsH.OutRelHum * wgtCurrHr;
    2937      416784 :                     tomorrowTs.WindSpeed = state.dataWeather->wvarsLastHr.WindSpeed * wgtPrevHr + wvarsH.WindSpeed * wgtCurrHr;
    2938      416784 :                     tomorrowTs.WindDir = interpolateWindDirection(state.dataWeather->wvarsLastHr.WindDir, wvarsH.WindDir, wgtCurrHr);
    2939      416784 :                     tomorrowTs.TotalSkyCover = state.dataWeather->wvarsLastHr.TotalSkyCover * wgtPrevHr + wvarsH.TotalSkyCover * wgtCurrHr;
    2940      416784 :                     tomorrowTs.OpaqueSkyCover = state.dataWeather->wvarsLastHr.OpaqueSkyCover * wgtPrevHr + wvarsH.OpaqueSkyCover * wgtCurrHr;
    2941             :                     // Sky emissivity now takes interpolated timestep inputs rather than interpolated calculation esky results
    2942      416784 :                     calcSky(state,
    2943      416784 :                             tomorrowTs.HorizIRSky,
    2944      416784 :                             tomorrowTs.SkyTemp,
    2945             :                             tomorrowTs.OpaqueSkyCover,
    2946             :                             tomorrowTs.OutDryBulbTemp,
    2947             :                             tomorrowTs.OutDewPointTemp,
    2948      416784 :                             tomorrowTs.OutRelHum * 0.01,
    2949      416784 :                             state.dataWeather->wvarsLastHr.HorizIRSky * wgtPrevHr + wvarsH.HorizIRSky * wgtCurrHr);
    2950             : 
    2951      416784 :                     tomorrowTs.DifSolarRad = state.dataWeather->wvarsLastHr.DifSolarRad * wgtPrevHrSolar + wvarsH.DifSolarRad * wgtCurrHrSolar +
    2952      416784 :                                              state.dataWeather->wvarsNextHr.DifSolarRad * wgtNextHrSolar;
    2953      416784 :                     tomorrowTs.BeamSolarRad = state.dataWeather->wvarsLastHr.BeamSolarRad * wgtPrevHrSolar + wvarsH.BeamSolarRad * wgtCurrHrSolar +
    2954      416784 :                                               state.dataWeather->wvarsNextHr.BeamSolarRad * wgtNextHrSolar;
    2955             : 
    2956      416784 :                     tomorrowTs.LiquidPrecip = state.dataWeather->wvarsLastHr.LiquidPrecip * wgtPrevHr + wvarsH.LiquidPrecip * wgtCurrHr;
    2957      416784 :                     tomorrowTs.LiquidPrecip /= double(state.dataGlobal->NumOfTimeStepInHour);
    2958      416784 :                     tomorrowTs.IsRain = tomorrowTs.LiquidPrecip >= state.dataWeather->IsRainThreshold; // Wthr%IsRain
    2959      416784 :                     tomorrowTs.IsSnow = wvarsH.IsSnow;
    2960             :                 } // End of TS Loop
    2961             : 
    2962       83472 :                 state.dataWeather->wvarsLastHr = wvarsHr(hour);
    2963             :             } // End of Hour Loop
    2964             :         }
    2965             : 
    2966        3853 :         if (thisEnviron.WP_Type1 != 0) {
    2967           0 :             switch (state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).skyTempModel) {
    2968           0 :             case SkyTempModel::ScheduleValue: {
    2969           0 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    2970             : 
    2971           0 :                 ScheduleManager::GetScheduleValuesForDay(state,
    2972           0 :                                                          state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).SchedulePtr,
    2973             :                                                          tmp,
    2974           0 :                                                          state.dataWeather->TomorrowVariables.DayOfYear_Schedule,
    2975           0 :                                                          state.dataWeather->CurDayOfWeek);
    2976             : 
    2977           0 :                 for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr) {
    2978           0 :                     for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS) {
    2979           0 :                         state.dataWeather->wvarsHrTsTomorrow(iTS, iHr).SkyTemp = tmp(iTS, iHr);
    2980             :                     }
    2981             :                 }
    2982           0 :             } break;
    2983           0 :             case SkyTempModel::DryBulbDelta: {
    2984           0 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    2985           0 :                 ScheduleManager::GetScheduleValuesForDay(state,
    2986           0 :                                                          state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).SchedulePtr,
    2987             :                                                          tmp,
    2988           0 :                                                          state.dataWeather->TomorrowVariables.DayOfYear_Schedule,
    2989           0 :                                                          state.dataWeather->CurDayOfWeek);
    2990             : 
    2991           0 :                 for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    2992           0 :                     for (int ts = 1; ts <= state.dataGlobal->NumOfTimeStepInHour; ++ts) {
    2993           0 :                         auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    2994           0 :                         tomorrowTs.SkyTemp = tomorrowTs.OutDryBulbTemp - tmp(ts, hour);
    2995             :                     }
    2996             :                 }
    2997           0 :             } break;
    2998           0 :             case SkyTempModel::DewPointDelta: {
    2999           0 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3000           0 :                 ScheduleManager::GetScheduleValuesForDay(state,
    3001           0 :                                                          state.dataWeather->WPSkyTemperature(thisEnviron.WP_Type1).SchedulePtr,
    3002             :                                                          tmp,
    3003           0 :                                                          state.dataWeather->TomorrowVariables.DayOfYear_Schedule,
    3004           0 :                                                          state.dataWeather->CurDayOfWeek);
    3005           0 :                 ForAllHrTs(state, [&state, &tmp](int iHr, int iTS) {
    3006           0 :                     auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3007           0 :                     tomorrowTs.SkyTemp = tomorrowTs.OutDewPointTemp - tmp(iTS, iHr);
    3008           0 :                 });
    3009           0 :             } break;
    3010           0 :             default:
    3011           0 :                 break;
    3012             :             }
    3013             :         }
    3014        3853 :     }
    3015             : 
    3016      416784 :     Real64 interpolateWindDirection(Real64 const prevHrWindDir, Real64 const curHrWindDir, Real64 const curHrWeight)
    3017             :     {
    3018             :         // adapted from http://stackoverflow.com/questions/2708476/rotation-interpolation
    3019      416784 :         Real64 curAng = curHrWindDir;
    3020      416784 :         Real64 prevAng = prevHrWindDir;
    3021      416784 :         Real64 diff = std::abs(curAng - prevAng);
    3022      416784 :         if (diff > 180.) {
    3023       33790 :             if (curAng > prevAng) {
    3024       14838 :                 prevAng += 360.;
    3025             :             } else {
    3026       18952 :                 curAng += 360.;
    3027             :             }
    3028             :         }
    3029      416784 :         Real64 interpAng = prevAng + (curAng - prevAng) * curHrWeight;
    3030      416784 :         return (fmod(interpAng, 360.)); // fmod is float modulus function
    3031             :     }
    3032             : 
    3033      778800 :     Real64 CalcSkyEmissivity(
    3034             :         EnergyPlusData &state, SkyTempModel const ESkyCalcType, Real64 const OSky, Real64 const DryBulb, Real64 const DewPoint, Real64 const RelHum)
    3035             :     {
    3036             :         // Calculate Sky Emissivity
    3037             :         // References:
    3038             :         // M. Li, Y. Jiang and C. F. M. Coimbra,
    3039             :         // "On the determination of atmospheric longwave irradiance under all-sky conditions,"
    3040             :         // Solar Energy 144, 2017, pp. 40–48,
    3041             :         // G. Clark and C. Allen, "The Estimation of Atmospheric Radiation for Clear and
    3042             :         // Cloudy Skies," Proc. 2nd National Passive Solar Conference (AS/ISES), 1978, pp. 675-678.
    3043             : 
    3044             :         Real64 ESky;
    3045             : 
    3046      778800 :         if (ESkyCalcType == SkyTempModel::Brunt) {
    3047           0 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3048           0 :             ESky = 0.618 + 0.056 * pow(PartialPress, 0.5);
    3049      778800 :         } else if (ESkyCalcType == SkyTempModel::Idso) {
    3050           0 :             double const PartialPress = RelHum * Psychrometrics::PsyPsatFnTemp(state, DryBulb) * 0.01;
    3051           0 :             ESky = 0.685 + 0.000032 * PartialPress * exp(1699 / (DryBulb + Constant::Kelvin));
    3052      778800 :         } else if (ESkyCalcType == SkyTempModel::BerdahlMartin) {
    3053           0 :             double const TDewC = min(DryBulb, DewPoint);
    3054           0 :             ESky = 0.758 + 0.521 * (TDewC / 100) + 0.625 * pow_2(TDewC / 100);
    3055             :         } else {
    3056      778800 :             ESky = 0.787 + 0.764 * std::log((min(DryBulb, DewPoint) + Constant::Kelvin) / Constant::Kelvin);
    3057             :         }
    3058      778800 :         return ESky * (1.0 + 0.0224 * OSky - 0.0035 * pow_2(OSky) + 0.00028 * pow_3(OSky));
    3059             :     }
    3060             : 
    3061        1226 :     void SetDayOfWeekInitialValues(int const EnvironDayOfWeek, // Starting Day of Week for the (Weather) RunPeriod (User Input)
    3062             :                                    int &currentDayOfWeek       // Current Day of Week
    3063             :     )
    3064             :     {
    3065             : 
    3066             :         // SUBROUTINE INFORMATION:
    3067             :         //       AUTHOR         Linda Lawrie
    3068             :         //       DATE WRITTEN   March 2012
    3069             : 
    3070             :         // PURPOSE OF THIS SUBROUTINE:
    3071             :         // Set of begin day of week for an environment.  Similar sets but slightly different
    3072             :         // conditions.  Improve code readability by having three routine calls instead of three
    3073             :         // IF blocks.
    3074             : 
    3075        1226 :         if (EnvironDayOfWeek != 0) {
    3076        1226 :             if (EnvironDayOfWeek <= 7) {
    3077        1204 :                 currentDayOfWeek = EnvironDayOfWeek - 1;
    3078             :             } else {
    3079          22 :                 currentDayOfWeek = EnvironDayOfWeek;
    3080             :             }
    3081             :         }
    3082        1226 :     }
    3083             : 
    3084           0 :     void ErrorInterpretWeatherDataLine(EnergyPlusData &state,
    3085             :                                        int const WYear,
    3086             :                                        int const WMonth,
    3087             :                                        int const WDay,
    3088             :                                        int const WHour,
    3089             :                                        int const WMinute,
    3090             :                                        std::string_view SaveLine,
    3091             :                                        std::string_view Line)
    3092             :     {
    3093           0 :         ShowSevereError(state, fmt::format("Invalid Weather Line at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3094           0 :         ShowContinueError(state, fmt::format("Full Data Line={}", SaveLine));
    3095           0 :         ShowContinueError(state, fmt::format("Remainder of line={}", Line));
    3096           0 :         ShowFatalError(state, "Error in Reading Weather Data");
    3097           0 :     }
    3098             : 
    3099      266075 :     void InterpretWeatherDataLine(EnergyPlusData &state,
    3100             :                                   std::string_view Line,
    3101             :                                   bool &ErrorFound, // True if an error is found, false otherwise
    3102             :                                   int &WYear,
    3103             :                                   int &WMonth,
    3104             :                                   int &WDay,
    3105             :                                   int &WHour,
    3106             :                                   int &WMinute,
    3107             :                                   Real64 &DryBulb,
    3108             :                                   Real64 &DewPoint,
    3109             :                                   Real64 &RelHum,
    3110             :                                   Real64 &AtmPress,
    3111             :                                   Real64 &ETHoriz,
    3112             :                                   Real64 &ETDirect,
    3113             :                                   Real64 &IRHoriz,
    3114             :                                   Real64 &GLBHoriz,
    3115             :                                   Real64 &DirectRad,
    3116             :                                   Real64 &DiffuseRad,
    3117             :                                   Real64 &GLBHorizIllum,
    3118             :                                   Real64 &DirectNrmIllum,
    3119             :                                   Real64 &DiffuseHorizIllum,
    3120             :                                   Real64 &ZenLum,
    3121             :                                   Real64 &WindDir,
    3122             :                                   Real64 &WindSpeed,
    3123             :                                   Real64 &TotalSkyCover,
    3124             :                                   Real64 &OpaqueSkyCover,
    3125             :                                   Real64 &Visibility,
    3126             :                                   Real64 &CeilHeight,
    3127             :                                   int &WObs,              // PresWeathObs
    3128             :                                   Array1D_int &WCodesArr, // PresWeathConds
    3129             :                                   Real64 &PrecipWater,
    3130             :                                   Real64 &AerosolOptDepth,
    3131             :                                   Real64 &SnowDepth,
    3132             :                                   Real64 &DaysSinceLastSnow,
    3133             :                                   Real64 &Albedo,
    3134             :                                   Real64 &LiquidPrecip)
    3135             :     {
    3136             : 
    3137             :         // SUBROUTINE INFORMATION:
    3138             :         //       AUTHOR         Linda Lawrie
    3139             :         //       DATE WRITTEN   April 2001
    3140             : 
    3141             :         // PURPOSE OF THIS SUBROUTINE:
    3142             :         // This subroutine interprets the EPW weather data line because comma delimited fields
    3143             :         // may cause problems with some compilers.  (Particularly character variables in
    3144             :         // comma delimited lines.
    3145             : 
    3146             :         // METHODOLOGY EMPLOYED:
    3147             :         // Field by field interpretation, eliminating the "data source field" which is also
    3148             :         // likely to contain blanks.  Note that the "Weatherconditions" must be a 9 character
    3149             :         // alpha field with no intervening blanks.
    3150             : 
    3151      266075 :         EP_SIZE_CHECK(WCodesArr, 9); // NOLINT(misc-static-assert)
    3152             : 
    3153             :         static constexpr std::string_view ValidDigits("0123456789");
    3154             : 
    3155      266075 :         std::string_view::size_type pos = 0;
    3156      266075 :         std::string_view current_line = Line;
    3157             : 
    3158      266075 :         ErrorFound = false;
    3159             : 
    3160             :         // Do the first five.  (To get to the DataSource field)
    3161             :         {
    3162      266075 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 5); // Returns the position **after** the nth occurrence of ','
    3163      266075 :             const bool succeeded = readList(current_line.substr(pos, (nth_pos - 1) - pos), WYear, WMonth, WDay, WHour, WMinute);
    3164      266075 :             if (!succeeded) {
    3165           0 :                 ShowSevereError(state, "Invalid Date info in Weather Line");
    3166           0 :                 ShowContinueError(state, fmt::format("Entire Data Line={}", Line));
    3167           0 :                 ShowFatalError(state, "Error in Reading Weather Data");
    3168             :             }
    3169             :         }
    3170             : 
    3171      266075 :         bool DateInError = false;
    3172      266075 :         if (WMonth >= 1 && WMonth <= 12) {
    3173             :             // Month number is valid
    3174      266075 :             if (WMonth != 2) {
    3175      240571 :                 if (WDay > state.dataWeather->EndDayOfMonth(WMonth)) {
    3176           0 :                     DateInError = true;
    3177             :                 }
    3178       25504 :             } else if (WDay > state.dataWeather->EndDayOfMonth(WMonth) + 1) { // Whether actually used is determined by calling routine.
    3179           0 :                 DateInError = true;
    3180             :             }
    3181             :         } else {
    3182           0 :             DateInError = true;
    3183             :         }
    3184             : 
    3185      266075 :         if (DateInError) {
    3186           0 :             ShowSevereError(state, format("Reading Weather Data Line, Invalid Date, Year={}, Month={}, Day={}", WYear, WMonth, WDay));
    3187           0 :             ShowFatalError(state, "Program terminates due to previous condition.");
    3188             :         }
    3189             : 
    3190             :         // index, unlike nth_occurrence returns the position of the search char, not the position after it
    3191      266075 :         pos = index(Line, ','); // WYear
    3192      266075 :         if (pos == std::string::npos) {
    3193           0 :             ShowSevereError(
    3194           0 :                 state, format("Invalid Weather Line (no commas) at date={:4}/{:2}/{:2} Hour#={:2} Min#={:2}", WYear, WMonth, WDay, WHour, WMinute));
    3195           0 :             ShowContinueError(state, fmt::format("Full Data Line={}", Line));
    3196           0 :             ShowFatalError(state, "Error in Reading Weather Data");
    3197             :         }
    3198      266075 :         current_line.remove_prefix(nth_occurrence(Line, ',', 6)); // remove WYear,WMonth,WDay,WHour,WMinute,Data Source/Integrity
    3199             : 
    3200             :         // Now read more numerics with List Directed I/O (note there is another "character" field lurking)
    3201             :         Real64 RField21;
    3202             :         {
    3203      266075 :             std::string_view::size_type nth_pos = nth_occurrence(current_line, ',', 21);
    3204             : 
    3205      266075 :             const bool succeeded = readList(current_line.substr(0, nth_pos - 1),
    3206             :                                             DryBulb,
    3207             :                                             DewPoint,
    3208             :                                             RelHum,
    3209             :                                             AtmPress,
    3210             :                                             ETHoriz,
    3211             :                                             ETDirect,
    3212             :                                             IRHoriz,
    3213             :                                             GLBHoriz,
    3214             :                                             DirectRad,
    3215             :                                             DiffuseRad,
    3216             :                                             GLBHorizIllum,
    3217             :                                             DirectNrmIllum,
    3218             :                                             DiffuseHorizIllum,
    3219             :                                             ZenLum,
    3220             :                                             WindDir,
    3221             :                                             WindSpeed,
    3222             :                                             TotalSkyCover,
    3223             :                                             OpaqueSkyCover,
    3224             :                                             Visibility,
    3225             :                                             CeilHeight,
    3226             :                                             RField21);
    3227             : 
    3228      266075 :             if (!succeeded) ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3229      266075 :             current_line.remove_prefix(nth_pos);
    3230             :         }
    3231      266075 :         pos = index(current_line, ',');
    3232      266075 :         std::string PresWeathCodes;
    3233      266075 :         if (pos != std::string::npos && pos != 0) {
    3234      266075 :             PresWeathCodes = current_line.substr(0, pos);
    3235             :         } else {
    3236           0 :             PresWeathCodes = "999999999";
    3237             :         }
    3238      266075 :         current_line.remove_prefix(pos + 1);
    3239             : 
    3240      266075 :         auto readNextNumber = // (AUTO_OK_LAMBDA)
    3241     6385500 :             [reachedEndOfCommands = false, &state, &WYear, &WMonth, &WDay, &WHour, &WMinute, &Line, &current_line]() mutable -> Real64 {
    3242     1596450 :             if (reachedEndOfCommands) {
    3243         100 :                 return 999.0;
    3244             :             }
    3245             :             Real64 target;
    3246     1596350 :             std::string_view::size_type pos = index(current_line, ',');
    3247             :             // We found a comma
    3248     1596350 :             if (pos != std::string::npos) {
    3249             :                 // Content is not empty
    3250     1596325 :                 if (pos != 0) {
    3251     1596325 :                     bool error = false;
    3252     1596325 :                     target = Util::ProcessNumber(current_line.substr(0, pos), error);
    3253     1596325 :                     if (error) {
    3254           0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3255             :                     }
    3256             :                 } else {
    3257           0 :                     target = 999.0;
    3258             :                 }
    3259     1596325 :                 current_line.remove_prefix(pos + 1);
    3260             :             } else {
    3261             :                 // Couldn't find next comma, but we need to process the potential current number
    3262          25 :                 reachedEndOfCommands = true;
    3263          25 :                 if (current_line.empty()) {
    3264           0 :                     target = 999.0;
    3265             :                 } else {
    3266          25 :                     bool error = false;
    3267          25 :                     target = Util::ProcessNumber(current_line, error);
    3268          25 :                     if (error) {
    3269           0 :                         ErrorInterpretWeatherDataLine(state, WYear, WMonth, WDay, WHour, WMinute, Line, current_line);
    3270             :                     }
    3271             :                 }
    3272             :             }
    3273     1596350 :             return target;
    3274      266075 :         };
    3275             : 
    3276      266075 :         PrecipWater = readNextNumber();
    3277      266075 :         AerosolOptDepth = readNextNumber();
    3278      266075 :         SnowDepth = readNextNumber();
    3279      266075 :         DaysSinceLastSnow = readNextNumber();
    3280      266075 :         Albedo = readNextNumber();
    3281      266075 :         LiquidPrecip = readNextNumber();
    3282             : 
    3283      266075 :         WObs = nint(RField21);
    3284      266075 :         if (WObs == 0) { // Obs Indicator indicates Weather Codes valid
    3285             :             // Check for miscellaneous characters
    3286         350 :             pos = index(PresWeathCodes, '\'');
    3287         350 :             while (pos != std::string::npos) {
    3288           0 :                 PresWeathCodes[pos] = ' ';
    3289           0 :                 pos = index(PresWeathCodes, '\'');
    3290             :             }
    3291         350 :             pos = index(PresWeathCodes, '"');
    3292         350 :             while (pos != std::string::npos) {
    3293           0 :                 PresWeathCodes[pos] = ' ';
    3294           0 :                 pos = index(PresWeathCodes, '"');
    3295             :             }
    3296         350 :             strip(PresWeathCodes);
    3297         350 :             if (len(PresWeathCodes) == 9) {
    3298        3500 :                 for (pos = 0; pos < 9; ++pos) {
    3299        3150 :                     if (!has(ValidDigits, PresWeathCodes[pos])) PresWeathCodes[pos] = '9';
    3300             :                 }
    3301             : 
    3302             :                 // we are trying to read a string of 9 integers with no spaces, each
    3303             :                 // into its own integer, like:
    3304             :                 // "123456789"
    3305             :                 // becomes
    3306             :                 // std::vector<int>{1,2,3,4,5,6,7,8,9};
    3307         350 :                 std::stringstream reader = stringReader(PresWeathCodes);
    3308        3500 :                 for (auto &value : WCodesArr) {
    3309        3150 :                     char c[2] = {0, 0};   // a string of 2 characters, init both to 0
    3310        3150 :                     reader >> c[0];       // read next char into the first byte
    3311        3150 :                     value = std::atoi(c); // convert this short string into the appropriate int to read
    3312             :                 }
    3313         350 :             } else {
    3314           0 :                 ++state.dataWeather->wvarsMissedCounts.WeathCodes;
    3315           0 :                 WCodesArr = 9;
    3316             :             }
    3317             :         } else {
    3318      265725 :             WCodesArr = 9;
    3319             :         }
    3320      266075 :     }
    3321             : 
    3322        5932 :     void SetUpDesignDay(EnergyPlusData &state, int const EnvrnNum) // Environment number passed into the routine
    3323             :     {
    3324             : 
    3325             :         // SUBROUTINE INFORMATION:
    3326             :         //       AUTHOR         Linda Lawrie
    3327             :         //       DATE WRITTEN   February 1977
    3328             :         //       MODIFIED       June 1997 (RKS); May 2013 (LKL) add temperature profile for drybulb.
    3329             :         //       RE-ENGINEERED  August 2003;LKL -- to generate timestep weather for design days.
    3330             : 
    3331             :         // PURPOSE OF THIS SUBROUTINE:
    3332             :         // This purpose of this subroutine is to convert the user supplied input
    3333             :         // values for the design day parameters into an entire weather day
    3334             :         // record.  This now bypasses any file I/O by keeping all of the
    3335             :         // weather day record information in the local module level derived type
    3336             :         // called DesignDay.
    3337             : 
    3338        5932 :         constexpr Real64 GlobalSolarConstant = 1367.0;
    3339        5932 :         constexpr Real64 ZHGlobalSolarConstant = 1355.0;
    3340             : 
    3341        5932 :         Real64 constexpr ZhangHuang_C0 = 0.5598;   // 37.6865d0
    3342        5932 :         Real64 constexpr ZhangHuang_C1 = 0.4982;   // 13.9263d0
    3343        5932 :         Real64 constexpr ZhangHuang_C2 = -0.6762;  // -20.2354d0
    3344        5932 :         Real64 constexpr ZhangHuang_C3 = 0.02842;  // 0.9695d0
    3345        5932 :         Real64 constexpr ZhangHuang_C4 = -0.00317; // -0.2046d0
    3346        5932 :         Real64 constexpr ZhangHuang_C5 = 0.014;    // -0.0980d0
    3347        5932 :         Real64 constexpr ZhangHuang_D = -17.853;   // -10.8568d0
    3348        5932 :         Real64 constexpr ZhangHuang_K = 0.843;     // 49.3112d0
    3349             :         static constexpr std::string_view RoutineNamePsyWFnTdbTwbPb("SetUpDesignDay:PsyWFnTdbTwbPb");
    3350             :         static constexpr std::string_view RoutineNamePsyWFnTdpPb("SetUpDesignDay:PsyWFnTdpPb");
    3351             :         static constexpr std::string_view RoutineNamePsyWFnTdbH("SetUpDesignDay:PsyWFnTdbH");
    3352             :         static constexpr std::string_view WeatherManager("WeatherManager");
    3353             :         static constexpr std::string_view RoutineNameLong("WeatherManager.cc subroutine SetUpDesignDay");
    3354             : 
    3355        5932 :         std::string StringOut;
    3356             :         //     For reporting purposes, set year to current system year
    3357             : 
    3358             :         struct HourlyWeatherData
    3359             :         {
    3360             :             // Members
    3361             :             Array1D<Real64> BeamSolarRad = Array1D<Real64>(Constant::HoursInDay, 0.0); // Hourly direct normal solar irradiance
    3362             :             Array1D<Real64> DifSolarRad = Array1D<Real64>(Constant::HoursInDay, 0.0);  // Hourly sky diffuse horizontal solar irradiance
    3363             :         };
    3364             : 
    3365             :         // Object Data
    3366        5932 :         HourlyWeatherData Wthr;
    3367             : 
    3368        5932 :         auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    3369             : 
    3370        5932 :         bool SaveWarmupFlag = state.dataGlobal->WarmupFlag;
    3371        5932 :         state.dataGlobal->WarmupFlag = true;
    3372             : 
    3373        5932 :         Array1D_int Date0(8);
    3374        5932 :         date_and_time(_, _, _, Date0);
    3375        5932 :         int CurrentYear = Date0(1);
    3376             : 
    3377        5932 :         if (state.dataGlobal->BeginSimFlag) {
    3378         796 :             state.dataWeather->PrintDDHeader = true;
    3379             :         }
    3380             : 
    3381        5932 :         auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    3382        5932 :         auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    3383        5932 :         designDay.Year = CurrentYear; // f90 date_and_time implemented. full 4 digit year !+ 1900
    3384        5932 :         designDay.Month = desDayInput.Month;
    3385        5932 :         designDay.DayOfMonth = desDayInput.DayOfMonth;
    3386        5932 :         designDay.DayOfYear = General::OrdinalDay(designDay.Month, designDay.DayOfMonth, 0);
    3387             :         static constexpr std::string_view MnDyFmt("{:02}/{:02}");
    3388        5932 :         state.dataEnvrn->CurMnDy = format(MnDyFmt, desDayInput.Month, desDayInput.DayOfMonth);
    3389             :         // EnvironmentName = DesDayInput( EnvrnNum ).Title;
    3390        5932 :         state.dataEnvrn->RunPeriodEnvironment = false;
    3391             :         // Following builds Environment start/end for ASHRAE 55 warnings
    3392        5932 :         state.dataEnvrn->EnvironmentStartEnd = state.dataEnvrn->CurMnDy + " - " + state.dataEnvrn->CurMnDy;
    3393             : 
    3394             :         // Check that barometric pressure is within range
    3395        5932 :         if (desDayInput.PressureEntered) {
    3396        5908 :             if (std::abs((desDayInput.PressBarom - state.dataEnvrn->StdBaroPress) / state.dataEnvrn->StdBaroPress) > 0.1) { // 10% off
    3397         108 :                 ShowWarningError(state,
    3398         108 :                                  format("SetUpDesignDay: Entered DesignDay Barometric Pressure={:.0R} differs by more than 10% from Standard "
    3399             :                                         "Barometric Pressure={:.0R}.",
    3400          54 :                                         desDayInput.PressBarom,
    3401          54 :                                         state.dataEnvrn->StdBaroPress));
    3402         108 :                 ShowContinueError(
    3403             :                     state,
    3404         108 :                     format("...occurs in DesignDay={}, Standard Pressure (based on elevation) will be used.", state.dataEnvrn->EnvironmentName));
    3405          54 :                 desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3406             :             }
    3407             :         } else {
    3408          24 :             desDayInput.PressBarom = state.dataEnvrn->StdBaroPress;
    3409             :         }
    3410             : 
    3411             :         // verify that design WB or DP <= design DB
    3412        5932 :         if (desDayInput.HumIndType == DesDayHumIndType::DewPoint && desDayInput.DewPointNeedsSet) {
    3413             :             // dew-point
    3414           0 :             Real64 testval = Psychrometrics::PsyWFnTdbRhPb(state, desDayInput.MaxDryBulb, 1.0, desDayInput.PressBarom);
    3415           0 :             desDayInput.HumIndValue = Psychrometrics::PsyTdpFnWPb(state, testval, desDayInput.PressBarom);
    3416             :         }
    3417             : 
    3418             :         // Day of week defaults to Monday, if day type specified, then that is used.
    3419        5932 :         designDay.DayOfWeek = 2;
    3420        5932 :         if (desDayInput.DayType <= 7) designDay.DayOfWeek = desDayInput.DayType;
    3421             : 
    3422             :         // set Holiday as indicated by user input
    3423        5932 :         designDay.HolidayIndex = 0;
    3424        5932 :         if (desDayInput.DayType > 7) designDay.HolidayIndex = desDayInput.DayType;
    3425             : 
    3426        5932 :         designDay.DaylightSavingIndex = desDayInput.DSTIndicator;
    3427             : 
    3428             :         //  Set up Solar parameters for day
    3429             :         Real64 A;    // Apparent solar irradiation at air mass = 0
    3430             :         Real64 B;    // Atmospheric extinction coefficient
    3431             :         Real64 C;    // ASHRAE diffuse radiation factor
    3432             :         Real64 AVSC; // Annual variation in the solar constant
    3433        5932 :         CalculateDailySolarCoeffs(
    3434        5932 :             state, designDay.DayOfYear, A, B, C, AVSC, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle);
    3435             : 
    3436        5932 :         if (state.dataWeather->PrintDDHeader && state.dataReportFlag->DoWeatherInitReporting) {
    3437             :             static constexpr std::string_view EnvDDHdFormat(
    3438             :                 "! <Environment:Design Day Data>, Max Dry-Bulb Temp {C}, Temp Range {dC}, Temp Range Ind Type, "
    3439             :                 "Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units, Pressure {Pa}, Wind Direction {deg CW from N}, Wind "
    3440             :                 "Speed {m/s}, Clearness, Rain, Snow");
    3441         789 :             print(state.files.eio, "{}\n", EnvDDHdFormat);
    3442             :             static constexpr std::string_view DDayMiscHdFormat(
    3443             :                 "! <Environment:Design Day Misc>,DayOfYear,ASHRAE A Coeff,ASHRAE B Coeff,ASHRAE C Coeff,Solar "
    3444             :                 "Constant-Annual Variation,Eq of Time {minutes}, Solar Declination Angle {deg}, Solar Model");
    3445         789 :             print(state.files.eio, "{}\n", DDayMiscHdFormat);
    3446         789 :             state.dataWeather->PrintDDHeader = false;
    3447             :         }
    3448        5932 :         if (state.dataReportFlag->DoWeatherInitReporting) {
    3449        1766 :             std::string_view const AlpUseRain = (desDayInput.RainInd == 1) ? "Yes" : "No";
    3450        1766 :             std::string_view const AlpUseSnow = (desDayInput.SnowInd == 1) ? "Yes" : "No";
    3451        1766 :             print(state.files.eio, "Environment:Design Day Data,");
    3452        1766 :             print(state.files.eio, "{:.2R},", desDayInput.MaxDryBulb);
    3453        1766 :             print(state.files.eio, "{:.2R},", desDayInput.DailyDBRange);
    3454             : 
    3455             :             static constexpr std::array<std::string_view, (int)DesDayDryBulbRangeType::Num> DesDayDryBulbRangeTypeStrings = {
    3456             :                 "DefaultMultipliers,", "MultiplierSchedule,", "DifferenceSchedule,", "TemperatureProfile,"};
    3457             : 
    3458        1766 :             print(state.files.eio, "{}", DesDayDryBulbRangeTypeStrings[(int)desDayInput.dryBulbRangeType]);
    3459             : 
    3460             :             static constexpr std::array<std::string_view, (int)DesDayHumIndType::Num> DesDayHumIndTypeStrings = {
    3461             :                 "Wetbulb,{:.2R},{{C}},",
    3462             :                 "Dewpoint,{:.2R},{{C}},",
    3463             :                 "Enthalpy,{:.2R},{{J/kgDryAir}},",
    3464             :                 "HumidityRatio,{:.4R},{{kgWater/kgDryAir}},",
    3465             :                 "Schedule,<schedule values from 0.0 to 100.0>,{{percent}},",
    3466             :                 "WetBulbProfileDefaultMultipliers,{:.2R},{{C}},",
    3467             :                 "WetBulbProfileDifferenceSchedule,{:.2R},{{C}},",
    3468             :                 "WetBulbProfileMultiplierSchedule,{:.2R},{{C}},"};
    3469             : 
    3470             :             // Hum Ind Type, Hum Ind Value at Max Temp, Hum Ind Units
    3471        1766 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch) {
    3472           3 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType]);
    3473        1763 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    3474          12 :                 print(state.files.eio,
    3475          12 :                       DesDayHumIndTypeStrings[(int)desDayInput.HumIndType],
    3476          12 :                       state.dataWeather->DesDayInput(state.dataWeather->Envrn).HumIndValue);
    3477             :             } else {
    3478        1751 :                 print(state.files.eio, DesDayHumIndTypeStrings[(int)desDayInput.HumIndType], desDayInput.HumIndValue);
    3479             :             }
    3480             : 
    3481        1766 :             print(state.files.eio, "{:.0R},", desDayInput.PressBarom);
    3482        1766 :             print(state.files.eio, "{:.0R},", desDayInput.WindDir);
    3483        1766 :             print(state.files.eio, "{:.1R},", desDayInput.WindSpeed);
    3484        1766 :             print(state.files.eio, "{:.2R},", desDayInput.SkyClear);
    3485             : 
    3486        1766 :             print(state.files.eio, "{},{}\n", AlpUseRain, AlpUseSnow);
    3487             : 
    3488             :             static constexpr std::string_view DDayMiscFormat("Environment:Design Day Misc,{:3},");
    3489        1766 :             print(state.files.eio, DDayMiscFormat, designDay.DayOfYear);
    3490        1766 :             print(state.files.eio, "{:.1R},", A);
    3491        1766 :             print(state.files.eio, "{:.4R},", B);
    3492        1766 :             print(state.files.eio, "{:.4R},", C);
    3493        1766 :             print(state.files.eio, "{:.1R},", AVSC);
    3494        1766 :             print(state.files.eio, "{:.2R},", designDay.EquationOfTime * 60.0);
    3495        1766 :             print(state.files.eio, "{:.1R},", std::asin(designDay.SinSolarDeclinAngle) / Constant::DegToRadians);
    3496             : 
    3497             :             // Why have a different string for "Schedule" here than the one used for input? Really, why?
    3498             :             static constexpr std::array<std::string_view, (int)DesDaySolarModel::Num> DesDaySolarModelStrings = {
    3499             :                 "ASHRAEClearSky", "ZhangHuang", "User supplied beam/diffuse from schedules", "ASHRAETau", "ASHRAETau2017"};
    3500             : 
    3501        1766 :             print(state.files.eio, "{}\n", DesDaySolarModelStrings[(int)desDayInput.solarModel]);
    3502             :         }
    3503             : 
    3504             :         // Must set up weather values for Design Day.  User can specify the "humidity indicator" as
    3505             :         // Wetbulb, DewPoint or input the relative humidity schedule.  For both wetbulb and dewpoint indicators, the
    3506             :         // humidity for the day will be constant, using the drybulb (max) and humidity indicator temperature to
    3507             :         // set the values.  For the scheduled values, these are already set in the DDxxx array.
    3508             : 
    3509        5932 :         state.dataGlobal->CurrentTime = 25.0;
    3510             :         Real64 HumidityRatio; // Humidity Ratio -- when constant for day
    3511             :         bool ConstantHumidityRatio;
    3512             : 
    3513        5932 :         switch (desDayInput.HumIndType) {
    3514        5856 :         case DesDayHumIndType::WetBulb: {
    3515        5856 :             HumidityRatio = Psychrometrics::PsyWFnTdbTwbPb(
    3516             :                 state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdbTwbPb);
    3517        5856 :             ConstantHumidityRatio = true;
    3518        5856 :         } break;
    3519          25 :         case DesDayHumIndType::DewPoint: {
    3520          25 :             HumidityRatio = Psychrometrics::PsyWFnTdpPb(state, desDayInput.HumIndValue, desDayInput.PressBarom, RoutineNamePsyWFnTdpPb);
    3521          25 :             ConstantHumidityRatio = true;
    3522          25 :         } break;
    3523           0 :         case DesDayHumIndType::HumRatio: {
    3524           0 :             HumidityRatio = desDayInput.HumIndValue;
    3525           0 :             ConstantHumidityRatio = true;
    3526           0 :         } break;
    3527          15 :         case DesDayHumIndType::Enthalpy: {
    3528             :             // HumIndValue is already in J/kg, so no conversions needed
    3529          15 :             HumidityRatio = Psychrometrics::PsyWFnTdbH(state, desDayInput.MaxDryBulb, desDayInput.HumIndValue, RoutineNamePsyWFnTdbH);
    3530          15 :             ConstantHumidityRatio = true;
    3531          15 :         } break;
    3532           6 :         case DesDayHumIndType::RelHumSch: {
    3533             :             // nothing to do -- DDHumIndModifier already contains the scheduled Relative Humidity
    3534           6 :             ConstantHumidityRatio = false;
    3535           6 :             ForAllHrTs(state, [&state, EnvrnNum](int iHr, int iTS) {
    3536         576 :                 state.dataWeather->wvarsHrTsTomorrow(iTS, iHr).OutRelHum = state.dataWeather->desDayMods(EnvrnNum)(iTS, iHr).OutRelHum;
    3537         576 :             });
    3538           6 :         } break;
    3539          30 :         case DesDayHumIndType::WBProfDef:
    3540             :         case DesDayHumIndType::WBProfDif:
    3541             :         case DesDayHumIndType::WBProfMul: {
    3542          30 :             ConstantHumidityRatio = false;
    3543          30 :         } break;
    3544           0 :         default: {
    3545           0 :             ShowSevereError(state, "SetUpDesignDay: Invalid Humidity Indicator type");
    3546           0 :             ShowContinueError(state, format("Occurred in Design Day={}", desDayInput.Title));
    3547           0 :         } break;
    3548             :         } // switch
    3549             : 
    3550             :         int OSky; // Opaque Sky Cover (tenths)
    3551        5932 :         if (desDayInput.RainInd != 0) {
    3552           0 :             OSky = 10;
    3553           0 :             ForAllHrTs(state, [&state](int iHr, int iTS) {
    3554           0 :                 auto &ts = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3555           0 :                 ts.IsRain = true;
    3556           0 :                 ts.LiquidPrecip = 3.0;
    3557           0 :             });
    3558             :         } else {
    3559        5932 :             OSky = 0;
    3560        5932 :             ForAllHrTs(state, [&state](int iHr, int iTS) {
    3561      778800 :                 auto &ts = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3562      778800 :                 ts.IsRain = false;
    3563      778800 :                 ts.LiquidPrecip = 0.0;
    3564      778800 :             });
    3565             :         }
    3566             : 
    3567             :         Real64 GndReflet; // Ground Reflectivity
    3568        5932 :         if (desDayInput.SnowInd == 0) {
    3569        5932 :             GndReflet = 0.2;
    3570        5932 :             ForAllHrTs(state, [&state](int iHr, int iTS) {
    3571      778800 :                 auto &ts = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3572      778800 :                 ts.IsSnow = false;
    3573      778800 :             });
    3574             :         } else { // Snow
    3575           0 :             GndReflet = 0.7;
    3576           0 :             ForAllHrTs(state, [&state](int iHr, int iTS) {
    3577           0 :                 auto &ts = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3578           0 :                 ts.IsSnow = true;
    3579           0 :             });
    3580             :         }
    3581             : 
    3582             :         // Some values are constant
    3583             : 
    3584        5932 :         ForAllHrTs(state, [&state, &desDayInput](int iHr, int iTS) {
    3585      778800 :             auto &ts = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3586      778800 :             ts.OutBaroPress = desDayInput.PressBarom;
    3587      778800 :             ts.WindSpeed = desDayInput.WindSpeed;
    3588      778800 :             ts.WindDir = desDayInput.WindDir;
    3589      778800 :             ts.Albedo = 0.0;
    3590      778800 :         });
    3591             : 
    3592             :         // resolve daily ranges
    3593             :         Real64 DBRange; // working copy of dry-bulb daily range, C (or 1 if input is difference)
    3594        5932 :         if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    3595           4 :             DBRange = 1.0; // use unscaled multiplier values if difference
    3596        5928 :         } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    3597           2 :             DBRange = 0.0;
    3598             :         } else {
    3599        5926 :             DBRange = desDayInput.DailyDBRange;
    3600             :         }
    3601             :         Real64 WBRange; // working copy of wet-bulb daily range. C (or 1 if input is difference)
    3602        5932 :         if (desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    3603           2 :             WBRange = 1.0; // use unscaled multiplier values if difference
    3604             :         } else {
    3605        5930 :             WBRange = desDayInput.DailyWBRange;
    3606             :         }
    3607             : 
    3608        5932 :         auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3609      148300 :         for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    3610      921168 :             for (int ts = 1; ts <= state.dataGlobal->NumOfTimeStepInHour; ++ts) {
    3611      778800 :                 auto const &desDayModsTS = desDayModsEnvrn(ts, hour);
    3612      778800 :                 auto &tomorrowTs = state.dataWeather->wvarsHrTsTomorrow(ts, hour);
    3613      778800 :                 if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    3614             :                     // dry-bulb profile
    3615      778608 :                     tomorrowTs.OutDryBulbTemp = desDayInput.MaxDryBulb - desDayModsTS.OutDryBulbTemp * DBRange;
    3616             :                 } else { // DesDayInput(EnvrnNum)%DBTempRangeType == DesDayDryBulbRangeType::Profile
    3617         192 :                     tomorrowTs.OutDryBulbTemp = desDayModsTS.OutDryBulbTemp;
    3618             :                 }
    3619             : 
    3620             :                 // wet-bulb - generate from profile, humidity ratio, or dew point
    3621      778800 :                 if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef || desDayInput.HumIndType == DesDayHumIndType::WBProfDif ||
    3622      776304 :                     desDayInput.HumIndType == DesDayHumIndType::WBProfMul) {
    3623        2880 :                     Real64 WetBulb = desDayInput.HumIndValue - desDayModsTS.OutRelHum * WBRange;
    3624        2880 :                     WetBulb = min(WetBulb, tomorrowTs.OutDryBulbTemp); // WB must be <= DB
    3625        2880 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3626        2880 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3627        2880 :                     tomorrowTs.OutRelHum =
    3628        2880 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3629      778800 :                 } else if (ConstantHumidityRatio) {
    3630             :                     //  Need Dew Point Temperature.  Use Relative Humidity to get Humidity Ratio, unless Humidity Ratio is constant
    3631             :                     // BG 9-26-07  moved following inside this IF statment; when HumIndType is 'Schedule' HumidityRatio wasn't being initialized
    3632             :                     Real64 WetBulb =
    3633      775344 :                         Psychrometrics::PsyTwbFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, RoutineNameLong);
    3634             : 
    3635      775344 :                     Real64 OutHumRat = Psychrometrics::PsyWFnTdpPb(state, tomorrowTs.OutDryBulbTemp, desDayInput.PressBarom);
    3636      775344 :                     if (HumidityRatio > OutHumRat) {
    3637      274646 :                         WetBulb = tomorrowTs.OutDryBulbTemp;
    3638             :                     } else {
    3639      500698 :                         OutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, tomorrowTs.OutDryBulbTemp, WetBulb, desDayInput.PressBarom);
    3640             :                     }
    3641      775344 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, OutHumRat, desDayInput.PressBarom);
    3642      775344 :                     tomorrowTs.OutRelHum =
    3643      775344 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, OutHumRat, desDayInput.PressBarom, WeatherManager) * 100.0;
    3644             :                 } else {
    3645             :                     HumidityRatio =
    3646         576 :                         Psychrometrics::PsyWFnTdbRhPb(state, tomorrowTs.OutDryBulbTemp, desDayModsTS.OutRelHum / 100.0, desDayInput.PressBarom);
    3647         576 :                     tomorrowTs.OutRelHum =
    3648         576 :                         Psychrometrics::PsyRhFnTdbWPb(state, tomorrowTs.OutDryBulbTemp, HumidityRatio, desDayInput.PressBarom, WeatherManager) *
    3649             :                         100.0;
    3650             :                     // TomorrowOutRelHum values set earlier
    3651         576 :                     tomorrowTs.OutDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, HumidityRatio, desDayInput.PressBarom);
    3652             :                 }
    3653             : 
    3654      778800 :                 double DryBulb = tomorrowTs.OutDryBulbTemp;
    3655      778800 :                 double RelHum = tomorrowTs.OutRelHum * 0.01;
    3656             :                 Real64 ESky =
    3657      778800 :                     CalcSkyEmissivity(state, envCurr.skyTempModel, OSky, DryBulb, tomorrowTs.OutDewPointTemp, RelHum); // Emissivitity of Sky
    3658      778800 :                 tomorrowTs.HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    3659             : 
    3660      778800 :                 if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    3661      778800 :                     envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    3662             :                     // Design day not scheduled
    3663      778608 :                     tomorrowTs.SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    3664             :                 }
    3665             :                 // Generate solar values for timestep
    3666             :                 //    working results = BeamRad and DiffRad
    3667             :                 //    stored to program globals at end of loop
    3668             :                 Real64 BeamRad;
    3669             :                 Real64 DiffRad;
    3670      778800 :                 if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    3671             :                     // scheduled: set value unconditionally (whether sun up or not)
    3672         576 :                     BeamRad = desDayModsTS.BeamSolarRad;
    3673         576 :                     DiffRad = desDayModsTS.DifSolarRad;
    3674             :                 } else {
    3675             : 
    3676             :                     // calc time = fractional hour of day
    3677             :                     Real64 CurTime;
    3678      778224 :                     if (state.dataGlobal->NumOfTimeStepInHour != 1) {
    3679      776832 :                         CurTime = double(hour - 1) + double(ts) * state.dataWeather->TimeStepFraction;
    3680             :                     } else {
    3681        1392 :                         CurTime = double(hour) + state.dataEnvrn->TS1TimeOffset;
    3682             :                     }
    3683             : 
    3684      778224 :                     Vector3<Real64> SUNCOS; // Sun direction cosines
    3685      778224 :                     CalculateSunDirectionCosines(
    3686             :                         state, CurTime, designDay.EquationOfTime, designDay.SinSolarDeclinAngle, designDay.CosSolarDeclinAngle, SUNCOS);
    3687      778224 :                     Real64 CosZenith = SUNCOS.z; // Cosine of Zenith Angle of Sun
    3688      778224 :                     if (CosZenith < DataEnvironment::SunIsUpValue) {
    3689      386273 :                         BeamRad = 0.0;
    3690      386273 :                         DiffRad = 0.0;
    3691             :                     } else {
    3692      391951 :                         Real64 SinSolarAltitude = SUNCOS.z;
    3693             : 
    3694      391951 :                         switch (desDayInput.solarModel) {
    3695      371513 :                         case DesDaySolarModel::ASHRAE_ClearSky: {
    3696      371513 :                             Real64 Exponent = B / CosZenith;
    3697             :                             Real64 TotHoriz; // Total Radiation on Horizontal Surface
    3698      371513 :                             if (Exponent > 700.0) {
    3699          12 :                                 TotHoriz = 0.0;
    3700             :                             } else {
    3701      371501 :                                 TotHoriz = desDayInput.SkyClear * A * (C + CosZenith) * std::exp(-B / CosZenith);
    3702             :                             }
    3703             :                             // Radiation on an extraterrestial horizontal surface
    3704      371513 :                             Real64 HO = GlobalSolarConstant * AVSC * CosZenith;
    3705      371513 :                             Real64 KT = TotHoriz / HO; // Radiation ratio
    3706      371513 :                             KT = min(KT, 0.75);
    3707      371513 :                             DiffRad = TotHoriz * (1.0045 + KT * (0.04349 + KT * (-3.5227 + 2.6313 * KT)));
    3708      371513 :                             if (desDayInput.SkyClear > 0.70) DiffRad = TotHoriz * C / (C + CosZenith);
    3709      371513 :                             BeamRad = (TotHoriz - DiffRad) / CosZenith;
    3710      371513 :                             DiffRad = max(0.0, DiffRad);
    3711      371513 :                             BeamRad = max(0.0, BeamRad);
    3712             : 
    3713      371513 :                         } break;
    3714       20248 :                         case DesDaySolarModel::ASHRAE_Tau:
    3715             :                         case DesDaySolarModel::ASHRAE_Tau2017: {
    3716       20248 :                             Real64 ETR = GlobalSolarConstant * AVSC; // radiation of an extraterrestrial normal surface, W/m2
    3717             :                             Real64 GloHorzRad;
    3718       20248 :                             ASHRAETauModel(
    3719             :                                 state, desDayInput.solarModel, ETR, CosZenith, desDayInput.TauB, desDayInput.TauD, BeamRad, DiffRad, GloHorzRad);
    3720       20248 :                         } break;
    3721         190 :                         case DesDaySolarModel::Zhang_Huang: {
    3722         190 :                             int Hour3Ago = mod(hour + 20, 24) + 1; // hour 3 hours before
    3723         190 :                             Real64 const TotSkyCover = max(1.0 - desDayInput.SkyClear, 0.0);
    3724         380 :                             Real64 GloHorzRad = (ZHGlobalSolarConstant * SinSolarAltitude *
    3725         190 :                                                      (ZhangHuang_C0 + ZhangHuang_C1 * TotSkyCover + ZhangHuang_C2 * pow_2(TotSkyCover) +
    3726         380 :                                                       ZhangHuang_C3 * (tomorrowTs.OutDryBulbTemp -
    3727         190 :                                                                        state.dataWeather->wvarsHrTsTomorrow(ts, Hour3Ago).OutDryBulbTemp) +
    3728         190 :                                                       ZhangHuang_C4 * tomorrowTs.OutRelHum + ZhangHuang_C5 * tomorrowTs.WindSpeed) +
    3729             :                                                  ZhangHuang_D) /
    3730         190 :                                                 ZhangHuang_K;
    3731         190 :                             GloHorzRad = max(GloHorzRad, 0.0);
    3732         190 :                             Real64 ClearnessIndex_kt = GloHorzRad / (GlobalSolarConstant * SinSolarAltitude);
    3733             :                             //          ClearnessIndex_kt=DesDayInput(EnvrnNum)%SkyClear
    3734         190 :                             Real64 ClearnessIndex_ktc = 0.4268 + 0.1934 * SinSolarAltitude;
    3735             :                             Real64 ClearnessIndex_kds;
    3736         190 :                             if (ClearnessIndex_kt < ClearnessIndex_ktc) {
    3737          96 :                                 ClearnessIndex_kds = (3.996 - 3.862 * SinSolarAltitude + 1.54 * pow_2(SinSolarAltitude)) * pow_3(ClearnessIndex_kt);
    3738             :                             } else {
    3739         188 :                                 ClearnessIndex_kds = ClearnessIndex_kt - (1.107 + 0.03569 * SinSolarAltitude + 1.681 * pow_2(SinSolarAltitude)) *
    3740          94 :                                                                              pow_3(1.0 - ClearnessIndex_kt);
    3741             :                             }
    3742             :                             // Calculate direct normal radiation, W/m2
    3743         190 :                             BeamRad = ZHGlobalSolarConstant * SinSolarAltitude * ClearnessIndex_kds *
    3744         190 :                                       ((1.0 - ClearnessIndex_kt) / (1.0 - ClearnessIndex_kds));
    3745             :                             // Calculation diffuse horizontal radiation, W/m2
    3746         190 :                             DiffRad =
    3747         190 :                                 ZHGlobalSolarConstant * SinSolarAltitude * ((ClearnessIndex_kt - ClearnessIndex_kds) / (1.0 - ClearnessIndex_kds));
    3748             : 
    3749         190 :                         } break;
    3750           0 :                         default:
    3751           0 :                             break;
    3752             :                         }
    3753             :                     }
    3754      778224 :                 }
    3755             : 
    3756             :                 // override result to 0 per environment var (for testing)
    3757      778800 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreBeamRadiation) BeamRad = 0.0;
    3758      778800 :                 if (state.dataEnvrn->IgnoreSolarRadiation || state.dataEnvrn->IgnoreDiffuseRadiation) DiffRad = 0.0;
    3759             : 
    3760      778800 :                 tomorrowTs.BeamSolarRad = BeamRad;
    3761      778800 :                 tomorrowTs.DifSolarRad = DiffRad;
    3762             : 
    3763             :             } // Timestep (TS) Loop
    3764             :         }     // Hour Loop
    3765             : 
    3766             :         // back-fill hour values from timesteps
    3767             :         // hour values = integrated over hour ending at time of hour
    3768             :         // insurance: hourly values not known to be needed
    3769      148300 :         for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    3770      142368 :             int Hour1Ago = mod(hour + 22, Constant::HoursInDay) + 1;
    3771      142368 :             auto const &tomorrowHr = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->NumOfTimeStepInHour, hour);
    3772      142368 :             auto const &tomorrowHr1Ago = state.dataWeather->wvarsHrTsTomorrow(state.dataGlobal->NumOfTimeStepInHour, Hour1Ago);
    3773             : 
    3774      142368 :             Real64 BeamRad = (tomorrowHr1Ago.BeamSolarRad + tomorrowHr.BeamSolarRad) / 2.0;
    3775      142368 :             Real64 DiffRad = (tomorrowHr1Ago.DifSolarRad + tomorrowHr.DifSolarRad) / 2.0;
    3776      142368 :             if (state.dataGlobal->NumOfTimeStepInHour > 1) {
    3777      777408 :                 for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour - 1; ++iTS) {
    3778      636432 :                     BeamRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).BeamSolarRad;
    3779      636432 :                     DiffRad += state.dataWeather->wvarsHrTsTomorrow(iTS, hour).DifSolarRad;
    3780             :                 }
    3781             :             }
    3782      142368 :             Wthr.BeamSolarRad(hour) = BeamRad / state.dataGlobal->NumOfTimeStepInHour;
    3783      142368 :             Wthr.DifSolarRad(hour) = DiffRad / state.dataGlobal->NumOfTimeStepInHour;
    3784             :         }
    3785             : 
    3786        5932 :         if (envCurr.WP_Type1 != 0) {
    3787             : 
    3788           2 :             switch (state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel) {
    3789           2 :             case SkyTempModel::ScheduleValue: {
    3790           4 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3791           2 :                 ScheduleManager::GetSingleDayScheduleValues(state, state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).SchedulePtr, tmp);
    3792           2 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3793           2 :                 ForAllHrTs(state, [&state, &tmp, &desDayModsEnvrn](int iHr, int iTS) {
    3794         192 :                     state.dataWeather->wvarsHrTsTomorrow(iTS, iHr).SkyTemp = desDayModsEnvrn(iTS, iHr).SkyTemp = tmp(iTS, iHr);
    3795         192 :                 });
    3796           2 :             } break;
    3797           0 :             case SkyTempModel::DryBulbDelta: {
    3798           0 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3799           0 :                 ScheduleManager::GetSingleDayScheduleValues(state, state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).SchedulePtr, tmp);
    3800           0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3801           0 :                 ForAllHrTs(state, [&state, &tmp, &desDayModsEnvrn](int iHr, int iTS) {
    3802           0 :                     auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3803           0 :                     desDayModsEnvrn(iTS, iHr).SkyTemp = tmp(iTS, iHr);
    3804           0 :                     tomorrowTS.SkyTemp = tomorrowTS.OutDryBulbTemp - tmp(iTS, iHr);
    3805           0 :                 });
    3806           0 :             } break;
    3807           0 :             case SkyTempModel::DewPointDelta: {
    3808           0 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3809           0 :                 ScheduleManager::GetSingleDayScheduleValues(state, state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).SchedulePtr, tmp);
    3810           0 :                 auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    3811           0 :                 ForAllHrTs(state, [&state, &tmp, &desDayModsEnvrn](int iHr, int iTS) {
    3812           0 :                     auto &tomorrowTS = state.dataWeather->wvarsHrTsTomorrow(iTS, iHr);
    3813           0 :                     desDayModsEnvrn(iTS, iHr).SkyTemp = tmp(iTS, iHr);
    3814           0 :                     tomorrowTS.SkyTemp = tomorrowTS.OutDewPointTemp - tmp(iTS, iHr);
    3815           0 :                 });
    3816           0 :             } break;
    3817           0 :             default: {
    3818           0 :             } break;
    3819             :             } // switch (skyTempModel)
    3820             :         }     // if (envCurr.WP_Type1 != 0)
    3821             : 
    3822        5932 :         state.dataGlobal->WarmupFlag = SaveWarmupFlag;
    3823        5932 :     }
    3824             : 
    3825       20248 :     Real64 AirMass(Real64 const CosZen) // COS( solar zenith), 0 - 1
    3826             :     {
    3827             : 
    3828             :         // SUBROUTINE INFORMATION:
    3829             :         //       AUTHOR         C Barnaby
    3830             :         //       DATE WRITTEN   Nov 2010
    3831             : 
    3832             :         // PURPOSE OF THIS SUBROUTINE:
    3833             :         // Calculate relative air mass using Kasten and Young approximation
    3834             : 
    3835             :         // METHODOLOGY EMPLOYED:
    3836             :         // Eqn (16), ASHRAE HOF 2009, p. 14.9
    3837             : 
    3838             :         // REFERENCES:
    3839             :         // ASHRAE HOF 2009 Chapter 14
    3840             :         // Kasten, F and T. Young.  1989.  Revised optical air mass tables
    3841             :         //   and approximating formula.  Applied Optics 28:4735-4738.
    3842             : 
    3843             :         Real64 AirMass;
    3844             :         Real64 SunAltD;
    3845             : 
    3846       20248 :         if (CosZen <= 0.001) {
    3847           6 :             AirMass = 37.07837343; // limit value calc'd with Excel
    3848             :                                    //  value increases little as CosZen -> 0
    3849       20242 :         } else if (CosZen >= 1.0) {
    3850           0 :             AirMass = 1.0;
    3851             :         } else {
    3852             :             // note: COS( Zen) = SIN( Alt)
    3853       20242 :             SunAltD = std::asin(CosZen) / Constant::DegToRadians; // altitude, degrees
    3854       20242 :             AirMass = 1.0 / (CosZen + 0.50572 * std::pow(6.07995 + SunAltD, -1.6364));
    3855             :         }
    3856       20248 :         return AirMass;
    3857             :     }
    3858             : 
    3859             :     //------------------------------------------------------------------------------
    3860             : 
    3861       20248 :     void ASHRAETauModel([[maybe_unused]] EnergyPlusData &state,
    3862             :                         DesDaySolarModel const TauModel, // ASHRAETau solar model type ASHRAE_Tau or ASHRAE_Tau2017
    3863             :                         Real64 const ETR,                // extraterrestrial normal irradiance, W/m2
    3864             :                         Real64 const CosZen,             // COS( solar zenith angle), 0 - 1
    3865             :                         Real64 const TauB,               // beam tau factor
    3866             :                         Real64 const TauD,               // dif tau factor
    3867             :                         Real64 &IDirN,                   // returned: direct (beam) irradiance on normal surface, W/m2
    3868             :                         Real64 &IDifH,                   // returned: diffuse irradiance on horiz surface, W/m2
    3869             :                         Real64 &IGlbH                    // returned: global irradiance on horiz surface, W/m2
    3870             :     )
    3871             :     {
    3872             : 
    3873             :         // SUBROUTINE INFORMATION:
    3874             :         //       AUTHOR         C Barnaby
    3875             :         //       DATE WRITTEN   Nov 2010
    3876             : 
    3877             :         // PURPOSE OF THIS SUBROUTINE:
    3878             :         // Calculate clear-sky direct and diffuse irradiance using ASHRAE "tau" model
    3879             : 
    3880             :         // METHODOLOGY EMPLOYED:
    3881             :         // Eqns (17-18), ASHRAE HOF 2009, p. 14.9
    3882             :         // Eqns (19-20), ASHRAE HOF 2013 p. 14.9 and 2017 p. 14.10
    3883             : 
    3884             :         // REFERENCES:
    3885             :         // ASHRAE HOF 2009 Chapter 14
    3886             : 
    3887             :         Real64 AB; // air mass exponents
    3888             :         Real64 AD;
    3889             :         Real64 M; // air mass
    3890             : 
    3891       20248 :         if (CosZen < DataEnvironment::SunIsUpValue || TauB <= 0.0 || TauD <= 0.0) {
    3892           0 :             IDirN = 0.0;
    3893           0 :             IDifH = 0.0;
    3894           0 :             IGlbH = 0.0;
    3895             :         } else {
    3896       20248 :             if (TauModel == DesDaySolarModel::ASHRAE_Tau) {
    3897       20248 :                 AB = 1.219 - 0.043 * TauB - 0.151 * TauD - 0.204 * TauB * TauD;
    3898       20248 :                 AD = 0.202 + 0.852 * TauB - 0.007 * TauD - 0.357 * TauB * TauD;
    3899             :             } else {
    3900             :                 // TauModelType == ASHRAE_Tau2017
    3901           0 :                 AB = 1.454 - 0.406 * TauB - 0.268 * TauD + 0.021 * TauB * TauD;
    3902           0 :                 AD = 0.507 + 0.205 * TauB - 0.080 * TauD - 0.190 * TauB * TauD;
    3903             :             }
    3904       20248 :             M = AirMass(CosZen);
    3905       20248 :             IDirN = ETR * std::exp(-TauB * std::pow(M, AB));
    3906       20248 :             IDifH = ETR * std::exp(-TauD * std::pow(M, AD));
    3907       20248 :             IGlbH = IDirN * CosZen + IDifH;
    3908             :         }
    3909       20248 :     }
    3910             : 
    3911         796 :     void AllocateWeatherData(EnergyPlusData &state)
    3912             :     {
    3913             : 
    3914             :         // SUBROUTINE INFORMATION:
    3915             :         //       AUTHOR         Linda Lawrie
    3916             :         //       DATE WRITTEN   December 2000
    3917             : 
    3918             :         // PURPOSE OF THIS SUBROUTINE:
    3919             :         // This subroutine allocates the weather data structures (Today, Tomorrow,
    3920             :         // Design Day) to the proper number of "time steps in hour" requested by the user.
    3921             :         // Interpolation of data is done later after either setting up the design day (hourly
    3922             :         // data) or reading in hourly weather data.
    3923             : 
    3924         796 :         state.dataWeather->wvarsHrTsToday.allocate(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3925         796 :         state.dataWeather->wvarsHrTsTomorrow.allocate(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    3926         796 :     }
    3927             : 
    3928        9785 :     void CalculateDailySolarCoeffs(EnergyPlusData &state,
    3929             :                                    int const DayOfYear,           // Day of year (1 - 366)
    3930             :                                    Real64 &A,                     // ASHRAE "A" - Apparent solar irradiation at air mass = 0 [W/M**2]
    3931             :                                    Real64 &B,                     // ASHRAE "B" - Atmospheric extinction coefficient
    3932             :                                    Real64 &C,                     // ASHRAE "C" - Diffuse radiation factor
    3933             :                                    Real64 &AnnVarSolConstant,     // Annual variation in the solar constant
    3934             :                                    Real64 &EquationOfTime,        // Equation of Time
    3935             :                                    Real64 &SineSolarDeclination,  // Sine of Solar Declination
    3936             :                                    Real64 &CosineSolarDeclination // Cosine of Solar Declination
    3937             :     )
    3938             :     {
    3939             : 
    3940             :         // SUBROUTINE INFORMATION:
    3941             :         //       AUTHOR         George Walton
    3942             :         //       DATE WRITTEN   May 1985
    3943             :         //       MODIFIED       1999 for EnergyPlus
    3944             :         //       RE-ENGINEERED  2001; LKL; Remove need for English -> SI conversion
    3945             :         //                      Implement Tarp "fix" for Southern Hemisphere
    3946             : 
    3947             :         // PURPOSE OF THIS SUBROUTINE:
    3948             :         // This subroutine computes the daily solar coefficients used in other
    3949             :         // calculations.  Specifically, this routine computes values of the solar declination, equation
    3950             :         // of time, and ashrae sky coefficients a, b, and c for a given
    3951             :         // day of the year.
    3952             : 
    3953             :         // METHODOLOGY EMPLOYED:
    3954             :         // The method is the same as that recommended in the ASHRAE loads
    3955             :         // algorithms manual, except that the fourier series expressions
    3956             :         // have been extended by two terms for greater accuracy.
    3957             :         // coefficients for the new expressions were determined at USACERL
    3958             :         // using data from the cited references.
    3959             : 
    3960             :         // REFERENCES:
    3961             :         // J. L. Threlkeld, "Thermal Environmental Engineering", 1970,
    3962             :         // p.316, for declination and equation of time.
    3963             :         // "ASHRAE Handbook of Fundamentals", 1972, p.387 for sky
    3964             :         // coefficients a, b, and c.
    3965             :         // See SUN3 in SolarShading. See SUN2 in BLAST.  See SUN3 in Tarp.
    3966             : 
    3967        9785 :         Real64 const DayCorrection(Constant::Pi * 2.0 / 366.0);
    3968             : 
    3969             :         // Fitted coefficients of Fourier series | Sine of declination coefficients
    3970             :         static constexpr std::array<Real64, 9> SineSolDeclCoef = {
    3971             :             0.00561800, 0.0657911, -0.392779, 0.00064440, -0.00618495, -0.00010101, -0.00007951, -0.00011691, 0.00002096};
    3972             :         // Fitted coefficients of Fourier Series | Equation of Time coefficients
    3973             :         static constexpr std::array<Real64, 9> EqOfTimeCoef = {
    3974             :             0.00021971, -0.122649, 0.00762856, -0.156308, -0.0530028, -0.00388702, -0.00123978, -0.00270502, -0.00167992};
    3975             :         // Fitted coefficients of Fourier Series | ASHRAE A Factor coefficients
    3976             :         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};
    3977             :         // Fitted coefficients of Fourier Series | ASHRAE B Factor coefficients
    3978             :         static constexpr std::array<Real64, 9> ASHRAE_B_Coef = {
    3979             :             0.171631, -0.00400448, -0.0344923, 0.00000209, 0.00325428, -0.00085429, 0.00229562, 0.0009034, -0.0011867};
    3980             :         // Fitted coefficients of Fourier Series | ASHRAE C Factor coefficients
    3981             :         static constexpr std::array<Real64, 9> ASHRAE_C_Coef = {
    3982             :             0.0905151, -0.00322522, -0.0407966, 0.000104164, 0.00745899, -0.00086461, 0.0013111, 0.000808275, -0.00170515};
    3983             : 
    3984             :         // Day of Year in Radians (Computed from Input DayOfYear)
    3985        9785 :         Real64 X = DayCorrection * DayOfYear; // Convert Julian date (Day of Year) to angle X
    3986             : 
    3987             :         // Calculate sines and cosines of X
    3988        9785 :         Real64 SinX = std::sin(X);
    3989        9785 :         Real64 CosX = std::cos(X);
    3990             : 
    3991        9785 :         SineSolarDeclination = SineSolDeclCoef[0] + SineSolDeclCoef[1] * SinX + SineSolDeclCoef[2] * CosX + SineSolDeclCoef[3] * (SinX * CosX * 2.0) +
    3992        9785 :                                SineSolDeclCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    3993        9785 :                                SineSolDeclCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    3994        9785 :                                SineSolDeclCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    3995        9785 :                                SineSolDeclCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    3996        9785 :                                SineSolDeclCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    3997        9785 :         CosineSolarDeclination = std::sqrt(1.0 - pow_2(SineSolarDeclination));
    3998             : 
    3999        9785 :         EquationOfTime = EqOfTimeCoef[0] + EqOfTimeCoef[1] * SinX + EqOfTimeCoef[2] * CosX + EqOfTimeCoef[3] * (SinX * CosX * 2.0) +
    4000        9785 :                          EqOfTimeCoef[4] * (pow_2(CosX) - pow_2(SinX)) +
    4001        9785 :                          EqOfTimeCoef[5] * (SinX * (pow_2(CosX) - pow_2(SinX)) + CosX * (SinX * CosX * 2.0)) +
    4002        9785 :                          EqOfTimeCoef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4003        9785 :                          EqOfTimeCoef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4004        9785 :                          EqOfTimeCoef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4005             : 
    4006        9785 :         AnnVarSolConstant = 1.000047 + 0.000352615 * SinX + 0.0334454 * CosX;
    4007             : 
    4008        9785 :         A = ASHRAE_A_Coef[0] + ASHRAE_A_Coef[1] * SinX + ASHRAE_A_Coef[2] * CosX + ASHRAE_A_Coef[3] * (SinX * CosX * 2.0) +
    4009        9785 :             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)) +
    4010        9785 :             ASHRAE_A_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4011        9785 :             ASHRAE_A_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4012        9785 :             ASHRAE_A_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4013             : 
    4014             :         // Compute B and C coefficients
    4015             : 
    4016        9785 :         if (state.dataEnvrn->Latitude < 0.0) {
    4017             :             // If in southern hemisphere, compute B and C with a six month time shift.
    4018           0 :             X -= Constant::Pi;
    4019           0 :             SinX = std::sin(X);
    4020           0 :             CosX = std::cos(X);
    4021             :         }
    4022             : 
    4023        9785 :         B = ASHRAE_B_Coef[0] + ASHRAE_B_Coef[1] * SinX + ASHRAE_B_Coef[2] * CosX + ASHRAE_B_Coef[3] * (SinX * CosX * 2.0) +
    4024        9785 :             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)) +
    4025        9785 :             ASHRAE_B_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4026        9785 :             ASHRAE_B_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4027        9785 :             ASHRAE_B_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4028             : 
    4029        9785 :         C = ASHRAE_C_Coef[0] + ASHRAE_C_Coef[1] * SinX + ASHRAE_C_Coef[2] * CosX + ASHRAE_C_Coef[3] * (SinX * CosX * 2.0) +
    4030        9785 :             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)) +
    4031        9785 :             ASHRAE_C_Coef[6] * (CosX * (pow_2(CosX) - pow_2(SinX)) - SinX * (SinX * CosX * 2.0)) +
    4032        9785 :             ASHRAE_C_Coef[7] * (2.0 * (SinX * CosX * 2.0) * (pow_2(CosX) - pow_2(SinX))) +
    4033        9785 :             ASHRAE_C_Coef[8] * (pow_2(pow_2(CosX) - pow_2(SinX)) - pow_2(SinX * CosX * 2.0));
    4034        9785 :     }
    4035             : 
    4036      778224 :     void CalculateSunDirectionCosines(EnergyPlusData &state,
    4037             :                                       Real64 const TimeValue,    // Current Time of Day
    4038             :                                       Real64 const EqOfTime,     // Equation of Time
    4039             :                                       Real64 const SinSolDeclin, // Sine of Solar Declination
    4040             :                                       Real64 const CosSolDeclin, // Cosine of Solar Declination
    4041             :                                       Vector3<Real64> &SUNCOS)
    4042             :     {
    4043             : 
    4044             :         // SUBROUTINE INFORMATION:
    4045             :         //       AUTHOR         George Walton
    4046             :         //       DATE WRITTEN   May 1975
    4047             :         //       MODIFIED       1999 for EnergyPlus
    4048             : 
    4049             :         // PURPOSE OF THIS SUBROUTINE:
    4050             :         // This routine computes the solar direction cosines for hourly
    4051             :         // radiation calculations.
    4052             : 
    4053             :         // REFERENCES:
    4054             :         // "NECAP Engineering Manual", 1974, p.3-117
    4055             : 
    4056      778224 :         EP_SIZE_CHECK(SUNCOS, 3); // NOLINT(misc-static-assert)
    4057             : 
    4058             :         // COMPUTE THE HOUR ANGLE
    4059             :         Real64 H =
    4060      778224 :             (15.0 * (12.0 - (TimeValue + EqOfTime)) + (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude)) * Constant::DegToRadians;
    4061      778224 :         Real64 COSH = std::cos(H);
    4062             :         // COMPUTE THE COSINE OF THE SOLAR ZENITH ANGLE.
    4063             :         // This is also the Sine of the Solar Altitude Angle
    4064             : 
    4065      778224 :         SUNCOS.z = SinSolDeclin * state.dataEnvrn->SinLatitude + CosSolDeclin * state.dataEnvrn->CosLatitude * COSH;
    4066             : 
    4067      778224 :         if (SUNCOS.z >= DataEnvironment::SunIsUpValue) { // If Sun above horizon, compute other direction cosines
    4068      391951 :             SUNCOS.y = SinSolDeclin * state.dataEnvrn->CosLatitude - CosSolDeclin * state.dataEnvrn->SinLatitude * COSH;
    4069      391951 :             SUNCOS.x = CosSolDeclin * std::sin(H);
    4070             :         } else { // Sun is down, set to 0.0
    4071      386273 :             SUNCOS.x = 0.0;
    4072      386273 :             SUNCOS.y = 0.0;
    4073             :         }
    4074      778224 :     }
    4075             : 
    4076     2900842 :     void DetermineSunUpDown(EnergyPlusData &state, Vector3<Real64> &SunCOS)
    4077             :     {
    4078             : 
    4079             :         // SUBROUTINE INFORMATION:
    4080             :         //       AUTHOR         Linda Lawrie
    4081             :         //       DATE WRITTEN   1999
    4082             : 
    4083             :         // PURPOSE OF THIS SUBROUTINE:
    4084             :         // This subroutine determines if the sun is up or down for the current
    4085             :         // hour/timestep.
    4086             : 
    4087             :         // REFERENCES:
    4088             :         // Sun routines from IBLAST, authored by Walton.
    4089             : 
    4090             :         // COMPUTE THE HOUR ANGLE
    4091     2900842 :         if (state.dataGlobal->NumOfTimeStepInHour != 1) {
    4092     5776448 :             state.dataWeather->HrAngle = (15.0 * (12.0 - (state.dataGlobal->CurrentTime + state.dataWeather->TodayVariables.EquationOfTime)) +
    4093     2888224 :                                           (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4094             :         } else {
    4095       12618 :             state.dataWeather->HrAngle =
    4096       12618 :                 (15.0 *
    4097       12618 :                      (12.0 - ((state.dataGlobal->CurrentTime + state.dataEnvrn->TS1TimeOffset) + state.dataWeather->TodayVariables.EquationOfTime)) +
    4098       12618 :                  (state.dataEnvrn->TimeZoneMeridian - state.dataEnvrn->Longitude));
    4099             :         }
    4100     2900842 :         Real64 H = state.dataWeather->HrAngle * Constant::DegToRadians;
    4101             : 
    4102             :         // Compute the Cosine of the Solar Zenith (Altitude) Angle.
    4103     2900842 :         Real64 CosZenith = state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle +
    4104     2900842 :                            state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H);
    4105             : 
    4106     2900842 :         Real64 SolarZenith = std::acos(CosZenith);
    4107     2900842 :         Real64 SinAltitude = state.dataEnvrn->CosLatitude * state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::cos(H) +
    4108     2900842 :                              state.dataEnvrn->SinLatitude * state.dataWeather->TodayVariables.SinSolarDeclinAngle;
    4109     2900842 :         Real64 SolarAltitude = std::asin(SinAltitude);
    4110     2900842 :         Real64 CosAzimuth = -(state.dataEnvrn->SinLatitude * CosZenith - state.dataWeather->TodayVariables.SinSolarDeclinAngle) /
    4111     2900842 :                             (state.dataEnvrn->CosLatitude * std::sin(SolarZenith));
    4112             :         // Following because above can yield invalid cos value.  (e.g. at south pole)
    4113     2900842 :         CosAzimuth = max(CosAzimuth, -1.0);
    4114     2900842 :         CosAzimuth = min(1.0, CosAzimuth);
    4115     2900842 :         Real64 SolarAzimuth = std::acos(CosAzimuth);
    4116             : 
    4117     2900842 :         state.dataWeather->SolarAltitudeAngle = SolarAltitude / Constant::DegToRadians;
    4118     2900842 :         state.dataWeather->SolarAzimuthAngle = SolarAzimuth / Constant::DegToRadians;
    4119     2900842 :         if (state.dataWeather->HrAngle < 0.0) {
    4120     1453014 :             state.dataWeather->SolarAzimuthAngle = 360.0 - state.dataWeather->SolarAzimuthAngle;
    4121             :         }
    4122             : 
    4123     2900842 :         SunCOS.z = CosZenith;
    4124     2900842 :         state.dataEnvrn->SunIsUpPrevTS = state.dataEnvrn->SunIsUp;
    4125     2900842 :         if (CosZenith < DataEnvironment::SunIsUpValue) {
    4126     1450870 :             state.dataEnvrn->SunIsUp = false;
    4127     1450870 :             SunCOS.y = 0.0;
    4128     1450870 :             SunCOS.x = 0.0;
    4129             :         } else {
    4130     1449972 :             state.dataEnvrn->SunIsUp = true;
    4131     1449972 :             SunCOS.y = state.dataWeather->TodayVariables.SinSolarDeclinAngle * state.dataEnvrn->CosLatitude -
    4132     1449972 :                        state.dataWeather->TodayVariables.CosSolarDeclinAngle * state.dataEnvrn->SinLatitude * std::cos(H);
    4133     1449972 :             SunCOS.x = state.dataWeather->TodayVariables.CosSolarDeclinAngle * std::sin(H);
    4134             :         }
    4135     2900842 :     }
    4136             : 
    4137         796 :     void OpenWeatherFile(EnergyPlusData &state, bool &ErrorsFound)
    4138             :     {
    4139             : 
    4140             :         // SUBROUTINE INFORMATION:
    4141             :         //       AUTHOR         Linda Lawrie
    4142             :         //       DATE WRITTEN   June 1999
    4143             : 
    4144             :         // PURPOSE OF THIS SUBROUTINE:
    4145             :         // This subroutine checks to see if a weather file and what kind of weather file
    4146             :         // exists in the working directory and calls appropriate routines to
    4147             :         // open the files and set up for use.
    4148             : 
    4149         796 :         state.dataWeather->WeatherFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    4150         796 :         if (state.dataWeather->WeatherFileExists) {
    4151         788 :             OpenEPlusWeatherFile(state, ErrorsFound, true);
    4152             :         }
    4153         796 :     }
    4154             : 
    4155        4537 :     void OpenEPlusWeatherFile(EnergyPlusData &state,
    4156             :                               bool &ErrorsFound,       // Will be set to true if errors found
    4157             :                               bool const ProcessHeader // Set to true when headers should be processed (rather than just read)
    4158             :     )
    4159             :     {
    4160             : 
    4161             :         // SUBROUTINE INFORMATION:
    4162             :         //       AUTHOR         Linda K. Lawrie
    4163             :         //       DATE WRITTEN   June 1999
    4164             : 
    4165             :         // PURPOSE OF THIS SUBROUTINE:
    4166             :         // This subroutine opens the EnergyPlus Weather File (in.epw) and processes
    4167             :         // the initial header records.
    4168             : 
    4169             :         // METHODOLOGY EMPLOYED:
    4170             :         // List directed reads, as possible.
    4171             : 
    4172        4537 :         state.files.inputWeatherFile.close();
    4173        4537 :         state.files.inputWeatherFile.filePath = state.files.inputWeatherFilePath.filePath;
    4174        4537 :         state.files.inputWeatherFile.open();
    4175        4537 :         if (!state.files.inputWeatherFile.good()) {
    4176           0 :             ShowFatalError(state, "OpenWeatherFile: Could not OPEN EPW Weather File", OptionalOutputFileRef(state.files.eso));
    4177             :         }
    4178             : 
    4179        4537 :         if (ProcessHeader) {
    4180             :             // Read in Header Information
    4181             : 
    4182             :             // Headers should come in order
    4183        7092 :             for (int typeNum = static_cast<int>(EpwHeaderType::Location); typeNum < static_cast<int>(EpwHeaderType::Num); ++typeNum) {
    4184        6304 :                 auto Line = state.files.inputWeatherFile.readLine();
    4185        6304 :                 if (Line.eof) {
    4186           0 :                     ShowFatalError(
    4187             :                         state,
    4188           0 :                         format("OpenWeatherFile: Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}",
    4189           0 :                                epwHeaders[typeNum]),
    4190           0 :                         OptionalOutputFileRef(state.files.eso));
    4191             :                 }
    4192             : 
    4193        6304 :                 int endcol = len(Line.data);
    4194        6304 :                 if (endcol > 0) {
    4195        6304 :                     if (int(Line.data[endcol - 1]) == DataSystemVariables::iUnicode_end) {
    4196           0 :                         ShowSevereError(state,
    4197             :                                         "OpenWeatherFile: EPW Weather File appears to be a Unicode or binary file.",
    4198           0 :                                         OptionalOutputFileRef(state.files.eso));
    4199           0 :                         ShowContinueError(state, "...This file cannot be read by this program. Please save as PC or Unix file and try again");
    4200           0 :                         ShowFatalError(state, "Program terminates due to previous condition.");
    4201             :                     }
    4202             :                 }
    4203        6304 :                 std::string::size_type const Pos = FindNonSpace(Line.data);
    4204        6304 :                 std::string::size_type const HdPos = index(Line.data, epwHeaders[typeNum]);
    4205        6304 :                 if (Pos != HdPos) continue;
    4206        6304 :                 ProcessEPWHeader(state, static_cast<EpwHeaderType>(typeNum), Line.data, ErrorsFound);
    4207        6304 :             }
    4208             :         } else { // Header already processed, just read
    4209        3749 :             SkipEPlusWFHeader(state);
    4210             :         }
    4211        4537 :     }
    4212             : 
    4213       12057 :     void CloseWeatherFile(EnergyPlusData &state)
    4214             :     {
    4215       12057 :         state.files.inputWeatherFile.close();
    4216       12057 :     }
    4217             : 
    4218         796 :     void ResolveLocationInformation(EnergyPlusData &state, bool &ErrorsFound) // Set to true if no location evident
    4219             :     {
    4220             : 
    4221             :         // SUBROUTINE INFORMATION:
    4222             :         //       AUTHOR         Rick Strand
    4223             :         //       DATE WRITTEN   June 1997
    4224             : 
    4225             :         // PURPOSE OF THIS SUBROUTINE:
    4226             :         // This subroutine is currently the main interface between the old data
    4227             :         // structure on the BLAST Weather file and the new data structure contained
    4228             :         // in this module.  At some point, this subroutine will be converted
    4229             :         // to read information directly from the new input file.
    4230             : 
    4231        1567 :         if (state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather &&
    4232         771 :             state.dataWeather->WeatherFileExists) {
    4233         763 :             if (state.dataWeather->LocationGathered) {
    4234             :                 // See if "matching" location
    4235         756 :                 if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4236        1461 :                     if (std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude) > 1.0 ||
    4237        1412 :                         std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude) > 1.0 ||
    4238        2167 :                         std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone) > 0.0 ||
    4239         706 :                         std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) / max(state.dataEnvrn->Elevation, 1.0) >
    4240             :                             0.10) {
    4241          71 :                         ShowWarningError(state, "Weather file location will be used rather than entered (IDF) Location object.");
    4242          71 :                         ShowContinueError(state, format("..Location object={}", state.dataWeather->LocationTitle));
    4243          71 :                         ShowContinueError(state, format("..Weather File Location={}", state.dataEnvrn->WeatherFileLocationTitle));
    4244         142 :                         ShowContinueError(
    4245             :                             state,
    4246         142 :                             format("..due to location differences, Latitude difference=[{:.2R}] degrees, Longitude difference=[{:.2R}] degrees.",
    4247          71 :                                    std::abs(state.dataEnvrn->Latitude - state.dataWeather->WeatherFileLatitude),
    4248          71 :                                    std::abs(state.dataEnvrn->Longitude - state.dataWeather->WeatherFileLongitude)));
    4249         142 :                         ShowContinueError(state,
    4250         142 :                                           format("..Time Zone difference=[{:.1R}] hour(s), Elevation difference=[{:.2R}] percent, [{:.2R}] meters.",
    4251          71 :                                                  std::abs(state.dataEnvrn->TimeZoneNumber - state.dataWeather->WeatherFileTimeZone),
    4252         142 :                                                  std::abs((state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation) /
    4253          71 :                                                           max(state.dataEnvrn->Elevation, 1.0) * 100.0),
    4254         142 :                                                  std::abs(state.dataEnvrn->Elevation - state.dataWeather->WeatherFileElevation)));
    4255             :                     }
    4256             :                 }
    4257             :             }
    4258         763 :             if (!state.dataWeather->keepUserSiteLocationDefinition) {
    4259         762 :                 state.dataWeather->LocationTitle = state.dataEnvrn->WeatherFileLocationTitle;
    4260         762 :                 state.dataEnvrn->Latitude = state.dataWeather->WeatherFileLatitude;
    4261         762 :                 state.dataEnvrn->Longitude = state.dataWeather->WeatherFileLongitude;
    4262         762 :                 state.dataEnvrn->TimeZoneNumber = state.dataWeather->WeatherFileTimeZone;
    4263         762 :                 state.dataEnvrn->Elevation = state.dataWeather->WeatherFileElevation;
    4264             :             }
    4265          33 :         } else if (!state.dataWeather->LocationGathered) {
    4266           0 :             state.dataWeather->LocationTitle = "Not Entered";
    4267           0 :             ShowSevereError(state, "No Location given. Must have location information for simulation.");
    4268           0 :             ErrorsFound = true;
    4269             :         }
    4270             : 
    4271         796 :         if (!ErrorsFound) {
    4272         796 :             state.dataEnvrn->StdBaroPress = DataEnvironment::StdPressureSeaLevel * std::pow(1.0 - 2.25577e-05 * state.dataEnvrn->Elevation, 5.2559);
    4273        1592 :             state.dataEnvrn->StdRhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(
    4274         796 :                 state, state.dataEnvrn->StdBaroPress, DataPrecisionGlobals::constant_twenty, DataPrecisionGlobals::constant_zero);
    4275             :             // Write Final Location Information to the initialization output file
    4276             :             static constexpr std::string_view LocHdFormat(
    4277             :                 "! <Site:Location>, Location Name, Latitude {N+/S- Deg}, Longitude {E+/W- Deg},  Time Zone Number "
    4278             :                 "{GMT+/-}, Elevation {m},  Standard Pressure at Elevation {Pa}, Standard RhoAir at Elevation\n");
    4279         796 :             print(state.files.eio, "{}", LocHdFormat);
    4280             : 
    4281             :             static constexpr std::string_view LocFormat("Site:Location,{},{:.2R},{:.2R},{:.2R},{:.2R},{:.0R},{:.4R}\n");
    4282         796 :             print(state.files.eio,
    4283             :                   LocFormat,
    4284         796 :                   state.dataWeather->LocationTitle,
    4285         796 :                   state.dataEnvrn->Latitude,
    4286         796 :                   state.dataEnvrn->Longitude,
    4287         796 :                   state.dataEnvrn->TimeZoneNumber,
    4288         796 :                   state.dataEnvrn->Elevation,
    4289         796 :                   state.dataEnvrn->StdBaroPress,
    4290         796 :                   state.dataEnvrn->StdRhoAir);
    4291             :         }
    4292         796 :     }
    4293             : 
    4294        2140 :     void CheckLocationValidity(EnergyPlusData &state)
    4295             :     {
    4296             : 
    4297             :         // SUBROUTINE INFORMATION:
    4298             :         //       AUTHOR         Rick Strand
    4299             :         //       DATE WRITTEN   June 1997
    4300             : 
    4301             :         // PURPOSE OF THIS SUBROUTINE:
    4302             :         // This subroutine is checks to see whether the user specified location
    4303             :         // or the weather file location (if one exists) is valid.  The standard
    4304             :         // time meridian is also calculated and compared to the user supplied
    4305             :         // or weather file time zone number.
    4306             : 
    4307        2140 :         bool LocationError = false; // Set to true if there is a problem detected
    4308             : 
    4309        2140 :         if ((state.dataEnvrn->Latitude == -999.0) && (state.dataEnvrn->Longitude == -999.0) && (state.dataEnvrn->TimeZoneNumber != -999.0)) {
    4310           0 :             ShowSevereError(state, "No location specified");
    4311           0 :             LocationError = true;
    4312             :         }
    4313             : 
    4314        2140 :         if ((state.dataEnvrn->Latitude < -90.0) || (state.dataEnvrn->Latitude > 90.0)) {
    4315           0 :             ShowSevereError(state, format("Latitude must be between -90 and 90; Entered={:.2R}", state.dataEnvrn->Latitude));
    4316           0 :             LocationError = true;
    4317             :         }
    4318             : 
    4319        2140 :         if ((state.dataEnvrn->Longitude < -180.0) || (state.dataEnvrn->Longitude > 180.0)) {
    4320           0 :             ShowSevereError(state, format("Longitude must be between -180 and 180; Entered={:.2R}", state.dataEnvrn->Longitude));
    4321           0 :             LocationError = true;
    4322             :         }
    4323             : 
    4324        2140 :         if ((state.dataEnvrn->TimeZoneNumber < -12.00) || (state.dataEnvrn->TimeZoneNumber > 14.00)) {
    4325           0 :             ShowSevereError(state, format("Time Zone must be between -12 and +14; Entered={:.2R}", state.dataEnvrn->TimeZoneNumber));
    4326           0 :             LocationError = true;
    4327             :         }
    4328             : 
    4329        2140 :         Real64 const StdTimeMerid = GetSTM(state.dataEnvrn->Longitude); // Standard time meridian.
    4330             : 
    4331             :         // Compare the standard time meridian with the time zone number.  If
    4332             :         // different, notify the user.  If StdTimeMerid couldn't be calculated,
    4333             :         // produce an error message.
    4334             : 
    4335        2140 :         if (state.dataEnvrn->varyingLocationSchedIndexLat > 0 || state.dataEnvrn->varyingLocationSchedIndexLong > 0) {
    4336             :             // don't do any warnings, the building is moving
    4337         796 :         } else if (StdTimeMerid >= -12.0 && StdTimeMerid <= 12.0) {
    4338         796 :             if (state.dataEnvrn->TimeZoneNumber != StdTimeMerid) {
    4339             :                 // Difference between Standard Time Meridian and TimeZone
    4340           9 :                 Real64 const DiffCalc = std::abs(state.dataEnvrn->TimeZoneNumber - StdTimeMerid);
    4341           9 :                 if (DiffCalc > 1.0 && DiffCalc < 24.0) {
    4342           0 :                     if (DiffCalc < 3.0) {
    4343           0 :                         ShowWarningError(state,
    4344           0 :                                          format("Standard Time Meridian and Time Zone differ by more than 1, Difference=\"{:.1R}\"", DiffCalc));
    4345           0 :                         ShowContinueError(state, "Solar Positions may be incorrect");
    4346             :                     } else {
    4347           0 :                         ShowSevereError(state, format("Standard Time Meridian and Time Zone differ by more than 2, Difference=\"{:.1R}\"", DiffCalc));
    4348           0 :                         ShowContinueError(state, "Solar Positions will be incorrect");
    4349             :                         //          LocationError=.TRUE.
    4350             :                     }
    4351             :                 }
    4352             :             }
    4353         796 :         } else {
    4354           0 :             ShowSevereError(state, "Unable to calculate the standard time meridian");
    4355           0 :             LocationError = true;
    4356             :         }
    4357             : 
    4358             :         // Error handling:  if there are any errors in the location information
    4359             :         // the simulation must be terminated
    4360             : 
    4361        2140 :         if (LocationError) {
    4362           0 :             ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4363             :         }
    4364             : 
    4365        2140 :         if (state.dataEnvrn->TimeZoneNumber <= 12.00) {
    4366        2140 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0;
    4367             :         } else {
    4368           0 :             state.dataEnvrn->TimeZoneMeridian = state.dataEnvrn->TimeZoneNumber * 15.0 - 360.0;
    4369             :         }
    4370        2140 :         state.dataEnvrn->SinLatitude = std::sin(Constant::DegToRadians * state.dataEnvrn->Latitude);
    4371        2140 :         state.dataEnvrn->CosLatitude = std::cos(Constant::DegToRadians * state.dataEnvrn->Latitude);
    4372             : 
    4373        2140 :         if (state.dataEnvrn->Latitude == 0.0 && state.dataEnvrn->Longitude == 0.0 && state.dataEnvrn->TimeZoneNumber == 0.0) {
    4374           0 :             ShowWarningError(state,
    4375             :                              "Did you realize that you have Latitude=0.0, Longitude=0.0 and TimeZone=0.0?  Your building site is in the middle of "
    4376             :                              "the Atlantic Ocean.");
    4377             :         }
    4378        2140 :     }
    4379             : 
    4380         771 :     void CheckWeatherFileValidity(EnergyPlusData &state)
    4381             :     {
    4382             : 
    4383             :         // SUBROUTINE INFORMATION:
    4384             :         //       AUTHOR         Linda Lawrie
    4385             :         //       DATE WRITTEN   February 1977
    4386             :         //       MODIFIED       June 1997 (RKS)
    4387             : 
    4388             :         // PURPOSE OF THIS SUBROUTINE:
    4389             :         // This subroutine contains a portion of the legacy subroutine CKBLDE.
    4390             :         // The main purpose of this routine is to check the validity of the
    4391             :         // weather dates provided by the user and the attached weather file.
    4392             :         // These functions may eventually be pushed to an interface.  This
    4393             :         // routine also sends the weather file header information at the
    4394             :         // Environment derived type.
    4395             : 
    4396         771 :         if (!state.dataWeather->WeatherFileExists) { // No weather file exists but the user requested one--print error message
    4397             : 
    4398           8 :             if (state.dataGlobal->DoWeathSim) {
    4399           0 :                 ShowSevereError(state, "GetNextEnvironment: Weather Environment(s) requested, but no weather file found");
    4400           0 :                 ShowFatalError(state, "Due to previous error condition, simulation terminated");
    4401             :             }
    4402             : 
    4403             :         } // ... end of WeatherFileExists IF-THEN
    4404         771 :     }
    4405             : 
    4406         796 :     void ReportOutputFileHeaders(EnergyPlusData &state)
    4407             :     {
    4408             : 
    4409             :         // SUBROUTINE INFORMATION:
    4410             :         //       AUTHOR         Rick Strand
    4411             :         //       DATE WRITTEN   June 1997
    4412             :         //       MODIFIED       December 2017; Jason DeGraw
    4413             : 
    4414             :         // PURPOSE OF THIS SUBROUTINE:
    4415             :         // This subroutine prints out the necessary header information required
    4416             :         // by the EnergyPlus output file format.  This subroutine can be
    4417             :         // replicated in any other modules which must send data to the output
    4418             :         // file.
    4419             : 
    4420             :         // METHODOLOGY EMPLOYED:
    4421             :         // For each report, the report flag integer must be saved from the
    4422             :         // global report number counter.  Then, the report counter must be
    4423             :         // incremented.  Finally, the header information for the report must
    4424             :         // be sent to the output file.
    4425             : 
    4426             :         using OutputProcessor::ReportFreq;
    4427             : 
    4428             :         static constexpr std::string_view EnvironmentString(",5,Environment Title[],Latitude[deg],Longitude[deg],Time Zone[],Elevation[m]");
    4429             : 
    4430             :         static constexpr std::array<std::string_view, (int)ReportFreq::Num> freqStrings = {
    4431             :             "", // No EachCall string
    4432             :             ",8,Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],Hour[],StartMinute[],EndMinute[],DayType",
    4433             :             "", // No Hour string
    4434             :             ",5,Cumulative Day of Simulation[],Month[],Day of Month[],DST Indicator[1=yes 0=no],DayType  ! When Daily ",
    4435             :             ",2,Cumulative Days of Simulation[],Month[]  ! When Monthly ",
    4436             :             ",1,Cumulative Days of Simulation[] ! When Run Period ",
    4437             :             ",1,Calendar Year of Simulation[] ! When Annual "};
    4438             : 
    4439         796 :         auto &op = state.dataOutputProcessor;
    4440             : 
    4441         796 :         state.dataWeather->EnvironmentReportNbr = ++op->ReportNumberCounter;
    4442         796 :         if (state.dataWeather->EnvironmentReportNbr != 1) { //  problem
    4443           0 :             ShowFatalError(state, "ReportOutputFileHeaders: Assigned report number for Environment title is not 1.  Contact Support.");
    4444             :         }
    4445         796 :         state.dataWeather->EnvironmentReportChr = fmt::to_string(state.dataWeather->EnvironmentReportNbr);
    4446         796 :         strip(state.dataWeather->EnvironmentReportChr);
    4447         796 :         print(state.files.eso, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4448         796 :         print(state.files.mtr, "{}{}\n", state.dataWeather->EnvironmentReportChr, EnvironmentString);
    4449             : 
    4450             :         // TImeStep and Hour share a stamp
    4451         796 :         op->freqStampReportNums[(int)ReportFreq::Hour] = op->freqStampReportNums[(int)ReportFreq::TimeStep] = ++op->ReportNumberCounter;
    4452         796 :         print(state.files.eso, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4453         796 :         print(state.files.mtr, "{}{}\n", op->freqStampReportNums[(int)ReportFreq::TimeStep], freqStrings[(int)ReportFreq::TimeStep]);
    4454             : 
    4455        3980 :         for (ReportFreq freq : {ReportFreq::Day, ReportFreq::Month, ReportFreq::Simulation, ReportFreq::Year}) {
    4456        3184 :             op->freqStampReportNums[(int)freq] = ++op->ReportNumberCounter;
    4457        3184 :             print(state.files.eso, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Report Variables Requested");
    4458        3184 :             print(state.files.mtr, "{}{}{}\n", op->freqStampReportNums[(int)freq], freqStrings[(int)freq], "Meters Requested");
    4459             :         }
    4460         796 :     }
    4461             : 
    4462     2900842 :     void ReportWeatherAndTimeInformation(EnergyPlusData &state, bool &printEnvrnStamp) // Set to true when the environment header should be printed
    4463             :     {
    4464             : 
    4465             :         // SUBROUTINE INFORMATION:
    4466             :         //       AUTHOR         Rick Strand
    4467             :         //       DATE WRITTEN   June 1997
    4468             : 
    4469             :         // PURPOSE OF THIS SUBROUTINE:
    4470             :         // This subroutine is the main driver of the weather reporting.  This
    4471             :         // routine is also responsible for printing the time and environment
    4472             :         // stamps.
    4473             : 
    4474             :         // METHODOLOGY EMPLOYED:
    4475             :         // Reporting is only done for non-warmup days.  The environment stamp
    4476             :         // is only reported at the beginning of an environment, but after the
    4477             :         // warmup days (to allow all modules to print the report headers to the
    4478             :         // output file.  This is controlled by the PrintEnvrnStamp variable
    4479             :         // which is passed in and reset if necessary.
    4480             : 
    4481             :         // Report the time stamp and the current weather to the output file
    4482             : 
    4483     2900842 :         if (!state.dataGlobal->WarmupFlag && !state.dataWeather->RPReadAllWeatherData) { // Write the required output information
    4484             : 
    4485             :             // The first time through in a non-warmup day, the environment header
    4486             :             // must be printed.  This must be done here and not in the generic
    4487             :             // DataGlobals::BeginEnvrnFlag block above because other modules in the simulation
    4488             :             // must also print out header information.  This can be done during
    4489             :             // the simulation warmup if the environment stamp printing is delayed
    4490             :             // until the warmup is completed.  The stamp should only be printed once
    4491             :             // per environment (set/reset of PrintEnvrnStamp).  In addition, before
    4492             :             // the first environment, the end of the header block flag must also be
    4493             :             // sent to the output file.
    4494             : 
    4495      689184 :             if (printEnvrnStamp) {
    4496             : 
    4497      208576 :                 if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting) {
    4498             :                     static constexpr std::string_view EndOfHeaderString("End of Data Dictionary"); // End of data dictionary marker
    4499         791 :                     print(state.files.eso, "{}\n", EndOfHeaderString);
    4500         791 :                     print(state.files.mtr, "{}\n", EndOfHeaderString);
    4501         791 :                     state.dataReportFlag->PrintEndDataDictionary = false;
    4502             :                 }
    4503      208576 :                 if (state.dataGlobal->DoOutputReporting) {
    4504        1696 :                     std::string const &Title = state.dataWeather->Environment(state.dataWeather->Envrn).Title;
    4505             :                     static constexpr std::string_view EnvironmentStampFormatStr(
    4506             :                         "{},{},{:7.2F},{:7.2F},{:7.2F},{:7.2F}\n"); // Format descriptor for environ stamp
    4507        1696 :                     print(state.files.eso,
    4508             :                           EnvironmentStampFormatStr,
    4509        1696 :                           state.dataWeather->EnvironmentReportChr,
    4510             :                           Title,
    4511        1696 :                           state.dataEnvrn->Latitude,
    4512        1696 :                           state.dataEnvrn->Longitude,
    4513        1696 :                           state.dataEnvrn->TimeZoneNumber,
    4514        1696 :                           state.dataEnvrn->Elevation);
    4515        1696 :                     print(state.files.mtr,
    4516             :                           EnvironmentStampFormatStr,
    4517        1696 :                           state.dataWeather->EnvironmentReportChr,
    4518             :                           Title,
    4519        1696 :                           state.dataEnvrn->Latitude,
    4520        1696 :                           state.dataEnvrn->Longitude,
    4521        1696 :                           state.dataEnvrn->TimeZoneNumber,
    4522        1696 :                           state.dataEnvrn->Elevation);
    4523        1696 :                     printEnvrnStamp = false;
    4524             :                 }
    4525             :             }
    4526             :         } // ... end of .NOT.WarmupFlag IF-THEN block.
    4527     2900842 :     }
    4528             : 
    4529         796 :     void ReadUserWeatherInput(EnergyPlusData &state)
    4530             :     {
    4531             : 
    4532             :         // SUBROUTINE INFORMATION:
    4533             :         //       AUTHOR         Richard Liesen
    4534             :         //       DATE WRITTEN   September 1997
    4535             : 
    4536             :         // PURPOSE OF THIS SUBROUTINE:
    4537             :         // This subroutine is the main driver of the weather manager module.
    4538             :         // It controls the assignment of weather related global variables as
    4539             :         // well as the reads and writes for retrieving weather information.
    4540             : 
    4541             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4542         796 :         bool ErrorsFound(false);
    4543             : 
    4544             :         // Get the number of design days and annual runs from user inpout
    4545         796 :         state.dataEnvrn->TotDesDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:DesignDay");
    4546         796 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    4547         796 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    4548         796 :         state.dataWeather->TotRunPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriod");
    4549         796 :         state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4550         796 :         state.dataGlobal->WeathSimReq = state.dataWeather->TotRunPers > 0;
    4551         796 :         state.dataWeather->TotReportPers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Output:Table:ReportPeriod");
    4552             : #ifdef GET_OUT
    4553             :         state.dataWeather->SPSiteScheduleNamePtr.allocate(state.dataEnvrn->TotDesDays * 5);
    4554             :         state.dataWeather->SPSiteScheduleUnits.allocate(state.dataEnvrn->TotDesDays * 5);
    4555             : 
    4556             :         state.dataWeather->SPSiteScheduleNamePtr = 0;
    4557             :         state.dataWeather->SPSiteScheduleUnits = "";
    4558             : #endif //
    4559             :        // Allocate the Design Day and Environment array to the # of DD's or/and
    4560             :        // Annual runs on input file
    4561         796 :         state.dataWeather->DesignDay.allocate(state.dataEnvrn->TotDesDays);
    4562         796 :         state.dataWeather->Environment.allocate(state.dataWeather->NumOfEnvrn);
    4563             : 
    4564             :         // Set all Environments to DesignDay and then the weather environment will be set
    4565             :         //  in the get annual run data subroutine
    4566        2462 :         for (int Env = 1; Env <= state.dataEnvrn->TotDesDays; ++Env) {
    4567        1666 :             state.dataWeather->Environment(Env).KindOfEnvrn = Constant::KindOfSim::DesignDay;
    4568             :         }
    4569         801 :         for (int Env = 1; Env <= RPD1 + RPD2; ++Env) {
    4570           5 :             if (!state.dataSysVars->DDOnly) {
    4571           0 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    4572             :             } else {
    4573           5 :                 state.dataWeather->Environment(state.dataEnvrn->TotDesDays + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4574             :             }
    4575             :         }
    4576        1981 :         for (int Env = 1; Env <= state.dataWeather->TotRunPers; ++Env) {
    4577        1185 :             state.dataWeather->Environment(state.dataEnvrn->TotDesDays + RPD1 + RPD2 + Env).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    4578             :         }
    4579             : 
    4580         796 :         if (state.dataEnvrn->TotDesDays >= 1) {
    4581         796 :             GetDesignDayData(state, state.dataEnvrn->TotDesDays, ErrorsFound);
    4582             :         }
    4583             : 
    4584         796 :         if (RPD1 >= 1 || RPD2 >= 1) {
    4585           3 :             GetRunPeriodDesignData(state, ErrorsFound);
    4586             :         }
    4587             : 
    4588             :         // the last environment(s) is designated the weather environment if an annual run
    4589             :         // is selected.  All of the design systems is done from the design day info
    4590             :         // which will have to be completed to run the annual run.
    4591         796 :         if (state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4592         771 :             GetRunPeriodData(state, state.dataWeather->TotRunPers, ErrorsFound);
    4593             :         }
    4594             : 
    4595         796 :         if (state.dataWeather->TotReportPers > 0) {
    4596           4 :             GetReportPeriodData(state, state.dataWeather->TotReportPers, ErrorsFound);
    4597           4 :             GroupReportPeriodByType(state, state.dataWeather->TotReportPers);
    4598             :         }
    4599             : 
    4600         796 :         if (state.dataSysVars->FullAnnualRun) {
    4601             :             // GetRunPeriodData may have reset the value of TotRunPers
    4602           6 :             state.dataWeather->NumOfEnvrn = state.dataEnvrn->TotDesDays + state.dataWeather->TotRunPers + RPD1 + RPD2;
    4603             :         }
    4604             : 
    4605         796 :         if (RPD1 >= 1 || RPD2 >= 1 || state.dataWeather->TotRunPers >= 1 || state.dataSysVars->FullAnnualRun) {
    4606         771 :             GetSpecialDayPeriodData(state, ErrorsFound);
    4607         771 :             GetDSTData(state, ErrorsFound);
    4608         771 :             if (state.dataWeather->IDFDaylightSaving) {
    4609         179 :                 state.dataWeather->DST = state.dataWeather->IDFDST;
    4610             :             }
    4611             :         }
    4612             : 
    4613         796 :         GetLocationInfo(state, ErrorsFound);
    4614             : 
    4615         796 :         GetGroundTemps(state);
    4616             : 
    4617         796 :         GetGroundReflectances(state, ErrorsFound);
    4618             : 
    4619         796 :         GetSnowGroundRefModifiers(state, ErrorsFound);
    4620             : 
    4621         796 :         GetWaterMainsTemperatures(state, ErrorsFound);
    4622             : 
    4623         796 :         GetWeatherStation(state, ErrorsFound);
    4624             : 
    4625         796 :         SetupEnvironmentTypes(state);
    4626             : 
    4627         796 :         GetWeatherProperties(state, ErrorsFound);
    4628             : #ifdef GET_OUT
    4629             :         // Deallocate ones used for schedule pointers
    4630             :         state.dataWeather->SPSiteScheduleNamePtr.deallocate();
    4631             :         state.dataWeather->SPSiteScheduleUnits.deallocate();
    4632             : #endif //
    4633         796 :         if (ErrorsFound) {
    4634           0 :             ShowFatalError(state, "GetWeatherInput: Above errors cause termination");
    4635             :         }
    4636         796 :     }
    4637             : 
    4638        1033 :     static int findYearForWeekday(int const month, int const day, ScheduleManager::DayType const weekday)
    4639             :     {
    4640             :         // Find a year that goes with a month/day and a weekday. A lookup table is used with the most recent year that includes
    4641             :         // the date with the weekday specified.
    4642             : 
    4643             :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4644             :         static std::array<int, 13> const defaultYear{{2013, 2014, 2015, 2010, 2011, 2017, 2007, 2013, 2014, 2015, 2010, 2011, 2017}};
    4645             : 
    4646        1033 :         int rem = calculateDayOfYear(month, day) % 7;
    4647        1033 :         return defaultYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4648             :     }
    4649             : 
    4650           0 :     static int findLeapYearForWeekday(int const month, int const day, ScheduleManager::DayType const weekday)
    4651             :     {
    4652             :         // 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
    4653             :         // the date with the weekday specified.
    4654             : 
    4655             :         // Tu, W, Th, F, Sa, Su, M, Tu, W, Th, F, Sa, Su
    4656             :         static std::array<int, 13> const defaultLeapYear{{2008, 1992, 2004, 2016, 2000, 2012, 1996, 2008, 1992, 2004, 2016, 2000, 2012}};
    4657             : 
    4658           0 :         int rem = calculateDayOfYear(month, day, true) % 7;
    4659           0 :         return defaultLeapYear[static_cast<int>(weekday) - rem + 5]; // static_cast<int>(weekday) - rem + 1 + 4
    4660             :     }
    4661             : 
    4662           4 :     void GetReportPeriodData(EnergyPlusData &state,
    4663             :                              int nReportPeriods, // Total number of Report Periods requested
    4664             :                              bool &ErrorsFound)
    4665             :     {
    4666           4 :         constexpr std::string_view routineName = "GetReportPeriodData";
    4667           4 :         state.dataWeather->ReportPeriodInput.allocate(nReportPeriods);
    4668             : 
    4669           4 :         auto const &ipsc = state.dataIPShortCut;
    4670           4 :         ipsc->cCurrentModuleObject = "Output:Table:ReportPeriod";
    4671           4 :         int Count = 0;
    4672             :         int NumAlpha;   // Number of alphas being input
    4673             :         int NumNumeric; // Number of numbers being input
    4674             :         int IOStat;     // IO Status when calling get input subroutine
    4675          13 :         for (int i = 1; i <= nReportPeriods; ++i) {
    4676          18 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4677           9 :                                                                      ipsc->cCurrentModuleObject,
    4678             :                                                                      i,
    4679           9 :                                                                      ipsc->cAlphaArgs,
    4680             :                                                                      NumAlpha,
    4681           9 :                                                                      ipsc->rNumericArgs,
    4682             :                                                                      NumNumeric,
    4683             :                                                                      IOStat,
    4684           9 :                                                                      ipsc->lNumericFieldBlanks,
    4685           9 :                                                                      ipsc->lAlphaFieldBlanks,
    4686           9 :                                                                      ipsc->cAlphaFieldNames,
    4687           9 :                                                                      ipsc->cNumericFieldNames);
    4688             : 
    4689           9 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    4690           9 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    4691             :             // A1, \field Name
    4692           9 :             if (std::find_if(state.dataWeather->ReportPeriodInput.begin(),
    4693           9 :                              state.dataWeather->ReportPeriodInput.end(),
    4694          48 :                              [&newName](ReportPeriodData const &rpd) { return newName == rpd.title; }) !=
    4695           9 :                 state.dataWeather->ReportPeriodInput.end()) {
    4696           0 :                 ShowSevereDuplicateName(state, eoh);
    4697           0 :                 ErrorsFound = true;
    4698             :             }
    4699             : 
    4700           9 :             ++Count;
    4701             : 
    4702           9 :             auto &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4703             :             // Loop = RP + Ptr;
    4704             :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "ReportPeriod 1" anyways
    4705             :             // which is fine for our reporting below
    4706           9 :             reportPeriodInput.title = newName;
    4707             :             // A2, \field Report Name
    4708           9 :             reportPeriodInput.reportName = ipsc->cAlphaArgs(2);
    4709             : 
    4710             :             // set the start and end day of month from user input
    4711             :             // N1, \field Begin Year
    4712             :             // N2, \field Begin Month
    4713             :             // N3, \field Begin Day of Month
    4714             :             // N4, \field Begin Hour of Day
    4715             :             // N5, \field End Year
    4716             :             // N6, \field End Month
    4717             :             // N7, \field End Day of Month
    4718             :             // N8; \field End Hour of Day
    4719           9 :             reportPeriodInput.startYear = int(ipsc->rNumericArgs(1));
    4720           9 :             reportPeriodInput.startMonth = int(ipsc->rNumericArgs(2));
    4721           9 :             reportPeriodInput.startDay = int(ipsc->rNumericArgs(3));
    4722           9 :             reportPeriodInput.startHour = int(ipsc->rNumericArgs(4));
    4723           9 :             reportPeriodInput.endYear = int(ipsc->rNumericArgs(5));
    4724           9 :             reportPeriodInput.endMonth = int(ipsc->rNumericArgs(6));
    4725           9 :             reportPeriodInput.endDay = int(ipsc->rNumericArgs(7));
    4726           9 :             reportPeriodInput.endHour = int(ipsc->rNumericArgs(8));
    4727             : 
    4728             :             // Validate year inputs
    4729           9 :             if (reportPeriodInput.startYear == 0) {
    4730           9 :                 if (reportPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    4731           0 :                     ShowSevereError(state,
    4732           0 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    4733           0 :                                            ipsc->cCurrentModuleObject,
    4734           0 :                                            reportPeriodInput.title));
    4735           0 :                     ErrorsFound = true;
    4736             :                 }
    4737           0 :             } else if (reportPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    4738           0 :                 ShowSevereError(state,
    4739           0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    4740           0 :                                        ipsc->cCurrentModuleObject,
    4741           0 :                                        reportPeriodInput.title,
    4742           0 :                                        reportPeriodInput.startYear));
    4743           0 :                 ErrorsFound = true;
    4744             :             }
    4745             : 
    4746           9 :             if (reportPeriodInput.endYear != 0 && reportPeriodInput.startYear > reportPeriodInput.endYear) {
    4747           0 :                 ShowSevereError(state,
    4748           0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    4749           0 :                                        ipsc->cCurrentModuleObject,
    4750           0 :                                        reportPeriodInput.title,
    4751           0 :                                        reportPeriodInput.startYear,
    4752           0 :                                        reportPeriodInput.endYear));
    4753           0 :                 ErrorsFound = true;
    4754             :             }
    4755             : 
    4756           9 :             reportPeriodInput.startJulianDate =
    4757           9 :                 computeJulianDate(reportPeriodInput.startYear, reportPeriodInput.startMonth, reportPeriodInput.startDay);
    4758           9 :             reportPeriodInput.endJulianDate = computeJulianDate(reportPeriodInput.endYear, reportPeriodInput.endMonth, reportPeriodInput.endDay);
    4759           9 :         }
    4760           4 :     }
    4761             : 
    4762           4 :     void GroupReportPeriodByType(EnergyPlusData &state, const int nReportPeriods)
    4763             :     {
    4764             :         // transfer data from the reporting period object to the corresponding report period type arrays
    4765             :         // ThermalResilienceSummary, CO2ResilienceSummary, VisualResilienceSummary, and AllResilienceSummaries
    4766          13 :         for (auto const &reportPeriodInput : state.dataWeather->ReportPeriodInput) {
    4767             : 
    4768           9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4769           4 :                 ++state.dataWeather->TotThermalReportPers;
    4770           5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4771           2 :                 ++state.dataWeather->TotCO2ReportPers;
    4772           3 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4773           2 :                 ++state.dataWeather->TotVisualReportPers;
    4774           1 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4775           1 :                 ++state.dataWeather->TotThermalReportPers;
    4776           1 :                 ++state.dataWeather->TotCO2ReportPers;
    4777           1 :                 ++state.dataWeather->TotVisualReportPers;
    4778             :             }
    4779             :         }
    4780             : 
    4781           4 :         state.dataWeather->ThermalReportPeriodInput.allocate(state.dataWeather->TotThermalReportPers);
    4782           4 :         state.dataWeather->CO2ReportPeriodInput.allocate(state.dataWeather->TotCO2ReportPers);
    4783           4 :         state.dataWeather->VisualReportPeriodInput.allocate(state.dataWeather->TotVisualReportPers);
    4784             : 
    4785          13 :         for (int i = 1, iThermal = 1, iVisual = 1, iCO2 = 1; i <= nReportPeriods; ++i) {
    4786           9 :             auto const &reportPeriodInput = state.dataWeather->ReportPeriodInput(i);
    4787           9 :             if (reportPeriodInput.reportName == "THERMALRESILIENCESUMMARY") {
    4788           4 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4789           4 :                 ++iThermal;
    4790           5 :             } else if (reportPeriodInput.reportName == "CO2RESILIENCESUMMARY") {
    4791           2 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4792           2 :                 ++iCO2;
    4793           3 :             } else if (reportPeriodInput.reportName == "VISUALRESILIENCESUMMARY") {
    4794           2 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4795           2 :                 ++iVisual;
    4796           1 :             } else if (reportPeriodInput.reportName == "ALLRESILIENCESUMMARIES") {
    4797           1 :                 state.dataWeather->ThermalReportPeriodInput(iThermal) = reportPeriodInput;
    4798           1 :                 ++iThermal;
    4799           1 :                 state.dataWeather->CO2ReportPeriodInput(iCO2) = reportPeriodInput;
    4800           1 :                 ++iCO2;
    4801           1 :                 state.dataWeather->VisualReportPeriodInput(iVisual) = reportPeriodInput;
    4802           1 :                 ++iVisual;
    4803             :             }
    4804             :         }
    4805           4 :     }
    4806             : 
    4807         771 :     void GetRunPeriodData(EnergyPlusData &state,
    4808             :                           int nRunPeriods, // Total number of Run Periods requested
    4809             :                           bool &ErrorsFound)
    4810             :     {
    4811             : 
    4812             :         // SUBROUTINE INFORMATION:
    4813             :         //       AUTHOR         Richard Liesen
    4814             :         //       DATE WRITTEN   October 1997
    4815             :         //       MODIFIED       February 1999, Add multiple run periods, Change name.
    4816             :         //                      March 2012, LKL, Add features to object; New "actual weather" object;
    4817             : 
    4818             :         // PURPOSE OF THIS SUBROUTINE:
    4819             :         // This subroutine gets the run period info from User input and the
    4820             :         //  simulation dates
    4821             : 
    4822         771 :         constexpr std::string_view routineName = "GetRunPeriodData";
    4823             :         // Call Input Get routine to retrieve annual run data
    4824         771 :         state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    4825             : 
    4826         771 :         auto const &ipsc = state.dataIPShortCut;
    4827         771 :         ipsc->cCurrentModuleObject = "RunPeriod";
    4828         771 :         int Count = 0;
    4829             :         int NumAlpha;   // Number of alphas being input
    4830             :         int NumNumeric; // Number of numbers being input
    4831             :         int IOStat;     // IO Status when calling get input subroutine
    4832        1956 :         for (int i = 1; i <= nRunPeriods; ++i) {
    4833        2370 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4834        1185 :                                                                      ipsc->cCurrentModuleObject,
    4835             :                                                                      i,
    4836        1185 :                                                                      ipsc->cAlphaArgs,
    4837             :                                                                      NumAlpha,
    4838        1185 :                                                                      ipsc->rNumericArgs,
    4839             :                                                                      NumNumeric,
    4840             :                                                                      IOStat,
    4841        1185 :                                                                      ipsc->lNumericFieldBlanks,
    4842        1185 :                                                                      ipsc->lAlphaFieldBlanks,
    4843        1185 :                                                                      ipsc->cAlphaFieldNames,
    4844        1185 :                                                                      ipsc->cNumericFieldNames);
    4845             : 
    4846             :             // A1, \field Name
    4847        1185 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    4848        1185 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    4849             : 
    4850        1185 :             if (std::find_if(state.dataWeather->RunPeriodInput.begin(),
    4851        1185 :                              state.dataWeather->RunPeriodInput.end(),
    4852        3396 :                              [&newName](RunPeriodData const &rpd) { return rpd.title == newName; }) != state.dataWeather->RunPeriodInput.end()) {
    4853           0 :                 ShowSevereDuplicateName(state, eoh);
    4854           0 :                 ErrorsFound = true;
    4855             :             }
    4856             : 
    4857        1185 :             ++Count;
    4858             :             // Loop = RP + Ptr;
    4859             :             // Note JM 2018-11-20: IDD allows blank name, but input processor will create a name such as "RUNPERIOD 1" anyways
    4860             :             // which is fine for our reporting below
    4861        1185 :             auto &runPeriodInput = state.dataWeather->RunPeriodInput(i);
    4862        1185 :             runPeriodInput.title = ipsc->cAlphaArgs(1);
    4863             : 
    4864             :             // set the start and end day of month from user input
    4865             :             // N1 , \field Begin Month
    4866             :             // N2 , \field Begin Day of Month
    4867             :             // N3,  \field Start Year
    4868             :             // N4 , \field End Month
    4869             :             // N5 , \field End Day of Month
    4870             :             // N6,  \field End Year
    4871        1185 :             runPeriodInput.startMonth = int(ipsc->rNumericArgs(1));
    4872        1185 :             runPeriodInput.startDay = int(ipsc->rNumericArgs(2));
    4873        1185 :             runPeriodInput.startYear = int(ipsc->rNumericArgs(3));
    4874        1185 :             runPeriodInput.endMonth = int(ipsc->rNumericArgs(4));
    4875        1185 :             runPeriodInput.endDay = int(ipsc->rNumericArgs(5));
    4876        1185 :             runPeriodInput.endYear = int(ipsc->rNumericArgs(6));
    4877        1185 :             runPeriodInput.TreatYearsAsConsecutive = true;
    4878             : 
    4879        1185 :             if (state.dataSysVars->FullAnnualRun && i == 1) {
    4880           6 :                 runPeriodInput.startMonth = 1;
    4881           6 :                 runPeriodInput.startDay = 1;
    4882           6 :                 runPeriodInput.endMonth = 12;
    4883           6 :                 runPeriodInput.endDay = 31;
    4884             :             }
    4885             : 
    4886             :             // Validate year inputs
    4887        1185 :             if (runPeriodInput.startYear == 0) {
    4888        1178 :                 if (runPeriodInput.endYear != 0) { // Have to have an input start year to input an end year
    4889           0 :                     ShowSevereError(state,
    4890           0 :                                     format("{}: object={}, end year cannot be specified if the start year is not.",
    4891           0 :                                            ipsc->cCurrentModuleObject,
    4892           0 :                                            runPeriodInput.title));
    4893           0 :                     ErrorsFound = true;
    4894             :                 }
    4895           7 :             } else if (runPeriodInput.startYear < 1583) { // Bail on the proleptic Gregorian calendar
    4896           0 :                 ShowSevereError(state,
    4897           0 :                                 format("{}: object={}, start year ({}) is too early, please choose a date after 1582.",
    4898           0 :                                        ipsc->cCurrentModuleObject,
    4899           0 :                                        runPeriodInput.title,
    4900           0 :                                        runPeriodInput.startYear));
    4901           0 :                 ErrorsFound = true;
    4902             :             }
    4903             : 
    4904        1185 :             if (runPeriodInput.endYear != 0 && runPeriodInput.startYear > runPeriodInput.endYear) {
    4905           0 :                 ShowSevereError(state,
    4906           0 :                                 format("{}: object={}, start year ({}) is after the end year ({}).",
    4907           0 :                                        ipsc->cCurrentModuleObject,
    4908           0 :                                        runPeriodInput.title,
    4909           0 :                                        runPeriodInput.startYear,
    4910           0 :                                        runPeriodInput.endYear));
    4911           0 :                 ErrorsFound = true;
    4912             :             }
    4913             : 
    4914             :             // A2 , \field Day of Week for Start Day
    4915        1185 :             bool inputWeekday = false;
    4916        1185 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) { // Have input
    4917        1038 :                 int dayType = getEnumValue(ScheduleManager::dayTypeNamesUC, state.dataIPShortCut->cAlphaArgs(2));
    4918        1038 :                 if (dayType < 1) {
    4919           0 :                     ShowWarningError(state,
    4920           0 :                                      format("{}: object={}{} invalid (Day of Week) [{}] for Start is not valid, Sunday will be used.",
    4921           0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    4922           0 :                                             state.dataWeather->RunPeriodInput(i).title,
    4923           0 :                                             state.dataIPShortCut->cAlphaFieldNames(2),
    4924           0 :                                             state.dataIPShortCut->cAlphaArgs(2)));
    4925           0 :                     runPeriodInput.startWeekDay = ScheduleManager::DayType::Sunday;
    4926             :                 } else {
    4927        1038 :                     runPeriodInput.startWeekDay = static_cast<ScheduleManager::DayType>(dayType);
    4928        1038 :                     inputWeekday = true;
    4929             :                 }
    4930             :             } else { // No input, set the default as Sunday. This may get overriden below
    4931         147 :                 runPeriodInput.startWeekDay = ScheduleManager::DayType::Sunday;
    4932             :             }
    4933             : 
    4934             :             // Validate the dates now that the weekday field has been looked at
    4935        1185 :             if (runPeriodInput.startMonth == 2 && runPeriodInput.startDay == 29) {
    4936             :                 // Requested start date is a leap year
    4937           0 :                 if (runPeriodInput.startYear == 0) { // No input starting year
    4938           0 :                     if (inputWeekday) {
    4939           0 :                         runPeriodInput.startYear =
    4940           0 :                             findLeapYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    4941             :                     } else {
    4942             :                         // 2012 is the default year, 1/1 is a Sunday
    4943           0 :                         runPeriodInput.startYear = 2012;
    4944           0 :                         runPeriodInput.startWeekDay =
    4945           0 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4946             :                     }
    4947             :                 } else {                                         // Have an input start year
    4948           0 :                     if (!isLeapYear(runPeriodInput.startYear)) { // Start year is not a leap year
    4949           0 :                         ShowSevereError(state,
    4950           0 :                                         format("{}: object={}, start year ({}) is not a leap year but the requested start date is 2/29.",
    4951           0 :                                                ipsc->cCurrentModuleObject,
    4952           0 :                                                runPeriodInput.title,
    4953           0 :                                                runPeriodInput.startYear));
    4954           0 :                         ErrorsFound = true;
    4955             :                     } else { // Start year is a leap year
    4956             :                         ScheduleManager::DayType weekday =
    4957           0 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4958           0 :                         if (inputWeekday) { // Check for correctness of input
    4959           0 :                             if (weekday != runPeriodInput.startWeekDay) {
    4960           0 :                                 ShowWarningError(state,
    4961           0 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    4962           0 :                                                         ipsc->cCurrentModuleObject,
    4963           0 :                                                         runPeriodInput.title,
    4964           0 :                                                         ipsc->cAlphaArgs(2),
    4965           0 :                                                         runPeriodInput.startYear,
    4966           0 :                                                         ScheduleManager::dayTypeNamesUC[static_cast<int>(weekday)]));
    4967           0 :                                 runPeriodInput.startWeekDay = weekday;
    4968             :                             }
    4969             :                         } else { // Set the weekday if it was not input
    4970           0 :                             runPeriodInput.startWeekDay = weekday;
    4971             :                         }
    4972             :                     }
    4973             :                 }
    4974           0 :             } else {
    4975             :                 // Non leap-day start date
    4976        1185 :                 if (!validMonthDay(runPeriodInput.startMonth, runPeriodInput.startDay)) {
    4977           0 :                     ShowSevereError(state,
    4978           0 :                                     format("{}: object={}, Invalid input start month/day ({}/{})",
    4979           0 :                                            ipsc->cCurrentModuleObject,
    4980           0 :                                            runPeriodInput.title,
    4981           0 :                                            runPeriodInput.startMonth,
    4982           0 :                                            runPeriodInput.startDay));
    4983           0 :                     ErrorsFound = true;
    4984             :                 } else {                                 // Month/day is valid
    4985        1185 :                     if (runPeriodInput.startYear == 0) { // No input starting year
    4986        1178 :                         if (inputWeekday) {
    4987        1033 :                             runPeriodInput.startYear =
    4988        1033 :                                 findYearForWeekday(runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.startWeekDay);
    4989             :                         } else {
    4990             :                             // 2017 is the default year, 1/1 is a Sunday
    4991         145 :                             runPeriodInput.startYear = 2017;
    4992         145 :                             runPeriodInput.startWeekDay =
    4993         145 :                                 calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4994             :                         }
    4995             :                     } else { // Have an input starting year
    4996             :                         ScheduleManager::DayType weekday =
    4997           7 :                             calculateDayOfWeek(state, runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    4998           7 :                         if (inputWeekday) { // Check for correctness of input
    4999           5 :                             if (weekday != runPeriodInput.startWeekDay) {
    5000           2 :                                 ShowWarningError(state,
    5001           3 :                                                  format("{}: object={}, start weekday ({}) does not match the start year ({}), corrected to {}.",
    5002           1 :                                                         ipsc->cCurrentModuleObject,
    5003           1 :                                                         runPeriodInput.title,
    5004           1 :                                                         ipsc->cAlphaArgs(2),
    5005           1 :                                                         runPeriodInput.startYear,
    5006           1 :                                                         ScheduleManager::dayTypeNamesUC[static_cast<int>(weekday)]));
    5007           1 :                                 runPeriodInput.startWeekDay = weekday;
    5008             :                             }
    5009             :                         } else { // Set the weekday if it was not input
    5010           2 :                             runPeriodInput.startWeekDay = weekday;
    5011             :                         }
    5012             :                     }
    5013             :                 }
    5014             :             }
    5015             : 
    5016             :             // Compute the Julian date of the start date
    5017        1185 :             runPeriodInput.startJulianDate = computeJulianDate(runPeriodInput.startYear, runPeriodInput.startMonth, runPeriodInput.startDay);
    5018             : 
    5019             :             // Validate the end date
    5020        1185 :             if (runPeriodInput.endMonth == 2 && runPeriodInput.endDay == 29) {
    5021             :                 // Requested end date is a leap year
    5022           0 :                 if (runPeriodInput.endYear == 0) { // No input end year
    5023           0 :                     if (isLeapYear(runPeriodInput.startYear) && runPeriodInput.startMonth < 3) {
    5024             :                         // The run period is from some date on or before 2/29 through 2/29
    5025           0 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5026             :                     } else {
    5027             :                         // There might be a better approach here, but for now just loop forward for the next leap year
    5028           0 :                         for (int yr = runPeriodInput.startYear + 1; yr < runPeriodInput.startYear + 10; yr++) {
    5029           0 :                             if (isLeapYear(yr)) {
    5030           0 :                                 runPeriodInput.endYear = yr;
    5031           0 :                                 break;
    5032             :                             }
    5033             :                         }
    5034             :                     }
    5035             :                 } else {                                       // Have an input end year
    5036           0 :                     if (!isLeapYear(runPeriodInput.endYear)) { // End year is not a leap year
    5037           0 :                         ShowSevereError(state,
    5038           0 :                                         format("{}: object={}, end year ({}) is not a leap year but the requested end date is 2/29.",
    5039           0 :                                                ipsc->cCurrentModuleObject,
    5040           0 :                                                runPeriodInput.title,
    5041           0 :                                                runPeriodInput.startYear));
    5042           0 :                         ErrorsFound = true;
    5043             :                     } else {
    5044           0 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5045           0 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5046           0 :                             ShowSevereError(state,
    5047           0 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5048           0 :                                                    ipsc->cCurrentModuleObject,
    5049           0 :                                                    runPeriodInput.title,
    5050           0 :                                                    runPeriodInput.startJulianDate,
    5051           0 :                                                    runPeriodInput.endJulianDate));
    5052           0 :                             ErrorsFound = true;
    5053             :                         }
    5054             :                     }
    5055             :                 }
    5056           0 :             } else {
    5057             :                 // Non leap-day end date
    5058        1185 :                 if (!validMonthDay(runPeriodInput.endMonth, runPeriodInput.endDay)) {
    5059           0 :                     ShowSevereError(state,
    5060           0 :                                     format("{}: object={}, Invalid input end month/day ({}/{})",
    5061           0 :                                            ipsc->cCurrentModuleObject,
    5062           0 :                                            runPeriodInput.title,
    5063           0 :                                            runPeriodInput.startMonth,
    5064           0 :                                            runPeriodInput.startDay));
    5065           0 :                     ErrorsFound = true;
    5066             :                 } else {                               // Month/day is valid
    5067        1185 :                     if (runPeriodInput.endYear == 0) { // No input end year
    5068             :                         // Assume same year as start year
    5069        1178 :                         runPeriodInput.endYear = runPeriodInput.startYear;
    5070        1178 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5071        1178 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5072           5 :                             runPeriodInput.endJulianDate = 0; // Force recalculation later
    5073           5 :                             runPeriodInput.endYear += 1;
    5074             :                         }
    5075             :                     } else { // Have an input end year
    5076           7 :                         runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5077           7 :                         if (runPeriodInput.startJulianDate > runPeriodInput.endJulianDate) {
    5078           0 :                             ShowSevereError(state,
    5079           0 :                                             format("{}: object={}, start Julian date ({}) is after the end Julian date ({}).",
    5080           0 :                                                    ipsc->cCurrentModuleObject,
    5081           0 :                                                    runPeriodInput.title,
    5082           0 :                                                    runPeriodInput.startJulianDate,
    5083           0 :                                                    runPeriodInput.endJulianDate));
    5084           0 :                             ErrorsFound = true;
    5085             :                         }
    5086             :                     }
    5087             :                 }
    5088             :             }
    5089             : 
    5090        1185 :             if (runPeriodInput.endJulianDate == 0) {
    5091           5 :                 runPeriodInput.endJulianDate = computeJulianDate(runPeriodInput.endYear, runPeriodInput.endMonth, runPeriodInput.endDay);
    5092             :             }
    5093             : 
    5094        1185 :             runPeriodInput.numSimYears = runPeriodInput.endYear - runPeriodInput.startYear + 1;
    5095             : 
    5096             :             // A3,  \field Use Weather File Holidays and Special Days
    5097             :             BooleanSwitch b;
    5098        1185 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5099           9 :                 runPeriodInput.useHolidays = true;
    5100        1176 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5101        1176 :                 runPeriodInput.useHolidays = static_cast<bool>(b);
    5102             :             } else {
    5103           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5104           0 :                 ErrorsFound = true;
    5105             :             }
    5106             : 
    5107             :             // A4,  \field Use Weather File Daylight Saving Period
    5108        1185 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5109           9 :                 runPeriodInput.useDST = true;
    5110        1176 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5111        1176 :                 runPeriodInput.useDST = static_cast<bool>(b);
    5112             :             } else {
    5113           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5114           0 :                 ErrorsFound = true;
    5115             :             }
    5116             : 
    5117             :             // A5,  \field Apply Weekend Holiday Rule
    5118        1185 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5119          18 :                 runPeriodInput.applyWeekendRule = true;
    5120        1167 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5121        1167 :                 runPeriodInput.applyWeekendRule = static_cast<bool>(b);
    5122             :             } else {
    5123           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5124           0 :                 ErrorsFound = true;
    5125             :             }
    5126             : 
    5127             :             // A6,  \field Use Weather File Rain Indicators
    5128        1185 :             if (ipsc->lAlphaFieldBlanks(6)) {
    5129          18 :                 runPeriodInput.useRain = true;
    5130        1167 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(6)))) != BooleanSwitch::Invalid) {
    5131        1167 :                 runPeriodInput.useRain = static_cast<bool>(b);
    5132             :             } else {
    5133           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6));
    5134           0 :                 ErrorsFound = true;
    5135             :             }
    5136             : 
    5137             :             // A7,  \field Use Weather File Snow Indicators
    5138        1185 :             if (ipsc->lAlphaFieldBlanks(7)) {
    5139          18 :                 runPeriodInput.useSnow = true;
    5140        1167 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    5141        1167 :                 runPeriodInput.useSnow = static_cast<bool>(b);
    5142             :             } else {
    5143           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7));
    5144           0 :                 ErrorsFound = true;
    5145             :             }
    5146             : 
    5147             :             // A8,  \field Treat Weather as Actual
    5148        1185 :             if (ipsc->lAlphaFieldBlanks(8)) {
    5149        1185 :                 runPeriodInput.actualWeather = false;
    5150           0 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    5151           0 :                 runPeriodInput.actualWeather = static_cast<bool>(b);
    5152             :             } else {
    5153           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8));
    5154           0 :                 ErrorsFound = true;
    5155             :             }
    5156             : 
    5157             :             // A9,  \field First Hour Interpolation Starting Values
    5158        1185 :             if (ipsc->lAlphaFieldBlanks(9) || Util::SameString(ipsc->cAlphaArgs(8), "Hour24")) {
    5159        1185 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5160           0 :             } else if (Util::SameString(ipsc->cAlphaArgs(9), "Hour1")) {
    5161           0 :                 runPeriodInput.firstHrInterpUsingHr1 = true;
    5162             :             } else {
    5163             :                 // fail-safe default
    5164           0 :                 runPeriodInput.firstHrInterpUsingHr1 = false;
    5165             :             }
    5166             : 
    5167        1185 :             runPeriodInput.dayOfWeek = static_cast<int>(runPeriodInput.startWeekDay);
    5168        1185 :             runPeriodInput.isLeapYear = isLeapYear(runPeriodInput.startYear);
    5169             : 
    5170             :             // calculate the annual start and end days from the user inputted month and day
    5171        1185 :             runPeriodInput.monWeekDay = 0;
    5172        1185 :             if (runPeriodInput.dayOfWeek != 0 && !ErrorsFound) {
    5173        1185 :                 SetupWeekDaysByMonth(state, runPeriodInput.startMonth, runPeriodInput.startDay, runPeriodInput.dayOfWeek, runPeriodInput.monWeekDay);
    5174             :             }
    5175        1185 :         }
    5176             : 
    5177         771 :         if (nRunPeriods == 0 && state.dataSysVars->FullAnnualRun) {
    5178           0 :             ShowWarningError(state, "No Run Periods input but Full Annual Simulation selected.  Adding Run Period to 1/1 through 12/31.");
    5179           0 :             state.dataWeather->Environment.redimension(++state.dataWeather->NumOfEnvrn);
    5180           0 :             state.dataWeather->Environment(state.dataWeather->NumOfEnvrn).KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    5181           0 :             nRunPeriods = 1;
    5182           0 :             state.dataGlobal->WeathSimReq = true;
    5183           0 :             state.dataWeather->RunPeriodInput.allocate(nRunPeriods);
    5184           0 :             auto &runPerInput1 = state.dataWeather->RunPeriodInput(1);
    5185           0 :             runPerInput1.startJulianDate = General::OrdinalDay(runPerInput1.startMonth, runPerInput1.startDay, state.dataWeather->LeapYearAdd);
    5186           0 :             runPerInput1.endJulianDate = General::OrdinalDay(runPerInput1.endMonth, runPerInput1.endDay, state.dataWeather->LeapYearAdd);
    5187           0 :             runPerInput1.monWeekDay = 0;
    5188           0 :             if (runPerInput1.dayOfWeek != 0 && !ErrorsFound) {
    5189           0 :                 SetupWeekDaysByMonth(state, runPerInput1.startMonth, runPerInput1.startDay, runPerInput1.dayOfWeek, runPerInput1.monWeekDay);
    5190             :             }
    5191         771 :         } else if (nRunPeriods > 1 && state.dataSysVars->FullAnnualRun) {
    5192           0 :             nRunPeriods = 1;
    5193             :         }
    5194         771 :     }
    5195             : 
    5196           3 :     void GetRunPeriodDesignData(EnergyPlusData &state, bool &ErrorsFound)
    5197             :     {
    5198             : 
    5199             :         // SUBROUTINE INFORMATION:
    5200             :         //       AUTHOR         Linda Lawrie
    5201             :         //       DATE WRITTEN   March 2008
    5202             : 
    5203             :         // PURPOSE OF THIS SUBROUTINE:
    5204             :         // This subroutine gets the run period design info from User input and the
    5205             :         //  simulation dates
    5206             : 
    5207           3 :         constexpr std::string_view routineName = "GetRunPeriodDesignData";
    5208             :         // Call Input Get routine to retrieve annual run data
    5209           3 :         int RPD1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileDays");
    5210           3 :         int RPD2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SizingPeriod:WeatherFileConditionType");
    5211           3 :         state.dataWeather->TotRunDesPers = RPD1 + RPD2;
    5212             : 
    5213           3 :         state.dataWeather->RunPeriodDesignInput.allocate(RPD1 + RPD2);
    5214             : 
    5215           3 :         int Count = 0;
    5216           3 :         auto const &ipsc = state.dataIPShortCut;
    5217           3 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileDays";
    5218           6 :         for (int i = 1; i <= RPD1; ++i) {
    5219             :             int NumAlphas;   // Number of alphas being input
    5220             :             int NumNumerics; // Number of Numerics being input
    5221             :             int IOStat;      // IO Status when calling get input subroutine
    5222           6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5223           3 :                                                                      ipsc->cCurrentModuleObject,
    5224             :                                                                      i,
    5225           3 :                                                                      ipsc->cAlphaArgs,
    5226             :                                                                      NumAlphas,
    5227           3 :                                                                      ipsc->rNumericArgs,
    5228             :                                                                      NumNumerics,
    5229             :                                                                      IOStat,
    5230           3 :                                                                      ipsc->lNumericFieldBlanks,
    5231           3 :                                                                      ipsc->lAlphaFieldBlanks,
    5232           3 :                                                                      ipsc->cAlphaFieldNames,
    5233           3 :                                                                      ipsc->cNumericFieldNames);
    5234             : 
    5235           3 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5236           3 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5237           6 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5238           6 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5239           8 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5240           6 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5241           0 :                 ShowSevereDuplicateName(state, eoh);
    5242           0 :                 ErrorsFound = true;
    5243             :             }
    5244             : 
    5245           3 :             ++Count;
    5246             : 
    5247           3 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5248           3 :             runPerDesInput.title = newName;
    5249           3 :             runPerDesInput.periodType = "User Selected WeatherFile RunPeriod (Design)";
    5250             : 
    5251             :             // set the start and end day of month from user input
    5252           3 :             runPerDesInput.startMonth = int(ipsc->rNumericArgs(1));
    5253           3 :             runPerDesInput.startDay = int(ipsc->rNumericArgs(2));
    5254           3 :             runPerDesInput.endMonth = int(ipsc->rNumericArgs(3));
    5255           3 :             runPerDesInput.endDay = int(ipsc->rNumericArgs(4));
    5256             : 
    5257           3 :             switch (runPerDesInput.startMonth) {
    5258           3 :             case 1:
    5259             :             case 3:
    5260             :             case 5:
    5261             :             case 7:
    5262             :             case 8:
    5263             :             case 10:
    5264             :             case 12: {
    5265           3 :                 if (runPerDesInput.startDay > 31) {
    5266           0 :                     ShowSevereError(state,
    5267           0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5268           0 :                                            ipsc->cCurrentModuleObject,
    5269           0 :                                            runPerDesInput.title,
    5270           0 :                                            ipsc->cNumericFieldNames(2),
    5271           0 :                                            runPerDesInput.startDay));
    5272           0 :                     ErrorsFound = true;
    5273             :                 }
    5274           3 :             } break;
    5275           0 :             case 4:
    5276             :             case 6:
    5277             :             case 9:
    5278             :             case 11: {
    5279           0 :                 if (runPerDesInput.startDay > 30) {
    5280           0 :                     ShowSevereError(state,
    5281           0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5282           0 :                                            ipsc->cCurrentModuleObject,
    5283           0 :                                            runPerDesInput.title,
    5284           0 :                                            ipsc->cNumericFieldNames(2),
    5285           0 :                                            runPerDesInput.startDay));
    5286           0 :                     ErrorsFound = true;
    5287             :                 }
    5288           0 :             } break;
    5289           0 :             case 2: {
    5290           0 :                 if (runPerDesInput.startDay > 28 + state.dataWeather->LeapYearAdd) {
    5291           0 :                     ShowSevereError(state,
    5292           0 :                                     format("{}: object={} {} invalid (Day of Month) [{}]",
    5293           0 :                                            ipsc->cCurrentModuleObject,
    5294           0 :                                            runPerDesInput.title,
    5295           0 :                                            ipsc->cNumericFieldNames(2),
    5296           0 :                                            runPerDesInput.startDay));
    5297           0 :                     ErrorsFound = true;
    5298             :                 }
    5299           0 :             } break;
    5300           0 :             default: {
    5301           0 :                 ShowSevereError(state,
    5302           0 :                                 format("{}: object={} {} invalid (Month) [{}]",
    5303           0 :                                        ipsc->cCurrentModuleObject,
    5304           0 :                                        runPerDesInput.title,
    5305           0 :                                        ipsc->cNumericFieldNames(1),
    5306           0 :                                        runPerDesInput.startMonth));
    5307           0 :                 ErrorsFound = true;
    5308           0 :             } break;
    5309             :             } // switch
    5310             : 
    5311           3 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5312           0 :                 runPerDesInput.dayOfWeek = (int)ScheduleManager::DayType::Monday; // Defaults to Monday
    5313             :             } else {
    5314           3 :                 runPerDesInput.dayOfWeek = getEnumValue(ScheduleManager::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    5315           3 :                 if (runPerDesInput.dayOfWeek < 1 || runPerDesInput.dayOfWeek == 8) {
    5316           0 :                     ShowWarningError(state,
    5317           0 :                                      format("{}: object={} {} invalid (Day of Week) [{} for Start is not Valid, Monday will be Used.",
    5318           0 :                                             ipsc->cCurrentModuleObject,
    5319           0 :                                             runPerDesInput.title,
    5320           0 :                                             ipsc->cAlphaFieldNames(1),
    5321           0 :                                             ipsc->cAlphaArgs(1)));
    5322           0 :                     runPerDesInput.dayOfWeek = (int)ScheduleManager::DayType::Monday; // Defaults to Monday
    5323             :                 }
    5324             :             }
    5325             : 
    5326             :             BooleanSwitch b;
    5327           3 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5328           0 :                 runPerDesInput.useDST = true;
    5329           3 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(3)))) != BooleanSwitch::Invalid) {
    5330           3 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5331             :             } else {
    5332           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5333           0 :                 ErrorsFound = true;
    5334             :             }
    5335             : 
    5336           3 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5337           0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5338           3 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5339           3 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5340             :             } else {
    5341           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5342           0 :                 ErrorsFound = true;
    5343             :             }
    5344             : 
    5345             :             // calculate the annual start and end days from the user inputted month and day
    5346           3 :             runPerDesInput.startJulianDate = General::OrdinalDay(runPerDesInput.startMonth, runPerDesInput.startDay, state.dataWeather->LeapYearAdd);
    5347           3 :             runPerDesInput.endJulianDate = General::OrdinalDay(runPerDesInput.endMonth, runPerDesInput.endDay, state.dataWeather->LeapYearAdd);
    5348           3 :             if (runPerDesInput.startJulianDate <= runPerDesInput.endJulianDate) {
    5349           3 :                 runPerDesInput.totalDays = (runPerDesInput.endJulianDate - runPerDesInput.startJulianDate + 1) * runPerDesInput.numSimYears;
    5350             :             } else {
    5351           0 :                 runPerDesInput.totalDays = (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - runPerDesInput.startJulianDate + 1 +
    5352           0 :                                             runPerDesInput.endJulianDate) *
    5353           0 :                                            runPerDesInput.numSimYears;
    5354             :             }
    5355           3 :             runPerDesInput.monWeekDay = 0;
    5356           3 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5357           3 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5358           3 :                 SetupWeekDaysByMonth(state,
    5359             :                                      runPeriodDesignInput1.startMonth,
    5360             :                                      runPeriodDesignInput1.startDay,
    5361             :                                      runPeriodDesignInput1.dayOfWeek,
    5362           3 :                                      runPeriodDesignInput1.monWeekDay);
    5363             :             }
    5364           3 :         }
    5365             : 
    5366           3 :         ipsc->cCurrentModuleObject = "SizingPeriod:WeatherFileConditionType";
    5367           5 :         for (int i = 1; i <= RPD2; ++i) {
    5368             :             int NumAlphas;   // Number of alphas being input
    5369             :             int NumNumerics; // Number of Numerics being input
    5370             :             int IOStat;      // IO Status when calling get input subroutine
    5371           4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5372           2 :                                                                      ipsc->cCurrentModuleObject,
    5373             :                                                                      i,
    5374           2 :                                                                      ipsc->cAlphaArgs,
    5375             :                                                                      NumAlphas,
    5376           2 :                                                                      ipsc->rNumericArgs,
    5377             :                                                                      NumNumerics,
    5378             :                                                                      IOStat,
    5379           2 :                                                                      ipsc->lNumericFieldBlanks,
    5380           2 :                                                                      ipsc->lAlphaFieldBlanks,
    5381           2 :                                                                      ipsc->cAlphaFieldNames,
    5382           2 :                                                                      ipsc->cNumericFieldNames);
    5383           2 :             std::string newName = Util::makeUPPER(ipsc->cAlphaArgs(1));
    5384             : 
    5385           2 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, newName};
    5386           4 :             if (std::find_if(state.dataWeather->RunPeriodDesignInput.begin(),
    5387           4 :                              state.dataWeather->RunPeriodDesignInput.end(),
    5388           6 :                              [&newName](RunPeriodData const &rpd) { return newName == rpd.title; }) !=
    5389           4 :                 state.dataWeather->RunPeriodDesignInput.end()) {
    5390           0 :                 ShowSevereDuplicateName(state, eoh);
    5391           0 :                 ErrorsFound = true;
    5392             :             }
    5393             : 
    5394           2 :             ++Count;
    5395           2 :             auto &runPerDesInput = state.dataWeather->RunPeriodDesignInput(Count);
    5396           2 :             runPerDesInput.title = ipsc->cAlphaArgs(1);
    5397           2 :             runPerDesInput.periodType = "User Selected WeatherFile Typical/Extreme Period (Design)=" + ipsc->cAlphaArgs(2);
    5398             : 
    5399             :             // Period Selection
    5400           2 :             if (ipsc->lAlphaFieldBlanks(2)) {
    5401           0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(2));
    5402           0 :                 ErrorsFound = true;
    5403             :             } else {
    5404           2 :                 int WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue);
    5405           2 :                 if (WhichPeriod == 0) {
    5406           0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue1);
    5407             :                     if (WhichPeriod != 0) {
    5408             :                     }
    5409             :                 }
    5410           2 :                 if (WhichPeriod == 0) {
    5411           0 :                     WhichPeriod = Util::FindItem(ipsc->cAlphaArgs(2), state.dataWeather->TypicalExtremePeriods, &TypicalExtremeData::MatchValue2);
    5412           0 :                     if (WhichPeriod != 0) {
    5413           0 :                         ShowWarningError(state,
    5414           0 :                                          format("{}: object={} {}={} matched to {}",
    5415           0 :                                                 ipsc->cCurrentModuleObject,
    5416           0 :                                                 runPerDesInput.title,
    5417           0 :                                                 ipsc->cAlphaFieldNames(2),
    5418           0 :                                                 ipsc->cAlphaArgs(2),
    5419           0 :                                                 state.dataWeather->TypicalExtremePeriods(WhichPeriod).MatchValue2));
    5420             :                     }
    5421             :                 }
    5422           2 :                 if (WhichPeriod == 0) {
    5423           0 :                     ShowSevereError(state,
    5424           0 :                                     format("{}: object={} {} invalid (not on Weather File)={}",
    5425           0 :                                            ipsc->cCurrentModuleObject,
    5426           0 :                                            runPerDesInput.title,
    5427           0 :                                            ipsc->cAlphaFieldNames(2),
    5428           0 :                                            ipsc->cAlphaArgs(2)));
    5429           0 :                     ErrorsFound = true;
    5430             :                 } else {
    5431           2 :                     auto const &typicalExtPer = state.dataWeather->TypicalExtremePeriods(WhichPeriod);
    5432           2 :                     runPerDesInput.startDay = typicalExtPer.StartDay;
    5433           2 :                     runPerDesInput.startMonth = typicalExtPer.StartMonth;
    5434           2 :                     runPerDesInput.startJulianDate = typicalExtPer.StartJDay;
    5435           2 :                     runPerDesInput.endDay = typicalExtPer.EndDay;
    5436           2 :                     runPerDesInput.endMonth = typicalExtPer.EndMonth;
    5437           2 :                     runPerDesInput.endJulianDate = typicalExtPer.EndJDay;
    5438           2 :                     runPerDesInput.totalDays = typicalExtPer.TotalDays;
    5439             :                 }
    5440             :             }
    5441             : 
    5442           2 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5443           0 :                 runPerDesInput.dayOfWeek = (int)ScheduleManager::DayType::Monday; // Defaults to Monday
    5444             :             } else {
    5445           2 :                 runPerDesInput.dayOfWeek = getEnumValue(ScheduleManager::dayTypeNamesUC, ipsc->cAlphaArgs(3));
    5446           2 :                 if (runPerDesInput.dayOfWeek < (int)ScheduleManager::DayType::Sunday ||
    5447           2 :                     runPerDesInput.dayOfWeek == (int)ScheduleManager::DayType::Holiday) {
    5448             :                     // Sunday-Saturday, SummerDesignDay, WinterDesignDay, CustomDay1, and CustomDay2 are all valid. Holiday is not valid.
    5449             :                     // The input processor should trap invalid key choices, so this should never trip.
    5450           0 :                     assert(false);
    5451             :                 }
    5452             :             }
    5453             : 
    5454             :             BooleanSwitch b;
    5455           2 :             if (ipsc->lAlphaFieldBlanks(4)) {
    5456           0 :                 runPerDesInput.useDST = true;
    5457           2 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    5458           2 :                 runPerDesInput.useDST = static_cast<bool>(b);
    5459             :             } else {
    5460           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5461           0 :                 ErrorsFound = true;
    5462             :             }
    5463             : 
    5464           2 :             if (ipsc->lAlphaFieldBlanks(5)) {
    5465           0 :                 runPerDesInput.useRain = runPerDesInput.useSnow = true;
    5466           2 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(5)))) != BooleanSwitch::Invalid) {
    5467           2 :                 runPerDesInput.useRain = runPerDesInput.useSnow = static_cast<bool>(b);
    5468             :             } else {
    5469           0 :                 ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    5470           0 :                 ErrorsFound = true;
    5471             :             }
    5472           2 :             auto &runPeriodDesignInput1 = state.dataWeather->RunPeriodDesignInput(1);
    5473           2 :             runPeriodDesignInput1.monWeekDay = 0;
    5474           2 :             if (runPeriodDesignInput1.dayOfWeek != 0 && !ErrorsFound) {
    5475           2 :                 SetupWeekDaysByMonth(state,
    5476             :                                      runPeriodDesignInput1.startMonth,
    5477             :                                      runPeriodDesignInput1.startDay,
    5478             :                                      runPeriodDesignInput1.dayOfWeek,
    5479           2 :                                      runPeriodDesignInput1.monWeekDay);
    5480             :             }
    5481           2 :         }
    5482           3 :     }
    5483             : 
    5484         771 :     void GetSpecialDayPeriodData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5485             :     {
    5486             : 
    5487             :         // SUBROUTINE INFORMATION:
    5488             :         //       AUTHOR         Linda Lawrie
    5489             :         //       DATE WRITTEN   June 2000
    5490             : 
    5491             :         // PURPOSE OF THIS SUBROUTINE:
    5492             :         // This subroutine reads any special day period data from the IDF and
    5493             :         // processes it into the data structure that will drive the values
    5494             :         // in the SpecialDayTypes array.
    5495             : 
    5496             :         // METHODOLOGY EMPLOYED:
    5497             :         // Processes the following IDD definition:
    5498             :         // SpecialDayPeriod,
    5499             :         //      \memo This object sets up holidays/special days to be used during weather file
    5500             :         //      \memo run periods.  (These are not used with DesignDay objects.)
    5501             :         //      \memo Depending on the value in the run period, days on the weather file may also
    5502             :         //      \memo be used.  However, the weather file specification will take precedence over
    5503             :         //      \memo any specification shown here.  (No error message on duplicate days or overlapping
    5504             :         //      \memo days).
    5505             :         //  A1, \field Holiday Name
    5506             :         //  A2, \field StartDate
    5507             :         //      \memo  Dates can be several formats:
    5508             :         //      \memo  <number>/<number>  (month/day)
    5509             :         //      \memo  <number> Month
    5510             :         //      \memo  Month <number>
    5511             :         //      \memo Months are January, February, March, April, May, June, July, August, September, October, November, December
    5512             :         //      \memo Months can be the first 3 letters of the month
    5513             :         //        \note will eventually allow: 3 Monday April (meaning 3rd Monday in April)
    5514             :         //  N1, \field duration (number of days)
    5515             :         //  A3; \field SpecialDayType
    5516             :         //        \note SpecialDayType selects the schedules appropriate for each day so labeled
    5517             :         //        \type choice
    5518             :         //        \key Holiday
    5519             :         //        \key SummerDesignDay
    5520             :         //        \key WinterDesignDay
    5521             :         //        \key CustomDay1
    5522             :         //        \key CustomDay2
    5523             : 
    5524         771 :         constexpr std::string_view routineName = "GetSpecialDayPeriodData";
    5525             : 
    5526         771 :         auto const &ipsc = state.dataIPShortCut;
    5527         771 :         ipsc->cCurrentModuleObject = "RunPeriodControl:SpecialDays";
    5528         771 :         int NumSpecDays = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5529             :         int Count;
    5530         771 :         if (allocated(state.dataWeather->SpecialDays)) { // EPW already allocated the array
    5531         763 :             Count = state.dataWeather->NumSpecialDays - NumSpecDays + 1;
    5532             :         } else {
    5533           8 :             state.dataWeather->SpecialDays.allocate(NumSpecDays);
    5534           8 :             state.dataWeather->NumSpecialDays = NumSpecDays;
    5535           8 :             Count = 1;
    5536             :         }
    5537             : 
    5538         771 :         Array1D_string AlphArray(3);
    5539             :         int NumAlphas;
    5540         771 :         Array1D<Real64> Duration(1);
    5541             :         int NumNumbers;
    5542             :         int IOStat;
    5543             : 
    5544        2060 :         for (int i = 1; i <= NumSpecDays; ++i, ++Count) {
    5545             : 
    5546        2578 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    5547        1289 :                 state, ipsc->cCurrentModuleObject, i, AlphArray, NumAlphas, Duration, NumNumbers, IOStat);
    5548             : 
    5549        1289 :             auto &specialDay = state.dataWeather->SpecialDays(Count);
    5550             : 
    5551        1289 :             specialDay.Name = AlphArray(1);
    5552        1289 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, specialDay.Name};
    5553             : 
    5554             :             int PMonth;
    5555             :             int PDay;
    5556             :             int PWeekDay;
    5557             :             DateType dateType;
    5558        1289 :             General::ProcessDateString(state, AlphArray(2), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    5559        1289 :             if (dateType == DateType::MonthDay) {
    5560         522 :                 specialDay.dateType = dateType;
    5561         522 :                 specialDay.Month = PMonth;
    5562         522 :                 specialDay.Day = PDay;
    5563         522 :                 specialDay.WeekDay = 0;
    5564         522 :                 specialDay.CompDate = PMonth * 32 + PDay;
    5565         522 :                 specialDay.WthrFile = false;
    5566         767 :             } else if (dateType != DateType::Invalid) {
    5567         767 :                 specialDay.dateType = dateType;
    5568         767 :                 specialDay.Month = PMonth;
    5569         767 :                 specialDay.Day = PDay;
    5570         767 :                 specialDay.WeekDay = PWeekDay;
    5571         767 :                 specialDay.CompDate = 0;
    5572         767 :                 specialDay.WthrFile = false;
    5573           0 :             } else if (dateType == DateType::Invalid) {
    5574           0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    5575           0 :                 ErrorsFound = true;
    5576             :             }
    5577             : 
    5578        1289 :             if (Duration(1) > 0) {
    5579        1289 :                 specialDay.Duration = int(Duration(1));
    5580             :             } else {
    5581           0 :                 ShowSevereError(
    5582           0 :                     state, format("{}: {} Invalid {}={:.0T}", ipsc->cCurrentModuleObject, AlphArray(1), ipsc->cNumericFieldNames(1), Duration(1)));
    5583           0 :                 ErrorsFound = true;
    5584             :             }
    5585             : 
    5586        1289 :             int DayType = getEnumValue(ScheduleManager::dayTypeNamesUC, AlphArray(3));
    5587        1289 :             if (DayType == 0) {
    5588           0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), AlphArray(3));
    5589           0 :                 ErrorsFound = true;
    5590             :             } else {
    5591        1289 :                 specialDay.DayType = DayType;
    5592             :             }
    5593             :         }
    5594         771 :     }
    5595             : 
    5596           7 :     void CalcSpecialDayTypes(EnergyPlusData &state)
    5597             :     {
    5598             : 
    5599             :         // SUBROUTINE INFORMATION:
    5600             :         //       AUTHOR         Linda Lawrie
    5601             :         //       DATE WRITTEN   June 2000
    5602             : 
    5603             :         // PURPOSE OF THIS SUBROUTINE:
    5604             :         // This subroutine creates the array of Special Day types used during
    5605             :         // the simulation.
    5606             : 
    5607             :         // METHODOLOGY EMPLOYED:
    5608             :         // Sets up the SpecialDayTypes array that then is used during simulation.
    5609             : 
    5610           7 :         state.dataWeather->SpecialDayTypes = 0; // Initialize/Reset Special Day Types array
    5611             : 
    5612          37 :         for (int i = 1; i <= state.dataWeather->NumSpecialDays; ++i) {
    5613          30 :             auto const &specialDay = state.dataWeather->SpecialDays(i);
    5614          30 :             if (specialDay.WthrFile) continue;
    5615             : 
    5616          30 :             int Warn = 0;
    5617             : 
    5618          30 :             int JDay = General::OrdinalDay(specialDay.Month, specialDay.Day, state.dataWeather->LeapYearAdd) - 1;
    5619             : 
    5620          60 :             for (int j = 1; j <= specialDay.Duration; ++j) {
    5621          30 :                 ++JDay;
    5622          30 :                 if (JDay > 366) {
    5623           0 :                     ShowWarningError(state, format("SpecialDay={} causes index of more than 366, ignoring those beyond 366", specialDay.Name));
    5624             :                 } else {
    5625          30 :                     if (state.dataWeather->SpecialDayTypes(JDay) != 0 && Warn == 0) {
    5626           0 :                         ShowWarningError(state, format("SpecialDay={} attempted overwrite of previous set special day", specialDay.Name));
    5627           0 :                         Warn = 1;
    5628          30 :                     } else if (state.dataWeather->SpecialDayTypes(JDay) == 0) {
    5629          30 :                         state.dataWeather->SpecialDayTypes(JDay) = specialDay.DayType;
    5630             :                     }
    5631             :                 }
    5632             :             }
    5633             :         }
    5634           7 :     }
    5635             : 
    5636         771 :     void GetDSTData(EnergyPlusData &state, bool &ErrorsFound) // will be set to true if severe errors are found in inputs
    5637             :     {
    5638             : 
    5639             :         // SUBROUTINE INFORMATION:
    5640             :         //       AUTHOR         Linda Lawrie
    5641             :         //       DATE WRITTEN   August 2000
    5642             : 
    5643             :         // PURPOSE OF THIS SUBROUTINE:
    5644             :         // This subroutine gets a possible "Daylight Saving Period" from the IDF.  Using this
    5645             :         // will overwrite any prior DST data.
    5646             : 
    5647             :         // METHODOLOGY EMPLOYED:
    5648             :         // Processes the following IDD definition:
    5649             :         // DaylightSavingPeriod,
    5650             :         //      \memo This object sets up the Daylight Saving period for any RunPeriod.
    5651             :         //      \memo Ignores any DaylightSavingperiod values on the weather file and uses this definition.
    5652             :         //      \memo (These are not used with DesignDay objects.)
    5653             :         //  A1, \field StartDate
    5654             :         //  A2, \field EndDate
    5655             :         //      \memo  Dates can be several formats:
    5656             :         //      \memo  <number>/<number>  (month/day)
    5657             :         //      \memo  <number> <Month>
    5658             :         //      \memo  <Month> <number>
    5659             :         //      \memo <Nth> <Weekday> in <Month)
    5660             :         //      \memo Last <WeekDay> in <Month>
    5661             :         //      \memo <Month> can be January, February, March, April, May, June, July, August, September,
    5662             :         // October, November, December
    5663             :         //      \memo Months can be the first 3 letters of the month
    5664             :         //      \memo <Weekday> can be Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
    5665             :         //      \memo <Nth> can be 1 or 1st, 2 or 2nd, etc. up to 5(?)
    5666             : 
    5667         771 :         constexpr std::string_view routineName = "GetDSTData";
    5668             : 
    5669         771 :         auto const &ipsc = state.dataIPShortCut;
    5670         771 :         ipsc->cCurrentModuleObject = "RunPeriodControl:DaylightSavingTime";
    5671         771 :         int NumFound = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    5672             : 
    5673         771 :         if (NumFound == 1) {
    5674             :             int NumAlphas;
    5675             :             int IOStat;
    5676             :             int NumNumbers;
    5677         358 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5678         179 :                                                                      ipsc->cCurrentModuleObject,
    5679             :                                                                      1,
    5680         179 :                                                                      ipsc->cAlphaArgs,
    5681             :                                                                      NumAlphas,
    5682         179 :                                                                      ipsc->rNumericArgs,
    5683             :                                                                      NumNumbers,
    5684             :                                                                      IOStat,
    5685         179 :                                                                      ipsc->lNumericFieldBlanks,
    5686         179 :                                                                      ipsc->lAlphaFieldBlanks,
    5687         179 :                                                                      ipsc->cAlphaFieldNames,
    5688         179 :                                                                      ipsc->cNumericFieldNames);
    5689             : 
    5690         179 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    5691             : 
    5692         179 :             if (NumAlphas != 2) {
    5693           0 :                 ShowSevereError(state, format("{}: Insufficient fields, must have Start AND End Dates", ipsc->cCurrentModuleObject));
    5694           0 :                 ErrorsFound = true;
    5695             :             } else { // Correct number of arguments
    5696         358 :                 General::ProcessDateString(state,
    5697         179 :                                            ipsc->cAlphaArgs(1),
    5698         179 :                                            state.dataWeather->IDFDST.StMon,
    5699         179 :                                            state.dataWeather->IDFDST.StDay,
    5700         179 :                                            state.dataWeather->IDFDST.StWeekDay,
    5701         179 :                                            state.dataWeather->IDFDST.StDateType,
    5702             :                                            ErrorsFound);
    5703         179 :                 if (state.dataWeather->IDFDST.StDateType == DateType::Invalid) {
    5704           0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    5705           0 :                     ErrorsFound = true;
    5706             :                 }
    5707         358 :                 General::ProcessDateString(state,
    5708         179 :                                            ipsc->cAlphaArgs(2),
    5709         179 :                                            state.dataWeather->IDFDST.EnMon,
    5710         179 :                                            state.dataWeather->IDFDST.EnDay,
    5711         179 :                                            state.dataWeather->IDFDST.EnWeekDay,
    5712         179 :                                            state.dataWeather->IDFDST.EnDateType,
    5713             :                                            ErrorsFound);
    5714         179 :                 if (state.dataWeather->IDFDST.EnDateType == DateType::Invalid) {
    5715           0 :                     ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    5716           0 :                     ErrorsFound = true;
    5717             :                 }
    5718         179 :                 state.dataWeather->IDFDaylightSaving = true;
    5719             :             }
    5720         592 :         } else if (NumFound > 1) {
    5721           0 :             ShowSevereError(state, format("{}: Too many objects in Input File, only one allowed.", ipsc->cCurrentModuleObject));
    5722           0 :             ErrorsFound = true;
    5723             :         }
    5724         771 :     }
    5725             : 
    5726         796 :     void GetDesignDayData(EnergyPlusData &state,
    5727             :                           int TotDesDays, // Total number of Design days to Setup
    5728             :                           bool &ErrorsFound)
    5729             :     {
    5730             : 
    5731             :         // SUBROUTINE INFORMATION:
    5732             :         //       AUTHOR         Richard Liesen
    5733             :         //       DATE WRITTEN   September 1997
    5734             : 
    5735             :         // PURPOSE OF THIS SUBROUTINE:
    5736             :         // This subroutine retrieves the design day info from user input file
    5737             :         //  which is later to be used in the Setup Design Day Routine.
    5738             : 
    5739             :         // REFERENCES:
    5740             :         // SizingPeriod:DesignDay,
    5741             :         //   A1, \field Name
    5742             :         //   N1,  \field Month
    5743             :         //   N2,  \field Day of Month
    5744             :         //   A2,  \field Day Type
    5745             :         //   N3,  \field Maximum Dry-Bulb Temperature
    5746             :         //   N4,  \field Daily Dry-Bulb Temperature Range
    5747             :         //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    5748             :         //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    5749             :         //   A5,  \field Humidity Condition Type
    5750             :         //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    5751             :         //   A6,  \field Humidity Condition Day Schedule Name
    5752             :         //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    5753             :         //   N7,  \field Enthalpy at Maximum Dry-Bulb  !will require units transition.
    5754             :         //   N8,  \field Daily Wet-Bulb Temperature Range
    5755             :         //   N9,  \field Barometric Pressure
    5756             :         //   N10, \field Wind Speed
    5757             :         //   N11, \field Wind Direction
    5758             :         //   A7,  \field Rain Indicator
    5759             :         //   A8,  \field Snow Indicator
    5760             :         //   A9,  \field Daylight Saving Time Indicator
    5761             :         //   A10, \field Solar Model Indicator
    5762             :         //   A11, \field Beam Solar Day Schedule Name
    5763             :         //   A12, \field Diffuse Solar Day Schedule Name
    5764             :         //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    5765             :         //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    5766             :         //   N14; \field Sky Clearness
    5767             : 
    5768             :         static constexpr std::array<std::string_view, static_cast<int>(DesDayHumIndType::Num)> DesDayHumIndTypeStringRep = {
    5769             :             "Wetbulb [C]",
    5770             :             "Dewpoint [C]",
    5771             :             "Enthalpy [J/kg]",
    5772             :             "Humidity Ratio []",
    5773             :             "Schedule []",
    5774             :             "WetBulbProfileDefaultMultipliers []",
    5775             :             "WetBulbProfileDifferenceSchedule []",
    5776             :             "WetBulbProfileMultiplierSchedule []"};
    5777             : 
    5778             :         // Below are the 2009 fractions, HOF, Chap 14, Table 6
    5779             :         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,
    5780             :                                                                         0.05, 0.00, 0.00, 0.06, 0.14, 0.24, 0.39, 0.50, 0.59, 0.68, 0.75, 0.82};
    5781             : 
    5782             :         static constexpr std::string_view routineName = "GetDesignDayData";
    5783             : 
    5784             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5785         796 :         std::string units;
    5786             :         Constant::Units unitType;
    5787             : 
    5788         796 :         state.dataWeather->DesDayInput.allocate(TotDesDays); // Allocate the array to the # of DD's
    5789         796 :         state.dataWeather->desDayMods.allocate(TotDesDays);
    5790        2462 :         for (int iDD = 1; iDD <= TotDesDays; ++iDD)
    5791        1666 :             state.dataWeather->desDayMods(iDD).allocate(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    5792             : 
    5793         796 :         state.dataWeather->spSiteSchedules.dimension(TotDesDays, Weather::SPSiteSchedules());
    5794             : 
    5795         796 :         if (state.dataSysVars->ReverseDD && TotDesDays <= 1) {
    5796           0 :             ShowSevereError(state, "GetDesignDayData: Reverse Design Day requested but # Design Days <=1");
    5797             :         }
    5798             : 
    5799         796 :         auto const &ipsc = state.dataIPShortCut;
    5800         796 :         ipsc->cCurrentModuleObject = "SizingPeriod:DesignDay";
    5801        2462 :         for (int iDesDay = 1; iDesDay <= TotDesDays; ++iDesDay) {
    5802             : 
    5803             :             int EnvrnNum;
    5804        1666 :             if (!state.dataSysVars->ReverseDD) {
    5805        1666 :                 EnvrnNum = iDesDay;
    5806           0 :             } else if (iDesDay == 1 && TotDesDays > 1) {
    5807           0 :                 EnvrnNum = 2;
    5808           0 :             } else if (iDesDay == 2) {
    5809           0 :                 EnvrnNum = 1;
    5810             :             } else {
    5811           0 :                 EnvrnNum = iDesDay;
    5812             :             }
    5813             : 
    5814             :             // Call Input Get routine to retrieve design day data
    5815        1666 :             bool MaxDryBulbEntered = false;
    5816        1666 :             bool PressureEntered = false;
    5817             :             int NumAlpha;    // Number of material alpha names being passed
    5818             :             int NumNumerics; // Number of material properties being passed
    5819             :             int IOStat;      // IO Status when calling get input subroutine
    5820        3332 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5821        1666 :                                                                      ipsc->cCurrentModuleObject,
    5822             :                                                                      iDesDay,
    5823        1666 :                                                                      ipsc->cAlphaArgs,
    5824             :                                                                      NumAlpha,
    5825        1666 :                                                                      ipsc->rNumericArgs,
    5826             :                                                                      NumNumerics,
    5827             :                                                                      IOStat,
    5828        1666 :                                                                      ipsc->lNumericFieldBlanks,
    5829        1666 :                                                                      ipsc->lAlphaFieldBlanks,
    5830        1666 :                                                                      ipsc->cAlphaFieldNames,
    5831        1666 :                                                                      ipsc->cNumericFieldNames);
    5832             : 
    5833        1666 :             auto &envCurr = state.dataWeather->Environment(EnvrnNum);
    5834        1666 :             auto &desDayInput = state.dataWeather->DesDayInput(EnvrnNum);
    5835        1666 :             desDayInput.Title = ipsc->cAlphaArgs(1); // Environment name
    5836        1666 :             envCurr.Title = desDayInput.Title;
    5837             : 
    5838        1666 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, desDayInput.Title};
    5839             : 
    5840             :             //   N3,  \field Maximum Dry-Bulb Temperature
    5841             :             //   N4,  \field Daily Dry-Bulb Temperature Range
    5842             :             //   N9,  \field Barometric Pressure
    5843             :             //   N10, \field Wind Speed
    5844             :             //   N11, \field Wind Direction
    5845        1666 :             desDayInput.MaxDryBulb = ipsc->rNumericArgs(3); // Maximum Dry-Bulb Temperature (C)
    5846        1666 :             MaxDryBulbEntered = !ipsc->lNumericFieldBlanks(3);
    5847        1666 :             desDayInput.DailyDBRange = ipsc->rNumericArgs(4); // Daily dry-bulb temperature range (deltaC)
    5848        1666 :             desDayInput.PressBarom = ipsc->rNumericArgs(9);   // Atmospheric/Barometric Pressure (Pascals)
    5849        1666 :             PressureEntered = !ipsc->lNumericFieldBlanks(9);
    5850        1666 :             desDayInput.PressureEntered = PressureEntered;
    5851        1666 :             desDayInput.WindSpeed = ipsc->rNumericArgs(10);           // Wind Speed (m/s)
    5852        1666 :             desDayInput.WindDir = mod(ipsc->rNumericArgs(11), 360.0); // Wind Direction
    5853             :             // (degrees clockwise from North, N=0, E=90, S=180, W=270)
    5854             :             //   N1,  \field Month
    5855             :             //   N2,  \field Day of Month
    5856             :             //   N12, \field ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    5857             :             //   N13, \field ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    5858             :             //   N8,  \field Daily Wet-Bulb Temperature Range
    5859        1666 :             desDayInput.Month = int(ipsc->rNumericArgs(1));      // Month of Year ( 1 - 12 )
    5860        1666 :             desDayInput.DayOfMonth = int(ipsc->rNumericArgs(2)); // Day of Month ( 1 - 31 )
    5861        1666 :             desDayInput.TauB = ipsc->rNumericArgs(12);           // beam tau >= 0
    5862        1666 :             desDayInput.TauD = ipsc->rNumericArgs(13);           // diffuse tau >= 0
    5863        1666 :             desDayInput.DailyWBRange = ipsc->rNumericArgs(8);    // Daily wet-bulb temperature range (deltaC)
    5864             : 
    5865             :             //   N14; \field Sky Clearness
    5866        1666 :             desDayInput.SkyClear = ipsc->rNumericArgs(14); // Sky Clearness (0 to 1)
    5867             : 
    5868             :             //   N15, \field Maximum Warmup Days Between Sizing Periods
    5869        1666 :             if (ipsc->lNumericFieldBlanks(15)) {
    5870             :                 // Default to -1 if not input
    5871        1666 :                 desDayInput.maxWarmupDays = -1;
    5872             :             } else {
    5873           0 :                 desDayInput.maxWarmupDays = int(ipsc->rNumericArgs(15));
    5874             :             }
    5875             :             //   A13, \field Begin Environment Reset Mode
    5876        1666 :             if (ipsc->lAlphaFieldBlanks(13)) {
    5877        1666 :                 desDayInput.suppressBegEnvReset = false;
    5878             :             } else {
    5879           0 :                 if (Util::SameString(ipsc->cAlphaArgs(13), "FullResetAtBeginEnvironment")) {
    5880           0 :                     desDayInput.suppressBegEnvReset = false;
    5881           0 :                 } else if (Util::SameString(ipsc->cAlphaArgs(13), "SuppressThermalResetAtBeginEnvironment")) {
    5882           0 :                     desDayInput.suppressBegEnvReset = true;
    5883             :                 }
    5884             :             }
    5885             :             // for PerformancePrecisionTradeoffs
    5886        1666 :             if (state.dataEnvrn->forceBeginEnvResetSuppress) {
    5887           2 :                 desDayInput.suppressBegEnvReset = true;
    5888             :             }
    5889             :             //   A7,  \field Rain Indicator
    5890             :             BooleanSwitch b;
    5891             : 
    5892        1666 :             if (ipsc->lAlphaFieldBlanks(7)) {
    5893           6 :                 desDayInput.RainInd = 0;
    5894        1660 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(7)))) != BooleanSwitch::Invalid) {
    5895        1660 :                 desDayInput.RainInd = (int)b;
    5896             :             } else {
    5897           0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(7), ipsc->cAlphaArgs(7), "No");
    5898           0 :                 desDayInput.RainInd = 0;
    5899             :             }
    5900             : 
    5901             :             //   A8,  \field Snow Indicator
    5902        1666 :             if (ipsc->lAlphaFieldBlanks(8)) {
    5903           6 :                 desDayInput.SnowInd = 0;
    5904        1660 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(8)))) != BooleanSwitch::Invalid) {
    5905        1660 :                 desDayInput.SnowInd = (int)b;
    5906             :             } else {
    5907           0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(8), ipsc->cAlphaArgs(8), "No");
    5908           0 :                 desDayInput.SnowInd = 0;
    5909             :             }
    5910             : 
    5911             :             //   A3,  \field Dry-Bulb Temperature Range Modifier Type
    5912             :             // check DB profile input
    5913        1666 :             if (ipsc->lAlphaFieldBlanks(3)) {
    5914        1532 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    5915         268 :             } else if ((desDayInput.dryBulbRangeType = static_cast<DesDayDryBulbRangeType>(
    5916         134 :                             getEnumValue(DesDayDryBulbRangeTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(3))))) != DesDayDryBulbRangeType::Invalid) {
    5917             :             } else {
    5918           0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5919           0 :                 ErrorsFound = true;
    5920           0 :                 desDayInput.dryBulbRangeType = DesDayDryBulbRangeType::Default;
    5921             :             }
    5922             : 
    5923        1666 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    5924           3 :                 units = "[]";
    5925           3 :                 unitType = Constant::Units::None;
    5926        1663 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) {
    5927           2 :                 units = "[deltaC]";
    5928           2 :                 unitType = Constant::Units::deltaC;
    5929        1661 :             } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    5930           1 :                 units = "[C]";
    5931           1 :                 unitType = Constant::Units::C;
    5932             :             }
    5933             : 
    5934        1666 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile && !MaxDryBulbEntered && ipsc->cAlphaArgs(3) != "invalid field") {
    5935           0 :                 ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(3), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    5936           0 :                 ErrorsFound = true;
    5937             :             }
    5938             : 
    5939             :             // Assume either "multiplier" option will make full use of range...
    5940        1666 :             if (desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Difference &&
    5941        1664 :                 desDayInput.dryBulbRangeType != DesDayDryBulbRangeType::Profile) {
    5942        1663 :                 Real64 testval = desDayInput.MaxDryBulb - desDayInput.DailyDBRange;
    5943        1663 :                 if (testval < -90.0 || testval > 70.0) {
    5944           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    5945           0 :                     ShowContinueError(state, format("{} ({.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(3), testval));
    5946           0 :                     ErrorsFound = true;
    5947             :                 }
    5948             :             }
    5949             : 
    5950             :             //   A4,  \field Dry-Bulb Temperature Range Modifier Day Schedule Name
    5951        1666 :             if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Default) {
    5952             :                 // Default dry-bulb temperature Range
    5953        1660 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    5954       41500 :                 for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    5955      267984 :                     for (int ts = 1; ts <= state.dataGlobal->NumOfTimeStepInHour; ++ts) {
    5956      228144 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    5957      228144 :                         Real64 WPrev = 1.0 - WNow;
    5958      228144 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutDryBulbTemp =
    5959      228144 :                             LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    5960             :                     }
    5961       39840 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    5962             :                 }
    5963             : 
    5964           6 :             } else if (ipsc->lAlphaFieldBlanks(4)) {
    5965           0 :                 ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaFieldNames(3), "SCHEDULE");
    5966           0 :                 ErrorsFound = true;
    5967             : 
    5968           6 :             } else if ((desDayInput.TempRangeSchPtr = ScheduleManager::GetDayScheduleIndex(state, ipsc->cAlphaArgs(4))) == 0) {
    5969           0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    5970           0 :                 ErrorsFound = true;
    5971             : 
    5972             :             } else {
    5973          12 :                 Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    5974           6 :                 ScheduleManager::GetSingleDayScheduleValues(state, desDayInput.TempRangeSchPtr, tmp);
    5975           6 :                 auto &desDayModEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    5976         150 :                 for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr) {
    5977         720 :                     for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS) {
    5978         576 :                         desDayModEnvrn(iTS, iHr).OutDryBulbTemp = tmp(iTS, iHr);
    5979             :                     }
    5980             :                 }
    5981             : 
    5982           6 :                 if (std::find(state.dataWeather->spSiteSchedNums.begin(), state.dataWeather->spSiteSchedNums.end(), desDayInput.TempRangeSchPtr) ==
    5983          12 :                     state.dataWeather->spSiteSchedNums.end()) {
    5984           4 :                     state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.TempRangeSchPtr);
    5985           8 :                     SetupOutputVariable(state,
    5986             :                                         "Sizing Period Site Drybulb Temperature Range Modifier Schedule Value",
    5987             :                                         unitType,
    5988           4 :                                         state.dataWeather->spSiteSchedules(EnvrnNum).OutDryBulbTemp,
    5989             :                                         OutputProcessor::TimeStepType::Zone,
    5990             :                                         OutputProcessor::StoreType::Average,
    5991           4 :                                         ipsc->cAlphaArgs(4));
    5992             :                 }
    5993             : 
    5994           6 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Multiplier) {
    5995           3 :                     if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.TempRangeSchPtr, 0.0, false, 1.0, false)) {
    5996           0 :                         ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    5997           0 :                         ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4)));
    5998           0 :                         ShowContinueError(state, "..Specified [Schedule] Dry-bulb Range Multiplier Values are not within [0.0, 1.0]");
    5999           0 :                         ErrorsFound = true;
    6000             :                     }
    6001           3 :                 } else if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Difference) { // delta, must be > 0.0
    6002           2 :                     if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.TempRangeSchPtr, 0.0, false)) {
    6003           0 :                         ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6004           0 :                         ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4)));
    6005           0 :                         ShowContinueError(state, "Some [Schedule] Dry-bulb Range Difference Values are < 0.0 [would make max larger].");
    6006           0 :                         ErrorsFound = true;
    6007             :                     }
    6008             :                 }
    6009             : 
    6010           6 :                 auto const &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6011           6 :                 Real64 testval = std::numeric_limits<Real64>::min();
    6012         150 :                 for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr) {
    6013         720 :                     for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS) {
    6014         576 :                         if (desDayModsEnvrn(iTS, iHr).OutDryBulbTemp > testval) testval = desDayModsEnvrn(iTS, iHr).OutDryBulbTemp;
    6015             :                     }
    6016             :                 }
    6017             : 
    6018           6 :                 if (desDayInput.dryBulbRangeType == DesDayDryBulbRangeType::Profile) {
    6019           1 :                     if (MaxDryBulbEntered) {
    6020           0 :                         ShowWarningError(state, format("{}=\"{}\", data override.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6021           0 :                         ShowContinueError(state, format("..{}=[{:.2R}] will be overwritten.", ipsc->cNumericFieldNames(3), desDayInput.MaxDryBulb));
    6022           0 :                         ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3)));
    6023           0 :                         ShowContinueError(state, format("..with max value=[{:.2R}].", testval));
    6024             :                     }
    6025           1 :                     desDayInput.MaxDryBulb = testval;
    6026             :                 }
    6027             : 
    6028           6 :                 testval = desDayInput.MaxDryBulb - testval;
    6029           6 :                 if (testval < -90.0 || testval > 70.0) {
    6030           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6031             :                     // should this be cNumericFieldNames?
    6032           0 :                     ShowContinueError(state, format("{} = ({.2R}) is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(4), testval));
    6033           0 :                     ErrorsFound = true;
    6034             :                 }
    6035           6 :             }
    6036             : 
    6037             :             //   A5,  \field Humidity Condition Type
    6038        1666 :             desDayInput.HumIndType = static_cast<DesDayHumIndType>(getEnumValue(DesDayHumIndTypeNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(5))));
    6039             : 
    6040        1666 :             switch (desDayInput.HumIndType) {
    6041        1640 :             case DesDayHumIndType::WetBulb: {
    6042             :                 //   N5,  \field Wetbulb or DewPoint at Maximum Dry-Bulb
    6043        1640 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6044           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6045           0 :                     ErrorsFound = true;
    6046             :                 } else {
    6047        1640 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6048             :                 }
    6049             : 
    6050        1640 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6051           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6052           0 :                     ShowContinueError(
    6053           0 :                         state, format("{} = {.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - WetBulb", desDayInput.HumIndValue));
    6054           0 :                     ErrorsFound = true;
    6055             :                 }
    6056        1640 :             } break;
    6057             : 
    6058           5 :             case DesDayHumIndType::DewPoint: {
    6059           5 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6060           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6061           0 :                     ErrorsFound = true;
    6062             :                 } else {
    6063           5 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6064             :                 }
    6065             : 
    6066           5 :                 if (desDayInput.HumIndValue < -90.0 || desDayInput.HumIndValue > 70.0) {
    6067           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6068           0 :                     ShowContinueError(
    6069             :                         state,
    6070           0 :                         format("{} = {.2R} is out of range [-90.0, 70.0]", ipsc->cAlphaFieldNames(5) + " - DewPoint", desDayInput.HumIndValue));
    6071           0 :                     ErrorsFound = true;
    6072             :                 }
    6073           5 :             } break;
    6074             : 
    6075           0 :             case DesDayHumIndType::HumRatio: {
    6076             :                 //   N6,  \field Humidity Ratio at Maximum Dry-Bulb
    6077           0 :                 if (ipsc->lNumericFieldBlanks(6)) {
    6078           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(6), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6079           0 :                     ErrorsFound = true;
    6080             :                 } else {
    6081           0 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(6); // Humidity Indicating Conditions at Max Dry-Bulb
    6082             :                 }
    6083             : 
    6084           0 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 0.03) {
    6085           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6086           0 :                     ShowContinueError(
    6087             :                         state,
    6088           0 :                         format("{} = {.2R} is out of range [0.0, 0.03]", ipsc->cAlphaFieldNames(5) + " - Humidity-Ratio", desDayInput.HumIndValue));
    6089           0 :                     ErrorsFound = true;
    6090             :                 }
    6091           0 :             } break;
    6092             : 
    6093           3 :             case DesDayHumIndType::Enthalpy: {
    6094             :                 //   N7,  \field Enthalpy at Maximum Dry-Bulb {J/kg}.
    6095           3 :                 if (ipsc->lNumericFieldBlanks(7)) {
    6096           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(7), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6097           0 :                     ErrorsFound = true;
    6098             :                 } else {
    6099           3 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(7); // Humidity Indicating Conditions at Max Dry-Bulb
    6100             :                 }
    6101             : 
    6102           3 :                 desDayInput.HumIndType = DesDayHumIndType::Enthalpy;
    6103           3 :                 if (desDayInput.HumIndValue < 0.0 || desDayInput.HumIndValue > 130000.0) {
    6104           0 :                     ShowSevereError(state, format("{}: {} = {}", routineName, ipsc->cCurrentModuleObject, desDayInput.Title));
    6105           0 :                     ShowContinueError(
    6106             :                         state,
    6107           0 :                         format("{} = {.0R} is out of range [0.0, 130000.0]", ipsc->cAlphaFieldNames(5) + " - Enthalpy", desDayInput.HumIndValue));
    6108           0 :                     ErrorsFound = true;
    6109             :                 }
    6110           3 :             } break;
    6111             : 
    6112           3 :             case DesDayHumIndType::RelHumSch: {
    6113           3 :                 units = "[%]";
    6114           3 :                 unitType = Constant::Units::Perc;
    6115           3 :             } break;
    6116             : 
    6117           2 :             case DesDayHumIndType::WBProfMul: {
    6118           2 :                 units = "[]";
    6119           2 :                 unitType = Constant::Units::None;
    6120           2 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6121           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6122           0 :                     ErrorsFound = true;
    6123             :                 } else {
    6124           2 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6125             :                 }
    6126           2 :             } break;
    6127             : 
    6128           1 :             case DesDayHumIndType::WBProfDif: {
    6129           1 :                 units = "[]";
    6130           1 :                 unitType = Constant::Units::None;
    6131           1 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6132           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6133           0 :                     ErrorsFound = true;
    6134             :                 } else {
    6135           1 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6136             :                 }
    6137           1 :             } break;
    6138             : 
    6139          12 :             case DesDayHumIndType::WBProfDef: {
    6140          12 :                 if (ipsc->lNumericFieldBlanks(5)) {
    6141           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cNumericFieldNames(5), ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
    6142           0 :                     ErrorsFound = true;
    6143             :                 } else {
    6144          12 :                     desDayInput.HumIndValue = ipsc->rNumericArgs(5); // Humidity Indicating Conditions at Max Dry-Bulb
    6145             :                 }
    6146          12 :             } break;
    6147             : 
    6148           0 :             default: {
    6149           0 :                 ShowWarningError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6150           0 :                 ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6151           0 :                 ShowContinueError(state, "WetBulb will be used. Maximum Dry Bulb will be used as WetBulb at Maximum Dry Bulb.");
    6152           0 :                 desDayInput.HumIndType = DesDayHumIndType::WetBulb;
    6153           0 :                 desDayInput.HumIndValue = ipsc->rNumericArgs(3);
    6154           0 :             } break;
    6155             :             } // switch (desDayInput.HumIndType)
    6156             : 
    6157             :             // resolve humidity schedule if needed
    6158             :             //   A6,  \field Humidity Condition Day Schedule Name
    6159        1666 :             if (desDayInput.HumIndType == DesDayHumIndType::RelHumSch || desDayInput.HumIndType == DesDayHumIndType::WBProfMul ||
    6160        1661 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6161           6 :                 if (ipsc->lAlphaFieldBlanks(6)) {
    6162           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6163           0 :                     ErrorsFound = true;
    6164           6 :                 } else if ((desDayInput.HumIndSchPtr = ScheduleManager::GetDayScheduleIndex(state, ipsc->cAlphaArgs(6))) == 0) {
    6165           0 :                     ShowWarningItemNotFound(state,
    6166             :                                             eoh,
    6167           0 :                                             ipsc->cAlphaFieldNames(6),
    6168           0 :                                             ipsc->cAlphaArgs(6),
    6169             :                                             "Default Humidity (constant for day using Humidity Indicator Temp).");
    6170             :                     // reset HumIndType ?
    6171             :                 } else {
    6172          12 :                     Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    6173           6 :                     ScheduleManager::GetSingleDayScheduleValues(state, desDayInput.HumIndSchPtr, tmp);
    6174             : 
    6175           6 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6176         150 :                     for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr)
    6177         720 :                         for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS)
    6178         576 :                             desDayModsEnvrn(iTS, iHr).OutRelHum = tmp(iTS, iHr);
    6179             : 
    6180           6 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(), state.dataWeather->spSiteSchedNums.end(), desDayInput.HumIndSchPtr) ==
    6181          12 :                         state.dataWeather->spSiteSchedNums.end()) {
    6182           5 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.HumIndSchPtr);
    6183          10 :                         SetupOutputVariable(state,
    6184             :                                             "Sizing Period Site Humidity Condition Schedule Value",
    6185             :                                             unitType,
    6186           5 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).OutRelHum,
    6187             :                                             OutputProcessor::TimeStepType::Zone,
    6188             :                                             OutputProcessor::StoreType::Average,
    6189           5 :                                             ipsc->cAlphaArgs(6));
    6190             :                     }
    6191             : 
    6192           6 :                     switch (desDayInput.HumIndType) {
    6193           3 :                     case DesDayHumIndType::RelHumSch: {
    6194           3 :                         if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.HumIndSchPtr, 0.0, false, 100.0, false)) {
    6195           0 :                             ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6196           0 :                             ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6)));
    6197           0 :                             ShowContinueError(state, "Specified [Scheduled] Relative Humidity Values are not within [0.0, 100.0]");
    6198           0 :                             ErrorsFound = true;
    6199             :                         }
    6200           3 :                     } break;
    6201           2 :                     case DesDayHumIndType::WBProfMul: {
    6202             :                         // multiplier: use schedule value, check 0 <= v <= 1
    6203           2 :                         if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.HumIndSchPtr, 0.0, false, 1.0, false)) {
    6204           0 :                             ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6205           0 :                             ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6)));
    6206           0 :                             ShowContinueError(state, "..Specified [Schedule] Wet-bulb Profile Range Multiplier Values are not within [0.0, 1.0]");
    6207           0 :                             ErrorsFound = true;
    6208             :                         }
    6209           2 :                     } break;
    6210           1 :                     case DesDayHumIndType::WBProfDif: {
    6211           1 :                         if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.HumIndSchPtr, 0.0, false)) {
    6212           0 :                             ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6213           0 :                             ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6)));
    6214           0 :                             ShowContinueError(state, "Some [Schedule] Wet-bulb Profile Difference Values are < 0.0 [would make max larger].");
    6215           0 :                             ErrorsFound = true;
    6216             :                         }
    6217           1 :                     } break;
    6218           0 :                     default: {
    6219           0 :                     } break;
    6220             :                     } // switch (desDayInput.HumIndType)
    6221           6 :                 }     // if (desDayInput.HumIndSchPtr == 0)
    6222             : 
    6223        1666 :             } else if (desDayInput.HumIndType == DesDayHumIndType::WBProfDef) {
    6224             :                 // re WetBulbProfileDefaultMultipliers
    6225          12 :                 Real64 LastHrValue = DefaultTempRangeMult[23];
    6226         300 :                 for (int hour = 1; hour <= Constant::HoursInDay; ++hour) {
    6227        1440 :                     for (int ts = 1; ts <= state.dataGlobal->NumOfTimeStepInHour; ++ts) {
    6228        1152 :                         Real64 WNow = state.dataWeather->Interpolation(ts);
    6229        1152 :                         Real64 WPrev = 1.0 - WNow;
    6230        1152 :                         state.dataWeather->desDayMods(EnvrnNum)(ts, hour).OutRelHum = LastHrValue * WPrev + DefaultTempRangeMult[hour - 1] * WNow;
    6231             :                     }
    6232         288 :                     LastHrValue = DefaultTempRangeMult[hour - 1];
    6233             :                 }
    6234             :             }
    6235             : 
    6236             :             // verify that design WB or DP <= design DB
    6237        1666 :             if (desDayInput.HumIndType == DesDayHumIndType::DewPoint || desDayInput.HumIndType == DesDayHumIndType::WetBulb ||
    6238          21 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfMul || desDayInput.HumIndType == DesDayHumIndType::WBProfDef ||
    6239           7 :                 desDayInput.HumIndType == DesDayHumIndType::WBProfDif) {
    6240        1660 :                 if (desDayInput.HumIndValue > desDayInput.MaxDryBulb) {
    6241           0 :                     ShowWarningError(state, format("{}=\"{}\", range check data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6242           0 :                     ShowContinueError(state,
    6243           0 :                                       format("..Humidity Indicator Temperature at Max Temperature={:.1R} > Max DryBulb={:.1R}",
    6244           0 :                                              desDayInput.HumIndValue,
    6245           0 :                                              desDayInput.MaxDryBulb));
    6246           0 :                     ShowContinueError(state, format("..{}=\"{}\".", ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5)));
    6247           0 :                     ShowContinueError(state, "..Conditions for day will be set to Relative Humidity = 100%");
    6248           0 :                     if (desDayInput.HumIndType == DesDayHumIndType::DewPoint) {
    6249           0 :                         desDayInput.DewPointNeedsSet = true;
    6250             :                     } else {
    6251             :                         // wet-bulb
    6252           0 :                         desDayInput.HumIndValue = desDayInput.MaxDryBulb;
    6253             :                     }
    6254             :                 }
    6255             :             }
    6256             : 
    6257             :             //   A10, \field Solar Model Indicator
    6258        1666 :             if (ipsc->lAlphaFieldBlanks(10)) {
    6259           6 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6260        3320 :             } else if ((desDayInput.solarModel = static_cast<DesDaySolarModel>(
    6261        1660 :                             getEnumValue(DesDaySolarModelNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(10))))) != DesDaySolarModel::Invalid) {
    6262             :             } else {
    6263           0 :                 ShowWarningInvalidKey(state, eoh, ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "ASHRAE ClearSky");
    6264           0 :                 desDayInput.solarModel = DesDaySolarModel::ASHRAE_ClearSky;
    6265             :             }
    6266             : 
    6267        1666 :             if (desDayInput.solarModel == DesDaySolarModel::SolarModel_Schedule) {
    6268             :                 //   A11, \field Beam Solar Day Schedule Name
    6269           3 :                 if (ipsc->lAlphaFieldBlanks(11)) {
    6270             :                     // should have entered beam schedule
    6271           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(11), "", "");
    6272           0 :                     ErrorsFound = true;
    6273           3 :                 } else if ((desDayInput.BeamSolarSchPtr = ScheduleManager::GetDayScheduleIndex(state, ipsc->cAlphaArgs(11))) == 0) {
    6274           0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11));
    6275           0 :                     ErrorsFound = true;
    6276             :                 } else {
    6277           6 :                     Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    6278           3 :                     ScheduleManager::GetSingleDayScheduleValues(state, desDayInput.BeamSolarSchPtr, tmp);
    6279           3 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6280          75 :                     for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr)
    6281         360 :                         for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS)
    6282         288 :                             desDayModsEnvrn(iTS, iHr).BeamSolarRad = tmp(iTS, iHr);
    6283             : 
    6284           3 :                     unitType = Constant::Units::W_m2;
    6285           3 :                     units = "[W/m2]";
    6286           6 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6287           6 :                                   state.dataWeather->spSiteSchedNums.end(),
    6288           9 :                                   desDayInput.BeamSolarSchPtr) == state.dataWeather->spSiteSchedNums.end()) {
    6289           3 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.BeamSolarSchPtr);
    6290           6 :                         SetupOutputVariable(state,
    6291             :                                             "Sizing Period Site Beam Solar Schedule Value",
    6292             :                                             unitType,
    6293           3 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).BeamSolarRad,
    6294             :                                             OutputProcessor::TimeStepType::Zone,
    6295             :                                             OutputProcessor::StoreType::Average,
    6296           3 :                                             ipsc->cAlphaArgs(11));
    6297             :                     }
    6298             : 
    6299           3 :                     if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.BeamSolarSchPtr, 0.0, false)) {
    6300           0 :                         ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6301           0 :                         ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(11), ipsc->cAlphaArgs(11)));
    6302           0 :                         ShowContinueError(state, "..Specified [Schedule] Values are not >= 0.0");
    6303           0 :                         ErrorsFound = true;
    6304             :                     }
    6305           3 :                 }
    6306             : 
    6307             :                 //   A12, \field Diffuse Solar Day Schedule Name
    6308           3 :                 if (ipsc->lAlphaFieldBlanks(12)) {
    6309             :                     // should have entered diffuse schedule
    6310           0 :                     ShowSevereEmptyField(state, eoh, ipsc->cAlphaFieldNames(12), "", "");
    6311           0 :                     ErrorsFound = true;
    6312           3 :                 } else if ((desDayInput.DiffuseSolarSchPtr = ScheduleManager::GetDayScheduleIndex(state, ipsc->cAlphaArgs(12))) == 0) {
    6313           0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12));
    6314           0 :                     ErrorsFound = true;
    6315             :                 } else {
    6316           6 :                     Array2D<Real64> tmp = Array2D<Real64>(state.dataGlobal->NumOfTimeStepInHour, Constant::HoursInDay);
    6317           3 :                     ScheduleManager::GetSingleDayScheduleValues(state, desDayInput.DiffuseSolarSchPtr, tmp);
    6318           3 :                     auto &desDayModsEnvrn = state.dataWeather->desDayMods(EnvrnNum);
    6319          75 :                     for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr)
    6320         360 :                         for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS)
    6321         288 :                             desDayModsEnvrn(iTS, iHr).DifSolarRad = tmp(iTS, iHr);
    6322             : 
    6323           3 :                     units = "[W/m2]";
    6324           3 :                     unitType = Constant::Units::W_m2;
    6325           6 :                     if (std::find(state.dataWeather->spSiteSchedNums.begin(),
    6326           6 :                                   state.dataWeather->spSiteSchedNums.end(),
    6327           9 :                                   desDayInput.DiffuseSolarSchPtr) == state.dataWeather->spSiteSchedNums.end()) {
    6328           3 :                         state.dataWeather->spSiteSchedNums.emplace_back(desDayInput.DiffuseSolarSchPtr);
    6329           6 :                         SetupOutputVariable(state,
    6330             :                                             "Sizing Period Site Diffuse Solar Schedule Value",
    6331             :                                             unitType,
    6332           3 :                                             state.dataWeather->spSiteSchedules(EnvrnNum).DifSolarRad,
    6333             :                                             OutputProcessor::TimeStepType::Zone,
    6334             :                                             OutputProcessor::StoreType::Average,
    6335           3 :                                             ipsc->cAlphaArgs(12));
    6336             :                     }
    6337           3 :                     if (!ScheduleManager::CheckDayScheduleValueMinMax(state, desDayInput.DiffuseSolarSchPtr, 0.0, false)) {
    6338           0 :                         ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6339           0 :                         ShowContinueError(state, format("..invalid field: {}=\"{}\".", ipsc->cAlphaFieldNames(12), ipsc->cAlphaArgs(12)));
    6340           0 :                         ShowContinueError(state, "..Specified [Schedule] Values are not >= 0.0");
    6341           0 :                         ErrorsFound = true;
    6342             :                     }
    6343           3 :                 }
    6344             : 
    6345        1663 :             } else if (desDayInput.solarModel == DesDaySolarModel::ASHRAE_ClearSky) {
    6346        1574 :                 if (ipsc->lNumericFieldBlanks(14)) {
    6347           0 :                     ShowWarningEmptyField(
    6348           0 :                         state, eoh, ipsc->cNumericFieldNames(14), ipsc->cAlphaFieldNames(10), ipsc->cAlphaArgs(10), "Zero clear sky (no solar)");
    6349             :                 }
    6350             :             }
    6351             : 
    6352             :             // Validate Design Day Month
    6353             : 
    6354        1666 :             switch (desDayInput.Month) {
    6355        1643 :             case 1:
    6356             :             case 3:
    6357             :             case 5:
    6358             :             case 7:
    6359             :             case 8:
    6360             :             case 10:
    6361             :             case 12: {
    6362        1643 :                 if (desDayInput.DayOfMonth > 31) {
    6363           0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6364           0 :                     ShowContinueError(
    6365             :                         state,
    6366           0 :                         format(".. invalid field: {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6367           0 :                     ErrorsFound = true;
    6368             :                 }
    6369        1643 :             } break;
    6370          21 :             case 4:
    6371             :             case 6:
    6372             :             case 9:
    6373             :             case 11: {
    6374          21 :                 if (desDayInput.DayOfMonth > 30) {
    6375           0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6376           0 :                     ShowContinueError(
    6377           0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6378           0 :                     ErrorsFound = true;
    6379             :                 }
    6380          21 :             } break;
    6381           2 :             case 2: {
    6382           2 :                 if (desDayInput.DayOfMonth > 28) {
    6383           0 :                     ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6384           0 :                     ShowContinueError(
    6385           0 :                         state, format(".. invalid {}=[{}], Month=[{}].", ipsc->cNumericFieldNames(2), desDayInput.DayOfMonth, desDayInput.Month));
    6386           0 :                     ErrorsFound = true;
    6387             :                 }
    6388           2 :             } break;
    6389           0 :             default: {
    6390           0 :                 ShowSevereError(state, format("{}=\"{}\", invalid data.", ipsc->cCurrentModuleObject, desDayInput.Title));
    6391           0 :                 ShowContinueError(state, format(".. invalid {} invalid (Month) [{}].", ipsc->cNumericFieldNames(1), desDayInput.Month));
    6392           0 :                 ErrorsFound = true;
    6393           0 :             } break;
    6394             :             } // switch (desDayInput.Month)
    6395             : 
    6396             :             //   A9,  \field Daylight Saving Time Indicator
    6397        1666 :             if (ipsc->lAlphaFieldBlanks(9)) {
    6398           6 :                 desDayInput.DSTIndicator = 0;
    6399        1660 :             } else if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(9)))) != BooleanSwitch::Invalid) {
    6400        1660 :                 desDayInput.DSTIndicator = (int)b;
    6401             :             } else {
    6402           0 :                 ShowWarningInvalidBool(state, eoh, ipsc->cAlphaFieldNames(9), ipsc->cAlphaArgs(9), "No");
    6403           0 :                 desDayInput.DSTIndicator = 0;
    6404             :             }
    6405             : 
    6406             :             //   A2,  \field Day Type
    6407        1666 :             desDayInput.DayType = getEnumValue(ScheduleManager::dayTypeNamesUC, ipsc->cAlphaArgs(2));
    6408        1666 :             if (desDayInput.DayType <= 0) {
    6409           0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
    6410           0 :                 ErrorsFound = true;
    6411             :             }
    6412             : 
    6413        1666 :             auto &designDay = state.dataWeather->DesignDay(EnvrnNum);
    6414        1666 :             envCurr.Title = desDayInput.Title;
    6415        1666 :             envCurr.KindOfEnvrn = Constant::KindOfSim::DesignDay;
    6416        1666 :             envCurr.DesignDayNum = EnvrnNum;
    6417        1666 :             envCurr.RunPeriodDesignNum = 0;
    6418        1666 :             envCurr.TotalDays = 1;
    6419        1666 :             envCurr.StartMonth = desDayInput.Month;
    6420        1666 :             envCurr.StartDay = desDayInput.DayOfMonth;
    6421        1666 :             envCurr.EndMonth = envCurr.StartMonth;
    6422        1666 :             envCurr.EndDay = envCurr.StartDay;
    6423        1666 :             envCurr.DayOfWeek = 0;
    6424        1666 :             envCurr.UseDST = false;
    6425        1666 :             envCurr.UseHolidays = false;
    6426        1666 :             envCurr.StartJDay = designDay.DayOfYear;
    6427        1666 :             envCurr.EndJDay = envCurr.StartJDay;
    6428             : 
    6429             :             // create predefined report on design day
    6430        1666 :             std::string envTitle = desDayInput.Title;
    6431        1666 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDmaxDB, envTitle, desDayInput.MaxDryBulb);
    6432        1666 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDrange, envTitle, desDayInput.DailyDBRange);
    6433        1666 :             if (desDayInput.HumIndType != DesDayHumIndType::RelHumSch) {
    6434        1663 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, desDayInput.HumIndValue);
    6435             :             } else {
    6436           3 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDhumid, envTitle, "N/A");
    6437             :             }
    6438        3332 :             OutputReportPredefined::PreDefTableEntry(
    6439        3332 :                 state, state.dataOutRptPredefined->pdchDDhumTyp, envTitle, DesDayHumIndTypeStringRep[(int)desDayInput.HumIndType]);
    6440        1666 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindSp, envTitle, desDayInput.WindSpeed);
    6441        1666 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDDwindDr, envTitle, desDayInput.WindDir);
    6442             :         }
    6443         796 :     }
    6444             : 
    6445         796 :     void GetLocationInfo(EnergyPlusData &state, bool &ErrorsFound)
    6446             :     {
    6447             : 
    6448             :         // SUBROUTINE INFORMATION:
    6449             :         //       AUTHOR         Richard Liesen
    6450             :         //       DATE WRITTEN   October 1997
    6451             : 
    6452             :         // PURPOSE OF THIS SUBROUTINE:
    6453             :         // This subroutine gets the location info from the IDF file; latitude,
    6454             :         //  longitude and time zone number.
    6455             : 
    6456         796 :         auto const &ipsc = state.dataIPShortCut;
    6457         796 :         ipsc->cCurrentModuleObject = "Site:Location";
    6458         796 :         int const NumLocations = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6459             : 
    6460         796 :         if (NumLocations > 1) {
    6461           0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6462           0 :             ErrorsFound = true;
    6463             :         }
    6464             : 
    6465         796 :         if (NumLocations == 1) {
    6466             :             int LocNumAlpha;             // Number of alpha names being passed
    6467             :             int LocNumProp;              // Number of properties being passed
    6468             :             int IOStat;                  // IO Status when calling get input subroutine
    6469         789 :             Array1D_string LocAlphas(2); // Temporary array to transfer location info (non-numerics)
    6470         789 :             Array1D<Real64> LocProps(4); // Temporary array to transfer location info (numerics)
    6471             :             // Call Input Get routine to retrieve Location information
    6472        1578 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    6473         789 :                 state, ipsc->cCurrentModuleObject, 1, LocAlphas, LocNumAlpha, LocProps, LocNumProp, IOStat);
    6474             : 
    6475             :             // set latitude, longitude, and time zone number variables
    6476         789 :             state.dataWeather->LocationTitle = LocAlphas(1);
    6477         789 :             state.dataEnvrn->Latitude = LocProps(1);
    6478         789 :             state.dataEnvrn->Longitude = LocProps(2);
    6479         789 :             state.dataEnvrn->TimeZoneNumber = LocProps(3);
    6480         789 :             state.dataEnvrn->Elevation = LocProps(4);
    6481         789 :             if (Util::SameString(LocAlphas(2), "Yes")) state.dataWeather->keepUserSiteLocationDefinition = true;
    6482         789 :             state.dataWeather->LocationGathered = true;
    6483         789 :         }
    6484         796 :     }
    6485             : 
    6486         796 :     void GetWeatherProperties(EnergyPlusData &state, bool &ErrorsFound)
    6487             :     {
    6488             : 
    6489             :         // SUBROUTINE INFORMATION:
    6490             :         //       AUTHOR         Linda Lawrie
    6491             :         //       DATE WRITTEN   July 2009
    6492             : 
    6493             :         // PURPOSE OF THIS SUBROUTINE:
    6494             :         // Weather properties are an advanced concept for simulation.  Primarily, these properties are
    6495             :         // used in the test suite runs that have specific requirements for certain properties (such as
    6496             :         // sky temperature).
    6497             : 
    6498             :         // REFERENCES:
    6499             :         // WeatherProperty:SkyTemperature,
    6500             :         //        \memo This object is used to override internal sky temperature calculations.
    6501             :         //   A1,  \field Name
    6502             :         //        \reference DesignDays
    6503             :         //        \note leave blank for RunPeriods (until we name them)
    6504             :         //        \note This field references the applicable design day or runperiod(s) if left blank.
    6505             :         //   A2,  \field Calculation Type
    6506             :         //        \type choice
    6507             :         //        \key ScheduleValue
    6508             :         //        \key DifferenceScheduleDryBulbValue
    6509             :         //        \key DifferenceScheduleDewPointValue
    6510             :         //        \key AlgorithmA
    6511             :         //   A3;  \field Schedule Name
    6512             :         //        \type object-list
    6513             :         //        \object-list DayScheduleNames
    6514             :         //        \object-list ScheduleNames
    6515             : 
    6516             :         static constexpr std::string_view routineName = "GetWeatherProperties";
    6517             : 
    6518             :         int Found;
    6519             :         int envFound;
    6520             : 
    6521         796 :         auto const &ipsc = state.dataIPShortCut;
    6522         796 :         ipsc->cCurrentModuleObject = "WeatherProperty:SkyTemperature";
    6523         796 :         state.dataWeather->NumWPSkyTemperatures = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6524             : 
    6525         796 :         state.dataWeather->WPSkyTemperature.allocate(state.dataWeather->NumWPSkyTemperatures); // by default, not used.
    6526             : 
    6527         798 :         for (int i = 1; i <= state.dataWeather->NumWPSkyTemperatures; ++i) {
    6528             :             int IOStat;
    6529             :             int NumAlpha;
    6530             :             int NumNumerics;
    6531           4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6532           2 :                                                                      ipsc->cCurrentModuleObject,
    6533             :                                                                      i,
    6534           2 :                                                                      ipsc->cAlphaArgs,
    6535             :                                                                      NumAlpha,
    6536           2 :                                                                      ipsc->rNumericArgs,
    6537             :                                                                      NumNumerics,
    6538             :                                                                      IOStat,
    6539           2 :                                                                      ipsc->lNumericFieldBlanks,
    6540           2 :                                                                      ipsc->lAlphaFieldBlanks,
    6541           2 :                                                                      ipsc->cAlphaFieldNames,
    6542           2 :                                                                      ipsc->cNumericFieldNames);
    6543             : 
    6544           2 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ipsc->cAlphaArgs(1)};
    6545           2 :             auto &wpSkyTemp = state.dataWeather->WPSkyTemperature(i);
    6546           2 :             if (ipsc->cAlphaArgs(1).empty()) {
    6547           1 :                 Found = 0;
    6548          14 :                 for (int j = 1; j <= state.dataWeather->NumOfEnvrn; ++j) {
    6549          13 :                     auto &environJ = state.dataWeather->Environment(j);
    6550          13 :                     if (environJ.KindOfEnvrn != Constant::KindOfSim::RunPeriodWeather) continue;
    6551           1 :                     if (environJ.WP_Type1 != 0) {
    6552           0 :                         ShowSevereError(state,
    6553           0 :                                         format("{}: {}=\"{}\", indicated Environment Name already assigned.",
    6554             :                                                routineName,
    6555           0 :                                                ipsc->cCurrentModuleObject,
    6556           0 :                                                ipsc->cAlphaArgs(1)));
    6557           0 :                         if (!environJ.Title.empty()) {
    6558           0 :                             ShowContinueError(state,
    6559           0 :                                               format("...Environment=\"{}\", already using {}=\"{}\".",
    6560           0 :                                                      environJ.Title,
    6561           0 :                                                      ipsc->cCurrentModuleObject,
    6562           0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6563             :                         } else {
    6564           0 :                             ShowContinueError(state,
    6565           0 :                                               format("... Runperiod Environment, already using {}=\"{}\".",
    6566           0 :                                                      ipsc->cCurrentModuleObject,
    6567           0 :                                                      state.dataWeather->WPSkyTemperature(environJ.WP_Type1).Name));
    6568             :                         }
    6569           0 :                         ErrorsFound = true;
    6570             :                     } else {
    6571           1 :                         environJ.WP_Type1 = i;
    6572           1 :                         Found = j;
    6573             :                     }
    6574             :                 }
    6575           1 :                 if (Found == 0) {
    6576           0 :                     ShowWarningError(state, "GetWeatherProperties: WeatherProperty:SkyTemperature=blank, no run periods found.");
    6577           0 :                     ShowContinueError(state, "...SkyTemperature will not be applied.");
    6578           0 :                     continue;
    6579             :                 }
    6580             :             } else { // really a name
    6581           1 :                 Found = Util::FindItemInList(ipsc->cAlphaArgs(1), state.dataWeather->Environment, &EnvironmentData::Title);
    6582           1 :                 envFound = Found;
    6583           1 :                 if (Found == 0) {
    6584           0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), ipsc->cAlphaArgs(1));
    6585           0 :                     ErrorsFound = true;
    6586           0 :                     continue;
    6587             :                 }
    6588             : 
    6589           1 :                 auto &envrnFound = state.dataWeather->Environment(Found);
    6590           1 :                 if (envrnFound.WP_Type1 != 0) {
    6591           0 :                     ShowSevereError(state,
    6592           0 :                                     format("{}:{}=\"{}\", indicated Environment Name already assigned.",
    6593             :                                            routineName,
    6594           0 :                                            ipsc->cCurrentModuleObject,
    6595           0 :                                            ipsc->cAlphaArgs(1)));
    6596           0 :                     ShowContinueError(state,
    6597           0 :                                       format("...Environment=\"{}\", already using {}=\"{}\".",
    6598           0 :                                              envrnFound.Title,
    6599           0 :                                              ipsc->cCurrentModuleObject,
    6600           0 :                                              state.dataWeather->WPSkyTemperature(envrnFound.WP_Type1).Name));
    6601           0 :                     ErrorsFound = true;
    6602             :                 } else {
    6603           1 :                     state.dataWeather->Environment(Found).WP_Type1 = i;
    6604             :                 }
    6605             :             }
    6606             : 
    6607           2 :             wpSkyTemp.Name = !ipsc->lAlphaFieldBlanks(1) ? ipsc->cAlphaArgs(1) : "All RunPeriods";
    6608             : 
    6609             :             // Validate Calculation Type.
    6610           2 :             std::string units;
    6611             :             Constant::Units unitType;
    6612           2 :             wpSkyTemp.skyTempModel = static_cast<SkyTempModel>(getEnumValue(Weather::SkyTempModelNamesUC, ipsc->cAlphaArgs(2)));
    6613             : 
    6614           2 :             switch (wpSkyTemp.skyTempModel) {
    6615           2 :             case SkyTempModel::ScheduleValue: {
    6616           2 :                 wpSkyTemp.IsSchedule = true;
    6617           2 :                 units = "[C]";
    6618           2 :                 unitType = Constant::Units::C;
    6619           2 :             } break;
    6620           0 :             case SkyTempModel::DryBulbDelta:
    6621             :             case SkyTempModel::DewPointDelta: {
    6622           0 :                 wpSkyTemp.IsSchedule = true;
    6623           0 :                 units = "[deltaC]";
    6624           0 :                 unitType = Constant::Units::deltaC;
    6625           0 :             } break;
    6626           0 :             case SkyTempModel::Brunt:
    6627             :             case SkyTempModel::Idso:
    6628             :             case SkyTempModel::BerdahlMartin:
    6629             :             case SkyTempModel::ClarkAllen: {
    6630           0 :                 wpSkyTemp.IsSchedule = false;
    6631           0 :             } break;
    6632           0 :             default: {
    6633             :                 // Bad inputs are trapped by input processor
    6634           0 :                 assert(false);
    6635             :             }
    6636             :             }
    6637             : 
    6638           2 :             if (wpSkyTemp.IsSchedule) {
    6639           2 :                 wpSkyTemp.ScheduleName = ipsc->cAlphaArgs(3);
    6640           3 :                 if (state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodWeather ||
    6641           1 :                     state.dataWeather->Environment(Found).KindOfEnvrn == Constant::KindOfSim::RunPeriodDesign) {
    6642           1 :                     wpSkyTemp.ScheduleName = ipsc->cAlphaArgs(3);
    6643             :                     // See if it's a schedule.
    6644           1 :                     Found = ScheduleManager::GetScheduleIndex(state, ipsc->cAlphaArgs(3));
    6645           1 :                     if (Found == 0) {
    6646           0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6647           0 :                         ErrorsFound = true;
    6648             :                     } else {
    6649           1 :                         wpSkyTemp.IsSchedule = true;
    6650           1 :                         wpSkyTemp.SchedulePtr = Found;
    6651             :                     }
    6652             :                 } else { // See if it's a valid schedule.
    6653           1 :                     Found = ScheduleManager::GetDayScheduleIndex(state, ipsc->cAlphaArgs(3));
    6654           1 :                     if (Found == 0) {
    6655           0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
    6656           0 :                         ErrorsFound = true;
    6657             :                     } else {
    6658           1 :                         if (envFound != 0) {
    6659           1 :                             if (std::find(state.dataWeather->spSiteSchedNums.begin(), state.dataWeather->spSiteSchedNums.end(), Found) ==
    6660           2 :                                 state.dataWeather->spSiteSchedNums.end()) {
    6661           1 :                                 state.dataWeather->spSiteSchedNums.emplace_back(Found);
    6662           2 :                                 SetupOutputVariable(state,
    6663             :                                                     "Sizing Period Site Sky Temperature Schedule Value",
    6664             :                                                     unitType,
    6665           1 :                                                     state.dataWeather->spSiteSchedules(envFound).SkyTemp,
    6666             :                                                     OutputProcessor::TimeStepType::Zone,
    6667             :                                                     OutputProcessor::StoreType::Average,
    6668           1 :                                                     ipsc->cAlphaArgs(3));
    6669             :                             }
    6670           1 :                             wpSkyTemp.IsSchedule = true;
    6671           1 :                             wpSkyTemp.SchedulePtr = Found;
    6672             :                         }
    6673             :                     }
    6674             :                 }
    6675             :             }
    6676             : 
    6677             :             BooleanSwitch b;
    6678           2 :             if (!wpSkyTemp.IsSchedule && !ipsc->lAlphaFieldBlanks(4)) {
    6679           0 :                 if ((b = getYesNoValue(Util::makeUPPER(ipsc->cAlphaArgs(4)))) != BooleanSwitch::Invalid) {
    6680           0 :                     wpSkyTemp.UseWeatherFileHorizontalIR = static_cast<bool>(b);
    6681             :                 } else {
    6682           0 :                     ShowSevereInvalidBool(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
    6683           0 :                     ErrorsFound = true;
    6684             :                 }
    6685             :             } else {
    6686           2 :                 wpSkyTemp.UseWeatherFileHorizontalIR = true;
    6687             :             }
    6688           2 :         }
    6689        3652 :         for (auto &envCurr : state.dataWeather->Environment) {
    6690        2856 :             if (envCurr.WP_Type1 != 0 && state.dataWeather->NumWPSkyTemperatures >= envCurr.WP_Type1) {
    6691           2 :                 envCurr.skyTempModel = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).skyTempModel;
    6692           2 :                 envCurr.UseWeatherFileHorizontalIR = state.dataWeather->WPSkyTemperature(envCurr.WP_Type1).UseWeatherFileHorizontalIR;
    6693             :             }
    6694             :         }
    6695         796 :     }
    6696             : 
    6697         796 :     void GetGroundTemps(EnergyPlusData &state)
    6698             :     {
    6699             : 
    6700             :         // SUBROUTINE INFORMATION:
    6701             :         //       AUTHOR         Richard Liesen
    6702             :         //       DATE WRITTEN   October 1997
    6703             : 
    6704             :         // PURPOSE OF THIS SUBROUTINE:
    6705             :         // This file reads the Ground Temps from the input file and puts them
    6706             :         //  in a new variable.
    6707             : 
    6708             :         // Initialize Site:GroundTemperature:BuildingSurface object
    6709        2388 :         state.dataWeather->siteBuildingSurfaceGroundTempsPtr = GroundTemperatureManager::GetGroundTempModelAndInit(
    6710        1592 :             state, GroundTemperatureManager::groundTempModelNamesUC[(int)GroundTempObjType::SiteBuildingSurfaceGroundTemp], "");
    6711             : 
    6712             :         // Initialize Site:GroundTemperature:FCFactorMethod object
    6713        2388 :         state.dataWeather->siteFCFactorMethodGroundTempsPtr = GroundTemperatureManager::GetGroundTempModelAndInit(
    6714        1592 :             state, GroundTemperatureManager::groundTempModelNamesUC[static_cast<int>(GroundTempObjType::SiteFCFactorMethodGroundTemp)], "");
    6715             : 
    6716             :         // Initialize Site:GroundTemperature:Shallow object
    6717        2388 :         state.dataWeather->siteShallowGroundTempsPtr = GroundTemperatureManager::GetGroundTempModelAndInit(
    6718        1592 :             state, GroundTemperatureManager::groundTempModelNamesUC[static_cast<int>(GroundTempObjType::SiteShallowGroundTemp)], "");
    6719             : 
    6720             :         // Initialize Site:GroundTemperature:Deep object
    6721        2388 :         state.dataWeather->siteDeepGroundTempsPtr = GroundTemperatureManager::GetGroundTempModelAndInit(
    6722        1592 :             state, GroundTemperatureManager::groundTempModelNamesUC[static_cast<int>(GroundTempObjType::SiteDeepGroundTemp)], "");
    6723         796 :     }
    6724             : 
    6725         796 :     void GetGroundReflectances(EnergyPlusData &state, bool &ErrorsFound)
    6726             :     {
    6727             : 
    6728             :         // SUBROUTINE INFORMATION:
    6729             :         //       AUTHOR         Linda Lawrie
    6730             :         //       DATE WRITTEN   March 2002
    6731             : 
    6732             :         // PURPOSE OF THIS SUBROUTINE:
    6733             :         // This file reads the Ground Reflectances from the input file (optional) and
    6734             :         // places them in the monthly array.
    6735             : 
    6736         796 :         auto const &ipsc = state.dataIPShortCut;
    6737         796 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance";
    6738         796 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6739         796 :         if (nObjs != 0) {
    6740           3 :             Array1D_string GndAlphas(1);  // Construction Alpha names defined
    6741           3 :             Array1D<Real64> GndProps(12); // Temporary array to transfer ground reflectances
    6742           3 :             if (nObjs == 1) {
    6743             :                 int GndNumAlpha; // Number of construction alpha names being passed
    6744             :                 int GndNumProp;  // dummy variable for properties being passed
    6745             :                 int IOStat;      // IO Status when calling get input subroutine
    6746             :                 // Get the object names for each construction from the input processor
    6747           6 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6748           3 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6749             : 
    6750           3 :                 if (GndNumProp < 12) {
    6751           0 :                     ShowSevereError(state, format("{}: Less than 12 values entered.", ipsc->cCurrentModuleObject));
    6752           0 :                     ErrorsFound = true;
    6753             :                 }
    6754             : 
    6755             :                 // Assign the ground reflectances to the variable
    6756           3 :                 state.dataWeather->GroundReflectances({1, 12}) = GndProps({1, 12});
    6757             : 
    6758             :             } else {
    6759           0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6760           0 :                 ErrorsFound = true;
    6761             :             }
    6762           3 :         }
    6763             : 
    6764             :         // Write Final Ground Reflectance Information to the initialization output file
    6765         796 :         print(state.files.eio,
    6766             :               "{}\n",
    6767             :               "! "
    6768             :               "<Site:GroundReflectance>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{dimensionless},"
    6769             :               "May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{dimensionless},Oct{"
    6770             :               "dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6771             : 
    6772         796 :         print(state.files.eio, " Site:GroundReflectance");
    6773       10348 :         for (int i = 1; i <= 12; ++i) {
    6774        9552 :             print(state.files.eio, ", {:5.2F}", state.dataWeather->GroundReflectances(i));
    6775             :         }
    6776         796 :         print(state.files.eio, "\n");
    6777         796 :     }
    6778             : 
    6779         796 :     void GetSnowGroundRefModifiers(EnergyPlusData &state, bool &ErrorsFound)
    6780             :     {
    6781             : 
    6782             :         // SUBROUTINE INFORMATION:
    6783             :         //       AUTHOR         Linda Lawrie
    6784             :         //       DATE WRITTEN   March 2002
    6785             : 
    6786             :         // PURPOSE OF THIS SUBROUTINE:
    6787             :         // This file reads the Snow Ground Reflectance Modifiers from the input file (optional) and
    6788             :         // places them in the variables.
    6789             : 
    6790         796 :         auto const &ipsc = state.dataIPShortCut;
    6791         796 :         ipsc->cCurrentModuleObject = "Site:GroundReflectance:SnowModifier";
    6792         796 :         int nObjs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6793         796 :         if (nObjs != 0) {
    6794           2 :             Array1D_string GndAlphas(1); // Construction Alpha names defined
    6795           2 :             Array1D<Real64> GndProps(2); // Temporary array to transfer ground reflectances
    6796           2 :             if (nObjs == 1) {
    6797             :                 int GndNumAlpha; // Number of construction alpha names being passed
    6798             :                 int GndNumProp;  // dummy variable for properties being passed
    6799             :                 int IOStat;      // IO Status when calling get input subroutine
    6800             :                 // Get the object names for each construction from the input processor
    6801           4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    6802           2 :                     state, ipsc->cCurrentModuleObject, 1, GndAlphas, GndNumAlpha, GndProps, GndNumProp, IOStat);
    6803             : 
    6804             :                 // Assign the ground reflectances to the variable
    6805           2 :                 state.dataWeather->SnowGndRefModifier = GndProps(1);
    6806           2 :                 state.dataWeather->SnowGndRefModifierForDayltg = GndProps(2);
    6807             : 
    6808             :             } else {
    6809           0 :                 ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6810           0 :                 ErrorsFound = true;
    6811             :             }
    6812           2 :         }
    6813             : 
    6814             :         // Write Final Ground Reflectance Modifier Information to the initialization output file
    6815         796 :         print(state.files.eio, "{}\n", "! <Site:GroundReflectance:SnowModifier>, Normal, Daylighting {dimensionless}");
    6816             :         static constexpr std::string_view Format_720(" Site:GroundReflectance:SnowModifier, {:7.3F}, {:7.3F}\n");
    6817         796 :         print(state.files.eio, Format_720, state.dataWeather->SnowGndRefModifier, state.dataWeather->SnowGndRefModifierForDayltg);
    6818             : 
    6819         796 :         print(state.files.eio,
    6820             :               "{}\n",
    6821             :               "! "
    6822             :               "<Site:GroundReflectance:Snow>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    6823             :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    6824             :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6825         796 :         print(state.files.eio, "{}", " Site:GroundReflectance:Snow");
    6826       10348 :         for (int i = 1; i <= 12; ++i) {
    6827        9552 :             print(state.files.eio, ", {:5.2F}", max(min(state.dataWeather->GroundReflectances(i) * state.dataWeather->SnowGndRefModifier, 1.0), 0.0));
    6828             :         }
    6829         796 :         print(state.files.eio, "\n");
    6830         796 :         print(state.files.eio,
    6831             :               "{}\n",
    6832             :               "! "
    6833             :               "<Site:GroundReflectance:Snow:Daylighting>,Jan{dimensionless},Feb{dimensionless},Mar{dimensionless},Apr{"
    6834             :               "dimensionless},May{dimensionless},Jun{dimensionless},Jul{dimensionless},Aug{dimensionless},Sep{"
    6835             :               "dimensionless},Oct{dimensionless},Nov{dimensionless},Dec{dimensionless}");
    6836         796 :         print(state.files.eio, " Site:GroundReflectance:Snow:Daylighting");
    6837       10348 :         for (nObjs = 1; nObjs <= 12; ++nObjs) {
    6838        9552 :             print(state.files.eio,
    6839             :                   ", {:5.2F}",
    6840       19104 :                   max(min(state.dataWeather->GroundReflectances(nObjs) * state.dataWeather->SnowGndRefModifierForDayltg, 1.0), 0.0));
    6841             :         }
    6842         796 :         print(state.files.eio, "\n");
    6843         796 :     }
    6844             : 
    6845         796 :     void GetWaterMainsTemperatures(EnergyPlusData &state, bool &ErrorsFound)
    6846             :     {
    6847             : 
    6848             :         // SUBROUTINE INFORMATION:
    6849             :         //       AUTHOR         Peter Graham Ellis
    6850             :         //       DATE WRITTEN   January 2005
    6851             : 
    6852             :         // PURPOSE OF THIS SUBROUTINE:
    6853             :         // Reads the input data for the WATER MAINS TEMPERATURES object.
    6854             : 
    6855         796 :         constexpr std::string_view routineName = "GetWaterMainsTemperatures";
    6856             : 
    6857         796 :         auto const &ipsc = state.dataIPShortCut;
    6858         796 :         ipsc->cCurrentModuleObject = "Site:WaterMainsTemperature";
    6859         796 :         int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    6860             : 
    6861         796 :         if (NumObjects == 1) {
    6862             :             int NumAlphas;               // Number of elements in the alpha array
    6863             :             int NumNums;                 // Number of elements in the numeric array
    6864             :             int IOStat;                  // IO Status when calling get input subroutine
    6865         129 :             Array1D_string AlphArray(2); // Character string data
    6866         129 :             Array1D<Real64> NumArray(2); // Numeric data
    6867         387 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6868         129 :                                                                      ipsc->cCurrentModuleObject,
    6869             :                                                                      1,
    6870             :                                                                      AlphArray,
    6871             :                                                                      NumAlphas,
    6872             :                                                                      NumArray,
    6873             :                                                                      NumNums,
    6874             :                                                                      IOStat,
    6875         129 :                                                                      ipsc->lNumericFieldBlanks,
    6876         129 :                                                                      ipsc->lAlphaFieldBlanks,
    6877         129 :                                                                      ipsc->cAlphaFieldNames,
    6878         129 :                                                                      ipsc->cNumericFieldNames);
    6879             : 
    6880         129 :             ErrorObjectHeader eoh{routineName, ipsc->cCurrentModuleObject, ""};
    6881             : 
    6882         258 :             state.dataWeather->WaterMainsTempsMethod =
    6883         129 :                 static_cast<Weather::WaterMainsTempCalcMethod>(getEnumValue(waterMainsCalcMethodNamesUC, AlphArray(1)));
    6884             : 
    6885         129 :             switch (state.dataWeather->WaterMainsTempsMethod) {
    6886           3 :             case WaterMainsTempCalcMethod::Schedule: {
    6887           3 :                 state.dataWeather->WaterMainsTempsScheduleName = AlphArray(2);
    6888           3 :                 state.dataWeather->WaterMainsTempsSchedule = ScheduleManager::GetScheduleIndex(state, AlphArray(2));
    6889           3 :                 if (state.dataWeather->WaterMainsTempsSchedule == 0) {
    6890           0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(2), AlphArray(2));
    6891           0 :                     ErrorsFound = true;
    6892             :                 }
    6893           3 :             } break;
    6894         126 :             case WaterMainsTempCalcMethod::Correlation: {
    6895         126 :                 if (NumNums == 0) {
    6896           0 :                     ShowSevereError(state, format("{}: Missing Annual Average and Maximum Difference fields.", ipsc->cCurrentModuleObject));
    6897           0 :                     ErrorsFound = true;
    6898         126 :                 } else if (NumNums == 1) {
    6899           0 :                     ShowSevereError(state, format("{}: Missing Maximum Difference field.", ipsc->cCurrentModuleObject));
    6900           0 :                     ErrorsFound = true;
    6901             :                 } else {
    6902         126 :                     state.dataWeather->WaterMainsTempsAnnualAvgAirTemp = NumArray(1);
    6903         126 :                     state.dataWeather->WaterMainsTempsMaxDiffAirTemp = NumArray(2);
    6904             :                 }
    6905         126 :             } break;
    6906           0 :             case WaterMainsTempCalcMethod::CorrelationFromWeatherFile: {
    6907             :                 // No action
    6908           0 :             } break;
    6909           0 :             default: {
    6910           0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(1), AlphArray(1));
    6911           0 :                 ErrorsFound = true;
    6912           0 :             } break;
    6913             :             } // switch
    6914             : 
    6915         796 :         } else if (NumObjects > 1) {
    6916           0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    6917           0 :             ErrorsFound = true;
    6918             :         }
    6919         796 :     }
    6920             : 
    6921     2900842 :     void CalcWaterMainsTemp(EnergyPlusData &state)
    6922             :     {
    6923             : 
    6924             :         // SUBROUTINE INFORMATION:
    6925             :         //       AUTHOR         Peter Graham Ellis
    6926             :         //       DATE WRITTEN   January 2005
    6927             :         //       MODIFIED       June 2018, B. Nigusse
    6928             : 
    6929             :         // PURPOSE OF THIS SUBROUTINE:
    6930             :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    6931             : 
    6932             :         // METHODOLOGY EMPLOYED:
    6933             :         // Water mains temperature is either taken from a schedule or calculated by a correlation.  The correlation
    6934             :         // is fit to Fahrenheit units, so the air temperature values are first convert to F, then mains temperature
    6935             :         // is calculated and converted back to C.
    6936             : 
    6937     2900842 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    6938        6942 :         case WaterMainsTempCalcMethod::Schedule:
    6939        6942 :             state.dataEnvrn->WaterMainsTemp = ScheduleManager::GetCurrentScheduleValue(state, state.dataWeather->WaterMainsTempsSchedule);
    6940        6942 :             break;
    6941      512386 :         case WaterMainsTempCalcMethod::Correlation:
    6942      512386 :             state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(
    6943      512386 :                 state, state.dataWeather->WaterMainsTempsAnnualAvgAirTemp, state.dataWeather->WaterMainsTempsMaxDiffAirTemp);
    6944      512386 :             break;
    6945           0 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    6946           0 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    6947           0 :                 state.dataEnvrn->WaterMainsTemp = WaterMainsTempFromCorrelation(state,
    6948           0 :                                                                                 state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp,
    6949           0 :                                                                                 state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff);
    6950             :             } else {
    6951           0 :                 state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    6952             :             }
    6953           0 :             break;
    6954     2381514 :         default:
    6955     2381514 :             state.dataEnvrn->WaterMainsTemp = 10.0; // 50 F
    6956     2381514 :             break;
    6957             :         }
    6958     2900842 :     }
    6959             : 
    6960      512386 :     Real64 WaterMainsTempFromCorrelation(EnergyPlusData &state, Real64 const AnnualOAAvgDryBulbTemp, Real64 const MonthlyOAAvgDryBulbTempMaxDiff)
    6961             :     {
    6962             : 
    6963             :         // SUBROUTINE INFORMATION:
    6964             :         //       AUTHOR         Peter Graham Ellis
    6965             :         //       DATE WRITTEN   January 2005
    6966             :         //       MODIFIED       B Nigusse June 2018 (Refactored)
    6967             : 
    6968             :         // PURPOSE OF THIS SUBROUTINE:
    6969             :         // Calculates the daily water mains temperature based on input data from the WATER MAINS TEMPERATURES object.
    6970             : 
    6971             :         // METHODOLOGY EMPLOYED:
    6972             :         // Water mains temperature calculated by a correlation.  The correlation is fit to Fahrenheit units, so the
    6973             :         // air temperature values are first convert to F, then mains temperature is calculated and converted back to C.
    6974             :         // used for Calculated Method: 'Correlation' and 'CorrelationFromWeatherFile'.
    6975             : 
    6976             :         // REFERENCES:
    6977             :         // Correlation developed by Jay Burch and Craig Christensen at NREL, described in:
    6978             :         // Hendron, R., Anderson, R., Christensen, C., Eastment, M., and Reeves, P.  2004.  "Development of an Energy
    6979             :         // Savings Benchmark for All Residential End-Uses", Proceedings of SimBuild 2004, IBPSA-USA National Conference,
    6980             :         // Boulder, CO, August 4 - 6, 2004.
    6981             : 
    6982             :         // Annual Average Outdoor Air Temperature (F)
    6983      512386 :         Real64 const Tavg = AnnualOAAvgDryBulbTemp * (9.0 / 5.0) + 32.0;
    6984             :         // Maximum difference in monthly average outdoor air temperatures (deltaF)
    6985      512386 :         Real64 const Tdiff = MonthlyOAAvgDryBulbTempMaxDiff * (9.0 / 5.0);
    6986             : 
    6987      512386 :         Real64 const Ratio = 0.4 + 0.01 * (Tavg - 44.0);
    6988      512386 :         Real64 const Lag = 35.0 - 1.0 * (Tavg - 44.0);
    6989      512386 :         Real64 constexpr Offset = 6.0;
    6990      512386 :         int const latitude_sign = (state.dataEnvrn->Latitude >= 0) ? 1 : -1;
    6991             : 
    6992             :         // calculated water main temp (F)
    6993             :         Real64 CurrentWaterMainsTemp =
    6994      512386 :             Tavg + Offset +
    6995      512386 :             Ratio * (Tdiff / 2.0) * latitude_sign * std::sin((0.986 * (state.dataEnvrn->DayOfYear - 15.0 - Lag) - 90) * Constant::DegToRadians);
    6996             : 
    6997      512386 :         if (CurrentWaterMainsTemp < 32.0) CurrentWaterMainsTemp = 32.0;
    6998             : 
    6999             :         // Convert F to C
    7000      512386 :         return (CurrentWaterMainsTemp - 32.0) * (5.0 / 9.0);
    7001             :     }
    7002         796 :     void GetWeatherStation(EnergyPlusData &state, bool &ErrorsFound)
    7003             :     {
    7004             : 
    7005             :         // SUBROUTINE INFORMATION:
    7006             :         //       AUTHOR         Peter Graham Ellis
    7007             :         //       DATE WRITTEN   January 2006
    7008             : 
    7009             :         // PURPOSE OF THIS SUBROUTINE:
    7010             :         // Reads the input data for the WEATHER STATION object.
    7011             : 
    7012         796 :         auto const &ipsc = state.dataIPShortCut;
    7013         796 :         ipsc->cCurrentModuleObject = "Site:WeatherStation";
    7014         796 :         int const NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ipsc->cCurrentModuleObject);
    7015             : 
    7016             :         // Default conditions for a weather station in an open field at a height of 10 m. (These should match the IDD defaults.)
    7017         796 :         Real64 WeatherFileWindSensorHeight = 10.0; // Height of the wind sensor at the weather station, i.e., weather file
    7018         796 :         Real64 WeatherFileWindExp = 0.14;          // Exponent for the wind velocity profile at the weather station
    7019         796 :         Real64 WeatherFileWindBLHeight = 270.0;    // Boundary layer height for the wind velocity profile at the weather station (m)
    7020         796 :         Real64 WeatherFileTempSensorHeight = 1.5;  // Height of the air temperature sensor at the weather station (m)
    7021             : 
    7022         796 :         if (NumObjects == 1) {
    7023             :             int NumAlphas;               // Number of elements in the alpha array
    7024             :             int NumNums;                 // Number of elements in the numeric array
    7025             :             int IOStat;                  // IO Status when calling get input subroutine
    7026           1 :             Array1D_string AlphArray(1); // Character string data
    7027           1 :             Array1D<Real64> NumArray(4); // Numeric data
    7028           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    7029           1 :                 state, ipsc->cCurrentModuleObject, 1, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    7030             : 
    7031           1 :             if (NumNums > 0) WeatherFileWindSensorHeight = NumArray(1);
    7032           1 :             if (NumNums > 1) WeatherFileWindExp = NumArray(2);
    7033           1 :             if (NumNums > 2) WeatherFileWindBLHeight = NumArray(3);
    7034           1 :             if (NumNums > 3) WeatherFileTempSensorHeight = NumArray(4);
    7035             : 
    7036         796 :         } else if (NumObjects > 1) {
    7037           0 :             ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", ipsc->cCurrentModuleObject));
    7038           0 :             ErrorsFound = true;
    7039             :         }
    7040             : 
    7041         796 :         state.dataEnvrn->WeatherFileWindModCoeff = std::pow(WeatherFileWindBLHeight / WeatherFileWindSensorHeight, WeatherFileWindExp);
    7042        1592 :         state.dataEnvrn->WeatherFileTempModCoeff = DataEnvironment::AtmosphericTempGradient * DataEnvironment::EarthRadius *
    7043         796 :                                                    WeatherFileTempSensorHeight / (DataEnvironment::EarthRadius + WeatherFileTempSensorHeight);
    7044             : 
    7045             :         // Write to the initialization output file
    7046         796 :         print(state.files.eio,
    7047             :               "{}\n",
    7048             :               "! <Environment:Weather Station>,Wind Sensor Height Above Ground {m},Wind Speed Profile Exponent "
    7049             :               "{},Wind Speed Profile Boundary Layer Thickness {m},Air Temperature Sensor Height Above Ground {m},Wind "
    7050             :               "Speed Modifier Coefficient-Internal,Temperature Modifier Coefficient-Internal");
    7051             : 
    7052             :         // Formats
    7053             :         static constexpr std::string_view Format_720("Environment:Weather Station,{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7054         796 :         print(state.files.eio,
    7055             :               Format_720,
    7056             :               WeatherFileWindSensorHeight,
    7057             :               WeatherFileWindExp,
    7058             :               WeatherFileWindBLHeight,
    7059             :               WeatherFileTempSensorHeight,
    7060         796 :               state.dataEnvrn->WeatherFileWindModCoeff,
    7061         796 :               state.dataEnvrn->WeatherFileTempModCoeff);
    7062         796 :     }
    7063             : 
    7064     2900842 :     void DayltgCurrentExtHorizIllum(EnergyPlusData &state)
    7065             :     {
    7066             : 
    7067             :         // SUBROUTINE INFORMATION:
    7068             :         //       AUTHOR         Fred Winkelmann
    7069             :         //       DATE WRITTEN   July 1997
    7070             :         //       MODIFIED       Nov98 (FW); Nov 2000 (FW)
    7071             : 
    7072             :         // PURPOSE OF THIS SUBROUTINE:
    7073             :         // CALCULATES EXTERIOR DAYLIGHT ILLUMINANCE AND LUMINOUS EFFICACY
    7074             : 
    7075             :         // METHODOLOGY EMPLOYED:
    7076             :         // CALLED by SetCurrentWeather.
    7077             :         // CALCULATES THE CURRENT-TIME-STEP
    7078             :         // ILLUMINANCE ON AN UNOBSTRUCTED HORIZONTAL SURFACE FROM THE
    7079             :         // THE SKY AND FROM DIRECT SUN.
    7080             : 
    7081             :         // REFERENCES:
    7082             :         // Based on DOE-2.1E subroutine DEXTIL.
    7083             : 
    7084             :         // SOLCOS(3), below, is the cosine of the solar zenith angle.
    7085     2900842 :         if (state.dataEnvrn->SunIsUp) {
    7086             :             // Exterior horizontal beam irradiance (W/m2)
    7087     1449972 :             Real64 SDIRH = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->SOLCOS.z;
    7088             :             // Exterior horizontal sky diffuse irradiance (W/m2)
    7089     1449972 :             Real64 SDIFH = state.dataEnvrn->DifSolarRad;
    7090             :             // Fraction of sky covered by clouds
    7091     1449972 :             state.dataEnvrn->CloudFraction = pow_2(SDIFH / (SDIRH + SDIFH + 0.0001));
    7092             :             // Luminous efficacy of sky diffuse solar and beam solar (lumens/W);
    7093             :             // Horizontal illuminance from sky and horizontal beam illuminance (lux)
    7094             :             // obtained from solar quantities on weather file and luminous efficacy.
    7095             : 
    7096     1449972 :             DayltgLuminousEfficacy(state, state.dataEnvrn->PDIFLW, state.dataEnvrn->PDIRLW);
    7097     1449972 :             state.dataEnvrn->HISKF = SDIFH * state.dataEnvrn->PDIFLW;
    7098     1449972 :             state.dataEnvrn->HISUNF = SDIRH * state.dataEnvrn->PDIRLW;
    7099     1449972 :             state.dataEnvrn->HISUNFnorm = state.dataEnvrn->BeamSolarRad * state.dataEnvrn->PDIRLW;
    7100             :         } else {
    7101     1450870 :             state.dataEnvrn->CloudFraction = 0.0;
    7102     1450870 :             state.dataEnvrn->PDIFLW = 0.0;
    7103     1450870 :             state.dataEnvrn->PDIRLW = 0.0;
    7104     1450870 :             state.dataEnvrn->HISKF = 0.0;
    7105     1450870 :             state.dataEnvrn->HISUNF = 0.0;
    7106     1450870 :             state.dataEnvrn->HISUNFnorm = 0.0;
    7107     1450870 :             state.dataEnvrn->SkyClearness = 0.0;
    7108     1450870 :             state.dataEnvrn->SkyBrightness = 0.0;
    7109             :         }
    7110     2900842 :     }
    7111             : 
    7112     1449972 :     void DayltgLuminousEfficacy(EnergyPlusData &state,
    7113             :                                 Real64 &DiffLumEff, // Luminous efficacy of sky diffuse solar radiation (lum/W)
    7114             :                                 Real64 &DirLumEff   // Luminous efficacy of beam solar radiation (lum/W)
    7115             :     )
    7116             :     {
    7117             :         // SUBROUTINE INFORMATION:
    7118             :         //       AUTHOR         Fred Winkelmann
    7119             :         //       DATE WRITTEN   July 1997
    7120             :         //       MODIFIED       August 2009, BG fixed upper bound for sky clearness bin 7
    7121             : 
    7122             :         // PURPOSE OF THIS SUBROUTINE:
    7123             :         // Uses diffuse horizontal solar irradiance, direct normal solar
    7124             :         // irradiance, atmospheric moisture and sun position
    7125             :         // to determine the luminous efficacy in lumens/watt
    7126             :         // of sky diffuse solar radiation and direct normal solar radiation.
    7127             :         // Based on an empirical method described in
    7128             :         // R. Perez, P. Ineichen, R. Seals, J. Michalsky and R. Stewart,
    7129             :         // "Modeling daylight availability and irradiance components from direct
    7130             :         // global irradiance components from direct and global irradiance,"
    7131             :         // Solar Energy 44 (1990) 271-289.
    7132             : 
    7133             :         // Diffuse luminous efficacy coefficients
    7134             :         static constexpr std::array<Real64, 8> ADiffLumEff = {97.24, 107.22, 104.97, 102.39, 100.71, 106.42, 141.88, 152.23};
    7135             :         static constexpr std::array<Real64, 8> BDiffLumEff = {-0.46, 1.15, 2.96, 5.59, 5.94, 3.83, 1.90, 0.35};
    7136             :         static constexpr std::array<Real64, 8> CDiffLumEff = {12.00, 0.59, -5.53, -13.95, -22.75, -36.15, -53.24, -45.27};
    7137             :         static constexpr std::array<Real64, 8> DDiffLumEff = {-8.91, -3.95, -8.77, -13.90, -23.74, -28.83, -14.03, -7.98};
    7138             :         // Direct luminous efficacy coefficients
    7139             :         static constexpr std::array<Real64, 8> ADirLumEff = {57.20, 98.99, 109.83, 110.34, 106.36, 107.19, 105.75, 101.18};
    7140             :         static constexpr std::array<Real64, 8> BDirLumEff = {-4.55, -3.46, -4.90, -5.84, -3.97, -1.25, 0.77, 1.58};
    7141             :         static constexpr std::array<Real64, 8> CDirLumEff = {-2.98, -1.21, -1.71, -1.99, -1.75, -1.51, -1.26, -1.10};
    7142             :         static constexpr std::array<Real64, 8> DDirLumEff = {117.12, 12.38, -8.81, -4.56, -6.16, -26.73, -34.44, -8.29};
    7143             :         // Monthly exterrestrial direct normal illuminance (lum/m2)
    7144             :         static constexpr std::array<Real64, 12> ExtraDirNormIll = {
    7145             :             131153.0, 130613.0, 128992.0, 126816.0, 124731.0, 123240.0, 122652.0, 123120.0, 124576.0, 126658.0, 128814.0, 130471.0};
    7146             : 
    7147     1449972 :         Real64 const SunZenith = std::acos(state.dataEnvrn->SOLCOS.z); // Solar zenith angle (radians)
    7148     1449972 :         Real64 const SunAltitude = Constant::PiOvr2 - SunZenith;       // Solar altitude angle (radians)
    7149     1449972 :         Real64 const SinSunAltitude = std::sin(SunAltitude);
    7150             :         // Clearness of sky. SkyClearness close to 1.0 corresponds to an overcast sky.
    7151             :         // SkyClearness > 6 is a clear sky.
    7152             :         // DifSolarRad is the diffuse horizontal irradiance.
    7153             :         // BeamSolarRad is the direct normal irradiance.
    7154     1449972 :         Real64 const Zeta = 1.041 * pow_3(SunZenith);
    7155     2899944 :         state.dataEnvrn->SkyClearness =
    7156     1449972 :             ((state.dataEnvrn->DifSolarRad + state.dataEnvrn->BeamSolarRad) / (state.dataEnvrn->DifSolarRad + 0.0001) + Zeta) / (1.0 + Zeta);
    7157             :         // Relative optical air mass
    7158     1449972 :         Real64 const AirMass = (1.0 - 0.1 * state.dataEnvrn->Elevation / 1000.0) /
    7159     1449972 :                                (SinSunAltitude + 0.15 / std::pow(SunAltitude / Constant::DegToRadians + 3.885, 1.253));
    7160             :         // In the following, 93.73 is the extraterrestrial luminous efficacy
    7161     1449972 :         state.dataEnvrn->SkyBrightness = (state.dataEnvrn->DifSolarRad * 93.73) * AirMass / ExtraDirNormIll[state.dataEnvrn->Month - 1];
    7162             :         int ISkyClearness; // Sky clearness bin
    7163     1449972 :         if (state.dataEnvrn->SkyClearness <= 1.065) {
    7164      544746 :             ISkyClearness = 0;
    7165      905226 :         } else if (state.dataEnvrn->SkyClearness <= 1.23) {
    7166       11432 :             ISkyClearness = 1;
    7167      893794 :         } else if (state.dataEnvrn->SkyClearness <= 1.50) {
    7168       15009 :             ISkyClearness = 2;
    7169      878785 :         } else if (state.dataEnvrn->SkyClearness <= 1.95) {
    7170       20545 :             ISkyClearness = 3;
    7171      858240 :         } else if (state.dataEnvrn->SkyClearness <= 2.80) {
    7172       98692 :             ISkyClearness = 4;
    7173      759548 :         } else if (state.dataEnvrn->SkyClearness <= 4.50) {
    7174      275751 :             ISkyClearness = 5;
    7175      483797 :         } else if (state.dataEnvrn->SkyClearness <= 6.20) {
    7176      175838 :             ISkyClearness = 6;
    7177             :         } else {
    7178      307959 :             ISkyClearness = 7;
    7179             :         }
    7180             : 
    7181             :         // Atmospheric moisture (cm of precipitable water)
    7182     1449972 :         Real64 const AtmosMoisture = std::exp(0.07 * state.dataEnvrn->OutDewPointTemp - 0.075);
    7183             :         // Sky diffuse luminous efficacy
    7184     1449972 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7185      502068 :             DiffLumEff = 0.0;
    7186             :         } else {
    7187      947904 :             DiffLumEff = ADiffLumEff[ISkyClearness] + BDiffLumEff[ISkyClearness] * AtmosMoisture +
    7188      947904 :                          CDiffLumEff[ISkyClearness] * state.dataEnvrn->SOLCOS.z +
    7189      947904 :                          DDiffLumEff[ISkyClearness] * std::log(state.dataEnvrn->SkyBrightness);
    7190             :         }
    7191             :         // Direct normal luminous efficacy
    7192     1449972 :         if (state.dataEnvrn->SkyBrightness <= 0.0) {
    7193      502068 :             DirLumEff = 0.0;
    7194             :         } else {
    7195      947904 :             DirLumEff =
    7196      947904 :                 max(0.0,
    7197      947904 :                     ADirLumEff[ISkyClearness] + BDirLumEff[ISkyClearness] * AtmosMoisture +
    7198      947904 :                         CDirLumEff[ISkyClearness] * std::exp(5.73 * SunZenith - 5.0) + DDirLumEff[ISkyClearness] * state.dataEnvrn->SkyBrightness);
    7199             :         }
    7200     1449972 :     }
    7201             : 
    7202        2140 :     Real64 GetSTM(Real64 const Longitude) // Longitude from user input
    7203             :     {
    7204             :         // FUNCTION INFORMATION:
    7205             :         //       AUTHOR         Linda K. Lawrie
    7206             :         //       DATE WRITTEN   August 2003
    7207             : 
    7208             :         // PURPOSE OF THIS FUNCTION:
    7209             :         // This function determines the "standard time meridian" from the input
    7210             :         // longitude. Calculates the proper Meridian from Longitude.  This
    7211             :         // value is needed for weather calculations so that the sun comes
    7212             :         // up and goes down at the right times.
    7213             : 
    7214             :         Real64 GetSTM;
    7215             : 
    7216        2140 :         Array1D<Real64> longl({-12, 12}); // Lower Longitude value for a Time Zone
    7217        2140 :         Array1D<Real64> longh({-12, 12}); // Upper Longitude value for a Time Zone
    7218             : 
    7219        2140 :         GetSTM = 0.0;
    7220             : 
    7221        2140 :         longl(0) = -7.5;
    7222        2140 :         longh(0) = 7.5;
    7223       27820 :         for (int i = 1; i <= 12; ++i) {
    7224       25680 :             longl(i) = longl(i - 1) + 15.0;
    7225       25680 :             longh(i) = longh(i - 1) + 15.0;
    7226             :         }
    7227       27820 :         for (int i = 1; i <= 12; ++i) {
    7228       25680 :             longl(-i) = longl(-i + 1) - 15.0;
    7229       25680 :             longh(-i) = longh(-i + 1) - 15.0;
    7230             :         }
    7231        2140 :         Real64 temp = mod(Longitude, 360.0);
    7232        2140 :         if (temp > 180.0) temp -= 180.0;
    7233             :         Real64 tz; // resultant tz meridian
    7234       13560 :         for (int i = -12; i <= 12; ++i) {
    7235       13560 :             if (temp > longl(i) && temp <= longh(i)) {
    7236        2140 :                 tz = i;
    7237        2140 :                 tz = mod(i, 24.0);
    7238        2140 :                 GetSTM = tz;
    7239        2140 :                 break;
    7240             :             }
    7241             :         }
    7242             : 
    7243        2140 :         return GetSTM;
    7244        2140 :     }
    7245             : 
    7246        6304 :     void ProcessEPWHeader(EnergyPlusData &state, EpwHeaderType const headerType, std::string &Line, bool &ErrorsFound)
    7247             :     {
    7248             : 
    7249             :         // SUBROUTINE INFORMATION:
    7250             :         //       AUTHOR         Linda Lawrie
    7251             :         //       DATE WRITTEN   December 1999
    7252             : 
    7253             :         // PURPOSE OF THIS SUBROUTINE:
    7254             :         // This subroutine processes each header line in the EPW weather file.
    7255             : 
    7256             :         // METHODOLOGY EMPLOYED:
    7257             :         // File is positioned to the correct line, then backspaced.  This routine
    7258             :         // reads in the line and processes as appropriate.
    7259             : 
    7260             :         Weather::DateType dateType;
    7261             :         int NumHdArgs;
    7262             : 
    7263             :         // Strip off Header value from Line
    7264        6304 :         std::string::size_type Pos = index(Line, ',');
    7265        6304 :         if ((Pos == std::string::npos) && !((headerType == EpwHeaderType::Comments1) || (headerType == EpwHeaderType::Comments2))) {
    7266           0 :             ShowSevereError(state, "Invalid Header line in in.epw -- no commas");
    7267           0 :             ShowContinueError(state, format("Line={}", Line));
    7268           0 :             ShowFatalError(state, "Previous conditions cause termination.");
    7269             :         }
    7270        6304 :         if (Pos != std::string::npos) Line.erase(0, Pos + 1);
    7271             : 
    7272        6304 :         switch (headerType) {
    7273         788 :         case Weather::EpwHeaderType::Location: {
    7274             : 
    7275             :             // LOCATION, A1 [City], A2 [State/Province/Region], A3 [Country],
    7276             :             // A4 [Source], N1 [WMO], N2 [Latitude],
    7277             :             // N3 [Longitude], N4 [Time Zone], N5 [Elevation {m}]
    7278             : 
    7279         788 :             NumHdArgs = 9;
    7280        7880 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7281        7092 :                 strip(Line);
    7282        7092 :                 Pos = index(Line, ',');
    7283        7092 :                 if (Pos == std::string::npos) {
    7284         784 :                     if (len(Line) == 0) {
    7285           0 :                         while (Pos == std::string::npos) {
    7286           0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7287           0 :                             strip(Line);
    7288           0 :                             uppercase(Line);
    7289           0 :                             Pos = index(Line, ',');
    7290             :                         }
    7291             :                     } else {
    7292         784 :                         Pos = len(Line);
    7293             :                     }
    7294             :                 }
    7295             : 
    7296             :                 switch (i) {
    7297         788 :                 case 1:
    7298         788 :                     state.dataWeather->EPWHeaderTitle = stripped(Line.substr(0, Pos));
    7299         788 :                     break;
    7300        2364 :                 case 2:
    7301             :                 case 3:
    7302             :                 case 4:
    7303        2364 :                     state.dataWeather->EPWHeaderTitle = strip(state.dataWeather->EPWHeaderTitle) + ' ' + stripped(Line.substr(0, Pos));
    7304        2364 :                     break;
    7305         788 :                 case 5:
    7306         788 :                     state.dataWeather->EPWHeaderTitle += " WMO#=" + stripped(Line.substr(0, Pos));
    7307         788 :                     break;
    7308        3152 :                 case 6:
    7309             :                 case 7:
    7310             :                 case 8:
    7311             :                 case 9: {
    7312             :                     bool errFlag;
    7313        3152 :                     Real64 const Number = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7314        3152 :                     if (!errFlag) {
    7315             :                         switch (i) {
    7316         788 :                         case 6:
    7317         788 :                             state.dataWeather->WeatherFileLatitude = Number;
    7318         788 :                             break;
    7319         788 :                         case 7:
    7320         788 :                             state.dataWeather->WeatherFileLongitude = Number;
    7321         788 :                             break;
    7322         788 :                         case 8:
    7323         788 :                             state.dataWeather->WeatherFileTimeZone = Number;
    7324         788 :                             break;
    7325         788 :                         case 9:
    7326         788 :                             state.dataWeather->WeatherFileElevation = Number;
    7327         788 :                             break;
    7328           0 :                         default:
    7329           0 :                             break;
    7330             :                         }
    7331             :                     }
    7332        3152 :                 } break;
    7333           0 :                 default:
    7334           0 :                     ShowSevereError(state, format("GetEPWHeader:LOCATION, invalid numeric={}", Line.substr(0, Pos)));
    7335           0 :                     ErrorsFound = true;
    7336           0 :                     break;
    7337             :                 }
    7338        7092 :                 Line.erase(0, Pos + 1);
    7339             :             }
    7340         788 :             state.dataEnvrn->WeatherFileLocationTitle = stripped(state.dataWeather->EPWHeaderTitle);
    7341         788 :         } break;
    7342         788 :         case Weather::EpwHeaderType::TypicalExtremePeriods: {
    7343         788 :             strip(Line);
    7344         788 :             Pos = index(Line, ',');
    7345         788 :             if (Pos == std::string::npos) {
    7346           0 :                 if (len(Line) == 0) {
    7347           0 :                     while (Pos == std::string::npos && len(Line) == 0) {
    7348           0 :                         Line = state.files.inputWeatherFile.readLine().data;
    7349           0 :                         strip(Line);
    7350           0 :                         Pos = index(Line, ',');
    7351             :                     }
    7352             :                 } else {
    7353           0 :                     Pos = len(Line);
    7354             :                 }
    7355             :             }
    7356             :             bool IOStatus;
    7357         788 :             state.dataWeather->NumEPWTypExtSets = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7358         788 :             Line.erase(0, Pos + 1);
    7359         788 :             state.dataWeather->TypicalExtremePeriods.allocate(state.dataWeather->NumEPWTypExtSets);
    7360         788 :             int TropExtremeCount = 0;
    7361        5387 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7362        4599 :                 strip(Line);
    7363        4599 :                 Pos = index(Line, ',');
    7364        4599 :                 if (Pos != std::string::npos) {
    7365        4599 :                     state.dataWeather->TypicalExtremePeriods(i).Title = Line.substr(0, Pos);
    7366        4599 :                     Line.erase(0, Pos + 1);
    7367             :                 } else {
    7368           0 :                     ShowWarningError(state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={}", Line.substr(0, Pos)));
    7369           0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7370           0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7371           0 :                     break;
    7372             :                 }
    7373        4599 :                 Pos = index(Line, ',');
    7374        4599 :                 if (Pos != std::string::npos) {
    7375        4599 :                     state.dataWeather->TypicalExtremePeriods(i).TEType = Line.substr(0, Pos);
    7376        4599 :                     Line.erase(0, Pos + 1);
    7377        4599 :                     if (Util::SameString(state.dataWeather->TypicalExtremePeriods(i).TEType, "EXTREME")) {
    7378        1576 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MAX")) {
    7379           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7380        1576 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY SEASON - WEEK NEAR ANNUAL MIN")) {
    7381           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7382        1576 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MAX")) {
    7383           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMax";
    7384        1576 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET SEASON - WEEK NEAR ANNUAL MIN")) {
    7385           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeasonMin";
    7386             :                             // to account for problems earlier in weather files:
    7387        1576 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7388           0 :                             if (TropExtremeCount == 0) {
    7389           0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Max";
    7390           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMax";
    7391           0 :                                 ++TropExtremeCount;
    7392           0 :                             } else if (TropExtremeCount == 1) {
    7393           0 :                                 state.dataWeather->TypicalExtremePeriods(i).Title = "No Dry Season - Week Near Annual Min";
    7394           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeasonMin";
    7395           0 :                                 ++TropExtremeCount;
    7396             :                             }
    7397             :                         } else { // make new short titles
    7398        1576 :                             if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7399         723 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7400         853 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7401         723 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7402         130 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7403          65 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7404          65 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7405          65 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7406           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7407           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7408           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7409           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7410           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7411           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7412           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7413           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7414           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7415           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7416           0 :                             } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7417           0 :                                 state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7418             :                             }
    7419             :                         }
    7420             :                     } else { // not extreme
    7421        3023 :                         if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SUMMER")) {
    7422         723 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Summer";
    7423        2300 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WINTER")) {
    7424         723 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Winter";
    7425        1577 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL HOT")) {
    7426           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalHot";
    7427        1577 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "TROPICAL COLD")) {
    7428           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "TropicalCold";
    7429        1577 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "AUTUMN")) {
    7430         723 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Autumn";
    7431         854 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO DRY")) {
    7432           0 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoDrySeason";
    7433         854 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "NO WET")) {
    7434           1 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "NoWetSeason";
    7435         853 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "WET ")) {
    7436          65 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "WetSeason";
    7437         788 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "DRY ")) {
    7438          65 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "DrySeason";
    7439         723 :                         } else if (has_prefixi(state.dataWeather->TypicalExtremePeriods(i).Title, "SPRING")) {
    7440         723 :                             state.dataWeather->TypicalExtremePeriods(i).ShortTitle = "Spring";
    7441             :                         }
    7442             :                     }
    7443             :                 } else {
    7444           0 :                     ShowWarningError(state,
    7445           0 :                                      format("ProcessEPWHeader: Invalid Typical/Extreme Periods Header(WeatherFile)={} {}",
    7446           0 :                                             state.dataWeather->TypicalExtremePeriods(i).Title,
    7447           0 :                                             Line.substr(0, Pos)));
    7448           0 :                     ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7449           0 :                     state.dataWeather->NumEPWTypExtSets = i - 1;
    7450           0 :                     break;
    7451             :                 }
    7452             :                 int PMonth;
    7453             :                 int PDay;
    7454             :                 int PWeekDay;
    7455        4599 :                 Pos = index(Line, ',');
    7456        4599 :                 if (Pos != std::string::npos) {
    7457        4599 :                     std::string dateStringUC = Line.substr(0, Pos);
    7458        4599 :                     dateStringUC = uppercase(dateStringUC);
    7459        4599 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7460        4599 :                     if (dateType != DateType::Invalid) {
    7461        4599 :                         if (PMonth != 0 && PDay != 0) {
    7462        4599 :                             state.dataWeather->TypicalExtremePeriods(i).StartMonth = PMonth;
    7463        4599 :                             state.dataWeather->TypicalExtremePeriods(i).StartDay = PDay;
    7464             :                         }
    7465             :                     } else {
    7466           0 :                         ShowSevereError(
    7467           0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7468           0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7469           0 :                         ErrorsFound = true;
    7470             :                     }
    7471        4599 :                     Line.erase(0, Pos + 1);
    7472        4599 :                 }
    7473        4599 :                 Pos = index(Line, ',');
    7474        4599 :                 if (Pos != std::string::npos) {
    7475        3811 :                     std::string dateStringUC = Line.substr(0, Pos);
    7476        3811 :                     dateStringUC = uppercase(dateStringUC);
    7477        3811 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7478        3811 :                     if (dateType != DateType::Invalid) {
    7479        3811 :                         if (PMonth != 0 && PDay != 0) {
    7480        3811 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7481        3811 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7482             :                         }
    7483             :                     } else {
    7484           0 :                         ShowSevereError(
    7485           0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7486           0 :                         ShowContinueError(state, format("...on processing Typical/Extreme period #{}", i));
    7487           0 :                         ErrorsFound = true;
    7488             :                     }
    7489        3811 :                     Line.erase(0, Pos + 1);
    7490        3811 :                 } else { // Pos=0, probably last one
    7491         788 :                     std::string const dateStringUC = uppercase(Line);
    7492         788 :                     General::ProcessDateString(state, dateStringUC, PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7493         788 :                     if (dateType != DateType::Invalid) {
    7494         788 :                         if (PMonth != 0 && PDay != 0) {
    7495         788 :                             state.dataWeather->TypicalExtremePeriods(i).EndMonth = PMonth;
    7496         788 :                             state.dataWeather->TypicalExtremePeriods(i).EndDay = PDay;
    7497             :                         }
    7498             :                     } else {
    7499           0 :                         ShowSevereError(
    7500           0 :                             state, format("ProcessEPWHeader: Invalid Typical/Extreme Periods End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7501           0 :                         ErrorsFound = true;
    7502             :                     }
    7503         788 :                 }
    7504             :             }
    7505             :             // Process periods to set up other values.
    7506        5387 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7507        4599 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7508             :                 // JulianDay (Month,Day,LeapYearValue)
    7509        4599 :                 std::string const ExtremePeriodTitle = Util::makeUPPER(typicalExtPer.ShortTitle);
    7510        4599 :                 if (ExtremePeriodTitle == "SUMMER") {
    7511        1446 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7512         723 :                         typicalExtPer.MatchValue = "SummerExtreme";
    7513         723 :                         typicalExtPer.MatchValue1 = "TropicalHot";
    7514         723 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7515             :                     } else {
    7516         723 :                         typicalExtPer.MatchValue = "SummerTypical";
    7517             :                     }
    7518             : 
    7519        3153 :                 } else if (ExtremePeriodTitle == "WINTER") {
    7520        1446 :                     if (Util::SameString(typicalExtPer.TEType, "EXTREME")) {
    7521         723 :                         typicalExtPer.MatchValue = "WinterExtreme";
    7522         723 :                         typicalExtPer.MatchValue1 = "TropicalCold";
    7523         723 :                         typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7524             :                     } else {
    7525         723 :                         typicalExtPer.MatchValue = "WinterTypical";
    7526             :                     }
    7527             : 
    7528        1707 :                 } else if (ExtremePeriodTitle == "AUTUMN") {
    7529         723 :                     typicalExtPer.MatchValue = "AutumnTypical";
    7530             : 
    7531         984 :                 } else if (ExtremePeriodTitle == "SPRING") {
    7532         723 :                     typicalExtPer.MatchValue = "SpringTypical";
    7533             : 
    7534         261 :                 } else if (ExtremePeriodTitle == "WETSEASON") {
    7535          65 :                     typicalExtPer.MatchValue = "WetSeason";
    7536             : 
    7537         196 :                 } else if (ExtremePeriodTitle == "DRYSEASON") {
    7538          65 :                     typicalExtPer.MatchValue = "DrySeason";
    7539             : 
    7540         131 :                 } else if (ExtremePeriodTitle == "NOWETSEASON") {
    7541           1 :                     typicalExtPer.MatchValue = "NoWetSeason";
    7542             : 
    7543         130 :                 } else if (ExtremePeriodTitle == "NODRYSEASON") {
    7544           0 :                     typicalExtPer.MatchValue = "NoDrySeason";
    7545             : 
    7546         130 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMAX") || (ExtremePeriodTitle == "NOWETSEASONMAX")) {
    7547           0 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7548           0 :                     typicalExtPer.MatchValue1 = "TropicalHot";
    7549           0 :                     typicalExtPer.MatchValue2 = "SummerExtreme";
    7550             : 
    7551         130 :                 } else if ((ExtremePeriodTitle == "NODRYSEASONMIN") || (ExtremePeriodTitle == "NOWETSEASONMIN")) {
    7552           0 :                     typicalExtPer.MatchValue = typicalExtPer.ShortTitle;
    7553           0 :                     typicalExtPer.MatchValue1 = "TropicalCold";
    7554           0 :                     typicalExtPer.MatchValue2 = "WinterExtreme";
    7555             : 
    7556         130 :                 } else if (ExtremePeriodTitle == "TROPICALHOT") {
    7557          65 :                     typicalExtPer.MatchValue = "TropicalHot";
    7558          65 :                     typicalExtPer.MatchValue1 = "SummerExtreme";
    7559          65 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMax";
    7560             : 
    7561          65 :                 } else if (ExtremePeriodTitle == "TROPICALCOLD") {
    7562          65 :                     typicalExtPer.MatchValue = "TropicalCold";
    7563          65 :                     typicalExtPer.MatchValue1 = "WinterExtreme";
    7564          65 :                     typicalExtPer.MatchValue2 = "NoDrySeasonMin";
    7565             : 
    7566             :                 } else {
    7567           0 :                     typicalExtPer.MatchValue = "Invalid - no match";
    7568             :                 }
    7569        4599 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, 0);
    7570        4599 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, 0);
    7571        4599 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7572        4593 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7573             :                 } else {
    7574           6 :                     typicalExtPer.TotalDays =
    7575           6 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7576             :                 }
    7577        4599 :             }
    7578         788 :         } break;
    7579         788 :         case Weather::EpwHeaderType::GroundTemperatures: {
    7580             :             // Added for ground surfaces defined with F or c factor method. TH 7/2009
    7581             :             // Assume the 0.5 m set of ground temperatures
    7582             :             // or first set on a weather file, if any.
    7583         788 :             Pos = index(Line, ',');
    7584         788 :             if (Pos != std::string::npos) {
    7585             :                 bool errFlag;
    7586         788 :                 int NumGrndTemps = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7587         788 :                 if (!errFlag && NumGrndTemps >= 1) {
    7588         788 :                     Line.erase(0, Pos + 1);
    7589             :                     // skip depth, soil conductivity, soil density, soil specific heat
    7590        3940 :                     for (int i = 1; i <= 4; ++i) {
    7591        3152 :                         Pos = index(Line, ',');
    7592        3152 :                         if (Pos == std::string::npos) {
    7593           0 :                             Line.clear();
    7594           0 :                             break;
    7595             :                         }
    7596        3152 :                         Line.erase(0, Pos + 1);
    7597             :                     }
    7598         788 :                     state.dataWeather->GroundTempsFCFromEPWHeader = 0.0;
    7599         788 :                     int actcount = 0;
    7600       10244 :                     for (int i = 1; i <= 12; ++i) { // take the first set of ground temperatures.
    7601        9456 :                         Pos = index(Line, ',');
    7602        9456 :                         if (Pos != std::string::npos) {
    7603        9456 :                             state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7604        9456 :                             ++actcount;
    7605             :                         } else {
    7606           0 :                             if (len(Line) > 0) {
    7607           0 :                                 state.dataWeather->GroundTempsFCFromEPWHeader(i) = Util::ProcessNumber(Line.substr(0, Pos), errFlag);
    7608           0 :                                 ++actcount;
    7609             :                             }
    7610           0 :                             break;
    7611             :                         }
    7612        9456 :                         Line.erase(0, Pos + 1);
    7613             :                     }
    7614         788 :                     if (actcount == 12) state.dataWeather->wthFCGroundTemps = true;
    7615             :                 }
    7616             :             }
    7617         788 :         } break;
    7618         788 :         case Weather::EpwHeaderType::HolidaysDST: {
    7619             :             // A1, \field LeapYear Observed
    7620             :             // \type choice
    7621             :             // \key Yes
    7622             :             // \key No
    7623             :             // \note Yes if Leap Year will be observed for this file
    7624             :             // \note No if Leap Year days (29 Feb) should be ignored in this file
    7625             :             // A2, \field Daylight Saving Start Day
    7626             :             // A3, \field Daylight Saving End Day
    7627             :             // N1, \field Number of Holidays
    7628             :             // A4, \field Holiday 1 Name
    7629             :             // A5, \field Holiday 1 Day
    7630             :             // etc.
    7631             :             // Start with Minimum number of NumHdArgs
    7632         788 :             uppercase(Line);
    7633         788 :             NumHdArgs = 4;
    7634         788 :             int CurCount = 0;
    7635        3962 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7636        3174 :                 strip(Line);
    7637        3174 :                 Pos = index(Line, ',');
    7638        3174 :                 if (Pos == std::string::npos) {
    7639         784 :                     if (len(Line) == 0) {
    7640           0 :                         while (Pos == std::string::npos) {
    7641           0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7642           0 :                             strip(Line);
    7643           0 :                             uppercase(Line);
    7644           0 :                             Pos = index(Line, ',');
    7645             :                         }
    7646             :                     } else {
    7647         784 :                         Pos = len(Line);
    7648             :                     }
    7649             :                 }
    7650             : 
    7651             :                 int PMonth;
    7652             :                 int PDay;
    7653             :                 int PWeekDay;
    7654             :                 bool IOStatus;
    7655        3174 :                 if (i == 1) {
    7656         788 :                     state.dataWeather->WFAllowsLeapYears = (Line[0] == 'Y');
    7657        2386 :                 } else if (i == 2) {
    7658             :                     // In this section, we call ProcessDateString, and if that fails, we can recover from it
    7659             :                     // by setting DST to false, so we don't affect ErrorsFound
    7660             : 
    7661             :                     // call ProcessDateString with local bool (unused)
    7662             :                     bool errflag1;
    7663         788 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, errflag1);
    7664         788 :                     if (dateType != DateType::Invalid) {
    7665             :                         // ErrorsFound is still false after ProcessDateString
    7666         788 :                         if (PMonth == 0 && PDay == 0) {
    7667         787 :                             state.dataWeather->EPWDaylightSaving = false;
    7668             :                         } else {
    7669           1 :                             state.dataWeather->EPWDaylightSaving = true;
    7670           1 :                             state.dataWeather->EPWDST.StDateType = dateType;
    7671           1 :                             state.dataWeather->EPWDST.StMon = PMonth;
    7672           1 :                             state.dataWeather->EPWDST.StDay = PDay;
    7673           1 :                             state.dataWeather->EPWDST.StWeekDay = PWeekDay;
    7674             :                         }
    7675             :                     } else {
    7676             :                         // ErrorsFound is untouched
    7677           0 :                         ShowContinueError(
    7678           0 :                             state, format("ProcessEPWHeader: Invalid Daylight Saving Period Start Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7679           0 :                         ShowContinueError(state, format("...invalid header={}", epwHeaders[static_cast<int>(headerType)]));
    7680           0 :                         ShowContinueError(state, "...Setting Weather File DST to false.");
    7681           0 :                         state.dataWeather->EPWDaylightSaving = false;
    7682             :                     }
    7683             : 
    7684        1598 :                 } else if (i == 3) {
    7685         788 :                     General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7686         788 :                     if (state.dataWeather->EPWDaylightSaving) {
    7687           1 :                         if (dateType != DateType::Invalid) {
    7688           1 :                             state.dataWeather->EPWDST.EnDateType = dateType;
    7689           1 :                             state.dataWeather->EPWDST.EnMon = PMonth;
    7690           1 :                             state.dataWeather->EPWDST.EnDay = PDay;
    7691           1 :                             state.dataWeather->EPWDST.EnWeekDay = PWeekDay;
    7692             :                         } else {
    7693           0 :                             ShowWarningError(
    7694             :                                 state,
    7695           0 :                                 format("ProcessEPWHeader: Invalid Daylight Saving Period End Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7696           0 :                             ShowContinueError(state, "...Setting Weather File DST to false.");
    7697           0 :                             state.dataWeather->EPWDaylightSaving = false;
    7698             :                         }
    7699           1 :                         state.dataWeather->DST = state.dataWeather->EPWDST;
    7700             :                     }
    7701             : 
    7702         810 :                 } else if (i == 4) {
    7703         788 :                     int NumEPWHolidays = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7704        1576 :                     state.dataWeather->NumSpecialDays =
    7705         788 :                         NumEPWHolidays + state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RunPeriodControl:SpecialDays");
    7706         788 :                     state.dataWeather->SpecialDays.allocate(state.dataWeather->NumSpecialDays);
    7707         788 :                     NumHdArgs = 4 + NumEPWHolidays * 2;
    7708             : 
    7709          22 :                 } else if ((i >= 5)) {
    7710          22 :                     if (mod(i, 2) != 0) {
    7711          11 :                         ++CurCount;
    7712          11 :                         if (CurCount > state.dataWeather->NumSpecialDays) {
    7713           0 :                             ShowSevereError(state, "Too many SpecialDays");
    7714           0 :                             ErrorsFound = true;
    7715             :                         } else {
    7716          11 :                             state.dataWeather->SpecialDays(CurCount).Name = Line.substr(0, Pos);
    7717             :                         }
    7718             :                         // Process name
    7719             :                     } else {
    7720          11 :                         if (CurCount <= state.dataWeather->NumSpecialDays) {
    7721          11 :                             auto &specialDay = state.dataWeather->SpecialDays(CurCount);
    7722             :                             // Process date
    7723          11 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound);
    7724          11 :                             if (dateType == DateType::MonthDay) {
    7725           6 :                                 specialDay.dateType = dateType;
    7726           6 :                                 specialDay.Month = PMonth;
    7727           6 :                                 specialDay.Day = PDay;
    7728           6 :                                 specialDay.WeekDay = 0;
    7729           6 :                                 specialDay.CompDate = PMonth * 32 + PDay;
    7730           6 :                                 specialDay.Duration = 1;
    7731           6 :                                 specialDay.DayType = 1;
    7732           6 :                                 specialDay.WthrFile = true;
    7733           5 :                             } else if (dateType != DateType::Invalid) {
    7734           5 :                                 specialDay.dateType = dateType;
    7735           5 :                                 specialDay.Month = PMonth;
    7736           5 :                                 specialDay.Day = PDay;
    7737           5 :                                 specialDay.WeekDay = PWeekDay;
    7738           5 :                                 specialDay.CompDate = 0;
    7739           5 :                                 specialDay.Duration = 1;
    7740           5 :                                 specialDay.DayType = 1;
    7741           5 :                                 specialDay.WthrFile = true;
    7742           0 :                             } else if (dateType == DateType::Invalid) {
    7743           0 :                                 ShowSevereError(state, format("Invalid SpecialDay Date Field(WeatherFile)={}", Line.substr(0, Pos)));
    7744           0 :                                 ErrorsFound = true;
    7745             :                             }
    7746             :                         }
    7747             :                     }
    7748             :                 }
    7749        3174 :                 Line.erase(0, Pos + 1);
    7750             :             }
    7751        5387 :             for (int i = 1; i <= state.dataWeather->NumEPWTypExtSets; ++i) {
    7752             :                 // General::OrdinalDay (Month,Day,LeapYearValue)
    7753        4599 :                 auto &typicalExtPer = state.dataWeather->TypicalExtremePeriods(i);
    7754        4599 :                 typicalExtPer.StartJDay = General::OrdinalDay(typicalExtPer.StartMonth, typicalExtPer.StartDay, state.dataWeather->LeapYearAdd);
    7755        4599 :                 typicalExtPer.EndJDay = General::OrdinalDay(typicalExtPer.EndMonth, typicalExtPer.EndDay, state.dataWeather->LeapYearAdd);
    7756        4599 :                 if (typicalExtPer.StartJDay <= typicalExtPer.EndJDay) {
    7757        4593 :                     typicalExtPer.TotalDays = typicalExtPer.EndJDay - typicalExtPer.StartJDay + 1;
    7758             :                 } else {
    7759           6 :                     typicalExtPer.TotalDays =
    7760           6 :                         General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - typicalExtPer.StartJDay + 1 + typicalExtPer.EndJDay;
    7761             :                 }
    7762             :             }
    7763         788 :         } break;
    7764        2364 :         case Weather::EpwHeaderType::Comments1:
    7765             :         case Weather::EpwHeaderType::Comments2:
    7766             :         case Weather::EpwHeaderType::DesignConditions: {
    7767             :             // no action
    7768        2364 :         } break;
    7769         788 :         case Weather::EpwHeaderType::DataPeriods: {
    7770             :             //     N1, \field Number of Data Periods
    7771             :             //     N2, \field Number of Records per hour
    7772             :             //     A1, \field Data Period 1 Name/Description
    7773             :             //     A2, \field Data Period 1 Start Day of Week
    7774             :             //       \type choice
    7775             :             //       \key  Sunday
    7776             :             //       \key  Monday
    7777             :             //       \key  Tuesday
    7778             :             //       \key  Wednesday
    7779             :             //       \key  Thursday
    7780             :             //       \key  Friday
    7781             :             //       \key  Saturday
    7782             :             //     A3, \field Data Period 1 Start Day
    7783             :             //     A4, \field Data Period 1 End Day
    7784         788 :             uppercase(Line);
    7785         788 :             NumHdArgs = 2;
    7786         788 :             int CurCount = 0;
    7787        5516 :             for (int i = 1; i <= NumHdArgs; ++i) {
    7788        4728 :                 strip(Line);
    7789        4728 :                 Pos = index(Line, ',');
    7790        4728 :                 if (Pos == std::string::npos) {
    7791         788 :                     if (len(Line) == 0) {
    7792           0 :                         while (Pos == std::string::npos) {
    7793           0 :                             Line = state.files.inputWeatherFile.readLine().data;
    7794           0 :                             strip(Line);
    7795           0 :                             uppercase(Line);
    7796           0 :                             Pos = index(Line, ',');
    7797             :                         }
    7798             :                     } else {
    7799         788 :                         Pos = len(Line);
    7800             :                     }
    7801             :                 }
    7802             : 
    7803             :                 bool IOStatus;
    7804        4728 :                 if (i == 1) {
    7805         788 :                     state.dataWeather->NumDataPeriods = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7806         788 :                     state.dataWeather->DataPeriods.allocate(state.dataWeather->NumDataPeriods);
    7807         788 :                     NumHdArgs += 4 * state.dataWeather->NumDataPeriods;
    7808         788 :                     if (state.dataWeather->NumDataPeriods > 0) {
    7809        1576 :                         for (auto &e : state.dataWeather->DataPeriods)
    7810        1576 :                             e.NumDays = 0;
    7811             :                     }
    7812             : 
    7813        3940 :                 } else if (i == 2) {
    7814         788 :                     state.dataWeather->NumIntervalsPerHour = Util::ProcessNumber(Line.substr(0, Pos), IOStatus);
    7815        3152 :                 } else if (i >= 3) {
    7816        3152 :                     int const CurOne = mod(i - 3, 4);
    7817             :                     int PMonth;
    7818             :                     int PDay;
    7819             :                     int PWeekDay;
    7820             :                     int PYear;
    7821        3152 :                     if (CurOne == 0) {
    7822             :                         // Description of Data Period
    7823         788 :                         ++CurCount;
    7824         788 :                         if (CurCount > state.dataWeather->NumDataPeriods) {
    7825           0 :                             ShowSevereError(state, "Too many data periods");
    7826           0 :                             ErrorsFound = true;
    7827             :                         } else {
    7828         788 :                             state.dataWeather->DataPeriods(CurCount).Name = Line.substr(0, Pos);
    7829             :                         }
    7830             : 
    7831        2364 :                     } else if (CurOne == 1) {
    7832             :                         // Start Day of Week
    7833         788 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7834         788 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7835         788 :                             dataPeriod.DayOfWeek = Line.substr(0, Pos);
    7836         788 :                             dataPeriod.WeekDay = getEnumValue(ScheduleManager::dayTypeNamesUC, dataPeriod.DayOfWeek);
    7837         788 :                             if (dataPeriod.WeekDay < 1 || dataPeriod.WeekDay > 7) {
    7838           0 :                                 ShowSevereError(state,
    7839           0 :                                                 fmt::format("Weather File -- Invalid Start Day of Week for Data Period #{}, Invalid day={}",
    7840             :                                                             CurCount,
    7841           0 :                                                             dataPeriod.DayOfWeek));
    7842           0 :                                 ErrorsFound = true;
    7843             :                             }
    7844             :                         }
    7845             : 
    7846        1576 :                     } else if (CurOne == 2) {
    7847             :                         // DataPeriod Start Day
    7848         788 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7849         788 :                             auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7850         788 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    7851         788 :                             if (dateType == DateType::MonthDay) {
    7852         788 :                                 dataPeriod.StMon = PMonth;
    7853         788 :                                 dataPeriod.StDay = PDay;
    7854         788 :                                 dataPeriod.StYear = PYear;
    7855         788 :                                 if (PYear != 0) dataPeriod.HasYearData = true;
    7856             :                             } else {
    7857           0 :                                 ShowSevereError(state,
    7858           0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day> (WeatherFile), found={}",
    7859           0 :                                                        Line.substr(0, Pos)));
    7860           0 :                                 ErrorsFound = true;
    7861             :                             }
    7862             :                         }
    7863             : 
    7864         788 :                     } else if (CurOne == 3) {
    7865         788 :                         auto &dataPeriod = state.dataWeather->DataPeriods(CurCount);
    7866         788 :                         if (CurCount <= state.dataWeather->NumDataPeriods) {
    7867         788 :                             General::ProcessDateString(state, Line.substr(0, Pos), PMonth, PDay, PWeekDay, dateType, ErrorsFound, PYear);
    7868         788 :                             if (dateType == DateType::MonthDay) {
    7869         788 :                                 dataPeriod.EnMon = PMonth;
    7870         788 :                                 dataPeriod.EnDay = PDay;
    7871         788 :                                 dataPeriod.EnYear = PYear;
    7872         788 :                                 if (PYear == 0 && dataPeriod.HasYearData) {
    7873           0 :                                     ShowWarningError(state, "Data Period (WeatherFile) - Start Date contains year. End Date does not.");
    7874           0 :                                     ShowContinueError(state, "...Assuming same year as Start Date for this data.");
    7875           0 :                                     dataPeriod.EnYear = dataPeriod.StYear;
    7876             :                                 }
    7877             :                             } else {
    7878           0 :                                 ShowSevereError(state,
    7879           0 :                                                 format("Data Periods must be of the form <DayOfYear> or <Month Day>, (WeatherFile) found={}",
    7880           0 :                                                        Line.substr(0, Pos)));
    7881           0 :                                 ErrorsFound = true;
    7882             :                             }
    7883             :                         }
    7884         788 :                         if (dataPeriod.StYear == 0 || dataPeriod.EnYear == 0) {
    7885         788 :                             dataPeriod.DataStJDay = General::OrdinalDay(dataPeriod.StMon, dataPeriod.StDay, state.dataWeather->LeapYearAdd);
    7886         788 :                             dataPeriod.DataEnJDay = General::OrdinalDay(dataPeriod.EnMon, dataPeriod.EnDay, state.dataWeather->LeapYearAdd);
    7887         788 :                             if (dataPeriod.DataStJDay <= dataPeriod.DataEnJDay) {
    7888         788 :                                 dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    7889             :                             } else {
    7890           0 :                                 dataPeriod.NumDays = (365 - dataPeriod.DataStJDay + 1) + (dataPeriod.DataEnJDay - 1 + 1);
    7891             :                             }
    7892             :                         } else { // weather file has actual year(s)
    7893           0 :                             dataPeriod.DataStJDay = computeJulianDate(dataPeriod.StYear, dataPeriod.StMon, dataPeriod.StDay);
    7894           0 :                             dataPeriod.DataEnJDay = computeJulianDate(dataPeriod.EnYear, dataPeriod.EnMon, dataPeriod.EnDay);
    7895           0 :                             dataPeriod.NumDays = dataPeriod.DataEnJDay - dataPeriod.DataStJDay + 1;
    7896             :                         }
    7897             :                         // Have processed the last item for this, can set up Weekdays for months
    7898         788 :                         dataPeriod.MonWeekDay = 0;
    7899         788 :                         if (!ErrorsFound) {
    7900        2364 :                             SetupWeekDaysByMonth(state,
    7901         788 :                                                  state.dataWeather->DataPeriods(CurCount).StMon,
    7902         788 :                                                  state.dataWeather->DataPeriods(CurCount).StDay,
    7903         788 :                                                  state.dataWeather->DataPeriods(CurCount).WeekDay,
    7904         788 :                                                  state.dataWeather->DataPeriods(CurCount).MonWeekDay);
    7905             :                         }
    7906             :                     }
    7907             :                 }
    7908        4728 :                 Line.erase(0, Pos + 1);
    7909             :             }
    7910         788 :         } break;
    7911           0 :         default: {
    7912             :             // Invalid header type
    7913           0 :             assert(false);
    7914             :         } break;
    7915             :         }
    7916        6304 :     }
    7917             : 
    7918        4975 :     void SkipEPlusWFHeader(EnergyPlusData &state)
    7919             :     {
    7920             : 
    7921             :         // SUBROUTINE INFORMATION:
    7922             :         //       AUTHOR         Linda K. Lawrie
    7923             :         //       DATE WRITTEN   August 2000
    7924             : 
    7925             :         // PURPOSE OF THIS SUBROUTINE:
    7926             :         // This subroutine skips the initial header records on the EnergyPlus Weather File (in.epw).
    7927             : 
    7928             :         static constexpr std::string_view Header("DATA PERIODS");
    7929             : 
    7930             :         // Read in Header Information
    7931        9950 :         InputFile::ReadResult<std::string> Line{"", true, false};
    7932             : 
    7933             :         // Headers should come in order
    7934             :         while (true) {
    7935       39800 :             Line = state.files.inputWeatherFile.readLine();
    7936       39800 :             if (Line.eof) {
    7937           0 :                 ShowFatalError(state,
    7938           0 :                                format("Unexpected End-of-File on EPW Weather file, while reading header information, looking for header={}", Header),
    7939           0 :                                OptionalOutputFileRef{state.files.eso});
    7940             :             }
    7941       39800 :             uppercase(Line.data);
    7942       39800 :             if (has(Line.data, Header)) break;
    7943             :         }
    7944             : 
    7945             :         // Dummy process Data Periods line
    7946             :         //  'DATA PERIODS'
    7947             :         //     N1, \field Number of Data Periods
    7948             :         //     N2, \field Number of Records per hour
    7949             :         //     A1, \field Data Period 1 Name/Description
    7950             :         //     A2, \field Data Period 1 Start Day of Week
    7951             :         //       \type choice
    7952             :         //       \key  Sunday
    7953             :         //       \key  Monday
    7954             :         //       \key  Tuesday
    7955             :         //       \key  Wednesday
    7956             :         //       \key  Thursday
    7957             :         //       \key  Friday
    7958             :         //       \key  Saturday
    7959             :         //     A3, \field Data Period 1 Start Day
    7960             :         //     A4, \field Data Period 1 End Day
    7961             : 
    7962        4975 :         int NumHdArgs = 2;
    7963        4975 :         int CurCount = 0;
    7964       14925 :         for (int i = 1; i <= NumHdArgs; ++i) {
    7965        9950 :             strip(Line.data);
    7966        9950 :             std::string::size_type Pos = index(Line.data, ',');
    7967        9950 :             if (Pos == std::string::npos) {
    7968           0 :                 if (len(Line.data) == 0) {
    7969           0 :                     while (Pos == std::string::npos) {
    7970           0 :                         Line = state.files.inputWeatherFile.readLine();
    7971           0 :                         strip(Line.data);
    7972           0 :                         uppercase(Line.data);
    7973           0 :                         Pos = index(Line.data, ',');
    7974             :                     }
    7975             :                 } else {
    7976           0 :                     Pos = len(Line.data);
    7977             :                 }
    7978             :             }
    7979             : 
    7980        9950 :             if (i == 1) {
    7981             :                 bool IOStatus;
    7982        4975 :                 int const NumPeriods = Util::ProcessNumber(Line.data.substr(0, Pos), IOStatus);
    7983        4975 :                 NumHdArgs += 4 * NumPeriods;
    7984        4975 :             } else if ((i >= 3)) {
    7985           0 :                 if (mod(i - 3, 4) == 0) ++CurCount;
    7986             :             }
    7987        9950 :             Line.data.erase(0, Pos + 1);
    7988             :         }
    7989        4975 :     }
    7990             : 
    7991        1226 :     void ReportMissing_RangeData(EnergyPlusData &state)
    7992             :     {
    7993             : 
    7994             :         // SUBROUTINE INFORMATION:
    7995             :         //       AUTHOR         Linda Lawrie
    7996             :         //       DATE WRITTEN   January 2002
    7997             : 
    7998             :         // PURPOSE OF THIS SUBROUTINE:
    7999             :         // This subroutine reports the counts of missing/out of range data
    8000             :         // for weather file environments.
    8001             : 
    8002             :         static constexpr std::string_view MissString("Missing Data Found on Weather Data File");
    8003             :         static constexpr std::string_view msFmt("Missing {}, Number of items={:5}");
    8004             :         static constexpr std::string_view InvString("Invalid Data Found on Weather Data File");
    8005             :         static constexpr std::string_view ivFmt("Invalid {}, Number of items={:5}");
    8006             :         static constexpr std::string_view RangeString("Out of Range Data Found on Weather Data File");
    8007             :         static constexpr std::string_view rgFmt("Out of Range {} [{},{}], Number of items={:5}");
    8008             : 
    8009        1226 :         if (!state.dataEnvrn->DisplayWeatherMissingDataWarnings) return;
    8010             : 
    8011           0 :         bool MissedHeader = false;
    8012           0 :         auto missedHeaderCheck = [&](Real64 const value, std::string const &description) {
    8013           0 :             if (value > 0) {
    8014           0 :                 if (!MissedHeader) {
    8015           0 :                     ShowWarningError(state, std::string{MissString});
    8016           0 :                     MissedHeader = true;
    8017             :                 }
    8018           0 :                 ShowMessage(state, format(msFmt, "\"" + description + "\"", value));
    8019             :             }
    8020           0 :         };
    8021             : 
    8022           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDryBulbTemp, "Dry Bulb Temperature");
    8023           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutBaroPress, "Atmospheric Pressure");
    8024           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutRelHum, "Relative Humidity");
    8025           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OutDewPointTemp, "Dew Point Temperatures");
    8026           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindSpeed, "Wind Speed");
    8027           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.WindDir, "Wind Direction");
    8028           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.BeamSolarRad, "Direct Radiation");
    8029           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.DifSolarRad, "Diffuse Radiation");
    8030           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.TotalSkyCover, "Total Sky Cover");
    8031           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.OpaqueSkyCover, "Opaque Sky Cover");
    8032           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.SnowDepth, "Snow Depth");
    8033           0 :         if (state.dataWeather->wvarsMissedCounts.WeathCodes > 0) {
    8034           0 :             ShowWarningError(state, std::string{InvString});
    8035           0 :             ShowMessage(state, format(ivFmt, "\"Weather Codes\" (not equal 9 digits)", state.dataWeather->wvarsMissedCounts.WeathCodes));
    8036             :         }
    8037           0 :         missedHeaderCheck(state.dataWeather->wvarsMissedCounts.LiquidPrecip, "Liquid Precipitation Depth");
    8038             : 
    8039           0 :         bool OutOfRangeHeader = false;
    8040             :         auto outOfRangeHeaderCheck = // (AUTO_OK_LAMBDA)
    8041           0 :             [&](Real64 const value, std::string_view description, std::string_view rangeLow, std::string_view rangeHigh, std::string_view extraMsg) {
    8042           0 :                 if (value > 0) {
    8043           0 :                     if (!OutOfRangeHeader) {
    8044           0 :                         ShowWarningError(state, std::string{RangeString});
    8045           0 :                         OutOfRangeHeader = true;
    8046             :                     }
    8047           0 :                     ShowMessage(state, EnergyPlus::format(rgFmt, description, rangeLow, rangeHigh, value));
    8048           0 :                     if (!extraMsg.empty()) ShowMessage(state, std::string{extraMsg});
    8049             :                 }
    8050           0 :             };
    8051           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDryBulbTemp, "Dry Bulb Temperatures", ">=-90", "<=70", "");
    8052           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutBaroPress,
    8053             :                               "Atmospheric Pressure",
    8054             :                               ">31000",
    8055             :                               "<=120000",
    8056             :                               "Out of Range values set to last good value");
    8057           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutRelHum, "Relative Humidity", ">=0", "<=110", "");
    8058           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.OutDewPointTemp, "Dew Point Temperatures", ">=-90", "<=70", "");
    8059           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindSpeed, "Wind Speed", ">=0", "<=40", "");
    8060           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.WindDir, "Wind Direction", ">=0", "<=360", "");
    8061           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.BeamSolarRad, "Direct Radiation", ">=0", "NoLimit", "");
    8062           0 :         outOfRangeHeaderCheck(state.dataWeather->wvarsOutOfRangeCounts.DifSolarRad, "Diffuse Radiation", ">=0", "NoLimit", "");
    8063             :     }
    8064             : 
    8065         796 :     void SetupInterpolationValues(EnergyPlusData &state)
    8066             :     {
    8067             : 
    8068             :         // SUBROUTINE INFORMATION:
    8069             :         //       AUTHOR         Linda Lawrie
    8070             :         //       DATE WRITTEN   November 2002
    8071             : 
    8072             :         // PURPOSE OF THIS SUBROUTINE:
    8073             :         // This subroutine creates the "interpolation" values / weights that are used for
    8074             :         // interpolating weather data from hourly down to the time step level.
    8075             : 
    8076             :         // METHODOLOGY EMPLOYED:
    8077             :         // Create arrays (InterpolationValues, SolarInterpolationValues) dependent on
    8078             :         // Number of Time Steps in Hour.  This will be used in the "SetCurrentWeather" procedure.
    8079             : 
    8080         796 :         int halfpoint = 0;
    8081             : 
    8082         796 :         state.dataWeather->Interpolation.allocate(state.dataGlobal->NumOfTimeStepInHour);
    8083         796 :         state.dataWeather->SolarInterpolation.allocate(state.dataGlobal->NumOfTimeStepInHour);
    8084         796 :         state.dataWeather->Interpolation = 0.0;
    8085         796 :         state.dataWeather->SolarInterpolation = 0.0;
    8086             : 
    8087        5369 :         for (int tloop = 1; tloop <= state.dataGlobal->NumOfTimeStepInHour; ++tloop) {
    8088        4573 :             state.dataWeather->Interpolation(tloop) =
    8089        4573 :                 (state.dataGlobal->NumOfTimeStepInHour == 1) ? 1.0 : min(1.0, (double(tloop) / double(state.dataGlobal->NumOfTimeStepInHour)));
    8090             :         }
    8091             : 
    8092         796 :         if (mod(state.dataGlobal->NumOfTimeStepInHour, 2) == 0) {
    8093             :             // even number of time steps.
    8094         783 :             halfpoint = state.dataGlobal->NumOfTimeStepInHour / 2;
    8095         783 :             state.dataWeather->SolarInterpolation(halfpoint) = 1.0;
    8096         783 :             Real64 tweight = 1.0 / double(state.dataGlobal->NumOfTimeStepInHour);
    8097        3063 :             for (int tloop = halfpoint + 1, hpoint = 1; tloop <= state.dataGlobal->NumOfTimeStepInHour; ++tloop, ++hpoint) {
    8098        2280 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8099             :             }
    8100        2280 :             for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8101        1497 :                 state.dataWeather->SolarInterpolation(tloop) = 1.0 - hpoint * tweight;
    8102             :             }
    8103             :         } else { // odd number of time steps
    8104          13 :             if (state.dataGlobal->NumOfTimeStepInHour == 1) {
    8105          13 :                 state.dataWeather->SolarInterpolation(1) = 0.5;
    8106           0 :             } else if (state.dataGlobal->NumOfTimeStepInHour == 3) {
    8107           0 :                 state.dataWeather->SolarInterpolation(1) = 5.0 / 6.0;
    8108           0 :                 state.dataWeather->SolarInterpolation(2) = 5.0 / 6.0;
    8109           0 :                 state.dataWeather->SolarInterpolation(3) = 0.5;
    8110             :             } else {
    8111           0 :                 Real64 tweight = 1.0 / double(state.dataGlobal->NumOfTimeStepInHour);
    8112           0 :                 halfpoint = state.dataGlobal->NumOfTimeStepInHour / 2;
    8113           0 :                 Real64 tweight1 = 1.0 - tweight / 2.0;
    8114           0 :                 state.dataWeather->SolarInterpolation(halfpoint) = tweight1;
    8115           0 :                 state.dataWeather->SolarInterpolation(halfpoint + 1) = tweight1;
    8116           0 :                 for (int tloop = halfpoint + 2, hpoint = 1; tloop <= state.dataGlobal->NumOfTimeStepInHour; ++tloop, ++hpoint) {
    8117           0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8118             :                 }
    8119           0 :                 for (int tloop = halfpoint - 1, hpoint = 1; tloop >= 1; --tloop, ++hpoint) {
    8120           0 :                     state.dataWeather->SolarInterpolation(tloop) = tweight1 - hpoint * tweight;
    8121             :                 }
    8122             :             }
    8123             :         }
    8124         796 :     }
    8125             : 
    8126         797 :     void SetupEnvironmentTypes(EnergyPlusData &state)
    8127             :     {
    8128             : 
    8129             :         // SUBROUTINE INFORMATION:
    8130             :         //       AUTHOR         Linda Lawrie
    8131             :         //       DATE WRITTEN   October 2010
    8132             : 
    8133             :         // PURPOSE OF THIS SUBROUTINE:
    8134             :         // Make sure Environment derived type is set prior to getting
    8135             :         // Weather Properties
    8136             : 
    8137             :         // Transfer weather file information to the Environment derived type
    8138         797 :         state.dataWeather->Envrn = state.dataEnvrn->TotDesDays + 1;
    8139             : 
    8140             :         // Sizing Periods from Weather File
    8141         802 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunDesPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8142           5 :             auto const &runPer = state.dataWeather->RunPeriodDesignInput(iRunPer);
    8143           5 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8144             : 
    8145           5 :             envCurr.StartMonth = runPer.startMonth;
    8146           5 :             envCurr.StartDay = runPer.startDay;
    8147           5 :             envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, state.dataWeather->LeapYearAdd);
    8148           5 :             envCurr.TotalDays = runPer.totalDays;
    8149           5 :             envCurr.EndMonth = runPer.endMonth;
    8150           5 :             envCurr.EndDay = runPer.endDay;
    8151           5 :             envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, state.dataWeather->LeapYearAdd);
    8152           5 :             envCurr.NumSimYears = runPer.numSimYears;
    8153           5 :             if (envCurr.StartJDay <= envCurr.EndJDay) {
    8154           5 :                 envCurr.TotalDays = (envCurr.EndJDay - envCurr.StartJDay + 1) * envCurr.NumSimYears;
    8155             :             } else {
    8156           0 :                 envCurr.TotalDays =
    8157           0 :                     (General::OrdinalDay(12, 31, state.dataWeather->LeapYearAdd) - envCurr.StartJDay + 1 + envCurr.EndJDay) * envCurr.NumSimYears;
    8158             :             }
    8159           5 :             state.dataEnvrn->TotRunDesPersDays += envCurr.TotalDays;
    8160           5 :             envCurr.UseDST = runPer.useDST;
    8161           5 :             envCurr.UseHolidays = runPer.useHolidays;
    8162           5 :             envCurr.Title = runPer.title;
    8163           5 :             envCurr.cKindOfEnvrn = runPer.periodType;
    8164           5 :             envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodDesign;
    8165           5 :             envCurr.DesignDayNum = 0;
    8166           5 :             envCurr.RunPeriodDesignNum = iRunPer;
    8167           5 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8168           5 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8169           5 :             envCurr.SetWeekDays = false;
    8170           5 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8171           5 :             envCurr.UseRain = runPer.useRain;
    8172           5 :             envCurr.UseSnow = runPer.useSnow;
    8173           5 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // this will just the default
    8174             :         }
    8175             : 
    8176             :         // RunPeriods from weather file
    8177        1984 :         for (int iRunPer = 1; iRunPer <= state.dataWeather->TotRunPers; ++iRunPer, ++state.dataWeather->Envrn) {
    8178        1187 :             auto const &runPer = state.dataWeather->RunPeriodInput(iRunPer);
    8179        1187 :             auto &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8180             : 
    8181        1187 :             envCurr.StartMonth = runPer.startMonth;
    8182        1187 :             envCurr.StartDay = runPer.startDay;
    8183        1187 :             envCurr.StartYear = runPer.startYear;
    8184        1187 :             envCurr.EndMonth = runPer.endMonth;
    8185        1187 :             envCurr.EndDay = runPer.endDay;
    8186        1187 :             envCurr.EndYear = runPer.endYear;
    8187        1187 :             envCurr.NumSimYears = runPer.numSimYears;
    8188        1187 :             envCurr.CurrentYear = runPer.startYear;
    8189        1187 :             envCurr.IsLeapYear = runPer.isLeapYear;
    8190        1187 :             envCurr.TreatYearsAsConsecutive = true;
    8191        1187 :             if (runPer.actualWeather) {
    8192             :                 // This will require leap years to be present, thus Julian days can be used for all the calculations
    8193           0 :                 envCurr.StartJDay = envCurr.StartDate = runPer.startJulianDate;
    8194           0 :                 envCurr.EndJDay = envCurr.EndDate = runPer.endJulianDate;
    8195           0 :                 envCurr.TotalDays = envCurr.EndDate - envCurr.StartDate + 1;
    8196           0 :                 envCurr.RawSimDays = envCurr.EndDate - envCurr.StartDate + 1;
    8197           0 :                 envCurr.MatchYear = true;
    8198           0 :                 envCurr.ActualWeather = true;
    8199             :             } else { // std RunPeriod
    8200        1187 :                 envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8201        1187 :                 if (envCurr.StartYear == envCurr.EndYear) {
    8202             :                     // Short-circuit all the calculations, we're in a single year
    8203             : 
    8204        1181 :                     envCurr.IsLeapYear = isLeapYear(envCurr.StartYear) && state.dataWeather->WFAllowsLeapYears;
    8205        1181 :                     int LocalLeapYearAdd = (int)envCurr.IsLeapYear;
    8206             : 
    8207        1181 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, LocalLeapYearAdd);
    8208        1181 :                     envCurr.EndJDay = General::OrdinalDay(runPer.endMonth, runPer.endDay, LocalLeapYearAdd);
    8209        1181 :                     envCurr.RawSimDays = (envCurr.EndJDay - envCurr.StartJDay + 1);
    8210        1181 :                     envCurr.TotalDays = envCurr.RawSimDays;
    8211             :                 } else {
    8212             :                     // Environment crosses year boundaries
    8213           6 :                     envCurr.RollDayTypeOnRepeat = runPer.RollDayTypeOnRepeat;
    8214           6 :                     envCurr.StartJDay = General::OrdinalDay(runPer.startMonth, runPer.startDay, (int)runPer.isLeapYear);
    8215          12 :                     envCurr.EndJDay = General::OrdinalDay(
    8216           6 :                         runPer.endMonth, runPer.endDay, (int)(isLeapYear(runPer.endYear) && state.dataWeather->WFAllowsLeapYears));
    8217           6 :                     envCurr.TotalDays = 366 - envCurr.StartJDay + envCurr.EndJDay + 365 * std::max(envCurr.NumSimYears - 2, 0);
    8218           6 :                     if (state.dataWeather->WFAllowsLeapYears) {
    8219             :                         // First year
    8220           0 :                         if (envCurr.StartJDay < 59) {
    8221           0 :                             if (isLeapYear(envCurr.StartYear)) {
    8222           0 :                                 ++envCurr.TotalDays;
    8223             :                             }
    8224             :                         }
    8225             :                         // Middle years
    8226           0 :                         for (int yr = envCurr.StartYear + 1; yr < envCurr.EndYear; ++yr) {
    8227           0 :                             if (isLeapYear(yr)) {
    8228           0 :                                 ++envCurr.TotalDays;
    8229             :                             }
    8230             :                         }
    8231             :                         // Last year not needed, the end ordinal date will take this into account
    8232             :                     }
    8233           6 :                     envCurr.RawSimDays = envCurr.TotalDays;
    8234             :                 }
    8235             :             }
    8236        1187 :             envCurr.UseDST = runPer.useDST;
    8237        1187 :             envCurr.UseHolidays = runPer.useHolidays;
    8238        1187 :             if (runPer.title.empty()) {
    8239           1 :                 envCurr.Title = state.dataEnvrn->WeatherFileLocationTitle;
    8240             :             } else {
    8241        1186 :                 envCurr.Title = runPer.title;
    8242             :             }
    8243        1187 :             if (envCurr.KindOfEnvrn == Constant::KindOfSim::ReadAllWeatherData) {
    8244           1 :                 envCurr.cKindOfEnvrn = "ReadAllWeatherDataRunPeriod";
    8245             :             } else {
    8246        1186 :                 envCurr.cKindOfEnvrn = "WeatherFileRunPeriod";
    8247        1186 :                 envCurr.KindOfEnvrn = Constant::KindOfSim::RunPeriodWeather;
    8248             :             }
    8249        1187 :             envCurr.DayOfWeek = runPer.dayOfWeek;
    8250        1187 :             envCurr.MonWeekDay = runPer.monWeekDay;
    8251        1187 :             envCurr.SetWeekDays = false;
    8252        1187 :             envCurr.ApplyWeekendRule = runPer.applyWeekendRule;
    8253        1187 :             envCurr.UseRain = runPer.useRain;
    8254        1187 :             envCurr.UseSnow = runPer.useSnow;
    8255        1187 :             envCurr.firstHrInterpUseHr1 = runPer.firstHrInterpUsingHr1; // first hour interpolation choice
    8256             :         }                                                               // for (i)
    8257         797 :     }
    8258             : 
    8259        2372 :     bool isLeapYear(int const Year)
    8260             :     {
    8261             :         // true if it's a leap year, false if not.
    8262             : 
    8263        2372 :         if (mod(Year, 4) == 0) { // Potential Leap Year
    8264           2 :             if (!(mod(Year, 100) == 0 && mod(Year, 400) != 0)) {
    8265           2 :                 return true;
    8266             :             }
    8267             :         }
    8268        2370 :         return false;
    8269             :     }
    8270             : 
    8271        9305 :     int computeJulianDate(int const gyyyy, // input/output gregorian year, should be specified as 4 digits
    8272             :                           int const gmm,   // input/output gregorian month
    8273             :                           int const gdd    // input/output gregorian day
    8274             :     )
    8275             :     {
    8276             :         // SUBROUTINE INFORMATION:
    8277             :         //       AUTHOR         Jason DeGraw
    8278             :         //       DATE WRITTEN   10/25/2017
    8279             : 
    8280             :         // PURPOSE OF THIS SUBROUTINE:
    8281             :         // Split the former JGDate function in two. Convert a gregorian
    8282             :         // date to actual julian date.  the advantage of storing a julian date
    8283             :         // in the jdate format rather than a 5 digit format is that any
    8284             :         // number of days can be add or subtracted to jdate and
    8285             :         // that result is a proper julian date.
    8286             : 
    8287             :         // REFERENCES:
    8288             :         // for discussion of this algorithm,
    8289             :         // see cacm, vol 11, no 10, oct 1968, page 657
    8290             : 
    8291        9305 :         int tyyyy = gyyyy;
    8292        9305 :         int tmm = gmm;
    8293        9305 :         int tdd = gdd;
    8294        9305 :         int l = (tmm - 14) / 12;
    8295        9305 :         return tdd - 32075 + 1461 * (tyyyy + 4800 + l) / 4 + 367 * (tmm - 2 - l * 12) / 12 - 3 * ((tyyyy + 4900 + l) / 100) / 4;
    8296             :     }
    8297             : 
    8298           0 :     int computeJulianDate(GregorianDate const &gdate)
    8299             :     {
    8300           0 :         return computeJulianDate(gdate.year, gdate.month, gdate.day);
    8301             :     }
    8302             : 
    8303           0 :     GregorianDate computeGregorianDate(int const jdate)
    8304             :     {
    8305           0 :         int tdate = jdate;
    8306           0 :         int l = tdate + 68569;
    8307           0 :         int n = 4 * l / 146097;
    8308           0 :         l -= (146097 * n + 3) / 4;
    8309           0 :         int tyyyy = 4000 * (l + 1) / 1461001;
    8310           0 :         l = l - 1461 * tyyyy / 4 + 31;
    8311           0 :         int tmm = 80 * l / 2447;
    8312           0 :         int tdd = l - 2447 * tmm / 80;
    8313           0 :         l = tmm / 11;
    8314           0 :         tmm += 2 - 12 * l;
    8315           0 :         tyyyy += 100 * (n - 49) + l;
    8316           0 :         return {tyyyy, tmm, tdd};
    8317             :     }
    8318             : 
    8319         152 :     ScheduleManager::DayType calculateDayOfWeek(EnergyPlusData &state, int const year, int const month, int const day)
    8320             :     {
    8321             : 
    8322             :         // FUNCTION INFORMATION:
    8323             :         //       AUTHOR         Linda Lawrie
    8324             :         //       DATE WRITTEN   March 2012
    8325             :         //       MODIFIED       October 2017, Jason DeGraw
    8326             : 
    8327             :         // PURPOSE OF THIS FUNCTION:
    8328             :         // Calculate the correct day of week.
    8329             : 
    8330             :         // METHODOLOGY EMPLOYED:
    8331             :         // Zeller's algorithm.
    8332             : 
    8333             :         // REFERENCES:
    8334             :         // http://en.wikipedia.org/wiki/Zeller%27s_congruence
    8335             :         // and other references around the web.
    8336             : 
    8337         152 :         int Gyyyy(year); // Gregorian yyyy
    8338         152 :         int Gmm(month);  // Gregorian mm
    8339             : 
    8340             :         // Jan, Feb are 13, 14 months of previous year
    8341         152 :         if (Gmm < 3) {
    8342          89 :             Gmm += 12;
    8343          89 :             --Gyyyy;
    8344             :         }
    8345             : 
    8346         152 :         state.dataEnvrn->DayOfWeek = mod(day + (13 * (Gmm + 1) / 5) + Gyyyy + (Gyyyy / 4) + 6 * (Gyyyy / 100) + (Gyyyy / 400), 7);
    8347         152 :         if (state.dataEnvrn->DayOfWeek == 0) state.dataEnvrn->DayOfWeek = 7;
    8348             : 
    8349         152 :         return static_cast<ScheduleManager::DayType>(state.dataEnvrn->DayOfWeek);
    8350             :     }
    8351             : 
    8352        1033 :     int calculateDayOfYear(int const Month, int const Day, bool const leapYear)
    8353             :     {
    8354             : 
    8355             :         // FUNCTION INFORMATION:
    8356             :         //       AUTHOR         Jason DeGraw
    8357             :         //       DATE WRITTEN   October 10, 2017
    8358             : 
    8359             :         // PURPOSE OF THIS FUNCTION:
    8360             :         // Compute the day of the year for leap and non-leap years.
    8361             : 
    8362             :         static std::array<int, 12> const daysbefore{{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}};
    8363             :         static std::array<int, 12> const daysbeforeleap{{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
    8364             : 
    8365             :         // Could probably do some bounds checking here, but for now assume the month is in [1, 12]
    8366        1033 :         if (leapYear) {
    8367           0 :             return daysbeforeleap[Month - 1] + Day;
    8368             :         } else {
    8369        1033 :             return daysbefore[Month - 1] + Day;
    8370             :         }
    8371             :     }
    8372             : 
    8373        2370 :     bool validMonthDay(int const month, int const day, int const leapYearAdd)
    8374             :     {
    8375             : 
    8376             :         // FUNCTION INFORMATION:
    8377             :         //       AUTHOR         Jason DeGraw
    8378             :         //       DATE WRITTEN   October 31, 2017
    8379             : 
    8380             :         // PURPOSE OF THIS FUNCTION:
    8381             :         // Determine if a month/day+leapyear combination is valid.
    8382             : 
    8383        2370 :         switch (month) {
    8384        2210 :         case 1:
    8385             :         case 3:
    8386             :         case 5:
    8387             :         case 7:
    8388             :         case 8:
    8389             :         case 10:
    8390             :         case 12:
    8391        2210 :             if (day > 31) {
    8392           0 :                 return false;
    8393             :             }
    8394        2210 :             break;
    8395         119 :         case 4:
    8396             :         case 6:
    8397             :         case 9:
    8398             :         case 11:
    8399         119 :             if (day > 30) {
    8400           0 :                 return false;
    8401             :             }
    8402         119 :             break;
    8403          41 :         case 2:
    8404          41 :             if (day > 28 + leapYearAdd) {
    8405           0 :                 return false;
    8406             :             }
    8407          41 :             break;
    8408           0 :         default:
    8409           0 :             return false;
    8410             :         }
    8411        2370 :         return true;
    8412             :     }
    8413             : 
    8414           0 :     void AnnualMonthlyDryBulbWeatherData::CalcAnnualAndMonthlyDryBulbTemp(EnergyPlusData &state)
    8415             :     {
    8416             : 
    8417             :         // PURPOSE OF THIS SUBROUTINE:
    8418             :         // Calculates monthly daily average outdoor air drybulb temperature from
    8419             :         // either weather (*.EPW) file or reads monthly daily average outdoor air
    8420             :         // drybulb temperature from STAT (*.stat) for use to autosize main water
    8421             :         // temperature.
    8422             : 
    8423           0 :         Real64 MonthlyDailyDryBulbMin(200.0);               // monthly-daily minimum outside air dry-bulb temperature
    8424           0 :         Real64 MonthlyDailyDryBulbMax(-200.0);              // monthly-daily maximum outside air dry-bulb temperature
    8425           0 :         Real64 AnnualDailyAverageDryBulbTempSum(0.0);       // annual sum of daily average outside air dry-bulb temperature
    8426           0 :         Array1D<Real64> MonthlyAverageDryBulbTemp(12, 0.0); // monthly-daily average outside air temperature
    8427             : 
    8428           0 :         if (!this->OADryBulbWeatherDataProcessed) {
    8429           0 :             const bool statFileExists = FileSystem::fileExists(state.files.inStatFilePath.filePath);
    8430           0 :             const bool epwFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    8431           0 :             if (statFileExists) {
    8432           0 :                 auto statFile = state.files.inStatFilePath.try_open();
    8433           0 :                 if (!statFile.good()) {
    8434           0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", statFile.filePath));
    8435           0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8436           0 :                     return;
    8437             :                 }
    8438             : 
    8439           0 :                 std::string lineAvg;
    8440           0 :                 while (statFile.good()) {
    8441           0 :                     auto lineIn = statFile.readLine();
    8442           0 :                     if (has(lineIn.data, "Monthly Statistics for Dry Bulb temperatures")) {
    8443           0 :                         for (int i = 1; i <= 7; ++i) {
    8444           0 :                             lineIn = statFile.readLine();
    8445             :                         }
    8446           0 :                         lineIn = statFile.readLine();
    8447           0 :                         lineAvg = lineIn.data;
    8448           0 :                         break;
    8449             :                     }
    8450           0 :                 }
    8451           0 :                 if (lineAvg.empty()) {
    8452           0 :                     ShowSevereError(
    8453             :                         state,
    8454           0 :                         format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have Monthly Statistics for Dry Bulb temperatures.",
    8455             :                                statFile.filePath));
    8456           0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8457           0 :                     return;
    8458           0 :                 } else if (lineAvg.find("Daily Avg") == std::string::npos) {
    8459           0 :                     ShowSevereError(state,
    8460           0 :                                     format("CalcAnnualAndMonthlyDryBulbTemp: Stat file '{}' does not have the 'Daily Avg' line in the Monthly "
    8461             :                                            "Statistics for Dry Bulb temperatures.",
    8462             :                                            statFile.filePath));
    8463           0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8464           0 :                     return;
    8465             :                 } else {
    8466           0 :                     int AnnualNumberOfDays = 0;
    8467           0 :                     for (int i = 1; i <= 12; ++i) {
    8468           0 :                         MonthlyAverageDryBulbTemp(i) = OutputReportTabular::StrToReal(OutputReportTabular::GetColumnUsingTabs(lineAvg, i + 2));
    8469           0 :                         AnnualDailyAverageDryBulbTempSum += MonthlyAverageDryBulbTemp(i) * state.dataWeather->EndDayOfMonth(i);
    8470           0 :                         MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyAverageDryBulbTemp(i));
    8471           0 :                         MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyAverageDryBulbTemp(i));
    8472           0 :                         AnnualNumberOfDays += state.dataWeather->EndDayOfMonth(i);
    8473             :                     }
    8474           0 :                     this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8475           0 :                     this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8476           0 :                     this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8477           0 :                     this->OADryBulbWeatherDataProcessed = true;
    8478             :                 }
    8479           0 :             } else if (epwFileExists) {
    8480           0 :                 auto epwFile = state.files.inputWeatherFilePath.try_open();
    8481           0 :                 bool epwHasLeapYear(false);
    8482           0 :                 if (!epwFile.good()) {
    8483           0 :                     ShowSevereError(state, format("CalcAnnualAndMonthlyDryBulbTemp: Could not open file {} for input (read).", epwFile.filePath));
    8484           0 :                     ShowContinueError(state, "Water Mains Temperature will be set to a fixed default value of 10.0 C.");
    8485           0 :                     return;
    8486             :                 }
    8487           0 :                 for (int i = 1; i <= 8; ++i) { // Headers
    8488           0 :                     auto epwLine = epwFile.readLine();
    8489             : 
    8490           0 :                     if (i == 5) {
    8491             :                         // HOLIDAYS/DAYLIGHT SAVINGS,Yes,0,0,0
    8492           0 :                         std::string::size_type pos = index(epwLine.data, ',');
    8493           0 :                         epwLine.data.erase(0, pos + 1);
    8494           0 :                         pos = index(epwLine.data, ',');
    8495           0 :                         std::string LeapYear = Util::makeUPPER(epwLine.data.substr(0, pos));
    8496           0 :                         if (LeapYear[0] == 'Y') {
    8497           0 :                             epwHasLeapYear = true;
    8498             :                         }
    8499           0 :                     }
    8500           0 :                 }
    8501           0 :                 Array1D<int> EndDayOfMonthLocal;
    8502           0 :                 EndDayOfMonthLocal = state.dataWeather->EndDayOfMonth;
    8503           0 :                 if (epwHasLeapYear) {
    8504             :                     // increase number of days for february by one day if weather data has leap year
    8505           0 :                     EndDayOfMonthLocal(2) = EndDayOfMonthLocal(2) + 1;
    8506             :                 }
    8507             :                 int DayNum;
    8508             :                 int DaysCountOfMonth;
    8509           0 :                 for (int i = 1; i <= 12; ++i) {
    8510           0 :                     Real64 MonthlyDailyDryBulbAvg = 0.0;
    8511           0 :                     DaysCountOfMonth = EndDayOfMonthLocal(i);
    8512           0 :                     for (DayNum = 1; DayNum <= DaysCountOfMonth; ++DayNum) {
    8513           0 :                         Real64 DailyAverageDryBulbTemp = 0.0;
    8514             :                         std::string::size_type pos;
    8515           0 :                         for (int j = 1; j <= 24; ++j) {
    8516           0 :                             auto epwLine = epwFile.readLine();
    8517           0 :                             for (int ind = 1; ind <= 6; ++ind) {
    8518           0 :                                 pos = index(epwLine.data, ',');
    8519           0 :                                 epwLine.data.erase(0, pos + 1);
    8520             :                             }
    8521           0 :                             pos = index(epwLine.data, ',');
    8522           0 :                             Real64 HourlyDryBulbTemp = OutputReportTabular::StrToReal(epwLine.data.substr(0, pos));
    8523           0 :                             DailyAverageDryBulbTemp += (HourlyDryBulbTemp / 24.0);
    8524           0 :                         }
    8525           0 :                         AnnualDailyAverageDryBulbTempSum += DailyAverageDryBulbTemp;
    8526           0 :                         MonthlyDailyDryBulbAvg += (DailyAverageDryBulbTemp / DaysCountOfMonth);
    8527             :                     }
    8528           0 :                     MonthlyAverageDryBulbTemp(i) = MonthlyDailyDryBulbAvg;
    8529           0 :                     MonthlyDailyDryBulbMin = min(MonthlyDailyDryBulbMin, MonthlyDailyDryBulbAvg);
    8530           0 :                     MonthlyDailyDryBulbMax = max(MonthlyDailyDryBulbMax, MonthlyDailyDryBulbAvg);
    8531             :                 }
    8532             :                 // calculate annual average outdoor air dry-bulb temperature and monthly daily average
    8533             :                 // outdoor air temperature maximum difference
    8534           0 :                 int AnnualNumberOfDays = 365;
    8535           0 :                 if (epwHasLeapYear) AnnualNumberOfDays++;
    8536           0 :                 this->AnnualAvgOADryBulbTemp = AnnualDailyAverageDryBulbTempSum / AnnualNumberOfDays;
    8537           0 :                 this->MonthlyAvgOADryBulbTempMaxDiff = MonthlyDailyDryBulbMax - MonthlyDailyDryBulbMin;
    8538           0 :                 this->MonthlyDailyAverageDryBulbTemp = MonthlyAverageDryBulbTemp;
    8539           0 :                 this->OADryBulbWeatherDataProcessed = true;
    8540           0 :             } else {
    8541           0 :                 ShowSevereError(state, "CalcAnnualAndMonthlyDryBulbTemp: weather file or stat file does not exist.");
    8542           0 :                 ShowContinueError(state, format("Weather file: {}.", state.files.inputWeatherFilePath.filePath));
    8543           0 :                 ShowContinueError(state, format("Stat file: {}.", state.files.inStatFilePath.filePath));
    8544           0 :                 ShowContinueError(state, "Water Mains Monthly Temperature cannot be calculated using CorrelationFromWeatherFile method.");
    8545           0 :                 ShowContinueError(state, "Instead a fixed default value of 10.0 C will be used.");
    8546             :             }
    8547             :         }
    8548           0 :     }
    8549             : 
    8550         796 :     void ReportWaterMainsTempParameters(EnergyPlusData &state)
    8551             :     {
    8552             :         // PURPOSE OF THIS SUBROUTINE:
    8553             :         // report site water mains temperature object user inputs and/or parameters calculated
    8554             :         // from weather or stat file
    8555             : 
    8556         796 :         if (!state.files.eio.good()) {
    8557           0 :             return;
    8558             :         }
    8559             : 
    8560         796 :         std::stringstream ss;
    8561         796 :         auto *eiostream = &ss;
    8562             : 
    8563             :         // Write annual average OA temperature and maximum difference in monthly-daily average outdoor air temperature
    8564             :         *eiostream << "! <Site Water Mains Temperature Information>"
    8565             :                       ",Calculation Method{}"
    8566             :                       ",Water Mains Temperature Schedule Name{}"
    8567             :                       ",Annual Average Outdoor Air Temperature{C}"
    8568             :                       ",Maximum Difference In Monthly Average Outdoor Air Temperatures{deltaC}"
    8569         796 :                       ",Fixed Default Water Mains Temperature{C}\n";
    8570             : 
    8571         796 :         switch (state.dataWeather->WaterMainsTempsMethod) {
    8572           3 :         case WaterMainsTempCalcMethod::Schedule:
    8573           3 :             *eiostream << "Site Water Mains Temperature Information,";
    8574           3 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8575           6 :                        << state.dataWeather->WaterMainsTempsScheduleName << ",";
    8576           3 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8577           6 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8578           3 :             *eiostream << "NA\n";
    8579           3 :             break;
    8580         126 :         case WaterMainsTempCalcMethod::Correlation:
    8581         126 :             *eiostream << "Site Water Mains Temperature Information,";
    8582         126 :             *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8583             :                        << "NA"
    8584         252 :                        << ",";
    8585         126 :             *eiostream << format("{:.2R}", state.dataWeather->WaterMainsTempsAnnualAvgAirTemp) << ","
    8586         252 :                        << format("{:.2R}", state.dataWeather->WaterMainsTempsMaxDiffAirTemp) << ",";
    8587         126 :             *eiostream << "NA\n";
    8588         126 :             break;
    8589           0 :         case WaterMainsTempCalcMethod::CorrelationFromWeatherFile:
    8590           0 :             if (state.dataWeather->OADryBulbAverage.OADryBulbWeatherDataProcessed) {
    8591           0 :                 *eiostream << "Site Water Mains Temperature Information,";
    8592           0 :                 *eiostream << waterMainsCalcMethodNames[static_cast<int>(state.dataWeather->WaterMainsTempsMethod)] << ","
    8593             :                            << "NA"
    8594           0 :                            << ",";
    8595           0 :                 *eiostream << format("{:.2R}", state.dataWeather->OADryBulbAverage.AnnualAvgOADryBulbTemp) << ","
    8596           0 :                            << format("{:.2R}", state.dataWeather->OADryBulbAverage.MonthlyAvgOADryBulbTempMaxDiff) << ","
    8597           0 :                            << "NA\n";
    8598             :             } else {
    8599           0 :                 *eiostream << "Site Water Mains Temperature Information,";
    8600             :                 *eiostream << "FixedDefault"
    8601             :                            << ","
    8602             :                            << "NA"
    8603             :                            << ","
    8604             :                            << "NA"
    8605             :                            << ","
    8606             :                            << "NA"
    8607           0 :                            << "," << format("{:.1R}", 10.0) << '\n';
    8608             :             }
    8609           0 :             break;
    8610         667 :         default:
    8611         667 :             *eiostream << "Site Water Mains Temperature Information,";
    8612             :             *eiostream << "FixedDefault"
    8613             :                        << ","
    8614             :                        << "NA"
    8615             :                        << ","
    8616             :                        << "NA"
    8617             :                        << ","
    8618             :                        << "NA"
    8619         667 :                        << "," << format("{:.1R}", 10.0) << '\n';
    8620         667 :             break;
    8621             :         }
    8622             : 
    8623         796 :         print(state.files.eio, "{}", ss.str());
    8624         796 :     }
    8625             : 
    8626      509256 :     void calcSky(EnergyPlusData &state,
    8627             :                  Real64 &HorizIRSky,
    8628             :                  Real64 &SkyTemp,
    8629             :                  Real64 OpaqueSkyCover,
    8630             :                  Real64 DryBulb,
    8631             :                  Real64 DewPoint,
    8632             :                  Real64 RelHum,
    8633             :                  Real64 IRHoriz)
    8634             :     {
    8635      509256 :         if (IRHoriz <= 0.0) IRHoriz = 9999.0;
    8636             : 
    8637      509256 :         auto const &envCurr = state.dataWeather->Environment(state.dataWeather->Envrn);
    8638      509256 :         if (!envCurr.UseWeatherFileHorizontalIR || IRHoriz >= 9999.0) {
    8639             :             // Missing or user defined to not use IRHoriz from weather, using sky cover and clear sky emissivity
    8640           0 :             Real64 ESky = CalcSkyEmissivity(state, envCurr.skyTempModel, OpaqueSkyCover, DryBulb, DewPoint, RelHum);
    8641           0 :             HorizIRSky = ESky * Constant::StefanBoltzmann * pow_4(DryBulb + Constant::Kelvin);
    8642           0 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8643           0 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8644           0 :                 SkyTemp = (DryBulb + Constant::Kelvin) * root_4(ESky) - Constant::Kelvin;
    8645             :             } else {
    8646           0 :                 SkyTemp = 0.0; // dealt with later
    8647             :             }
    8648           0 :         } else {
    8649             :             // Valid IR from weather files
    8650      509256 :             HorizIRSky = IRHoriz;
    8651      509256 :             if (envCurr.skyTempModel == SkyTempModel::Brunt || envCurr.skyTempModel == SkyTempModel::Idso ||
    8652      509256 :                 envCurr.skyTempModel == SkyTempModel::BerdahlMartin || envCurr.skyTempModel == SkyTempModel::ClarkAllen) {
    8653      509256 :                 SkyTemp = root_4(IRHoriz / Constant::StefanBoltzmann) - Constant::Kelvin;
    8654             :             } else {
    8655           0 :                 SkyTemp = 0.0; // dealt with later
    8656             :             }
    8657             :         }
    8658      509256 :     }
    8659             : 
    8660       17804 :     void ForAllHrTs(EnergyPlusData &state, std::function<void(int, int)> f)
    8661             :     {
    8662      445100 :         for (int iHr = 1; iHr <= Constant::HoursInDay; ++iHr)
    8663     2764464 :             for (int iTS = 1; iTS <= state.dataGlobal->NumOfTimeStepInHour; ++iTS)
    8664     2337168 :                 f(iHr, iTS);
    8665       17804 :     }
    8666             : 
    8667             : } // namespace Weather
    8668             : 
    8669             : } // namespace EnergyPlus

Generated by: LCOV version 1.14