LCOV - code coverage report
Current view: top level - EnergyPlus - EMSManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 838 1093 76.7 %
Date: 2024-08-23 23:50:59 Functions: 28 30 93.3 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Array1D.hh>
      54             : #include <ObjexxFCL/Fmath.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <EnergyPlus/Construction.hh>
      58             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59             : #include <EnergyPlus/DataAirLoop.hh>
      60             : #include <EnergyPlus/DataAirSystems.hh>
      61             : #include <EnergyPlus/DataHVACGlobals.hh>
      62             : #include <EnergyPlus/DataHeatBalance.hh>
      63             : #include <EnergyPlus/DataIPShortCuts.hh>
      64             : #include <EnergyPlus/DataLoopNode.hh>
      65             : #include <EnergyPlus/DataRuntimeLanguage.hh>
      66             : #include <EnergyPlus/DataSurfaces.hh>
      67             : #include <EnergyPlus/DataZoneControls.hh>
      68             : #include <EnergyPlus/EMSManager.hh>
      69             : #include <EnergyPlus/General.hh>
      70             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      71             : #include <EnergyPlus/OutAirNodeManager.hh>
      72             : #include <EnergyPlus/OutputProcessor.hh>
      73             : #include <EnergyPlus/PluginManager.hh>
      74             : #include <EnergyPlus/RuntimeLanguageProcessor.hh>
      75             : #include <EnergyPlus/ScheduleManager.hh>
      76             : #include <EnergyPlus/UtilityRoutines.hh>
      77             : 
      78             : namespace EnergyPlus {
      79             : 
      80             : // note there are routines that lie outside of the Module at the end of this file
      81             : 
      82             : namespace EMSManager {
      83             : 
      84             :     // MODULE INFORMATION:
      85             :     //       AUTHOR         Peter Graham Ellis
      86             :     //       DATE WRITTEN   June 2006
      87             :     //       MODIFIED       Brent Griffith
      88             :     //                      May - August 2009
      89             : 
      90             :     // PURPOSE OF THIS MODULE:
      91             :     // This module manages the programmable energy management system(EMS).
      92             : 
      93             :     constexpr std::array<std::string_view, static_cast<int>(EMSCallFrom::Num)> EMSCallFromNamesUC{"ENDOFZONESIZING",
      94             :                                                                                                   "ENDOFSYSTEMSIZING",
      95             :                                                                                                   "BEGINNEWENVIRONMENT",
      96             :                                                                                                   "AFTERNEWENVIRONMENTWARMUPISCOMPLETE",
      97             :                                                                                                   "BEGINTIMESTEPBEFOREPREDICTOR",
      98             :                                                                                                   "AFTERPREDICTORBEFOREHVACMANAGERS",
      99             :                                                                                                   "AFTERPREDICTORAFTERHVACMANAGERS",
     100             :                                                                                                   "INSIDEHVACSYSTEMITERATIONLOOP",
     101             :                                                                                                   "ENDOFSYSTEMTIMESTEPBEFOREHVACREPORTING",
     102             :                                                                                                   "ENDOFSYSTEMTIMESTEPAFTERHVACREPORTING",
     103             :                                                                                                   "ENDOFZONETIMESTEPBEFOREZONEREPORTING",
     104             :                                                                                                   "ENDOFZONETIMESTEPAFTERZONEREPORTING",
     105             :                                                                                                   "SETUPSIMULATION",
     106             :                                                                                                   "EXTERNALINTERFACE",
     107             :                                                                                                   "AFTERCOMPONENTINPUTREADIN",
     108             :                                                                                                   "USERDEFINEDCOMPONENTMODEL",
     109             :                                                                                                   "UNITARYSYSTEMSIZING",
     110             :                                                                                                   "BEGINZONETIMESTEPBEFOREINITHEATBALANCE",
     111             :                                                                                                   "BEGINZONETIMESTEPAFTERINITHEATBALANCE",
     112             :                                                                                                   "BEGINZONETIMESTEPBEFORESETCURRENTWEATHER"};
     113             : 
     114             :     constexpr std::array<std::string_view, (int)HVAC::CtrlVarType::Num> controlTypeNames = {"Temperature Setpoint",
     115             :                                                                                             "Temperature Minimum Setpoint",
     116             :                                                                                             "Temperature Maximum Setpoint",
     117             :                                                                                             "Humidity Ratio Setpoint",
     118             :                                                                                             "Humidity Ratio Minimum Setpoint",
     119             :                                                                                             "Humidity Ratio Maximum Setpoint",
     120             :                                                                                             "Mass Flow Rate Setpoint",
     121             :                                                                                             "Mass Flow Rate Minimum Available Setpoint",
     122             :                                                                                             "Mass Flow Rate Maximum Available Setpoint"};
     123             : 
     124         796 :     void CheckIfAnyEMS(EnergyPlusData &state)
     125             :     {
     126             : 
     127             :         // SUBROUTINE INFORMATION:
     128             :         //       AUTHOR         Brent Griffith
     129             :         //       DATE WRITTEN   April 2009
     130             :         //       MODIFIED       Rui Zhang February 2010
     131             : 
     132             :         // PURPOSE OF THIS SUBROUTINE:
     133             :         // Determine if EMS is used in model and set flag
     134             :         // This needs to be checked early so calls to SetupEMSActuator
     135             :         // can be avoided if there is no EMS in model.
     136             :         // We cannot do error checking during the full get input until later in the simulation.
     137             : 
     138             :         // METHODOLOGY EMPLOYED:
     139             :         // Get number of EMS-related input objects and set
     140             :         // global logical AnyEnergyManagementSystemInModel
     141             : 
     142         796 :         std::string cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     143         796 :         state.dataRuntimeLang->NumSensors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     144             : 
     145         796 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     146         796 :         state.dataRuntimeLang->numActuatorsUsed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     147             : 
     148         796 :         cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     149         796 :         state.dataRuntimeLang->NumProgramCallManagers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     150             : 
     151         796 :         cCurrentModuleObject = "EnergyManagementSystem:Program";
     152         796 :         state.dataRuntimeLang->NumErlPrograms = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     153             : 
     154         796 :         cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
     155         796 :         state.dataRuntimeLang->NumErlSubroutines = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     156             : 
     157         796 :         cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
     158         796 :         state.dataRuntimeLang->NumUserGlobalVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     159             : 
     160         796 :         cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
     161         796 :         state.dataRuntimeLang->NumEMSOutputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     162             : 
     163         796 :         cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
     164        1592 :         state.dataRuntimeLang->NumEMSMeteredOutputVariables =
     165         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     166             : 
     167         796 :         cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
     168         796 :         state.dataRuntimeLang->NumEMSCurveIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     169             : 
     170         796 :         cCurrentModuleObject = "ExternalInterface:Variable";
     171        1592 :         state.dataRuntimeLang->NumExternalInterfaceGlobalVariables =
     172         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     173             : 
     174             :         // added for FMUImport
     175         796 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
     176        1592 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables =
     177         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     178             : 
     179             :         // added for FMUExport
     180         796 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
     181        1592 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables =
     182         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     183             : 
     184         796 :         cCurrentModuleObject = "ExternalInterface:Actuator";
     185        1592 :         state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed =
     186         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     187             : 
     188             :         // added for FMUImport
     189         796 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     190        1592 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed =
     191         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     192             : 
     193             :         // added for FMUExport
     194         796 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
     195        1592 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed =
     196         796 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     197             : 
     198         796 :         cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
     199         796 :         state.dataRuntimeLang->NumEMSConstructionIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     200             : 
     201         796 :         cCurrentModuleObject = "Output:EnergyManagementSystem";
     202         796 :         int NumOutputEMSs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     203             : 
     204             :         // Python plugin instances also count since actuators need to be set up for them
     205         796 :         int numPythonPlugins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PythonPlugin:Instance");
     206         796 :         int numActiveCallbacks = PluginManagement::PluginManager::numActiveCallbacks(state);
     207             : 
     208             :         // added for FMU
     209         796 :         if ((state.dataRuntimeLang->NumSensors + state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumProgramCallManagers +
     210         796 :              state.dataRuntimeLang->NumErlPrograms + state.dataRuntimeLang->NumErlSubroutines + state.dataRuntimeLang->NumUserGlobalVariables +
     211         796 :              state.dataRuntimeLang->NumEMSOutputVariables + state.dataRuntimeLang->NumEMSCurveIndices +
     212         796 :              state.dataRuntimeLang->NumExternalInterfaceGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     213         796 :              state.dataRuntimeLang->NumEMSConstructionIndices + state.dataRuntimeLang->NumEMSMeteredOutputVariables +
     214         796 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     215         796 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
     216         796 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed +
     217         796 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables + NumOutputEMSs + numPythonPlugins +
     218         796 :              numActiveCallbacks) > 0) {
     219          73 :             state.dataGlobal->AnyEnergyManagementSystemInModel = true;
     220             :         } else {
     221         723 :             state.dataGlobal->AnyEnergyManagementSystemInModel = false;
     222             :         }
     223             : 
     224             :         // turn on EMS capability if we are running with an external HVAC manager or via API
     225         796 :         state.dataGlobal->AnyEnergyManagementSystemInModel =
     226         796 :             state.dataGlobal->AnyEnergyManagementSystemInModel || state.dataGlobal->externalHVACManager || state.dataGlobal->eplusRunningViaAPI;
     227             : 
     228         796 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
     229             : 
     230          73 :             General::ScanForReports(state, "EnergyManagementSystem", state.dataRuntimeLang->OutputEDDFile);
     231          73 :             if (state.dataRuntimeLang->OutputEDDFile) {
     232             :                 // open up output file for EMS EDD file  EMS Data and Debug
     233          41 :                 state.files.edd.ensure_open(state, "CheckIFAnyEMS", state.files.outputControl.edd);
     234             :             }
     235             :         } else {
     236         723 :             General::ScanForReports(state, "EnergyManagementSystem", state.dataRuntimeLang->OutputEDDFile);
     237         723 :             if (state.dataRuntimeLang->OutputEDDFile) {
     238           0 :                 ShowWarningError(state, "CheckIFAnyEMS: No EnergyManagementSystem has been set up in the input file but output is requested.");
     239           0 :                 ShowContinueError(state,
     240             :                                   "No EDD file will be produced. Refer to EMS Application Guide and/or InputOutput Reference to set up your "
     241             :                                   "EnergyManagementSystem.");
     242             :             }
     243             :         }
     244         796 :     }
     245             : 
     246             :     // MODULE SUBROUTINES:
     247             : 
     248    35292272 :     void ManageEMS(EnergyPlusData &state,
     249             :                    EMSCallFrom const iCalledFrom,                    // indicates where subroutine was called from, parameters in DataGlobals.
     250             :                    bool &anyProgramRan,                              // true if any Erl programs ran for this call
     251             :                    ObjexxFCL::Optional_int_const ProgramManagerToRun // specific program manager to run
     252             :     )
     253             :     {
     254             : 
     255             :         // SUBROUTINE INFORMATION:
     256             :         //       AUTHOR         Peter Graham Ellis
     257             :         //       DATE WRITTEN   June 2006
     258             :         //       MODIFIED       na
     259             :         //       RE-ENGINEERED  Brent Griffith, April 2009
     260             :         //                      added calling point argument and logic.
     261             :         //                      Collapsed SimulateEMS into this routine
     262             : 
     263    35292272 :         anyProgramRan = false;
     264    35292272 :         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) return; // quick return if nothing to do
     265             : 
     266     5771273 :         if (iCalledFrom == EMSCallFrom::BeginNewEnvironment) {
     267         142 :             RuntimeLanguageProcessor::BeginEnvrnInitializeRuntimeLanguage(state);
     268         142 :             PluginManagement::onBeginEnvironment(state);
     269             :         }
     270             : 
     271     5771273 :         InitEMS(state, iCalledFrom);
     272             : 
     273             :         // also call plugins and callbacks here for convenience
     274     5771273 :         if (iCalledFrom != EMSCallFrom::UserDefinedComponentModel) { // don't run user-defined component plugins this way
     275     5341042 :             bool anyPluginsOrCallbacksRan = false;
     276     5341042 :             PluginManagement::runAnyRegisteredCallbacks(state, iCalledFrom, anyPluginsOrCallbacksRan);
     277     5341042 :             if (anyPluginsOrCallbacksRan) {
     278      206890 :                 anyProgramRan = true;
     279             :             }
     280             :         }
     281             : 
     282     5771273 :         if (iCalledFrom == EMSCallFrom::SetupSimulation) {
     283          72 :             ProcessEMSInput(state, true);
     284          72 :             return;
     285             :         }
     286             : 
     287             :         // Run the Erl programs depending on calling point.
     288             : 
     289     5771201 :         if (iCalledFrom != EMSCallFrom::UserDefinedComponentModel) {
     290    29190592 :             for (int ProgramManagerNum = 1; ProgramManagerNum <= state.dataRuntimeLang->NumProgramCallManagers; ++ProgramManagerNum) {
     291             : 
     292    23849623 :                 if (state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).CallingPoint == iCalledFrom) {
     293     3968156 :                     for (int ErlProgramNum = 1; ErlProgramNum <= state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).NumErlPrograms;
     294             :                          ++ErlProgramNum) {
     295     2048481 :                         RuntimeLanguageProcessor::EvaluateStack(
     296     2048482 :                             state, state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).ErlProgramARR(ErlProgramNum));
     297     2048481 :                         anyProgramRan = true;
     298             :                     }
     299             :                 }
     300             :             }
     301             :         } else { // call specific program manager
     302      430231 :             if (present(ProgramManagerToRun)) {
     303     1300564 :                 for (int ErlProgramNum = 1; ErlProgramNum <= state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerToRun).NumErlPrograms;
     304             :                      ++ErlProgramNum) {
     305      870333 :                     RuntimeLanguageProcessor::EvaluateStack(
     306      870333 :                         state, state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerToRun).ErlProgramARR(ErlProgramNum));
     307      870333 :                     anyProgramRan = true;
     308             :                 }
     309             :             }
     310             :         }
     311             : 
     312     5771200 :         if (iCalledFrom == EMSCallFrom::ExternalInterface) {
     313      106848 :             anyProgramRan = true;
     314             :         }
     315             : 
     316     5771200 :         if (!anyProgramRan) {
     317     4609577 :             return;
     318             :         }
     319             : 
     320             :         // Set actuated variables with new values
     321    24562215 :         for (int ActuatorUsedLoop = 1;
     322    24562215 :              ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     323    24562215 :                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     324    24562215 :                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
     325             :              ++ActuatorUsedLoop) {
     326    23400592 :             auto const &thisActuatorUsed = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop);
     327             : 
     328    23400592 :             int ErlVariableNum = thisActuatorUsed.ErlVariableNum;
     329    23400592 :             if (ErlVariableNum <= 0) {
     330           0 :                 continue; // this can happen for good reason during sizing
     331             :             }
     332             : 
     333    23400592 :             int EMSActuatorVariableNum = thisActuatorUsed.ActuatorVariableNum;
     334    23400592 :             if (EMSActuatorVariableNum <= 0) {
     335       87101 :                 continue; // this can happen for good reason during sizing
     336             :             }
     337             : 
     338    23313491 :             auto const &thisErlVar = state.dataRuntimeLang->ErlVariable(ErlVariableNum);
     339    23313491 :             auto &thisActuatorAvail = state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum);
     340             : 
     341    23313491 :             if (thisErlVar.Value.Type == DataRuntimeLanguage::Value::Null) {
     342     2363542 :                 *thisActuatorAvail.Actuated = false;
     343             :             } else {
     344             :                 // Set the value and the actuated flag remotely on the actuated object via the pointer
     345    20949949 :                 switch (thisActuatorAvail.PntrVarTypeUsed) {
     346    20715358 :                 case DataRuntimeLanguage::PtrDataType::Real: {
     347    20715358 :                     *thisActuatorAvail.Actuated = true;
     348    20715358 :                     *thisActuatorAvail.RealValue = thisErlVar.Value.Number;
     349    20715358 :                 } break;
     350      234591 :                 case DataRuntimeLanguage::PtrDataType::Integer: {
     351      234591 :                     *thisActuatorAvail.Actuated = true;
     352      234591 :                     int tmpInteger = std::floor(thisErlVar.Value.Number);
     353      234591 :                     *thisActuatorAvail.IntValue = tmpInteger;
     354      234591 :                 } break;
     355           0 :                 case DataRuntimeLanguage::PtrDataType::Logical: {
     356           0 :                     *thisActuatorAvail.Actuated = true;
     357           0 :                     if (thisErlVar.Value.Number == 0.0) {
     358           0 :                         *thisActuatorAvail.LogValue = false;
     359           0 :                     } else if (thisErlVar.Value.Number == 1.0) {
     360           0 :                         *thisActuatorAvail.LogValue = true;
     361             :                     } else {
     362           0 :                         *thisActuatorAvail.LogValue = false;
     363             :                     }
     364           0 :                 } break;
     365           0 :                 default:
     366           0 :                     break;
     367             :                 }
     368             :             }
     369             :         }
     370             : 
     371     1161623 :         ReportEMS(state);
     372             :     }
     373             : 
     374     5771273 :     void InitEMS(EnergyPlusData &state, EMSCallFrom const iCalledFrom) // indicates where subroutine was called from, parameters in DataGlobals.
     375             :     {
     376             : 
     377             :         // SUBROUTINE INFORMATION:
     378             :         //       AUTHOR         Brent Griffith
     379             :         //       DATE WRITTEN   May 2009
     380             : 
     381             :         // PURPOSE OF THIS SUBROUTINE:
     382             :         // collect routines needed to initialize EMS
     383             : 
     384     5771273 :         if (state.dataEMSMgr->GetEMSUserInput) {
     385          73 :             SetupZoneInfoAsInternalDataAvail(state);
     386          73 :             SetupWindowShadingControlActuators(state);
     387          73 :             SetupSurfaceConvectionActuators(state);
     388          73 :             SetupSurfaceConstructionActuators(state);
     389          73 :             SetupSurfaceOutdoorBoundaryConditionActuators(state);
     390          73 :             SetupZoneOutdoorBoundaryConditionActuators(state);
     391          73 :             GetEMSInput(state);
     392          73 :             state.dataEMSMgr->GetEMSUserInput = false;
     393             :         }
     394             : 
     395     5771273 :         if (!state.dataZoneCtrls->GetZoneAirStatsInputFlag && !state.dataEMSMgr->ZoneThermostatActuatorsHaveBeenSetup) {
     396          73 :             SetupThermostatActuators(state);
     397          73 :             state.dataEMSMgr->ZoneThermostatActuatorsHaveBeenSetup = true;
     398             :         }
     399             : 
     400             :         // need to delay setup of HVAC actuator until after the systems input has been processed (if present)
     401     5771273 :         if (state.dataEMSMgr->FinishProcessingUserInput && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     402          72 :             SetupNodeSetPointsAsActuators(state);
     403          72 :             SetupPrimaryAirSystemAvailMgrAsActuators(state);
     404             :             //    CALL SetupWindowShadingControlActuators !this is too late for including in sizing, moved to GetEMSUserInput
     405             :             //    CALL SetupThermostatActuators !this is too late for including in sizing, moved to GetEMSUserInput
     406             :             //    CALL SetupSurfaceConvectionActuators !this is too late for including in sizing, moved to GetEMSUserInput
     407          72 :             state.dataEMSMgr->FinishProcessingUserInput = false;
     408             :         }
     409             : 
     410     5771273 :         RuntimeLanguageProcessor::InitializeRuntimeLanguage(state);
     411             : 
     412     5771273 :         if ((state.dataGlobal->BeginEnvrnFlag) || (iCalledFrom == EMSCallFrom::ZoneSizing) || (iCalledFrom == EMSCallFrom::SystemSizing) ||
     413             :             (iCalledFrom == EMSCallFrom::UserDefinedComponentModel)) {
     414             : 
     415             :             // another pass at trying to setup input data.
     416      441083 :             if (state.dataEMSMgr->FinishProcessingUserInput) {
     417        6593 :                 ProcessEMSInput(state, false);
     418             :             }
     419             : 
     420             :             // update internal data variables being used by Erl
     421    26107691 :             for (int InternalVarUsedNum = 1; InternalVarUsedNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternalVarUsedNum) {
     422    25666608 :                 int ErlVariableNum = state.dataRuntimeLang->EMSInternalVarsUsed(InternalVarUsedNum).ErlVariableNum;
     423    25666608 :                 int InternVarAvailNum = state.dataRuntimeLang->EMSInternalVarsUsed(InternalVarUsedNum).InternVarNum;
     424    25666608 :                 if (InternVarAvailNum <= 0) continue; // sometimes executes before completely finished setting up.
     425    25658653 :                 if (ErlVariableNum <= 0) continue;
     426             : 
     427    25658653 :                 switch (state.dataRuntimeLang->EMSInternalVarsAvailable(InternVarAvailNum).PntrVarTypeUsed) {
     428    25658653 :                 case DataRuntimeLanguage::PtrDataType::Real: {
     429    25658653 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value =
     430    51317306 :                         RuntimeLanguageProcessor::SetErlValueNumber(*state.dataRuntimeLang->EMSInternalVarsAvailable(InternVarAvailNum).RealValue);
     431    25658653 :                 } break;
     432           0 :                 case DataRuntimeLanguage::PtrDataType::Integer: {
     433           0 :                     Real64 tmpReal = double(*state.dataRuntimeLang->EMSInternalVarsAvailable(InternVarAvailNum).IntValue);
     434           0 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value = RuntimeLanguageProcessor::SetErlValueNumber(tmpReal);
     435           0 :                 } break;
     436           0 :                 default:
     437           0 :                     break;
     438             :                 }
     439             :             }
     440             :         }
     441             : 
     442             :         // Update sensors with current data
     443    93500172 :         for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     444    87728899 :             int ErlVariableNum = state.dataRuntimeLang->Sensor(SensorNum).VariableNum;
     445    87728899 :             if ((ErlVariableNum > 0) && (state.dataRuntimeLang->Sensor(SensorNum).Index > -1)) {
     446    87728899 :                 if (state.dataRuntimeLang->Sensor(SensorNum).SchedNum == 0) { // not a schedule so get from output processor
     447             : 
     448   173010392 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value = RuntimeLanguageProcessor::SetErlValueNumber(
     449             :                         GetInternalVariableValue(
     450    86505196 :                             state, state.dataRuntimeLang->Sensor(SensorNum).VariableType, state.dataRuntimeLang->Sensor(SensorNum).Index),
     451   173010392 :                         state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
     452             :                 } else { // schedule so use schedule service
     453             : 
     454     2447406 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value = RuntimeLanguageProcessor::SetErlValueNumber(
     455     1223703 :                         ScheduleManager::GetCurrentScheduleValue(state, state.dataRuntimeLang->Sensor(SensorNum).SchedNum),
     456     2447406 :                         state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
     457             :                 }
     458             :             }
     459             :         }
     460     5771273 :     }
     461             : 
     462     1161623 :     void ReportEMS(EnergyPlusData &state)
     463             :     {
     464             : 
     465             :         // SUBROUTINE INFORMATION:
     466             :         //       AUTHOR         Peter Graham Ellis
     467             :         //       DATE WRITTEN   June 2006
     468             :         // PURPOSE OF THIS SUBROUTINE:
     469             :         // Calculates report variables.
     470             : 
     471             :         // METHODOLOGY EMPLOYED:
     472             :         // Standard EnergyPlus methodology.
     473             : 
     474     1161623 :         RuntimeLanguageProcessor::ReportRuntimeLanguage(state);
     475     1161623 :     }
     476             : 
     477          73 :     void GetEMSInput(EnergyPlusData &state)
     478             :     {
     479             : 
     480             :         // SUBROUTINE INFORMATION:
     481             :         //       AUTHOR         Peter Graham Ellis
     482             :         //       DATE WRITTEN   June 2006
     483             :         //       MODIFIED       BG April 2009, finishing, renaming, etc.
     484             : 
     485             :         // PURPOSE OF THIS SUBROUTINE:
     486             :         // Gets the EMS input from the input file.
     487             : 
     488             :         // METHODOLOGY EMPLOYED:
     489             :         // Standard EnergyPlus methodology.
     490             : 
     491             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     492             : 
     493             :         int NumAlphas; // Number of elements in the alpha array
     494             :         int NumNums;   // Number of elements in the numeric array
     495             :         int IOStat;    // IO Status when calling get input subroutine
     496          73 :         bool ErrorsFound(false);
     497          73 :         Array1D_string cAlphaFieldNames;
     498          73 :         Array1D_string cNumericFieldNames;
     499          73 :         Array1D_bool lNumericFieldBlanks;
     500          73 :         Array1D_bool lAlphaFieldBlanks;
     501          73 :         Array1D_string cAlphaArgs;
     502          73 :         Array1D<Real64> rNumericArgs;
     503          73 :         std::string cCurrentModuleObject;
     504             :         OutputProcessor::VariableType VarType;
     505          73 :         int TotalArgs(0); // argument for call to GetObjectDefMaxArgs
     506             :         bool errFlag;
     507             : 
     508          73 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     509          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     510          73 :         int MaxNumNumbers = NumNums;
     511          73 :         int MaxNumAlphas = NumAlphas;
     512          73 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     513          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     514          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     515          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     516          73 :         cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     517          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     518          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     519          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     520          73 :         cCurrentModuleObject = "EnergyManagementSystem:Program";
     521          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     522          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     523          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     524          73 :         cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
     525          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     526          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     527          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     528          73 :         cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
     529          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     530          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     531          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     532          73 :         cCurrentModuleObject = "ExternalInterface:Variable";
     533          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     534          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     535          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     536          73 :         cCurrentModuleObject = "ExternalInterface:Actuator";
     537          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     538          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     539          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     540          73 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
     541          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     542          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     543          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     544          73 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     545          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     546          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     547          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     548          73 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
     549          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     550          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     551          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     552          73 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
     553          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     554          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     555          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     556             :         //  cCurrentModuleObject = 'EnergyManagementSystem:Sensor'
     557             :         //  CALL state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(cCurrentModuleObject,TotalArgs,NumAlphas,NumNums)
     558             :         //  MaxNumNumbers=MAX(MaxNumNumbers,NumNums)
     559             :         //  MaxNumAlphas=MAX(MaxNumAlphas,NumAlphas)
     560          73 :         cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
     561          73 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     562          73 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     563          73 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     564             : 
     565          73 :         cAlphaFieldNames.allocate(MaxNumAlphas);
     566          73 :         cAlphaArgs.allocate(MaxNumAlphas);
     567          73 :         lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
     568          73 :         cNumericFieldNames.allocate(MaxNumNumbers);
     569          73 :         rNumericArgs.dimension(MaxNumNumbers, 0.0);
     570          73 :         lNumericFieldBlanks.dimension(MaxNumNumbers, false);
     571             : 
     572          73 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     573          73 :         if (state.dataRuntimeLang->NumSensors > 0) {
     574          51 :             state.dataRuntimeLang->Sensor.allocate(state.dataRuntimeLang->NumSensors);
     575             : 
     576        1855 :             for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     577        1804 :                 auto &thisSensor = state.dataRuntimeLang->Sensor(SensorNum);
     578        1804 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     579             :                                                                          cCurrentModuleObject,
     580             :                                                                          SensorNum,
     581             :                                                                          cAlphaArgs,
     582             :                                                                          NumAlphas,
     583             :                                                                          rNumericArgs,
     584             :                                                                          NumNums,
     585             :                                                                          IOStat,
     586             :                                                                          lNumericFieldBlanks,
     587             :                                                                          lAlphaFieldBlanks,
     588             :                                                                          cAlphaFieldNames,
     589             :                                                                          cNumericFieldNames);
     590        1804 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     591        1804 :                 if (!errFlag) {
     592        1804 :                     thisSensor.Name = cAlphaArgs(1);
     593             : 
     594             :                     // really needs to check for conflicts with program and function names too...done later
     595        1804 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     596             : 
     597        1804 :                     if (VariableNum > 0) {
     598           0 :                         ShowSevereError(state, format("Invalid {}={}", cAlphaFieldNames(1), cAlphaArgs(1)));
     599           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     600           0 :                         ShowContinueError(state, "Object name conflicts with a global variable name in EMS");
     601           0 :                         ErrorsFound = true;
     602             :                     } else {
     603        1804 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     604        1804 :                         thisSensor.VariableNum = VariableNum;
     605        1804 :                         state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true;
     606             :                     }
     607             :                 }
     608             : 
     609        1804 :                 if (cAlphaArgs(2) == "*") cAlphaArgs(2).clear();
     610        1804 :                 thisSensor.UniqueKeyName = cAlphaArgs(2);
     611        1804 :                 thisSensor.OutputVarName = cAlphaArgs(3);
     612             : 
     613        1804 :                 int VarIndex = GetMeterIndex(state, cAlphaArgs(3));
     614        1804 :                 if (VarIndex > -1) {
     615          11 :                     if (!lAlphaFieldBlanks(2)) {
     616           0 :                         ShowWarningError(state, format("Unused{}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
     617           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     618           0 :                         ShowContinueError(state, "Meter Name found; Key Name will be ignored"); // why meters have no keys..
     619             :                     } else {
     620          11 :                         thisSensor.VariableType = OutputProcessor::VariableType::Meter;
     621          11 :                         thisSensor.Index = VarIndex;
     622          11 :                         thisSensor.CheckedOkay = true;
     623             :                     }
     624             :                 } else {
     625             :                     // Search for variable names
     626        1793 :                     GetVariableTypeAndIndex(state, cAlphaArgs(3), cAlphaArgs(2), VarType, VarIndex);
     627        1793 :                     if (VarType != OutputProcessor::VariableType::Invalid) {
     628         531 :                         thisSensor.VariableType = VarType;
     629         531 :                         if (VarIndex != -1) {
     630         531 :                             thisSensor.Index = VarIndex;
     631         531 :                             thisSensor.CheckedOkay = true;
     632             :                         }
     633             :                     }
     634             :                 }
     635             : 
     636             :             } // SensorNum
     637             :         }
     638             : 
     639          73 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     640             : 
     641          73 :         if (state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     642          73 :                 state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     643          73 :                 state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed >
     644             :             0) {
     645          88 :             state.dataRuntimeLang->EMSActuatorUsed.allocate(state.dataRuntimeLang->numActuatorsUsed +
     646          44 :                                                             state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     647          44 :                                                             state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     648          44 :                                                             state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed);
     649         741 :             for (int ActuatorNum = 1;
     650         741 :                  ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     651         741 :                                     state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     652         741 :                                     state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
     653             :                  ++ActuatorNum) {
     654         697 :                 auto &thisEMSactuator = state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum);
     655             :                 // If we process the ExternalInterface actuators, all we need to do is to change the
     656             :                 // name of the module object, and shift the ActuatorNum in GetObjectItem
     657         697 :                 if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed) {
     658         696 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
     659             :                                                                              cCurrentModuleObject,
     660             :                                                                              ActuatorNum,
     661             :                                                                              cAlphaArgs,
     662             :                                                                              NumAlphas,
     663             :                                                                              rNumericArgs,
     664             :                                                                              NumNums,
     665             :                                                                              IOStat,
     666             :                                                                              lNumericFieldBlanks,
     667             :                                                                              lAlphaFieldBlanks,
     668             :                                                                              cAlphaFieldNames,
     669             :                                                                              cNumericFieldNames);
     670           1 :                 } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed) {
     671           0 :                     cCurrentModuleObject = "ExternalInterface:Actuator";
     672           0 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
     673             :                                                                              cCurrentModuleObject,
     674           0 :                                                                              ActuatorNum - state.dataRuntimeLang->numActuatorsUsed,
     675             :                                                                              cAlphaArgs,
     676             :                                                                              NumAlphas,
     677             :                                                                              rNumericArgs,
     678             :                                                                              NumNums,
     679             :                                                                              IOStat,
     680             :                                                                              lNumericFieldBlanks,
     681             :                                                                              lAlphaFieldBlanks,
     682             :                                                                              cAlphaFieldNames,
     683             :                                                                              cNumericFieldNames);
     684           1 :                 } else if (ActuatorNum <= (state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     685           1 :                                            state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed)) {
     686           1 :                     cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     687           2 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
     688             :                                                                              cCurrentModuleObject,
     689           1 :                                                                              ActuatorNum - state.dataRuntimeLang->numActuatorsUsed -
     690           1 :                                                                                  state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed,
     691             :                                                                              cAlphaArgs,
     692             :                                                                              NumAlphas,
     693             :                                                                              rNumericArgs,
     694             :                                                                              NumNums,
     695             :                                                                              IOStat,
     696             :                                                                              lNumericFieldBlanks,
     697             :                                                                              lAlphaFieldBlanks,
     698             :                                                                              cAlphaFieldNames,
     699             :                                                                              cNumericFieldNames);
     700           0 :                 } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     701           0 :                                               state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     702           0 :                                               state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed) {
     703           0 :                     cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
     704           0 :                     state.dataInputProcessing->inputProcessor->getObjectItem(
     705             :                         state,
     706             :                         cCurrentModuleObject,
     707           0 :                         ActuatorNum - state.dataRuntimeLang->numActuatorsUsed - state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed -
     708           0 :                             state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed,
     709             :                         cAlphaArgs,
     710             :                         NumAlphas,
     711             :                         rNumericArgs,
     712             :                         NumNums,
     713             :                         IOStat,
     714             :                         lNumericFieldBlanks,
     715             :                         lAlphaFieldBlanks,
     716             :                         cAlphaFieldNames,
     717             :                         cNumericFieldNames);
     718             :                 }
     719             : 
     720         697 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     721         697 :                 if (!errFlag) {
     722         697 :                     thisEMSactuator.Name = cAlphaArgs(1);
     723             : 
     724             :                     // really needs to check for conflicts with program and function names too...
     725         697 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     726             : 
     727         697 :                     if (VariableNum > 0) {
     728           0 :                         ShowSevereError(state, format("Invalid {}={}", cAlphaFieldNames(1), cAlphaArgs(1)));
     729           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     730           0 :                         ShowContinueError(state, "Object name conflicts with a global variable name in EMS");
     731           0 :                         ErrorsFound = true;
     732             :                     } else {
     733         697 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     734         697 :                         thisEMSactuator.ErlVariableNum = VariableNum;
     735             :                         // initialize Erl variable for actuator to null
     736         697 :                         state.dataRuntimeLang->ErlVariable(VariableNum).Value = state.dataRuntimeLang->Null;
     737         697 :                         if (ActuatorNum > state.dataRuntimeLang->numActuatorsUsed) {
     738             :                             // Initialize variables for the ExternalInterface variables
     739           1 :                             RuntimeLanguageProcessor::ExternalInterfaceInitializeErlVariable(
     740           2 :                                 state, VariableNum, RuntimeLanguageProcessor::SetErlValueNumber(rNumericArgs(1)), lNumericFieldBlanks(1));
     741             :                         }
     742             :                     }
     743             :                 }
     744             : 
     745             :                 // need to store characters to finish processing later (once available Actuators have all been setup)
     746         697 :                 thisEMSactuator.ComponentTypeName = cAlphaArgs(3);
     747         697 :                 thisEMSactuator.UniqueIDName = cAlphaArgs(2);
     748         697 :                 thisEMSactuator.ControlTypeName = cAlphaArgs(4);
     749             : 
     750             :                 int ActuatorVariableNum;
     751         697 :                 bool FoundActuatorName = false;
     752      338559 :                 for (ActuatorVariableNum = 1; ActuatorVariableNum <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorVariableNum) {
     753      338218 :                     if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).ComponentTypeName, cAlphaArgs(3))) {
     754        6651 :                         if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).UniqueIDName, cAlphaArgs(2))) {
     755         358 :                             if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).ControlTypeName, cAlphaArgs(4))) {
     756         356 :                                 FoundActuatorName = true;
     757         356 :                                 break;
     758             :                             }
     759             :                         }
     760             :                     }
     761             :                 }
     762             : 
     763         697 :                 if (FoundActuatorName) {
     764             :                     // SetupNodeSetPointAsActuators has NOT been called yet at this point
     765         356 :                     thisEMSactuator.ActuatorVariableNum = ActuatorVariableNum;
     766         356 :                     thisEMSactuator.CheckedOkay = true;
     767             : 
     768         356 :                     int nHandle = state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).handleCount;
     769         356 :                     if (nHandle > 0) {
     770           0 :                         EnergyPlus::ShowWarningError(state,
     771           0 :                                                      format("Seems like you already tried to get a Handle on this Actuator {}times.", nHandle));
     772           0 :                         EnergyPlus::ShowContinueError(state,
     773           0 :                                                       format("Occurred for componentType='{}', controlType='{}', uniqueKey='{}'.",
     774           0 :                                                              thisEMSactuator.ComponentTypeName,
     775           0 :                                                              thisEMSactuator.ControlTypeName,
     776           0 :                                                              thisEMSactuator.UniqueIDName));
     777           0 :                         EnergyPlus::ShowContinueError(state, "You should take note that there is a risk of overwritting.");
     778             :                     }
     779         356 :                     ++state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).handleCount;
     780             :                 }
     781             :             } // ActuatorNum
     782             :         }
     783             : 
     784          73 :         cCurrentModuleObject = "EnergyManagementSystem:InternalVariable";
     785          73 :         state.dataRuntimeLang->NumInternalVariablesUsed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     786          73 :         if (state.dataRuntimeLang->NumInternalVariablesUsed > 0) {
     787          28 :             state.dataRuntimeLang->EMSInternalVarsUsed.allocate(state.dataRuntimeLang->NumInternalVariablesUsed);
     788             : 
     789         583 :             for (int InternVarNum = 1; InternVarNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternVarNum) {
     790         555 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     791             :                                                                          cCurrentModuleObject,
     792             :                                                                          InternVarNum,
     793             :                                                                          cAlphaArgs,
     794             :                                                                          NumAlphas,
     795             :                                                                          rNumericArgs,
     796             :                                                                          NumNums,
     797             :                                                                          IOStat,
     798             :                                                                          lNumericFieldBlanks,
     799             :                                                                          lAlphaFieldBlanks,
     800             :                                                                          cAlphaFieldNames,
     801             :                                                                          cNumericFieldNames);
     802             : 
     803         555 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     804         555 :                 if (!errFlag) {
     805         555 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).Name = cAlphaArgs(1);
     806         555 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     807         555 :                     if (VariableNum > 0) {
     808           0 :                         ShowSevereError(state, format("Invalid {}={}", cAlphaFieldNames(1), cAlphaArgs(1)));
     809           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     810           0 :                         ShowContinueError(state, "Object name conflicts with a global variable name in EMS");
     811           0 :                         ErrorsFound = true;
     812             :                     } else {
     813         555 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     814         555 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).ErlVariableNum = VariableNum;
     815             :                     }
     816             : 
     817         555 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName = cAlphaArgs(2);
     818         555 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternalDataTypeName = cAlphaArgs(3);
     819             : 
     820         555 :                     bool FoundObjectName = false;
     821             :                     int InternalVarAvailNum; // do loop counter for internal variables available (inner)
     822       53843 :                     for (InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
     823       53543 :                         if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName, cAlphaArgs(3))) {
     824        3473 :                             if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName, cAlphaArgs(2))) {
     825         255 :                                 FoundObjectName = true;
     826         255 :                                 break; // InternalVarAvailNum now holds needed index pointer
     827             :                             }
     828             :                         }
     829             :                     }
     830             : 
     831         555 :                     if (FoundObjectName) {
     832         255 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternVarNum = InternalVarAvailNum;
     833         255 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay = true;
     834             :                     }
     835             :                 }
     836             :             }
     837             :         }
     838             : 
     839          73 :         RuntimeLanguageProcessor::InitializeRuntimeLanguage(
     840             :             state); // Loads built-in globals and functions, then performs GetInput for runtime language objects
     841             : 
     842          73 :         if (state.dataRuntimeLang->NumProgramCallManagers > 0) {
     843          53 :             cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     844          53 :             state.dataRuntimeLang->EMSProgramCallManager.allocate(state.dataRuntimeLang->NumProgramCallManagers);
     845             : 
     846         593 :             for (int CallManagerNum = 1; CallManagerNum <= state.dataRuntimeLang->NumProgramCallManagers; ++CallManagerNum) {
     847             : 
     848         540 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     849             :                                                                          cCurrentModuleObject,
     850             :                                                                          CallManagerNum,
     851             :                                                                          cAlphaArgs,
     852             :                                                                          NumAlphas,
     853             :                                                                          rNumericArgs,
     854             :                                                                          NumNums,
     855             :                                                                          IOStat,
     856             :                                                                          lNumericFieldBlanks,
     857             :                                                                          lAlphaFieldBlanks,
     858             :                                                                          cAlphaFieldNames,
     859             :                                                                          cNumericFieldNames);
     860             : 
     861         540 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).Name = cAlphaArgs(1);
     862             : 
     863         540 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).CallingPoint =
     864        1080 :                     static_cast<EMSCallFrom>(getEnumValue(EMSCallFromNamesUC, Util::makeUPPER(cAlphaArgs(2))));
     865             : 
     866         540 :                 ErrorsFound = ErrorsFound || (state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).CallingPoint == EMSCallFrom::Invalid);
     867             : 
     868         540 :                 int NumErlProgramsThisManager = NumAlphas - 2; // temporary size of Erl programs in EMSProgramCallManager
     869         540 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).NumErlPrograms = NumErlProgramsThisManager;
     870         540 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).ErlProgramARR.allocate(NumErlProgramsThisManager);
     871         540 :                 int ManagerProgramNum = 0; // index counter for Erl programs inside EMSProgramCallManager
     872        1163 :                 for (int AlphaNum = 3; AlphaNum <= NumAlphas; ++AlphaNum) {
     873             :                     // find program name in Stack structure
     874         623 :                     if (lAlphaFieldBlanks(AlphaNum)) { // throw error
     875           0 :                         ShowSevereError(state, format("Invalid {}={}", cAlphaFieldNames(AlphaNum), cAlphaArgs(AlphaNum)));
     876           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     877           0 :                         ShowContinueError(state, "Program names cannot be blank");
     878           0 :                         ErrorsFound = true;
     879             :                     }
     880             : 
     881         623 :                     int StackNum = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataRuntimeLang->ErlStack);
     882             : 
     883         623 :                     if (StackNum > 0) { // found it
     884             :                         // check for duplicate and warn.
     885         910 :                         for (int Loop = 1; Loop <= ManagerProgramNum; ++Loop) {
     886         287 :                             if (state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).ErlProgramARR(Loop) == StackNum) {
     887           0 :                                 ShowWarningError(state, format("Duplicate {}={}", cAlphaFieldNames(AlphaNum), cAlphaArgs(AlphaNum)));
     888           0 :                                 ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     889           0 :                                 ShowContinueError(state, "Erl program appears more than once, and the simulation continues.");
     890             :                             }
     891             :                         }
     892             : 
     893         623 :                         ++ManagerProgramNum;
     894             : 
     895         623 :                         state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).ErlProgramARR(ManagerProgramNum) = StackNum;
     896             : 
     897             :                     } else {
     898           0 :                         ShowSevereError(state, format("Invalid {}={}", cAlphaFieldNames(AlphaNum), cAlphaArgs(AlphaNum)));
     899           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     900           0 :                         ShowContinueError(state, "Program Name not found.");
     901           0 :                         ErrorsFound = true;
     902             :                     }
     903             :                 } // AlphaNum
     904             :             }
     905             : 
     906             :         } else { // no program calling manager in input
     907          20 :             if (state.dataRuntimeLang->NumErlPrograms > 0) {
     908           0 :                 cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     909           0 :                 ShowWarningError(state, format("Energy Management System is missing input object {}", cCurrentModuleObject));
     910           0 :                 ShowContinueError(state, "EnergyPlus Runtime Language programs need a calling manager to control when they get executed");
     911             :             }
     912             :         }
     913             : 
     914          73 :         cAlphaFieldNames.deallocate();
     915          73 :         cAlphaArgs.deallocate();
     916          73 :         lAlphaFieldBlanks.deallocate();
     917          73 :         cNumericFieldNames.deallocate();
     918          73 :         rNumericArgs.deallocate();
     919          73 :         lNumericFieldBlanks.deallocate();
     920             : 
     921          73 :         if (ErrorsFound) {
     922           0 :             ShowFatalError(state, "Errors found in getting Energy Management System input. Preceding condition causes termination.");
     923             :         }
     924          73 :     }
     925             : 
     926        6665 :     void ProcessEMSInput(EnergyPlusData &state, bool const reportErrors) // .  If true, then report out errors ,otherwise setup what we can
     927             :     {
     928             : 
     929             :         // SUBROUTINE INFORMATION:
     930             :         //       AUTHOR         B. Griffith
     931             :         //       DATE WRITTEN   May 2009
     932             : 
     933             :         // PURPOSE OF THIS SUBROUTINE:
     934             :         // contains Some input checks that need to be deferred until later in the simulation
     935             : 
     936             :         // METHODOLOGY EMPLOYED:
     937             :         // Loop over objects doing input checks.
     938             :         // Had to break up get user input into two phases because
     939             :         // the actuators can't be set up until all the HVAC systems are read in, sized, etc.
     940             :         // but we also want to allow customizing sizing calcs which occur much earlier in the simulation.
     941             :         //  so here we do a final pass and throw the errors that would usually occur during get input.
     942             : 
     943             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     944             :         OutputProcessor::VariableType VarType;
     945        6665 :         bool ErrorsFound(false);
     946             :         bool FoundObjectType;
     947             :         bool FoundObjectName;
     948             :         bool FoundActuatorName;
     949             :         int ActuatorVariableNum;
     950             :         int InternVarNum;        // local do loop index
     951             :         int InternalVarAvailNum; // local do loop index
     952        6665 :         std::string cCurrentModuleObject;
     953             : 
     954        6665 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     955      170333 :         for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     956      163668 :             if (state.dataRuntimeLang->Sensor(SensorNum).CheckedOkay) continue;
     957             : 
     958             :             // try again to process sensor.
     959       56099 :             int VarIndex = GetMeterIndex(state, state.dataRuntimeLang->Sensor(SensorNum).OutputVarName);
     960       56099 :             if (VarIndex > -1) {
     961             : 
     962         184 :                 state.dataRuntimeLang->Sensor(SensorNum).VariableType = OutputProcessor::VariableType::Meter;
     963         184 :                 state.dataRuntimeLang->Sensor(SensorNum).Index = VarIndex;
     964             : 
     965             :             } else {
     966             :                 // Search for variable names
     967       55915 :                 GetVariableTypeAndIndex(state,
     968       55915 :                                         state.dataRuntimeLang->Sensor(SensorNum).OutputVarName,
     969       55915 :                                         state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName,
     970             :                                         VarType,
     971             :                                         VarIndex);
     972       55915 :                 if (VarType == OutputProcessor::VariableType::Invalid) {
     973       54657 :                     if (reportErrors) {
     974           0 :                         ShowSevereError(
     975             :                             state,
     976           0 :                             format("Invalid Output:Variable or Output:Meter Name ={}", state.dataRuntimeLang->Sensor(SensorNum).OutputVarName));
     977           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->Sensor(SensorNum).Name));
     978           0 :                         ShowContinueError(state, "Output:Variable Name not found");
     979           0 :                         ErrorsFound = true;
     980             :                     }
     981        1258 :                 } else if (VarIndex == -1) {
     982           0 :                     if (reportErrors) {
     983           0 :                         ShowSevereError(state,
     984           0 :                                         format("Invalid Output:Variable or Output:Meter Index Key Name ={}",
     985           0 :                                                state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName));
     986           0 :                         ShowContinueError(state,
     987           0 :                                           format("For Output:Variable or Output:Meter = {}", state.dataRuntimeLang->Sensor(SensorNum).OutputVarName));
     988           0 :                         ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->Sensor(SensorNum).Name));
     989           0 :                         ShowContinueError(state, "Unique Key Name not found.");
     990           0 :                         ErrorsFound = true;
     991             :                     }
     992             :                 } else {
     993        1258 :                     state.dataRuntimeLang->Sensor(SensorNum).VariableType = VarType;
     994        1258 :                     state.dataRuntimeLang->Sensor(SensorNum).Index = VarIndex;
     995        1258 :                     state.dataRuntimeLang->Sensor(SensorNum).CheckedOkay = true;
     996             :                     // If variable is Schedule Value, then get the schedule id to register it as being used
     997        1258 :                     if (Util::SameString(state.dataRuntimeLang->Sensor(SensorNum).OutputVarName, "Schedule Value")) {
     998          34 :                         state.dataRuntimeLang->Sensor(SensorNum).SchedNum =
     999          34 :                             ScheduleManager::GetScheduleIndex(state, state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName);
    1000          34 :                         if (state.dataRuntimeLang->Sensor(SensorNum).SchedNum == 0) {
    1001           0 :                             state.dataRuntimeLang->Sensor(SensorNum).CheckedOkay = false;
    1002           0 :                             if (reportErrors) {
    1003           0 :                                 ShowSevereError(state,
    1004           0 :                                                 format("Invalid Output:Variable or Output:Meter Index Key Name ={}",
    1005           0 :                                                        state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName));
    1006           0 :                                 ShowContinueError(
    1007             :                                     state,
    1008           0 :                                     format("For Output:Variable or Output:Meter = {}", state.dataRuntimeLang->Sensor(SensorNum).OutputVarName));
    1009           0 :                                 ShowContinueError(state,
    1010           0 :                                                   format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->Sensor(SensorNum).Name));
    1011           0 :                                 ShowContinueError(state, "Schedule Name not found.");
    1012           0 :                                 ErrorsFound = true;
    1013             :                             }
    1014             :                         }
    1015             :                     }
    1016             :                 }
    1017             :             }
    1018             : 
    1019             :         } // SensorNum
    1020             : 
    1021             :         // added for FMU
    1022       67072 :         for (int ActuatorNum = 1; ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
    1023       67072 :                                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
    1024       67072 :                                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
    1025             :              ++ActuatorNum) {
    1026             :             // If we process the ExternalInterface actuators, all we need to do is to change the
    1027             : 
    1028       60407 :             if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed) {
    1029       60373 :                 cCurrentModuleObject = "EnergyManagementSystem:Actuator";
    1030          34 :             } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed) {
    1031           0 :                 cCurrentModuleObject = "ExternalInterface:Actuator";
    1032          34 :             } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
    1033          34 :                                           state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed) {
    1034          34 :                 cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
    1035           0 :             } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
    1036           0 :                                           state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
    1037           0 :                                           state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed) {
    1038           0 :                 cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
    1039             :             }
    1040             : 
    1041       60407 :             if (state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).CheckedOkay) continue;
    1042       15854 :             FoundObjectType = false;
    1043       15854 :             FoundObjectName = false;
    1044       15854 :             FoundActuatorName = false;
    1045    22019871 :             for (ActuatorVariableNum = 1; ActuatorVariableNum <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorVariableNum) {
    1046    22004358 :                 if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).ComponentTypeName,
    1047    22004358 :                                      state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ComponentTypeName)) {
    1048       55808 :                     FoundObjectType = true;
    1049       55808 :                     if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).UniqueIDName,
    1050       55808 :                                          state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).UniqueIDName)) {
    1051         681 :                         FoundObjectName = true;
    1052         681 :                         if (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).ControlTypeName,
    1053         681 :                                              state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ControlTypeName)) {
    1054         341 :                             FoundActuatorName = true;
    1055         341 :                             break;
    1056             :                         }
    1057             :                     }
    1058             :                 }
    1059             :             }
    1060             : 
    1061       15854 :             if (!FoundObjectType) {
    1062       13913 :                 if (reportErrors) {
    1063           0 :                     ShowSevereError(
    1064           0 :                         state, format("Invalid Actuated Component Type ={}", state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ComponentTypeName));
    1065           0 :                     ShowContinueError(state,
    1066           0 :                                       format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).Name));
    1067           0 :                     ShowContinueError(state, "Component Type not found");
    1068           0 :                     if (state.dataRuntimeLang->OutputEDDFile) {
    1069           0 :                         ShowContinueError(state, "Review .edd file for valid component types.");
    1070             :                     } else {
    1071           0 :                         ShowContinueError(state, "Use Output:EnergyManagementSystem object to create .edd file for valid component types.");
    1072             :                     }
    1073           0 :                     ErrorsFound = true;
    1074             :                 }
    1075             :             }
    1076             : 
    1077       15854 :             if (!FoundObjectName) {
    1078       15513 :                 if (reportErrors) {
    1079           0 :                     ShowSevereError(
    1080             :                         state,
    1081           0 :                         format("Invalid Actuated Component Unique Name ={}", state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).UniqueIDName));
    1082           0 :                     ShowContinueError(state,
    1083           0 :                                       format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).Name));
    1084           0 :                     ShowContinueError(state, "Component Unique key name not found ");
    1085           0 :                     if (state.dataRuntimeLang->OutputEDDFile) {
    1086           0 :                         ShowContinueError(state, "Review edd file for valid component names.");
    1087             :                     } else {
    1088           0 :                         ShowContinueError(state, "Use Output:EnergyManagementSystem object to create .edd file for valid component names.");
    1089             :                     }
    1090           0 :                     ErrorsFound = true;
    1091             :                 }
    1092             :             }
    1093             : 
    1094       15854 :             if (!FoundActuatorName) {
    1095       15513 :                 if (reportErrors) {
    1096           0 :                     ShowSevereError(
    1097             :                         state,
    1098           0 :                         format("Invalid Actuated Component Control Type ={}", state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ControlTypeName));
    1099           0 :                     ShowContinueError(state,
    1100           0 :                                       format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).Name));
    1101           0 :                     ShowContinueError(state, "Control Type not found");
    1102           0 :                     if (state.dataRuntimeLang->OutputEDDFile) {
    1103           0 :                         ShowContinueError(state, "Review edd file for valid component control types.");
    1104             :                     } else {
    1105           0 :                         ShowContinueError(state, "Use Output:EnergyManagementSystem object to create .edd file for valid component control types.");
    1106             :                     }
    1107           0 :                     ErrorsFound = true;
    1108             :                 }
    1109             :             } else {
    1110         341 :                 state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ActuatorVariableNum = ActuatorVariableNum;
    1111         341 :                 state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).CheckedOkay = true;
    1112         341 :                 int nHandle = state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).handleCount;
    1113         341 :                 if (nHandle > 0) {
    1114           8 :                     EnergyPlus::ShowWarningError(state, format("Seems like you already tried to get a Handle on this Actuator {}times.", nHandle));
    1115          16 :                     EnergyPlus::ShowContinueError(state,
    1116          16 :                                                   format("Occurred for componentType='{}', controlType='{}', uniqueKey='{}'.",
    1117           8 :                                                          state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ComponentTypeName,
    1118           8 :                                                          state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ControlTypeName,
    1119           8 :                                                          state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).UniqueIDName));
    1120           8 :                     EnergyPlus::ShowContinueError(state, "You should take note that there is a risk of overwritting.");
    1121             :                 }
    1122         341 :                 ++state.dataRuntimeLang->EMSActuatorAvailable(ActuatorVariableNum).handleCount;
    1123             : 
    1124             :                 // Warn if actuator applied to an air boundary surface
    1125         341 :                 if (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).ComponentTypeName, "AIRFLOW NETWORK WINDOW/DOOR OPENING")) {
    1126             :                     int actuatedSurfNum =
    1127           1 :                         Util::FindItemInList(state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).UniqueIDName, state.dataSurface->Surface);
    1128           1 :                     if (actuatedSurfNum > 0) {
    1129           1 :                         if (state.dataSurface->Surface(actuatedSurfNum).IsAirBoundarySurf) {
    1130           0 :                             ShowWarningError(
    1131             :                                 state,
    1132           0 :                                 format("GetEMSInput: EnergyManagementSystem:Actuator={} actuates an opening attached to an air boundary surface.",
    1133           0 :                                        state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum).Name));
    1134             :                         }
    1135             :                     }
    1136             :                 }
    1137             :             }
    1138             :         } // ActuatorNum
    1139             : 
    1140        6665 :         cCurrentModuleObject = "EnergyManagementSystem:InternalVariable";
    1141       55843 :         for (InternVarNum = 1; InternVarNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternVarNum) {
    1142       49178 :             if (state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay) continue;
    1143        8255 :             FoundObjectType = false;
    1144        8255 :             FoundObjectName = false;
    1145     2083930 :             for (InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    1146     2075975 :                 if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName,
    1147     2075975 :                                      state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternalDataTypeName)) {
    1148        2156 :                     FoundObjectType = true;
    1149        2156 :                     if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName,
    1150        2156 :                                          state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName)) {
    1151         300 :                         FoundObjectName = true;
    1152         300 :                         break; // InternalVarAvailNum now holds needed index pointer
    1153             :                     }
    1154             :                 }
    1155             :             }
    1156             : 
    1157        8255 :             if (!FoundObjectType) {
    1158        6675 :                 if (reportErrors) {
    1159           0 :                     ShowSevereError(
    1160             :                         state,
    1161           0 :                         format("Invalid Internal Data Type ={}", state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternalDataTypeName));
    1162           0 :                     ShowContinueError(
    1163           0 :                         state, format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).Name));
    1164           0 :                     ShowContinueError(state, "Internal data type name not found");
    1165           0 :                     ErrorsFound = true;
    1166             :                 }
    1167             :             }
    1168             : 
    1169        8255 :             if (!FoundObjectName) {
    1170        7955 :                 if (reportErrors) {
    1171           0 :                     ShowSevereError(
    1172             :                         state,
    1173           0 :                         format("Invalid Internal Data Index Key Name ={}", state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName));
    1174           0 :                     ShowContinueError(
    1175           0 :                         state, format("Entered in {}={}", cCurrentModuleObject, state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).Name));
    1176           0 :                     ShowContinueError(state, "Internal data unique identifier not found");
    1177           0 :                     ErrorsFound = true;
    1178             :                 }
    1179             :             } else {
    1180         300 :                 state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternVarNum = InternalVarAvailNum;
    1181         300 :                 state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay = true;
    1182             :             }
    1183             :         }
    1184        6665 :         if (reportErrors) {
    1185          72 :             EchoOutActuatorKeyChoices(state);
    1186          72 :             EchoOutInternalVariableChoices(state);
    1187             :         }
    1188             : 
    1189        6665 :         if (ErrorsFound) {
    1190           0 :             ShowFatalError(state, "Errors found in processing Energy Management System input. Preceding condition causes termination.");
    1191             :         }
    1192             : 
    1193        6665 :         if (reportErrors) {
    1194          72 :             RuntimeLanguageProcessor::BeginEnvrnInitializeRuntimeLanguage(state);
    1195             :         }
    1196        6665 :     }
    1197             : 
    1198       57708 :     void GetVariableTypeAndIndex(
    1199             :         EnergyPlusData &state, std::string const &VarName, std::string const &VarKeyName, OutputProcessor::VariableType &VarType, int &VarIndex)
    1200             :     {
    1201             : 
    1202             :         // SUBROUTINE INFORMATION:
    1203             :         //       AUTHOR         Peter Graham Ellis
    1204             :         //       DATE WRITTEN   June 2006
    1205             : 
    1206             :         // PURPOSE OF THIS SUBROUTINE:
    1207             :         // local helper routine intended to lookup report variables only.
    1208             :         //    Use GetMeterIndex for meters.
    1209             : 
    1210             :         // METHODOLOGY EMPLOYED:
    1211             :         // make calls to OutputProcessor methods GetVariableKeyCountandType and GetVariableKeys
    1212             : 
    1213             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1214             :         int NumKeys;
    1215             :         OutputProcessor::StoreType AvgOrSum;
    1216             :         OutputProcessor::TimeStepType StepType;
    1217       57708 :         Constant::Units units = Constant::Units::None;
    1218       57708 :         Array1D_string keyName;
    1219       57708 :         Array1D_int KeyIndex;
    1220             : 
    1221       57708 :         VarType = OutputProcessor::VariableType::Invalid;
    1222       57708 :         VarIndex = -1;
    1223       57708 :         GetVariableKeyCountandType(state, VarName, NumKeys, VarType, AvgOrSum, StepType, units);
    1224             : 
    1225             :         // note that schedules are not getting VarType set right...
    1226             : 
    1227       57708 :         if (NumKeys > 0) {
    1228        1789 :             KeyIndex.allocate(NumKeys);
    1229        1789 :             keyName.allocate(NumKeys);
    1230        1789 :             GetVariableKeys(state, VarName, VarType, keyName, KeyIndex);
    1231             : 
    1232        1789 :             if (VarType == OutputProcessor::VariableType::Schedule) {
    1233           0 :                 VarIndex = KeyIndex(1);
    1234        1789 :             } else if (keyName(1) == "ENVIRONMENT") {
    1235          38 :                 VarIndex = KeyIndex(1);
    1236             :             } else {
    1237       72312 :                 for (int KeyNum = 1; KeyNum <= NumKeys; ++KeyNum) {
    1238       72312 :                     if (state.dataOutputProcessor->outVars[KeyIndex(KeyNum)]->keyUC == VarKeyName) {
    1239        1751 :                         VarIndex = KeyIndex(KeyNum);
    1240        1751 :                         break;
    1241             :                     }
    1242             :                 }
    1243             :             }
    1244        1789 :             KeyIndex.deallocate();
    1245        1789 :             keyName.deallocate();
    1246             :         }
    1247       57708 :     }
    1248             : 
    1249          72 :     void EchoOutActuatorKeyChoices(EnergyPlusData &state)
    1250             :     {
    1251             : 
    1252             :         // SUBROUTINE INFORMATION:
    1253             :         //       AUTHOR         Brent Griffith
    1254             :         //       DATE WRITTEN   April 2009
    1255             : 
    1256             :         // PURPOSE OF THIS SUBROUTINE:
    1257             :         // echo out actuators registered with SetupEMSActuator for user access
    1258             : 
    1259             :         // METHODOLOGY EMPLOYED:
    1260             :         // mine structure and write to edd file
    1261             :         // note this executes after final processing and sizing-related calling points may already execute Erl programs
    1262             : 
    1263          72 :         if (state.dataRuntimeLang->OutputEMSActuatorAvailFull) {
    1264             : 
    1265          40 :             print(state.files.edd, "! <EnergyManagementSystem:Actuator Available>, Component Unique Name, Component Type,  Control Type, Units\n");
    1266       64383 :             for (int ActuatorLoop = 1; ActuatorLoop <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorLoop) {
    1267       64343 :                 print(state.files.edd,
    1268             :                       "EnergyManagementSystem:Actuator Available,{},{},{},{}\n",
    1269       64343 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).UniqueIDName,
    1270       64343 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ComponentTypeName,
    1271       64343 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ControlTypeName,
    1272       64343 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).Units);
    1273             :             }
    1274          32 :         } else if (state.dataRuntimeLang->OutputEMSActuatorAvailSmall) {
    1275           0 :             print(state.files.edd, "! <EnergyManagementSystem:Actuator Available>, *, Component Type, Control Type, Units\n");
    1276             :             int FoundTypeName;
    1277             :             int FoundControlType;
    1278           0 :             for (int ActuatorLoop = 1; ActuatorLoop <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorLoop) {
    1279           0 :                 if (ActuatorLoop + 1 <= state.dataRuntimeLang->numEMSActuatorsAvailable) {
    1280           0 :                     FoundTypeName = Util::FindItemInList(
    1281           0 :                         state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ComponentTypeName,
    1282           0 :                         state.dataRuntimeLang->EMSActuatorAvailable({ActuatorLoop + 1, state.dataRuntimeLang->numEMSActuatorsAvailable}),
    1283             :                         &DataRuntimeLanguage::EMSActuatorAvailableType::ComponentTypeName,
    1284           0 :                         state.dataRuntimeLang->numEMSActuatorsAvailable - (ActuatorLoop + 1));
    1285           0 :                     FoundControlType = Util::FindItemInList(
    1286           0 :                         state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ControlTypeName,
    1287           0 :                         state.dataRuntimeLang->EMSActuatorAvailable({ActuatorLoop + 1, state.dataRuntimeLang->numEMSActuatorsAvailable}),
    1288             :                         &DataRuntimeLanguage::EMSActuatorAvailableType::ControlTypeName,
    1289           0 :                         state.dataRuntimeLang->numEMSActuatorsAvailable - (ActuatorLoop + 1));
    1290             :                 } else {
    1291           0 :                     FoundTypeName = 1;
    1292           0 :                     FoundControlType = 1;
    1293             :                 }
    1294           0 :                 if ((FoundTypeName == 0) || (FoundControlType == 0)) {
    1295           0 :                     print(state.files.edd,
    1296             :                           "EnergyManagementSystem:Actuator Available, *,{},{},{}\n",
    1297           0 :                           state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ComponentTypeName,
    1298           0 :                           state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ControlTypeName,
    1299           0 :                           state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).Units);
    1300             :                 }
    1301             :             }
    1302             :         }
    1303          72 :     }
    1304             : 
    1305          72 :     void EchoOutInternalVariableChoices(EnergyPlusData &state)
    1306             :     {
    1307             : 
    1308             :         // SUBROUTINE INFORMATION:
    1309             :         //       AUTHOR         Brent Griffith
    1310             :         //       DATE WRITTEN   April 2009
    1311             : 
    1312             :         // PURPOSE OF THIS SUBROUTINE:
    1313             :         // echo out actuators registered with SetupEMSActuator for user access
    1314             : 
    1315             :         // METHODOLOGY EMPLOYED:
    1316             :         // mine structure and write to eio file
    1317             : 
    1318          72 :         if (state.dataRuntimeLang->OutputEMSInternalVarsFull) {
    1319             : 
    1320          40 :             print(state.files.edd, "! <EnergyManagementSystem:InternalVariable Available>, Unique Name, Internal Data Type, Units \n");
    1321       10899 :             for (int InternalDataLoop = 1; InternalDataLoop <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalDataLoop) {
    1322       10859 :                 print(state.files.edd,
    1323             :                       "EnergyManagementSystem:InternalVariable Available,{},{},{}\n",
    1324       10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).UniqueIDName,
    1325       10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).DataTypeName,
    1326       10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).Units);
    1327             :             }
    1328             : 
    1329          32 :         } else if (state.dataRuntimeLang->OutputEMSInternalVarsSmall) {
    1330           0 :             print(state.files.edd, "! <EnergyManagementSystem:InternalVariable Available>, *, Internal Data Type\n");
    1331           0 :             for (int InternalDataLoop = 1; InternalDataLoop <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalDataLoop) {
    1332           0 :                 int Found(0);
    1333           0 :                 if (InternalDataLoop + 1 <= state.dataRuntimeLang->numEMSInternalVarsAvailable) {
    1334           0 :                     Found = Util::FindItemInList(
    1335           0 :                         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).DataTypeName,
    1336           0 :                         state.dataRuntimeLang->EMSInternalVarsAvailable({InternalDataLoop + 1, state.dataRuntimeLang->numEMSInternalVarsAvailable}),
    1337             :                         &DataRuntimeLanguage::InternalVarsAvailableType::DataTypeName,
    1338           0 :                         state.dataRuntimeLang->numEMSInternalVarsAvailable - (InternalDataLoop + 1));
    1339             :                 }
    1340           0 :                 if (Found == 0) {
    1341           0 :                     print(state.files.edd,
    1342             :                           "EnergyManagementSystem:InternalVariable Available, *,{},{}\n",
    1343           0 :                           state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).DataTypeName,
    1344           0 :                           state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).Units);
    1345             :                 }
    1346             :             }
    1347             :         }
    1348          72 :     }
    1349             : 
    1350          72 :     void SetupNodeSetPointsAsActuators(EnergyPlusData &state)
    1351             :     {
    1352             : 
    1353             :         // SUBROUTINE INFORMATION:
    1354             :         //       AUTHOR         Brent Griffith
    1355             :         //       DATE WRITTEN   May 2009
    1356             : 
    1357             :         // PURPOSE OF THIS SUBROUTINE:
    1358             :         // make system nodes in model available for EMS control
    1359             : 
    1360             :         // METHODOLOGY EMPLOYED:
    1361             :         // Loop over node structures and make calls to SetupEMSActuator
    1362             :         // the pattern for the basic node setpoints is a little different in that the actuators directly
    1363             :         // affect the node variables, rather than using separate logical override flag and ems values
    1364             : 
    1365          72 :         state.dataEMSMgr->lDummy = false;
    1366             : 
    1367          72 :         if (state.dataLoopNodes->NumOfNodes > 0) {
    1368             : 
    1369       13892 :             for (int LoopNode = 1; LoopNode <= state.dataLoopNodes->NumOfNodes; ++LoopNode) {
    1370             :                 // setup the setpoint for each type of variable that can be controlled
    1371       27644 :                 SetupEMSActuator(state,
    1372             :                                  "System Node Setpoint",
    1373       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1374             :                                  "Temperature Setpoint",
    1375             :                                  "[C]",
    1376       13822 :                                  state.dataEMSMgr->lDummy,
    1377       13822 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPoint);
    1378       27644 :                 SetupEMSActuator(state,
    1379             :                                  "System Node Setpoint",
    1380       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1381             :                                  "Temperature Minimum Setpoint",
    1382             :                                  "[C]",
    1383       13822 :                                  state.dataEMSMgr->lDummy,
    1384       13822 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPointLo);
    1385       27644 :                 SetupEMSActuator(state,
    1386             :                                  "System Node Setpoint",
    1387       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1388             :                                  "Temperature Maximum Setpoint",
    1389             :                                  "[C]",
    1390       13822 :                                  state.dataEMSMgr->lDummy,
    1391       13822 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPointHi);
    1392       27644 :                 SetupEMSActuator(state,
    1393             :                                  "System Node Setpoint",
    1394       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1395             :                                  "Humidity Ratio Setpoint",
    1396             :                                  "[kgWater/kgDryAir]",
    1397       13822 :                                  state.dataEMSMgr->lDummy,
    1398       13822 :                                  state.dataLoopNodes->Node(LoopNode).HumRatSetPoint);
    1399       27644 :                 SetupEMSActuator(state,
    1400             :                                  "System Node Setpoint",
    1401       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1402             :                                  "Humidity Ratio Maximum Setpoint",
    1403             :                                  "[kgWater/kgDryAir]",
    1404       13822 :                                  state.dataEMSMgr->lDummy,
    1405       13822 :                                  state.dataLoopNodes->Node(LoopNode).HumRatMax);
    1406       27644 :                 SetupEMSActuator(state,
    1407             :                                  "System Node Setpoint",
    1408       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1409             :                                  "Humidity Ratio Minimum Setpoint",
    1410             :                                  "[kgWater/kgDryAir]",
    1411       13822 :                                  state.dataEMSMgr->lDummy,
    1412       13822 :                                  state.dataLoopNodes->Node(LoopNode).HumRatMin);
    1413       27644 :                 SetupEMSActuator(state,
    1414             :                                  "System Node Setpoint",
    1415       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1416             :                                  "Mass Flow Rate Setpoint",
    1417             :                                  "[kg/s]",
    1418       13822 :                                  state.dataEMSMgr->lDummy,
    1419       13822 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateSetPoint);
    1420       27644 :                 SetupEMSActuator(state,
    1421             :                                  "System Node Setpoint",
    1422       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1423             :                                  "Mass Flow Rate Maximum Available Setpoint",
    1424             :                                  "[kg/s]",
    1425       13822 :                                  state.dataEMSMgr->lDummy,
    1426       13822 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateMaxAvail);
    1427       27644 :                 SetupEMSActuator(state,
    1428             :                                  "System Node Setpoint",
    1429       13822 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1430             :                                  "Mass Flow Rate Minimum Available Setpoint",
    1431             :                                  "[kg/s]",
    1432       13822 :                                  state.dataEMSMgr->lDummy,
    1433       13822 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateMinAvail);
    1434             :             }
    1435             : 
    1436             :         } // NumOfNodes > 0
    1437             : 
    1438          72 :         if (state.dataOutAirNodeMgr->NumOutsideAirNodes > 0) {
    1439         737 :             for (int OutsideAirNodeNum = 1; OutsideAirNodeNum <= state.dataOutAirNodeMgr->NumOutsideAirNodes; ++OutsideAirNodeNum) {
    1440         676 :                 int NodeNum = state.dataOutAirNodeMgr->OutsideAirNodeList(OutsideAirNodeNum);
    1441        1352 :                 SetupEMSActuator(state,
    1442             :                                  "Outdoor Air System Node",
    1443         676 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1444             :                                  "Drybulb Temperature",
    1445             :                                  "[C]",
    1446         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb,
    1447         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirDryBulb);
    1448        1352 :                 SetupEMSActuator(state,
    1449             :                                  "Outdoor Air System Node",
    1450         676 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1451             :                                  "Wetbulb Temperature",
    1452             :                                  "[C]",
    1453         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb,
    1454         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWetBulb);
    1455        1352 :                 SetupEMSActuator(state,
    1456             :                                  "Outdoor Air System Node",
    1457         676 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1458             :                                  "Wind Speed",
    1459             :                                  "[m/s]",
    1460         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindSpeed,
    1461         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindSpeed);
    1462        1352 :                 SetupEMSActuator(state,
    1463             :                                  "Outdoor Air System Node",
    1464         676 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1465             :                                  "Wind Direction",
    1466             :                                  "[degree]",
    1467         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindDir,
    1468         676 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindDir);
    1469        8290 :                 for (int ActuatorUsedLoop = 1; ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed; ActuatorUsedLoop++) {
    1470        7750 :                     if (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ComponentTypeName, "Outdoor Air System Node") &&
    1471         128 :                         Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).UniqueIDName,
    1472         128 :                                          state.dataLoopNodes->NodeID(NodeNum))) {
    1473           8 :                         state.dataLoopNodes->Node(NodeNum).IsLocalNode = true;
    1474           8 :                         break;
    1475             :                     }
    1476             :                 }
    1477             :             }
    1478             :         }
    1479          72 :     }
    1480             : 
    1481     2804481 :     void UpdateEMSTrendVariables(EnergyPlusData &state)
    1482             :     {
    1483             : 
    1484             :         // SUBROUTINE INFORMATION:
    1485             :         //       AUTHOR         Brent Griffith
    1486             :         //       DATE WRITTEN   May 2009
    1487             : 
    1488             :         // PURPOSE OF THIS SUBROUTINE:
    1489             :         // Logged trend data
    1490             : 
    1491             :         // METHODOLOGY EMPLOYED:
    1492             :         // Store current value of Erl Variable in Trend stack
    1493             :         // Trend arrays are pushed so that the latest value is
    1494             :         //  always at index 1.  old values get lost.
    1495             : 
    1496             :         // checks with quick return if no updates needed.
    1497     2804481 :         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) return;
    1498      408516 :         if (state.dataRuntimeLang->NumErlTrendVariables == 0) return;
    1499             : 
    1500       23736 :         for (int TrendNum = 1; TrendNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendNum) {
    1501       14475 :             int ErlVarNum = state.dataRuntimeLang->TrendVariable(TrendNum).ErlVariablePointer;
    1502       14475 :             int TrendDepth = state.dataRuntimeLang->TrendVariable(TrendNum).LogDepth;
    1503       14475 :             if ((ErlVarNum > 0) && (TrendDepth > 0)) {
    1504       14475 :                 Real64 currentVal = state.dataRuntimeLang->ErlVariable(ErlVarNum).Value.Number;
    1505             :                 // push into trend
    1506       14475 :                 state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR = state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR;
    1507       14475 :                 state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR(1) = currentVal;
    1508       28950 :                 state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR({2, TrendDepth}) =
    1509       43425 :                     state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR({1, TrendDepth - 1});
    1510             :             }
    1511             :         }
    1512             :     }
    1513             : 
    1514        1914 :     bool CheckIfNodeSetPointManaged(EnergyPlusData &state, int const NodeNum, HVAC::CtrlVarType const ctrlVar, bool byHandle)
    1515             :     {
    1516             : 
    1517             :         // SUBROUTINE INFORMATION:
    1518             :         //       AUTHOR         Brent Griffith
    1519             :         //       DATE WRITTEN   May 2009
    1520             :         //       MODIFIED       July 2020, Julien Marrec of EffiBEM: added option to check by handle (for API)
    1521             : 
    1522             :         // PURPOSE OF THIS SUBROUTINE:
    1523             :         // Provide method to verify that a specific node is (probably) managed by EMS
    1524             : 
    1525             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1526        1914 :         bool FoundControl(false);
    1527             : 
    1528        1914 :         std::string cNodeName = state.dataLoopNodes->NodeID(NodeNum);
    1529        1914 :         std::string cComponentTypeName = "System Node Setpoint";
    1530        1914 :         std::string_view cControlTypeName = controlTypeNames[(int)ctrlVar];
    1531             : 
    1532        1914 :         if (byHandle) {
    1533       44242 :             for (int Loop = 1; Loop <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++Loop) {
    1534       44727 :                 if ((state.dataRuntimeLang->EMSActuatorAvailable(Loop).handleCount > 0) &&
    1535         732 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).ComponentTypeName, cComponentTypeName)) &&
    1536       44974 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).UniqueIDName, cNodeName)) &&
    1537          28 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).ControlTypeName, cControlTypeName))) {
    1538          28 :                     FoundControl = true;
    1539          28 :                     break;
    1540             :                 }
    1541             :             }
    1542          28 :             if (!FoundControl) {
    1543           0 :                 ShowWarningError(
    1544           0 :                     state, format("Missing '{}' for node named named '{}'.", controlTypeNames[(int)ctrlVar], state.dataLoopNodes->NodeID(NodeNum)));
    1545             :             }
    1546             :         } else {
    1547        8184 :             for (int Loop = 1; Loop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed; ++Loop) {
    1548        7595 :                 if ((Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).ComponentTypeName, cComponentTypeName)) &&
    1549        7595 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).UniqueIDName, cNodeName)) &&
    1550          82 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).ControlTypeName, cControlTypeName))) {
    1551          82 :                     FoundControl = true;
    1552          82 :                     break;
    1553             :                 }
    1554             :             }
    1555             :         }
    1556             : 
    1557        1914 :         return FoundControl;
    1558        1914 :     }
    1559             : 
    1560        1886 :     bool CheckIfNodeSetPointManagedByEMS(EnergyPlusData &state,
    1561             :                                          int const NodeNum, // index of node being checked.
    1562             :                                          HVAC::CtrlVarType const ctrlVar,
    1563             :                                          bool &ErrorFlag)
    1564             :     {
    1565             : 
    1566             :         // SUBROUTINE INFORMATION:
    1567             :         //       AUTHOR         Brent Griffith
    1568             :         //       DATE WRITTEN   May 2009
    1569             : 
    1570             :         // PURPOSE OF THIS SUBROUTINE:
    1571             :         // Provide method to verify that a specific node is (probably) managed by EMS
    1572             : 
    1573             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1574        1886 :         bool FoundControl = CheckIfNodeSetPointManaged(state, NodeNum, ctrlVar, false);
    1575             : 
    1576        1886 :         if ((!ErrorFlag) && (!FoundControl)) {
    1577        1804 :             int numPythonPlugins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PythonPlugin:Instance");
    1578        1804 :             int numActiveCallbacks = PluginManagement::PluginManager::numActiveCallbacks(state); // errorCallback;
    1579        1804 :             if ((numPythonPlugins + numActiveCallbacks) == 0) {
    1580        1396 :                 ErrorFlag = true;
    1581             :             } else {
    1582             :                 // We'll defer to checking at the end whether a Plugin / API called getActuatorHandle on it
    1583         408 :                 auto &nodeSetpointCheck = state.dataLoopNodes->NodeSetpointCheck(NodeNum);
    1584         408 :                 nodeSetpointCheck.needsSetpointChecking = true;
    1585         408 :                 nodeSetpointCheck.checkSetPoint[(int)ctrlVar] = true;
    1586             :             }
    1587             :         }
    1588             : 
    1589        1886 :         return FoundControl;
    1590             :     }
    1591             : 
    1592           0 :     bool isScheduleManaged(EnergyPlusData &state, int const scheduleNum)
    1593             :     {
    1594             :         // Check if a specific schedule has an EMS or External Interface actuator assigned to it
    1595             :         static constexpr std::string_view cControlTypeName = "SCHEDULE VALUE";
    1596           0 :         std::string_view cSchedName = state.dataScheduleMgr->Schedule(scheduleNum).Name;
    1597             : 
    1598           0 :         for (int Loop = 1; Loop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed; ++Loop) {
    1599           0 :             if ((Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).UniqueIDName, cSchedName)) &&
    1600           0 :                 (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).ControlTypeName, cControlTypeName))) {
    1601           0 :                 return true;
    1602             :             }
    1603             :         }
    1604           0 :         return false;
    1605             :     }
    1606             : 
    1607         794 :     void checkSetpointNodesAtEnd(EnergyPlusData &state)
    1608             :     {
    1609             : 
    1610             :         // SUBROUTINE INFORMATION:
    1611             :         //       AUTHOR         Julien Marrec of EffiBEM
    1612             :         //       DATE WRITTEN   July 2020
    1613             : 
    1614             :         // PURPOSE OF THIS SUBROUTINE:
    1615             :         // This subroutine checks any nodes where we couldn't find a Setpoint in EMS, after the PythonPlugin / API have been called
    1616             :         // so we can check if getActuatorHandle was ever actually called for that node.
    1617             : 
    1618         794 :         bool FatalErrorFlag = false;
    1619             : 
    1620       62943 :         for (int NodeNum = 1; NodeNum <= state.dataLoopNodes->NumOfNodes; ++NodeNum) {
    1621       62149 :             auto &nodeSetpointCheck = state.dataLoopNodes->NodeSetpointCheck(NodeNum);
    1622             : 
    1623       62149 :             if (nodeSetpointCheck.needsSetpointChecking) {
    1624             :                 // Start by setting it to false (assume matched)
    1625          28 :                 nodeSetpointCheck.needsSetpointChecking = false;
    1626             : 
    1627         280 :                 for (int iCtrlVar = 0; iCtrlVar < (int)HVAC::CtrlVarType::Num; ++iCtrlVar) {
    1628         252 :                     if (nodeSetpointCheck.checkSetPoint[iCtrlVar]) {
    1629          28 :                         nodeSetpointCheck.needsSetpointChecking |=
    1630          28 :                             !CheckIfNodeSetPointManaged(state, NodeNum, static_cast<HVAC::CtrlVarType>(iCtrlVar), true);
    1631             :                     }
    1632             :                 }
    1633             : 
    1634          28 :                 if (nodeSetpointCheck.needsSetpointChecking) {
    1635           0 :                     FatalErrorFlag = true;
    1636             :                 }
    1637             :             }
    1638             :         }
    1639             : 
    1640         794 :         if (FatalErrorFlag) {
    1641           0 :             ShowFatalError(state,
    1642             :                            "checkSetpointNodesAtEnd: At least one node does not have a setpoint attached, "
    1643             :                            "neither via a SetpointManager, EMS:Actuator, or API");
    1644             :         }
    1645         794 :     }
    1646             : 
    1647      248596 :     bool CheckIfNodeMoreInfoSensedByEMS(EnergyPlusData &state,
    1648             :                                         int const nodeNum, // index of node being checked.
    1649             :                                         std::string const &varName)
    1650             :     {
    1651      248596 :         bool returnValue = false;
    1652     5365252 :         for (int loop = 1; loop <= state.dataRuntimeLang->NumSensors; ++loop) {
    1653     5118288 :             if (state.dataRuntimeLang->Sensor(loop).UniqueKeyName == state.dataLoopNodes->NodeID(nodeNum) &&
    1654        1632 :                 Util::SameString(state.dataRuntimeLang->Sensor(loop).OutputVarName, varName)) {
    1655           1 :                 returnValue = true;
    1656             :             }
    1657             :         }
    1658             : 
    1659      248596 :         return returnValue;
    1660             :     }
    1661             : 
    1662          72 :     void SetupPrimaryAirSystemAvailMgrAsActuators(EnergyPlusData &state)
    1663             :     {
    1664             : 
    1665             :         // SUBROUTINE INFORMATION:
    1666             :         //       AUTHOR         Brent Griffith
    1667             :         //       DATE WRITTEN   May 2009
    1668             : 
    1669             :         // PURPOSE OF THIS SUBROUTINE:
    1670             :         // make air system status available as EMS actuator
    1671             : 
    1672          72 :         state.dataEMSMgr->lDummy2 = false;
    1673             : 
    1674          72 :         if (allocated(state.dataAirLoop->PriAirSysAvailMgr)) {
    1675          60 :             int numAirLoops = isize(state.dataAirLoop->PriAirSysAvailMgr);
    1676         397 :             for (int Loop = 1; Loop <= numAirLoops; ++Loop) {
    1677         674 :                 SetupEMSActuator(state,
    1678             :                                  "AirLoopHVAC",
    1679         337 :                                  state.dataAirSystemsData->PrimaryAirSystems(Loop).Name,
    1680             :                                  "Availability Status",
    1681             :                                  "[ ]",
    1682         337 :                                  state.dataEMSMgr->lDummy2,
    1683         337 :                                  (int &)state.dataAirLoop->PriAirSysAvailMgr(Loop).availStatus);
    1684             :             }
    1685             :         }
    1686          72 :     }
    1687             : 
    1688          73 :     void SetupWindowShadingControlActuators(EnergyPlusData &state)
    1689             :     {
    1690             : 
    1691             :         // SUBROUTINE INFORMATION:
    1692             :         //       AUTHOR         Brent Griffith
    1693             :         //       DATE WRITTEN   May 2009
    1694             : 
    1695             :         // PURPOSE OF THIS SUBROUTINE:
    1696             :         // make calls to SetupEMSactuator for public data for Window Shades
    1697             : 
    1698             :         // METHODOLOGY EMPLOYED:
    1699             :         // Loop thru SurfaceWindow and register any shading controls
    1700             : 
    1701       10989 :         for (int loopSurfNum = 1; loopSurfNum <= state.dataSurface->TotSurfaces; ++loopSurfNum) {
    1702             : 
    1703       10916 :             if (state.dataSurface->Surface(loopSurfNum).Class != DataSurfaces::SurfaceClass::Window) continue;
    1704        1688 :             if (state.dataSurface->Surface(loopSurfNum).ExtBoundCond != DataSurfaces::ExternalEnvironment) continue;
    1705        1688 :             if (!state.dataSurface->Surface(loopSurfNum).HasShadeControl) continue;
    1706             : 
    1707          12 :             if (state.dataSurface->SurfWinHasShadeOrBlindLayer(loopSurfNum)) {
    1708          30 :                 SetupEMSActuator(state,
    1709             :                                  "Window Shading Control",
    1710          10 :                                  state.dataSurface->Surface(loopSurfNum).Name,
    1711             :                                  "Control Status",
    1712             :                                  "[ShadeStatus]",
    1713          10 :                                  state.dataSurface->SurfWinShadingFlagEMSOn(loopSurfNum),
    1714          10 :                                  state.dataSurface->SurfWinShadingFlagEMSValue(loopSurfNum));
    1715          10 :                 if (state.dataSurface->SurfWinMovableSlats(loopSurfNum)) {
    1716           0 :                     SetupEMSActuator(state,
    1717             :                                      "Window Shading Control",
    1718           0 :                                      state.dataSurface->Surface(loopSurfNum).Name,
    1719             :                                      "Slat Angle",
    1720             :                                      "[degrees]",
    1721           0 :                                      state.dataSurface->SurfWinSlatAngThisTSDegEMSon(loopSurfNum),
    1722           0 :                                      state.dataSurface->SurfWinSlatAngThisTSDegEMSValue(loopSurfNum));
    1723             :                 }
    1724           2 :             } else if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(loopSurfNum).activeWindowShadingControl).ShadingType ==
    1725             :                        DataSurfaces::WinShadingType::ExtScreen) {
    1726           0 :                 SetupEMSActuator(state,
    1727             :                                  "Window Shading Control",
    1728           0 :                                  state.dataSurface->Surface(loopSurfNum).Name,
    1729             :                                  "Control Status",
    1730             :                                  "[ShadeStatus]",
    1731           0 :                                  state.dataSurface->SurfWinShadingFlagEMSOn(loopSurfNum),
    1732           0 :                                  state.dataSurface->SurfWinShadingFlagEMSValue(loopSurfNum));
    1733             :             } else {
    1734           2 :                 if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(loopSurfNum).activeWindowShadingControl).ShadingType !=
    1735             :                     DataSurfaces::WinShadingType::SwitchableGlazing) {
    1736           0 :                     ShowSevereError(state,
    1737           0 :                                     format("Missing shade or blind layer in window construction name = '{}', surface name = '{}'.",
    1738           0 :                                            state.dataConstruction->Construct(state.dataSurface->Surface(loopSurfNum).activeShadedConstruction).Name,
    1739           0 :                                            state.dataSurface->Surface(loopSurfNum).Name));
    1740           0 :                     ShowContinueError(state,
    1741             :                                       "...'Control Status' or 'Slat Angle' EMS Actuator cannot be set for a construction that does not have a shade "
    1742             :                                       "or a blind layer.");
    1743           0 :                     ShowContinueError(state, "...Add shade or blind layer to this construction in order to be able to apply EMS Actuator.");
    1744             :                 }
    1745             :             }
    1746             :         }
    1747          73 :     }
    1748             : 
    1749          73 :     void SetupThermostatActuators(EnergyPlusData &state)
    1750             :     {
    1751             : 
    1752             :         // SUBROUTINE INFORMATION:
    1753             :         //       AUTHOR         Brent Griffith
    1754             :         //       DATE WRITTEN   May 2009
    1755             : 
    1756             :         // PURPOSE OF THIS SUBROUTINE:
    1757             :         // Make zone thermostats, humidistats, and comfort controls available to EMS
    1758             : 
    1759             :         // METHODOLOGY EMPLOYED:
    1760             :         // Loop over structures and call SetupEMSactuator for public data in DataZoneControls.
    1761             : 
    1762        1091 :         for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
    1763        2036 :             SetupEMSActuator(state,
    1764             :                              "Zone Temperature Control",
    1765        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).ZoneName,
    1766             :                              "Heating Setpoint",
    1767             :                              "[C]",
    1768        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideHeatingSetPointOn,
    1769        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideHeatingSetPointValue);
    1770        2036 :             SetupEMSActuator(state,
    1771             :                              "Zone Temperature Control",
    1772        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).ZoneName,
    1773             :                              "Cooling Setpoint",
    1774             :                              "[C]",
    1775        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideCoolingSetPointOn,
    1776        1018 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideCoolingSetPointValue);
    1777             :         }
    1778             : 
    1779          95 :         for (int Loop = 1; Loop <= state.dataZoneCtrls->NumHumidityControlZones; ++Loop) {
    1780          44 :             SetupEMSActuator(state,
    1781             :                              "Zone Humidity Control",
    1782          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).ZoneName,
    1783             :                              "Relative Humidity Humidifying Setpoint",
    1784             :                              "[%]",
    1785          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideHumidifySetPointOn,
    1786          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideHumidifySetPointValue);
    1787          44 :             SetupEMSActuator(state,
    1788             :                              "Zone Humidity Control",
    1789          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).ZoneName,
    1790             :                              "Relative Humidity Dehumidifying Setpoint",
    1791             :                              "[%]",
    1792          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideDehumidifySetPointOn,
    1793          22 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideDehumidifySetPointValue);
    1794             :         }
    1795             : 
    1796          73 :         for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
    1797           0 :             SetupEMSActuator(state,
    1798             :                              "Zone Comfort Control",
    1799           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).ZoneName,
    1800             :                              "Heating Setpoint",
    1801             :                              "[]",
    1802           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).EMSOverrideHeatingSetPointOn,
    1803           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).EMSOverrideHeatingSetPointValue);
    1804           0 :             SetupEMSActuator(state,
    1805             :                              "Zone Comfort Control",
    1806           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).ZoneName,
    1807             :                              "Cooling Setpoint",
    1808             :                              "[]",
    1809           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).EMSOverrideCoolingSetPointOn,
    1810           0 :                              state.dataZoneCtrls->ComfortControlledZone(Loop).EMSOverrideCoolingSetPointValue);
    1811             :         }
    1812          73 :     }
    1813             : 
    1814          73 :     void SetupSurfaceConvectionActuators(EnergyPlusData &state)
    1815             :     {
    1816             : 
    1817             :         // SUBROUTINE INFORMATION:
    1818             :         //       AUTHOR         Brent Griffith
    1819             :         //       DATE WRITTEN   May 2009
    1820             : 
    1821             :         // PURPOSE OF THIS SUBROUTINE:
    1822             :         // Setup EMS actuators available for surface convection coefficients
    1823             : 
    1824       10989 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1825       21832 :             SetupEMSActuator(state,
    1826             :                              "Surface",
    1827       10916 :                              state.dataSurface->Surface(SurfNum).Name,
    1828             :                              "Interior Surface Convection Heat Transfer Coefficient",
    1829             :                              "[W/m2-K]",
    1830       10916 :                              state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum),
    1831       10916 :                              state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum));
    1832       21832 :             SetupEMSActuator(state,
    1833             :                              "Surface",
    1834       10916 :                              state.dataSurface->Surface(SurfNum).Name,
    1835             :                              "Exterior Surface Convection Heat Transfer Coefficient",
    1836             :                              "[W/m2-K]",
    1837       10916 :                              state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum),
    1838       10916 :                              state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum));
    1839             :         }
    1840          73 :     }
    1841             : 
    1842          73 :     void SetupSurfaceConstructionActuators(EnergyPlusData &state)
    1843             :     {
    1844             : 
    1845             :         // SUBROUTINE INFORMATION:
    1846             :         //       AUTHOR         B. Griffith
    1847             :         //       DATE WRITTEN   Jan 2012
    1848             : 
    1849             :         // PURPOSE OF THIS SUBROUTINE:
    1850             :         // setup EMS actuators available for surface construction
    1851             : 
    1852       10989 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1853             : 
    1854       10916 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
    1855             : 
    1856       32664 :             SetupEMSActuator(state,
    1857             :                              "Surface",
    1858       10888 :                              state.dataSurface->Surface(SurfNum).Name,
    1859             :                              "Construction State",
    1860             :                              "[ ]",
    1861       10888 :                              state.dataSurface->SurfEMSConstructionOverrideON(SurfNum),
    1862       10888 :                              state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum));
    1863             :         }
    1864             : 
    1865             :         // Setup error checking storage
    1866             : 
    1867          73 :         if (!allocated(state.dataRuntimeLang->EMSConstructActuatorChecked))
    1868          73 :             state.dataRuntimeLang->EMSConstructActuatorChecked.allocate(state.dataHeatBal->TotConstructs, state.dataSurface->TotSurfaces);
    1869          73 :         state.dataRuntimeLang->EMSConstructActuatorChecked = false;
    1870             : 
    1871          73 :         if (!allocated(state.dataRuntimeLang->EMSConstructActuatorIsOkay))
    1872          73 :             state.dataRuntimeLang->EMSConstructActuatorIsOkay.allocate(state.dataHeatBal->TotConstructs, state.dataSurface->TotSurfaces);
    1873          73 :         state.dataRuntimeLang->EMSConstructActuatorIsOkay = false;
    1874          73 :     }
    1875             : 
    1876          73 :     void SetupSurfaceOutdoorBoundaryConditionActuators(EnergyPlusData &state)
    1877             :     {
    1878             : 
    1879             :         // SUBROUTINE INFORMATION:
    1880             :         //       AUTHOR         B. Griffith
    1881             :         //       DATE WRITTEN   May 2013
    1882             : 
    1883             :         // PURPOSE OF THIS SUBROUTINE:
    1884             :         // setup EMS actuators for outside boundary conditions by surface
    1885             : 
    1886             :         // METHODOLOGY EMPLOYED:
    1887             :         // loop through all surfaces, cycle if not heat transfer or outdoors BC
    1888             : 
    1889       10989 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1890             : 
    1891       10916 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
    1892       10888 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond != DataSurfaces::ExternalEnvironment) continue;
    1893             : 
    1894        7800 :             SetupEMSActuator(state,
    1895             :                              "Surface",
    1896        3900 :                              state.dataSurface->Surface(SurfNum).Name,
    1897             :                              "View Factor To Ground",
    1898             :                              "[ ]",
    1899        3900 :                              state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum),
    1900        3900 :                              state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum));
    1901             : 
    1902        7800 :             SetupEMSActuator(state,
    1903             :                              "Surface",
    1904        3900 :                              state.dataSurface->Surface(SurfNum).Name,
    1905             :                              "Outdoor Air Drybulb Temperature",
    1906             :                              "[C]",
    1907        3900 :                              state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum),
    1908        3900 :                              state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum));
    1909             : 
    1910        7800 :             SetupEMSActuator(state,
    1911             :                              "Surface",
    1912        3900 :                              state.dataSurface->Surface(SurfNum).Name,
    1913             :                              "Outdoor Air Wetbulb Temperature",
    1914             :                              "[C]",
    1915        3900 :                              state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum),
    1916        3900 :                              state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum));
    1917        3900 :             if (state.dataSurface->Surface(SurfNum).ExtWind) {
    1918        7786 :                 SetupEMSActuator(state,
    1919             :                                  "Surface",
    1920        3893 :                                  state.dataSurface->Surface(SurfNum).Name,
    1921             :                                  "Outdoor Air Wind Speed",
    1922             :                                  "[m/s]",
    1923        3893 :                                  state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum),
    1924        3893 :                                  state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum));
    1925        7786 :                 SetupEMSActuator(state,
    1926             :                                  "Surface",
    1927        3893 :                                  state.dataSurface->Surface(SurfNum).Name,
    1928             :                                  "Outdoor Air Wind Direction",
    1929             :                                  "[degree]",
    1930        3893 :                                  state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum),
    1931        3893 :                                  state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum));
    1932             :             }
    1933             :         }
    1934          73 :     }
    1935             : 
    1936          73 :     void SetupZoneInfoAsInternalDataAvail(EnergyPlusData &state)
    1937             :     {
    1938             : 
    1939             :         // SUBROUTINE INFORMATION:
    1940             :         //       AUTHOR         Brent Griffith
    1941             :         //       DATE WRITTEN   May 2009
    1942             : 
    1943             :         // PURPOSE OF THIS SUBROUTINE:
    1944             :         // set up zone-related info as internal data
    1945             : 
    1946          73 :         if (!state.dataHeatBal->Zone.empty()) {
    1947        1192 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1948        1119 :                 auto &zone = state.dataHeatBal->Zone(ZoneNum);
    1949             : 
    1950        1119 :                 SetupEMSInternalVariable(state, "Zone Floor Area", zone.Name, "[m2]", zone.FloorArea);
    1951        1119 :                 SetupEMSInternalVariable(state, "Zone Air Volume", zone.Name, "[m3]", zone.Volume);
    1952        1119 :                 SetupEMSInternalVariable(state, "Zone Multiplier", zone.Name, "[ ]", zone.Multiplier);
    1953        1119 :                 SetupEMSInternalVariable(state, "Zone List Multiplier", zone.Name, "[ ]", zone.ListMultiplier);
    1954             :             }
    1955             :         }
    1956          73 :     }
    1957             : 
    1958          73 :     void SetupZoneOutdoorBoundaryConditionActuators(EnergyPlusData &state)
    1959             :     {
    1960             : 
    1961             :         // SUBROUTINE INFORMATION:
    1962             :         //       AUTHOR         X Luo
    1963             :         //       DATE WRITTEN   July 2017
    1964             : 
    1965             :         // PURPOSE OF THIS SUBROUTINE:
    1966             :         // setup EMS actuators for outside boundary conditions by surface
    1967             : 
    1968             :         // METHODOLOGY EMPLOYED:
    1969             :         // loop through all surfaces, cycle if not heat transfer or outdoors BC
    1970             : 
    1971        1192 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1972        1119 :             auto &zone = state.dataHeatBal->Zone(ZoneNum);
    1973             : 
    1974        1119 :             SetupEMSActuator(state,
    1975             :                              "Zone",
    1976             :                              zone.Name,
    1977             :                              "Outdoor Air Drybulb Temperature",
    1978             :                              "[C]",
    1979        1119 :                              zone.OutDryBulbTempEMSOverrideOn,
    1980        1119 :                              zone.OutDryBulbTempEMSOverrideValue);
    1981        1119 :             SetupEMSActuator(state,
    1982             :                              "Zone",
    1983             :                              zone.Name,
    1984             :                              "Outdoor Air Wetbulb Temperature",
    1985             :                              "[C]",
    1986        1119 :                              zone.OutWetBulbTempEMSOverrideOn,
    1987        1119 :                              zone.OutWetBulbTempEMSOverrideValue);
    1988        1119 :             SetupEMSActuator(
    1989        1119 :                 state, "Zone", zone.Name, "Outdoor Air Wind Speed", "[m/s]", zone.WindSpeedEMSOverrideOn, zone.WindSpeedEMSOverrideValue);
    1990        1119 :             SetupEMSActuator(
    1991        1119 :                 state, "Zone", zone.Name, "Outdoor Air Wind Direction", "[degree]", zone.WindDirEMSOverrideOn, zone.WindDirEMSOverrideValue);
    1992             :         }
    1993          73 :     }
    1994             : 
    1995         794 :     void checkForUnusedActuatorsAtEnd(EnergyPlusData &state)
    1996             :     {
    1997             :         // call at end of simulation to check if any of the user's actuators were never initialized.
    1998             :         // Could be a mistake we want to help users catch // Issue #4404.
    1999        1490 :         for (int actuatorUsedLoop = 1; actuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed; ++actuatorUsedLoop) {
    2000         696 :             if (!state.dataRuntimeLang->ErlVariable(state.dataRuntimeLang->EMSActuatorUsed(actuatorUsedLoop).ErlVariableNum).Value.initialized) {
    2001           0 :                 ShowWarningError(state,
    2002             :                                  "checkForUnusedActuatorsAtEnd: Unused EMS Actuator detected, suggesting possible unintended programming error or "
    2003             :                                  "spelling mistake.");
    2004           0 :                 ShowContinueError(state,
    2005           0 :                                   format("Check Erl programs related to EMS actuator variable name = {}",
    2006           0 :                                          state.dataRuntimeLang->EMSActuatorUsed(actuatorUsedLoop).Name));
    2007           0 :                 ShowContinueError(state,
    2008           0 :                                   format("EMS Actuator type name = {}", state.dataRuntimeLang->EMSActuatorUsed(actuatorUsedLoop).ComponentTypeName));
    2009           0 :                 ShowContinueError(
    2010           0 :                     state, format("EMS Actuator unique component name = {}", state.dataRuntimeLang->EMSActuatorUsed(actuatorUsedLoop).UniqueIDName));
    2011           0 :                 ShowContinueError(state,
    2012           0 :                                   format("EMS Actuator control type = {}", state.dataRuntimeLang->EMSActuatorUsed(actuatorUsedLoop).ControlTypeName));
    2013             :             }
    2014             :         }
    2015         794 :     }
    2016             : 
    2017             : } // namespace EMSManager
    2018             : 
    2019             : // Moved these setup EMS actuator routines out of module to solve circular use problems between
    2020             : //  ScheduleManager and OutputProcessor. Followed pattern used for SetupOutputVariable
    2021             : 
    2022      208966 : void SetupEMSActuator(EnergyPlusData &state,
    2023             :                       std::string_view cComponentTypeName,
    2024             :                       std::string_view cUniqueIDName,
    2025             :                       std::string_view cControlTypeName,
    2026             :                       std::string_view cUnits,
    2027             :                       bool &lEMSActuated,
    2028             :                       Real64 &rValue)
    2029             : {
    2030             : 
    2031             :     // SUBROUTINE INFORMATION:
    2032             :     //       AUTHOR         Peter Graham Ellis
    2033             :     //       DATE WRITTEN   June 2006
    2034             :     //       MODIFIED       Brent Griffith April 2009,
    2035             : 
    2036             :     // PURPOSE OF THIS SUBROUTINE:
    2037             :     // register a new actuator for EMS
    2038             :     //   set  up pointer to logical and real value
    2039             : 
    2040             :     // METHODOLOGY EMPLOYED:
    2041             :     // push size of ActuatorVariable and add a new one.
    2042             :     //  check for duplicates.
    2043             : 
    2044      208966 :     std::string const UpperCaseObjectType(Util::makeUPPER(cComponentTypeName));
    2045      208966 :     std::string const UpperCaseObjectName(Util::makeUPPER(cUniqueIDName));
    2046      208966 :     std::string const UpperCaseActuatorName(Util::makeUPPER(cControlTypeName));
    2047             : 
    2048      208966 :     DataRuntimeLanguage::EMSActuatorKey const key(UpperCaseObjectType, UpperCaseObjectName, UpperCaseActuatorName);
    2049             : 
    2050      208966 :     if (state.dataRuntimeLang->EMSActuator_lookup.find(key) == state.dataRuntimeLang->EMSActuator_lookup.end()) {
    2051      208926 :         if (state.dataRuntimeLang->numEMSActuatorsAvailable == 0) {
    2052          73 :             state.dataRuntimeLang->EMSActuatorAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2053          73 :             state.dataRuntimeLang->numEMSActuatorsAvailable = 1;
    2054          73 :             state.dataRuntimeLang->maxEMSActuatorsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2055             :         } else {
    2056      208853 :             if (state.dataRuntimeLang->numEMSActuatorsAvailable + 1 > state.dataRuntimeLang->maxEMSActuatorsAvailable) {
    2057          87 :                 state.dataRuntimeLang->EMSActuatorAvailable.redimension(state.dataRuntimeLang->maxEMSActuatorsAvailable *= 2);
    2058             :             }
    2059      208853 :             ++state.dataRuntimeLang->numEMSActuatorsAvailable;
    2060             :         }
    2061             : 
    2062      208926 :         auto &actuator(state.dataRuntimeLang->EMSActuatorAvailable(state.dataRuntimeLang->numEMSActuatorsAvailable));
    2063      208926 :         actuator.ComponentTypeName = cComponentTypeName;
    2064      208926 :         actuator.UniqueIDName = cUniqueIDName;
    2065      208926 :         actuator.ControlTypeName = cControlTypeName;
    2066      208926 :         actuator.Units = cUnits;
    2067      208926 :         actuator.Actuated = &lEMSActuated; // Pointer assigment
    2068      208926 :         actuator.RealValue = &rValue;      // Pointer assigment
    2069      208926 :         actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Real;
    2070      208926 :         state.dataRuntimeLang->EMSActuator_lookup.insert(key);
    2071             :     }
    2072      208966 : }
    2073             : 
    2074       11235 : void SetupEMSActuator(EnergyPlusData &state,
    2075             :                       std::string_view cComponentTypeName,
    2076             :                       std::string_view cUniqueIDName,
    2077             :                       std::string_view cControlTypeName,
    2078             :                       std::string_view cUnits,
    2079             :                       bool &lEMSActuated,
    2080             :                       int &iValue)
    2081             : {
    2082             : 
    2083             :     // SUBROUTINE INFORMATION:
    2084             :     //       AUTHOR         Brent Griffith
    2085             :     //       DATE WRITTEN   May 2009
    2086             : 
    2087             :     // PURPOSE OF THIS SUBROUTINE:
    2088             :     // register a new actuator for EMS
    2089             :     //   set  up pointer to logical and integer value
    2090             : 
    2091             :     // METHODOLOGY EMPLOYED:
    2092             :     // push size of ActuatorVariable and add a new one.
    2093             :     //  check for duplicates.
    2094             : 
    2095       11235 :     std::string const UpperCaseObjectType(Util::makeUPPER(cComponentTypeName));
    2096       11235 :     std::string const UpperCaseObjectName(Util::makeUPPER(cUniqueIDName));
    2097       11235 :     std::string const UpperCaseActuatorName(Util::makeUPPER(cControlTypeName));
    2098             : 
    2099       11235 :     DataRuntimeLanguage::EMSActuatorKey const key(UpperCaseObjectType, UpperCaseObjectName, UpperCaseActuatorName);
    2100             : 
    2101       11235 :     if (state.dataRuntimeLang->EMSActuator_lookup.find(key) == state.dataRuntimeLang->EMSActuator_lookup.end()) {
    2102       11235 :         if (state.dataRuntimeLang->numEMSActuatorsAvailable == 0) {
    2103           0 :             state.dataRuntimeLang->EMSActuatorAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2104           0 :             state.dataRuntimeLang->numEMSActuatorsAvailable = 1;
    2105           0 :             state.dataRuntimeLang->maxEMSActuatorsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2106             :         } else {
    2107       11235 :             if (state.dataRuntimeLang->numEMSActuatorsAvailable + 1 > state.dataRuntimeLang->maxEMSActuatorsAvailable) {
    2108           7 :                 state.dataRuntimeLang->EMSActuatorAvailable.redimension(state.dataRuntimeLang->maxEMSActuatorsAvailable *= 2);
    2109             :             }
    2110       11235 :             ++state.dataRuntimeLang->numEMSActuatorsAvailable;
    2111             :         }
    2112             : 
    2113       11235 :         auto &actuator(state.dataRuntimeLang->EMSActuatorAvailable(state.dataRuntimeLang->numEMSActuatorsAvailable));
    2114       11235 :         actuator.ComponentTypeName = cComponentTypeName;
    2115       11235 :         actuator.UniqueIDName = cUniqueIDName;
    2116       11235 :         actuator.ControlTypeName = cControlTypeName;
    2117       11235 :         actuator.Units = cUnits;
    2118       11235 :         actuator.Actuated = &lEMSActuated; // Pointer assigment
    2119       11235 :         actuator.IntValue = &iValue;       // Pointer assigment
    2120       11235 :         actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Integer;
    2121       11235 :         state.dataRuntimeLang->EMSActuator_lookup.insert(key);
    2122             :     }
    2123       11235 : }
    2124             : 
    2125           0 : void SetupEMSActuator(EnergyPlusData &state,
    2126             :                       std::string_view cComponentTypeName,
    2127             :                       std::string_view cUniqueIDName,
    2128             :                       std::string_view cControlTypeName,
    2129             :                       std::string_view cUnits,
    2130             :                       bool &lEMSActuated,
    2131             :                       bool &lValue)
    2132             : {
    2133             : 
    2134             :     // SUBROUTINE INFORMATION:
    2135             :     //       AUTHOR         Brent Griffith
    2136             :     //       DATE WRITTEN   August 2009
    2137             : 
    2138             :     // PURPOSE OF THIS SUBROUTINE:
    2139             :     // register a new actuator for EMS
    2140             :     //   set  up pointer to logical and logical value
    2141             : 
    2142             :     // METHODOLOGY EMPLOYED:
    2143             :     // push size of ActuatorVariable and add a new one.
    2144             :     //  check for duplicates.
    2145             : 
    2146           0 :     std::string const UpperCaseObjectType(Util::makeUPPER(cComponentTypeName));
    2147           0 :     std::string const UpperCaseObjectName(Util::makeUPPER(cUniqueIDName));
    2148           0 :     std::string const UpperCaseActuatorName(Util::makeUPPER(cControlTypeName));
    2149             : 
    2150           0 :     DataRuntimeLanguage::EMSActuatorKey const key(UpperCaseObjectType, UpperCaseObjectName, UpperCaseActuatorName);
    2151             : 
    2152           0 :     if (state.dataRuntimeLang->EMSActuator_lookup.find(key) == state.dataRuntimeLang->EMSActuator_lookup.end()) {
    2153           0 :         if (state.dataRuntimeLang->numEMSActuatorsAvailable == 0) {
    2154           0 :             state.dataRuntimeLang->EMSActuatorAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2155           0 :             state.dataRuntimeLang->numEMSActuatorsAvailable = 1;
    2156           0 :             state.dataRuntimeLang->maxEMSActuatorsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2157             :         } else {
    2158           0 :             if (state.dataRuntimeLang->numEMSActuatorsAvailable + 1 > state.dataRuntimeLang->maxEMSActuatorsAvailable) {
    2159           0 :                 state.dataRuntimeLang->EMSActuatorAvailable.redimension(state.dataRuntimeLang->maxEMSActuatorsAvailable *= 2);
    2160             :             }
    2161           0 :             ++state.dataRuntimeLang->numEMSActuatorsAvailable;
    2162             :         }
    2163             : 
    2164           0 :         auto &actuator(state.dataRuntimeLang->EMSActuatorAvailable(state.dataRuntimeLang->numEMSActuatorsAvailable));
    2165           0 :         actuator.ComponentTypeName = cComponentTypeName;
    2166           0 :         actuator.UniqueIDName = cUniqueIDName;
    2167           0 :         actuator.ControlTypeName = cControlTypeName;
    2168           0 :         actuator.Units = cUnits;
    2169           0 :         actuator.Actuated = &lEMSActuated; // Pointer assigment
    2170           0 :         actuator.LogValue = &lValue;       // Pointer assigment
    2171           0 :         actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Logical;
    2172           0 :         state.dataRuntimeLang->EMSActuator_lookup.insert(key);
    2173             :     }
    2174           0 : }
    2175             : 
    2176       34770 : void SetupEMSInternalVariable(
    2177             :     EnergyPlusData &state, std::string_view cDataTypeName, std::string_view cUniqueIDName, std::string_view cUnits, Real64 &rValue)
    2178             : {
    2179             : 
    2180             :     // SUBROUTINE INFORMATION:
    2181             :     //       AUTHOR         Brent Griffith
    2182             :     //       DATE WRITTEN   May 2009
    2183             : 
    2184             :     // PURPOSE OF THIS SUBROUTINE:
    2185             :     // Setup internal data source and make available to EMS
    2186             : 
    2187             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2188       34770 :     bool FoundDuplicate = false;
    2189             : 
    2190    32103733 :     for (int InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    2191    32883618 :         if ((Util::SameString(cDataTypeName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName)) &&
    2192      814655 :             (Util::SameString(cUniqueIDName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName))) {
    2193           0 :             FoundDuplicate = true;
    2194           0 :             break;
    2195             :         }
    2196             :     }
    2197             : 
    2198       34770 :     if (FoundDuplicate) {
    2199           0 :         ShowSevereError(state, "Duplicate internal variable was sent to SetupEMSInternalVariable.");
    2200           0 :         ShowContinueError(state, format("Internal variable type = {} ; name = {}", cDataTypeName, cUniqueIDName));
    2201           0 :         ShowContinueError(state, "Called from SetupEMSInternalVariable.");
    2202             :     } else {
    2203             :         // add new internal data variable
    2204       34770 :         if (state.dataRuntimeLang->numEMSInternalVarsAvailable == 0) {
    2205         358 :             state.dataRuntimeLang->EMSInternalVarsAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2206         358 :             state.dataRuntimeLang->numEMSInternalVarsAvailable = 1;
    2207         358 :             state.dataRuntimeLang->maxEMSInternalVarsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2208             :         } else {
    2209       34412 :             if (state.dataRuntimeLang->numEMSInternalVarsAvailable + 1 > state.dataRuntimeLang->maxEMSInternalVarsAvailable) {
    2210          30 :                 state.dataRuntimeLang->EMSInternalVarsAvailable.redimension(state.dataRuntimeLang->maxEMSInternalVarsAvailable +=
    2211          15 :                                                                             state.dataRuntimeLang->varsAvailableAllocInc);
    2212             :             }
    2213       34412 :             ++state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2214             :         }
    2215             : 
    2216       34770 :         int InternalVarAvailNum = state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2217       34770 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName = cDataTypeName;
    2218       34770 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName = cUniqueIDName;
    2219       34770 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).Units = cUnits;
    2220       34770 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).RealValue = &rValue;
    2221       34770 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Real;
    2222             :     }
    2223       34770 : }
    2224             : 
    2225        2238 : void SetupEMSInternalVariable(
    2226             :     EnergyPlusData &state, std::string_view cDataTypeName, std::string_view cUniqueIDName, std::string_view cUnits, int &iValue)
    2227             : {
    2228             : 
    2229             :     // SUBROUTINE INFORMATION:
    2230             :     //       AUTHOR         Brent Griffith
    2231             :     //       DATE WRITTEN   May 2009
    2232             : 
    2233             :     // PURPOSE OF THIS SUBROUTINE:
    2234             :     // Setup internal data source and make available to EMS
    2235             : 
    2236             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2237        2238 :     bool FoundDuplicate = false;
    2238             : 
    2239      596133 :     for (int InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    2240      651969 :         if ((Util::SameString(cDataTypeName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName)) &&
    2241       58074 :             (Util::SameString(cUniqueIDName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName))) {
    2242           0 :             FoundDuplicate = true;
    2243           0 :             break;
    2244             :         }
    2245             :     }
    2246             : 
    2247        2238 :     if (FoundDuplicate) {
    2248           0 :         ShowSevereError(state, "Duplicate internal variable was sent to SetupEMSInternalVariable.");
    2249           0 :         ShowContinueError(state, format("Internal variable type = {} ; name = {}", cDataTypeName, cUniqueIDName));
    2250           0 :         ShowContinueError(state, "called from SetupEMSInternalVariable");
    2251             :     } else {
    2252             :         // add new internal data variable
    2253        2238 :         if (state.dataRuntimeLang->numEMSInternalVarsAvailable == 0) {
    2254           0 :             state.dataRuntimeLang->EMSInternalVarsAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2255           0 :             state.dataRuntimeLang->numEMSInternalVarsAvailable = 1;
    2256           0 :             state.dataRuntimeLang->maxEMSInternalVarsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2257             :         } else {
    2258        2238 :             if (state.dataRuntimeLang->numEMSInternalVarsAvailable + 1 > state.dataRuntimeLang->maxEMSInternalVarsAvailable) {
    2259           0 :                 state.dataRuntimeLang->EMSInternalVarsAvailable.redimension(state.dataRuntimeLang->maxEMSInternalVarsAvailable +=
    2260           0 :                                                                             state.dataRuntimeLang->varsAvailableAllocInc);
    2261             :             }
    2262        2238 :             ++state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2263             :         }
    2264             : 
    2265        2238 :         int InternalVarAvailNum = state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2266        2238 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName = cDataTypeName;
    2267        2238 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName = cUniqueIDName;
    2268        2238 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).Units = cUnits;
    2269        2238 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).IntValue = &iValue;
    2270        2238 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Integer;
    2271             :     }
    2272        2238 : }
    2273             : 
    2274             : } // namespace EnergyPlus

Generated by: LCOV version 1.14