LCOV - code coverage report
Current view: top level - EnergyPlus - EMSManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 73.3 % 1072 786
Test Date: 2025-06-02 12:03:30 Functions: 96.7 % 30 29

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

Generated by: LCOV version 2.0-1