LCOV - code coverage report
Current view: top level - EnergyPlus - DemandManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 26.8 % 780 209
Test Date: 2025-06-02 12:03:30 Functions: 50.0 % 10 5

            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       164434 : 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       164434 :     if (state.dataDemandManager->GetInput && !state.dataGlobal->DoingSizing) {
     108            0 :         GetDemandManagerInput(state);
     109            0 :         GetDemandManagerListInput(state);
     110            0 :         state.dataDemandManager->GetInput = false;
     111              :     }
     112              : 
     113       164434 :     if (state.dataDemandManager->NumDemandManagerList > 0) {
     114              : 
     115            0 :         if (state.dataGlobal->WarmupFlag) {
     116            0 :             state.dataDemandManager->BeginDemandSim = true;
     117            0 :             if (state.dataDemandManager->ClearHistory) {
     118              :                 // Clear historical variables
     119            0 :                 for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     120            0 :                     state.dataDemandManager->DemandManagerList(ListNum).History = 0.0;
     121            0 :                     state.dataDemandManager->DemandManagerList(ListNum).MeterDemand = 0.0;
     122            0 :                     state.dataDemandManager->DemandManagerList(ListNum).AverageDemand = 0.0;
     123            0 :                     state.dataDemandManager->DemandManagerList(ListNum).PeakDemand = 0.0;
     124            0 :                     state.dataDemandManager->DemandManagerList(ListNum).ScheduledLimit = 0.0;
     125            0 :                     state.dataDemandManager->DemandManagerList(ListNum).DemandLimit = 0.0;
     126            0 :                     state.dataDemandManager->DemandManagerList(ListNum).AvoidedDemand = 0.0;
     127            0 :                     state.dataDemandManager->DemandManagerList(ListNum).OverLimit = 0.0;
     128            0 :                     state.dataDemandManager->DemandManagerList(ListNum).OverLimitDuration = 0.0;
     129              :                 } // ListNum
     130              : 
     131              :                 // Clear demand manager variables
     132            0 :                 for (auto &e : state.dataDemandManager->DemandMgr) {
     133            0 :                     e.Active = false;
     134            0 :                     e.ElapsedTime = 0;
     135            0 :                     e.ElapsedRotationTime = 0;
     136            0 :                     e.RotatedLoadNum = 0;
     137              :                 }
     138              :             }
     139            0 :             state.dataDemandManager->ClearHistory = false;
     140              :         }
     141              : 
     142            0 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing) {
     143              : 
     144            0 :             if (state.dataDemandManager->BeginDemandSim) {
     145            0 :                 state.dataDemandManager->BeginDemandSim = false;
     146            0 :                 state.dataDemandManager->ClearHistory = true;
     147              :             }
     148              : 
     149            0 :             state.dataDemandManager->DemandManagerExtIterations = 0;
     150            0 :             state.dataDemandManager->DemandManagerHBIterations = 0;
     151            0 :             state.dataDemandManager->DemandManagerHVACIterations = 0;
     152              : 
     153            0 :             state.dataDemandManager->firstTime = true;
     154            0 :             state.dataDemandManager->ResimExt = false;
     155            0 :             state.dataDemandManager->ResimHB = false;
     156            0 :             state.dataDemandManager->ResimHVAC = false;
     157              : 
     158            0 :             while (state.dataDemandManager->firstTime || state.dataDemandManager->ResimExt || state.dataDemandManager->ResimHB ||
     159            0 :                    state.dataDemandManager->ResimHVAC) {
     160            0 :                 state.dataDemandManager->firstTime = false;
     161              : 
     162            0 :                 Resimulate(state, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
     163            0 :                 state.dataDemandManager->ResimExt = false;
     164            0 :                 state.dataDemandManager->ResimHB = false;
     165            0 :                 state.dataDemandManager->ResimHVAC = false;
     166              : 
     167            0 :                 SurveyDemandManagers(state); // Determines which Demand Managers can reduce demand
     168              : 
     169            0 :                 for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     170            0 :                     SimulateDemandManagerList(
     171            0 :                         state, ListNum, state.dataDemandManager->ResimExt, state.dataDemandManager->ResimHB, state.dataDemandManager->ResimHVAC);
     172              :                 } // ListNum
     173              : 
     174            0 :                 ActivateDemandManagers(state); // Sets limits on loads
     175              : 
     176            0 :                 if (state.dataDemandManager->DemandManagerExtIterations + state.dataDemandManager->DemandManagerHBIterations +
     177            0 :                         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            0 :             for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     186            0 :                 ReportDemandManagerList(state, ListNum);
     187              :             } // ListNum
     188              :         }
     189              :     }
     190       164434 : }
     191              : 
     192            0 : 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            0 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     207              : 
     208              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     209              :     bool OnPeak;
     210              : 
     211            0 :     auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
     212              : 
     213            0 :     demandManagerList.ScheduledLimit = demandManagerList.limitSched->getCurrentVal();
     214            0 :     demandManagerList.DemandLimit = demandManagerList.ScheduledLimit * demandManagerList.SafetyFraction;
     215              : 
     216            0 :     demandManagerList.MeterDemand =
     217            0 :         GetInstantMeterValue(state, demandManagerList.Meter, OutputProcessor::TimeStepType::Zone) / state.dataGlobal->TimeStepZoneSec +
     218            0 :         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            0 :         demandManagerList.AverageDemand + (demandManagerList.MeterDemand - demandManagerList.History(1)) / demandManagerList.AveragingWindow;
     223              : 
     224            0 :     OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
     225              : 
     226            0 :     if (OnPeak) {
     227            0 :         Real64 OverLimit = AverageDemand - demandManagerList.DemandLimit;
     228              : 
     229            0 :         if (OverLimit > 0.0) {
     230              : 
     231            0 :             switch (demandManagerList.ManagerPriority) {
     232            0 :             case ManagePriorityType::Sequential: { // Activate first Demand Manager that can reduce demand
     233              : 
     234            0 :                 for (int MgrNum = 1; MgrNum <= demandManagerList.NumOfManager; ++MgrNum) {
     235            0 :                     auto &demandMgr = state.dataDemandManager->DemandMgr(demandManagerList.Manager(MgrNum));
     236              : 
     237            0 :                     if (demandMgr.CanReduceDemand) {
     238            0 :                         demandMgr.Activate = true;
     239              : 
     240            0 :                         switch (demandMgr.Type) {
     241            0 :                         case ManagerType::ExtLights: {
     242            0 :                             ResimExt = true;
     243            0 :                         } break;
     244            0 :                         case ManagerType::Lights:
     245              :                         case ManagerType::ElecEquip: {
     246            0 :                             ResimHB = true;
     247            0 :                             ResimHVAC = true;
     248            0 :                         } break;
     249            0 :                         case ManagerType::Thermostats:
     250              :                         case ManagerType::Ventilation: {
     251            0 :                             ResimHVAC = true;
     252            0 :                         } break;
     253            0 :                         default:
     254            0 :                             break;
     255              :                         }
     256              : 
     257            0 :                         break; // Leave the loop
     258              :                     }
     259              :                 } // MgrNum
     260              : 
     261            0 :             } 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            0 : }
     299              : 
     300           74 : 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           74 :     constexpr std::string_view cCurrentModuleObject = "DemandManagerAssignmentList";
     318              : 
     319           74 :     auto &s_ipsc = state.dataIPShortCut;
     320           74 :     auto const &s_ip = state.dataInputProcessing->inputProcessor;
     321              : 
     322           74 :     state.dataDemandManager->NumDemandManagerList = s_ip->getNumObjectsFound(state, cCurrentModuleObject);
     323              : 
     324           74 :     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            1 :         bool ErrorsFound = false;
     329              : 
     330            1 :         state.dataDemandManager->DemandManagerList.allocate(state.dataDemandManager->NumDemandManagerList);
     331              : 
     332            1 :         for (int ListNum = 1; ListNum <= state.dataDemandManager->NumDemandManagerList; ++ListNum) {
     333              : 
     334            1 :             auto &thisDemandMgrList = state.dataDemandManager->DemandManagerList(ListNum);
     335              : 
     336            3 :             s_ip->getObjectItem(state,
     337              :                                 cCurrentModuleObject,
     338              :                                 ListNum,
     339            1 :                                 s_ipsc->cAlphaArgs,
     340              :                                 NumAlphas,
     341            1 :                                 s_ipsc->rNumericArgs,
     342              :                                 NumNums,
     343              :                                 IOStat,
     344              :                                 _,
     345            1 :                                 s_ipsc->lAlphaFieldBlanks,
     346            1 :                                 s_ipsc->cAlphaFieldNames,
     347            1 :                                 s_ipsc->cNumericFieldNames);
     348              : 
     349            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     350              : 
     351            1 :             thisDemandMgrList.Name = s_ipsc->cAlphaArgs(1);
     352              : 
     353            1 :             thisDemandMgrList.Meter = GetMeterIndex(state, s_ipsc->cAlphaArgs(2));
     354              : 
     355            1 :             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            1 :             } 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            1 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
     376            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     377            0 :                 ErrorsFound = true;
     378            1 :             } 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            1 :             thisDemandMgrList.SafetyFraction = s_ipsc->rNumericArgs(1);
     384              : 
     385            1 :             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            1 :             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            1 :             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            1 :             thisDemandMgrList.History.allocate(thisDemandMgrList.AveragingWindow);
     401            1 :             thisDemandMgrList.History = 0.0;
     402              : 
     403              :             // Validate Demand Manager Priority
     404            1 :             thisDemandMgrList.ManagerPriority =
     405            1 :                 static_cast<ManagePriorityType>(getEnumValue(ManagePriorityNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(6))));
     406            1 :             ErrorsFound = ErrorsFound || (thisDemandMgrList.ManagerPriority == ManagePriorityType::Invalid);
     407              : 
     408              :             // Get DEMAND MANAGER Type and Name pairs
     409            1 :             thisDemandMgrList.NumOfManager = int((NumAlphas - 6) / 2.0);
     410              : 
     411            1 :             if (thisDemandMgrList.NumOfManager > 0) {
     412            1 :                 thisDemandMgrList.Manager.allocate(thisDemandMgrList.NumOfManager);
     413            2 :                 for (int MgrNum = 1; MgrNum <= thisDemandMgrList.NumOfManager; ++MgrNum) {
     414              : 
     415            1 :                     auto &thisManager = thisDemandMgrList.Manager(MgrNum);
     416              :                     // Validate DEMAND MANAGER Type
     417            1 :                     ManagerType MgrType = static_cast<ManagerType>(getEnumValue(ManagerNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(MgrNum * 2 + 5))));
     418            1 :                     if (MgrType != ManagerType::Invalid) {
     419            1 :                         thisManager = Util::FindItemInList(s_ipsc->cAlphaArgs(MgrNum * 2 + 6), state.dataDemandManager->DemandMgr);
     420            1 :                         if (thisManager == 0) {
     421            2 :                             ShowSevereError(state,
     422            2 :                                             format("{} = \"{}\" invalid {} = \"{}\" not found.",
     423              :                                                    cCurrentModuleObject,
     424            1 :                                                    thisDemandMgrList.Name,
     425            1 :                                                    s_ipsc->cAlphaFieldNames(MgrNum * 2 + 6),
     426            1 :                                                    s_ipsc->cAlphaArgs(MgrNum * 2 + 6)));
     427            1 :                             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            2 :             SetupOutputVariable(state,
     446              :                                 "Demand Manager Meter Demand Power",
     447              :                                 Constant::Units::W,
     448            1 :                                 thisDemandMgrList.MeterDemand,
     449              :                                 OutputProcessor::TimeStepType::Zone,
     450              :                                 OutputProcessor::StoreType::Average,
     451            1 :                                 thisDemandMgrList.Name);
     452              : 
     453            2 :             SetupOutputVariable(state,
     454              :                                 "Demand Manager Average Demand Power",
     455              :                                 Constant::Units::W,
     456            1 :                                 thisDemandMgrList.AverageDemand,
     457              :                                 OutputProcessor::TimeStepType::Zone,
     458              :                                 OutputProcessor::StoreType::Average,
     459            1 :                                 thisDemandMgrList.Name);
     460              : 
     461            2 :             SetupOutputVariable(state,
     462              :                                 "Demand Manager Peak Demand Power",
     463              :                                 Constant::Units::W,
     464            1 :                                 thisDemandMgrList.PeakDemand,
     465              :                                 OutputProcessor::TimeStepType::Zone,
     466              :                                 OutputProcessor::StoreType::Average,
     467            1 :                                 thisDemandMgrList.Name);
     468              : 
     469            2 :             SetupOutputVariable(state,
     470              :                                 "Demand Manager Scheduled Limit Power",
     471              :                                 Constant::Units::W,
     472            1 :                                 thisDemandMgrList.ScheduledLimit,
     473              :                                 OutputProcessor::TimeStepType::Zone,
     474              :                                 OutputProcessor::StoreType::Average,
     475            1 :                                 thisDemandMgrList.Name);
     476              : 
     477            2 :             SetupOutputVariable(state,
     478              :                                 "Demand Manager Demand Limit Power",
     479              :                                 Constant::Units::W,
     480            1 :                                 thisDemandMgrList.DemandLimit,
     481              :                                 OutputProcessor::TimeStepType::Zone,
     482              :                                 OutputProcessor::StoreType::Average,
     483            1 :                                 thisDemandMgrList.Name);
     484              : 
     485            2 :             SetupOutputVariable(state,
     486              :                                 "Demand Manager Over Limit Power",
     487              :                                 Constant::Units::W,
     488            1 :                                 thisDemandMgrList.OverLimit,
     489              :                                 OutputProcessor::TimeStepType::Zone,
     490              :                                 OutputProcessor::StoreType::Average,
     491            1 :                                 thisDemandMgrList.Name);
     492              : 
     493            2 :             SetupOutputVariable(state,
     494              :                                 "Demand Manager Over Limit Time",
     495              :                                 Constant::Units::hr,
     496            1 :                                 thisDemandMgrList.OverLimitDuration,
     497              :                                 OutputProcessor::TimeStepType::Zone,
     498              :                                 OutputProcessor::StoreType::Sum,
     499            1 :                                 thisDemandMgrList.Name);
     500              : 
     501            1 :             if (ErrorsFound) {
     502            2 :                 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            0 :         SetupOutputVariable(state,
     509              :                             "Demand Manager Exterior Energy Iteration Count",
     510              :                             Constant::Units::None,
     511            0 :                             state.dataDemandManager->DemandManagerExtIterations,
     512              :                             OutputProcessor::TimeStepType::Zone,
     513              :                             OutputProcessor::StoreType::Sum,
     514              :                             "ManageDemand");
     515              : 
     516            0 :         SetupOutputVariable(state,
     517              :                             "Demand Manager Heat Balance Iteration Count",
     518              :                             Constant::Units::None,
     519            0 :                             state.dataDemandManager->DemandManagerHBIterations,
     520              :                             OutputProcessor::TimeStepType::Zone,
     521              :                             OutputProcessor::StoreType::Sum,
     522              :                             "ManageDemand");
     523              : 
     524            0 :         SetupOutputVariable(state,
     525              :                             "Demand Manager HVAC Iteration Count",
     526              :                             Constant::Units::None,
     527            0 :                             state.dataDemandManager->DemandManagerHVACIterations,
     528              :                             OutputProcessor::TimeStepType::Zone,
     529              :                             OutputProcessor::StoreType::Sum,
     530              :                             "ManageDemand");
     531              :     }
     532           73 : }
     533              : 
     534           75 : 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           75 :     auto &s_ipsc = state.dataIPShortCut;
     548           75 :     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           75 :     Array1D_string AlphArray; // Character string data
     555           75 :     Array1D<Real64> NumArray; // Numeric data
     556           75 :     bool ErrorsFound(false);
     557              : 
     558           75 :     int MaxAlphas = 0;
     559           75 :     int MaxNums = 0;
     560           75 :     std::string CurrentModuleObject = "DemandManager:ExteriorLights";
     561           75 :     int NumDemandMgrExtLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     562           75 :     if (NumDemandMgrExtLights > 0) {
     563            1 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     564            1 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     565            1 :         MaxNums = max(MaxNums, NumNums);
     566              :     }
     567           75 :     CurrentModuleObject = "DemandManager:Lights";
     568           75 :     int NumDemandMgrLights = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     569           75 :     if (NumDemandMgrLights > 0) {
     570            0 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     571            0 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     572            0 :         MaxNums = max(MaxNums, NumNums);
     573              :     }
     574           75 :     CurrentModuleObject = "DemandManager:ElectricEquipment";
     575           75 :     int NumDemandMgrElecEquip = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     576           75 :     if (NumDemandMgrElecEquip > 0) {
     577            0 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     578            0 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     579            0 :         MaxNums = max(MaxNums, NumNums);
     580              :     }
     581           75 :     CurrentModuleObject = "DemandManager:Thermostats";
     582           75 :     int NumDemandMgrThermostats = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     583           75 :     if (NumDemandMgrThermostats > 0) {
     584            0 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     585            0 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     586            0 :         MaxNums = max(MaxNums, NumNums);
     587              :     }
     588           75 :     CurrentModuleObject = "DemandManager:Ventilation";
     589           75 :     int NumDemandMgrVentilation = s_ip->getNumObjectsFound(state, CurrentModuleObject);
     590           75 :     if (NumDemandMgrVentilation > 0) {
     591            1 :         s_ip->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     592            1 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     593            1 :         MaxNums = max(MaxNums, NumNums);
     594              :     }
     595              : 
     596          150 :     state.dataDemandManager->NumDemandMgr =
     597           75 :         NumDemandMgrExtLights + NumDemandMgrLights + NumDemandMgrElecEquip + NumDemandMgrThermostats + NumDemandMgrVentilation;
     598              : 
     599           75 :     auto &DemandMgr(state.dataDemandManager->DemandMgr);
     600              : 
     601           75 :     if (state.dataDemandManager->NumDemandMgr > 0) {
     602            2 :         AlphArray.dimension(MaxAlphas, std::string());
     603            2 :         NumArray.dimension(MaxNums, 0.0);
     604              :         int IOStat; // IO Status when calling get input subroutine
     605              : 
     606            2 :         DemandMgr.allocate(state.dataDemandManager->NumDemandMgr);
     607            2 :         state.dataDemandManager->UniqueDemandMgrNames.reserve(state.dataDemandManager->NumDemandMgr);
     608              : 
     609              :         // Get input for DemandManager:ExteriorLights
     610            2 :         int StartIndex = 1;
     611            2 :         int EndIndex = NumDemandMgrExtLights;
     612              : 
     613            2 :         CurrentModuleObject = "DemandManager:ExteriorLights";
     614              : 
     615            3 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     616            1 :             auto &demandMgr = DemandMgr(MgrNum);
     617              : 
     618            3 :             s_ip->getObjectItem(state,
     619              :                                 CurrentModuleObject,
     620            1 :                                 MgrNum - StartIndex + 1,
     621              :                                 AlphArray,
     622              :                                 NumAlphas,
     623              :                                 NumArray,
     624              :                                 NumNums,
     625              :                                 IOStat,
     626              :                                 _,
     627            1 :                                 s_ipsc->lAlphaFieldBlanks,
     628            1 :                                 s_ipsc->cAlphaFieldNames,
     629            1 :                                 s_ipsc->cNumericFieldNames);
     630              : 
     631            1 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     632              : 
     633            1 :             GlobalNames::VerifyUniqueInterObjectName(
     634            2 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     635            1 :             demandMgr.Name = AlphArray(1);
     636              : 
     637            1 :             demandMgr.Type = ManagerType::ExtLights;
     638              : 
     639            1 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     640            1 :                 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            1 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     648            1 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     649              : 
     650            1 :             if (NumArray(1) == 0.0) {
     651            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     652              :             } else {
     653            1 :                 demandMgr.LimitDuration = NumArray(1);
     654              :             }
     655              : 
     656            1 :             demandMgr.LowerLimit = NumArray(2);
     657              : 
     658              :             // Validate Selection Control
     659            1 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     660            1 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     661              : 
     662            1 :             if (NumArray(4) == 0.0) {
     663            1 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     664              :             } else {
     665            0 :                 demandMgr.RotationDuration = NumArray(4);
     666              :             }
     667              : 
     668            1 :             demandMgr.NumOfLoads = NumAlphas - 4;
     669              : 
     670            1 :             if (demandMgr.NumOfLoads > 0) {
     671            1 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     672              : 
     673            2 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
     674            1 :                     int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataExteriorEnergyUse->ExteriorLights);
     675              : 
     676            1 :                     if (LoadPtr > 0) {
     677            1 :                         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            2 :         StartIndex = EndIndex + 1;
     699            2 :         EndIndex += NumDemandMgrLights;
     700              : 
     701            2 :         CurrentModuleObject = "DemandManager:Lights";
     702              : 
     703            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     704            0 :             auto &demandMgr = DemandMgr(MgrNum);
     705              : 
     706            0 :             s_ip->getObjectItem(state,
     707              :                                 CurrentModuleObject,
     708            0 :                                 MgrNum - StartIndex + 1,
     709              :                                 AlphArray,
     710              :                                 NumAlphas,
     711              :                                 NumArray,
     712              :                                 NumNums,
     713              :                                 IOStat,
     714              :                                 _,
     715            0 :                                 s_ipsc->lAlphaFieldBlanks,
     716            0 :                                 s_ipsc->cAlphaFieldNames,
     717            0 :                                 s_ipsc->cNumericFieldNames);
     718              : 
     719            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     720            0 :             GlobalNames::VerifyUniqueInterObjectName(
     721            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     722            0 :             demandMgr.Name = AlphArray(1);
     723              : 
     724            0 :             demandMgr.Type = ManagerType::Lights;
     725              : 
     726            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     727            0 :                 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            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     735            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     736              : 
     737            0 :             if (NumArray(1) == 0.0) {
     738            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     739              :             } else {
     740            0 :                 demandMgr.LimitDuration = NumArray(1);
     741              :             }
     742              : 
     743            0 :             demandMgr.LowerLimit = NumArray(2);
     744              : 
     745              :             // Validate Selection Control
     746            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     747            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     748              : 
     749            0 :             if (NumArray(4) == 0.0) {
     750            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     751              :             } else {
     752            0 :                 demandMgr.RotationDuration = NumArray(4);
     753              :             }
     754              : 
     755              :             // Count actual pointers to controlled zones
     756            0 :             demandMgr.NumOfLoads = 0;
     757            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     758            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->lightsObjects);
     759            0 :                 if (LoadPtr > 0) {
     760            0 :                     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            0 :             if (demandMgr.NumOfLoads > 0) {
     780            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     781            0 :                 int LoadNum = 0;
     782            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     783            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->lightsObjects);
     784            0 :                     if (LoadPtr > 0) {
     785            0 :                         for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces; ++Item1) {
     786            0 :                             ++LoadNum;
     787            0 :                             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            2 :         StartIndex = EndIndex + 1;
     807            2 :         EndIndex += NumDemandMgrElecEquip;
     808              : 
     809            2 :         CurrentModuleObject = "DemandManager:ElectricEquipment";
     810              : 
     811            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     812            0 :             auto &demandMgr = DemandMgr(MgrNum);
     813              : 
     814            0 :             s_ip->getObjectItem(state,
     815              :                                 CurrentModuleObject,
     816            0 :                                 MgrNum - StartIndex + 1,
     817              :                                 AlphArray,
     818              :                                 NumAlphas,
     819              :                                 NumArray,
     820              :                                 NumNums,
     821              :                                 IOStat,
     822              :                                 _,
     823            0 :                                 s_ipsc->lAlphaFieldBlanks,
     824            0 :                                 s_ipsc->cAlphaFieldNames,
     825            0 :                                 s_ipsc->cNumericFieldNames);
     826              : 
     827            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     828            0 :             GlobalNames::VerifyUniqueInterObjectName(
     829            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     830              : 
     831            0 :             demandMgr.Name = AlphArray(1);
     832              : 
     833            0 :             demandMgr.Type = ManagerType::ElecEquip;
     834              : 
     835            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     836            0 :                 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            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     844            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     845              : 
     846            0 :             if (NumArray(1) == 0.0) {
     847            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     848              :             } else {
     849            0 :                 demandMgr.LimitDuration = NumArray(1);
     850              :             }
     851              : 
     852            0 :             demandMgr.LowerLimit = NumArray(2);
     853              : 
     854              :             // Validate Selection Control
     855            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     856            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     857              : 
     858            0 :             if (NumArray(4) == 0.0) {
     859            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     860              :             } else {
     861            0 :                 demandMgr.RotationDuration = NumArray(4);
     862              :             }
     863              : 
     864              :             // Count actual pointers to controlled zones
     865            0 :             demandMgr.NumOfLoads = 0;
     866            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     867            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->zoneElectricObjects);
     868            0 :                 if (LoadPtr > 0) {
     869            0 :                     demandMgr.NumOfLoads += state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces;
     870              :                 } else {
     871            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->ZoneElectric);
     872            0 :                     if (LoadPtr > 0) {
     873            0 :                         ++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            0 :             if (demandMgr.NumOfLoads > 0) {
     889            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     890            0 :                 int LoadNum = 0;
     891            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     892            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->zoneElectricObjects);
     893            0 :                     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            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->ZoneElectric);
     900            0 :                         if (LoadPtr > 0) {
     901            0 :                             ++LoadNum;
     902            0 :                             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            2 :         StartIndex = EndIndex + 1;
     916            2 :         EndIndex += NumDemandMgrThermostats;
     917              : 
     918            2 :         CurrentModuleObject = "DemandManager:Thermostats";
     919              : 
     920            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     921            0 :             auto &demandMgr = DemandMgr(MgrNum);
     922              : 
     923            0 :             s_ip->getObjectItem(state,
     924              :                                 CurrentModuleObject,
     925            0 :                                 MgrNum - StartIndex + 1,
     926              :                                 AlphArray,
     927              :                                 NumAlphas,
     928              :                                 NumArray,
     929              :                                 NumNums,
     930              :                                 IOStat,
     931              :                                 _,
     932            0 :                                 s_ipsc->lAlphaFieldBlanks,
     933            0 :                                 s_ipsc->cAlphaFieldNames,
     934            0 :                                 s_ipsc->cNumericFieldNames);
     935              : 
     936            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     937              : 
     938            0 :             GlobalNames::VerifyUniqueInterObjectName(
     939            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     940            0 :             demandMgr.Name = AlphArray(1);
     941              : 
     942            0 :             demandMgr.Type = ManagerType::Thermostats;
     943              : 
     944            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     945            0 :                 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            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     953            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     954              : 
     955            0 :             if (NumArray(1) == 0.0) {
     956            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     957              :             } else {
     958            0 :                 demandMgr.LimitDuration = NumArray(1);
     959              :             }
     960              : 
     961            0 :             demandMgr.LowerLimit = NumArray(2);
     962            0 :             demandMgr.UpperLimit = NumArray(3);
     963              : 
     964            0 :             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            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     975            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     976              : 
     977            0 :             if (NumArray(5) == 0.0) {
     978            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     979              :             } else {
     980            0 :                 demandMgr.RotationDuration = NumArray(5);
     981              :             }
     982              : 
     983              :             // Count actual pointers to controlled zones
     984            0 :             demandMgr.NumOfLoads = 0;
     985            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     986            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TStatObjects);
     987            0 :                 if (LoadPtr > 0) {
     988            0 :                     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            0 :             if (demandMgr.NumOfLoads > 0) {
    1006            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
    1007            0 :                 int LoadNum = 0;
    1008            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
    1009            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TStatObjects);
    1010            0 :                     if (LoadPtr > 0) {
    1011            0 :                         for (int Item1 = 1; Item1 <= state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones; ++Item1) {
    1012            0 :                             ++LoadNum;
    1013            0 :                             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            2 :         StartIndex = EndIndex + 1;
    1032            2 :         EndIndex += NumDemandMgrVentilation;
    1033              : 
    1034            2 :         CurrentModuleObject = "DemandManager:Ventilation";
    1035              : 
    1036            3 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
    1037            1 :             auto &demandMgr = DemandMgr(MgrNum);
    1038              : 
    1039            3 :             s_ip->getObjectItem(state,
    1040              :                                 CurrentModuleObject,
    1041            1 :                                 MgrNum - StartIndex + 1,
    1042              :                                 AlphArray,
    1043              :                                 NumAlphas,
    1044              :                                 NumArray,
    1045              :                                 NumNums,
    1046              :                                 IOStat,
    1047              :                                 _,
    1048            1 :                                 s_ipsc->lAlphaFieldBlanks,
    1049            1 :                                 s_ipsc->cAlphaFieldNames,
    1050            1 :                                 s_ipsc->cNumericFieldNames);
    1051              : 
    1052            1 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
    1053            1 :             GlobalNames::VerifyUniqueInterObjectName(
    1054            2 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
    1055            1 :             demandMgr.Name = AlphArray(1);
    1056              : 
    1057            1 :             demandMgr.Type = ManagerType::Ventilation;
    1058              : 
    1059            1 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
    1060            1 :                 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            1 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitVentNamesUC, Util::makeUPPER(AlphArray(3))));
    1068            1 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
    1069              : 
    1070            1 :             demandMgr.LimitDuration = (NumArray(1) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(1);
    1071              : 
    1072            1 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) {
    1073            1 :                 demandMgr.FixedRate = NumArray(2);
    1074              :             }
    1075            1 :             if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
    1076            0 :                 demandMgr.ReductionRatio = NumArray(3);
    1077              :             }
    1078              : 
    1079            1 :             demandMgr.LowerLimit = NumArray(4);
    1080              : 
    1081              :             // Validate Selection Control
    1082            1 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
    1083            1 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
    1084              : 
    1085            1 :             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            1 :             int AlphaShift = 4;
    1090              : 
    1091              :             // Count actual pointers to air controllers
    1092            1 :             demandMgr.NumOfLoads = 0;
    1093            2 :             for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1094            1 :                 int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1095            1 :                 if (LoadPtr > 0) {
    1096            1 :                     ++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            1 :             if (demandMgr.NumOfLoads > 0) {
    1109            1 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
    1110            2 :                 for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1111            1 :                     int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1112            1 :                     if (LoadPtr > 0) {
    1113            1 :                         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            2 :         AlphArray.deallocate();
    1124            2 :         NumArray.deallocate();
    1125              :     }
    1126              : 
    1127           75 :     if (ErrorsFound) {
    1128            0 :         ShowFatalError(state, "Errors found in processing input for demand managers. Preceding condition causes termination.");
    1129              :     }
    1130           75 : }
    1131              : 
    1132            0 : 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            0 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1146              : 
    1147            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1148              : 
    1149            0 :         demandMgr.CanReduceDemand = false;
    1150              : 
    1151            0 :         if (!demandMgr.Available) {
    1152            0 :             continue;
    1153              :         }
    1154            0 :         if (demandMgr.LimitControl == ManagerLimit::Off) {
    1155            0 :             continue;
    1156              :         }
    1157              : 
    1158            0 :         if (demandMgr.Active) {
    1159            0 :             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            0 :         for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1164            0 :             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            0 :             LoadInterface(state, DemandAction::CheckCanReduce, MgrNum, LoadPtr, CanReduceDemand);
    1169              : 
    1170            0 :             if (CanReduceDemand) {
    1171            0 :                 demandMgr.CanReduceDemand = true;
    1172            0 :                 break; // If any one load can reduce demand, then the whole demand manager can reduce demand
    1173              :             }
    1174              : 
    1175              :         } // LoadNum
    1176              : 
    1177              :     } // MgrNum
    1178            0 : }
    1179              : 
    1180            0 : 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            0 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1190              : 
    1191            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1192              : 
    1193            0 :         if (demandMgr.Activate) {
    1194              :             bool CanReduceDemand;
    1195            0 :             demandMgr.Activate = false;
    1196            0 :             demandMgr.Active = true;
    1197              : 
    1198            0 :             switch (demandMgr.SelectionControl) {
    1199            0 :             case ManagerSelection::All: {
    1200              :                 // Turn ON limiting on all loads
    1201            0 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1202            0 :                     LoadPtr = demandMgr.Load(LoadNum);
    1203            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1204              :                 } // LoadNum
    1205              : 
    1206            0 :             } 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            0 : }
    1266              : 
    1267       248592 : 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       248592 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1284              : 
    1285            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1286              : 
    1287              :         // Check availability
    1288            0 :         bool Available = demandMgr.availSched->getCurrentVal() > 0.0;
    1289              : 
    1290            0 :         demandMgr.Available = Available;
    1291              : 
    1292              :         // Update demand manager status
    1293            0 :         if (Available) {
    1294              : 
    1295            0 :             if (demandMgr.Active) {
    1296              : 
    1297            0 :                 demandMgr.ElapsedTime += state.dataGlobal->MinutesInTimeStep;
    1298              : 
    1299              :                 // Check for expiring limit duration
    1300            0 :                 if (demandMgr.ElapsedTime >= demandMgr.LimitDuration) {
    1301            0 :                     demandMgr.ElapsedTime = 0;
    1302            0 :                     demandMgr.ElapsedRotationTime = 0;
    1303            0 :                     demandMgr.Active = false;
    1304              : 
    1305              :                     // Demand Manager is not available, remove demand limits from all loads
    1306            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1307            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1308            0 :                         LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1309              :                     } // LoadNum
    1310              : 
    1311              :                 } else {
    1312              : 
    1313            0 :                     switch (demandMgr.SelectionControl) {
    1314            0 :                     case ManagerSelection::All: {
    1315              :                         // Do nothing; limits remain on all loads
    1316              : 
    1317            0 :                     } 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       248592 : }
    1387              : 
    1388            0 : 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            0 :     auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
    1407              : 
    1408            0 :     Real64 BillingPeriod = (demandManagerList.billingSched == nullptr) ? state.dataEnvrn->Month : demandManagerList.billingSched->getCurrentVal();
    1409              : 
    1410            0 :     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            0 :         demandManagerList.PeakDemand = 0.0;
    1415            0 :         demandManagerList.OverLimitDuration = 0.0;
    1416              : 
    1417            0 :         demandManagerList.BillingPeriod = BillingPeriod;
    1418              :     }
    1419              : 
    1420              :     // Add new timestep to demand history and subtract oldest timestep
    1421            0 :     AveragingWindow = demandManagerList.AveragingWindow;
    1422            0 :     demandManagerList.AverageDemand += (demandManagerList.MeterDemand - demandManagerList.History(1)) / AveragingWindow;
    1423              : 
    1424              :     // Update demand history
    1425            0 :     for (int Item = 1; Item <= AveragingWindow - 1; ++Item) {
    1426            0 :         demandManagerList.History(Item) = demandManagerList.History(Item + 1);
    1427              :     }
    1428            0 :     demandManagerList.History(AveragingWindow) = demandManagerList.MeterDemand;
    1429              : 
    1430            0 :     OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
    1431              : 
    1432            0 :     if (OnPeak) {
    1433            0 :         demandManagerList.PeakDemand = max(demandManagerList.AverageDemand, demandManagerList.PeakDemand);
    1434              : 
    1435            0 :         OverLimit = demandManagerList.AverageDemand - demandManagerList.ScheduledLimit;
    1436            0 :         if (OverLimit > 0.0) {
    1437            0 :             demandManagerList.OverLimit = OverLimit;
    1438            0 :             demandManagerList.OverLimitDuration += (state.dataGlobal->MinutesInTimeStep / 60.0);
    1439              :         } else {
    1440            0 :             demandManagerList.OverLimit = 0.0;
    1441              :         }
    1442              : 
    1443              :     } else {
    1444            0 :         demandManagerList.OverLimit = 0.0;
    1445              :     }
    1446            0 : }
    1447              : 
    1448            0 : 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            0 :     auto const &s_dhbf = state.dataHeatBalFanSys;
    1461            0 :     auto const &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1462              : 
    1463              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1464              :     Real64 LowestPower;
    1465              : 
    1466            0 :     CanReduceDemand = false;
    1467              : 
    1468            0 :     switch (demandMgr.Type) {
    1469            0 :     case ManagerType::ExtLights: {
    1470            0 :         LowestPower = state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1471            0 :         if (Action == DemandAction::CheckCanReduce) {
    1472            0 :             if (state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).Power > LowestPower) {
    1473            0 :                 CanReduceDemand = true;
    1474              :             }
    1475            0 :         } else if (Action == DemandAction::SetLimit) {
    1476            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = true;
    1477            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DemandLimit = LowestPower;
    1478            0 :         } else if (Action == DemandAction::ClearLimit) {
    1479            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = false;
    1480              :         }
    1481            0 :     } break;
    1482              : 
    1483            0 :     case ManagerType::Lights: {
    1484            0 :         LowestPower = state.dataHeatBal->Lights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1485            0 :         if (Action == DemandAction::CheckCanReduce) {
    1486            0 :             if (state.dataHeatBal->Lights(LoadPtr).Power > LowestPower) {
    1487            0 :                 CanReduceDemand = true;
    1488              :             }
    1489            0 :         } else if (Action == DemandAction::SetLimit) {
    1490            0 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = true;
    1491            0 :             state.dataHeatBal->Lights(LoadPtr).DemandLimit = LowestPower;
    1492            0 :         } else if (Action == DemandAction::ClearLimit) {
    1493            0 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = false;
    1494              :         }
    1495            0 :     } break;
    1496              : 
    1497            0 :     case ManagerType::ElecEquip: {
    1498            0 :         LowestPower = state.dataHeatBal->ZoneElectric(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1499            0 :         if (Action == DemandAction::CheckCanReduce) {
    1500            0 :             if (state.dataHeatBal->ZoneElectric(LoadPtr).Power > LowestPower) {
    1501            0 :                 CanReduceDemand = true;
    1502              :             }
    1503            0 :         } else if (Action == DemandAction::SetLimit) {
    1504            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = true;
    1505            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).DemandLimit = LowestPower;
    1506            0 :         } else if (Action == DemandAction::ClearLimit) {
    1507            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = false;
    1508              :         }
    1509            0 :     } break;
    1510              : 
    1511            0 :     case ManagerType::Thermostats: {
    1512            0 :         auto &tempZone = state.dataZoneCtrls->TempControlledZone(LoadPtr);
    1513            0 :         auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(tempZone.ActualZoneNum);
    1514            0 :         if (Action == DemandAction::CheckCanReduce) {
    1515            0 :             if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit) {
    1516            0 :                 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            0 :         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            0 :     } break;
    1543              : 
    1544            0 :     case ManagerType::Ventilation: {
    1545            0 :         Real64 FlowRate(0);
    1546            0 :         FlowRate = MixedAir::OAGetFlowRate(state, LoadPtr);
    1547            0 :         if (Action == DemandAction::CheckCanReduce) {
    1548            0 :             CanReduceDemand = true;
    1549            0 :         } else if (Action == DemandAction::SetLimit) {
    1550            0 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, true);
    1551            0 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) {
    1552            0 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, demandMgr.FixedRate);
    1553            0 :             } else if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
    1554            0 :                 Real64 DemandRate(0);
    1555            0 :                 DemandRate = FlowRate * demandMgr.ReductionRatio;
    1556            0 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, DemandRate);
    1557              :             }
    1558            0 :         } else if (Action == DemandAction::ClearLimit) {
    1559            0 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, false);
    1560              :         }
    1561            0 :     } break;
    1562            0 :     default:
    1563            0 :         break;
    1564              :     }
    1565            0 : }
    1566              : 
    1567           73 : 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           73 :     if (state.dataDemandManager->GetInput) {
    1579           73 :         GetDemandManagerInput(state);
    1580           73 :         GetDemandManagerListInput(state);
    1581           73 :         state.dataDemandManager->GetInput = false;
    1582              :     }
    1583           73 : }
    1584              : 
    1585              : } // namespace EnergyPlus::DemandManager
        

Generated by: LCOV version 2.0-1