LCOV - code coverage report
Current view: top level - EnergyPlus - DemandManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 68.8 % 780 537
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 10 10

            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              : // ObjexxFCL Headers
      49              : #include <ObjexxFCL/Fmath.hh>
      50              : 
      51              : // EnergyPlus Headers
      52              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      53              : #include <EnergyPlus/DataEnvironment.hh>
      54              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      55              : #include <EnergyPlus/DataHeatBalance.hh>
      56              : #include <EnergyPlus/DataIPShortCuts.hh>
      57              : #include <EnergyPlus/DataZoneControls.hh>
      58              : #include <EnergyPlus/DemandManager.hh>
      59              : #include <EnergyPlus/GlobalNames.hh>
      60              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      61              : #include <EnergyPlus/InternalHeatGains.hh>
      62              : #include <EnergyPlus/MixedAir.hh>
      63              : #include <EnergyPlus/OutputProcessor.hh>
      64              : #include <EnergyPlus/ScheduleManager.hh>
      65              : #include <EnergyPlus/SimulationManager.hh>
      66              : #include <EnergyPlus/UtilityRoutines.hh>
      67              : 
      68              : namespace EnergyPlus::DemandManager {
      69              : 
      70              : // MODULE INFORMATION:
      71              : //       AUTHOR         Peter Graham Ellis
      72              : //       DATE WRITTEN   July 2005
      73              : //       MODIFIED       Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
      74              : //       RE-ENGINEERED  na
      75              : 
      76              : // PURPOSE OF THIS MODULE:
      77              : // This module provides controls for demand limiting various loads.
      78              : 
      79              : // METHODOLOGY EMPLOYED:
      80              : // ManageDemand is called from within the ManageHVAC routine after the first pass through SimHVAC, but
      81              : // _before_ any variables are reported or histories are updated.  If the metered demand is above the
      82              : // limit action is taken using the various demand managers to reduce loads.  Exterior energy use, zone
      83              : // heat balance, and HVAC system are then resimulated as necessary.  It is possible to iterate several
      84              : // times through ManageDemand before the final demand managers are established and the timestep can be
      85              : // completed.
      86              : 
      87              : constexpr std::array<std::string_view, static_cast<int>(ManagerType::Num)> ManagerNamesUC{"DEMANDMANAGER:EXTERIORLIGHTS",
      88              :                                                                                           "DEMANDMANAGER:LIGHTS",
      89              :                                                                                           "DEMANDMANAGER:ELECTRICEQUIPMENT",
      90              :                                                                                           "DEMANDMANAGER:THERMOSTATS",
      91              :                                                                                           "DEMANDMANAGER:VENTILATION"};
      92              : constexpr std::array<std::string_view, static_cast<int>(ManagePriorityType::Num)> ManagePriorityNamesUC{"SEQUENTIAL", "OPTIMAL", "ALL"};
      93              : constexpr std::array<std::string_view, static_cast<int>(ManagerLimit::Num)> ManagerLimitNamesUC{"OFF", "FIXED", "VARIABLE", "REDUCTIONRATIO"};
      94              : constexpr std::array<std::string_view, static_cast<int>(ManagerLimit::Num)> ManagerLimitVentNamesUC{"OFF", "FIXEDRATE", "VARIABLE", "REDUCTIONRATIO"};
      95              : constexpr std::array<std::string_view, static_cast<int>(ManagerSelection::Num)> ManagerSelectionNamesUC{"ALL", "ROTATEMANY", "ROTATEONE"};
      96              : 
      97      1989307 : void ManageDemand(EnergyPlusData &state)
      98              : {
      99              : 
     100              :     // SUBROUTINE INFORMATION:
     101              :     //       AUTHOR         Peter Graham Ellis
     102              :     //       DATE WRITTEN   July 2005
     103              : 
     104              :     // Locals
     105              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     106              : 
     107      1989307 :     if (state.dataDemandManager->GetInput && !state.dataGlobal->DoingSizing) {
     108            0 :         GetDemandManagerInput(state);
     109            0 :         GetDemandManagerListInput(state);
     110            0 :         state.dataDemandManager->GetInput = false;
     111              :     }
     112              : 
     113      1989307 :     if (state.dataDemandManager->NumDemandManagerList > 0) {
     114              : 
     115         8064 :         if (state.dataGlobal->WarmupFlag) {
     116         6912 :             state.dataDemandManager->BeginDemandSim = true;
     117         6912 :             if (state.dataDemandManager->ClearHistory) {
     118              :                 // Clear historical variables
     119           24 :                 for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     120           12 :                     state.dataDemandManager->DemandManagerList(ListNum).History = 0.0;
     121           12 :                     state.dataDemandManager->DemandManagerList(ListNum).MeterDemand = 0.0;
     122           12 :                     state.dataDemandManager->DemandManagerList(ListNum).AverageDemand = 0.0;
     123           12 :                     state.dataDemandManager->DemandManagerList(ListNum).PeakDemand = 0.0;
     124           12 :                     state.dataDemandManager->DemandManagerList(ListNum).ScheduledLimit = 0.0;
     125           12 :                     state.dataDemandManager->DemandManagerList(ListNum).DemandLimit = 0.0;
     126           12 :                     state.dataDemandManager->DemandManagerList(ListNum).AvoidedDemand = 0.0;
     127           12 :                     state.dataDemandManager->DemandManagerList(ListNum).OverLimit = 0.0;
     128           12 :                     state.dataDemandManager->DemandManagerList(ListNum).OverLimitDuration = 0.0;
     129              :                 } // ListNum
     130              : 
     131              :                 // Clear demand manager variables
     132           84 :                 for (auto &e : state.dataDemandManager->DemandMgr) {
     133           72 :                     e.Active = false;
     134           72 :                     e.ElapsedTime = 0;
     135           72 :                     e.ElapsedRotationTime = 0;
     136           72 :                     e.RotatedLoadNum = 0;
     137              :                 }
     138              :             }
     139         6912 :             state.dataDemandManager->ClearHistory = false;
     140              :         }
     141              : 
     142         8064 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing) {
     143              : 
     144         1152 :             if (state.dataDemandManager->BeginDemandSim) {
     145           12 :                 state.dataDemandManager->BeginDemandSim = false;
     146           12 :                 state.dataDemandManager->ClearHistory = true;
     147              :             }
     148              : 
     149         1152 :             state.dataDemandManager->DemandManagerExtIterations = 0;
     150         1152 :             state.dataDemandManager->DemandManagerHBIterations = 0;
     151         1152 :             state.dataDemandManager->DemandManagerHVACIterations = 0;
     152              : 
     153         1152 :             state.dataDemandManager->firstTime = true;
     154         1152 :             state.dataDemandManager->ResimExt = false;
     155         1152 :             state.dataDemandManager->ResimHB = false;
     156         1152 :             state.dataDemandManager->ResimHVAC = false;
     157              : 
     158         3791 :             while (state.dataDemandManager->firstTime || state.dataDemandManager->ResimExt || state.dataDemandManager->ResimHB ||
     159         1194 :                    state.dataDemandManager->ResimHVAC) {
     160         1445 :                 state.dataDemandManager->firstTime = false;
     161              : 
     162         1445 :                 Resimulate(state, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
     163         1445 :                 state.dataDemandManager->ResimExt = false;
     164         1445 :                 state.dataDemandManager->ResimHB = false;
     165         1445 :                 state.dataDemandManager->ResimHVAC = false;
     166              : 
     167         1445 :                 SurveyDemandManagers(state); // Determines which Demand Managers can reduce demand
     168              : 
     169         2890 :                 for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     170         1445 :                     SimulateDemandManagerList(
     171         1445 :                         state, ListNum, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
     172              :                 } // ListNum
     173              : 
     174         1445 :                 ActivateDemandManagers(state); // Sets limits on loads
     175              : 
     176         1445 :                 if (state.dataDemandManager->DemandManagerExtIterations + state.dataDemandManager->DemandManagerHBIterations +
     177         1445 :                         state.dataDemandManager->DemandManagerHVACIterations >
     178              :                     500) {
     179              :                     // This error can only happen if there is a bug in the code
     180            0 :                     ShowFatalError(state, "Too many DemandManager iterations. (>500)");
     181            0 :                     break;
     182              :                 }
     183              :             }
     184              : 
     185         2304 :             for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     186         1152 :                 ReportDemandManagerList(state, ListNum);
     187              :             } // ListNum
     188              :         }
     189              :     }
     190      1989307 : }
     191              : 
     192         1445 : void SimulateDemandManagerList(EnergyPlusData &state,
     193              :                                int const ListNum,
     194              :                                bool &ResimExt, // Flag to resimulate the exterior energy use simulation
     195              :                                bool &ResimHB,  // Flag to resimulate the heat balance simulation (including HVAC)
     196              :                                bool &ResimHVAC // Flag to resimulate the HVAC simulation
     197              : )
     198              : {
     199              : 
     200              :     // SUBROUTINE INFORMATION:
     201              :     //       AUTHOR         Peter Graham Ellis
     202              :     //       DATE WRITTEN   July 2005
     203              :     //       MODIFIED       Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
     204              : 
     205              :     // Using/Aliasing
     206         1445 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     207              : 
     208              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     209              :     bool OnPeak;
     210              : 
     211         1445 :     auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
     212              : 
     213         1445 :     demandManagerList.ScheduledLimit = demandManagerList.limitSched->getCurrentVal();
     214         1445 :     demandManagerList.DemandLimit = demandManagerList.ScheduledLimit * demandManagerList.SafetyFraction;
     215              : 
     216         1445 :     demandManagerList.MeterDemand =
     217         1445 :         GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::Zone) / state.dataGlobal->TimeStepZoneSec +
     218         1445 :         GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::System) / TimeStepSysSec;
     219              : 
     220              :     // Calculate average demand over the averaging window including the current timestep meter demand
     221              :     Real64 AverageDemand =
     222         1445 :         demandManagerList.AverageDemand + (demandManagerList.MeterDemand - demandManagerList.History(1)) / demandManagerList.AveragingWindow;
     223              : 
     224         1445 :     OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
     225              : 
     226         1445 :     if (OnPeak) {
     227         1445 :         Real64 OverLimit = AverageDemand - demandManagerList.DemandLimit;
     228              : 
     229         1445 :         if (OverLimit > 0.0) {
     230              : 
     231          329 :             switch (demandManagerList.ManagerPriority) {
     232          329 :             case ManagePriorityType::Sequential: { // Activate first Demand Manager that can reduce demand
     233              : 
     234          999 :                 for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
     235          963 :                     auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
     236              : 
     237          963 :                     if (demandMgr.CanReduceDemand) {
     238          293 :                         demandMgr.Activate = true;
     239              : 
     240          293 :                         switch (demandMgr.Type) {
     241           55 :                         case ManagerType::ExtLights: {
     242           55 :                             ResimExt = true;
     243           55 :                         } break;
     244          196 :                         case ManagerType::Lights:
     245              :                         case ManagerType::ElecEquip: {
     246          196 :                             ResimHB = true;
     247          196 :                             ResimHVAC = true;
     248          196 :                         } break;
     249           42 :                         case ManagerType::Thermostats:
     250              :                         case ManagerType::Ventilation: {
     251           42 :                             ResimHVAC = true;
     252           42 :                         } break;
     253            0 :                         default:
     254            0 :                             break;
     255              :                         }
     256              : 
     257          293 :                         break; // Leave the loop
     258              :                     }
     259              :                 } // MgrNum
     260              : 
     261          329 :             } break;
     262            0 :             case ManagePriorityType::Optimal: {
     263              :                 // Not yet implemented
     264              : 
     265            0 :             } break;
     266            0 :             case ManagePriorityType::All: { // Activate ALL Demand Managers that can reduce demand
     267              : 
     268            0 :                 for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
     269            0 :                     auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
     270              : 
     271            0 :                     if (demandMgr.CanReduceDemand) {
     272            0 :                         demandMgr.Activate = true;
     273              : 
     274            0 :                         switch (demandMgr.Type) {
     275            0 :                         case ManagerType::ExtLights: {
     276            0 :                             ResimExt = true;
     277            0 :                         } break;
     278            0 :                         case ManagerType::Lights:
     279              :                         case ManagerType::ElecEquip: {
     280            0 :                             ResimHB = true;
     281            0 :                             ResimHVAC = true;
     282            0 :                         } break;
     283            0 :                         case ManagerType::Thermostats:
     284              :                         case ManagerType::Ventilation: {
     285            0 :                             ResimHVAC = true;
     286            0 :                         } break;
     287            0 :                         default:
     288            0 :                             break;
     289              :                         }
     290              :                     }
     291              :                 } // MgrNum
     292            0 :             } break;
     293            0 :             default:
     294            0 :                 break;
     295              :             }
     296              :         }
     297              :     }
     298         1445 : }
     299              : 
     300          800 : void GetDemandManagerListInput(EnergyPlusData &state)
     301              : {
     302              : 
     303              :     // SUBROUTINE INFORMATION:
     304              :     //       AUTHOR         Peter Graham Ellis
     305              :     //       DATE WRITTEN   July 2005
     306              :     //       MODIFIED       Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
     307              : 
     308              :     // PURPOSE OF THIS SUBROUTINE:
     309              :     // Gets the DEMAND MANAGER LIST input from the input file.
     310              : 
     311              :     // METHODOLOGY EMPLOYED:
     312              :     // Standard EnergyPlus methodology.
     313              : 
     314              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     315              : 
     316              :     static constexpr std::string_view routineName = "GetDemandManagerListInput";
     317          800 :     constexpr std::string_view cCurrentModuleObject = "DemandManagerAssignmentList";
     318              : 
     319          800 :     auto &s_ipsc = state.dataIPShortCut;
     320          800 :     auto const &s_ip = state.dataInputProcessing->inputProcessor;
     321              : 
     322          800 :     state.dataDemandManager->NumDemandManagerList = s_ip->getNumObjectsFound(state, cCurrentModuleObject);
     323              : 
     324          800 :     if (state.dataDemandManager->NumDemandManagerList > 0) {
     325              :         int NumAlphas; // Number of elements in the alpha array
     326              :         int NumNums;   // Number of elements in the numeric array
     327              :         int IOStat;    // IO Status when calling get input subroutine
     328            6 :         bool ErrorsFound = false;
     329              : 
     330            6 :         state.dataDemandManager->DemandManagerList.allocate(state.dataDemandManager->NumDemandManagerList);
     331              : 
     332           12 :         for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     333              : 
     334            6 :             auto &thisDemandMgrList = state.dataDemandManager->DemandManagerList(ListNum);
     335              : 
     336           18 :             s_ip->getObjectItem(state,
     337              :                                 cCurrentModuleObject,
     338              :                                 ListNum,
     339            6 :                                 s_ipsc->cAlphaArgs,
     340              :                                 NumAlphas,
     341            6 :                                 s_ipsc->rNumericArgs,
     342              :                                 NumNums,
     343              :                                 IOStat,
     344              :                                 _,
     345            6 :                                 s_ipsc->lAlphaFieldBlanks,
     346            6 :                                 s_ipsc->cAlphaFieldNames,
     347            6 :                                 s_ipsc->cNumericFieldNames);
     348              : 
     349            6 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     350              : 
     351            6 :             thisDemandMgrList.Name = s_ipsc->cAlphaArgs(1);
     352              : 
     353            6 :             thisDemandMgrList.Meter = GetMeterIndex(state, s_ipsc->cAlphaArgs(2));
     354              : 
     355            6 :             if (thisDemandMgrList.Meter == -1) {
     356            0 :                 ShowSevereError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     357            0 :                 ShowContinueError(state, format("Entered in {} = {}", cCurrentModuleObject, thisDemandMgrList.Name));
     358            0 :                 ErrorsFound = true;
     359              : 
     360            6 :             } else if ((state.dataOutputProcessor->meters[thisDemandMgrList.Meter]->resource == Constant::eResource::Electricity) ||
     361            0 :                        (state.dataOutputProcessor->meters[thisDemandMgrList.Meter]->resource == Constant::eResource::ElectricityNet)) {
     362              :             } else {
     363            0 :                 ShowSevereError(state,
     364            0 :                                 format("{} = \"{}\" invalid value {} = \"{}\".",
     365              :                                        cCurrentModuleObject,
     366            0 :                                        thisDemandMgrList.Name,
     367            0 :                                        s_ipsc->cAlphaFieldNames(2),
     368            0 :                                        s_ipsc->cAlphaArgs(2)));
     369            0 :                 ShowContinueError(state, "Only Electricity and ElectricityNet meters are currently allowed.");
     370            0 :                 ErrorsFound = true;
     371              :             }
     372              : 
     373              :             // Further checking for conflicting DEMAND MANAGER LISTs
     374              : 
     375            6 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
     376            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     377            0 :                 ErrorsFound = true;
     378            6 :             } else if ((thisDemandMgrList.limitSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
     379            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
     380            0 :                 ErrorsFound = true;
     381              :             }
     382              : 
     383            6 :             thisDemandMgrList.SafetyFraction = s_ipsc->rNumericArgs(1);
     384              : 
     385            6 :             if (s_ipsc->lAlphaFieldBlanks(4)) {
     386            0 :             } else if ((thisDemandMgrList.billingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
     387            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
     388            0 :                 ErrorsFound = true;
     389              :             }
     390              : 
     391            6 :             if (s_ipsc->lAlphaFieldBlanks(5)) {
     392            0 :             } else if ((thisDemandMgrList.peakSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
     393            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
     394            0 :                 ErrorsFound = true;
     395              :             }
     396              : 
     397            6 :             thisDemandMgrList.AveragingWindow = max(int(s_ipsc->rNumericArgs(2) / state.dataGlobal->MinutesInTimeStep), 1);
     398              :             // Round to nearest timestep
     399              :             // Can make this fancier to include windows that do not fit the timesteps
     400            6 :             thisDemandMgrList.History.allocate(thisDemandMgrList.AveragingWindow);
     401            6 :             thisDemandMgrList.History = 0.0;
     402              : 
     403              :             // Validate Demand Manager Priority
     404            6 :             thisDemandMgrList.ManagerPriority =
     405            6 :                 static_cast<ManagePriorityType>(getEnumValue(ManagePriorityNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(6))));
     406            6 :             ErrorsFound = ErrorsFound || (thisDemandMgrList.ManagerPriority == ManagePriorityType::Invalid);
     407              : 
     408              :             // Get DEMAND MANAGER Type and Name pairs
     409            6 :             thisDemandMgrList.NumOfManager = int((NumAlphas - 6) / 2.0);
     410              : 
     411            6 :             if (thisDemandMgrList.NumOfManager > 0) {
     412            6 :                 thisDemandMgrList.Manager.allocate(thisDemandMgrList.NumOfManager);
     413           42 :                 for (int MgrNum = 1; MgrNum <= thisDemandMgrList.NumOfManager; ++MgrNum) {
     414              : 
     415           36 :                     auto &thisManager = thisDemandMgrList.Manager(MgrNum);
     416              :                     // Validate DEMAND MANAGER Type
     417           36 :                     ManagerType MgrType = static_cast<ManagerType>(getEnumValue(ManagerNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(MgrNum * 2 + 5))));
     418           36 :                     if (MgrType != ManagerType::Invalid) {
     419           36 :                         thisManager = Util::FindItemInList(s_ipsc->cAlphaArgs(MgrNum * 2 + 6), state.dataDemandManager->DemandMgr);
     420           36 :                         if (thisManager == 0) {
     421            0 :                             ShowSevereError(state,
     422            0 :                                             format("{} = \"{}\" invalid {} = \"{}\" not found.",
     423              :                                                    cCurrentModuleObject,
     424            0 :                                                    thisDemandMgrList.Name,
     425            0 :                                                    s_ipsc->cAlphaFieldNames(MgrNum * 2 + 6),
     426            0 :                                                    s_ipsc->cAlphaArgs(MgrNum * 2 + 6)));
     427            0 :                             ErrorsFound = true;
     428              :                         }
     429              :                     } else {
     430            0 :                         ShowSevereError(state,
     431            0 :                                         format("{} = \"{}\" invalid value {} = \"{}\".",
     432              :                                                cCurrentModuleObject,
     433            0 :                                                thisDemandMgrList.Name,
     434            0 :                                                s_ipsc->cAlphaFieldNames(MgrNum * 2 + 5),
     435            0 :                                                s_ipsc->cAlphaArgs(MgrNum * 2 + 5)));
     436            0 :                         ErrorsFound = true;
     437              :                     }
     438              : 
     439              :                     // Check that each is not already referenced using %DemandManagerList field
     440              : 
     441              :                 } // MgrNum
     442              :             }
     443              : 
     444              :             // Setup report variables
     445           12 :             SetupOutputVariable(state,
     446              :                                 "Demand Manager Meter Demand Power",
     447              :                                 Constant::Units::W,
     448            6 :                                 thisDemandMgrList.MeterDemand,
     449              :                                 OutputProcessor::TimeStepType::Zone,
     450              :                                 OutputProcessor::StoreType::Average,
     451            6 :                                 thisDemandMgrList.Name);
     452              : 
     453           12 :             SetupOutputVariable(state,
     454              :                                 "Demand Manager Average Demand Power",
     455              :                                 Constant::Units::W,
     456            6 :                                 thisDemandMgrList.AverageDemand,
     457              :                                 OutputProcessor::TimeStepType::Zone,
     458              :                                 OutputProcessor::StoreType::Average,
     459            6 :                                 thisDemandMgrList.Name);
     460              : 
     461           12 :             SetupOutputVariable(state,
     462              :                                 "Demand Manager Peak Demand Power",
     463              :                                 Constant::Units::W,
     464            6 :                                 thisDemandMgrList.PeakDemand,
     465              :                                 OutputProcessor::TimeStepType::Zone,
     466              :                                 OutputProcessor::StoreType::Average,
     467            6 :                                 thisDemandMgrList.Name);
     468              : 
     469           12 :             SetupOutputVariable(state,
     470              :                                 "Demand Manager Scheduled Limit Power",
     471              :                                 Constant::Units::W,
     472            6 :                                 thisDemandMgrList.ScheduledLimit,
     473              :                                 OutputProcessor::TimeStepType::Zone,
     474              :                                 OutputProcessor::StoreType::Average,
     475            6 :                                 thisDemandMgrList.Name);
     476              : 
     477           12 :             SetupOutputVariable(state,
     478              :                                 "Demand Manager Demand Limit Power",
     479              :                                 Constant::Units::W,
     480            6 :                                 thisDemandMgrList.DemandLimit,
     481              :                                 OutputProcessor::TimeStepType::Zone,
     482              :                                 OutputProcessor::StoreType::Average,
     483            6 :                                 thisDemandMgrList.Name);
     484              : 
     485           12 :             SetupOutputVariable(state,
     486              :                                 "Demand Manager Over Limit Power",
     487              :                                 Constant::Units::W,
     488            6 :                                 thisDemandMgrList.OverLimit,
     489              :                                 OutputProcessor::TimeStepType::Zone,
     490              :                                 OutputProcessor::StoreType::Average,
     491            6 :                                 thisDemandMgrList.Name);
     492              : 
     493           12 :             SetupOutputVariable(state,
     494              :                                 "Demand Manager Over Limit Time",
     495              :                                 Constant::Units::hr,
     496            6 :                                 thisDemandMgrList.OverLimitDuration,
     497              :                                 OutputProcessor::TimeStepType::Zone,
     498              :                                 OutputProcessor::StoreType::Sum,
     499            6 :                                 thisDemandMgrList.Name);
     500              : 
     501            6 :             if (ErrorsFound) {
     502            0 :                 ShowFatalError(state, format("Errors found in processing input for {}.", cCurrentModuleObject));
     503              :             }
     504              : 
     505              :         } // ListNum
     506              : 
     507              :         // Iteration diagnostic reporting for all DEMAND MANAGER LISTs
     508           18 :         SetupOutputVariable(state,
     509              :                             "Demand Manager Exterior Energy Iteration Count",
     510              :                             Constant::Units::None,
     511            6 :                             state.dataDemandManager->DemandManagerExtIterations,
     512              :                             OutputProcessor::TimeStepType::Zone,
     513              :                             OutputProcessor::StoreType::Sum,
     514              :                             "ManageDemand");
     515              : 
     516           18 :         SetupOutputVariable(state,
     517              :                             "Demand Manager Heat Balance Iteration Count",
     518              :                             Constant::Units::None,
     519            6 :                             state.dataDemandManager->DemandManagerHBIterations,
     520              :                             OutputProcessor::TimeStepType::Zone,
     521              :                             OutputProcessor::StoreType::Sum,
     522              :                             "ManageDemand");
     523              : 
     524           18 :         SetupOutputVariable(state,
     525              :                             "Demand Manager HVAC Iteration Count",
     526              :                             Constant::Units::None,
     527            6 :                             state.dataDemandManager->DemandManagerHVACIterations,
     528              :                             OutputProcessor::TimeStepType::Zone,
     529              :                             OutputProcessor::StoreType::Sum,
     530              :                             "ManageDemand");
     531              :     }
     532          800 : }
     533              : 
     534          800 : void GetDemandManagerInput(EnergyPlusData &state)
     535              : {
     536              : 
     537              :     // SUBROUTINE INFORMATION:
     538              :     //       AUTHOR         Peter Graham Ellis
     539              :     //       DATE WRITTEN   July 2005
     540              :     //       MODIFIED       MODIFIED       Simon Vidanovic (March 2015) - Introduced DemandManager:Ventilation
     541              : 
     542              :     // PURPOSE OF THIS SUBROUTINE:
     543              :     // Gets the DEMAND MANAGER input from the input file.
     544              : 
     545              :     static constexpr std::string_view routineName = "GetDemandManagerInput";
     546              : 
     547          800 :     auto &s_ipsc = state.dataIPShortCut;
     548          800 :     auto const &s_ip = state.dataInputProcessing->inputProcessor;
     549              : 
     550              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     551              :     int NumAlphas;            // Number of elements in the alpha array
     552              :     int NumNums;              // Number of elements in the numeric array
     553              :     int NumParams;            // Number of arguments total in an ObjectDef
     554          800 :     Array1D_string AlphArray; // Character string data
     555          800 :     Array1D<Real64> NumArray; // Numeric data
     556          800 :     bool ErrorsFound(false);
     557              : 
     558          800 :     int MaxAlphas = 0;
     559          800 :     int MaxNums = 0;
     560          800 :     std::string CurrentModuleObject = "DemandManager:ExteriorLights";
     561          800 :     int NumDemandMgrExtLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     562          800 :     if (NumDemandMgrExtLights > 0) {
     563            5 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     564            5 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     565            5 :         MaxNums = max(MaxNums, NumNums);
     566              :     }
     567          800 :     CurrentModuleObject = "DemandManager:Lights";
     568          800 :     int NumDemandMgrLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     569          800 :     if (NumDemandMgrLights > 0) {
     570            6 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     571            6 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     572            6 :         MaxNums = max(MaxNums, NumNums);
     573              :     }
     574          800 :     CurrentModuleObject = "DemandManager:ElectricEquipment";
     575          800 :     int NumDemandMgrElecEquip = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     576          800 :     if (NumDemandMgrElecEquip > 0) {
     577            5 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     578            5 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     579            5 :         MaxNums = max(MaxNums, NumNums);
     580              :     }
     581          800 :     CurrentModuleObject = "DemandManager:Thermostats";
     582          800 :     int NumDemandMgrThermostats = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     583          800 :     if (NumDemandMgrThermostats > 0) {
     584            5 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     585            5 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     586            5 :         MaxNums = max(MaxNums, NumNums);
     587              :     }
     588          800 :     CurrentModuleObject = "DemandManager:Ventilation";
     589          800 :     int NumDemandMgrVentilation = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     590          800 :     if (NumDemandMgrVentilation > 0) {
     591            5 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     592            5 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     593            5 :         MaxNums = max(MaxNums, NumNums);
     594              :     }
     595              : 
     596         1600 :     state.dataDemandManager->NumDemandMgr =
     597          800 :         NumDemandMgrExtLights + NumDemandMgrLights + NumDemandMgrElecEquip + NumDemandMgrThermostats + NumDemandMgrVentilation;
     598              : 
     599          800 :     auto &DemandMgr(state.dataDemandManager->DemandMgr);
     600              : 
     601          800 :     if (state.dataDemandManager->NumDemandMgr > 0) {
     602            6 :         AlphArray.dimension(MaxAlphas, std::string());
     603            6 :         NumArray.dimension(MaxNums, 0.0);
     604              :         int IOStat; // IO Status when calling get input subroutine
     605              : 
     606            6 :         DemandMgr.allocate(state.dataDemandManager->NumDemandMgr);
     607            6 :         state.dataDemandManager->UniqueDemandMgrNames.reserve(state.dataDemandManager->NumDemandMgr);
     608              : 
     609              :         // Get input for DemandManager:ExteriorLights
     610            6 :         int StartIndex = 1;
     611            6 :         int EndIndex = NumDemandMgrExtLights;
     612              : 
     613            6 :         CurrentModuleObject = "DemandManager:ExteriorLights";
     614              : 
     615           11 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     616            5 :             auto &demandMgr = DemandMgr(MgrNum);
     617              : 
     618           15 :             s_ip->getObjectItem(state,
     619              :                                 CurrentModuleObject,
     620            5 :                                 MgrNum - StartIndex + 1,
     621              :                                 AlphArray,
     622              :                                 NumAlphas,
     623              :                                 NumArray,
     624              :                                 NumNums,
     625              :                                 IOStat,
     626              :                                 _,
     627            5 :                                 s_ipsc->lAlphaFieldBlanks,
     628            5 :                                 s_ipsc->cAlphaFieldNames,
     629            5 :                                 s_ipsc->cNumericFieldNames);
     630              : 
     631            5 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     632              : 
     633            5 :             GlobalNames::VerifyUniqueInterObjectName(
     634           10 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     635            5 :             demandMgr.Name = AlphArray(1);
     636              : 
     637            5 :             demandMgr.Type = ManagerType::ExtLights;
     638              : 
     639            5 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     640            5 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     641            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     642            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     643            0 :                 ErrorsFound = true;
     644              :             }
     645              : 
     646              :             // Validate Limiting Control
     647            5 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     648            5 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     649              : 
     650            5 :             if (NumArray(1) == 0.0) {
     651            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     652              :             } else {
     653            5 :                 demandMgr.LimitDuration = NumArray(1);
     654              :             }
     655              : 
     656            5 :             demandMgr.LowerLimit = NumArray(2);
     657              : 
     658              :             // Validate Selection Control
     659            5 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     660            5 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     661              : 
     662            5 :             if (NumArray(4) == 0.0) {
     663            5 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     664              :             } else {
     665            0 :                 demandMgr.RotationDuration = NumArray(4);
     666              :             }
     667              : 
     668            5 :             demandMgr.NumOfLoads = NumAlphas - 4;
     669              : 
     670            5 :             if (demandMgr.NumOfLoads > 0) {
     671            5 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     672              : 
     673           10 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
     674            5 :                     int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataExteriorEnergyUse->ExteriorLights);
     675              : 
     676            5 :                     if (LoadPtr > 0) {
     677            5 :                         demandMgr.Load(LoadNum) = LoadPtr;
     678              : 
     679              :                     } else {
     680            0 :                         ShowSevereError(state,
     681            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     682              :                                                CurrentModuleObject,
     683            0 :                                                s_ipsc->cAlphaArgs(1),
     684            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     685              :                                                AlphArray(LoadNum + 4)));
     686            0 :                         ErrorsFound = true;
     687              :                     }
     688              :                 } // LoadNum
     689              :             } else {
     690            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     691            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     692            0 :                 ErrorsFound = true;
     693              :             }
     694              : 
     695              :         } // MgrNum
     696              : 
     697              :         // Get input for DemandManager:Lights
     698            6 :         StartIndex = EndIndex + 1;
     699            6 :         EndIndex += NumDemandMgrLights;
     700              : 
     701            6 :         CurrentModuleObject = "DemandManager:Lights";
     702              : 
     703           12 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     704            6 :             auto &demandMgr = DemandMgr(MgrNum);
     705              : 
     706           18 :             s_ip->getObjectItem(state,
     707              :                                 CurrentModuleObject,
     708            6 :                                 MgrNum - StartIndex + 1,
     709              :                                 AlphArray,
     710              :                                 NumAlphas,
     711              :                                 NumArray,
     712              :                                 NumNums,
     713              :                                 IOStat,
     714              :                                 _,
     715            6 :                                 s_ipsc->lAlphaFieldBlanks,
     716            6 :                                 s_ipsc->cAlphaFieldNames,
     717            6 :                                 s_ipsc->cNumericFieldNames);
     718              : 
     719            6 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     720            6 :             GlobalNames::VerifyUniqueInterObjectName(
     721           12 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     722            6 :             demandMgr.Name = AlphArray(1);
     723              : 
     724            6 :             demandMgr.Type = ManagerType::Lights;
     725              : 
     726            6 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     727            6 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     728            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     729            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     730            0 :                 ErrorsFound = true;
     731              :             }
     732              : 
     733              :             // Validate Limiting Control
     734            6 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     735            6 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     736              : 
     737            6 :             if (NumArray(1) == 0.0) {
     738            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     739              :             } else {
     740            6 :                 demandMgr.LimitDuration = NumArray(1);
     741              :             }
     742              : 
     743            6 :             demandMgr.LowerLimit = NumArray(2);
     744              : 
     745              :             // Validate Selection Control
     746            6 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     747            6 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     748              : 
     749            6 :             if (NumArray(4) == 0.0) {
     750            6 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     751              :             } else {
     752            0 :                 demandMgr.RotationDuration = NumArray(4);
     753              :             }
     754              : 
     755              :             // Count actual pointers to controlled zones
     756            6 :             demandMgr.NumOfLoads = 0;
     757           12 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     758            6 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->lightsObjects);
     759            6 :                 if (LoadPtr > 0) {
     760            6 :                     demandMgr.NumOfLoads += state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces;
     761              :                 } else {
     762            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->Lights);
     763            0 :                     if (LoadPtr > 0) {
     764            0 :                         ++demandMgr.NumOfLoads;
     765              :                     } else {
     766            0 :                         ShowSevereError(state,
     767            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     768              :                                                CurrentModuleObject,
     769            0 :                                                s_ipsc->cAlphaArgs(1),
     770            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     771              :                                                AlphArray(LoadNum + 4)));
     772            0 :                         ErrorsFound = true;
     773              :                     }
     774              :                 }
     775              :             }
     776              : 
     777              :             //      demandMgr%NumOfLoads = NumAlphas - 4
     778              : 
     779            6 :             if (demandMgr.NumOfLoads > 0) {
     780            6 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     781            6 :                 int LoadNum = 0;
     782           12 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     783            6 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->lightsObjects);
     784            6 :                     if (LoadPtr > 0) {
     785           36 :                         for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces; ++Item1) {
     786           30 :                             ++LoadNum;
     787           30 :                             demandMgr.Load(LoadNum) = state.dataInternalHeatGains->lightsObjects(LoadPtr).spaceStartPtr + Item1 - 1;
     788              :                         }
     789              :                     } else {
     790            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->Lights);
     791            0 :                         if (LoadPtr > 0) {
     792            0 :                             ++LoadNum;
     793            0 :                             demandMgr.Load(LoadNum) = LoadPtr;
     794              :                         }
     795              :                     }
     796              :                 } // LoadNum
     797              :             } else {
     798            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     799            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     800            0 :                 ErrorsFound = true;
     801              :             }
     802              : 
     803              :         } // MgrNum
     804              : 
     805              :         // Get input for DemandManager:ElectricEquipment
     806            6 :         StartIndex = EndIndex + 1;
     807            6 :         EndIndex += NumDemandMgrElecEquip;
     808              : 
     809            6 :         CurrentModuleObject = "DemandManager:ElectricEquipment";
     810              : 
     811           21 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     812           15 :             auto &demandMgr = DemandMgr(MgrNum);
     813              : 
     814           45 :             s_ip->getObjectItem(state,
     815              :                                 CurrentModuleObject,
     816           15 :                                 MgrNum - StartIndex + 1,
     817              :                                 AlphArray,
     818              :                                 NumAlphas,
     819              :                                 NumArray,
     820              :                                 NumNums,
     821              :                                 IOStat,
     822              :                                 _,
     823           15 :                                 s_ipsc->lAlphaFieldBlanks,
     824           15 :                                 s_ipsc->cAlphaFieldNames,
     825           15 :                                 s_ipsc->cNumericFieldNames);
     826              : 
     827           15 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     828           15 :             GlobalNames::VerifyUniqueInterObjectName(
     829           30 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     830              : 
     831           15 :             demandMgr.Name = AlphArray(1);
     832              : 
     833           15 :             demandMgr.Type = ManagerType::ElecEquip;
     834              : 
     835           15 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     836           15 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     837            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     838            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     839            0 :                 ErrorsFound = true;
     840              :             }
     841              : 
     842              :             // Validate Limiting Control
     843           15 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     844           15 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     845              : 
     846           15 :             if (NumArray(1) == 0.0) {
     847            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     848              :             } else {
     849           15 :                 demandMgr.LimitDuration = NumArray(1);
     850              :             }
     851              : 
     852           15 :             demandMgr.LowerLimit = NumArray(2);
     853              : 
     854              :             // Validate Selection Control
     855           15 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     856           15 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     857              : 
     858           15 :             if (NumArray(4) == 0.0) {
     859           15 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     860              :             } else {
     861            0 :                 demandMgr.RotationDuration = NumArray(4);
     862              :             }
     863              : 
     864              :             // Count actual pointers to controlled zones
     865           15 :             demandMgr.NumOfLoads = 0;
     866           30 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     867           15 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->zoneElectricObjects);
     868           15 :                 if (LoadPtr > 0) {
     869            0 :                     demandMgr.NumOfLoads += state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces;
     870              :                 } else {
     871           15 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->ZoneElectric);
     872           15 :                     if (LoadPtr > 0) {
     873           15 :                         ++demandMgr.NumOfLoads;
     874              :                     } else {
     875            0 :                         ShowSevereError(state,
     876            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     877              :                                                CurrentModuleObject,
     878            0 :                                                s_ipsc->cAlphaArgs(1),
     879            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     880              :                                                AlphArray(LoadNum + 4)));
     881            0 :                         ErrorsFound = true;
     882              :                     }
     883              :                 }
     884              :             }
     885              : 
     886              :             //      demandMgr%NumOfLoads = NumAlphas - 4
     887              : 
     888           15 :             if (demandMgr.NumOfLoads > 0) {
     889           15 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     890           15 :                 int LoadNum = 0;
     891           30 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     892           15 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->zoneElectricObjects);
     893           15 :                     if (LoadPtr > 0) {
     894            0 :                         for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces; ++Item1) {
     895            0 :                             ++LoadNum;
     896            0 :                             demandMgr.Load(LoadNum) = state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).spaceStartPtr + Item1 - 1;
     897              :                         }
     898              :                     } else {
     899           15 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->ZoneElectric);
     900           15 :                         if (LoadPtr > 0) {
     901           15 :                             ++LoadNum;
     902           15 :                             demandMgr.Load(LoadNum) = LoadPtr;
     903              :                         }
     904              :                     }
     905              :                 } // LoadNum
     906              :             } else {
     907            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     908            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     909            0 :                 ErrorsFound = true;
     910              :             }
     911              : 
     912              :         } // MgrNum
     913              : 
     914              :         // Get input for DemandManager:Thermostats
     915            6 :         StartIndex = EndIndex + 1;
     916            6 :         EndIndex += NumDemandMgrThermostats;
     917              : 
     918            6 :         CurrentModuleObject = "DemandManager:Thermostats";
     919              : 
     920           11 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     921            5 :             auto &demandMgr = DemandMgr(MgrNum);
     922              : 
     923           15 :             s_ip->getObjectItem(state,
     924              :                                 CurrentModuleObject,
     925            5 :                                 MgrNum - StartIndex + 1,
     926              :                                 AlphArray,
     927              :                                 NumAlphas,
     928              :                                 NumArray,
     929              :                                 NumNums,
     930              :                                 IOStat,
     931              :                                 _,
     932            5 :                                 s_ipsc->lAlphaFieldBlanks,
     933            5 :                                 s_ipsc->cAlphaFieldNames,
     934            5 :                                 s_ipsc->cNumericFieldNames);
     935              : 
     936            5 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     937              : 
     938            5 :             GlobalNames::VerifyUniqueInterObjectName(
     939           10 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     940            5 :             demandMgr.Name = AlphArray(1);
     941              : 
     942            5 :             demandMgr.Type = ManagerType::Thermostats;
     943              : 
     944            5 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     945            5 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     946            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     947            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     948            0 :                 ErrorsFound = true;
     949              :             }
     950              : 
     951              :             // Validate Limiting Control
     952            5 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     953            5 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     954              : 
     955            5 :             if (NumArray(1) == 0.0) {
     956            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     957              :             } else {
     958            5 :                 demandMgr.LimitDuration = NumArray(1);
     959              :             }
     960              : 
     961            5 :             demandMgr.LowerLimit = NumArray(2);
     962            5 :             demandMgr.UpperLimit = NumArray(3);
     963              : 
     964            5 :             if (demandMgr.LowerLimit > demandMgr.UpperLimit) {
     965            0 :                 ShowSevereError(state, format("Invalid input for {} = {}", CurrentModuleObject, AlphArray(1)));
     966            0 :                 ShowContinueError(
     967              :                     state,
     968            0 :                     format("{} [{:.2R}] > {} [{:.2R}]", s_ipsc->cNumericFieldNames(2), NumArray(2), s_ipsc->cNumericFieldNames(3), NumArray(3)));
     969            0 :                 ShowContinueError(state, format("{} cannot be greater than {}", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3)));
     970            0 :                 ErrorsFound = true;
     971              :             }
     972              : 
     973              :             // Validate Selection Control
     974            5 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     975            5 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     976              : 
     977            5 :             if (NumArray(5) == 0.0) {
     978            5 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     979              :             } else {
     980            0 :                 demandMgr.RotationDuration = NumArray(5);
     981              :             }
     982              : 
     983              :             // Count actual pointers to controlled zones
     984            5 :             demandMgr.NumOfLoads = 0;
     985           10 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     986            5 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TStatObjects);
     987            5 :                 if (LoadPtr > 0) {
     988            5 :                     demandMgr.NumOfLoads += state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones;
     989              :                 } else {
     990            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TempControlledZone);
     991            0 :                     if (LoadPtr > 0) {
     992            0 :                         ++demandMgr.NumOfLoads;
     993              :                     } else {
     994            0 :                         ShowSevereError(state,
     995            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     996              :                                                CurrentModuleObject,
     997            0 :                                                s_ipsc->cAlphaArgs(1),
     998            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     999              :                                                AlphArray(LoadNum + 4)));
    1000            0 :                         ErrorsFound = true;
    1001              :                     }
    1002              :                 }
    1003              :             }
    1004              : 
    1005            5 :             if (demandMgr.NumOfLoads > 0) {
    1006            5 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
    1007            5 :                 int LoadNum = 0;
    1008           10 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
    1009            5 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TStatObjects);
    1010            5 :                     if (LoadPtr > 0) {
    1011           30 :                         for (int Item1 = 1; Item1 <= state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones; ++Item1) {
    1012           25 :                             ++LoadNum;
    1013           25 :                             demandMgr.Load(LoadNum) = state.dataZoneCtrls->TStatObjects(LoadPtr).TempControlledZoneStartPtr + Item1 - 1;
    1014              :                         }
    1015              :                     } else {
    1016            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TempControlledZone);
    1017            0 :                         if (LoadPtr > 0) {
    1018            0 :                             ++LoadNum;
    1019            0 :                             demandMgr.Load(LoadNum) = LoadPtr;
    1020              :                         }
    1021              :                     }
    1022              :                 } // LoadNum
    1023              :             } else {
    1024            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1025            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
    1026            0 :                 ErrorsFound = true;
    1027              :             }
    1028              :         } // MgrNum
    1029              : 
    1030              :         // Get input for DemandManager:Ventilation
    1031            6 :         StartIndex = EndIndex + 1;
    1032            6 :         EndIndex += NumDemandMgrVentilation;
    1033              : 
    1034            6 :         CurrentModuleObject = "DemandManager:Ventilation";
    1035              : 
    1036           11 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
    1037            5 :             auto &demandMgr = DemandMgr(MgrNum);
    1038              : 
    1039           15 :             s_ip->getObjectItem(state,
    1040              :                                 CurrentModuleObject,
    1041            5 :                                 MgrNum - StartIndex + 1,
    1042              :                                 AlphArray,
    1043              :                                 NumAlphas,
    1044              :                                 NumArray,
    1045              :                                 NumNums,
    1046              :                                 IOStat,
    1047              :                                 _,
    1048            5 :                                 s_ipsc->lAlphaFieldBlanks,
    1049            5 :                                 s_ipsc->cAlphaFieldNames,
    1050            5 :                                 s_ipsc->cNumericFieldNames);
    1051              : 
    1052            5 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
    1053            5 :             GlobalNames::VerifyUniqueInterObjectName(
    1054           10 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
    1055            5 :             demandMgr.Name = AlphArray(1);
    1056              : 
    1057            5 :             demandMgr.Type = ManagerType::Ventilation;
    1058              : 
    1059            5 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
    1060            5 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
    1061            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
    1062            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
    1063            0 :                 ErrorsFound = true;
    1064              :             }
    1065              : 
    1066              :             // Validate Limiting Control
    1067            5 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitVentNamesUC, Util::makeUPPER(AlphArray(3))));
    1068            5 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
    1069              : 
    1070            5 :             demandMgr.LimitDuration = (NumArray(1) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(1);
    1071              : 
    1072            5 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) {
    1073            2 :                 demandMgr.FixedRate = NumArray(2);
    1074              :             }
    1075            5 :             if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
    1076            3 :                 demandMgr.ReductionRatio = NumArray(3);
    1077              :             }
    1078              : 
    1079            5 :             demandMgr.LowerLimit = NumArray(4);
    1080              : 
    1081              :             // Validate Selection Control
    1082            5 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
    1083            5 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
    1084              : 
    1085            5 :             demandMgr.RotationDuration = (NumArray(5) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(5);
    1086              : 
    1087              :             // Count number of string fields for loading Controller:OutdoorAir names. This number must be increased in case if
    1088              :             // new string field is added or decreased if string fields are removed.
    1089            5 :             int AlphaShift = 4;
    1090              : 
    1091              :             // Count actual pointers to air controllers
    1092            5 :             demandMgr.NumOfLoads = 0;
    1093           10 :             for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1094            5 :                 int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1095            5 :                 if (LoadPtr > 0) {
    1096            5 :                     ++demandMgr.NumOfLoads;
    1097              :                 } else {
    1098            0 :                     ShowSevereError(state,
    1099            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
    1100              :                                            CurrentModuleObject,
    1101            0 :                                            s_ipsc->cAlphaArgs(1),
    1102            0 :                                            s_ipsc->cAlphaFieldNames(LoadNum + AlphaShift),
    1103              :                                            AlphArray(LoadNum + AlphaShift)));
    1104            0 :                     ErrorsFound = true;
    1105              :                 }
    1106              :             }
    1107              : 
    1108            5 :             if (demandMgr.NumOfLoads > 0) {
    1109            5 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
    1110           10 :                 for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1111            5 :                     int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1112            5 :                     if (LoadPtr > 0) {
    1113            5 :                         demandMgr.Load(LoadNum) = LoadPtr;
    1114              :                     }
    1115              :                 }
    1116              :             } else {
    1117            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1118            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
    1119            0 :                 ErrorsFound = true;
    1120              :             }
    1121              :         } // MgrNum
    1122              : 
    1123            6 :         AlphArray.deallocate();
    1124            6 :         NumArray.deallocate();
    1125              :     }
    1126              : 
    1127          800 :     if (ErrorsFound) {
    1128            0 :         ShowFatalError(state, "Errors found in processing input for demand managers. Preceding condition causes termination.");
    1129              :     }
    1130          800 : }
    1131              : 
    1132         1445 : void SurveyDemandManagers(EnergyPlusData &state)
    1133              : {
    1134              : 
    1135              :     // SUBROUTINE INFORMATION:
    1136              :     //       AUTHOR         Peter Graham Ellis
    1137              :     //       DATE WRITTEN   July 2005
    1138              : 
    1139              :     // PURPOSE OF THIS SUBROUTINE:
    1140              :     // Checks to see if any demand managers can reduce the load
    1141              : 
    1142              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1143              :     bool CanReduceDemand;
    1144              : 
    1145        10260 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1146              : 
    1147         8815 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1148              : 
    1149         8815 :         demandMgr.CanReduceDemand = false;
    1150              : 
    1151         8815 :         if (!demandMgr.Available) {
    1152            0 :             continue;
    1153              :         }
    1154         8815 :         if (demandMgr.LimitControl == ManagerLimit::Off) {
    1155            0 :             continue;
    1156              :         }
    1157              : 
    1158         8815 :         if (demandMgr.Active) {
    1159         1788 :             continue; // This works for FIXED control action, but not VARIABLE
    1160              :         }
    1161              :         // VARIABLE control could actually reduce demand farther, even if active already
    1162              : 
    1163        11467 :         for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1164        10579 :             int LoadPtr = demandMgr.Load(LoadNum);
    1165              : 
    1166              :             // Check if this load can reduce demand
    1167              :             // Assume FIXED control action for now, needs more sophisticated check for VARIABLE control
    1168        10579 :             LoadInterface(state, DemandAction::CheckCanReduce, MgrNum, LoadPtr, CanReduceDemand);
    1169              : 
    1170        10579 :             if (CanReduceDemand) {
    1171         6139 :                 demandMgr.CanReduceDemand = true;
    1172         6139 :                 break; // If any one load can reduce demand, then the whole demand manager can reduce demand
    1173              :             }
    1174              : 
    1175              :         } // LoadNum
    1176              : 
    1177              :     } // MgrNum
    1178         1445 : }
    1179              : 
    1180         1445 : void ActivateDemandManagers(EnergyPlusData &state)
    1181              : {
    1182              : 
    1183              :     // SUBROUTINE INFORMATION:
    1184              :     //       AUTHOR         Peter Graham Ellis
    1185              :     //       DATE WRITTEN   July 2005
    1186              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1187              :     int LoadPtr;
    1188              : 
    1189        10260 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1190              : 
    1191         8815 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1192              : 
    1193         8815 :         if (demandMgr.Activate) {
    1194              :             bool CanReduceDemand;
    1195          293 :             demandMgr.Activate = false;
    1196          293 :             demandMgr.Active = true;
    1197              : 
    1198          293 :             switch (demandMgr.SelectionControl) {
    1199          293 :             case ManagerSelection::All: {
    1200              :                 // Turn ON limiting on all loads
    1201          790 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1202          497 :                     LoadPtr = demandMgr.Load(LoadNum);
    1203          497 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1204              :                 } // LoadNum
    1205              : 
    1206          293 :             } break;
    1207            0 :             case ManagerSelection::Many: { // All loads are limited except for one
    1208            0 :                 if (demandMgr.NumOfLoads > 1) {
    1209              : 
    1210              :                     // Turn ON limiting on all loads
    1211            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1212            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1213            0 :                         LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1214              :                     } // LoadNum
    1215              : 
    1216              :                     // Set next rotated load (from last time it was active)
    1217            0 :                     int RotatedLoadNum = demandMgr.RotatedLoadNum;
    1218            0 :                     ++RotatedLoadNum;
    1219            0 :                     if (RotatedLoadNum > demandMgr.NumOfLoads) {
    1220            0 :                         RotatedLoadNum = 1;
    1221              :                     }
    1222            0 :                     demandMgr.RotatedLoadNum = RotatedLoadNum;
    1223              : 
    1224              :                     // Turn OFF limiting for the new rotated load
    1225            0 :                     LoadPtr = demandMgr.Load(RotatedLoadNum);
    1226            0 :                     LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1227              :                 } else {
    1228              :                     // Turn ON limiting for the one and only load
    1229            0 :                     LoadPtr = demandMgr.Load(1);
    1230            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1231              :                 }
    1232              : 
    1233            0 :             } break;
    1234            0 :             case ManagerSelection::One: { // Only one load is limited
    1235            0 :                 if (demandMgr.NumOfLoads > 1) {
    1236              :                     // Turn OFF limiting on all loads
    1237            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1238            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1239            0 :                         LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1240              :                     } // LoadNum
    1241              : 
    1242              :                     // Set next rotated load (from last time it was active)
    1243            0 :                     int RotatedLoadNum = demandMgr.RotatedLoadNum;
    1244            0 :                     ++RotatedLoadNum;
    1245            0 :                     if (RotatedLoadNum > demandMgr.NumOfLoads) {
    1246            0 :                         RotatedLoadNum = 1;
    1247              :                     }
    1248            0 :                     demandMgr.RotatedLoadNum = RotatedLoadNum;
    1249              : 
    1250              :                     // Turn ON limiting for the new rotated load
    1251            0 :                     LoadPtr = demandMgr.Load(RotatedLoadNum);
    1252            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1253              :                 } else {
    1254              :                     // Turn ON limiting for the one and only load
    1255            0 :                     LoadPtr = demandMgr.Load(1);
    1256            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1257              :                 }
    1258            0 :             } break;
    1259            0 :             default:
    1260            0 :                 break;
    1261              :             }
    1262              :         }
    1263              : 
    1264              :     } // MgrNum
    1265         1445 : }
    1266              : 
    1267      2828212 : void UpdateDemandManagers(EnergyPlusData &state)
    1268              : {
    1269              : 
    1270              :     // SUBROUTINE INFORMATION:
    1271              :     //       AUTHOR         Peter Graham Ellis
    1272              :     //       DATE WRITTEN   July 2005
    1273              : 
    1274              :     // PURPOSE OF THIS SUBROUTINE:
    1275              :     // Expires limits and rotates loads after specified time duration.
    1276              :     // It updates availability flags, expires managers that ended in the last timestep, etc.
    1277              : 
    1278              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1279              :     int LoadPtr;
    1280              :     bool CanReduceDemand;
    1281              :     int RotatedLoadNum;
    1282              : 
    1283      2876596 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1284              : 
    1285        48384 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1286              : 
    1287              :         // Check availability
    1288        48384 :         bool Available = demandMgr.availSched->getCurrentVal() > 0.0;
    1289              : 
    1290        48384 :         demandMgr.Available = Available;
    1291              : 
    1292              :         // Update demand manager status
    1293        48384 :         if (Available) {
    1294              : 
    1295        48384 :             if (demandMgr.Active) {
    1296              : 
    1297         1172 :                 demandMgr.ElapsedTime += state.dataGlobal->MinutesInTimeStep;
    1298              : 
    1299              :                 // Check for expiring limit duration
    1300         1172 :                 if (demandMgr.ElapsedTime >= demandMgr.LimitDuration) {
    1301          293 :                     demandMgr.ElapsedTime = 0;
    1302          293 :                     demandMgr.ElapsedRotationTime = 0;
    1303          293 :                     demandMgr.Active = false;
    1304              : 
    1305              :                     // Demand Manager is not available, remove demand limits from all loads
    1306          790 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1307          497 :                         LoadPtr = demandMgr.Load(LoadNum);
    1308          497 :                         LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1309              :                     } // LoadNum
    1310              : 
    1311              :                 } else {
    1312              : 
    1313          879 :                     switch (demandMgr.SelectionControl) {
    1314          879 :                     case ManagerSelection::All: {
    1315              :                         // Do nothing; limits remain on all loads
    1316              : 
    1317          879 :                     } break;
    1318            0 :                     case ManagerSelection::Many: { // All loads are limited except for one
    1319            0 :                         demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
    1320              : 
    1321            0 :                         if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
    1322            0 :                             demandMgr.ElapsedRotationTime = 0;
    1323              : 
    1324            0 :                             if (demandMgr.NumOfLoads > 1) {
    1325              :                                 // Turn ON limiting for the old rotated load
    1326            0 :                                 RotatedLoadNum = demandMgr.RotatedLoadNum;
    1327            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1328            0 :                                 LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1329              : 
    1330              :                                 // Set next rotated load
    1331            0 :                                 ++RotatedLoadNum;
    1332            0 :                                 if (RotatedLoadNum > demandMgr.NumOfLoads) {
    1333            0 :                                     RotatedLoadNum = 1;
    1334              :                                 }
    1335            0 :                                 demandMgr.RotatedLoadNum = RotatedLoadNum;
    1336              : 
    1337              :                                 // Turn OFF limiting for the new rotated load
    1338            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1339            0 :                                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1340              :                             }
    1341              :                         }
    1342              : 
    1343            0 :                     } break;
    1344            0 :                     case ManagerSelection::One: { // Only one load is limited
    1345            0 :                         demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
    1346              : 
    1347            0 :                         if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
    1348            0 :                             demandMgr.ElapsedRotationTime = 0;
    1349              : 
    1350            0 :                             if (demandMgr.NumOfLoads > 1) {
    1351              :                                 // Turn OFF limiting for the old rotated load
    1352            0 :                                 RotatedLoadNum = demandMgr.RotatedLoadNum;
    1353            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1354            0 :                                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1355              : 
    1356              :                                 // Set next rotated load
    1357            0 :                                 ++RotatedLoadNum;
    1358            0 :                                 if (RotatedLoadNum > demandMgr.NumOfLoads) {
    1359            0 :                                     RotatedLoadNum = 1;
    1360              :                                 }
    1361            0 :                                 demandMgr.RotatedLoadNum = RotatedLoadNum;
    1362              : 
    1363              :                                 // Turn ON limiting for the new rotated load
    1364            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1365            0 :                                 LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1366              :                             }
    1367              :                         }
    1368            0 :                     } break;
    1369            0 :                     default:
    1370            0 :                         break;
    1371              :                     }
    1372              :                 }
    1373              :             }
    1374              : 
    1375              :         } else { // Demand Manager is not available
    1376            0 :             demandMgr.Active = false;
    1377              : 
    1378              :             // Demand Manager is not available, remove demand limits from all loads
    1379            0 :             for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1380            0 :                 LoadPtr = demandMgr.Load(LoadNum);
    1381            0 :                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1382              :             } // LoadNum
    1383              :         }
    1384              : 
    1385              :     } // MgrNum
    1386      2828212 : }
    1387              : 
    1388         1152 : void ReportDemandManagerList(EnergyPlusData &state, int const ListNum)
    1389              : {
    1390              : 
    1391              :     // SUBROUTINE INFORMATION:
    1392              :     //       AUTHOR         Peter Graham Ellis
    1393              :     //       DATE WRITTEN   July 2005
    1394              : 
    1395              :     // PURPOSE OF THIS SUBROUTINE:
    1396              :     // Calculates report variables.
    1397              : 
    1398              :     // METHODOLOGY EMPLOYED:
    1399              :     // Standard EnergyPlus methodology.
    1400              : 
    1401              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1402              :     int AveragingWindow;
    1403              :     bool OnPeak;
    1404              :     Real64 OverLimit;
    1405              : 
    1406         1152 :     auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
    1407              : 
    1408         1152 :     Real64 BillingPeriod = (demandManagerList.billingSched == nullptr) ? state.dataEnvrn->Month : demandManagerList.billingSched->getCurrentVal();
    1409              : 
    1410         1152 :     if (demandManagerList.BillingPeriod != BillingPeriod) {
    1411              :         // Reset variables for new billing period
    1412              :         // demandManagerList%History = 0.0        ! Don't reset--continue from previous billing period
    1413              :         // demandManagerList%AverageDemand = 0.0  ! Don't reset--continue from previous billing period
    1414           12 :         demandManagerList.PeakDemand = 0.0;
    1415           12 :         demandManagerList.OverLimitDuration = 0.0;
    1416              : 
    1417           12 :         demandManagerList.BillingPeriod = BillingPeriod;
    1418              :     }
    1419              : 
    1420              :     // Add new timestep to demand history and subtract oldest timestep
    1421         1152 :     AveragingWindow = demandManagerList.AveragingWindow;
    1422         1152 :     demandManagerList.AverageDemand += (demandManagerList.MeterDemand - demandManagerList.History(1)) / AveragingWindow;
    1423              : 
    1424              :     // Update demand history
    1425         1152 :     for (int Item = 1; Item <= AveragingWindow - 1; ++Item) {
    1426            0 :         demandManagerList.History(Item) = demandManagerList.History(Item + 1);
    1427              :     }
    1428         1152 :     demandManagerList.History(AveragingWindow) = demandManagerList.MeterDemand;
    1429              : 
    1430         1152 :     OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
    1431              : 
    1432         1152 :     if (OnPeak) {
    1433         1152 :         demandManagerList.PeakDemand = max(demandManagerList.AverageDemand, demandManagerList.PeakDemand);
    1434              : 
    1435         1152 :         OverLimit = demandManagerList.AverageDemand - demandManagerList.ScheduledLimit;
    1436         1152 :         if (OverLimit > 0.0) {
    1437           36 :             demandManagerList.OverLimit = OverLimit;
    1438           36 :             demandManagerList.OverLimitDuration += (state.dataGlobal->MinutesInTimeStep / 60.0);
    1439              :         } else {
    1440         1116 :             demandManagerList.OverLimit = 0.0;
    1441              :         }
    1442              : 
    1443              :     } else {
    1444            0 :         demandManagerList.OverLimit = 0.0;
    1445              :     }
    1446         1152 : }
    1447              : 
    1448        11573 : void LoadInterface(EnergyPlusData &state, DemandAction const Action, int const MgrNum, int const LoadPtr, bool &CanReduceDemand)
    1449              : {
    1450              : 
    1451              :     // SUBROUTINE INFORMATION:
    1452              :     //       AUTHOR         Peter Graham Ellis
    1453              :     //       DATE WRITTEN   August 2005
    1454              : 
    1455              :     // PURPOSE OF THIS SUBROUTINE:
    1456              :     // Provides a universal interface to handle all communication with the various load objects.
    1457              :     // Demand managers for new types of loads can be easily added with a new CASE statement in this subroutine
    1458              :     // and new GetInput code.
    1459              : 
    1460        11573 :     auto const &s_dhbf = state.dataHeatBalFanSys;
    1461        11573 :     auto const &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1462              : 
    1463              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1464              :     Real64 LowestPower;
    1465              : 
    1466        11573 :     CanReduceDemand = false;
    1467              : 
    1468        11573 :     switch (demandMgr.Type) {
    1469          938 :     case ManagerType::ExtLights: {
    1470          938 :         LowestPower = state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1471          938 :         if (Action == DemandAction::CheckCanReduce) {
    1472          828 :             if (state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).Power > LowestPower) {
    1473          828 :                 CanReduceDemand = true;
    1474              :             }
    1475          110 :         } else if (Action == DemandAction::SetLimit) {
    1476           55 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = true;
    1477           55 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DemandLimit = LowestPower;
    1478           55 :         } else if (Action == DemandAction::ClearLimit) {
    1479           55 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = false;
    1480              :         }
    1481          938 :     } break;
    1482              : 
    1483         5294 :     case ManagerType::Lights: {
    1484         5294 :         LowestPower = state.dataHeatBal->Lights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1485         5294 :         if (Action == DemandAction::CheckCanReduce) {
    1486         4784 :             if (state.dataHeatBal->Lights(LoadPtr).Power > LowestPower) {
    1487          344 :                 CanReduceDemand = true;
    1488              :             }
    1489          510 :         } else if (Action == DemandAction::SetLimit) {
    1490          255 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = true;
    1491          255 :             state.dataHeatBal->Lights(LoadPtr).DemandLimit = LowestPower;
    1492          255 :         } else if (Action == DemandAction::ClearLimit) {
    1493          255 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = false;
    1494              :         }
    1495         5294 :     } break;
    1496              : 
    1497         3131 :     case ManagerType::ElecEquip: {
    1498         3131 :         LowestPower = state.dataHeatBal->ZoneElectric(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1499         3131 :         if (Action == DemandAction::CheckCanReduce) {
    1500         2841 :             if (state.dataHeatBal->ZoneElectric(LoadPtr).Power > LowestPower) {
    1501         2841 :                 CanReduceDemand = true;
    1502              :             }
    1503          290 :         } else if (Action == DemandAction::SetLimit) {
    1504          145 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = true;
    1505          145 :             state.dataHeatBal->ZoneElectric(LoadPtr).DemandLimit = LowestPower;
    1506          145 :         } else if (Action == DemandAction::ClearLimit) {
    1507          145 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = false;
    1508              :         }
    1509         3131 :     } break;
    1510              : 
    1511         1233 :     case ManagerType::Thermostats: {
    1512         1233 :         auto &tempZone = state.dataZoneCtrls->TempControlledZone(LoadPtr);
    1513         1233 :         auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(tempZone.ActualZoneNum);
    1514         1233 :         if (Action == DemandAction::CheckCanReduce) {
    1515         1233 :             if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit) {
    1516         1233 :                 CanReduceDemand = true; // Heating | Cooling
    1517              :             }
    1518            0 :         } else if (Action == DemandAction::SetLimit) {
    1519            0 :             tempZone.ManageDemand = true;
    1520            0 :             tempZone.HeatingResetLimit = demandMgr.LowerLimit;
    1521            0 :             tempZone.CoolingResetLimit = demandMgr.UpperLimit;
    1522            0 :         } else if (Action == DemandAction::ClearLimit) {
    1523            0 :             tempZone.ManageDemand = false;
    1524              :         }
    1525         1233 :         if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
    1526            0 :             auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(LoadPtr);
    1527            0 :             if (state.dataHeatBalFanSys->ComfortControlType(comfortZone.ActualZoneNum) != HVAC::SetptType::Uncontrolled) {
    1528            0 :                 auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(comfortZone.ActualZoneNum);
    1529            0 :                 if (Action == DemandAction::CheckCanReduce) {
    1530            0 :                     if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit) {
    1531            0 :                         CanReduceDemand = true; // Heating
    1532              :                     }
    1533            0 :                 } else if (Action == DemandAction::SetLimit) {
    1534            0 :                     comfortZone.ManageDemand = true;
    1535            0 :                     comfortZone.HeatingResetLimit = demandMgr.LowerLimit;
    1536            0 :                     comfortZone.CoolingResetLimit = demandMgr.UpperLimit;
    1537            0 :                 } else if (Action == DemandAction::ClearLimit) {
    1538            0 :                     comfortZone.ManageDemand = false;
    1539              :                 }
    1540              :             }
    1541              :         }
    1542         1233 :     } break;
    1543              : 
    1544          977 :     case ManagerType::Ventilation: {
    1545          977 :         Real64 FlowRate(0);
    1546          977 :         FlowRate = MixedAir::OAGetFlowRate(state, LoadPtr);
    1547          977 :         if (Action == DemandAction::CheckCanReduce) {
    1548          893 :             CanReduceDemand = true;
    1549           84 :         } else if (Action == DemandAction::SetLimit) {
    1550           42 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, true);
    1551           42 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) {
    1552           22 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, demandMgr.FixedRate);
    1553           20 :             } else if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
    1554           20 :                 Real64 DemandRate(0);
    1555           20 :                 DemandRate = FlowRate * demandMgr.ReductionRatio;
    1556           20 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, DemandRate);
    1557              :             }
    1558           42 :         } else if (Action == DemandAction::ClearLimit) {
    1559           42 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, false);
    1560              :         }
    1561          977 :     } break;
    1562            0 :     default:
    1563            0 :         break;
    1564              :     }
    1565        11573 : }
    1566              : 
    1567          800 : void InitDemandManagers(EnergyPlusData &state)
    1568              : {
    1569              : 
    1570              :     // SUBROUTINE INFORMATION:
    1571              :     //       AUTHOR         Linda Lawrie
    1572              :     //       DATE WRITTEN   September 2010
    1573              : 
    1574              :     // PURPOSE OF THIS SUBROUTINE:
    1575              :     // Provide external call to get Demand manager input after
    1576              :     // appropriate initializations.
    1577              : 
    1578          800 :     if (state.dataDemandManager->GetInput) {
    1579          800 :         GetDemandManagerInput(state);
    1580          800 :         GetDemandManagerListInput(state);
    1581          800 :         state.dataDemandManager->GetInput = false;
    1582              :     }
    1583          800 : }
    1584              : 
    1585              : } // namespace EnergyPlus::DemandManager
        

Generated by: LCOV version 2.0-1