LCOV - code coverage report
Current view: top level - EnergyPlus - ScheduleManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 61.7 % 1850 1141
Test Date: 2025-05-22 16:09:37 Functions: 80.0 % 65 52

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

Generated by: LCOV version 2.0-1