LCOV - code coverage report
Current view: top level - EnergyPlus - ScheduleManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 72.2 % 1926 1390
Test Date: 2025-07-17 05:04:31 Functions: 77.3 % 66 51

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <map>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/string.functions.hh>
      53              : 
      54              : // EnergyPlus Headers
      55              : #include <EnergyPlus/CommandLineInterface.hh>
      56              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      57              : #include <EnergyPlus/DataEnvironment.hh>
      58              : #include <EnergyPlus/DataStringGlobals.hh>
      59              : #include <EnergyPlus/DataSystemVariables.hh>
      60              : #include <EnergyPlus/EMSManager.hh>
      61              : #include <EnergyPlus/FileSystem.hh>
      62              : #include <EnergyPlus/General.hh>
      63              : // #include <EnergyPlus/GlobalNames.hh>
      64              : #include <EnergyPlus/InputProcessing/CsvParser.hh>
      65              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      66              : #include <EnergyPlus/OutputProcessor.hh>
      67              : #include <EnergyPlus/ScheduleManager.hh>
      68              : #include <EnergyPlus/StringUtilities.hh>
      69              : #include <EnergyPlus/UtilityRoutines.hh>
      70              : #include <EnergyPlus/WeatherManager.hh>
      71              : 
      72              : namespace EnergyPlus {
      73              : 
      74              : namespace Sched {
      75              :     // Module containing the Schedule Manager routines
      76              : 
      77              :     // MODULE INFORMATION:
      78              :     //       AUTHOR         Linda K. Lawrie
      79              :     //       DATE WRITTEN   September 1997
      80              :     //       MODIFIED       January 2003 -- added sub-hourly schedule possibility (and interval scheduling)
      81              :     //                      J. Glazer January 2005 -- added Schedule:File
      82              :     //                      Michael Wetter February 2010 -- added Schedule for external Interface
      83              :     //                      L Lawrie - October 2012 - added sub-hourly option for Schedule:File
      84              : 
      85              :     // PURPOSE OF THIS MODULE:
      86              :     // To provide the capabilities of getting the schedule data from the input,
      87              :     // validating it, and storing it in such a manner that the schedule manager
      88              :     // can provide the scheduling value needs for the simulation.
      89              : 
      90              :     // REFERENCES:
      91              :     // Proposal for Schedule Manager in EnergyPlus (Rick Strand)
      92              : 
      93              :     // MODULE PARAMETER DEFINITIONS
      94        17675 :     int GetScheduleTypeNum(EnergyPlusData &state, std::string const &name)
      95              :     {
      96        17675 :         auto const &s_sched = state.dataSched;
      97        45584 :         for (int i = 0; i < (int)s_sched->scheduleTypes.size(); ++i) {
      98        45572 :             if (s_sched->scheduleTypes[i]->Name == name) {
      99        17663 :                 return i;
     100              :             }
     101              :         }
     102           12 :         return SchedNum_Invalid;
     103              :     }
     104              : 
     105        26302 :     Real64 ScheduleBase::getMinVal(EnergyPlusData &state)
     106              :     {
     107        26302 :         if (!isMinMaxSet) {
     108            2 :             setMinMaxVals(state);
     109              :         }
     110        26302 :         return minVal;
     111              :     }
     112              : 
     113        26092 :     Real64 ScheduleBase::getMaxVal(EnergyPlusData &state)
     114              :     {
     115        26092 :         if (!isMinMaxSet) {
     116          414 :             setMinMaxVals(state);
     117              :         }
     118        26092 :         return maxVal;
     119              :     }
     120              : 
     121              :     // Day types are 1-based for EMS and output and other uses, so add a dummy
     122              :     constexpr std::array<std::string_view, (int)DayType::Num> dayTypeNames = {"Unused",
     123              :                                                                               "Sunday",
     124              :                                                                               "Monday",
     125              :                                                                               "Tuesday",
     126              :                                                                               "Wednesday",
     127              :                                                                               "Thursday",
     128              :                                                                               "Friday",
     129              :                                                                               "Saturday",
     130              :                                                                               "Holiday",
     131              :                                                                               "SummerDesignDay",
     132              :                                                                               "WinterDesignDay",
     133              :                                                                               "CustomDay1",
     134              :                                                                               "CustomDay2"};
     135              : 
     136              :     constexpr std::array<std::string_view, (int)DayType::Num> dayTypeNamesUC = {"UNUSED",
     137              :                                                                                 "SUNDAY",
     138              :                                                                                 "MONDAY",
     139              :                                                                                 "TUESDAY",
     140              :                                                                                 "WEDNESDAY",
     141              :                                                                                 "THURSDAY",
     142              :                                                                                 "FRIDAY",
     143              :                                                                                 "SATURDAY",
     144              :                                                                                 "HOLIDAY",
     145              :                                                                                 "SUMMERDESIGNDAY",
     146              :                                                                                 "WINTERDESIGNDAY",
     147              :                                                                                 "CUSTOMDAY1",
     148              :                                                                                 "CUSTOMDAY2"};
     149              : 
     150              :     static constexpr std::array<std::string_view, (int)LimitUnits::Num> limitUnitNamesUC = {"DIMENSIONLESS",
     151              :                                                                                             "TEMPERATURE",
     152              :                                                                                             "DELTATEMPERATURE",
     153              :                                                                                             "PRECIPITATIONRATE",
     154              :                                                                                             "ANGLE",
     155              :                                                                                             "CONVECTIONCOEFFICIENT",
     156              :                                                                                             "ACTIVITYLEVEL",
     157              :                                                                                             "VELOCITY",
     158              :                                                                                             "CAPACITY",
     159              :                                                                                             "POWER",
     160              :                                                                                             "AVAILABILITY",
     161              :                                                                                             "PERCENT",
     162              :                                                                                             "CONTROL",
     163              :                                                                                             "MODE"};
     164              : 
     165              :     constexpr std::array<std::string_view, (int)ReportLevel::Num> reportLevelNames = {"Hourly", "Timestep"};
     166              :     constexpr std::array<std::string_view, (int)ReportLevel::Num> reportLevelNamesUC = {"HOURLY", "TIMESTEP"};
     167              :     constexpr std::array<std::string_view, (int)Interpolation::Num> interpolationNames = {"No", "Average", "Linear"};
     168              :     constexpr std::array<std::string_view, (int)Interpolation::Num> interpolationNamesUC = {"NO", "AVERAGE", "LINEAR"};
     169              : 
     170          532 :     bool DaySchedule::checkValsForLimitViolations(EnergyPlusData &state) const
     171              :     {
     172          532 :         auto &s_sched = state.dataSched;
     173              : 
     174          532 :         if (this->schedTypeNum == SchedNum_Invalid) {
     175            0 :             return false;
     176              :         }
     177          532 :         auto *schedType = s_sched->scheduleTypes[this->schedTypeNum];
     178          532 :         if (!schedType->isLimited) {
     179           58 :             return false;
     180              :         }
     181              : 
     182        45642 :         for (int i = 0; i < Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour; ++i) {
     183        45168 :             if (this->tsVals[i] < schedType->minVal || this->tsVals[i] > schedType->maxVal) {
     184            0 :                 return true;
     185              :             }
     186              :         }
     187              : 
     188          474 :         return false;
     189              :     } // ScheduleDay::checkValsForLimitViolations()
     190              : 
     191          532 :     bool DaySchedule::checkValsForBadIntegers(EnergyPlusData &state) const
     192              :     {
     193          532 :         auto &s_sched = state.dataSched;
     194          532 :         if (this->schedTypeNum == SchedNum_Invalid) {
     195            0 :             return false;
     196              :         }
     197          532 :         auto *schedType = s_sched->scheduleTypes[this->schedTypeNum];
     198          532 :         if (schedType->isReal) {
     199          505 :             return false;
     200              :         }
     201              :         // Make sure each is integer
     202         3195 :         for (int i = 0; i < Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour; ++i) {
     203         3168 :             if (this->tsVals[i] != int(this->tsVals[i])) {
     204            0 :                 return true;
     205              :             }
     206              :         }
     207           27 :         return false;
     208              :     } // ScheduleDay::checkValsForBadIntegers()
     209              : 
     210        79758 :     void DaySchedule::populateFromMinuteVals(EnergyPlusData &state, std::array<Real64, Constant::iMinutesInDay> const &minuteVals)
     211              :     {
     212        79758 :         auto &s_glob = state.dataGlobal;
     213        79758 :         if (this->interpolation == Interpolation::Average) {
     214         6200 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
     215         5952 :                 int begMin = 0;
     216         5952 :                 int endMin = s_glob->MinutesInTimeStep - 1;
     217        37200 :                 for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
     218        31248 :                     Real64 accum = 0.0;
     219       388368 :                     for (int iMin = begMin; iMin <= endMin; ++iMin) {
     220       357120 :                         accum += minuteVals[hr * Constant::iMinutesInHour + iMin];
     221              :                     }
     222        31248 :                     this->tsVals[hr * s_glob->TimeStepsInHour + ts] = accum / double(s_glob->MinutesInTimeStep);
     223        31248 :                     this->sumTsVals += this->tsVals[hr * s_glob->TimeStepsInHour + ts];
     224        31248 :                     begMin = endMin + 1;
     225        31248 :                     endMin += s_glob->MinutesInTimeStep;
     226              :                 }
     227              :             }
     228              :         } else {
     229      1987750 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
     230      1908240 :                 int endMinute = s_glob->MinutesInTimeStep - 1;
     231     11274816 :                 for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
     232      9366576 :                     this->tsVals[hr * s_glob->TimeStepsInHour + ts] = minuteVals[hr * Constant::iMinutesInHour + endMinute];
     233      9366576 :                     this->sumTsVals += this->tsVals[hr * s_glob->TimeStepsInHour + ts];
     234      9366576 :                     endMinute += s_glob->MinutesInTimeStep;
     235              :                 }
     236              :             }
     237              :         }
     238        79758 :     } // ScheduleDay::populateFromHrMinVals()
     239              : 
     240         1871 :     ScheduleConstant *AddScheduleConstant(EnergyPlusData &state, std::string const &name, Real64 value)
     241              :     {
     242         1871 :         auto const &s_sched = state.dataSched;
     243         1871 :         auto const &s_glob = state.dataGlobal;
     244              : 
     245         1871 :         auto *sched = new ScheduleConstant;
     246         1871 :         sched->Name = name;
     247         1871 :         sched->type = SchedType::Constant;
     248         1871 :         sched->Num = (int)s_sched->schedules.size();
     249         1871 :         sched->currentVal = value;
     250              :         // When InitConstantScheduleData is called, TimeStepsInHour is 0, so we ensure 24
     251         1871 :         sched->tsVals.assign(Constant::iHoursInDay * max(1, s_glob->TimeStepsInHour), value);
     252              : 
     253         1871 :         s_sched->schedules.push_back(sched);
     254         1871 :         s_sched->scheduleMap.insert_or_assign(std::move(Util::makeUPPER(sched->Name)), sched->Num);
     255              : 
     256         1871 :         return sched;
     257              :     } // AddScheduleConstant()
     258              : 
     259        17025 :     ScheduleDetailed *AddScheduleDetailed(EnergyPlusData &state, std::string const &name)
     260              :     {
     261        17025 :         auto const &s_sched = state.dataSched;
     262              : 
     263        17025 :         auto *sched = new ScheduleDetailed;
     264        17025 :         sched->Name = name;
     265              : 
     266        17025 :         sched->Num = (int)s_sched->schedules.size();
     267        17025 :         s_sched->schedules.push_back(sched);
     268        17025 :         s_sched->scheduleMap.insert_or_assign(std::move(Util::makeUPPER(sched->Name)), sched->Num);
     269              : 
     270        17025 :         sched->type = SchedType::Year;
     271        17025 :         return sched;
     272              :     } // AddScheduleDetailed()
     273              : 
     274       125193 :     DaySchedule *AddDaySchedule(EnergyPlusData &state, std::string const &name)
     275              :     {
     276       125193 :         auto &s_glob = state.dataGlobal;
     277       125193 :         auto &s_sched = state.dataSched;
     278              : 
     279       125193 :         auto *daySched = new DaySchedule;
     280       125193 :         daySched->Name = name;
     281              : 
     282       125193 :         daySched->Num = (int)s_sched->daySchedules.size();
     283       125193 :         s_sched->daySchedules.push_back(daySched);
     284       125193 :         s_sched->dayScheduleMap.insert_or_assign(std::move(Util::makeUPPER(daySched->Name)), daySched->Num);
     285              : 
     286       125193 :         daySched->tsVals.resize(Constant::iHoursInDay * s_glob->TimeStepsInHour);
     287              : 
     288       125193 :         return daySched;
     289              :     } // AddDaySchedule()
     290              : 
     291       113346 :     WeekSchedule *AddWeekSchedule(EnergyPlusData &state, std::string const &name)
     292              :     {
     293       113346 :         auto const &s_sched = state.dataSched;
     294              : 
     295       113346 :         auto *weekSched = new WeekSchedule;
     296       113346 :         weekSched->Name = name;
     297              : 
     298       113346 :         weekSched->Num = (int)s_sched->weekSchedules.size();
     299       113346 :         s_sched->weekSchedules.push_back(weekSched);
     300       113346 :         s_sched->weekScheduleMap.insert_or_assign(std::move(Util::makeUPPER(weekSched->Name)), weekSched->Num);
     301              : 
     302       113346 :         return weekSched;
     303              :     } // AddWeekSchedule()
     304              : 
     305          803 :     void InitConstantScheduleData(EnergyPlusData &state)
     306              :     {
     307              :         // Create ScheduleAlwaysOn and ScheduleAlwaysOff
     308              :         // Create constant schedules
     309          803 :         auto *schedOff = AddScheduleConstant(state, "Constant-0.0", 0.0);
     310          803 :         assert(schedOff->Num == SchedNum_AlwaysOff);
     311          803 :         schedOff->isUsed = true; // Suppress unused warnings
     312              : 
     313          803 :         auto *schedOn = AddScheduleConstant(state, "Constant-1.0", 1.0);
     314          803 :         assert(schedOn->Num == SchedNum_AlwaysOn);
     315          803 :         schedOn->isUsed = true; // Suppress unused warnings
     316          803 :     }
     317              : 
     318          803 :     void ProcessScheduleInput(EnergyPlusData &state)
     319              :     {
     320              :         // SUBROUTINE INFORMATION:
     321              :         //       AUTHOR         Linda K. Lawrie
     322              :         //       DATE WRITTEN   September 1997
     323              :         //       MODIFIED       Rui Zhang February 2010
     324              : 
     325              :         // PURPOSE OF THIS SUBROUTINE:
     326              :         // This subroutine processes the schedules input for EnergyPlus.
     327              : 
     328              :         // METHODOLOGY EMPLOYED:
     329              :         // Uses the standard get routines in the InputProcessor.
     330              : 
     331              :         // Using/Aliasing
     332              :         using DataStringGlobals::CharComma;
     333              :         using DataStringGlobals::CharSemicolon;
     334              :         using DataStringGlobals::CharSpace;
     335              :         using DataStringGlobals::CharTab;
     336              :         using DataSystemVariables::CheckForActualFilePath;
     337              :         using General::ProcessDateString;
     338              : 
     339              :         // Locals
     340              :         // SUBROUTINE PARAMETER DEFINITIONS:
     341          803 :         constexpr std::string_view routineName = "ProcessScheduleInput";
     342              : 
     343              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     344              : 
     345          803 :         Array1D_string Alphas;
     346          803 :         Array1D_string cAlphaFields;
     347          803 :         Array1D_string cNumericFields;
     348          803 :         Array1D<Real64> Numbers;
     349          803 :         Array1D_bool lAlphaBlanks;
     350          803 :         Array1D_bool lNumericBlanks;
     351              :         int NumAlphas;
     352              :         int NumNumbers;
     353              :         int Status;
     354              : 
     355              :         int EndMonth;
     356              :         int EndDay;
     357              :         int StartPointer;
     358              :         int EndPointer;
     359              :         int NumPointer;
     360          803 :         bool ErrorsFound(false);
     361              :         bool NumErrorFlag;
     362              : 
     363          803 :         std::string CFld; // Character field for error message
     364              :         //  CHARACTER(len=20) CFld1        ! Character field for error message
     365              : 
     366              :         std::array<Real64, Constant::iMinutesInDay> minuteVals;
     367              :         std::array<bool, Constant::iMinutesInDay> setMinuteVals;
     368              : 
     369              :         int NumFields;
     370              :         //  LOGICAL RptSchedule
     371              : 
     372              :         int MinutesPerItem;
     373              :         int NumExpectedItems;
     374              :         std::array<bool, (int)DayType::Num> allDays;
     375              :         std::array<bool, (int)DayType::Num> theseDays;
     376              :         bool ErrorHere;
     377              :         int SchNum;
     378              :         int WkCount;
     379              :         int DyCount;
     380              :         int NumField;
     381              :         int Count;
     382              :         Weather::DateType PDateType;
     383              :         int PWeekDay;
     384              :         int ThruField;
     385              :         int UntilFld;
     386              :         int xxcount;
     387              :         //  REAL(r64) tempval
     388          803 :         std::string CurrentThrough;
     389          803 :         std::string LastFor;
     390          803 :         std::string errmsg;
     391              :         // for SCHEDULE:FILE
     392              :         int rowCnt;
     393              : 
     394          803 :         std::string subString;
     395              :         int MaxNums1;
     396              :         char ColumnSep;
     397              :         bool FileIntervalInterpolated;
     398              :         int rowLimitCount;
     399              :         int skiprowCount;
     400              :         int curcolCount;
     401          803 :         int numerrors = 0;
     402              : 
     403          803 :         auto const &s_glob = state.dataGlobal;
     404          803 :         auto const &s_ip = state.dataInputProcessing->inputProcessor;
     405          803 :         auto const &s_sched = state.dataSched;
     406              : 
     407          803 :         if (s_sched->ScheduleInputProcessed) {
     408            0 :             return;
     409              :         }
     410              : 
     411          803 :         s_sched->ScheduleInputProcessed = true;
     412              : 
     413          803 :         int MaxNums = 1; // Need at least 1 number because it's used as a local variable in the Schedule Types loop
     414          803 :         int MaxAlps = 0;
     415              : 
     416          803 :         std::string CurrentModuleObject = "ScheduleTypeLimits";
     417          803 :         int NumScheduleTypes = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     418          803 :         if (NumScheduleTypes > 0) {
     419          801 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     420          801 :             MaxNums = max(MaxNums, NumNumbers);
     421          801 :             MaxAlps = max(MaxAlps, NumAlphas);
     422              :         }
     423          803 :         CurrentModuleObject = "Schedule:Day:Hourly";
     424          803 :         int NumHrDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     425          803 :         if (NumHrDaySchedules > 0) {
     426           17 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     427           17 :             MaxNums = max(MaxNums, NumNumbers);
     428           17 :             MaxAlps = max(MaxAlps, NumAlphas);
     429              :         }
     430          803 :         CurrentModuleObject = "Schedule:Day:Interval";
     431          803 :         int NumIntDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     432          803 :         if (NumIntDaySchedules > 0) {
     433            9 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     434            9 :             MaxNums = max(MaxNums, NumNumbers);
     435            9 :             MaxAlps = max(MaxAlps, NumAlphas);
     436              :         }
     437          803 :         CurrentModuleObject = "Schedule:Day:List";
     438          803 :         int NumLstDaySchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     439          803 :         if (NumLstDaySchedules > 0) {
     440            1 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     441            1 :             MaxNums = max(MaxNums, NumNumbers);
     442            1 :             MaxAlps = max(MaxAlps, NumAlphas);
     443              :         }
     444          803 :         CurrentModuleObject = "Schedule:Week:Daily";
     445          803 :         int NumRegWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     446          803 :         if (NumRegWeekSchedules > 0) {
     447           19 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     448           19 :             MaxNums = max(MaxNums, NumNumbers);
     449           19 :             MaxAlps = max(MaxAlps, NumAlphas);
     450              :         }
     451          803 :         CurrentModuleObject = "Schedule:Week:Compact";
     452          803 :         int NumCptWeekSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     453          803 :         if (NumCptWeekSchedules > 0) {
     454            4 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     455            4 :             MaxNums = max(MaxNums, NumNumbers);
     456            4 :             MaxAlps = max(MaxAlps, NumAlphas);
     457              :         }
     458          803 :         CurrentModuleObject = "Schedule:Year";
     459          803 :         int NumRegSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     460          803 :         if (NumRegSchedules > 0) {
     461           23 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     462           23 :             MaxNums = max(MaxNums, NumNumbers);
     463           23 :             MaxAlps = max(MaxAlps, NumAlphas);
     464              :         }
     465          803 :         CurrentModuleObject = "Schedule:Compact";
     466          803 :         int NumCptSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     467          803 :         if (NumCptSchedules > 0) {
     468          773 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     469          773 :             MaxNums = max(MaxNums, NumNumbers);
     470          773 :             MaxAlps = max(MaxAlps, NumAlphas + 1);
     471              :         }
     472          803 :         CurrentModuleObject = "Schedule:File";
     473          803 :         int NumCommaFileSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     474          803 :         if (NumCommaFileSchedules > 0) {
     475            8 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     476            8 :             MaxNums = max(MaxNums, NumNumbers);
     477            8 :             MaxAlps = max(MaxAlps, NumAlphas);
     478              :         }
     479              : 
     480          803 :         CurrentModuleObject = "Schedule:Constant";
     481          803 :         int NumConstantSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     482          803 :         if (NumConstantSchedules > 0) {
     483           95 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     484           95 :             MaxNums = max(MaxNums, NumNumbers);
     485           95 :             MaxAlps = max(MaxAlps, NumAlphas);
     486              :         }
     487          803 :         CurrentModuleObject = "ExternalInterface:Schedule";
     488          803 :         int NumExternalInterfaceSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     489              :         // added for FMI
     490          803 :         if (NumExternalInterfaceSchedules > 0) {
     491            0 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     492            0 :             MaxNums = max(MaxNums, NumNumbers);
     493            0 :             MaxAlps = max(MaxAlps, NumAlphas + 1);
     494              :         }
     495              :         // added for FMU Import
     496          803 :         CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
     497          803 :         int NumExternalInterfaceFunctionalMockupUnitImportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     498          803 :         if (NumExternalInterfaceFunctionalMockupUnitImportSchedules > 0) {
     499            1 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     500            1 :             MaxNums = max(MaxNums, NumNumbers);
     501            1 :             MaxAlps = max(MaxAlps, NumAlphas + 1);
     502              :         }
     503              :         // added for FMU Export
     504          803 :         CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule";
     505          803 :         int NumExternalInterfaceFunctionalMockupUnitExportSchedules = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     506          803 :         if (NumExternalInterfaceFunctionalMockupUnitExportSchedules > 0) {
     507            0 :             s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     508            0 :             MaxNums = max(MaxNums, NumNumbers);
     509            0 :             MaxAlps = max(MaxAlps, NumAlphas + 1);
     510              :         }
     511          803 :         CurrentModuleObject = "Output:Schedules";
     512          803 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, Count, NumAlphas, NumNumbers);
     513          803 :         MaxNums = max(MaxNums, NumNumbers);
     514          803 :         MaxAlps = max(MaxAlps, NumAlphas);
     515              : 
     516          803 :         Alphas.allocate(MaxAlps); // Maximum Alphas possible
     517          803 :         cAlphaFields.allocate(MaxAlps);
     518          803 :         cNumericFields.allocate(MaxNums);
     519          803 :         Numbers.dimension(MaxNums, 0.0); // Maximum Numbers possible
     520          803 :         lAlphaBlanks.dimension(MaxAlps, true);
     521          803 :         lNumericBlanks.dimension(MaxNums, true);
     522              : 
     523              :         // Prescan to determine extra day and week schedules due to compact schedule input
     524          803 :         CurrentModuleObject = "Schedule:Compact";
     525          803 :         MaxNums1 = 0;
     526              : 
     527        17403 :         for (int LoopIndex = 1; LoopIndex <= NumCptSchedules; ++LoopIndex) {
     528        16600 :             s_ip->getObjectItem(state, CurrentModuleObject, LoopIndex, Alphas, NumAlphas, Numbers, NumNumbers, Status);
     529              :             // # 'THROUGH" => Number of additional week schedules
     530              :             // # 'FOR' => Number of additional day schedules
     531       235266 :             for (Count = 3; Count <= NumAlphas; ++Count) {
     532       218666 :                 if (has_prefix(Alphas(Count), "UNTIL")) {
     533        80156 :                     ++MaxNums1;
     534              :                 }
     535              :             }
     536              :         }
     537          803 :         if (MaxNums1 > MaxNums) {
     538          752 :             MaxNums = MaxNums1;
     539          752 :             cNumericFields.deallocate();
     540          752 :             Numbers.deallocate();
     541          752 :             lNumericBlanks.deallocate();
     542          752 :             cNumericFields.allocate(MaxNums);
     543          752 :             Numbers.dimension(MaxNums, 0.0); // Maximum Numbers possible
     544          752 :             lNumericBlanks.dimension(MaxNums, true);
     545              :         }
     546              : 
     547              :         // add week and day schedules for each FILE:COMMA schedule
     548              : 
     549          803 :         CurrentModuleObject = "Schedule:File:Shading";
     550          803 :         int NumCommaFileShading = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     551          803 :         NumAlphas = 0;
     552          803 :         NumNumbers = 0;
     553          803 :         if (NumCommaFileShading > 1) {
     554            0 :             ShowWarningError(state, format("{}: More than 1 occurrence of this object found, only first will be used.", CurrentModuleObject));
     555              :         }
     556              : 
     557          803 :         std::map<fs::path, nlohmann::json>::iterator schedule_file_shading_result;
     558          803 :         if (NumCommaFileShading != 0) {
     559            1 :             s_ip->getObjectItem(state,
     560              :                                 CurrentModuleObject,
     561              :                                 1,
     562              :                                 Alphas,
     563              :                                 NumAlphas,
     564              :                                 Numbers,
     565              :                                 NumNumbers,
     566              :                                 Status,
     567              :                                 lNumericBlanks,
     568              :                                 lAlphaBlanks,
     569              :                                 cAlphaFields,
     570              :                                 cNumericFields);
     571            1 :             std::string ShadingSunlitFracFileName = Alphas(1);
     572              : 
     573            1 :             std::string contextString = CurrentModuleObject + ", " + cAlphaFields(1) + ": ";
     574            1 :             state.files.TempFullFilePath.filePath = CheckForActualFilePath(state, ShadingSunlitFracFileName, contextString);
     575              : 
     576            1 :             if (state.files.TempFullFilePath.filePath.empty()) {
     577            0 :                 ShowFatalError(state, "Program terminates due to previous condition.");
     578              :             }
     579              : 
     580            1 :             if (state.dataEnvrn->CurrentYearIsLeapYear) {
     581            0 :                 rowLimitCount = 366 * Constant::iHoursInDay * s_glob->TimeStepsInHour;
     582              :             } else {
     583            1 :                 rowLimitCount = 365 * Constant::iHoursInDay * s_glob->TimeStepsInHour;
     584              :             }
     585            1 :             ColumnSep = CharComma;
     586              : 
     587            1 :             schedule_file_shading_result = s_sched->UniqueProcessedExternalFiles.find(state.files.TempFullFilePath.filePath);
     588            1 :             if (schedule_file_shading_result == s_sched->UniqueProcessedExternalFiles.end()) {
     589              : 
     590            1 :                 FileSystem::FileTypes const ext = FileSystem::getFileType(state.files.TempFullFilePath.filePath);
     591            1 :                 if (FileSystem::is_flat_file_type(ext)) {
     592            1 :                     auto const schedule_data = FileSystem::readFile(state.files.TempFullFilePath.filePath);
     593            1 :                     CsvParser csvParser;
     594            1 :                     skiprowCount = 1; // make sure to parse header row only for Schedule:File:Shading
     595            1 :                     auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
     596            1 :                                                                             csvParser.decode(schedule_data, ColumnSep, skiprowCount));
     597            1 :                     if (csvParser.hasErrors()) {
     598            0 :                         for (const auto &[error, isContinued] : csvParser.errors()) {
     599            0 :                             if (isContinued) {
     600            0 :                                 ShowContinueError(state, error);
     601              :                             } else {
     602            0 :                                 ShowSevereError(state, error);
     603              :                             }
     604            0 :                         }
     605            0 :                         ShowContinueError(state, fmt::format("Error Occurred in {}", state.files.TempFullFilePath.filePath));
     606            0 :                         ShowFatalError(state, "Program terminates due to previous condition.");
     607              :                     }
     608            1 :                     schedule_file_shading_result = it.first;
     609            1 :                 } else if (FileSystem::is_all_json_type(ext)) {
     610            0 :                     auto schedule_data = FileSystem::readJSON(state.files.TempFullFilePath.filePath);
     611              :                     auto it = // (AUTO_OK_ITER)
     612            0 :                         s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath, std::move(schedule_data));
     613            0 :                     schedule_file_shading_result = it.first;
     614            0 :                 } else {
     615            0 :                     ShowSevereError(state,
     616            0 :                                     fmt::format(R"({}: {}="{}", {}="{}" has an unknown file extension and cannot be read by this program.)",
     617              :                                                 routineName,
     618              :                                                 CurrentModuleObject,
     619              :                                                 Alphas(1),
     620              :                                                 cAlphaFields(3),
     621              :                                                 Alphas(3)));
     622            0 :                     ShowFatalError(state, "Program terminates due to previous condition.");
     623              :                 }
     624              :             }
     625              : 
     626            1 :             auto const &column_json = schedule_file_shading_result->second["values"].at(0); // assume there is at least 1 column
     627            1 :             rowCnt = column_json.size();
     628              :             int NumCSVAllColumnsSchedules =
     629            1 :                 schedule_file_shading_result->second["header"].get<std::set<std::string>>().size() - 1; // -1 to account for timestamp column
     630              : 
     631            1 :             if (schedule_file_shading_result->second["header"].back().get<std::string>() == "()") {
     632            0 :                 ShowWarningError(state,
     633            0 :                                  format("{}: {}=\"{}\" Removing last column of the CSV since it has '()' for the surface name.",
     634              :                                         routineName,
     635              :                                         CurrentModuleObject,
     636              :                                         Alphas(1)));
     637            0 :                 ShowContinueError(state, "This was a problem in E+ 22.2.0 and below, consider removing it from the file to suppress this warning.");
     638            0 :                 schedule_file_shading_result->second["header"].erase(NumCSVAllColumnsSchedules);
     639            0 :                 assert(schedule_file_shading_result->second["header"].size() == schedule_file_shading_result->second["values"].size());
     640            0 :                 --NumCSVAllColumnsSchedules;
     641              :             }
     642              : 
     643            1 :             if (rowCnt != rowLimitCount) {
     644            0 :                 if (rowCnt < rowLimitCount) {
     645            0 :                     ShowSevereError(state, format("{}: {}=\"{}\" {} data values read.", routineName, CurrentModuleObject, Alphas(1), rowCnt));
     646            0 :                 } else if (rowCnt > rowLimitCount) {
     647            0 :                     ShowSevereError(state, format("{}: {}=\"{}\" too many data values read.", routineName, CurrentModuleObject, Alphas(1)));
     648              :                 }
     649            0 :                 ShowContinueError(
     650              :                     state,
     651            0 :                     format("Number of rows in the shading file must be a full year multiplied by the simulation TimeStep: {}.", rowLimitCount));
     652            0 :                 ShowFatalError(state, "Program terminates due to previous condition.");
     653              :             }
     654              : 
     655              :             // schedule values have been filled into the CSVAllColumnNameAndValues map.
     656            1 :             s_sched->ScheduleFileShadingProcessed = true;
     657              : 
     658            1 :             if (numerrors > 0) {
     659            0 :                 ShowWarningError(
     660              :                     state,
     661            0 :                     format(
     662              :                         "{}:{}=\"{}\" {} records had errors - these values are set to 0.", routineName, CurrentModuleObject, Alphas(1), numerrors));
     663              :             }
     664            1 :         }
     665              : 
     666              :         //!  Most initializations in the schedule data structures are taken care of in
     667              :         //!  the definitions (see above)
     668              : 
     669         1606 :         print(state.files.audit.ensure_open(state, "ProcessScheduleInput", state.files.outputControl.audit),
     670              :               "{}\n",
     671              :               "  Processing Schedule Input -- Start");
     672              : 
     673              :         //!! Get Schedule Types
     674              : 
     675          803 :         CurrentModuleObject = "ScheduleTypeLimits";
     676         5092 :         for (int Loop = 1; Loop <= NumScheduleTypes; ++Loop) {
     677         4289 :             s_ip->getObjectItem(state,
     678              :                                 CurrentModuleObject,
     679              :                                 Loop,
     680              :                                 Alphas,
     681              :                                 NumAlphas,
     682              :                                 Numbers,
     683              :                                 NumNumbers,
     684              :                                 Status,
     685              :                                 lNumericBlanks,
     686              :                                 lAlphaBlanks,
     687              :                                 cAlphaFields,
     688              :                                 cNumericFields);
     689              : 
     690         4289 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     691              : 
     692         4289 :             if (s_sched->scheduleTypeMap.find(Alphas(1)) != s_sched->scheduleTypeMap.end()) {
     693            0 :                 ShowSevereDuplicateName(state, eoh);
     694            0 :                 ErrorsFound = true;
     695            0 :                 continue;
     696              :             }
     697              : 
     698         4289 :             auto *schedType = new ScheduleType;
     699         4289 :             schedType->Name = Alphas(1);
     700              : 
     701         4289 :             schedType->Num = (int)s_sched->scheduleTypes.size();
     702         4289 :             s_sched->scheduleTypes.push_back(schedType);
     703         4289 :             s_sched->scheduleTypeMap.insert_or_assign(schedType->Name, schedType->Num);
     704              : 
     705         4289 :             schedType->isLimited = !lNumericBlanks(1) && !lNumericBlanks(2);
     706              : 
     707         4289 :             if (!lNumericBlanks(1)) {
     708         3301 :                 schedType->minVal = Numbers(1);
     709              :             }
     710         4289 :             if (!lNumericBlanks(2)) {
     711         3292 :                 schedType->maxVal = Numbers(2);
     712              :             }
     713              : 
     714         4289 :             if (schedType->isLimited) {
     715         3292 :                 if (Alphas(2) == "DISCRETE" || Alphas(2) == "INTEGER") {
     716         1440 :                     schedType->isReal = false;
     717         1852 :                 } else if (Alphas(2) == "CONTINUOUS" || Alphas(2) == "REAL") {
     718         1852 :                     schedType->isReal = true;
     719              :                 } else {
     720            0 :                     ShowSevereInvalidKey(state, eoh, cAlphaFields(2), Alphas(2));
     721            0 :                     ErrorsFound = true;
     722              :                 }
     723              :             }
     724              : 
     725         4289 :             if (NumAlphas >= 3 && !lAlphaBlanks(3)) {
     726          593 :                 schedType->limitUnits = static_cast<LimitUnits>(getEnumValue(limitUnitNamesUC, Alphas(3)));
     727          593 :                 if (schedType->limitUnits == LimitUnits::Invalid) {
     728            0 :                     ShowSevereInvalidKey(state, eoh, cAlphaFields(3), Alphas(3));
     729            0 :                     ErrorsFound = true;
     730              :                 }
     731              :             }
     732              : 
     733         4289 :             if (schedType->isLimited && schedType->minVal > schedType->maxVal) {
     734            0 :                 if (schedType->isReal) {
     735            0 :                     ShowSevereCustom(
     736            0 :                         state, eoh, format("{} [{:.2R}] > {} [{:.2R}].", cNumericFields(1), schedType->minVal, cNumericFields(2), schedType->maxVal));
     737              :                 } else {
     738            0 :                     ShowSevereCustom(
     739            0 :                         state, eoh, format("{} [{:.0R}] > {} [{:.0R}].", cNumericFields(1), schedType->minVal, cNumericFields(2), schedType->maxVal));
     740              :                 }
     741            0 :                 ShowContinueError(state, "  Other warning/severes about schedule values may appear.");
     742              :             }
     743              :         } // for (Loop)
     744              : 
     745              :         //!! Get Day Schedules (all types)
     746              : 
     747              :         //!!=> Get "DAYSCHEDULE" (Hourly)
     748              : 
     749          803 :         Count = 0;
     750          803 :         CurrentModuleObject = "Schedule:Day:Hourly";
     751          976 :         for (int Loop = 1; Loop <= NumHrDaySchedules; ++Loop) {
     752          173 :             s_ip->getObjectItem(state,
     753              :                                 CurrentModuleObject,
     754              :                                 Loop,
     755              :                                 Alphas,
     756              :                                 NumAlphas,
     757              :                                 Numbers,
     758              :                                 NumNumbers,
     759              :                                 Status,
     760              :                                 lNumericBlanks,
     761              :                                 lAlphaBlanks,
     762              :                                 cAlphaFields,
     763              :                                 cNumericFields);
     764              : 
     765          173 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     766              : 
     767          173 :             if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
     768            0 :                 ShowSevereDuplicateName(state, eoh);
     769            0 :                 ErrorsFound = true;
     770            0 :                 continue;
     771              :             }
     772              : 
     773          173 :             auto *daySched = AddDaySchedule(state, Alphas(1));
     774              : 
     775              :             // Validate ScheduleType
     776          173 :             if (lAlphaBlanks(2)) {
     777            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
     778            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     779          173 :             } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
     780            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     781            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     782              :             }
     783              : 
     784          173 :             daySched->interpolation = Interpolation::No;
     785              : 
     786         4325 :             for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
     787        28104 :                 for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
     788        23952 :                     daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = Numbers(hr + 1);
     789        23952 :                     daySched->sumTsVals += daySched->tsVals[hr * s_glob->TimeStepsInHour + ts];
     790              :                 }
     791              :             }
     792              : 
     793          173 :             if (daySched->checkValsForLimitViolations(state)) {
     794            0 :                 ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
     795              :             }
     796              : 
     797          173 :             if (daySched->checkValsForBadIntegers(state)) {
     798            0 :                 ShowWarningCustom(state, eoh, format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2)));
     799              :             }
     800              : 
     801              :         } // for (Loop)
     802              : 
     803              :         //!! Get "DaySchedule:Interval"
     804              : 
     805          803 :         CurrentModuleObject = "Schedule:Day:Interval";
     806         1156 :         for (int Loop = 1; Loop <= NumIntDaySchedules; ++Loop) {
     807          353 :             s_ip->getObjectItem(state,
     808              :                                 CurrentModuleObject,
     809              :                                 Loop,
     810              :                                 Alphas,
     811              :                                 NumAlphas,
     812              :                                 Numbers,
     813              :                                 NumNumbers,
     814              :                                 Status,
     815              :                                 lNumericBlanks,
     816              :                                 lAlphaBlanks,
     817              :                                 cAlphaFields,
     818              :                                 cNumericFields);
     819              : 
     820          353 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     821              : 
     822          353 :             if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
     823            0 :                 ShowSevereDuplicateName(state, eoh);
     824            0 :                 ErrorsFound = true;
     825            0 :                 continue;
     826              :             }
     827              : 
     828          353 :             auto *daySched = AddDaySchedule(state, Alphas(1));
     829              : 
     830              :             // Validate ScheduleType
     831          353 :             if (lAlphaBlanks(2)) {
     832            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
     833            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     834          353 :             } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
     835            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     836            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     837              :             }
     838              : 
     839          353 :             NumFields = NumAlphas - 3;
     840              :             // check to see if numfield=0
     841          353 :             if (NumFields == 0) {
     842            0 :                 ShowSevereCustom(state,
     843              :                                  eoh,
     844            0 :                                  format("Insufficient data entered for a full schedule day."
     845              :                                         "Number of interval fields == [{}].",
     846              :                                         NumFields));
     847            0 :                 ErrorsFound = true;
     848              :             }
     849              : 
     850              :             // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
     851          353 :             daySched->interpolation = static_cast<Interpolation>(getEnumValue(interpolationNamesUC, Alphas(3)));
     852          353 :             if (daySched->interpolation == Interpolation::Invalid) {
     853            0 :                 ShowSevereInvalidKey(state, eoh, cAlphaFields(3), Alphas(3));
     854            0 :                 ErrorsFound = true;
     855              :             }
     856              : 
     857          353 :             ProcessIntervalFields(state,
     858         1412 :                                   Alphas({4, _}),
     859              :                                   Numbers,
     860              :                                   NumFields,
     861              :                                   NumNumbers,
     862              :                                   minuteVals,
     863              :                                   setMinuteVals,
     864              :                                   ErrorsFound,
     865          353 :                                   Alphas(1),
     866              :                                   CurrentModuleObject,
     867              :                                   daySched->interpolation);
     868              : 
     869              :             // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule()
     870          353 :             daySched->populateFromMinuteVals(state, minuteVals);
     871              : 
     872          353 :             if (daySched->checkValsForLimitViolations(state)) {
     873            0 :                 ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
     874              :             }
     875              : 
     876          353 :             if (daySched->checkValsForBadIntegers(state)) {
     877            0 :                 ShowWarningCustom(state, eoh, format("One or more values are not integer in {}={}", cAlphaFields(2), Alphas(2)));
     878              :             }
     879              :         }
     880              : 
     881              :         //!! Get "DaySchedule:List"
     882              : 
     883          803 :         CurrentModuleObject = "Schedule:Day:List";
     884          809 :         for (int Loop = 1; Loop <= NumLstDaySchedules; ++Loop) {
     885            6 :             s_ip->getObjectItem(state,
     886              :                                 CurrentModuleObject,
     887              :                                 Loop,
     888              :                                 Alphas,
     889              :                                 NumAlphas,
     890              :                                 Numbers,
     891              :                                 NumNumbers,
     892              :                                 Status,
     893              :                                 lNumericBlanks,
     894              :                                 lAlphaBlanks,
     895              :                                 cAlphaFields,
     896              :                                 cNumericFields);
     897              : 
     898            6 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     899              : 
     900            6 :             if (s_sched->dayScheduleMap.find(Alphas(1)) != s_sched->dayScheduleMap.end()) {
     901            0 :                 ShowSevereDuplicateName(state, eoh);
     902            0 :                 ErrorsFound = true;
     903            0 :                 continue;
     904              :             }
     905              : 
     906            6 :             auto *daySched = AddDaySchedule(state, Alphas(1));
     907              : 
     908              :             // Validate ScheduleType
     909            6 :             if (lAlphaBlanks(2)) {
     910            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
     911            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     912            6 :             } else if ((daySched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
     913            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     914            0 :                 ShowContinueError(state, "Schedule will not be validated.");
     915              :             }
     916              : 
     917              :             // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
     918            6 :             daySched->interpolation = static_cast<Interpolation>(getEnumValue(interpolationNamesUC, Alphas(3)));
     919              : 
     920              :             // check to see if there are any fields
     921            6 :             if (Numbers(1) <= 0.0) {
     922            0 :                 ShowSevereCustom(state,
     923              :                                  eoh,
     924            0 :                                  format("Insufficient data entered for a full schedule day."
     925              :                                         "...Minutes per Item field = [{}].",
     926              :                                         Numbers(1)));
     927            0 :                 ErrorsFound = true;
     928            0 :                 continue;
     929              :             }
     930            6 :             if (NumNumbers < 25) {
     931            0 :                 ShowSevereCustom(state,
     932              :                                  eoh,
     933            0 :                                  format("Insufficient data entered for a full schedule day."
     934              :                                         "...Minutes per Item field = [{}] and only [{}] to apply to list fields.",
     935              :                                         Numbers(1),
     936            0 :                                         NumNumbers - 1));
     937            0 :                 ErrorsFound = true;
     938            0 :                 continue;
     939              :             }
     940              : 
     941            6 :             MinutesPerItem = int(Numbers(1));
     942            6 :             NumExpectedItems = 1440 / MinutesPerItem;
     943            6 :             if ((NumNumbers - 1) != NumExpectedItems) {
     944            0 :                 ShowSevereCustom(state,
     945              :                                  eoh,
     946            0 :                                  format("Number of Entered Items={} not equal number of expected items={}"
     947              :                                         "based on {}={}",
     948            0 :                                         NumNumbers - 1,
     949              :                                         NumExpectedItems,
     950              :                                         cNumericFields(1),
     951              :                                         MinutesPerItem));
     952            0 :                 ErrorsFound = true;
     953            0 :                 continue;
     954              :             }
     955              : 
     956            6 :             if (mod(Constant::iMinutesInHour, MinutesPerItem) != 0) {
     957            0 :                 ShowSevereCustom(state, eoh, format("{}={} not evenly divisible into 60", cNumericFields(1), MinutesPerItem));
     958            0 :                 ErrorsFound = true;
     959            0 :                 continue;
     960              :             }
     961              : 
     962              :             // Number of numbers in the Numbers list okay to process
     963            6 :             int hr = 0;
     964            6 :             int begMin = 0;
     965            6 :             int endMin = MinutesPerItem - 1;
     966          438 :             for (int NumFields = 2; NumFields <= NumNumbers; ++NumFields) {
     967         9072 :                 for (int iMin = begMin; iMin <= endMin; ++iMin) {
     968         8640 :                     minuteVals[hr * Constant::iMinutesInHour + iMin] = Numbers(NumFields);
     969              :                 }
     970          432 :                 begMin = endMin + 1;
     971          432 :                 endMin += MinutesPerItem;
     972          432 :                 if (endMin >= Constant::iMinutesInHour) {
     973          144 :                     endMin = MinutesPerItem - 1;
     974          144 :                     begMin = 0;
     975          144 :                     ++hr;
     976              :                 }
     977              :             }
     978              : 
     979              :             // Now parcel into TS Value.... tsVals.resize() was called in AddDaySchedule()
     980            6 :             daySched->populateFromMinuteVals(state, minuteVals);
     981              : 
     982            6 :             if (daySched->checkValsForLimitViolations(state)) {
     983            0 :                 ShowWarningCustom(state, eoh, format("Values are outside of range for {}={}", cAlphaFields(2), Alphas(2)));
     984              :             }
     985              : 
     986            6 :             if (daySched->checkValsForBadIntegers(state)) {
     987            0 :                 ShowWarningCustom(state, eoh, format("One or more values are not integer for {}={}", cAlphaFields(2), Alphas(2)));
     988              :             }
     989              :         }
     990              : 
     991              :         //!! Get Week Schedules - regular
     992              : 
     993          803 :         CurrentModuleObject = "Schedule:Week:Daily";
     994         1150 :         for (int Loop = 1; Loop <= NumRegWeekSchedules; ++Loop) {
     995          347 :             s_ip->getObjectItem(state,
     996              :                                 CurrentModuleObject,
     997              :                                 Loop,
     998              :                                 Alphas,
     999              :                                 NumAlphas,
    1000              :                                 Numbers,
    1001              :                                 NumNumbers,
    1002              :                                 Status,
    1003              :                                 lNumericBlanks,
    1004              :                                 lAlphaBlanks,
    1005              :                                 cAlphaFields,
    1006              :                                 cNumericFields);
    1007              : 
    1008          347 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1009              : 
    1010          347 :             if (s_sched->weekScheduleMap.find(Alphas(1)) != s_sched->weekScheduleMap.end()) {
    1011            0 :                 ShowSevereDuplicateName(state, eoh);
    1012            0 :                 ErrorsFound = true;
    1013            0 :                 continue;
    1014              :             }
    1015              : 
    1016          347 :             auto *weekSched = AddWeekSchedule(state, Alphas(1));
    1017              : 
    1018              :             // Rest of Alphas are processed into schedule nums
    1019         4511 :             for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    1020         4164 :                 if ((weekSched->dayScheds[iDayType] = GetDaySchedule(state, Alphas(iDayType + 1))) == nullptr) {
    1021            0 :                     ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(iDayType + 1), Alphas(iDayType + 1));
    1022            0 :                     ErrorsFound = true;
    1023              :                 }
    1024              :             } // for (iDayType)
    1025              :         }
    1026              : 
    1027              :         //!! Get Week Schedules - compact
    1028          803 :         Count = NumRegWeekSchedules;
    1029          803 :         CurrentModuleObject = "Schedule:Week:Compact";
    1030          855 :         for (int Loop = 1; Loop <= NumCptWeekSchedules; ++Loop) {
    1031           52 :             s_ip->getObjectItem(state,
    1032              :                                 CurrentModuleObject,
    1033              :                                 Loop,
    1034              :                                 Alphas,
    1035              :                                 NumAlphas,
    1036              :                                 Numbers,
    1037              :                                 NumNumbers,
    1038              :                                 Status,
    1039              :                                 lNumericBlanks,
    1040              :                                 lAlphaBlanks,
    1041              :                                 cAlphaFields,
    1042              :                                 cNumericFields);
    1043              : 
    1044           52 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1045              : 
    1046           52 :             if (s_sched->weekScheduleMap.find(Alphas(1)) != s_sched->weekScheduleMap.end()) {
    1047            0 :                 ShowSevereDuplicateName(state, eoh);
    1048            0 :                 ErrorsFound = true;
    1049            0 :                 continue;
    1050              :             }
    1051              : 
    1052           52 :             auto *weekSched = AddWeekSchedule(state, Alphas(1));
    1053              : 
    1054           52 :             std::fill(allDays.begin(), allDays.end(), false);
    1055              :             // Rest of Alphas are processed into schedule indices
    1056          140 :             for (int idx = 2; idx <= NumAlphas; idx += 2) {
    1057           88 :                 auto *daySched = GetDaySchedule(state, Alphas(idx + 1));
    1058           88 :                 if (daySched == nullptr) {
    1059            0 :                     ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(idx + 1), Alphas(idx + 1));
    1060            0 :                     ShowContinueError(state, format("ref: {} \"{}\"", cAlphaFields(idx), Alphas(idx)));
    1061            0 :                     ErrorsFound = true;
    1062              :                 } else {
    1063           88 :                     std::fill(theseDays.begin(), theseDays.end(), false);
    1064           88 :                     ErrorHere = false;
    1065           88 :                     ProcessForDayTypes(state, Alphas(idx), theseDays, allDays, ErrorHere);
    1066           88 :                     if (ErrorHere) {
    1067            0 :                         ShowContinueError(state, format("{}: {}=\"{}", routineName, CurrentModuleObject, Alphas(1)));
    1068            0 :                         ErrorsFound = true;
    1069              :                     } else {
    1070         1144 :                         for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    1071         1056 :                             if (theseDays[iDayType]) {
    1072          624 :                                 weekSched->dayScheds[iDayType] = daySched;
    1073              :                             }
    1074              :                         }
    1075              :                     }
    1076              :                 }
    1077              :             }
    1078              : 
    1079              :             //  Have processed all named days, check to make sure all given
    1080          676 :             for (int iDayType = iDayType_Sun; iDayType < (int)DayType::Num; ++iDayType) {
    1081          624 :                 if (allDays[iDayType] == true) {
    1082          624 :                     continue;
    1083              :                 }
    1084            0 :                 ShowSevereError(state, format("{}: {}=\"{}\", Missing some day assignments", routineName, CurrentModuleObject, Alphas(1)));
    1085            0 :                 ErrorsFound = true;
    1086            0 :                 break;
    1087              :             }
    1088              :         }
    1089          803 :         NumRegWeekSchedules = Count;
    1090              : 
    1091              :         //!! Get Schedules (all types)
    1092              : 
    1093              :         //!! Get Regular Schedules
    1094              : 
    1095          803 :         CurrentModuleObject = "Schedule:Year";
    1096          980 :         for (int Loop = 1; Loop <= NumRegSchedules; ++Loop) {
    1097          177 :             s_ip->getObjectItem(state,
    1098              :                                 CurrentModuleObject,
    1099              :                                 Loop,
    1100              :                                 Alphas,
    1101              :                                 NumAlphas,
    1102              :                                 Numbers,
    1103              :                                 NumNumbers,
    1104              :                                 Status,
    1105              :                                 lNumericBlanks,
    1106              :                                 lAlphaBlanks,
    1107              :                                 cAlphaFields,
    1108              :                                 cNumericFields);
    1109              : 
    1110          177 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1111              : 
    1112          177 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1113            0 :                 ShowSevereDuplicateName(state, eoh);
    1114            0 :                 ErrorsFound = true;
    1115            0 :                 continue;
    1116              :             }
    1117              : 
    1118          177 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    1119              : 
    1120              :             // Validate ScheduleType
    1121          177 :             if (lAlphaBlanks(2)) {
    1122            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1123            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1124          177 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1125            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1126            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1127              :             }
    1128              : 
    1129          177 :             int NumPointer = 0;
    1130              : 
    1131              :             std::array<int, 367> daysInYear;
    1132          177 :             std::fill(daysInYear.begin(), daysInYear.end(), 0);
    1133              : 
    1134              :             // Rest of Alphas (Weekschedules) are processed into Pointers
    1135          583 :             for (int idx = 3; idx <= NumAlphas; ++idx) {
    1136          406 :                 auto *weekSched = GetWeekSchedule(state, Alphas(idx));
    1137          406 :                 if (weekSched == nullptr) {
    1138            0 :                     ShowSevereItemNotFoundAudit(state, eoh, cAlphaFields(idx), Alphas(idx));
    1139            0 :                     ErrorsFound = true;
    1140            0 :                     continue;
    1141              :                 }
    1142              : 
    1143              :                 // Process for month, day
    1144          406 :                 int StartMonth = int(Numbers(NumPointer + 1));
    1145          406 :                 int StartDay = int(Numbers(NumPointer + 2));
    1146          406 :                 int EndMonth = int(Numbers(NumPointer + 3));
    1147          406 :                 int EndDay = int(Numbers(NumPointer + 4));
    1148          406 :                 NumPointer += 4;
    1149          406 :                 int StartPointer = General::OrdinalDay(StartMonth, StartDay, 1);
    1150          406 :                 int EndPointer = General::OrdinalDay(EndMonth, EndDay, 1);
    1151          406 :                 if (StartPointer <= EndPointer) {
    1152        65188 :                     for (int Count = StartPointer; Count <= EndPointer; ++Count) {
    1153        64782 :                         ++daysInYear[Count];
    1154        64782 :                         sched->weekScheds[Count] = weekSched;
    1155              :                     }
    1156              :                 } else {
    1157            0 :                     for (int Count = StartPointer; Count <= 366; ++Count) {
    1158            0 :                         ++daysInYear[Count];
    1159            0 :                         sched->weekScheds[Count] = weekSched;
    1160              :                     }
    1161            0 :                     for (int Count = 1; Count <= EndPointer; ++Count) {
    1162            0 :                         ++daysInYear[Count];
    1163            0 :                         sched->weekScheds[Count] = weekSched;
    1164              :                     }
    1165              :                 }
    1166              :             }
    1167              : 
    1168              :             // Perform Error checks on this item
    1169              :             // Do special test for Feb 29.  Make equal to Feb 28.
    1170          177 :             if (daysInYear[60] == 0) {
    1171            0 :                 daysInYear[60] = daysInYear[59];
    1172            0 :                 sched->weekScheds[60] = sched->weekScheds[59];
    1173              :             }
    1174              : 
    1175        64959 :             for (int iDay = 1; iDay <= 366; ++iDay) {
    1176        64782 :                 if (daysInYear[iDay] == 0) {
    1177            0 :                     ShowSevereCustomAudit(state, eoh, "has missing days in its schedule pointers");
    1178            0 :                     ErrorsFound = true;
    1179            0 :                     break;
    1180        64782 :                 } else if (daysInYear[iDay] > 1) {
    1181            0 :                     ShowSevereCustomAudit(state, eoh, "has overlapping days in its schedule pointers");
    1182            0 :                     ErrorsFound = true;
    1183            0 :                     break;
    1184              :                 }
    1185              :             }
    1186              : 
    1187              :             // What does it mean to actuate a schedule?
    1188          177 :             if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
    1189           70 :                 SetupEMSActuator(state, "Schedule:Year", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
    1190              :             }
    1191              :         }
    1192              : 
    1193              :         //!! Get Compact Schedules
    1194              :         // SCHEDULE:COMPACT,
    1195              :         //   \memo Irregular object.  Does not follow the usual definition for fields.  Fields A3... are:
    1196              :         //   \memo Through: Date
    1197              :         //   \memo For: Applicable days (ref: Weekschedule:Compact)
    1198              :         //   \memo Interpolate: Yes/No (ref: Dayschedule:interval) -- optional, if not used will be "No"
    1199              :         //   \memo Until: <Time> (ref: Dayschedule:Interval)
    1200              :         //   \memo <numeric value>
    1201              :         //   \memo words "Through","For","Interpolate","Until" must be included.
    1202              :         //  A1 , \field Name
    1203              :         //       \required-field
    1204              :         //       \type alpha
    1205              :         //       \reference ScheduleNames
    1206              :         //  A2 , \field ScheduleType
    1207              :         //       \type object-list
    1208              :         //       \object-list ScheduleTypeNames
    1209              :         //  A3 , \field Complex Field #1
    1210              :         //  A4 , \field Complex Field #2
    1211              :         //  A5 , \field Complex Field #3
    1212              : 
    1213          803 :         SchNum = NumRegSchedules;
    1214          803 :         CurrentModuleObject = "Schedule:Compact";
    1215        17403 :         for (int Loop = 1; Loop <= NumCptSchedules; ++Loop) {
    1216        16600 :             s_ip->getObjectItem(state,
    1217              :                                 CurrentModuleObject,
    1218              :                                 Loop,
    1219              :                                 Alphas,
    1220              :                                 NumAlphas,
    1221              :                                 Numbers,
    1222              :                                 NumNumbers,
    1223              :                                 Status,
    1224              :                                 lNumericBlanks,
    1225              :                                 lAlphaBlanks,
    1226              :                                 cAlphaFields,
    1227              :                                 cNumericFields);
    1228              : 
    1229        16600 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1230              : 
    1231        16600 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1232            0 :                 ShowSevereDuplicateName(state, eoh);
    1233            0 :                 ErrorsFound = true;
    1234            0 :                 continue;
    1235              :             }
    1236              : 
    1237        16600 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    1238        16600 :             sched->type = SchedType::Compact;
    1239              : 
    1240              :             // Validate ScheduleType
    1241        16600 :             if (lAlphaBlanks(2)) {
    1242            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1243            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1244        16600 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1245           10 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1246           30 :                 ShowContinueError(state, "Schedule will not be validated.");
    1247              :             }
    1248              : 
    1249        16600 :             NumPointer = 0;
    1250              : 
    1251              :             std::array<int, 367> daysInYear;
    1252        16600 :             std::fill(daysInYear.begin() + 1, daysInYear.end(), 0);
    1253              :             // Process the "complex" fields -- so named because they are not a 1:1 correspondence
    1254              :             // as other objects are
    1255        16600 :             NumField = 3;
    1256        16600 :             StartPointer = 1;
    1257        16600 :             WkCount = 0;
    1258        16600 :             DyCount = 0;
    1259        16600 :             bool FullYearSet = false;
    1260        39755 :             while (NumField < NumAlphas) {
    1261              :                 //   Process "Through"
    1262        23155 :                 if (!has_prefix(Alphas(NumField), "THROUGH:") && !has_prefix(Alphas(NumField), "THROUGH")) {
    1263            0 :                     ShowSevereCustom(state, eoh, format("Expecting \"Through:\" date, instead found entry={}", Alphas(NumField)));
    1264            0 :                     ErrorsFound = true;
    1265            0 :                     goto Through_exit;
    1266              :                 }
    1267              : 
    1268        23155 :                 int sPos = (Alphas(NumField)[7] == ':') ? 8 : 7;
    1269        23155 :                 Alphas(NumField).erase(0, sPos);
    1270        23155 :                 strip(Alphas(NumField));
    1271              : 
    1272        23155 :                 CurrentThrough = Alphas(NumField);
    1273        23155 :                 ErrorHere = false;
    1274        23155 :                 ProcessDateString(state, Alphas(NumField), EndMonth, EndDay, PWeekDay, PDateType, ErrorHere);
    1275        23155 :                 if (PDateType == Weather::DateType::NthDayInMonth || PDateType == Weather::DateType::LastDayInMonth) {
    1276            0 :                     ShowSevereCustom(state, eoh, format("Invalid \"Through:\" date, found entry={}", Alphas(NumField)));
    1277            0 :                     ErrorsFound = true;
    1278            0 :                     goto Through_exit;
    1279              :                 }
    1280              : 
    1281        23155 :                 if (ErrorHere) {
    1282            0 :                     ShowSevereCustom(state, eoh, "Invalid \"Through:\" date");
    1283            0 :                     ErrorsFound = true;
    1284            0 :                     goto Through_exit;
    1285              :                 }
    1286              : 
    1287        23155 :                 EndPointer = General::OrdinalDay(EndMonth, EndDay, 1);
    1288        23155 :                 if (EndPointer == 366) {
    1289        16600 :                     if (FullYearSet) {
    1290            0 :                         ShowSevereCustom(
    1291            0 :                             state, eoh, format("New \"Through\" entry when \"full year\" already set \"Through\" field={}", CurrentThrough));
    1292            0 :                         ErrorsFound = true;
    1293              :                     }
    1294        16600 :                     FullYearSet = true;
    1295              :                 }
    1296              : 
    1297        23155 :                 ++WkCount;
    1298              : 
    1299        23155 :                 auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", Alphas(1), WkCount));
    1300        23155 :                 weekSched->isUsed = true;
    1301              : 
    1302      6098755 :                 for (int iDay = StartPointer; iDay <= EndPointer; ++iDay) {
    1303      6075600 :                     sched->weekScheds[iDay] = weekSched;
    1304      6075600 :                     ++daysInYear[iDay];
    1305              :                 }
    1306              : 
    1307        23155 :                 StartPointer = EndPointer + 1;
    1308        23155 :                 ThruField = NumField;
    1309        23155 :                 std::fill(allDays.begin(), allDays.end(), false);
    1310        23155 :                 ++NumField;
    1311              : 
    1312        58024 :                 while (NumField < NumAlphas) { // Continues until next "Through"
    1313        41424 :                     if (has_prefix(Alphas(NumField), "THROUGH")) {
    1314         6555 :                         goto For_exit;
    1315              :                     }
    1316              :                     //   "For" must be next, adds to "# Day Schedules"
    1317        34869 :                     if (!has_prefix(Alphas(NumField), "FOR")) {
    1318            0 :                         ShowSevereCustom(state, eoh, format("Looking for \"For\" field, found={}", Alphas(NumField)));
    1319            0 :                         ErrorsFound = true;
    1320            0 :                         goto Through_exit;
    1321              :                     }
    1322              : 
    1323        34869 :                     ++DyCount;
    1324              : 
    1325        34869 :                     auto *daySched = AddDaySchedule(state, format("{}_dy_{}", Alphas(1), DyCount));
    1326              : 
    1327        34869 :                     daySched->schedTypeNum = sched->schedTypeNum;
    1328        34869 :                     daySched->isUsed = true;
    1329              : 
    1330        34869 :                     std::fill(theseDays.begin(), theseDays.end(), false);
    1331        34869 :                     ErrorHere = false;
    1332        34869 :                     LastFor = Alphas(NumField);
    1333        34869 :                     ProcessForDayTypes(state, Alphas(NumField), theseDays, allDays, ErrorHere);
    1334        34869 :                     if (ErrorHere) {
    1335            0 :                         ShowContinueError(state, format("ref {}=\"{}\"", CurrentModuleObject, Alphas(1)));
    1336            0 :                         ShowContinueError(state, format("ref Through field={}", Alphas(ThruField)));
    1337            0 :                         ErrorsFound = true;
    1338              :                     } else {
    1339       453297 :                         for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    1340       418428 :                             if (theseDays[iDayType]) {
    1341       277860 :                                 weekSched->dayScheds[iDayType] = daySched;
    1342              :                             }
    1343              :                         }
    1344              :                     }
    1345              : 
    1346              :                     // Check for "Interpolate"
    1347        34869 :                     ++NumField;
    1348        34869 :                     if (has_prefix(Alphas(NumField), "INTERPOLATE") || !has_prefix(Alphas(NumField), "UNTIL")) {
    1349          330 :                         if (has(Alphas(NumField), "NO")) {
    1350           88 :                             daySched->interpolation = Interpolation::No;
    1351          242 :                         } else if (has(Alphas(NumField), "AVERAGE")) {
    1352          242 :                             daySched->interpolation = Interpolation::Average;
    1353            0 :                         } else if (has(Alphas(NumField), "LINEAR")) {
    1354            0 :                             daySched->interpolation = Interpolation::Linear;
    1355              :                         } else {
    1356            0 :                             ShowSevereInvalidKey(state, eoh, cAlphaFields(NumField), Alphas(NumField));
    1357            0 :                             ErrorsFound = true;
    1358              :                         }
    1359          330 :                         ++NumField;
    1360              :                     }
    1361              : 
    1362        34869 :                     NumNumbers = 0;
    1363        34869 :                     xxcount = 0;
    1364        34869 :                     UntilFld = NumField;
    1365              :                     while (true) {
    1366        98425 :                         if (has_prefix(Alphas(NumField), "FOR")) {
    1367        11714 :                             break;
    1368              :                         }
    1369        86711 :                         if (has_prefix(Alphas(NumField), "THROUGH")) {
    1370         6555 :                             break;
    1371              :                         }
    1372        80156 :                         if (has_prefix(Alphas(NumField), "UNTIL")) {
    1373              :                             // Process Until/Value pairs for later processing by other routine.
    1374        80156 :                             ++NumField;
    1375        80156 :                             ++xxcount;
    1376        80156 :                             ++NumNumbers;
    1377        80156 :                             Numbers(NumNumbers) = Util::ProcessNumber(Alphas(NumField), ErrorHere);
    1378        80156 :                             if (ErrorHere) {
    1379            0 :                                 ShowSevereCustom(
    1380            0 :                                     state, eoh, format("Until field=[{}] has illegal value field=[{}].", Alphas(NumField - 1), Alphas(NumField)));
    1381            0 :                                 ErrorsFound = true;
    1382              :                             }
    1383        80156 :                             ++NumField;
    1384        80156 :                             Alphas(UntilFld + xxcount) = Alphas(NumField); // In case next is "until"
    1385              :                         } else {
    1386            0 :                             ShowSevereCustom(state, eoh, format("Looking for \"Until\" field, found={}", Alphas(NumField)));
    1387            0 :                             ErrorsFound = true;
    1388            0 :                             goto Through_exit;
    1389              :                         }
    1390        80156 :                         if (Alphas(NumField).empty()) {
    1391        16600 :                             break;
    1392              :                         }
    1393              :                     }
    1394              : 
    1395              :                     // Process Untils, Numbers
    1396        34869 :                     if (NumNumbers > 0) {
    1397        34869 :                         NumFields = NumNumbers;
    1398        34869 :                         ErrorHere = false;
    1399        34869 :                         ProcessIntervalFields(state,
    1400       139476 :                                               Alphas({UntilFld, _}),
    1401              :                                               Numbers,
    1402              :                                               NumFields,
    1403              :                                               NumNumbers,
    1404              :                                               minuteVals,
    1405              :                                               setMinuteVals,
    1406              :                                               ErrorHere,
    1407        34869 :                                               daySched->Name,
    1408        69738 :                                               CurrentModuleObject + " DaySchedule Fields",
    1409              :                                               daySched->interpolation);
    1410              :                         // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
    1411        34869 :                         if (ErrorHere) {
    1412            0 :                             ShowContinueError(state, format("ref {}=\"{}\"", CurrentModuleObject, Alphas(1)));
    1413            0 :                             ErrorsFound = true;
    1414              :                         }
    1415              : 
    1416        34869 :                         daySched->populateFromMinuteVals(state, minuteVals);
    1417              :                     }
    1418              :                 }
    1419              : 
    1420        16600 :             For_exit:;
    1421       301015 :                 for (int iDayType = iDayType_Sun; iDayType < (int)DayType::Num; ++iDayType) {
    1422       277860 :                     if (allDays[iDayType] == true) {
    1423       277860 :                         continue;
    1424              :                     }
    1425              : 
    1426            0 :                     ShowWarningCustom(state, eoh, format("has missing day types in Through={}", CurrentThrough));
    1427            0 :                     ShowContinueError(state, format("Last \"For\" field={}", LastFor));
    1428            0 :                     std::string errmsg = "Missing day types=,";
    1429            0 :                     for (int kDayType = iDayType_Sun; kDayType < (int)DayType::Num; ++kDayType) {
    1430            0 :                         if (allDays[kDayType]) {
    1431            0 :                             continue;
    1432              :                         }
    1433            0 :                         errmsg.erase(errmsg.length() - 1);
    1434            0 :                         errmsg = format("{} \"{}\",-", errmsg, dayTypeNames[kDayType]);
    1435              :                     }
    1436            0 :                     errmsg.erase(errmsg.length() - 2);
    1437            0 :                     ShowContinueError(state, errmsg);
    1438            0 :                     ShowContinueError(state, "Missing day types will have 0.0 as Schedule Values");
    1439            0 :                     break;
    1440            0 :                 }
    1441              :             }
    1442              : 
    1443        16600 :         Through_exit:;
    1444        16600 :             if (daysInYear[60] == 0) {
    1445            0 :                 daysInYear[60] = daysInYear[59];
    1446            0 :                 sched->weekScheds[60] = sched->weekScheds[59];
    1447              :             }
    1448              : 
    1449        16600 :             if (std::find(daysInYear.begin() + 1, daysInYear.end(), 0) != daysInYear.end()) {
    1450            0 :                 ShowSevereCustomAudit(state, eoh, "has missing days in its schedule pointers");
    1451            0 :                 ErrorsFound = true;
    1452              :             }
    1453      6092200 :             if (std::find_if(daysInYear.begin() + 1, daysInYear.end(), [](int i) { return i > 1; }) != daysInYear.end()) {
    1454            0 :                 ShowSevereCustomAudit(state, eoh, "has overlapping days in its schedule pointers");
    1455            0 :                 ErrorsFound = true;
    1456              :             }
    1457              : 
    1458        16600 :             if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
    1459         3860 :                 SetupEMSActuator(state, "Schedule:Compact", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
    1460              :             }
    1461              :         }
    1462              : 
    1463              :         //  Schedule:File,
    1464              :         //   \min-fields 5
    1465              :         //         \memo A Schedule:File points to a text computer file that has 8760-8784 hours of data.
    1466              :         //    A1 , \field Name
    1467              :         //         \required-field
    1468              :         //         \type alpha
    1469              :         //         \reference ScheduleNames
    1470              :         //    A2 , \field Schedule Type Limits Name
    1471              :         //         \type object-list
    1472              :         //         \object-list ScheduleTypeLimitsNames
    1473              :         //    A3 , \field File Name
    1474              :         //         \required-field
    1475              :         //         \retaincase
    1476              :         //    N1 , \field Column Number
    1477              :         //         \required-field
    1478              :         //         \type integer
    1479              :         //         \minimum 1
    1480              :         //    N2 , \field Rows to Skip at Top
    1481              :         //         \required-field
    1482              :         //         \type integer
    1483              :         //         \minimum 0
    1484              :         //    N3 , \field Number of Hours of Data
    1485              :         //         \note 8760 hours does not account for leap years, 8784 does.
    1486              :         //         \note should be either 8760 or 8784
    1487              :         //         \default 8760
    1488              :         //         \minimum 8760
    1489              :         //         \maximum 8784
    1490              :         //    A4 , \field Column Separator
    1491              :         //         \type choice
    1492              :         //         \key Comma
    1493              :         //         \key Tab
    1494              :         //         \key Space
    1495              :         //         \key Semicolon
    1496              :         //         \default Comma
    1497              :         //    A5 , \field Interpolate to Timestep
    1498              :         //         \note when the interval does not match the user specified timestep a "Yes" choice will average between the intervals request (to
    1499              :         //         \note timestep resolution.  a "No" choice will use the interval value at the simulation timestep without regard to if it matches
    1500              :         //         \note the boundary or not.
    1501              :         //         \type choice
    1502              :         //         \key Yes
    1503              :         //         \key No
    1504              :         //         \default No
    1505              :         //    N4 ; \field Minutes per Item
    1506              :         //         \note Must be evenly divisible into 60
    1507              :         //         \type integer
    1508              :         //         \minimum 1
    1509              :         //         \maximum 60
    1510              : 
    1511              :         // continue adding to SchNum,AddWeekSch,AddDaySch
    1512              : 
    1513          803 :         CurrentModuleObject = "Schedule:File";
    1514          936 :         for (int Loop = 1; Loop <= NumCommaFileSchedules; ++Loop) {
    1515          133 :             s_ip->getObjectItem(state,
    1516              :                                 CurrentModuleObject,
    1517              :                                 Loop,
    1518              :                                 Alphas,
    1519              :                                 NumAlphas,
    1520              :                                 Numbers,
    1521              :                                 NumNumbers,
    1522              :                                 Status,
    1523              :                                 lNumericBlanks,
    1524              :                                 lAlphaBlanks,
    1525              :                                 cAlphaFields,
    1526              :                                 cNumericFields);
    1527              : 
    1528          133 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1529              : 
    1530          133 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1531            0 :                 ShowSevereDuplicateName(state, eoh);
    1532            0 :                 ErrorsFound = true;
    1533            0 :                 continue;
    1534              :             }
    1535              : 
    1536          133 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    1537          133 :             sched->type = SchedType::File;
    1538              : 
    1539              :             // Validate ScheduleType
    1540          133 :             if (lAlphaBlanks(2)) {
    1541            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1542            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1543          133 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1544            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1545            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1546              :             }
    1547              : 
    1548              :             // Numbers(1) - which column
    1549          133 :             curcolCount = Numbers(1);
    1550              :             // Numbers(2) - number of rows to skip
    1551          133 :             skiprowCount = Numbers(2);
    1552          133 :             if (Numbers(3) == 0) {
    1553            0 :                 Numbers(3) = 8760.0;
    1554              :             }
    1555          133 :             if (Numbers(3) != 8760 && Numbers(3) != 8784) {
    1556            0 :                 ShowSevereCustom(
    1557              :                     state,
    1558              :                     eoh,
    1559            0 :                     format("{} must = 8760 or 8784 (for a leap year).  Value = {:.0T}, Schedule not processed.", cNumericFields(3), Numbers(3)));
    1560            0 :                 ErrorsFound = true;
    1561            0 :                 continue;
    1562              :             }
    1563              : 
    1564          133 :             if (lAlphaBlanks(4) || Util::SameString(Alphas(4), "comma")) {
    1565          133 :                 ColumnSep = CharComma;
    1566          133 :                 Alphas(4) = "comma";
    1567            0 :             } else if (Util::SameString(Alphas(4), "semicolon")) {
    1568            0 :                 ColumnSep = CharSemicolon;
    1569            0 :             } else if (Util::SameString(Alphas(4), "tab")) {
    1570            0 :                 ColumnSep = CharTab;
    1571            0 :             } else if (Util::SameString(Alphas(4), "space")) {
    1572            0 :                 ColumnSep = CharSpace;
    1573              :             } else {
    1574            0 :                 ShowSevereInvalidKey(state, eoh, cAlphaFields(4), Alphas(4), "..must be Comma, Semicolon, Tab, or Space.");
    1575            0 :                 ErrorsFound = true;
    1576            0 :                 continue;
    1577              :             }
    1578              : 
    1579              :             // Depending on value of "Interpolate" field, the value for each time step in each hour gets processed:
    1580          133 :             Interpolation interp = Interpolation::No;
    1581              : 
    1582          133 :             if (!lAlphaBlanks(5)) {
    1583            4 :                 if (BooleanSwitch bs = getYesNoValue(Alphas(5)); bs != BooleanSwitch::Invalid) {
    1584            4 :                     interp = static_cast<bool>(bs) ? Interpolation::Average : Interpolation::Linear;
    1585              :                 } else {
    1586            0 :                     ShowSevereInvalidKey(state, eoh, cAlphaFields(5), Alphas(5));
    1587            0 :                     ErrorsFound = true;
    1588              :                 }
    1589              :             }
    1590              : 
    1591          133 :             sched->UseDaylightSaving = true;
    1592          133 :             if ((Alphas(6)) == "NO") {
    1593            2 :                 sched->UseDaylightSaving = false;
    1594              :             }
    1595              : 
    1596              :             // is it a sub-hourly schedule or not?
    1597          133 :             int MinutesPerItem = Constant::iMinutesInHour;
    1598          133 :             if (NumNumbers > 3) {
    1599          133 :                 MinutesPerItem = int(Numbers(4));
    1600              :                 // int NumExpectedItems = 1440 / MinutesPerItem;
    1601          133 :                 if (mod(Constant::iMinutesInHour, MinutesPerItem) != 0) {
    1602            0 :                     ShowSevereCustom(
    1603            0 :                         state, eoh, format("Requested {} field value ({}) not evenly divisible into 60", cNumericFields(4), MinutesPerItem));
    1604            0 :                     ErrorsFound = true;
    1605            0 :                     continue;
    1606              :                 }
    1607              :             }
    1608              : 
    1609          133 :             int numHourlyValues = Numbers(3);
    1610          133 :             int rowLimitCount = (Numbers(3) * Constant::rMinutesInHour) / MinutesPerItem;
    1611          133 :             int hrLimitCount = Constant::iMinutesInHour / MinutesPerItem;
    1612              : 
    1613          133 :             std::string contextString = format("{}=\"{}\", {}: ", CurrentModuleObject, Alphas(1), cAlphaFields(3));
    1614              : 
    1615          133 :             state.files.TempFullFilePath.filePath = CheckForActualFilePath(state, Alphas(3), contextString);
    1616              :             // Setup file reading parameters
    1617          133 :             if (state.files.TempFullFilePath.filePath.empty()) {
    1618            0 :                 ErrorsFound = true;
    1619              :             } else {
    1620          133 :                 auto result = s_sched->UniqueProcessedExternalFiles.find(state.files.TempFullFilePath.filePath);
    1621          133 :                 if (result == s_sched->UniqueProcessedExternalFiles.end()) {
    1622            9 :                     FileSystem::FileTypes const ext = FileSystem::getFileType(state.files.TempFullFilePath.filePath);
    1623            9 :                     if (FileSystem::is_flat_file_type(ext)) {
    1624            9 :                         auto const schedule_data = FileSystem::readFile(state.files.TempFullFilePath.filePath);
    1625            9 :                         CsvParser csvParser;
    1626            9 :                         auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
    1627            9 :                                                                                 csvParser.decode(schedule_data, ColumnSep, skiprowCount));
    1628            9 :                         if (csvParser.hasErrors()) {
    1629            0 :                             for (const auto &[error, isContinued] : csvParser.errors()) {
    1630            0 :                                 if (isContinued) {
    1631            0 :                                     ShowContinueError(state, error);
    1632              :                                 } else {
    1633            0 :                                     ShowSevereError(state, error);
    1634              :                                 }
    1635            0 :                             }
    1636            0 :                             ShowContinueError(state, fmt::format("Error Occurred in {}", state.files.TempFullFilePath.filePath));
    1637            0 :                             ShowFatalError(state, "Program terminates due to previous condition.");
    1638              :                         }
    1639            9 :                         result = it.first;
    1640            9 :                     } else if (FileSystem::is_all_json_type(ext)) {
    1641            0 :                         auto it = s_sched->UniqueProcessedExternalFiles.emplace(state.files.TempFullFilePath.filePath,
    1642            0 :                                                                                 FileSystem::readJSON(state.files.TempFullFilePath.filePath));
    1643            0 :                         result = it.first;
    1644            0 :                     } else {
    1645            0 :                         ShowSevereCustom(
    1646              :                             state,
    1647              :                             eoh,
    1648            0 :                             format("{} = {} has an unknown file extension and cannot be read by this program.", cAlphaFields(3), Alphas(3)));
    1649            0 :                         ShowFatalError(state, "Program terminates due to previous condition.");
    1650              :                     }
    1651              :                 }
    1652              : 
    1653          133 :                 auto const &column_json = result->second["values"][curcolCount - 1];
    1654          133 :                 rowCnt = column_json.size();
    1655          133 :                 auto const column_values = column_json.get<std::vector<Real64>>(); // (AUTO_OK_OBJ)
    1656              : 
    1657              :                 // schedule values have been filled into the hourlyFileValues array.
    1658              : 
    1659          133 :                 if (numerrors > 0) {
    1660            0 :                     ShowWarningCustom(state,
    1661              :                                       eoh,
    1662            0 :                                       format("{} records had errors - these values are set to 0."
    1663              :                                              "Use Output:Diagnostics,DisplayExtraWarnings; to see individual records in error.",
    1664              :                                              numerrors));
    1665              :                 }
    1666              : 
    1667          133 :                 if (rowCnt < rowLimitCount) {
    1668            0 :                     ShowWarningCustom(state,
    1669              :                                       eoh,
    1670            0 :                                       format("less than {} hourly values read from file."
    1671              :                                              "..Number read={}.",
    1672              :                                              numHourlyValues,
    1673            0 :                                              (rowCnt * Constant::iMinutesInHour) / MinutesPerItem));
    1674              :                 }
    1675              : 
    1676              :                 // process the data into the normal schedule data structures
    1677              :                 // note -- schedules are ALWAYS 366 days so some special measures have to be done at 29 Feb "day of year" (60)
    1678          133 :                 int iDay = 0;
    1679          133 :                 int hDay = 0;
    1680          133 :                 int ifld = 0;
    1681              :                 while (true) {
    1682              :                     // create string of which day of year
    1683        48678 :                     ++iDay;
    1684        48678 :                     ++hDay;
    1685        48678 :                     if (iDay > 366) {
    1686          133 :                         break;
    1687              :                     }
    1688              :                     // increment both since a week schedule is being defined for each day so that a day is valid
    1689              :                     // no matter what the day type that is used in a design day.
    1690              : 
    1691              :                     // define day schedule
    1692        48545 :                     auto *daySched = AddDaySchedule(state, format("{}_dy_{}", Alphas(1), iDay));
    1693        48545 :                     daySched->schedTypeNum = sched->schedTypeNum;
    1694              : 
    1695              :                     // define week schedule
    1696        48545 :                     auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", Alphas(1), iDay));
    1697              : 
    1698              :                     // for all day types point the week schedule to the newly defined day schedule
    1699       631085 :                     for (int kDayType = 1; kDayType < (int)DayType::Num; ++kDayType) {
    1700       582540 :                         weekSched->dayScheds[kDayType] = daySched;
    1701              :                     }
    1702              : 
    1703              :                     // schedule is pointing to the week schedule
    1704        48545 :                     sched->weekScheds[iDay] = weekSched;
    1705              : 
    1706        48545 :                     if (MinutesPerItem == Constant::iMinutesInHour) {
    1707       100375 :                         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    1708        96360 :                             Real64 curHrVal = column_values[ifld]; // hourlyFileValues((hDay - 1) * 24 + jHour)
    1709        96360 :                             ++ifld;
    1710       481800 :                             for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
    1711       385440 :                                 daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = curHrVal;
    1712       385440 :                                 daySched->sumTsVals += daySched->tsVals[hr * s_glob->TimeStepsInHour + ts];
    1713              :                             }
    1714              :                         }
    1715              :                     } else { // Minutes Per Item < 60
    1716      1113250 :                         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    1717      1068720 :                             int endMin = MinutesPerItem - 1;
    1718      1068720 :                             int begMin = 0;
    1719      5694000 :                             for (int NumFields = 1; NumFields <= hrLimitCount; ++NumFields) {
    1720     68748480 :                                 for (int iMin = begMin; iMin <= endMin; ++iMin) {
    1721     64123200 :                                     minuteVals[hr * Constant::iMinutesInHour + iMin] = column_values[ifld];
    1722              :                                 }
    1723              : 
    1724      4625280 :                                 ++ifld;
    1725      4625280 :                                 begMin = endMin + 1;
    1726      4625280 :                                 endMin += MinutesPerItem;
    1727              :                             }
    1728              :                         }
    1729              : 
    1730        44530 :                         daySched->interpolation = interp;
    1731        44530 :                         daySched->populateFromMinuteVals(state, minuteVals);
    1732              :                     }
    1733        48545 :                     if (iDay == 59 && rowCnt < 8784 * hrLimitCount) { // 28 Feb
    1734              :                         // Dup 28 Feb to 29 Feb (60)
    1735          133 :                         ++iDay;
    1736          133 :                         sched->weekScheds[iDay] = sched->weekScheds[iDay - 1];
    1737              :                     }
    1738        48545 :                 }
    1739          133 :             }
    1740              : 
    1741          133 :             if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
    1742            0 :                 SetupEMSActuator(state, "Schedule:File", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
    1743              :             }
    1744          133 :         }
    1745              : 
    1746          803 :         if (NumCommaFileShading != 0) {
    1747            1 :             auto const &values_json = schedule_file_shading_result->second["values"];
    1748            1 :             auto const headers = schedule_file_shading_result->second["header"].get<std::vector<std::string>>();  // (AUTO_OK_OBJ)
    1749            1 :             auto const headers_set = schedule_file_shading_result->second["header"].get<std::set<std::string>>(); // (AUTO_OK_OBJ)
    1750              : 
    1751          115 :             for (auto const &header : headers_set) {
    1752          114 :                 size_t column = 0;
    1753          114 :                 auto column_it = std::find(headers.begin(), headers.end(), header);
    1754          114 :                 if (column_it != headers.end()) {
    1755          228 :                     column = std::distance(headers.begin(), column_it);
    1756              :                 }
    1757          114 :                 if (column == 0) {
    1758            1 :                     continue; // Skip timestamp column and any duplicate column, which will be 0 as well since it won't be found.
    1759              :                 }
    1760          113 :                 auto const column_values = values_json.at(column).get<std::vector<Real64>>(); // (AUTO_OK_OBJ)
    1761              : 
    1762          113 :                 std::string curName = format("{}_shading", header);
    1763          113 :                 std::string curNameUC = Util::makeUPPER(curName);
    1764              : 
    1765          113 :                 if (s_sched->scheduleMap.find(curNameUC) != s_sched->scheduleMap.end()) {
    1766            0 :                     ShowSevereError(state, format("Duplicate schedule name {}", curName));
    1767            0 :                     ErrorsFound = true;
    1768            0 :                     continue;
    1769              :                 }
    1770              : 
    1771          113 :                 auto *schedShading = AddScheduleDetailed(state, curName);
    1772          113 :                 schedShading->type = SchedType::File;
    1773              : 
    1774          113 :                 int iDay = 0;
    1775          113 :                 int ifld = 0;
    1776              :                 while (true) {
    1777              :                     // create string of which day of year
    1778        41358 :                     ++iDay;
    1779        41358 :                     if (iDay > 366) {
    1780          113 :                         break;
    1781              :                     }
    1782              : 
    1783              :                     // day schedule
    1784        41245 :                     auto *daySched = AddDaySchedule(state, format("{}_dy_{}", curName, iDay));
    1785        41245 :                     daySched->schedTypeNum = schedShading->schedTypeNum;
    1786              : 
    1787              :                     // define week schedule
    1788        41245 :                     auto *weekSched = AddWeekSchedule(state, format("{}_wk_{}", curName, iDay));
    1789              : 
    1790              :                     // for all day types point the week schedule to the newly defined day schedule
    1791       536185 :                     for (int kDayType = 1; kDayType < (int)DayType::Num; ++kDayType) {
    1792       494940 :                         weekSched->dayScheds[kDayType] = daySched;
    1793              :                     }
    1794              : 
    1795              :                     // schedule is pointing to the week schedule
    1796        41245 :                     schedShading->weekScheds[iDay] = weekSched;
    1797              : 
    1798      1031125 :                     for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    1799      4949400 :                         for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
    1800      3959520 :                             daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = column_values[ifld];
    1801      3959520 :                             ++ifld;
    1802              :                         }
    1803              :                     }
    1804              : 
    1805        41245 :                     if (iDay == 59 && !state.dataEnvrn->CurrentYearIsLeapYear) { // 28 Feb
    1806              :                         // Dup 28 Feb to 29 Feb (60)
    1807          113 :                         ++iDay;
    1808          113 :                         schedShading->weekScheds[iDay] = schedShading->weekScheds[iDay - 1];
    1809              :                     }
    1810        41245 :                 }
    1811          115 :             }
    1812            1 :         }
    1813              : 
    1814              :         // Constant Schedules
    1815          803 :         CurrentModuleObject = "Schedule:Constant";
    1816         1068 :         for (int Loop = 1; Loop <= NumConstantSchedules; ++Loop) {
    1817          265 :             s_ip->getObjectItem(state,
    1818              :                                 CurrentModuleObject,
    1819              :                                 Loop,
    1820              :                                 Alphas,
    1821              :                                 NumAlphas,
    1822              :                                 Numbers,
    1823              :                                 NumNumbers,
    1824              :                                 Status,
    1825              :                                 lNumericBlanks,
    1826              :                                 lAlphaBlanks,
    1827              :                                 cAlphaFields,
    1828              :                                 cNumericFields);
    1829              : 
    1830          265 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1831              : 
    1832          265 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1833            0 :                 ShowSevereDuplicateName(state, eoh);
    1834            0 :                 ErrorsFound = true;
    1835            0 :                 continue;
    1836              :             }
    1837              : 
    1838          265 :             auto *sched = AddScheduleConstant(state, Alphas(1), Numbers(1));
    1839              : 
    1840              :             // Validate ScheduleType
    1841          265 :             if (lAlphaBlanks(2)) { // No warning here for constant schedules
    1842           34 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1843          102 :                 ShowContinueError(state, "Schedule will not be validated.");
    1844          231 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1845            2 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1846            6 :                 ShowContinueError(state, "Schedule will not be validated.");
    1847              :             }
    1848              : 
    1849          265 :             if (s_glob->AnyEnergyManagementSystemInModel) { // setup constant schedules as actuators
    1850           94 :                 SetupEMSActuator(state, "Schedule:Constant", sched->Name, "Schedule Value", "[ ]", sched->EMSActuatedOn, sched->EMSVal);
    1851              :             }
    1852              :         }
    1853              :         // When InitConstantScheduleData is called, TimeStepsInHour is 0, so we delay it here
    1854          803 :         static_cast<ScheduleConstant *>(s_sched->schedules[SchedNum_AlwaysOff])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 0.0);
    1855          803 :         static_cast<ScheduleConstant *>(s_sched->schedules[SchedNum_AlwaysOn])->tsVals.assign(Constant::iHoursInDay * s_glob->TimeStepsInHour, 1.0);
    1856              : 
    1857          803 :         CurrentModuleObject = "ExternalInterface:Schedule";
    1858          803 :         for (int Loop = 1; Loop <= NumExternalInterfaceSchedules; ++Loop) {
    1859            0 :             s_ip->getObjectItem(state,
    1860              :                                 CurrentModuleObject,
    1861              :                                 Loop,
    1862              :                                 Alphas,
    1863              :                                 NumAlphas,
    1864              :                                 Numbers,
    1865              :                                 NumNumbers,
    1866              :                                 Status,
    1867              :                                 lNumericBlanks,
    1868              :                                 lAlphaBlanks,
    1869              :                                 cAlphaFields,
    1870              :                                 cNumericFields);
    1871              : 
    1872            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1873              : 
    1874            0 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1875            0 :                 ShowSevereDuplicateName(state, eoh);
    1876            0 :                 ErrorsFound = true;
    1877            0 :                 continue;
    1878              :             }
    1879              : 
    1880            0 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    1881            0 :             sched->type = SchedType::External;
    1882              : 
    1883              :             // Validate ScheduleType
    1884            0 :             if (lAlphaBlanks(2)) {
    1885            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1886            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1887            0 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1888            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1889            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1890              :             }
    1891              : 
    1892              :             // TODO: I'm not sure this Jazz is necessary
    1893              :             // Add day schedule
    1894            0 :             auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
    1895            0 :             daySched->isUsed = true;
    1896            0 :             daySched->schedTypeNum = sched->schedTypeNum;
    1897              : 
    1898              :             //   Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
    1899              :             //   It will be overwritten during run time stepping after the warm up period
    1900            0 :             if (NumNumbers < 1) {
    1901            0 :                 ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
    1902            0 :                 NumErrorFlag = true;
    1903              :             }
    1904            0 :             ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
    1905              : 
    1906            0 :             auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
    1907            0 :             weekSched->isUsed = true;
    1908            0 :             for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    1909            0 :                 weekSched->dayScheds[iDayType] = daySched;
    1910              :             }
    1911              : 
    1912            0 :             for (int iDay = 1; iDay <= 366; ++iDay) {
    1913            0 :                 sched->weekScheds[iDay] = weekSched;
    1914              :             }
    1915              :         } // for (Loop)
    1916              : 
    1917              :         // added for FMU Import
    1918          803 :         CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
    1919          805 :         for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitImportSchedules; ++Loop) {
    1920            2 :             s_ip->getObjectItem(state,
    1921              :                                 CurrentModuleObject,
    1922              :                                 Loop,
    1923              :                                 Alphas,
    1924              :                                 NumAlphas,
    1925              :                                 Numbers,
    1926              :                                 NumNumbers,
    1927              :                                 Status,
    1928              :                                 lNumericBlanks,
    1929              :                                 lAlphaBlanks,
    1930              :                                 cAlphaFields,
    1931              :                                 cNumericFields);
    1932              : 
    1933            2 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1934              : 
    1935            2 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    1936            0 :                 ShowSevereDuplicateName(state, eoh);
    1937            0 :                 if (NumExternalInterfaceSchedules >= 1) {
    1938            0 :                     ShowContinueError(
    1939              :                         state,
    1940            0 :                         format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule."
    1941              :                                "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)",
    1942              :                                cAlphaFields(1)));
    1943              :                 }
    1944            0 :                 ErrorsFound = true;
    1945            0 :                 continue;
    1946              :             }
    1947              : 
    1948            2 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    1949            2 :             sched->type = SchedType::External;
    1950              : 
    1951              :             // Validate ScheduleType
    1952            2 :             if (lAlphaBlanks(2)) {
    1953            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    1954            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1955            2 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    1956            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1957            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    1958              :             }
    1959              : 
    1960              :             // TODO: I'm not sure this Jazz is necessary
    1961              :             // Add day schedule
    1962            2 :             auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
    1963            2 :             daySched->isUsed = true;
    1964            2 :             daySched->schedTypeNum = sched->schedTypeNum;
    1965              : 
    1966              :             //   Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
    1967              :             //   It will be overwritten during run time stepping after the warm up period
    1968            2 :             if (NumNumbers < 1) {
    1969            0 :                 ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
    1970            0 :                 NumErrorFlag = true;
    1971              :             }
    1972            2 :             ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
    1973              : 
    1974            2 :             auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
    1975            2 :             weekSched->isUsed = true;
    1976           26 :             for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    1977           24 :                 weekSched->dayScheds[iDayType] = daySched;
    1978              :             }
    1979              : 
    1980          734 :             for (int iDay = 1; iDay <= 366; ++iDay) {
    1981          732 :                 sched->weekScheds[iDay] = weekSched;
    1982              :             }
    1983              :         }
    1984              : 
    1985              :         // added for FMU Export
    1986          803 :         CurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Schedule";
    1987          803 :         for (int Loop = 1; Loop <= NumExternalInterfaceFunctionalMockupUnitExportSchedules; ++Loop) {
    1988            0 :             s_ip->getObjectItem(state,
    1989              :                                 CurrentModuleObject,
    1990              :                                 Loop,
    1991              :                                 Alphas,
    1992              :                                 NumAlphas,
    1993              :                                 Numbers,
    1994              :                                 NumNumbers,
    1995              :                                 Status,
    1996              :                                 lNumericBlanks,
    1997              :                                 lAlphaBlanks,
    1998              :                                 cAlphaFields,
    1999              :                                 cNumericFields);
    2000              : 
    2001            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    2002              : 
    2003            0 :             if (s_sched->scheduleMap.find(Alphas(1)) != s_sched->scheduleMap.end()) {
    2004            0 :                 ShowSevereDuplicateName(state, eoh);
    2005            0 :                 if (NumExternalInterfaceSchedules >= 1) {
    2006            0 :                     ShowContinueError(
    2007              :                         state,
    2008            0 :                         format("{} defined as an ExternalInterface:Schedule and ExternalInterface:FunctionalMockupUnitImport:To:Schedule."
    2009              :                                "This will cause the schedule to be overwritten by PtolemyServer and FunctionalMockUpUnitImport)",
    2010              :                                cAlphaFields(1)));
    2011              :                 }
    2012            0 :                 ErrorsFound = true;
    2013            0 :                 continue;
    2014              :             }
    2015              : 
    2016            0 :             auto *sched = AddScheduleDetailed(state, Alphas(1));
    2017            0 :             sched->type = SchedType::External;
    2018              : 
    2019              :             // Validate ScheduleType
    2020            0 :             if (lAlphaBlanks(2)) {
    2021            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(2));
    2022            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    2023            0 :             } else if ((sched->schedTypeNum = GetScheduleTypeNum(state, Alphas(2))) == SchedNum_Invalid) {
    2024            0 :                 ShowWarningItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    2025            0 :                 ShowContinueError(state, "Schedule will not be validated.");
    2026              :             }
    2027              : 
    2028              :             // TODO: I'm not sure this Jazz is necessary
    2029              :             // Add day schedule
    2030            0 :             auto *daySched = AddDaySchedule(state, format("{}_xi_dy_", Alphas(1)));
    2031            0 :             daySched->isUsed = true;
    2032            0 :             daySched->schedTypeNum = sched->schedTypeNum;
    2033              : 
    2034              :             //   Initialize the ExternalInterface day schedule for the ExternalInterface compact schedule.
    2035              :             //   It will be overwritten during run time stepping after the warm up period
    2036            0 :             if (NumNumbers < 1) {
    2037            0 :                 ShowWarningCustom(state, eoh, "Initial value is not numeric or is missing. Fix idf file.");
    2038            0 :                 NumErrorFlag = true;
    2039              :             }
    2040            0 :             ExternalInterfaceSetSchedule(state, daySched->Num, Numbers(1));
    2041              : 
    2042            0 :             auto *weekSched = AddWeekSchedule(state, format("{}_xi_wk_", Alphas(1)));
    2043            0 :             weekSched->isUsed = true;
    2044            0 :             for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    2045            0 :                 weekSched->dayScheds[iDayType] = daySched;
    2046              :             }
    2047              : 
    2048            0 :             std::fill(sched->weekScheds.begin() + 1, sched->weekScheds.end(), weekSched);
    2049              :         } // for (Loop)
    2050              : 
    2051              :         // Validate by ScheduleLimitsType
    2052        19699 :         for (auto *sched : s_sched->schedules) {
    2053              : 
    2054        18896 :             if (sched->schedTypeNum == SchedNum_Invalid) {
    2055         1765 :                 continue;
    2056              :             }
    2057              : 
    2058        17131 :             auto const *schedType = s_sched->scheduleTypes[sched->schedTypeNum];
    2059        17131 :             if (!schedType->isLimited) {
    2060         3562 :                 continue;
    2061              :             }
    2062              : 
    2063        13569 :             if (!sched->checkMinMaxVals(state, Clusive::In, schedType->minVal, Clusive::In, schedType->maxVal)) {
    2064            0 :                 ErrorObjectHeader eoh{routineName, "Schedule", sched->Name};
    2065            0 :                 ShowSevereBadMinMax(state, eoh, "", "", Clusive::In, schedType->minVal, Clusive::In, schedType->maxVal);
    2066            0 :                 ErrorsFound = true;
    2067              :             }
    2068          803 :         }
    2069              : 
    2070          803 :         if (ErrorsFound) {
    2071            0 :             ShowFatalError(state, format("{}: Preceding Errors cause termination.", routineName));
    2072              :         }
    2073              : 
    2074          803 :         if (s_sched->scheduleTypes.size() + s_sched->daySchedules.size() + s_sched->weekSchedules.size() + s_sched->schedules.size() > 0) {
    2075          803 :             CurrentModuleObject = "Output:Schedules";
    2076          803 :             NumFields = s_ip->getNumObjectsFound(state, CurrentModuleObject);
    2077              : 
    2078              :             // Report the ScheduleTypeLimits only once, not for each report level.
    2079          803 :             if (NumFields > 0) {
    2080           21 :                 ReportScheduleTypeLimits(state);
    2081              :             }
    2082              : 
    2083          803 :             std::set<ReportLevel> reportLevelSet;
    2084              :             //    RptSchedule=.FALSE.
    2085          826 :             for (int Count = 1; Count <= NumFields; ++Count) {
    2086           23 :                 s_ip->getObjectItem(state, CurrentModuleObject, Count, Alphas, NumAlphas, Numbers, NumNumbers, Status);
    2087              : 
    2088           23 :                 ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    2089              : 
    2090              :                 // IDD only allows Hourly or Timestep as valid values on the required field, anything else should be an error in the input processor
    2091           23 :                 ReportLevel reportLevel = static_cast<ReportLevel>(getEnumValue(reportLevelNamesUC, Alphas(1)));
    2092           23 :                 if (reportLevel == ReportLevel::Invalid) {
    2093            0 :                     ShowWarningInvalidKey(state, eoh, cAlphaFields(1), Alphas(1), "HOURLY report will be done");
    2094            0 :                     reportLevel = ReportLevel::Hourly;
    2095              :                 }
    2096           23 :                 if (auto [it, inserted] = reportLevelSet.insert(reportLevel); inserted) {
    2097              :                     // If this is the first time we see this report level, we need to report the details
    2098           23 :                     ReportScheduleDetails(state, reportLevel);
    2099              :                 } else {
    2100            0 :                     ShowWarningCustom(state,
    2101              :                                       eoh,
    2102            0 :                                       format("Report level {} has already been processed. This report level will not be processed again.",
    2103            0 :                                              reportLevelNames[(int)reportLevel]));
    2104            0 :                     continue;
    2105           23 :                 }
    2106              :             }
    2107          803 :         }
    2108              : 
    2109          803 :         Alphas.deallocate();
    2110          803 :         cAlphaFields.deallocate();
    2111          803 :         cNumericFields.deallocate();
    2112          803 :         Numbers.deallocate();
    2113          803 :         lAlphaBlanks.deallocate();
    2114          803 :         lNumericBlanks.deallocate();
    2115              : 
    2116          803 :         print(state.files.audit, "{}\n", "  Processing Schedule Input -- Complete");
    2117        36025 :     } // ProcessScheduleInput()
    2118              : 
    2119           21 :     void ReportScheduleTypeLimits(EnergyPlusData &state)
    2120              :     {
    2121           21 :         std::string YesNoLimited;
    2122           21 :         std::string minValStr;
    2123           21 :         std::string maxValStr;
    2124           21 :         std::string YesNoContinous;
    2125              : 
    2126           21 :         std::string_view constexpr scheduleTypeLimitTableName("ScheduleTypeLimits");
    2127           21 :         print(state.files.eio, "! <{}>,Name,Limited? {{Yes/No}},Minimum,Maximum,Continuous? {{Yes/No - Discrete}}\n", scheduleTypeLimitTableName);
    2128              : 
    2129          155 :         for (auto const *schedType : state.dataSched->scheduleTypes) {
    2130          134 :             if (schedType->isLimited) {
    2131           98 :                 YesNoLimited = "Yes";
    2132           98 :                 minValStr = format("{:.2R}", schedType->minVal);
    2133           98 :                 strip(minValStr);
    2134           98 :                 maxValStr = format("{:.2R}", schedType->maxVal);
    2135           98 :                 strip(maxValStr);
    2136           98 :                 if (schedType->isReal) {
    2137           61 :                     YesNoContinous = "Yes";
    2138              :                 } else {
    2139           37 :                     YesNoContinous = "No";
    2140           37 :                     minValStr = fmt::to_string((int)schedType->minVal);
    2141           37 :                     maxValStr = fmt::to_string((int)schedType->maxVal);
    2142              :                 }
    2143              :             } else {
    2144           36 :                 YesNoLimited = "No";
    2145           36 :                 minValStr = "N/A";
    2146           36 :                 maxValStr = "N/A";
    2147           36 :                 YesNoContinous = "N/A";
    2148              :             }
    2149          134 :             print(state.files.eio,
    2150              :                   "{},{},{},{},{},{}\n",
    2151              :                   scheduleTypeLimitTableName,
    2152          134 :                   schedType->Name,
    2153              :                   YesNoLimited,
    2154              :                   minValStr,
    2155              :                   maxValStr,
    2156              :                   YesNoContinous);
    2157           21 :         }
    2158           21 :     }
    2159              : 
    2160           23 :     void ReportScheduleDetails(EnergyPlusData &state,
    2161              :                                ReportLevel const LevelOfDetail) // =1: hourly; =2: timestep; = 3: make IDF excerpt
    2162              :     {
    2163              :         // SUBROUTINE INFORMATION:
    2164              :         //       AUTHOR         Linda K. Lawrie
    2165              :         //       DATE WRITTEN   January 2003
    2166              :         //       MODIFIED       February 2008 - add IDF outputs (compact schedules)
    2167              : 
    2168              :         // PURPOSE OF THIS SUBROUTINE:
    2169              :         // This subroutine puts the details of the Schedules on the .eio file (Inits file).
    2170              : 
    2171              :         // SUBROUTINE PARAMETER DEFINITIONS:
    2172              : 
    2173           23 :         assert(LevelOfDetail != ReportLevel::Invalid);
    2174              : 
    2175           23 :         constexpr std::array<std::string_view, 12> Months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    2176           23 :         constexpr std::array<std::string_view, 25> HrField = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
    2177              :                                                               "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24"};
    2178              : 
    2179              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2180              : 
    2181           23 :         auto const &s_glob = state.dataGlobal;
    2182           23 :         auto const &s_sched = state.dataSched;
    2183              : 
    2184           23 :         std::vector<std::string> times;
    2185           23 :         int const NumTimesInDay = (LevelOfDetail == ReportLevel::TimeStep) ? s_glob->TimeStepsInHour * Constant::iHoursInDay : Constant::iHoursInDay;
    2186           23 :         if (LevelOfDetail == ReportLevel::TimeStep) {
    2187           20 :             times.reserve(NumTimesInDay);
    2188            3 :         } else if (LevelOfDetail == ReportLevel::Hourly) {
    2189            3 :             times.reserve(NumTimesInDay);
    2190              :         } else {
    2191            0 :             assert(false); // Invalid report level
    2192              :         }
    2193              : 
    2194          575 :         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    2195          552 :             if (LevelOfDetail == ReportLevel::TimeStep) {
    2196         2784 :                 for (int ts = 0; ts < s_glob->TimeStepsInHour - 1; ++ts) {
    2197         4608 :                     times.emplace_back(fmt::format("{}:{:02}", HrField[hr], ((ts + 1)) * s_glob->MinutesInTimeStep));
    2198              :                 }
    2199              :             }
    2200         1104 :             times.emplace_back(fmt::format("{}:00", HrField[hr + 1]));
    2201              :         }
    2202           23 :         assert(times.size() == NumTimesInDay);
    2203              : 
    2204           23 :         std::string_view const &reportLevelName = reportLevelNames[(int)LevelOfDetail];
    2205           23 :         std::string const dayScheduleTableName = format("DaySchedule - {}", reportLevelName);
    2206           23 :         std::string const weekScheduleTableName = format("WeekSchedule - {}", reportLevelName); // TODO: "Schedule:Week:Daily" ?
    2207           23 :         std::string const scheduleTableName = format("Schedule - {}", reportLevelName);         // TODO: "Detailed Schedule" maybe?
    2208              : 
    2209              :         // Schedule Types Header
    2210              :         {
    2211              :             // This is just a top level separator, for convenience/neatness, will not match any actual data
    2212           23 :             print(state.files.eio, "! Schedule Details Report={} =====================\n", reportLevelName);
    2213              : 
    2214              :             // ! <DaySchedule_Hourly>,Name,ScheduleType,Interpolated {Yes/No},Time (HH:MM) =>,00:15,00:30,..23:45,24.00
    2215           23 :             print(state.files.eio, "! <{}>,Name,ScheduleType,Interpolated {{Average/Linear/No}},Time (HH:MM) =>", dayScheduleTableName);
    2216         2879 :             for (const auto &time : times) {
    2217         2856 :                 print(state.files.eio, ",{}", time);
    2218           23 :             }
    2219           23 :             print(state.files.eio, "\n");
    2220              : 
    2221              :             // ! <WeekSchedule_Hourly>,Name,Sunday,Monday,...,Saturday,Holiday,SummerDesignDay,WinterDesignDay,CustomDay1,CustomDay2
    2222           23 :             print(state.files.eio, "! <{}>,Name", weekScheduleTableName);
    2223          299 :             for (int Count = 1; Count < (int)DayType::Num; ++Count) {
    2224          276 :                 print(state.files.eio, ",{}", dayTypeNames[Count]);
    2225              :             }
    2226           23 :             print(state.files.eio, "\n");
    2227              : 
    2228              :             // ! <Schedule_Hourly>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31
    2229           23 :             print(state.files.eio, "! <{}>,Name,ScheduleType,{{Until Date,WeekSchedule}}** Repeated until Dec 31\n", scheduleTableName);
    2230              :         }
    2231              : 
    2232          944 :         for (auto *daySched : s_sched->daySchedules) {
    2233              : 
    2234          921 :             print(state.files.eio,
    2235              :                   "{},{},{},{},{}",
    2236              :                   dayScheduleTableName,
    2237          921 :                   daySched->Name,
    2238         1842 :                   (daySched->schedTypeNum == SchedNum_Invalid) ? "" : s_sched->scheduleTypes[daySched->schedTypeNum]->Name,
    2239          921 :                   interpolationNames[(int)daySched->interpolation],
    2240              :                   "Values:");
    2241              : 
    2242          921 :             if (LevelOfDetail == ReportLevel::Hourly) {
    2243          575 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    2244          552 :                     print(state.files.eio, ",{:.2R}", daySched->tsVals[(hr + 1) * s_glob->TimeStepsInHour - 1]);
    2245              :                 }
    2246          898 :             } else if (LevelOfDetail == ReportLevel::TimeStep) {
    2247        22450 :                 for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    2248       150000 :                     for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
    2249       128448 :                         print(state.files.eio, ",{:.2R}", daySched->tsVals[hr * s_glob->TimeStepsInHour + ts]);
    2250              :                     }
    2251              :                 }
    2252              :             } else {
    2253            0 :                 assert(false);
    2254              :             }
    2255          921 :             print(state.files.eio, "\n");
    2256           23 :         }
    2257              : 
    2258          672 :         for (auto *weekSched : s_sched->weekSchedules) {
    2259          649 :             print(state.files.eio, "{},{}", weekScheduleTableName, weekSched->Name);
    2260         8437 :             for (int DayNum = 1; DayNum < (int)DayType::Num; ++DayNum) {
    2261         7788 :                 print(state.files.eio, ",{}", weekSched->dayScheds[DayNum]->Name);
    2262              :             }
    2263          649 :             print(state.files.eio, "\n");
    2264           23 :         }
    2265              : 
    2266          712 :         for (auto *sched : s_sched->schedules) {
    2267              : 
    2268          689 :             if (sched->type == SchedType::Constant) {
    2269           48 :                 continue;
    2270              :             }
    2271              : 
    2272          641 :             auto *schedDetailed = dynamic_cast<ScheduleDetailed *>(sched);
    2273          641 :             assert(schedDetailed != nullptr);
    2274              : 
    2275          641 :             print(state.files.eio,
    2276              :                   "{},{},{}",
    2277              :                   scheduleTableName,
    2278          641 :                   schedDetailed->Name,
    2279         1282 :                   (sched->schedTypeNum == SchedNum_Invalid) ? "" : s_sched->scheduleTypes[sched->schedTypeNum]->Name);
    2280              : 
    2281          641 :             int PMon = 0;
    2282          641 :             int PDay = 0;
    2283          641 :             std::string_view constexpr ThruFmt(",Through {} {:02},{}");
    2284          641 :             int DayNum = 1;
    2285         1290 :             while (DayNum <= 366) {
    2286          649 :                 auto *weekSched = schedDetailed->weekScheds[DayNum];
    2287       234614 :                 while (schedDetailed->weekScheds[DayNum] == weekSched && DayNum <= 366) {
    2288       234606 :                     if (DayNum == 366) {
    2289          641 :                         General::InvOrdinalDay(DayNum, PMon, PDay, 1);
    2290          641 :                         print(state.files.eio, ThruFmt, Months[PMon - 1], PDay, weekSched->Name);
    2291              :                     }
    2292       234606 :                     ++DayNum;
    2293       234606 :                     if (DayNum > 366) {
    2294          641 :                         break; // compound If might have a problem unless this included.
    2295              :                     }
    2296              :                 }
    2297          649 :                 if (DayNum <= 366) {
    2298            8 :                     General::InvOrdinalDay(DayNum - 1, PMon, PDay, 1);
    2299            8 :                     print(state.files.eio, ThruFmt, Months[PMon - 1], PDay, weekSched->Name);
    2300              :                 }
    2301              :             }
    2302          641 :             print(state.files.eio, "\n");
    2303           23 :         }
    2304              : 
    2305           23 :     } // ReportScheduleDetails()
    2306              : 
    2307            0 :     Real64 GetCurrentScheduleValue(EnergyPlusData const &state, int const schedNum)
    2308              :     {
    2309              :         // Wrapper for method
    2310            0 :         return state.dataSched->schedules[schedNum]->getCurrentVal();
    2311              :     }
    2312              : 
    2313      5697462 :     void UpdateScheduleVals(EnergyPlusData &state)
    2314              :     {
    2315              :         // SUBROUTINE INFORMATION:
    2316              :         //       AUTHOR         Linda Lawrie
    2317              :         //       DATE WRITTEN   August 2011; adapted from Autodesk (time reduction)
    2318              : 
    2319              :         // PURPOSE OF THIS SUBROUTINE:
    2320              :         // This routine calculates all the scheduled values as a time reduction measure and
    2321              :         // stores them in the CurrentValue item of the schedule data structure.
    2322              : 
    2323              :         // METHODOLOGY EMPLOYED:
    2324              :         // Use internal Schedule data structure to calculate current value.  Note that missing values in
    2325              : 
    2326      5697462 :         auto const &s_sched = state.dataSched;
    2327      5697462 :         auto const &s_glob = state.dataGlobal;
    2328              : 
    2329    145662997 :         for (auto *sched : s_sched->schedules) {
    2330    139965535 :             if (sched->EMSActuatedOn) {
    2331       182271 :                 sched->currentVal = sched->EMSVal;
    2332              :             } else {
    2333    139783264 :                 sched->currentVal = sched->getHrTsVal(state, s_glob->HourOfDay, s_glob->TimeStep);
    2334              :             }
    2335      5697462 :         }
    2336      5697462 :     }
    2337              : 
    2338    130782663 :     Real64 ScheduleDetailed::getHrTsVal(EnergyPlusData &state,
    2339              :                                         int hr,
    2340              :                                         int ts // Negative => unspecified
    2341              :     ) const
    2342              :     {
    2343              :         // FUNCTION INFORMATION:
    2344              :         //       AUTHOR         Linda K. Lawrie
    2345              :         //       DATE WRITTEN   January 2003
    2346              :         // PURPOSE OF THIS FUNCTION:
    2347              :         // This function provides a method to look up schedule values for any hour, timestep, day
    2348              :         // of the year (rather than just the "current time").
    2349    130782663 :         auto const &s_glob = state.dataGlobal;
    2350              : 
    2351    130782663 :         if (this->EMSActuatedOn) {
    2352            0 :             return this->EMSVal;
    2353              :         }
    2354              : 
    2355              :         //  so, current date, but maybe TimeStep added
    2356              : 
    2357              :         // Hourly Value
    2358    130782663 :         if (hr > Constant::iHoursInDay) {
    2359            0 :             ShowFatalError(state, format("LookUpScheduleValue called with thisHour={}", hr));
    2360              :         }
    2361              : 
    2362    130782663 :         int thisHr = hr + state.dataEnvrn->DSTIndicator * this->UseDaylightSaving;
    2363              : 
    2364    130782663 :         int thisDayOfYear = state.dataEnvrn->DayOfYear_Schedule;
    2365    130782663 :         int thisDayOfWeek = state.dataEnvrn->DayOfWeek;
    2366    130782663 :         int thisHolidayNum = state.dataEnvrn->HolidayIndex;
    2367    130782663 :         if (thisHr > Constant::iHoursInDay) { // In case HourOfDay is 24 and DSTIndicator is 1, you're actually the next day
    2368        51146 :             thisDayOfYear += 1;
    2369        51146 :             thisHr -= Constant::iHoursInDay;
    2370        51146 :             thisDayOfWeek = state.dataEnvrn->DayOfWeekTomorrow;
    2371        51146 :             thisHolidayNum = state.dataEnvrn->HolidayIndexTomorrow;
    2372              :         }
    2373              : 
    2374              :         // In the case where DST is applied on 12/31 at 24:00, which is the case for a Southern Hemisphere location for eg
    2375              :         // (DayOfYear_Schedule is a bit weird, ScheduleManager always assumes LeapYear)
    2376    130782663 :         if (thisDayOfYear == 367) {
    2377            0 :             thisDayOfYear = 1;
    2378              :         }
    2379              : 
    2380    130782663 :         auto const *weekSched = this->weekScheds[thisDayOfYear];
    2381    130782663 :         auto const *daySched = (thisHolidayNum > 0) ? weekSched->dayScheds[thisHolidayNum] : weekSched->dayScheds[thisDayOfWeek];
    2382    130782663 :         if (daySched == nullptr) {
    2383              :             // We already warned in ProcessScheduleInput that there were missing days: Missing day types will have 0.0 as Schedule Values
    2384            0 :             return 0.0;
    2385              :         }
    2386              : 
    2387              :         // If Unspecified or equal to zero, use NumOfTimeStepInHour, otherwise use supplied
    2388    130782663 :         if (ts <= 0) {
    2389      1157613 :             ts = s_glob->TimeStepsInHour;
    2390              :         }
    2391              : 
    2392    130782663 :         return daySched->tsVals[(thisHr - 1) * s_glob->TimeStepsInHour + (ts - 1)];
    2393              :     } // ScheduleDetailed::getHrTsVal()
    2394              : 
    2395     13027261 :     Real64 ScheduleConstant::getHrTsVal([[maybe_unused]] EnergyPlusData &state, [[maybe_unused]] int hr, [[maybe_unused]] int ts) const
    2396              :     {
    2397              :         // cf #10962 - We can't use currentValue as it could be overwritten by the EMS Sensor
    2398     13027261 :         return this->tsVals.front();
    2399              :     } // ScheduleConstant::getHrTsVal()
    2400              : 
    2401        22564 :     Sched::Schedule *GetScheduleAlwaysOn(EnergyPlusData &state)
    2402              :     {
    2403        22564 :         return state.dataSched->schedules[SchedNum_AlwaysOn];
    2404              :     }
    2405              : 
    2406           16 :     Sched::Schedule *GetScheduleAlwaysOff(EnergyPlusData &state)
    2407              :     {
    2408           16 :         return state.dataSched->schedules[SchedNum_AlwaysOff];
    2409              :     }
    2410              : 
    2411       128643 :     Sched::Schedule *GetSchedule(EnergyPlusData &state, std::string const &name)
    2412              :     {
    2413              :         // FUNCTION INFORMATION:
    2414              :         //       AUTHOR         Linda K. Lawrie
    2415              :         //       DATE WRITTEN   September 1997
    2416              : 
    2417              :         // PURPOSE OF THIS FUNCTION:
    2418              :         // This function returns the internal pointer to Schedule "ScheduleName".
    2419       128643 :         auto const &s_sched = state.dataSched;
    2420              : 
    2421       128643 :         auto found = s_sched->scheduleMap.find(name);
    2422       128643 :         if (found == s_sched->scheduleMap.end()) {
    2423        57458 :             return nullptr;
    2424              :         }
    2425              : 
    2426        71185 :         int schedNum = found->second;
    2427              : 
    2428        71185 :         auto *sched = s_sched->schedules[schedNum];
    2429              : 
    2430        71185 :         if (!sched->isUsed) {
    2431        16379 :             sched->isUsed = true;
    2432              : 
    2433        16379 :             if (sched->type != SchedType::Constant) {
    2434              : 
    2435        16163 :                 auto *schedDetailed = dynamic_cast<ScheduleDetailed *>(sched);
    2436        16163 :                 assert(schedDetailed != nullptr);
    2437              : 
    2438        16163 :                 schedDetailed->isUsed = true;
    2439      5931821 :                 for (int iWeek = 1; iWeek <= 366; ++iWeek) {
    2440      5915658 :                     if (auto *weekSched = schedDetailed->weekScheds[iWeek]; weekSched != nullptr) {
    2441      5915658 :                         if (weekSched->isUsed) {
    2442      5867113 :                             continue;
    2443              :                         }
    2444              : 
    2445        48545 :                         weekSched->isUsed = true;
    2446       631085 :                         for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    2447       582540 :                             auto *daySched = weekSched->dayScheds[iDayType];
    2448       582540 :                             daySched->isUsed = true;
    2449              :                         }
    2450              :                     }
    2451              :                 }
    2452              :             }
    2453              :         }
    2454        71185 :         return sched;
    2455       128643 :     } // GetSchedule()
    2456              : 
    2457            2 :     int GetScheduleNum(EnergyPlusData &state, std::string const &name)
    2458              :     {
    2459            2 :         auto *sched = GetSchedule(state, name);
    2460            2 :         return (sched == nullptr) ? -1 : sched->Num;
    2461              :     }
    2462              : 
    2463          406 :     Sched::WeekSchedule *GetWeekSchedule(EnergyPlusData &state, std::string const &name)
    2464              :     {
    2465          406 :         auto const &s_sched = state.dataSched;
    2466              : 
    2467          406 :         auto found = s_sched->weekScheduleMap.find(name);
    2468          406 :         if (found == s_sched->weekScheduleMap.end()) {
    2469            0 :             return nullptr;
    2470              :         }
    2471              : 
    2472          406 :         int weekSchedNum = found->second;
    2473              : 
    2474          406 :         auto *weekSched = s_sched->weekSchedules[weekSchedNum];
    2475              : 
    2476          406 :         if (!weekSched->isUsed) {
    2477          399 :             weekSched->isUsed = true;
    2478         5187 :             for (int iDayType = 1; iDayType < (int)DayType::Num; ++iDayType) {
    2479         4788 :                 auto *daySched = weekSched->dayScheds[iDayType];
    2480         4788 :                 if (daySched == nullptr) {
    2481            0 :                     continue;
    2482              :                 }
    2483         4788 :                 daySched->isUsed = true;
    2484              :             }
    2485              :         }
    2486          406 :         return weekSched;
    2487          406 :     } // GetWeekSchedule()
    2488              : 
    2489            0 :     int GetWeekScheduleNum(EnergyPlusData &state, std::string const &name)
    2490              :     {
    2491            0 :         auto *weekSched = GetWeekSchedule(state, name);
    2492            0 :         return (weekSched == nullptr) ? -1 : weekSched->Num;
    2493              :     }
    2494              : 
    2495         4271 :     Sched::DaySchedule *GetDaySchedule(EnergyPlusData &state, std::string const &name)
    2496              :     {
    2497              :         // FUNCTION INFORMATION:
    2498              :         //       AUTHOR         Linda K. Lawrie
    2499              :         //       DATE WRITTEN   September 1997
    2500              : 
    2501              :         // PURPOSE OF THIS FUNCTION:
    2502              :         // This function returns the internal pointer to Schedule "ScheduleName".
    2503         4271 :         auto const &s_sched = state.dataSched;
    2504              : 
    2505         4271 :         auto found = s_sched->dayScheduleMap.find(name);
    2506         4271 :         if (found == s_sched->dayScheduleMap.end()) {
    2507            0 :             return nullptr;
    2508              :         }
    2509              : 
    2510         4271 :         int daySchedNum = found->second;
    2511              : 
    2512         4271 :         auto *daySched = s_sched->daySchedules[daySchedNum];
    2513              : 
    2514         4271 :         daySched->isUsed = true;
    2515              : 
    2516         4271 :         return daySched;
    2517         4271 :     } // GetDaySchedule()
    2518              : 
    2519            0 :     int GetDayScheduleNum(EnergyPlusData &state, std::string const &name)
    2520              :     {
    2521            0 :         auto *daySched = GetDaySchedule(state, name);
    2522            0 :         return (daySched == nullptr) ? -1 : daySched->Num;
    2523              :     }
    2524              : 
    2525          452 :     void ScheduleConstant::setMinMaxVals([[maybe_unused]] EnergyPlusData &state)
    2526              :     {
    2527          452 :         assert(!isMinMaxSet);
    2528          452 :         minVal = maxVal = currentVal;
    2529          452 :         isMinMaxSet = true;
    2530          452 :     }
    2531              : 
    2532            0 :     std::vector<Real64> const &ScheduleConstant::getDayVals(EnergyPlusData &state, [[maybe_unused]] int jDay, [[maybe_unused]] int dayofWeek)
    2533              :     {
    2534            0 :         assert((int)tsVals.size() == Constant::iHoursInDay * state.dataGlobal->TimeStepsInHour);
    2535            0 :         return this->tsVals;
    2536              :     } // ScheduleConstant::getDayVals()
    2537              : 
    2538        33269 :     std::vector<Real64> const &ScheduleDetailed::getDayVals(EnergyPlusData &state, int jDay, int dayOfWeek)
    2539              :     {
    2540              :         // PURPOSE OF THIS SUBROUTINE:
    2541              :         // This subroutine returns an entire day's worth of schedule values.
    2542        33269 :         auto const &s_env = state.dataEnvrn;
    2543              : 
    2544              :         // Determine which Week Schedule is used
    2545        33269 :         auto const *weekSched = this->weekScheds[(jDay == -1) ? state.dataEnvrn->DayOfYear_Schedule : jDay];
    2546              : 
    2547        33269 :         DaySchedule *daySched = nullptr;
    2548              :         // Now, which day?
    2549        33269 :         if (dayOfWeek == -1) {
    2550        28227 :             daySched = weekSched->dayScheds[(s_env->HolidayIndex > 0) ? s_env->HolidayIndex : s_env->DayOfWeek];
    2551         5042 :         } else if (dayOfWeek <= 7 && s_env->HolidayIndex > 0) {
    2552         5042 :             daySched = weekSched->dayScheds[s_env->HolidayIndex];
    2553              :         } else {
    2554            0 :             daySched = weekSched->dayScheds[dayOfWeek];
    2555              :         }
    2556              : 
    2557        33269 :         return daySched->getDayVals(state);
    2558              :     } // ScheduleDetailed::getDayVals()
    2559              : 
    2560        73538 :     void ExternalInterfaceSetSchedule(EnergyPlusData &state,
    2561              :                                       int schedNum,
    2562              :                                       Real64 value // The new value for the schedule
    2563              :     )
    2564              :     {
    2565              :         // FUNCTION INFORMATION:
    2566              :         //       AUTHOR         Michael Wetter
    2567              :         //       DATE WRITTEN   February 2010
    2568              : 
    2569              :         // PURPOSE OF THIS SUBROUTINE:
    2570              :         // This subroutine sets all values of the schedule referenced by 'ScheduleIndex'
    2571              :         // to the value specified by 'Value'. The subroutine is used by the ExternalInterface to
    2572              :         // write real-time data into a schedule so that EnergyPlus modules can use
    2573              :         // real-time data by referencing a schedule. This allows overwriting setpoint
    2574              :         // for supervisory controls or internal gains obtained from real-time occupancy
    2575              :         // measurements.
    2576        73538 :         auto const &s_glob = state.dataGlobal;
    2577        73538 :         auto const &s_sched = state.dataSched;
    2578        73538 :         auto *daySched = s_sched->daySchedules[schedNum];
    2579              : 
    2580      1838450 :         for (int hr = 0; hr < Constant::iHoursInDay; ++hr) {
    2581      8824560 :             for (int ts = 0; ts < s_glob->TimeStepsInHour; ++ts) {
    2582      7059648 :                 daySched->tsVals[hr * s_glob->TimeStepsInHour + ts] = value;
    2583              :             }
    2584              :         }
    2585        73538 :     } // ExternalInterfaceSetSchedule()
    2586              : 
    2587        35222 :     void ProcessIntervalFields(EnergyPlusData &state,
    2588              :                                Array1S_string const Untils,
    2589              :                                Array1S<Real64> const Numbers,
    2590              :                                int const NumUntils,
    2591              :                                int const NumNumbers,
    2592              :                                std::array<Real64, Constant::iMinutesInDay> &minuteVals,
    2593              :                                std::array<bool, Constant::iMinutesInDay> &setMinuteVals,
    2594              :                                bool &ErrorsFound,
    2595              :                                std::string const &DayScheduleName, // Name (used for errors)
    2596              :                                std::string const &ErrContext,      // Context (used for errors)
    2597              :                                Interpolation interpolation         // enumeration on how to interpolate values in schedule
    2598              :     )
    2599              :     {
    2600              :         // SUBROUTINE INFORMATION:
    2601              :         //       AUTHOR         <author>
    2602              :         //       DATE WRITTEN   <date_written>
    2603              : 
    2604              :         // PURPOSE OF THIS SUBROUTINE:
    2605              :         // This subroutine processes the "interval" fields with/without optional "until" in front of
    2606              :         // time (hh:mm).
    2607              : 
    2608              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2609              :         int HHField;
    2610              :         int MMField;
    2611              : 
    2612        35222 :         int begHr = 0;   // starting hour
    2613        35222 :         int begMin = 0;  // starting minute
    2614        35222 :         int endHr = -1;  // ending hour
    2615        35222 :         int endMin = -1; // ending minute
    2616              :         std::string::size_type sFld;
    2617              : 
    2618              :         int totalMinutes;
    2619              :         Real64 incrementPerMinute;
    2620              :         Real64 curValue;
    2621              : 
    2622        35222 :         std::fill(minuteVals.begin(), minuteVals.end(), 0.0);
    2623        35222 :         std::fill(setMinuteVals.begin(), setMinuteVals.end(), false);
    2624              : 
    2625        35222 :         sFld = 0;
    2626              : 
    2627        35222 :         Real64 StartValue = 0;
    2628        35222 :         Real64 EndValue = 0;
    2629              : 
    2630        35222 :         if (NumUntils != NumNumbers) {
    2631            0 :             ShowSevereError(state,
    2632            0 :                             format("ProcessScheduleInput: ProcessIntervalFields, number of Time fields does not match number of value fields, {}={}",
    2633              :                                    ErrContext,
    2634              :                                    DayScheduleName));
    2635            0 :             ErrorsFound = true;
    2636            0 :             return;
    2637              :         }
    2638              : 
    2639       120361 :         for (int Count = 1; Count <= NumUntils; ++Count) {
    2640        85139 :             std::string const &until = Untils(Count);
    2641        85139 :             int Pos = index(until, "UNTIL");
    2642        85139 :             if (Pos == 0) {
    2643        80378 :                 if (until[5] == ':') {
    2644        80356 :                     sFld = 6;
    2645              :                 } else {
    2646           22 :                     sFld = 5;
    2647              :                 }
    2648        80378 :                 DecodeHHMMField(state, until.substr(sFld), HHField, MMField, ErrorsFound, DayScheduleName, until, interpolation);
    2649         4761 :             } else if (Pos == (int)std::string::npos) {
    2650         4761 :                 DecodeHHMMField(state, until, HHField, MMField, ErrorsFound, DayScheduleName, until, interpolation);
    2651              :             } else { // Until found but wasn't first field
    2652            0 :                 ShowSevereError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", until));
    2653            0 :                 ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
    2654            0 :                 ErrorsFound = true;
    2655            0 :                 continue;
    2656              :             }
    2657              :             // Field decoded
    2658        85139 :             if (HHField < 0 || HHField > Constant::iHoursInDay || MMField < 0 || MMField > Constant::iMinutesInHour) {
    2659            0 :                 ShowSevereError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", until));
    2660            0 :                 ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
    2661            0 :                 ErrorsFound = true;
    2662            0 :                 continue;
    2663              :             }
    2664        85139 :             if (HHField == Constant::iHoursInDay && MMField > 0 && MMField < Constant::iMinutesInHour) {
    2665            0 :                 ShowWarningError(state, format("ProcessScheduleInput: ProcessIntervalFields, Invalid \"Until\" field encountered={}", Untils(Count)));
    2666            0 :                 ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
    2667            0 :                 ShowContinueError(state, "Terminating the field at 24:00");
    2668            0 :                 MMField = 0;
    2669              :             }
    2670              : 
    2671              :             // Fill in values
    2672        85139 :             if (MMField == 0) {
    2673        84295 :                 endHr = HHField - 1;
    2674        84295 :                 endMin = Constant::iMinutesInHour - 1;
    2675          844 :             } else if (MMField < Constant::iMinutesInHour) {
    2676          844 :                 endHr = HHField;
    2677          844 :                 endMin = MMField - 1;
    2678              :             }
    2679              : 
    2680        85139 :             if (interpolation == Interpolation::Linear) {
    2681            0 :                 totalMinutes = (endHr - begHr) * Constant::iMinutesInHour + (endMin - begMin) + 1;
    2682            0 :                 if (totalMinutes == 0) {
    2683            0 :                     totalMinutes = 1; // protect future division
    2684              :                 }
    2685            0 :                 if (Count == 1) {
    2686            0 :                     StartValue = Numbers(Count); // assume first period is flat
    2687            0 :                     EndValue = Numbers(Count);
    2688              :                 } else {
    2689            0 :                     StartValue = EndValue;
    2690            0 :                     EndValue = Numbers(Count);
    2691              :                 }
    2692            0 :                 incrementPerMinute = (EndValue - StartValue) / totalMinutes;
    2693            0 :                 curValue = StartValue + incrementPerMinute;
    2694              :             }
    2695              : 
    2696        85139 :             if (begHr > endHr) {
    2697            8 :                 if (begHr == endHr + 1 && begMin == 0 && endMin == Constant::iMinutesInHour - 1) {
    2698           16 :                     ShowWarningError(state,
    2699           16 :                                      format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, zero time interval detected, {}={}",
    2700              :                                             ErrContext,
    2701              :                                             DayScheduleName));
    2702              :                 } else {
    2703            0 :                     ShowSevereError(state,
    2704            0 :                                     format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, overlapping times detected, {}={}",
    2705              :                                            ErrContext,
    2706              :                                            DayScheduleName));
    2707            0 :                     ErrorsFound = true;
    2708              :                 }
    2709              : 
    2710        85131 :             } else if (begHr == endHr) {
    2711      1546603 :                 for (int iMin = begMin; iMin <= endMin; ++iMin) {
    2712      1520728 :                     if (setMinuteVals[begHr * Constant::iMinutesInHour + iMin] == true) {
    2713            0 :                         ShowSevereError(
    2714              :                             state,
    2715            0 :                             format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, overlapping times detected, {}={}",
    2716              :                                    ErrContext,
    2717              :                                    DayScheduleName));
    2718            0 :                         ErrorsFound = true;
    2719            0 :                         goto UntilLoop_exit;
    2720              :                     }
    2721              :                 }
    2722              : 
    2723        25875 :                 if (interpolation == Interpolation::Linear) {
    2724            0 :                     for (int iMin = begMin; iMin <= endMin; ++iMin) {
    2725            0 :                         minuteVals[begHr * Constant::iMinutesInHour + iMin] = curValue;
    2726            0 :                         curValue += incrementPerMinute;
    2727            0 :                         setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
    2728              :                     }
    2729              :                 } else {
    2730      1546603 :                     for (int iMin = begMin; iMin <= endMin; ++iMin) {
    2731      1520728 :                         minuteVals[begHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
    2732      1520728 :                         setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
    2733              :                     }
    2734              :                 }
    2735              : 
    2736        25875 :                 begMin = endMin + 1;
    2737        25875 :                 if (begMin >= Constant::iMinutesInHour) {
    2738        25183 :                     ++begHr;
    2739        25183 :                     begMin = 0;
    2740              :                 }
    2741              : 
    2742              :             } else { // begHr < endHr
    2743        59256 :                 if (interpolation == Interpolation::Linear) {
    2744            0 :                     for (int iMin = begMin; iMin <= Constant::iMinutesInHour - 1; ++iMin) { // for portion of starting hour
    2745            0 :                         minuteVals[begHr * Constant::iMinutesInHour + iMin] = curValue;
    2746            0 :                         curValue += incrementPerMinute;
    2747            0 :                         setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
    2748              :                     }
    2749              : 
    2750            0 :                     for (int iHr = begHr + 1; iHr <= endHr - 1; ++iHr) { // for intermediate hours
    2751            0 :                         for (int iMin = 0; iMin <= Constant::iMinutesInHour - 1; ++iMin) {
    2752            0 :                             minuteVals[iHr * Constant::iMinutesInHour + iMin] = curValue;
    2753            0 :                             curValue += incrementPerMinute;
    2754            0 :                             setMinuteVals[iHr * Constant::iMinutesInHour + iMin] = true;
    2755              :                         }
    2756              :                     }
    2757              : 
    2758            0 :                     for (int iMin = 0; iMin <= endMin; ++iMin) { // for ending hour
    2759            0 :                         minuteVals[endHr * Constant::iMinutesInHour + iMin] = curValue;
    2760            0 :                         curValue += incrementPerMinute;
    2761            0 :                         setMinuteVals[endHr * Constant::iMinutesInHour + iMin] = true;
    2762              :                     }
    2763              : 
    2764              :                 } else { // either no interpolation or "average" interpolation (average just is when the interval does not match the timestep)
    2765              :                          // Fill values for first hour (which may not start at minute 0)
    2766              :                          // For std::fill the end marker has to be 1 past the last position you want to fill
    2767      3659890 :                     for (int iMin = begMin; iMin <= Constant::iMinutesInHour; ++iMin) {
    2768      3600634 :                         minuteVals[begHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
    2769      3600634 :                         setMinuteVals[begHr * Constant::iMinutesInHour + iMin] = true;
    2770              :                     }
    2771              : 
    2772              :                     // Fill values for middle hours (which start at minute 0 and end in minute 59)
    2773        59256 :                     if ((begHr + 1) <= (endHr - 1)) {
    2774       756171 :                         for (int iHr = begHr + 1; iHr <= endHr - 1; ++iHr) {
    2775     42808885 :                             for (int iMin = 0; iMin <= Constant::iMinutesInHour - 1; ++iMin) {
    2776     42107100 :                                 minuteVals[iHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
    2777     42107100 :                                 setMinuteVals[iHr * Constant::iMinutesInHour + iMin] = true;
    2778              :                             }
    2779              :                         }
    2780              :                     }
    2781              : 
    2782              :                     // Fill values for last hour (which starts at minute 0 but may end on minute that isn't 59)
    2783      3609730 :                     for (int iMin = 0; iMin <= endMin; ++iMin) {
    2784      3550474 :                         minuteVals[endHr * Constant::iMinutesInHour + iMin] = Numbers(Count);
    2785      3550474 :                         setMinuteVals[endHr * Constant::iMinutesInHour + iMin] = true;
    2786              :                     }
    2787              :                 }
    2788              : 
    2789        59256 :                 begHr = endHr;
    2790        59256 :                 begMin = endMin + 1;
    2791        59256 :                 if (begMin >= Constant::iMinutesInHour) {
    2792        59104 :                     ++begHr;
    2793        59104 :                     begMin = 0;
    2794              :                 }
    2795              :             }
    2796              :         }
    2797        35222 :     UntilLoop_exit:;
    2798              : 
    2799     50754902 :         for (int iMin = 0; iMin < Constant::iMinutesInDay; ++iMin) {
    2800     50719680 :             if (setMinuteVals[iMin] == false) {
    2801            0 :                 ShowSevereError(state,
    2802            0 :                                 format("ProcessScheduleInput: ProcessIntervalFields, Processing time fields, incomplete day detected, {}={}",
    2803              :                                        ErrContext,
    2804              :                                        DayScheduleName));
    2805            0 :                 ErrorsFound = true;
    2806              :             }
    2807              :         }
    2808              :     }
    2809              : 
    2810        85139 :     void DecodeHHMMField(EnergyPlusData &state,
    2811              :                          std::string const &FieldValue,      // Input field value
    2812              :                          int &RetHH,                         // Returned "hour"
    2813              :                          int &RetMM,                         // Returned "minute"
    2814              :                          bool &ErrorsFound,                  // True if errors found in this field
    2815              :                          std::string const &DayScheduleName, // originating day schedule name
    2816              :                          std::string const &FullFieldValue,  // Full Input field value
    2817              :                          Interpolation interpolation         // enumeration on how to interpolate values in schedule
    2818              :     )
    2819              :     {
    2820              :         // SUBROUTINE INFORMATION:
    2821              :         //       AUTHOR         Linda K Lawrie
    2822              :         //       DATE WRITTEN   January 2003
    2823              : 
    2824              :         // PURPOSE OF THIS SUBROUTINE:
    2825              : 
    2826              :         // This subroutine decodes a hhmm date field input as part of the "until" time in a schedule
    2827              :         // representation.
    2828              : 
    2829              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2830              :         Real64 rRetHH; // real Returned "hour"
    2831        85139 :         std::string hHour;
    2832        85139 :         std::string mMinute;
    2833              : 
    2834        85139 :         std::string String = stripped(FieldValue);
    2835        85139 :         std::string::size_type const Pos = index(String, ':');
    2836        85139 :         bool nonIntegral = false;
    2837              : 
    2838        85139 :         auto const &s_glob = state.dataGlobal;
    2839        85139 :         if (Pos == std::string::npos) {
    2840            0 :             ShowSevereError(state,
    2841            0 :                             format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (no : separator in hh:mm)={}",
    2842            0 :                                    stripped(FullFieldValue)));
    2843            0 :             ShowContinueError(state, format("Occurred in Day Schedule={}", DayScheduleName));
    2844            0 :             ErrorsFound = true;
    2845            0 :             return;
    2846        85139 :         } else if (Pos == 0) {
    2847            0 :             RetHH = 0;
    2848              :         } else {
    2849        85139 :             bool error = false;
    2850        85139 :             Real64 rRetHH = Util::ProcessNumber(String.substr(0, Pos), error);
    2851        85139 :             RetHH = int(rRetHH);
    2852        85139 :             if (double(RetHH) != rRetHH || error || rRetHH < 0.0) {
    2853            0 :                 if (double(RetHH) != rRetHH && rRetHH >= 0.0) {
    2854            0 :                     ShowWarningError(state,
    2855            0 :                                      format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (non-integer numeric in HH)={}",
    2856            0 :                                             stripped(FullFieldValue)));
    2857            0 :                     ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
    2858            0 :                     nonIntegral = true;
    2859              :                 } else {
    2860            0 :                     ShowSevereError(state,
    2861            0 :                                     format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (invalid numeric in HH)={}",
    2862            0 :                                            stripped(FullFieldValue)));
    2863            0 :                     ShowContinueError(
    2864            0 :                         state, format("Field values must be integer and represent hours:minutes. Occurred in Day Schedule={}", DayScheduleName));
    2865            0 :                     ErrorsFound = true;
    2866            0 :                     return;
    2867              :                 }
    2868              :             }
    2869              :         }
    2870              : 
    2871        85139 :         String.erase(0, Pos + 1);
    2872        85139 :         bool error = false;
    2873        85139 :         Real64 rRetMM = Util::ProcessNumber(String, error);
    2874        85139 :         RetMM = int(rRetMM);
    2875        85139 :         if (double(RetMM) != rRetMM || error || rRetMM < 0.0) {
    2876            0 :             if (double(RetMM) != rRetMM && rRetMM >= 0.0) {
    2877            0 :                 ShowWarningError(state,
    2878            0 :                                  format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (non-integer numeric in MM)={}",
    2879            0 :                                         stripped(FullFieldValue)));
    2880            0 :                 ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
    2881            0 :                 nonIntegral = true;
    2882              :             } else {
    2883            0 :                 ShowSevereError(state,
    2884            0 :                                 format("ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field submitted (invalid numeric in MM)={}",
    2885            0 :                                        stripped(FullFieldValue)));
    2886            0 :                 ShowContinueError(state,
    2887            0 :                                   format("Field values must be integer and represent hours:minutes. Occurred in Day Schedule={}", DayScheduleName));
    2888            0 :                 ErrorsFound = true;
    2889            0 :                 return;
    2890              :             }
    2891              :         }
    2892              : 
    2893        85139 :         if (nonIntegral) {
    2894            0 :             std::string hHour; // these haven't been initialized?
    2895            0 :             std::string mMinute;
    2896            0 :             ShowContinueError(state, format("Until value to be used will be: {:2.2F}:{:2.2F}", hHour, mMinute));
    2897            0 :         }
    2898        85139 :         if (interpolation == Interpolation::No) {
    2899        83817 :             if (!isMinuteMultipleOfTimestep(RetMM, s_glob->MinutesInTimeStep)) {
    2900           82 :                 ShowWarningError(
    2901              :                     state,
    2902           82 :                     format(
    2903              :                         "ProcessScheduleInput: DecodeHHMMField, Invalid \"until\" field value is not a multiple of the minutes for each timestep: {}",
    2904           82 :                         stripped(FullFieldValue)));
    2905           41 :                 ShowContinueError(state, format("Other errors may result. Occurred in Day Schedule={}", DayScheduleName));
    2906              :             }
    2907              :         }
    2908        85139 :     }
    2909              : 
    2910        83817 :     bool isMinuteMultipleOfTimestep(int minute, int numMinutesPerTimestep)
    2911              :     {
    2912        83817 :         if (minute != 0) {
    2913          252 :             return (minute % numMinutesPerTimestep == 0);
    2914              :         } else {
    2915        83565 :             return true;
    2916              :         }
    2917              :     }
    2918              : 
    2919        34957 :     void ProcessForDayTypes(EnergyPlusData &state,
    2920              :                             std::string const &ForDayField,               // Field containing the "FOR:..."
    2921              :                             std::array<bool, (int)DayType::Num> &these,   // Array to contain returned "true" days
    2922              :                             std::array<bool, (int)DayType::Num> &already, // Array of days already done
    2923              :                             bool &ErrorsFound                             // Will be true if error found.
    2924              :     )
    2925              :     {
    2926              :         // SUBROUTINE INFORMATION:
    2927              :         //       AUTHOR         Linda K. Lawrie
    2928              :         //       DATE WRITTEN   February 2003
    2929              : 
    2930              :         // PURPOSE OF THIS SUBROUTINE:
    2931              :         // This subroutine processes a field "For: day types" and returns
    2932              :         // those day types (can be multiple) from field.
    2933              :         // Argument array dimensioning
    2934              : 
    2935              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2936        34957 :         bool OneValid = false;
    2937        34957 :         bool DupAssignment = false;
    2938              : 
    2939              :         // Just test for specific days
    2940        34957 :         if (has(ForDayField, "WEEKDAY")) {
    2941         4910 :             these[iDayType_Mon] = these[iDayType_Tue] = these[iDayType_Wed] = these[iDayType_Thu] = these[iDayType_Fri] = true;
    2942         4910 :             if (already[iDayType_Mon] || already[iDayType_Tue] || already[iDayType_Wed] || already[iDayType_Thu] || already[iDayType_Fri]) {
    2943            0 :                 DupAssignment = true;
    2944              :             }
    2945         4910 :             already[iDayType_Mon] = already[iDayType_Tue] = already[iDayType_Wed] = already[iDayType_Thu] = already[iDayType_Fri] = true;
    2946         4910 :             OneValid = true;
    2947              :         }
    2948        34957 :         if (has(ForDayField, "MONDAY")) { // Should this be an else-if
    2949          106 :             these[iDayType_Mon] = true;
    2950          106 :             if (already[iDayType_Mon]) {
    2951            0 :                 DupAssignment = true;
    2952              :             } else {
    2953          106 :                 already[iDayType_Mon] = true;
    2954              :             }
    2955          106 :             OneValid = true;
    2956              :         }
    2957        34957 :         if (has(ForDayField, "TUESDAY")) {
    2958          144 :             these[iDayType_Tue] = true;
    2959          144 :             if (already[iDayType_Tue]) {
    2960            0 :                 DupAssignment = true;
    2961              :             } else {
    2962          144 :                 already[iDayType_Tue] = true;
    2963              :             }
    2964          144 :             OneValid = true;
    2965              :         }
    2966        34957 :         if (has(ForDayField, "WEDNESDAY")) {
    2967           88 :             these[iDayType_Wed] = true;
    2968           88 :             if (already[iDayType_Wed]) {
    2969            0 :                 DupAssignment = true;
    2970              :             } else {
    2971           88 :                 already[iDayType_Wed] = true;
    2972              :             }
    2973           88 :             OneValid = true;
    2974              :         }
    2975        34957 :         if (has(ForDayField, "THURSDAY")) {
    2976           88 :             these[iDayType_Thu] = true;
    2977           88 :             if (already[iDayType_Thu]) {
    2978            0 :                 DupAssignment = true;
    2979              :             } else {
    2980           88 :                 already[iDayType_Thu] = true;
    2981              :             }
    2982           88 :             OneValid = true;
    2983              :         }
    2984        34957 :         if (has(ForDayField, "FRIDAY")) {
    2985          126 :             these[iDayType_Fri] = true;
    2986          126 :             if (already[iDayType_Fri]) {
    2987            0 :                 DupAssignment = true;
    2988              :             } else {
    2989          126 :                 already[iDayType_Fri] = true;
    2990              :             }
    2991          126 :             OneValid = true;
    2992              :         }
    2993        34957 :         if (has(ForDayField, "WEEKEND")) {
    2994         2077 :             these[iDayType_Sun] = these[iDayType_Sat] = true;
    2995         2077 :             if (already[iDayType_Sun] || already[iDayType_Sat]) {
    2996            0 :                 DupAssignment = true;
    2997              :             }
    2998         2077 :             already[iDayType_Sun] = already[iDayType_Sat] = true;
    2999         2077 :             OneValid = true;
    3000              :         }
    3001              : 
    3002        34957 :         if (has(ForDayField, "SATURDAY")) {
    3003         1715 :             these[iDayType_Sat] = true;
    3004         1715 :             if (already[iDayType_Sat]) {
    3005            0 :                 DupAssignment = true;
    3006              :             } else {
    3007         1715 :                 already[iDayType_Sat] = true;
    3008              :             }
    3009         1715 :             OneValid = true;
    3010              :         }
    3011        34957 :         if (has(ForDayField, "SUNDAY")) {
    3012         1204 :             these[iDayType_Sun] = true;
    3013         1204 :             if (already[iDayType_Sun]) {
    3014            0 :                 DupAssignment = true;
    3015              :             } else {
    3016         1204 :                 already[iDayType_Sun] = true;
    3017              :             }
    3018         1204 :             OneValid = true;
    3019              :         }
    3020        34957 :         if (has(ForDayField, "CUSTOMDAY1")) {
    3021         1786 :             these[iDayType_Cus1] = true;
    3022         1786 :             if (already[iDayType_Cus1]) {
    3023            0 :                 DupAssignment = true;
    3024              :             } else {
    3025         1786 :                 already[iDayType_Cus1] = true;
    3026              :             }
    3027         1786 :             OneValid = true;
    3028              :         }
    3029        34957 :         if (has(ForDayField, "CUSTOMDAY2")) {
    3030         1768 :             these[iDayType_Cus2] = true;
    3031         1768 :             if (already[iDayType_Cus2]) {
    3032            0 :                 DupAssignment = true;
    3033              :             } else {
    3034         1768 :                 already[iDayType_Cus2] = true;
    3035              :             }
    3036         1768 :             OneValid = true;
    3037              :         }
    3038        34957 :         if (has(ForDayField, "ALLDAY")) {
    3039       247730 :             for (int iDay = 0; iDay < (int)DayType::Num; ++iDay) {
    3040       230035 :                 these[iDay] = true;
    3041       230035 :                 if (already[iDay]) {
    3042            0 :                     DupAssignment = true;
    3043              :                 } else {
    3044       230035 :                     already[iDay] = true;
    3045              :                 }
    3046              :             }
    3047        17695 :             OneValid = true;
    3048              :         }
    3049        34957 :         if (has(ForDayField, "HOLIDAY")) {
    3050         3248 :             these[iDayType_Hol] = true;
    3051         3248 :             if (already[iDayType_Hol]) {
    3052            0 :                 DupAssignment = true;
    3053              :             } else {
    3054         3248 :                 already[iDayType_Hol] = true;
    3055              :             }
    3056         3248 :             OneValid = true;
    3057              :         }
    3058        34957 :         if (has(ForDayField, "SUMMER")) {
    3059         4850 :             these[iDayType_SumDes] = true;
    3060         4850 :             if (already[iDayType_SumDes]) {
    3061            0 :                 DupAssignment = true;
    3062              :             } else {
    3063         4850 :                 already[iDayType_SumDes] = true;
    3064              :             }
    3065         4850 :             OneValid = true;
    3066              :         }
    3067        34957 :         if (has(ForDayField, "WINTER")) {
    3068         4562 :             these[iDayType_WinDes] = true;
    3069         4562 :             if (already[iDayType_WinDes]) {
    3070            0 :                 DupAssignment = true;
    3071              :             } else {
    3072         4562 :                 already[iDayType_WinDes] = true;
    3073              :             }
    3074         4562 :             OneValid = true;
    3075              :         }
    3076        34957 :         if (has(ForDayField, "ALLOTHERDAY")) {
    3077        53326 :             for (int iDay = 0; iDay < (int)DayType::Num; ++iDay) {
    3078        49517 :                 if (!already[iDay]) {
    3079        21562 :                     these[iDay] = already[iDay] = true;
    3080              :                 }
    3081              :             }
    3082         3809 :             OneValid = true;
    3083              :         }
    3084              : 
    3085        34957 :         if (DupAssignment) {
    3086            0 :             ShowSevereError(state, format("ProcessForDayTypes: Duplicate assignment attempted in \"for\" days field={}", ForDayField));
    3087            0 :             ErrorsFound = true;
    3088              :         }
    3089        34957 :         if (!OneValid) {
    3090            0 :             ShowSevereError(state, format("ProcessForDayTypes: No valid day assignments found in \"for\" days field={}", ForDayField));
    3091            0 :             ErrorsFound = true;
    3092              :         }
    3093        34957 :     } // ProcessScheduleInput()
    3094              : 
    3095        74051 :     void DaySchedule::setMinMaxVals([[maybe_unused]] EnergyPlusData &state)
    3096              :     {
    3097        74051 :         assert(!this->isMinMaxSet);
    3098              : 
    3099        74051 :         auto const &s_glob = state.dataGlobal;
    3100              : 
    3101        74051 :         this->minVal = this->maxVal = this->tsVals[0];
    3102      8609435 :         for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
    3103      8535384 :             Real64 value = this->tsVals[i];
    3104      8535384 :             if (value < this->minVal) {
    3105        11694 :                 this->minVal = value;
    3106      8523690 :             } else if (value > this->maxVal) {
    3107       257760 :                 this->maxVal = value;
    3108              :             }
    3109              :         }
    3110              : 
    3111        74051 :         this->isMinMaxSet = true;
    3112        74051 :     }
    3113              : 
    3114        62370 :     void WeekSchedule::setMinMaxVals(EnergyPlusData &state)
    3115              :     {
    3116        62370 :         assert(!this->isMinMaxSet);
    3117              : 
    3118        62370 :         auto *daySched1 = this->dayScheds[1];
    3119        62370 :         if (!daySched1->isMinMaxSet) {
    3120        62176 :             daySched1->setMinMaxVals(state);
    3121              :         }
    3122              : 
    3123        62370 :         this->minVal = daySched1->minVal;
    3124        62370 :         this->maxVal = daySched1->maxVal;
    3125              : 
    3126        62370 :         auto *daySchedPrev = daySched1;
    3127       748440 :         for (int iDay = 2; iDay < (int)DayType::Num; ++iDay) {
    3128       686070 :             auto *daySched = this->dayScheds[iDay];
    3129       686070 :             if (daySched == daySchedPrev) {
    3130       661086 :                 continue;
    3131              :             }
    3132              : 
    3133        24984 :             if (!daySched->isMinMaxSet) {
    3134        11861 :                 daySched->setMinMaxVals(state);
    3135              :             }
    3136        24984 :             if (daySched->minVal < this->minVal) {
    3137         1805 :                 this->minVal = daySched->minVal;
    3138              :             }
    3139        24984 :             if (daySched->maxVal > this->maxVal) {
    3140         4525 :                 this->maxVal = daySched->maxVal;
    3141              :             }
    3142        24984 :             daySchedPrev = daySched;
    3143              :         }
    3144              : 
    3145        62370 :         this->isMinMaxSet = true;
    3146        62370 :     } // ScheduleWeek::setMinMaxVals()
    3147              : 
    3148        16085 :     void ScheduleDetailed::setMinMaxVals(EnergyPlusData &state)
    3149              :     {
    3150        16085 :         assert(!this->isMinMaxSet);
    3151              : 
    3152        16085 :         auto *weekSched1 = this->weekScheds[1];
    3153        16085 :         if (!weekSched1->isMinMaxSet) {
    3154        16081 :             weekSched1->setMinMaxVals(state);
    3155              :         }
    3156              : 
    3157        16085 :         this->minVal = weekSched1->minVal;
    3158        16085 :         this->maxVal = weekSched1->maxVal;
    3159              : 
    3160        16085 :         auto *weekSchedPrev = weekSched1;
    3161              : 
    3162      5887110 :         for (int iWeek = 2; iWeek <= 366; ++iWeek) {
    3163      5871025 :             auto *weekSched = this->weekScheds[iWeek];
    3164      5871025 :             if (iWeek == 366 && weekSched == nullptr) {
    3165            0 :                 continue;
    3166              :             }
    3167      5871025 :             if (weekSched == weekSchedPrev) {
    3168      5824733 :                 continue;
    3169              :             }
    3170        46292 :             if (!weekSched->isMinMaxSet) {
    3171        46289 :                 weekSched->setMinMaxVals(state);
    3172              :             }
    3173              : 
    3174        46292 :             if (weekSched->minVal < this->minVal) {
    3175         1141 :                 this->minVal = weekSched->minVal;
    3176              :             }
    3177        46292 :             if (weekSched->maxVal > this->maxVal) {
    3178         2721 :                 this->maxVal = weekSched->maxVal;
    3179              :             }
    3180        46292 :             weekSchedPrev = weekSched;
    3181              :         }
    3182              : 
    3183        16085 :         this->isMinMaxSet = true;
    3184        16085 :     }
    3185              : 
    3186            0 :     bool CheckScheduleValueMin(EnergyPlusData &state,
    3187              :                                int const schedNum, // Which Schedule being tested
    3188              :                                Clusive clu,
    3189              :                                Real64 const min // Minimum desired value
    3190              :     )
    3191              :     {
    3192              :         // FUNCTION INFORMATION:
    3193              :         //       AUTHOR         Linda K. Lawrie
    3194              :         //       DATE WRITTEN   February 2003
    3195              : 
    3196              :         // PURPOSE OF THIS FUNCTION:
    3197              :         // This function checks the indicated schedule values for validity.
    3198              : 
    3199              :         // METHODOLOGY EMPLOYED:
    3200              :         // Schedule data structure stores this on first validity check.  If there, then is returned else
    3201              :         // looks up minimum and maximum values for the schedule and then sets result of function based on
    3202              :         // requested minimum/maximum checks.
    3203              : 
    3204            0 :         return state.dataSched->schedules[schedNum]->checkMinVal(state, clu, min);
    3205              :     }
    3206              : 
    3207        22849 :     bool ScheduleBase::checkMinVal(EnergyPlusData &state, Clusive clu, Real64 min)
    3208              :     {
    3209        22849 :         if (!this->isMinMaxSet) { // Set Minimum/Maximums for this schedule
    3210         1949 :             this->setMinMaxVals(state);
    3211              :         }
    3212              : 
    3213              :         //  Min/max for schedule has been set.  Test.
    3214        22849 :         return (clu == Clusive::In) ? (FLT_EPSILON >= min - this->minVal) : (this->minVal > min);
    3215              :     } // ScheduleDetailed::checkMinVal()
    3216              : 
    3217         2676 :     bool ScheduleBase::checkMaxVal(EnergyPlusData &state, Clusive cluMax, Real64 const max)
    3218              :     {
    3219         2676 :         if (!this->isMinMaxSet) {
    3220            0 :             this->setMinMaxVals(state);
    3221              :         }
    3222              : 
    3223         2676 :         return (cluMax == Clusive::Ex) ? (this->maxVal < max) : (this->maxVal - max <= FLT_EPSILON);
    3224              :     }
    3225              : 
    3226        28134 :     bool ScheduleBase::checkMinMaxVals(EnergyPlusData &state,
    3227              :                                        Clusive cluMin,   // Minimum indicator ('>', '>=')
    3228              :                                        Real64 const min, // Minimum desired value
    3229              :                                        Clusive cluMax,   // Maximum indicator ('<', ',=')
    3230              :                                        Real64 const max) // Maximum desired value
    3231              :     {
    3232              :         // FUNCTION INFORMATION:
    3233              :         //       AUTHOR         Linda K. Lawrie
    3234              :         //       DATE WRITTEN   February 2003
    3235              : 
    3236              :         // PURPOSE OF THIS FUNCTION:
    3237              :         // This function checks the indicated schedule values for validity.
    3238              : 
    3239              :         // METHODOLOGY EMPLOYED:
    3240              :         // Schedule data structure stores this on first validity check.  If there, then is returned else
    3241              :         // looks up minimum and maximum values for the schedule and then sets result of function based on
    3242              :         // requested minimum/maximum checks.
    3243              : 
    3244        28134 :         if (!this->isMinMaxSet) {
    3245        14186 :             this->setMinMaxVals(state);
    3246              :         }
    3247              : 
    3248        28134 :         bool minOk = (cluMin == Clusive::Ex) ? (this->minVal > min) : (FLT_EPSILON >= min - this->minVal);
    3249        28134 :         bool maxOk = (cluMax == Clusive::Ex) ? (this->maxVal < max) : (this->maxVal - max <= FLT_EPSILON);
    3250              : 
    3251        28134 :         return (minOk && maxOk);
    3252              :     } // ScheduleBase::checkMinMaxVals()
    3253              : 
    3254            0 :     bool CheckScheduleValueMinMax(EnergyPlusData &state,
    3255              :                                   int const schedNum, // Which Schedule being tested
    3256              :                                   Clusive cluMin,     // Minimum indicator ('>', '>=')
    3257              :                                   Real64 const min,   // Minimum desired value
    3258              :                                   Clusive cluMax,     // Maximum indicator ('<', ',=')
    3259              :                                   Real64 const max    // Maximum desired value
    3260              :     )
    3261              :     {
    3262              :         // Wrapper for method
    3263            0 :         return state.dataSched->schedules[schedNum]->checkMinMaxVals(state, cluMin, min, cluMax, max);
    3264              :     } // CheckScheduleValueMinMax()
    3265              : 
    3266           59 :     bool ScheduleConstant::hasVal([[maybe_unused]] EnergyPlusData &state, Real64 const value) const
    3267              :     {
    3268           59 :         return value == this->currentVal;
    3269              :     } // ScheduleConstant::hasVal()
    3270              : 
    3271        11769 :     bool ScheduleDetailed::hasVal(EnergyPlusData &state, Real64 const value) const
    3272              :     {
    3273        11769 :         auto const &s_sched = state.dataSched;
    3274        11769 :         auto const &s_glob = state.dataGlobal;
    3275              : 
    3276              :         // These arrays make sure you don't check the same day or week schedule twice
    3277        11769 :         std::vector<bool> weekSchedChecked;
    3278        11769 :         weekSchedChecked.resize(s_sched->weekSchedules.size());
    3279        11769 :         std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
    3280              : 
    3281        11769 :         std::vector<bool> daySchedChecked;
    3282        11769 :         daySchedChecked.resize(s_sched->daySchedules.size());
    3283        11769 :         std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
    3284              : 
    3285      4176483 :         for (int iWeek = 1; iWeek <= 366; ++iWeek) {
    3286      4165104 :             auto const *weekSched = this->weekScheds[iWeek];
    3287      4165104 :             if (weekSchedChecked[weekSched->Num]) {
    3288      4151397 :                 continue;
    3289              :             }
    3290              : 
    3291       173513 :             for (int iDay = 1; iDay < (int)DayType::Num; ++iDay) {
    3292       160196 :                 auto const *daySched = weekSched->dayScheds[iDay];
    3293       160196 :                 if (daySchedChecked[daySched->Num]) {
    3294       144799 :                     continue;
    3295              :                 }
    3296              : 
    3297      1933429 :                 for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
    3298      1918422 :                     if (daySched->tsVals[i] == value) {
    3299          390 :                         return true;
    3300              :                     }
    3301              :                 }
    3302        15007 :                 daySchedChecked[daySched->Num] = true;
    3303              :             }
    3304        13317 :             weekSchedChecked[weekSched->Num] = true;
    3305              :         }
    3306              : 
    3307        11379 :         return false;
    3308        11769 :     } // ScheduleDetailed::hasVal()
    3309              : 
    3310            0 :     bool CheckScheduleValue(EnergyPlusData &state,
    3311              :                             int const schedNum, // Which Schedule being tested
    3312              :                             Real64 const value  // Actual desired value
    3313              :     )
    3314              :     {
    3315              :         // Method wrapper
    3316            0 :         return state.dataSched->schedules[schedNum]->hasVal(state, value);
    3317              :     }
    3318              : 
    3319            0 :     bool CheckDayScheduleMinValues(EnergyPlusData &state,
    3320              :                                    int const schedNum, // Which Day Schedule being tested
    3321              :                                    Clusive cluMin,
    3322              :                                    Real64 const min)
    3323              :     {
    3324              :         // Method wrapper
    3325            0 :         return state.dataSched->daySchedules[schedNum]->checkMinVal(state, cluMin, min);
    3326              :     } // CheckDayScheduleMinValues()
    3327              : 
    3328            0 :     bool ScheduleConstant::hasFractionalVal([[maybe_unused]] EnergyPlusData &state) const
    3329              :     {
    3330            0 :         return (this->currentVal > 0.0) && (this->currentVal < 1.0);
    3331              :     } // ScheduleYear::hasFractionalVal()
    3332              : 
    3333          160 :     bool ScheduleDetailed::hasFractionalVal(EnergyPlusData &state) const
    3334              :     {
    3335          160 :         auto const &s_sched = state.dataSched;
    3336          160 :         auto const &s_glob = state.dataGlobal;
    3337              : 
    3338              :         // These arrays make sure you don't check the same day or week schedule twice
    3339          160 :         std::vector<bool> weekSchedChecked;
    3340          160 :         weekSchedChecked.resize(s_sched->weekSchedules.size());
    3341          160 :         std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
    3342              : 
    3343          160 :         std::vector<bool> daySchedChecked;
    3344          160 :         daySchedChecked.resize(s_sched->daySchedules.size());
    3345          160 :         std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
    3346              : 
    3347        58720 :         for (int iWeek = 1; iWeek <= 366; ++iWeek) {
    3348        58560 :             auto const *weekSched = this->weekScheds[iWeek];
    3349        58560 :             if (weekSchedChecked[weekSched->Num]) {
    3350        58350 :                 continue;
    3351              :             }
    3352              : 
    3353         2730 :             for (int iDay = 1; iDay < (int)DayType::Num; ++iDay) {
    3354         2520 :                 auto const *daySched = weekSched->dayScheds[iDay];
    3355         2520 :                 if (daySchedChecked[daySched->Num]) {
    3356         2188 :                     continue;
    3357              :                 }
    3358              : 
    3359        38060 :                 for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
    3360        37728 :                     if (daySched->tsVals[i] > 0.0 && daySched->tsVals[i] < 1.0) {
    3361            0 :                         return true;
    3362              :                     }
    3363              :                 }
    3364          332 :                 daySchedChecked[daySched->Num] = true;
    3365              :             }
    3366          210 :             weekSchedChecked[weekSched->Num] = true;
    3367              :         }
    3368              : 
    3369          160 :         return false;
    3370          160 :     } // ScheduleDetailed::hasFractionalVal()
    3371              : 
    3372          332 :     std::pair<Real64, Real64> ScheduleConstant::getMinMaxValsByDayType([[maybe_unused]] EnergyPlusData &state,
    3373              :                                                                        [[maybe_unused]] DayTypeGroup const days)
    3374              :     {
    3375          332 :         return std::make_pair(this->currentVal, this->currentVal);
    3376              :     } // ScheduleConstant::getMinMaxValsByDayType()
    3377              : 
    3378        53692 :     std::pair<Real64, Real64> ScheduleDetailed::getMinMaxValsByDayType(EnergyPlusData &state, DayTypeGroup const days)
    3379              :     {
    3380              :         // J. Glazer - March 2024
    3381              :         // finds the minimum and maximum for a specific set of day types for a given schedule
    3382        53692 :         constexpr std::array<std::array<bool, (int)DayType::Num>, (int)DayTypeGroup::Num> dayTypeFilters = {{
    3383              :             //  Unused    Sun    Mon    Tues   Wed    Thur   Fri    Sat    Hol    Summer Winter Cust1  Cust2
    3384              :             {false, false, true, true, true, true, true, false, false, false, false, false, false},     // Weekday
    3385              :             {false, true, false, false, false, false, false, true, true, false, false, false, false},   // WeekendHoliday
    3386              :             {false, false, false, false, false, false, false, false, false, true, false, false, false}, // SummerDesign
    3387              :             {false, false, false, false, false, false, false, false, false, false, true, false, false}  // WinterDesign
    3388              :         }};
    3389              : 
    3390        53692 :         auto const &s_sched = state.dataSched;
    3391              : 
    3392        53692 :         if (!this->isMinMaxSet) {
    3393            0 :             this->setMinMaxVals(state);
    3394              :         }
    3395              : 
    3396        53692 :         if (!this->MaxMinByDayTypeSet[(int)days]) {
    3397              : 
    3398         9592 :             bool firstSet = true;
    3399         9592 :             std::array<bool, (int)DayType::Num> const &dayTypeFilter = dayTypeFilters[(int)days];
    3400              : 
    3401              :             // These arrays make sure you don't check the same day or week schedule twice
    3402         9592 :             std::vector<bool> weekSchedChecked;
    3403         9592 :             weekSchedChecked.resize(s_sched->weekSchedules.size());
    3404         9592 :             std::fill(weekSchedChecked.begin(), weekSchedChecked.end(), false);
    3405              : 
    3406         9592 :             std::vector<bool> daySchedChecked;
    3407         9592 :             daySchedChecked.resize(s_sched->daySchedules.size());
    3408         9592 :             std::fill(daySchedChecked.begin(), daySchedChecked.end(), false);
    3409              : 
    3410         9592 :             this->MinByDayType[(int)days] = this->MaxByDayType[(int)days] = 0.0;
    3411              : 
    3412      3520264 :             for (int iDay = 1; iDay <= 366; ++iDay) {
    3413      3510672 :                 auto const *weekSched = this->weekScheds[iDay];
    3414      3510672 :                 if (weekSchedChecked[weekSched->Num]) {
    3415      3496864 :                     continue;
    3416              :                 }
    3417              : 
    3418       179504 :                 for (int jDayType = 1; jDayType < (int)DayType::Num; ++jDayType) {
    3419       165696 :                     if (!dayTypeFilter[jDayType]) {
    3420       131176 :                         continue;
    3421              :                     }
    3422              : 
    3423        34520 :                     auto *daySched = weekSched->dayScheds[jDayType];
    3424        34520 :                     if (daySchedChecked[daySched->Num]) {
    3425        20473 :                         continue;
    3426              :                     }
    3427              : 
    3428        14047 :                     if (!daySched->isMinMaxSet) {
    3429            0 :                         daySched->setMinMaxVals(state);
    3430              :                     }
    3431              : 
    3432        14047 :                     if (firstSet) {
    3433         9592 :                         this->MinByDayType[(int)days] = daySched->minVal;
    3434         9592 :                         this->MaxByDayType[(int)days] = daySched->maxVal;
    3435         9592 :                         firstSet = false;
    3436              :                     } else {
    3437         4455 :                         this->MinByDayType[(int)days] = min(this->MinByDayType[(int)days], daySched->minVal);
    3438         4455 :                         this->MaxByDayType[(int)days] = max(this->MaxByDayType[(int)days], daySched->maxVal);
    3439              :                     }
    3440              : 
    3441        14047 :                     daySchedChecked[daySched->Num] = true;
    3442              :                 }
    3443        13808 :                 weekSchedChecked[weekSched->Num] = true;
    3444              :             }
    3445         9592 :             this->MaxMinByDayTypeSet[(int)days] = true;
    3446         9592 :         }
    3447       107384 :         return std::make_pair(this->MinByDayType[(int)days], this->MaxByDayType[(int)days]);
    3448              :     } // ScheduleDetailed::getMinMaxValsByDayType()
    3449              : 
    3450      2799876 :     void ReportScheduleVals(EnergyPlusData &state)
    3451              :     {
    3452              :         // SUBROUTINE INFORMATION:
    3453              :         //       AUTHOR         Linda Lawrie
    3454              :         //       DATE WRITTEN   February 2004
    3455              : 
    3456              :         // PURPOSE OF THIS SUBROUTINE:
    3457              :         // This subroutine puts the proper current schedule values into the "reporting"
    3458              :         // slot for later reporting.
    3459      2799876 :         auto const &s_sched = state.dataSched;
    3460              : 
    3461      2799876 :         if (s_sched->DoScheduleReportingSetup) { // CurrentModuleObject='Any Schedule'
    3462        19699 :             for (auto *sched : s_sched->schedules) {
    3463              :                 // No variables for the built-in AlwaysOn and AlwaysOff schedules
    3464        18896 :                 if (sched->Num == SchedNum_AlwaysOff || sched->Num == SchedNum_AlwaysOn) {
    3465         1606 :                     continue;
    3466              :                 }
    3467              : 
    3468              :                 // Set Up Reporting
    3469        34580 :                 SetupOutputVariable(state,
    3470              :                                     "Schedule Value",
    3471              :                                     Constant::Units::None,
    3472        17290 :                                     sched->currentVal,
    3473              :                                     OutputProcessor::TimeStepType::Zone,
    3474              :                                     OutputProcessor::StoreType::Average,
    3475        17290 :                                     sched->Name);
    3476          803 :             }
    3477          803 :             s_sched->DoScheduleReportingSetup = false;
    3478              :         }
    3479              : 
    3480      2799876 :         UpdateScheduleVals(state);
    3481      2799876 :     }
    3482              : 
    3483          780 :     void ReportOrphanSchedules(EnergyPlusData &state)
    3484              :     {
    3485              :         // SUBROUTINE INFORMATION:
    3486              :         //       AUTHOR         Linda Lawrie
    3487              :         //       DATE WRITTEN   April 2008
    3488              : 
    3489              :         // PURPOSE OF THIS SUBROUTINE:
    3490              :         // In response to CR7498, report orphan (unused) schedule items.
    3491              : 
    3492          780 :         bool NeedOrphanMessage = true;
    3493          780 :         bool NeedUseMessage = false;
    3494          780 :         int NumCount = 0;
    3495              : 
    3496          780 :         auto const &s_sched = state.dataSched;
    3497          780 :         auto const &s_glob = state.dataGlobal;
    3498              : 
    3499        18666 :         for (auto const *sched : s_sched->schedules) {
    3500        17886 :             if (sched->isUsed) {
    3501        17180 :                 continue;
    3502              :             }
    3503          706 :             if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
    3504            2 :                 ShowWarningError(state, "The following schedule names are \"Unused Schedules\".  These schedules are in the idf");
    3505            2 :                 ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
    3506            1 :                 NeedOrphanMessage = false;
    3507              :             }
    3508          706 :             if (s_glob->DisplayUnusedSchedules) {
    3509            1 :                 ShowMessage(state, format("Schedule:Year or Schedule:Compact or Schedule:File or Schedule:Constant={}", sched->Name));
    3510              :             } else {
    3511          705 :                 ++NumCount;
    3512              :             }
    3513          780 :         }
    3514              : 
    3515          780 :         if (NumCount > 0) {
    3516           95 :             ShowMessage(state, format("There are {} unused schedules in input.", NumCount));
    3517           95 :             NeedUseMessage = true;
    3518              :         }
    3519              : 
    3520          780 :         NeedOrphanMessage = true;
    3521          780 :         NumCount = 0;
    3522              : 
    3523       112878 :         for (auto *weekSched : s_sched->weekSchedules) {
    3524       112098 :             if (weekSched->isUsed) {
    3525        70853 :                 continue;
    3526              :             }
    3527        41245 :             if (weekSched->Name.empty()) {
    3528            0 :                 continue;
    3529              :             }
    3530        41245 :             if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
    3531            0 :                 ShowWarningError(state, "The following week schedule names are \"Unused Schedules\".  These schedules are in the idf");
    3532            0 :                 ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
    3533            0 :                 NeedOrphanMessage = false;
    3534              :             }
    3535        41245 :             if (s_glob->DisplayUnusedSchedules) {
    3536            0 :                 ShowMessage(state, format("Schedule:Week:Daily or Schedule:Week:Compact={}", weekSched->Name));
    3537              :             } else {
    3538        41245 :                 ++NumCount;
    3539              :             }
    3540          780 :         }
    3541              : 
    3542          780 :         if (NumCount > 0) {
    3543            2 :             ShowMessage(state, fmt::format("There are {} unused week schedules in input.", NumCount));
    3544            1 :             NeedUseMessage = true;
    3545              :         }
    3546              : 
    3547          780 :         NeedOrphanMessage = true;
    3548          780 :         NumCount = 0;
    3549              : 
    3550       123602 :         for (auto *daySched : s_sched->daySchedules) {
    3551       122822 :             if (daySched->isUsed) {
    3552        81571 :                 continue;
    3553              :             }
    3554        41251 :             if (daySched->Name.empty()) {
    3555            0 :                 continue;
    3556              :             }
    3557        41251 :             if (NeedOrphanMessage && s_glob->DisplayUnusedSchedules) {
    3558            0 :                 ShowWarningError(state, "The following day schedule names are \"Unused Schedules\".  These schedules are in the idf");
    3559            0 :                 ShowContinueError(state, " file but are never obtained by the simulation and therefore are NOT used.");
    3560            0 :                 NeedOrphanMessage = false;
    3561              :             }
    3562              : 
    3563        41251 :             if (s_glob->DisplayUnusedSchedules) {
    3564            0 :                 ShowMessage(state, format("Schedule:Day:Hourly or Schedule:Day:Interval or Schedule:Day:List={}", daySched->Name));
    3565              :             } else {
    3566        41251 :                 ++NumCount;
    3567              :             }
    3568          780 :         }
    3569              : 
    3570          780 :         if (NumCount > 0) {
    3571            4 :             ShowMessage(state, format("There are {} unused day schedules in input.", NumCount));
    3572            4 :             NeedUseMessage = true;
    3573              :         }
    3574              : 
    3575          780 :         if (NeedUseMessage) {
    3576          288 :             ShowMessage(state, "Use Output:Diagnostics,DisplayUnusedSchedules; to see them.");
    3577              :         }
    3578          780 :     } // ReportOrphanSchedules()
    3579              : 
    3580              :     // returns the annual full load hours for a schedule - essentially the sum of the hourly values
    3581           24 :     Real64 ScheduleConstant::getAnnualHoursFullLoad([[maybe_unused]] EnergyPlusData &state,
    3582              :                                                     int const StartDayOfWeek, // Day of week for start of year
    3583              :                                                     bool const isLeapYear     // true if it is a leap year containing February 29
    3584              :     )
    3585              :     {
    3586           24 :         if (StartDayOfWeek < iDayType_Sun || StartDayOfWeek > iDayType_Sat) {
    3587            0 :             return 0.0; // Assert this instead?
    3588              :         }
    3589              : 
    3590           24 :         int DaysInYear = (isLeapYear) ? 366 : 365;
    3591           24 :         return DaysInYear * Constant::iHoursInDay * this->currentVal;
    3592              :     }
    3593              : 
    3594              :     // returns the annual full load hours for a schedule - essentially the sum of the hourly values
    3595        10648 :     Real64 ScheduleDetailed::getAnnualHoursFullLoad(EnergyPlusData &state,
    3596              :                                                     int const StartDayOfWeek, // Day of week for start of year
    3597              :                                                     bool const isLeapYear     // true if it is a leap year containing February 29
    3598              :     )
    3599              :     {
    3600              :         // J. Glazer - July 2017
    3601              :         // adapted from Linda K. Lawrie original code for ScheduleAverageHoursPerWeek()
    3602        10648 :         auto const &s_glob = state.dataGlobal;
    3603              : 
    3604        10648 :         int DaysInYear = (isLeapYear) ? 366 : 365;
    3605              : 
    3606        10648 :         int DayT = StartDayOfWeek;
    3607        10648 :         Real64 TotalHours = 0.0;
    3608              : 
    3609        10648 :         if (DayT < iDayType_Sun || DayT > iDayType_Sat) {
    3610            0 :             return TotalHours;
    3611              :         }
    3612              : 
    3613      3897184 :         for (int iDay = 1; iDay <= DaysInYear; ++iDay) {
    3614      3886536 :             auto const *weekSched = this->weekScheds[iDay];
    3615      3886536 :             auto const *daySched = weekSched->dayScheds[DayT];
    3616              : 
    3617      3886536 :             TotalHours += daySched->sumTsVals / double(s_glob->TimeStepsInHour);
    3618      3886536 :             ++DayT;
    3619      3886536 :             if (DayT > iDayType_Sat) {
    3620       553712 :                 DayT = iDayType_Sun;
    3621              :             }
    3622              :         }
    3623              : 
    3624        10648 :         return TotalHours;
    3625              :     }
    3626              : 
    3627              :     // returns the average number of hours per week based on the schedule index provided
    3628         4135 :     Real64 Schedule::getAverageWeeklyHoursFullLoad(EnergyPlusData &state,
    3629              :                                                    int const StartDayOfWeek, // Day of week for start of year
    3630              :                                                    bool const isLeapYear     // true if it is a leap year containing February 29
    3631              :     )
    3632              :     {
    3633              :         // FUNCTION INFORMATION:
    3634              :         //       AUTHOR         Linda K. Lawrie
    3635              :         //       DATE WRITTEN   August 2006
    3636              :         //       MODIFIED       September 2012; Glazer - CR8849
    3637              : 
    3638              :         // PURPOSE OF THIS FUNCTION:
    3639              :         // This function returns the "average" hours per week for a schedule over
    3640              :         // the entire year.
    3641              : 
    3642         4135 :         Real64 WeeksInYear = (isLeapYear) ? (366.0 / 7.0) : (365.0 / 7.0);
    3643         4135 :         return this->getAnnualHoursFullLoad(state, StartDayOfWeek, isLeapYear) / WeeksInYear;
    3644              :     }
    3645              : 
    3646              :     // returns the annual hours greater than 1% for a schedule - essentially the number of hours with any operation
    3647         6516 :     Real64 ScheduleDetailed::getAnnualHoursGreaterThan1Percent(EnergyPlusData &state,
    3648              :                                                                int const StartDayOfWeek, // Day of week for start of year
    3649              :                                                                bool const isItLeapYear   // true if it is a leap year containing February 29
    3650              :     )
    3651              :     {
    3652              :         // J. Glazer - July 2017
    3653              :         // adapted from Linda K. Lawrie original code for ScheduleAverageHoursPerWeek()
    3654         6516 :         auto const &s_glob = state.dataGlobal;
    3655              : 
    3656         6516 :         int DaysInYear = (isItLeapYear) ? 366 : 365;
    3657              : 
    3658         6516 :         int DayT = StartDayOfWeek;
    3659         6516 :         Real64 TotalHours = 0.0;
    3660              : 
    3661         6516 :         if (DayT < iDayType_Sun || DayT > iDayType_Sat) {
    3662            0 :             return TotalHours;
    3663              :         }
    3664              : 
    3665      2384867 :         for (int iDay = 1; iDay <= DaysInYear; ++iDay) {
    3666      2378351 :             auto const *weekSched = this->weekScheds[iDay];
    3667      2378351 :             auto const *daySched = weekSched->dayScheds[DayT];
    3668    294096167 :             for (int i = 0; i < Constant::iHoursInDay * s_glob->TimeStepsInHour; ++i) {
    3669    291717816 :                 if (daySched->tsVals[i] > 0.0) {
    3670    213742489 :                     TotalHours += s_glob->TimeStepZone;
    3671              :                 }
    3672              :             }
    3673              : 
    3674      2378351 :             ++DayT;
    3675      2378351 :             if (DayT > iDayType_Sat) {
    3676       338843 :                 DayT = iDayType_Sun;
    3677              :             }
    3678              :         }
    3679              : 
    3680         6516 :         return TotalHours;
    3681              :     } // ScheduleDetailed::getAnnualHoursGreaterThan1Percent()
    3682              : 
    3683              :     // returns the annual hours greater than 1% for a schedule - essentially the number of hours with any operation
    3684           21 :     Real64 ScheduleConstant::getAnnualHoursGreaterThan1Percent([[maybe_unused]] EnergyPlusData &state,
    3685              :                                                                int const StartDayOfWeek, // Day of week for start of year
    3686              :                                                                bool const isItLeapYear   // true if it is a leap year containing February 29
    3687              :     )
    3688              :     {
    3689           21 :         int DaysInYear = (isItLeapYear) ? 366 : 365;
    3690              : 
    3691           21 :         if (StartDayOfWeek < iDayType_Sun || StartDayOfWeek > iDayType_Sat) {
    3692            0 :             return 0.0; // Assert this instead?
    3693              :         }
    3694              : 
    3695           21 :         return (this->currentVal > 0.0) ? (Constant::rHoursInDay * DaysInYear) : 0;
    3696              :     } // ScheduleConstant::getHoursGreaterThan1Percent()
    3697              : 
    3698              :     // returns the temperature value from a schedule at a certain time for the first day of the week in either January or July
    3699              :     std::tuple<Real64, int, std::string>
    3700         3568 :     ScheduleDetailed::getValAndCountOnDay(EnergyPlusData &state, bool const isSummer, DayType const dayOfWeek, int const hourOfDay)
    3701              :     {
    3702              :         // J.Glazer - Aug 2017
    3703              : 
    3704         3568 :         auto const &s_glob = state.dataGlobal;
    3705              : 
    3706              :         // determine month to use based on hemiphere and season
    3707              :         int month;
    3708         3568 :         if (isSummer) {
    3709         1766 :             month = (state.dataEnvrn->Latitude > 0.) ? 7 : 1;
    3710              :         } else {
    3711         1802 :             month = (state.dataEnvrn->Latitude > 0.) ? 1 : 7;
    3712              :         }
    3713              : 
    3714         3568 :         std::string monthName = (month == 1) ? "January" : "July";
    3715              : 
    3716         3568 :         int jdateSelect = General::nthDayOfWeekOfMonth(state, (int)dayOfWeek, 1, month);
    3717              : 
    3718              :         // determine number of days in year
    3719         3568 :         int DaysInYear = (state.dataEnvrn->CurrentYearIsLeapYear) ? 366 : 365;
    3720              : 
    3721              :         // should adjust date if lands on a holiday but for now assume that it does not
    3722              : 
    3723              :         // adjust time of day for daylight savings time
    3724         3568 :         int hourSelect = hourOfDay + state.dataWeather->DSTIndex(jdateSelect);
    3725              : 
    3726              :         // get the value at the selected time
    3727         3568 :         int constexpr firstTimeStep = 1;
    3728         3568 :         auto const *weekSched = this->weekScheds[jdateSelect];
    3729         3568 :         auto const *daySched = weekSched->dayScheds[(int)dayOfWeek];
    3730              : 
    3731         3568 :         Real64 value = daySched->tsVals[(hourSelect - 1) * state.dataGlobal->TimeStepsInHour + (firstTimeStep - 1)];
    3732         3568 :         int countOfSame = 0;
    3733              : 
    3734              :         // count the number of times with that same value
    3735      1305896 :         for (int jdateOfYear = 1; jdateOfYear <= DaysInYear; ++jdateOfYear) {
    3736      1302328 :             auto const *wSched = this->weekScheds[jdateOfYear];
    3737      1302328 :             if (wSched == weekSched) { // if same week schedule can short circuit rest of testing and increment counter
    3738      1291440 :                 ++countOfSame;
    3739      1291440 :                 continue;
    3740              :             }
    3741              : 
    3742        10888 :             auto const *dSched = wSched->dayScheds[(int)dayOfWeek];
    3743        10888 :             if (dSched == daySched) { // if same day schedule can short circuit rest of testing and increment counter
    3744           12 :                 ++countOfSame;
    3745           12 :                 continue;
    3746              :             }
    3747              : 
    3748        10876 :             if (dSched->tsVals[(hourSelect - 1) * s_glob->TimeStepsInHour + (firstTimeStep - 1)] == value) {
    3749         4310 :                 ++countOfSame;
    3750              :             }
    3751              :         }
    3752              : 
    3753         7136 :         return std::make_tuple(value, countOfSame, monthName);
    3754         3568 :     } // ScheduleDetailed::getValAndCountOnDay()
    3755              : 
    3756              :     // returns the temperature value from a schedule at a certain time for the first day of the week in either January or July
    3757           18 :     std::tuple<Real64, int, std::string> ScheduleConstant::getValAndCountOnDay(EnergyPlusData &state,
    3758              :                                                                                bool const isSummer,
    3759              :                                                                                [[maybe_unused]] DayType const dayOfWeek,
    3760              :                                                                                [[maybe_unused]] int const hourOfDay)
    3761              :     {
    3762              :         // determine month to use based on hemiphere and season
    3763              :         int month;
    3764           18 :         if (isSummer) {
    3765           10 :             month = (state.dataEnvrn->Latitude > 0.) ? 7 : 1;
    3766              :         } else {
    3767            8 :             month = (state.dataEnvrn->Latitude > 0.) ? 1 : 7;
    3768              :         }
    3769              : 
    3770           18 :         std::string monthName = (month == 1) ? "January" : "July";
    3771           18 :         int DaysInYear = (state.dataEnvrn->CurrentYearIsLeapYear) ? 366 : 365;
    3772           36 :         return std::make_tuple(this->currentVal, DaysInYear, monthName);
    3773           18 :     } // ScheduleConstant::getValAndCountOnDay()
    3774              : 
    3775            0 :     void ShowSevereBadMin(EnergyPlusData &state,
    3776              :                           ErrorObjectHeader const &eoh,
    3777              :                           std::string_view fieldName,
    3778              :                           std::string_view fieldVal,
    3779              :                           Clusive cluMin,
    3780              :                           Real64 minVal,
    3781              :                           std::string_view msg)
    3782              :     {
    3783            0 :         ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3784            0 :         ShowContinueError(
    3785            0 :             state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMin == Clusive::In ? "<" : "<=", minVal));
    3786            0 :         if (!msg.empty()) {
    3787            0 :             ShowContinueError(state, format("{}", msg));
    3788              :         }
    3789            0 :     }
    3790              : 
    3791            0 :     void ShowSevereBadMax(EnergyPlusData &state,
    3792              :                           ErrorObjectHeader const &eoh,
    3793              :                           std::string_view fieldName,
    3794              :                           std::string_view fieldVal,
    3795              :                           Clusive cluMax,
    3796              :                           Real64 maxVal,
    3797              :                           std::string_view msg)
    3798              :     {
    3799            0 :         ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3800            0 :         ShowContinueError(
    3801            0 :             state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMax == Clusive::In ? ">" : ">=", maxVal));
    3802            0 :         if (!msg.empty()) {
    3803            0 :             ShowContinueError(state, format("{}", msg));
    3804              :         }
    3805            0 :     }
    3806              : 
    3807            0 :     void ShowSevereBadMinMax(EnergyPlusData &state,
    3808              :                              ErrorObjectHeader const &eoh,
    3809              :                              std::string_view fieldName,
    3810              :                              std::string_view fieldVal,
    3811              :                              Clusive cluMin,
    3812              :                              Real64 minVal,
    3813              :                              Clusive cluMax,
    3814              :                              Real64 maxVal,
    3815              :                              std::string_view msg)
    3816              :     {
    3817            0 :         ShowSevereError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3818            0 :         ShowContinueError(state,
    3819            0 :                           format("{} = {}, schedule contains values that are {} {} and/or {} {}",
    3820              :                                  fieldName,
    3821              :                                  fieldVal,
    3822            0 :                                  cluMin == Clusive::In ? "<" : "<=",
    3823              :                                  minVal,
    3824            0 :                                  cluMax == Clusive::In ? ">" : ">=",
    3825              :                                  maxVal));
    3826            0 :         if (!msg.empty()) {
    3827            0 :             ShowContinueError(state, format("{}", msg));
    3828              :         }
    3829            0 :     }
    3830              : 
    3831            0 :     void ShowWarningBadMin(EnergyPlusData &state,
    3832              :                            ErrorObjectHeader const &eoh,
    3833              :                            std::string_view fieldName,
    3834              :                            std::string_view fieldVal,
    3835              :                            Clusive cluMin,
    3836              :                            Real64 minVal,
    3837              :                            std::string_view msg)
    3838              :     {
    3839            0 :         ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3840            0 :         ShowContinueError(
    3841            0 :             state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMin == Clusive::In ? "<" : "<=", minVal));
    3842            0 :         if (!msg.empty()) {
    3843            0 :             ShowContinueError(state, format("{}", msg));
    3844              :         }
    3845            0 :     }
    3846              : 
    3847            0 :     void ShowWarningBadMax(EnergyPlusData &state,
    3848              :                            ErrorObjectHeader const &eoh,
    3849              :                            std::string_view fieldName,
    3850              :                            std::string_view fieldVal,
    3851              :                            Clusive cluMax,
    3852              :                            Real64 maxVal,
    3853              :                            std::string_view msg)
    3854              :     {
    3855            0 :         ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3856            0 :         ShowContinueError(
    3857            0 :             state, format("{} = {}, schedule contains values that are {} {}", fieldName, fieldVal, cluMax == Clusive::In ? ">" : ">=", maxVal));
    3858            0 :         if (!msg.empty()) {
    3859            0 :             ShowContinueError(state, format("{}", msg));
    3860              :         }
    3861            0 :     }
    3862              : 
    3863            0 :     void ShowWarningBadMinMax(EnergyPlusData &state,
    3864              :                               ErrorObjectHeader const &eoh,
    3865              :                               std::string_view fieldName,
    3866              :                               std::string_view fieldVal,
    3867              :                               Clusive cluMin,
    3868              :                               Real64 minVal,
    3869              :                               Clusive cluMax,
    3870              :                               Real64 maxVal,
    3871              :                               std::string_view msg)
    3872              :     {
    3873            0 :         ShowWarningError(state, format("{}: {} = {}", eoh.routineName, eoh.objectType, eoh.objectName));
    3874            0 :         ShowContinueError(state,
    3875            0 :                           format("{} = {}, schedule contains values that are {} {} and/or {} {}",
    3876              :                                  fieldName,
    3877              :                                  fieldVal,
    3878            0 :                                  cluMin == Clusive::In ? "<" : "<=",
    3879              :                                  minVal,
    3880            0 :                                  cluMax == Clusive::In ? ">" : ">=",
    3881              :                                  maxVal));
    3882            0 :         if (!msg.empty()) {
    3883            0 :             ShowContinueError(state, format("{}", msg));
    3884              :         }
    3885            0 :     }
    3886              : 
    3887              : } // namespace Sched
    3888              : 
    3889              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1