LCOV - code coverage report
Current view: top level - EnergyPlus - DemandManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 27.1 % 768 208
Test Date: 2025-05-22 16:09:37 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            1 :             demandMgr.LowerLimit = NumArray(2);
     656              : 
     657              :             // Validate Selection Control
     658            1 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     659            1 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     660              : 
     661            1 :             if (NumArray(4) == 0.0)
     662            1 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     663              :             else
     664            0 :                 demandMgr.RotationDuration = NumArray(4);
     665              : 
     666            1 :             demandMgr.NumOfLoads = NumAlphas - 4;
     667              : 
     668            1 :             if (demandMgr.NumOfLoads > 0) {
     669            1 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     670              : 
     671            2 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
     672            1 :                     int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataExteriorEnergyUse->ExteriorLights);
     673              : 
     674            1 :                     if (LoadPtr > 0) {
     675            1 :                         demandMgr.Load(LoadNum) = LoadPtr;
     676              : 
     677              :                     } else {
     678            0 :                         ShowSevereError(state,
     679            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     680              :                                                CurrentModuleObject,
     681            0 :                                                s_ipsc->cAlphaArgs(1),
     682            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     683              :                                                AlphArray(LoadNum + 4)));
     684            0 :                         ErrorsFound = true;
     685              :                     }
     686              :                 } // LoadNum
     687              :             } else {
     688            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     689            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     690            0 :                 ErrorsFound = true;
     691              :             }
     692              : 
     693              :         } // MgrNum
     694              : 
     695              :         // Get input for DemandManager:Lights
     696            2 :         StartIndex = EndIndex + 1;
     697            2 :         EndIndex += NumDemandMgrLights;
     698              : 
     699            2 :         CurrentModuleObject = "DemandManager:Lights";
     700              : 
     701            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     702            0 :             auto &demandMgr = DemandMgr(MgrNum);
     703              : 
     704            0 :             s_ip->getObjectItem(state,
     705              :                                 CurrentModuleObject,
     706            0 :                                 MgrNum - StartIndex + 1,
     707              :                                 AlphArray,
     708              :                                 NumAlphas,
     709              :                                 NumArray,
     710              :                                 NumNums,
     711              :                                 IOStat,
     712              :                                 _,
     713            0 :                                 s_ipsc->lAlphaFieldBlanks,
     714            0 :                                 s_ipsc->cAlphaFieldNames,
     715            0 :                                 s_ipsc->cNumericFieldNames);
     716              : 
     717            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     718            0 :             GlobalNames::VerifyUniqueInterObjectName(
     719            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     720            0 :             demandMgr.Name = AlphArray(1);
     721              : 
     722            0 :             demandMgr.Type = ManagerType::Lights;
     723              : 
     724            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     725            0 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     726            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     727            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     728            0 :                 ErrorsFound = true;
     729              :             }
     730              : 
     731              :             // Validate Limiting Control
     732            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     733            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     734              : 
     735            0 :             if (NumArray(1) == 0.0)
     736            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     737              :             else
     738            0 :                 demandMgr.LimitDuration = NumArray(1);
     739              : 
     740            0 :             demandMgr.LowerLimit = NumArray(2);
     741              : 
     742              :             // Validate Selection Control
     743            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     744            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     745              : 
     746            0 :             if (NumArray(4) == 0.0)
     747            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     748              :             else
     749            0 :                 demandMgr.RotationDuration = NumArray(4);
     750              : 
     751              :             // Count actual pointers to controlled zones
     752            0 :             demandMgr.NumOfLoads = 0;
     753            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     754            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->lightsObjects);
     755            0 :                 if (LoadPtr > 0) {
     756            0 :                     demandMgr.NumOfLoads += state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces;
     757              :                 } else {
     758            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->Lights);
     759            0 :                     if (LoadPtr > 0) {
     760            0 :                         ++demandMgr.NumOfLoads;
     761              :                     } else {
     762            0 :                         ShowSevereError(state,
     763            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     764              :                                                CurrentModuleObject,
     765            0 :                                                s_ipsc->cAlphaArgs(1),
     766            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     767              :                                                AlphArray(LoadNum + 4)));
     768            0 :                         ErrorsFound = true;
     769              :                     }
     770              :                 }
     771              :             }
     772              : 
     773              :             //      demandMgr%NumOfLoads = NumAlphas - 4
     774              : 
     775            0 :             if (demandMgr.NumOfLoads > 0) {
     776            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     777            0 :                 int LoadNum = 0;
     778            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     779            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->lightsObjects);
     780            0 :                     if (LoadPtr > 0) {
     781            0 :                         for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->lightsObjects(LoadPtr).numOfSpaces; ++Item1) {
     782            0 :                             ++LoadNum;
     783            0 :                             demandMgr.Load(LoadNum) = state.dataInternalHeatGains->lightsObjects(LoadPtr).spaceStartPtr + Item1 - 1;
     784              :                         }
     785              :                     } else {
     786            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->Lights);
     787            0 :                         if (LoadPtr > 0) {
     788            0 :                             ++LoadNum;
     789            0 :                             demandMgr.Load(LoadNum) = LoadPtr;
     790              :                         }
     791              :                     }
     792              :                 } // LoadNum
     793              :             } else {
     794            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     795            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     796            0 :                 ErrorsFound = true;
     797              :             }
     798              : 
     799              :         } // MgrNum
     800              : 
     801              :         // Get input for DemandManager:ElectricEquipment
     802            2 :         StartIndex = EndIndex + 1;
     803            2 :         EndIndex += NumDemandMgrElecEquip;
     804              : 
     805            2 :         CurrentModuleObject = "DemandManager:ElectricEquipment";
     806              : 
     807            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     808            0 :             auto &demandMgr = DemandMgr(MgrNum);
     809              : 
     810            0 :             s_ip->getObjectItem(state,
     811              :                                 CurrentModuleObject,
     812            0 :                                 MgrNum - StartIndex + 1,
     813              :                                 AlphArray,
     814              :                                 NumAlphas,
     815              :                                 NumArray,
     816              :                                 NumNums,
     817              :                                 IOStat,
     818              :                                 _,
     819            0 :                                 s_ipsc->lAlphaFieldBlanks,
     820            0 :                                 s_ipsc->cAlphaFieldNames,
     821            0 :                                 s_ipsc->cNumericFieldNames);
     822              : 
     823            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     824            0 :             GlobalNames::VerifyUniqueInterObjectName(
     825            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     826              : 
     827            0 :             demandMgr.Name = AlphArray(1);
     828              : 
     829            0 :             demandMgr.Type = ManagerType::ElecEquip;
     830              : 
     831            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     832            0 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     833            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     834            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     835            0 :                 ErrorsFound = true;
     836              :             }
     837              : 
     838              :             // Validate Limiting Control
     839            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     840            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     841              : 
     842            0 :             if (NumArray(1) == 0.0)
     843            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     844              :             else
     845            0 :                 demandMgr.LimitDuration = NumArray(1);
     846              : 
     847            0 :             demandMgr.LowerLimit = NumArray(2);
     848              : 
     849              :             // Validate Selection Control
     850            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     851            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     852              : 
     853            0 :             if (NumArray(4) == 0.0)
     854            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     855              :             else
     856            0 :                 demandMgr.RotationDuration = NumArray(4);
     857              : 
     858              :             // Count actual pointers to controlled zones
     859            0 :             demandMgr.NumOfLoads = 0;
     860            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     861            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataInternalHeatGains->zoneElectricObjects);
     862            0 :                 if (LoadPtr > 0) {
     863            0 :                     demandMgr.NumOfLoads += state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces;
     864              :                 } else {
     865            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataHeatBal->ZoneElectric);
     866            0 :                     if (LoadPtr > 0) {
     867            0 :                         ++demandMgr.NumOfLoads;
     868              :                     } else {
     869            0 :                         ShowSevereError(state,
     870            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     871              :                                                CurrentModuleObject,
     872            0 :                                                s_ipsc->cAlphaArgs(1),
     873            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     874              :                                                AlphArray(LoadNum + 4)));
     875            0 :                         ErrorsFound = true;
     876              :                     }
     877              :                 }
     878              :             }
     879              : 
     880              :             //      demandMgr%NumOfLoads = NumAlphas - 4
     881              : 
     882            0 :             if (demandMgr.NumOfLoads > 0) {
     883            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     884            0 :                 int LoadNum = 0;
     885            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
     886            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataInternalHeatGains->zoneElectricObjects);
     887            0 :                     if (LoadPtr > 0) {
     888            0 :                         for (int Item1 = 1; Item1 <= state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).numOfSpaces; ++Item1) {
     889            0 :                             ++LoadNum;
     890            0 :                             demandMgr.Load(LoadNum) = state.dataInternalHeatGains->zoneElectricObjects(LoadPtr).spaceStartPtr + Item1 - 1;
     891              :                         }
     892              :                     } else {
     893            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataHeatBal->ZoneElectric);
     894            0 :                         if (LoadPtr > 0) {
     895            0 :                             ++LoadNum;
     896            0 :                             demandMgr.Load(LoadNum) = LoadPtr;
     897              :                         }
     898              :                     }
     899              :                 } // LoadNum
     900              :             } else {
     901            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     902            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
     903            0 :                 ErrorsFound = true;
     904              :             }
     905              : 
     906              :         } // MgrNum
     907              : 
     908              :         // Get input for DemandManager:Thermostats
     909            2 :         StartIndex = EndIndex + 1;
     910            2 :         EndIndex += NumDemandMgrThermostats;
     911              : 
     912            2 :         CurrentModuleObject = "DemandManager:Thermostats";
     913              : 
     914            2 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
     915            0 :             auto &demandMgr = DemandMgr(MgrNum);
     916              : 
     917            0 :             s_ip->getObjectItem(state,
     918              :                                 CurrentModuleObject,
     919            0 :                                 MgrNum - StartIndex + 1,
     920              :                                 AlphArray,
     921              :                                 NumAlphas,
     922              :                                 NumArray,
     923              :                                 NumNums,
     924              :                                 IOStat,
     925              :                                 _,
     926            0 :                                 s_ipsc->lAlphaFieldBlanks,
     927            0 :                                 s_ipsc->cAlphaFieldNames,
     928            0 :                                 s_ipsc->cNumericFieldNames);
     929              : 
     930            0 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
     931              : 
     932            0 :             GlobalNames::VerifyUniqueInterObjectName(
     933            0 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
     934            0 :             demandMgr.Name = AlphArray(1);
     935              : 
     936            0 :             demandMgr.Type = ManagerType::Thermostats;
     937              : 
     938            0 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     939            0 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
     940            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
     941            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     942            0 :                 ErrorsFound = true;
     943              :             }
     944              : 
     945              :             // Validate Limiting Control
     946            0 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitNamesUC, Util::makeUPPER(AlphArray(3))));
     947            0 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
     948              : 
     949            0 :             if (NumArray(1) == 0.0)
     950            0 :                 demandMgr.LimitDuration = state.dataGlobal->MinutesInTimeStep;
     951              :             else
     952            0 :                 demandMgr.LimitDuration = NumArray(1);
     953              : 
     954            0 :             demandMgr.LowerLimit = NumArray(2);
     955            0 :             demandMgr.UpperLimit = NumArray(3);
     956              : 
     957            0 :             if (demandMgr.LowerLimit > demandMgr.UpperLimit) {
     958            0 :                 ShowSevereError(state, format("Invalid input for {} = {}", CurrentModuleObject, AlphArray(1)));
     959            0 :                 ShowContinueError(
     960              :                     state,
     961            0 :                     format("{} [{:.2R}] > {} [{:.2R}]", s_ipsc->cNumericFieldNames(2), NumArray(2), s_ipsc->cNumericFieldNames(3), NumArray(3)));
     962            0 :                 ShowContinueError(state, format("{} cannot be greater than {}", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3)));
     963            0 :                 ErrorsFound = true;
     964              :             }
     965              : 
     966              :             // Validate Selection Control
     967            0 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
     968            0 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
     969              : 
     970            0 :             if (NumArray(5) == 0.0)
     971            0 :                 demandMgr.RotationDuration = state.dataGlobal->MinutesInTimeStep;
     972              :             else
     973            0 :                 demandMgr.RotationDuration = NumArray(5);
     974              : 
     975              :             // Count actual pointers to controlled zones
     976            0 :             demandMgr.NumOfLoads = 0;
     977            0 :             for (int LoadNum = 1; LoadNum <= NumAlphas - 4; ++LoadNum) {
     978            0 :                 int LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TStatObjects);
     979            0 :                 if (LoadPtr > 0) {
     980            0 :                     demandMgr.NumOfLoads += state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones;
     981              :                 } else {
     982            0 :                     LoadPtr = Util::FindItemInList(AlphArray(LoadNum + 4), state.dataZoneCtrls->TempControlledZone);
     983            0 :                     if (LoadPtr > 0) {
     984            0 :                         ++demandMgr.NumOfLoads;
     985              :                     } else {
     986            0 :                         ShowSevereError(state,
     987            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" not found.",
     988              :                                                CurrentModuleObject,
     989            0 :                                                s_ipsc->cAlphaArgs(1),
     990            0 :                                                s_ipsc->cAlphaFieldNames(LoadNum + 4),
     991              :                                                AlphArray(LoadNum + 4)));
     992            0 :                         ErrorsFound = true;
     993              :                     }
     994              :                 }
     995              :             }
     996              : 
     997            0 :             if (demandMgr.NumOfLoads > 0) {
     998            0 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
     999            0 :                 int LoadNum = 0;
    1000            0 :                 for (int Item = 1; Item <= NumAlphas - 4; ++Item) {
    1001            0 :                     int LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TStatObjects);
    1002            0 :                     if (LoadPtr > 0) {
    1003            0 :                         for (int Item1 = 1; Item1 <= state.dataZoneCtrls->TStatObjects(LoadPtr).NumOfZones; ++Item1) {
    1004            0 :                             ++LoadNum;
    1005            0 :                             demandMgr.Load(LoadNum) = state.dataZoneCtrls->TStatObjects(LoadPtr).TempControlledZoneStartPtr + Item1 - 1;
    1006              :                         }
    1007              :                     } else {
    1008            0 :                         LoadPtr = Util::FindItemInList(AlphArray(Item + 4), state.dataZoneCtrls->TempControlledZone);
    1009            0 :                         if (LoadPtr > 0) {
    1010            0 :                             ++LoadNum;
    1011            0 :                             demandMgr.Load(LoadNum) = LoadPtr;
    1012              :                         }
    1013              :                     }
    1014              :                 } // LoadNum
    1015              :             } else {
    1016            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1017            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
    1018            0 :                 ErrorsFound = true;
    1019              :             }
    1020              :         } // MgrNum
    1021              : 
    1022              :         // Get input for DemandManager:Ventilation
    1023            2 :         StartIndex = EndIndex + 1;
    1024            2 :         EndIndex += NumDemandMgrVentilation;
    1025              : 
    1026            2 :         CurrentModuleObject = "DemandManager:Ventilation";
    1027              : 
    1028            3 :         for (int MgrNum = StartIndex; MgrNum <= EndIndex; ++MgrNum) {
    1029            1 :             auto &demandMgr = DemandMgr(MgrNum);
    1030              : 
    1031            3 :             s_ip->getObjectItem(state,
    1032              :                                 CurrentModuleObject,
    1033            1 :                                 MgrNum - StartIndex + 1,
    1034              :                                 AlphArray,
    1035              :                                 NumAlphas,
    1036              :                                 NumArray,
    1037              :                                 NumNums,
    1038              :                                 IOStat,
    1039              :                                 _,
    1040            1 :                                 s_ipsc->lAlphaFieldBlanks,
    1041            1 :                                 s_ipsc->cAlphaFieldNames,
    1042            1 :                                 s_ipsc->cNumericFieldNames);
    1043              : 
    1044            1 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
    1045            1 :             GlobalNames::VerifyUniqueInterObjectName(
    1046            2 :                 state, state.dataDemandManager->UniqueDemandMgrNames, AlphArray(1), CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), ErrorsFound);
    1047            1 :             demandMgr.Name = AlphArray(1);
    1048              : 
    1049            1 :             demandMgr.Type = ManagerType::Ventilation;
    1050              : 
    1051            1 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
    1052            1 :                 demandMgr.availSched = Sched::GetScheduleAlwaysOn(state);
    1053            0 :             } else if ((demandMgr.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
    1054            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
    1055            0 :                 ErrorsFound = true;
    1056              :             }
    1057              : 
    1058              :             // Validate Limiting Control
    1059            1 :             demandMgr.LimitControl = static_cast<ManagerLimit>(getEnumValue(ManagerLimitVentNamesUC, Util::makeUPPER(AlphArray(3))));
    1060            1 :             ErrorsFound = ErrorsFound || (demandMgr.LimitControl == ManagerLimit::Invalid);
    1061              : 
    1062            1 :             demandMgr.LimitDuration = (NumArray(1) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(1);
    1063              : 
    1064            1 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) demandMgr.FixedRate = NumArray(2);
    1065            1 :             if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) demandMgr.ReductionRatio = NumArray(3);
    1066              : 
    1067            1 :             demandMgr.LowerLimit = NumArray(4);
    1068              : 
    1069              :             // Validate Selection Control
    1070            1 :             demandMgr.SelectionControl = static_cast<ManagerSelection>(getEnumValue(ManagerSelectionNamesUC, Util::makeUPPER(AlphArray(4))));
    1071            1 :             ErrorsFound = ErrorsFound || (demandMgr.SelectionControl == ManagerSelection::Invalid);
    1072              : 
    1073            1 :             demandMgr.RotationDuration = (NumArray(5) == 0.0) ? state.dataGlobal->MinutesInTimeStep : NumArray(5);
    1074              : 
    1075              :             // Count number of string fields for loading Controller:OutdoorAir names. This number must be increased in case if
    1076              :             // new string field is added or decreased if string fields are removed.
    1077            1 :             int AlphaShift = 4;
    1078              : 
    1079              :             // Count actual pointers to air controllers
    1080            1 :             demandMgr.NumOfLoads = 0;
    1081            2 :             for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1082            1 :                 int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1083            1 :                 if (LoadPtr > 0) {
    1084            1 :                     ++demandMgr.NumOfLoads;
    1085              :                 } else {
    1086            0 :                     ShowSevereError(state,
    1087            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
    1088              :                                            CurrentModuleObject,
    1089            0 :                                            s_ipsc->cAlphaArgs(1),
    1090            0 :                                            s_ipsc->cAlphaFieldNames(LoadNum + AlphaShift),
    1091              :                                            AlphArray(LoadNum + AlphaShift)));
    1092            0 :                     ErrorsFound = true;
    1093              :                 }
    1094              :             }
    1095              : 
    1096            1 :             if (demandMgr.NumOfLoads > 0) {
    1097            1 :                 demandMgr.Load.allocate(demandMgr.NumOfLoads);
    1098            2 :                 for (int LoadNum = 1; LoadNum <= NumAlphas - AlphaShift; ++LoadNum) {
    1099            1 :                     int LoadPtr = MixedAir::GetOAController(state, AlphArray(LoadNum + AlphaShift));
    1100            1 :                     if (LoadPtr > 0) {
    1101            1 :                         demandMgr.Load(LoadNum) = LoadPtr;
    1102              :                     }
    1103              :                 }
    1104              :             } else {
    1105            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid value for number of loads.", CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1106            0 :                 ShowContinueError(state, "Number of loads is calculated to be less than one. Demand manager must have at least one load assigned.");
    1107            0 :                 ErrorsFound = true;
    1108              :             }
    1109              :         } // MgrNum
    1110              : 
    1111            2 :         AlphArray.deallocate();
    1112            2 :         NumArray.deallocate();
    1113              :     }
    1114              : 
    1115           75 :     if (ErrorsFound) {
    1116            0 :         ShowFatalError(state, "Errors found in processing input for demand managers. Preceding condition causes termination.");
    1117              :     }
    1118           75 : }
    1119              : 
    1120            0 : void SurveyDemandManagers(EnergyPlusData &state)
    1121              : {
    1122              : 
    1123              :     // SUBROUTINE INFORMATION:
    1124              :     //       AUTHOR         Peter Graham Ellis
    1125              :     //       DATE WRITTEN   July 2005
    1126              : 
    1127              :     // PURPOSE OF THIS SUBROUTINE:
    1128              :     // Checks to see if any demand managers can reduce the load
    1129              : 
    1130              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1131              :     bool CanReduceDemand;
    1132              : 
    1133            0 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1134              : 
    1135            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1136              : 
    1137            0 :         demandMgr.CanReduceDemand = false;
    1138              : 
    1139            0 :         if (!demandMgr.Available) continue;
    1140            0 :         if (demandMgr.LimitControl == ManagerLimit::Off) continue;
    1141              : 
    1142            0 :         if (demandMgr.Active) continue; // This works for FIXED control action, but not VARIABLE
    1143              :         // VARIABLE control could actually reduce demand farther, even if active already
    1144              : 
    1145            0 :         for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1146            0 :             int LoadPtr = demandMgr.Load(LoadNum);
    1147              : 
    1148              :             // Check if this load can reduce demand
    1149              :             // Assume FIXED control action for now, needs more sophisticated check for VARIABLE control
    1150            0 :             LoadInterface(state, DemandAction::CheckCanReduce, MgrNum, LoadPtr, CanReduceDemand);
    1151              : 
    1152            0 :             if (CanReduceDemand) {
    1153            0 :                 demandMgr.CanReduceDemand = true;
    1154            0 :                 break; // If any one load can reduce demand, then the whole demand manager can reduce demand
    1155              :             }
    1156              : 
    1157              :         } // LoadNum
    1158              : 
    1159              :     } // MgrNum
    1160            0 : }
    1161              : 
    1162            0 : void ActivateDemandManagers(EnergyPlusData &state)
    1163              : {
    1164              : 
    1165              :     // SUBROUTINE INFORMATION:
    1166              :     //       AUTHOR         Peter Graham Ellis
    1167              :     //       DATE WRITTEN   July 2005
    1168              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1169              :     int LoadPtr;
    1170              : 
    1171            0 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1172              : 
    1173            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1174              : 
    1175            0 :         if (demandMgr.Activate) {
    1176              :             bool CanReduceDemand;
    1177            0 :             demandMgr.Activate = false;
    1178            0 :             demandMgr.Active = true;
    1179              : 
    1180            0 :             switch (demandMgr.SelectionControl) {
    1181            0 :             case ManagerSelection::All: {
    1182              :                 // Turn ON limiting on all loads
    1183            0 :                 for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1184            0 :                     LoadPtr = demandMgr.Load(LoadNum);
    1185            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1186              :                 } // LoadNum
    1187              : 
    1188            0 :             } break;
    1189            0 :             case ManagerSelection::Many: { // All loads are limited except for one
    1190            0 :                 if (demandMgr.NumOfLoads > 1) {
    1191              : 
    1192              :                     // Turn ON limiting on all loads
    1193            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1194            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1195            0 :                         LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1196              :                     } // LoadNum
    1197              : 
    1198              :                     // Set next rotated load (from last time it was active)
    1199            0 :                     int RotatedLoadNum = demandMgr.RotatedLoadNum;
    1200            0 :                     ++RotatedLoadNum;
    1201            0 :                     if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
    1202            0 :                     demandMgr.RotatedLoadNum = RotatedLoadNum;
    1203              : 
    1204              :                     // Turn OFF limiting for the new rotated load
    1205            0 :                     LoadPtr = demandMgr.Load(RotatedLoadNum);
    1206            0 :                     LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1207              :                 } else {
    1208              :                     // Turn ON limiting for the one and only load
    1209            0 :                     LoadPtr = demandMgr.Load(1);
    1210            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1211              :                 }
    1212              : 
    1213            0 :             } break;
    1214            0 :             case ManagerSelection::One: { // Only one load is limited
    1215            0 :                 if (demandMgr.NumOfLoads > 1) {
    1216              :                     // Turn OFF limiting on all loads
    1217            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1218            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1219            0 :                         LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1220              :                     } // LoadNum
    1221              : 
    1222              :                     // Set next rotated load (from last time it was active)
    1223            0 :                     int RotatedLoadNum = demandMgr.RotatedLoadNum;
    1224            0 :                     ++RotatedLoadNum;
    1225            0 :                     if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
    1226            0 :                     demandMgr.RotatedLoadNum = RotatedLoadNum;
    1227              : 
    1228              :                     // Turn ON limiting for the new rotated load
    1229            0 :                     LoadPtr = demandMgr.Load(RotatedLoadNum);
    1230            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1231              :                 } else {
    1232              :                     // Turn ON limiting for the one and only load
    1233            0 :                     LoadPtr = demandMgr.Load(1);
    1234            0 :                     LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1235              :                 }
    1236            0 :             } break;
    1237            0 :             default:
    1238            0 :                 break;
    1239              :             }
    1240              :         }
    1241              : 
    1242              :     } // MgrNum
    1243            0 : }
    1244              : 
    1245       248592 : void UpdateDemandManagers(EnergyPlusData &state)
    1246              : {
    1247              : 
    1248              :     // SUBROUTINE INFORMATION:
    1249              :     //       AUTHOR         Peter Graham Ellis
    1250              :     //       DATE WRITTEN   July 2005
    1251              : 
    1252              :     // PURPOSE OF THIS SUBROUTINE:
    1253              :     // Expires limits and rotates loads after specified time duration.
    1254              :     // It updates availability flags, expires managers that ended in the last timestep, etc.
    1255              : 
    1256              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1257              :     int LoadPtr;
    1258              :     bool CanReduceDemand;
    1259              :     int RotatedLoadNum;
    1260              : 
    1261       248592 :     for (int MgrNum = 1; MgrNum <= state.dataDemandManager->NumDemandMgr; ++MgrNum) {
    1262              : 
    1263            0 :         auto &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1264              : 
    1265              :         // Check availability
    1266            0 :         bool Available = demandMgr.availSched->getCurrentVal() > 0.0;
    1267              : 
    1268            0 :         demandMgr.Available = Available;
    1269              : 
    1270              :         // Update demand manager status
    1271            0 :         if (Available) {
    1272              : 
    1273            0 :             if (demandMgr.Active) {
    1274              : 
    1275            0 :                 demandMgr.ElapsedTime += state.dataGlobal->MinutesInTimeStep;
    1276              : 
    1277              :                 // Check for expiring limit duration
    1278            0 :                 if (demandMgr.ElapsedTime >= demandMgr.LimitDuration) {
    1279            0 :                     demandMgr.ElapsedTime = 0;
    1280            0 :                     demandMgr.ElapsedRotationTime = 0;
    1281            0 :                     demandMgr.Active = false;
    1282              : 
    1283              :                     // Demand Manager is not available, remove demand limits from all loads
    1284            0 :                     for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1285            0 :                         LoadPtr = demandMgr.Load(LoadNum);
    1286            0 :                         LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1287              :                     } // LoadNum
    1288              : 
    1289              :                 } else {
    1290              : 
    1291            0 :                     switch (demandMgr.SelectionControl) {
    1292            0 :                     case ManagerSelection::All: {
    1293              :                         // Do nothing; limits remain on all loads
    1294              : 
    1295            0 :                     } break;
    1296            0 :                     case ManagerSelection::Many: { // All loads are limited except for one
    1297            0 :                         demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
    1298              : 
    1299            0 :                         if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
    1300            0 :                             demandMgr.ElapsedRotationTime = 0;
    1301              : 
    1302            0 :                             if (demandMgr.NumOfLoads > 1) {
    1303              :                                 // Turn ON limiting for the old rotated load
    1304            0 :                                 RotatedLoadNum = demandMgr.RotatedLoadNum;
    1305            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1306            0 :                                 LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1307              : 
    1308              :                                 // Set next rotated load
    1309            0 :                                 ++RotatedLoadNum;
    1310            0 :                                 if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
    1311            0 :                                 demandMgr.RotatedLoadNum = RotatedLoadNum;
    1312              : 
    1313              :                                 // Turn OFF limiting for the new rotated load
    1314            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1315            0 :                                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1316              :                             }
    1317              :                         }
    1318              : 
    1319            0 :                     } break;
    1320            0 :                     case ManagerSelection::One: { // Only one load is limited
    1321            0 :                         demandMgr.ElapsedRotationTime += state.dataGlobal->MinutesInTimeStep;
    1322              : 
    1323            0 :                         if (demandMgr.ElapsedRotationTime >= demandMgr.RotationDuration) {
    1324            0 :                             demandMgr.ElapsedRotationTime = 0;
    1325              : 
    1326            0 :                             if (demandMgr.NumOfLoads > 1) {
    1327              :                                 // Turn OFF limiting for the old rotated load
    1328            0 :                                 RotatedLoadNum = demandMgr.RotatedLoadNum;
    1329            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1330            0 :                                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1331              : 
    1332              :                                 // Set next rotated load
    1333            0 :                                 ++RotatedLoadNum;
    1334            0 :                                 if (RotatedLoadNum > demandMgr.NumOfLoads) RotatedLoadNum = 1;
    1335            0 :                                 demandMgr.RotatedLoadNum = RotatedLoadNum;
    1336              : 
    1337              :                                 // Turn ON limiting for the new rotated load
    1338            0 :                                 LoadPtr = demandMgr.Load(RotatedLoadNum);
    1339            0 :                                 LoadInterface(state, DemandAction::SetLimit, MgrNum, LoadPtr, CanReduceDemand);
    1340              :                             }
    1341              :                         }
    1342            0 :                     } break;
    1343            0 :                     default:
    1344            0 :                         break;
    1345              :                     }
    1346              :                 }
    1347              :             }
    1348              : 
    1349              :         } else { // Demand Manager is not available
    1350            0 :             demandMgr.Active = false;
    1351              : 
    1352              :             // Demand Manager is not available, remove demand limits from all loads
    1353            0 :             for (int LoadNum = 1; LoadNum <= demandMgr.NumOfLoads; ++LoadNum) {
    1354            0 :                 LoadPtr = demandMgr.Load(LoadNum);
    1355            0 :                 LoadInterface(state, DemandAction::ClearLimit, MgrNum, LoadPtr, CanReduceDemand);
    1356              :             } // LoadNum
    1357              :         }
    1358              : 
    1359              :     } // MgrNum
    1360       248592 : }
    1361              : 
    1362            0 : void ReportDemandManagerList(EnergyPlusData &state, int const ListNum)
    1363              : {
    1364              : 
    1365              :     // SUBROUTINE INFORMATION:
    1366              :     //       AUTHOR         Peter Graham Ellis
    1367              :     //       DATE WRITTEN   July 2005
    1368              : 
    1369              :     // PURPOSE OF THIS SUBROUTINE:
    1370              :     // Calculates report variables.
    1371              : 
    1372              :     // METHODOLOGY EMPLOYED:
    1373              :     // Standard EnergyPlus methodology.
    1374              : 
    1375              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1376              :     int AveragingWindow;
    1377              :     bool OnPeak;
    1378              :     Real64 OverLimit;
    1379              : 
    1380            0 :     auto &demandManagerList = state.dataDemandManager->DemandManagerList(ListNum);
    1381              : 
    1382            0 :     Real64 BillingPeriod = (demandManagerList.billingSched == nullptr) ? state.dataEnvrn->Month : demandManagerList.billingSched->getCurrentVal();
    1383              : 
    1384            0 :     if (demandManagerList.BillingPeriod != BillingPeriod) {
    1385              :         // Reset variables for new billing period
    1386              :         // demandManagerList%History = 0.0        ! Don't reset--continue from previous billing period
    1387              :         // demandManagerList%AverageDemand = 0.0  ! Don't reset--continue from previous billing period
    1388            0 :         demandManagerList.PeakDemand = 0.0;
    1389            0 :         demandManagerList.OverLimitDuration = 0.0;
    1390              : 
    1391            0 :         demandManagerList.BillingPeriod = BillingPeriod;
    1392              :     }
    1393              : 
    1394              :     // Add new timestep to demand history and subtract oldest timestep
    1395            0 :     AveragingWindow = demandManagerList.AveragingWindow;
    1396            0 :     demandManagerList.AverageDemand += (demandManagerList.MeterDemand - demandManagerList.History(1)) / AveragingWindow;
    1397              : 
    1398              :     // Update demand history
    1399            0 :     for (int Item = 1; Item <= AveragingWindow - 1; ++Item) {
    1400            0 :         demandManagerList.History(Item) = demandManagerList.History(Item + 1);
    1401              :     }
    1402            0 :     demandManagerList.History(AveragingWindow) = demandManagerList.MeterDemand;
    1403              : 
    1404            0 :     OnPeak = (demandManagerList.peakSched == nullptr) || (demandManagerList.peakSched->getCurrentVal() == 1);
    1405              : 
    1406            0 :     if (OnPeak) {
    1407            0 :         demandManagerList.PeakDemand = max(demandManagerList.AverageDemand, demandManagerList.PeakDemand);
    1408              : 
    1409            0 :         OverLimit = demandManagerList.AverageDemand - demandManagerList.ScheduledLimit;
    1410            0 :         if (OverLimit > 0.0) {
    1411            0 :             demandManagerList.OverLimit = OverLimit;
    1412            0 :             demandManagerList.OverLimitDuration += (state.dataGlobal->MinutesInTimeStep / 60.0);
    1413              :         } else {
    1414            0 :             demandManagerList.OverLimit = 0.0;
    1415              :         }
    1416              : 
    1417              :     } else {
    1418            0 :         demandManagerList.OverLimit = 0.0;
    1419              :     }
    1420            0 : }
    1421              : 
    1422            0 : void LoadInterface(EnergyPlusData &state, DemandAction const Action, int const MgrNum, int const LoadPtr, bool &CanReduceDemand)
    1423              : {
    1424              : 
    1425              :     // SUBROUTINE INFORMATION:
    1426              :     //       AUTHOR         Peter Graham Ellis
    1427              :     //       DATE WRITTEN   August 2005
    1428              : 
    1429              :     // PURPOSE OF THIS SUBROUTINE:
    1430              :     // Provides a universal interface to handle all communication with the various load objects.
    1431              :     // Demand managers for new types of loads can be easily added with a new CASE statement in this subroutine
    1432              :     // and new GetInput code.
    1433              : 
    1434            0 :     auto const &s_dhbf = state.dataHeatBalFanSys;
    1435            0 :     auto const &demandMgr = state.dataDemandManager->DemandMgr(MgrNum);
    1436              : 
    1437              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1438              :     Real64 LowestPower;
    1439              : 
    1440            0 :     CanReduceDemand = false;
    1441              : 
    1442            0 :     switch (demandMgr.Type) {
    1443            0 :     case ManagerType::ExtLights: {
    1444            0 :         LowestPower = state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1445            0 :         if (Action == DemandAction::CheckCanReduce) {
    1446            0 :             if (state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).Power > LowestPower) CanReduceDemand = true;
    1447            0 :         } else if (Action == DemandAction::SetLimit) {
    1448            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = true;
    1449            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).DemandLimit = LowestPower;
    1450            0 :         } else if (Action == DemandAction::ClearLimit) {
    1451            0 :             state.dataExteriorEnergyUse->ExteriorLights(LoadPtr).ManageDemand = false;
    1452              :         }
    1453            0 :     } break;
    1454              : 
    1455            0 :     case ManagerType::Lights: {
    1456            0 :         LowestPower = state.dataHeatBal->Lights(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1457            0 :         if (Action == DemandAction::CheckCanReduce) {
    1458            0 :             if (state.dataHeatBal->Lights(LoadPtr).Power > LowestPower) CanReduceDemand = true;
    1459            0 :         } else if (Action == DemandAction::SetLimit) {
    1460            0 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = true;
    1461            0 :             state.dataHeatBal->Lights(LoadPtr).DemandLimit = LowestPower;
    1462            0 :         } else if (Action == DemandAction::ClearLimit) {
    1463            0 :             state.dataHeatBal->Lights(LoadPtr).ManageDemand = false;
    1464              :         }
    1465            0 :     } break;
    1466              : 
    1467            0 :     case ManagerType::ElecEquip: {
    1468            0 :         LowestPower = state.dataHeatBal->ZoneElectric(LoadPtr).DesignLevel * demandMgr.LowerLimit;
    1469            0 :         if (Action == DemandAction::CheckCanReduce) {
    1470            0 :             if (state.dataHeatBal->ZoneElectric(LoadPtr).Power > LowestPower) CanReduceDemand = true;
    1471            0 :         } else if (Action == DemandAction::SetLimit) {
    1472            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = true;
    1473            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).DemandLimit = LowestPower;
    1474            0 :         } else if (Action == DemandAction::ClearLimit) {
    1475            0 :             state.dataHeatBal->ZoneElectric(LoadPtr).ManageDemand = false;
    1476              :         }
    1477            0 :     } break;
    1478              : 
    1479            0 :     case ManagerType::Thermostats: {
    1480            0 :         auto &tempZone = state.dataZoneCtrls->TempControlledZone(LoadPtr);
    1481            0 :         auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(tempZone.ActualZoneNum);
    1482            0 :         if (Action == DemandAction::CheckCanReduce) {
    1483            0 :             if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit)
    1484            0 :                 CanReduceDemand = true; // Heating | Cooling
    1485            0 :         } else if (Action == DemandAction::SetLimit) {
    1486            0 :             tempZone.ManageDemand = true;
    1487            0 :             tempZone.HeatingResetLimit = demandMgr.LowerLimit;
    1488            0 :             tempZone.CoolingResetLimit = demandMgr.UpperLimit;
    1489            0 :         } else if (Action == DemandAction::ClearLimit) {
    1490            0 :             tempZone.ManageDemand = false;
    1491              :         }
    1492            0 :         if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
    1493            0 :             auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(LoadPtr);
    1494            0 :             if (state.dataHeatBalFanSys->ComfortControlType(comfortZone.ActualZoneNum) != HVAC::SetptType::Uncontrolled) {
    1495            0 :                 auto &zoneTstatSetpt = s_dhbf->zoneTstatSetpts(comfortZone.ActualZoneNum);
    1496            0 :                 if (Action == DemandAction::CheckCanReduce) {
    1497            0 :                     if (zoneTstatSetpt.setptLo > demandMgr.LowerLimit || zoneTstatSetpt.setptHi < demandMgr.UpperLimit)
    1498            0 :                         CanReduceDemand = true; // Heating
    1499            0 :                 } else if (Action == DemandAction::SetLimit) {
    1500            0 :                     comfortZone.ManageDemand = true;
    1501            0 :                     comfortZone.HeatingResetLimit = demandMgr.LowerLimit;
    1502            0 :                     comfortZone.CoolingResetLimit = demandMgr.UpperLimit;
    1503            0 :                 } else if (Action == DemandAction::ClearLimit) {
    1504            0 :                     comfortZone.ManageDemand = false;
    1505              :                 }
    1506              :             }
    1507              :         }
    1508            0 :     } break;
    1509              : 
    1510            0 :     case ManagerType::Ventilation: {
    1511            0 :         Real64 FlowRate(0);
    1512            0 :         FlowRate = MixedAir::OAGetFlowRate(state, LoadPtr);
    1513            0 :         if (Action == DemandAction::CheckCanReduce) {
    1514            0 :             CanReduceDemand = true;
    1515            0 :         } else if (Action == DemandAction::SetLimit) {
    1516            0 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, true);
    1517            0 :             if (demandMgr.LimitControl == ManagerLimit::Fixed) {
    1518            0 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, demandMgr.FixedRate);
    1519            0 :             } else if (demandMgr.LimitControl == ManagerLimit::ReductionRatio) {
    1520            0 :                 Real64 DemandRate(0);
    1521            0 :                 DemandRate = FlowRate * demandMgr.ReductionRatio;
    1522            0 :                 MixedAir::OASetDemandManagerVentilationFlow(state, LoadPtr, DemandRate);
    1523              :             }
    1524            0 :         } else if (Action == DemandAction::ClearLimit) {
    1525            0 :             MixedAir::OASetDemandManagerVentilationState(state, LoadPtr, false);
    1526              :         }
    1527            0 :     } break;
    1528            0 :     default:
    1529            0 :         break;
    1530              :     }
    1531            0 : }
    1532              : 
    1533           73 : void InitDemandManagers(EnergyPlusData &state)
    1534              : {
    1535              : 
    1536              :     // SUBROUTINE INFORMATION:
    1537              :     //       AUTHOR         Linda Lawrie
    1538              :     //       DATE WRITTEN   September 2010
    1539              : 
    1540              :     // PURPOSE OF THIS SUBROUTINE:
    1541              :     // Provide external call to get Demand manager input after
    1542              :     // appropriate initializations.
    1543              : 
    1544           73 :     if (state.dataDemandManager->GetInput) {
    1545           73 :         GetDemandManagerInput(state);
    1546           73 :         GetDemandManagerListInput(state);
    1547           73 :         state.dataDemandManager->GetInput = false;
    1548              :     }
    1549           73 : }
    1550              : 
    1551              : } // namespace EnergyPlus::DemandManager
        

Generated by: LCOV version 2.0-1