LCOV - code coverage report
Current view: top level - EnergyPlus - EMSManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 77.8 % 1072 834
Test Date: 2025-06-02 07:23:51 Functions: 93.3 % 30 28

            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         1602 :     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         1602 :         std::string cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     143         1602 :         state.dataRuntimeLang->NumSensors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     144              : 
     145         1602 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     146         1602 :         state.dataRuntimeLang->numActuatorsUsed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     147              : 
     148         1602 :         cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     149         1602 :         state.dataRuntimeLang->NumProgramCallManagers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     150              : 
     151         1602 :         cCurrentModuleObject = "EnergyManagementSystem:Program";
     152         1602 :         state.dataRuntimeLang->NumErlPrograms = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     153              : 
     154         1602 :         cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
     155         1602 :         state.dataRuntimeLang->NumErlSubroutines = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     156              : 
     157         1602 :         cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
     158         1602 :         state.dataRuntimeLang->NumUserGlobalVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     159              : 
     160         1602 :         cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
     161         1602 :         state.dataRuntimeLang->NumEMSOutputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     162              : 
     163         1602 :         cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
     164         3204 :         state.dataRuntimeLang->NumEMSMeteredOutputVariables =
     165         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     166              : 
     167         1602 :         cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
     168         1602 :         state.dataRuntimeLang->NumEMSCurveIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     169              : 
     170         1602 :         cCurrentModuleObject = "ExternalInterface:Variable";
     171         3204 :         state.dataRuntimeLang->NumExternalInterfaceGlobalVariables =
     172         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     173              : 
     174              :         // added for FMUImport
     175         1602 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
     176         3204 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables =
     177         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     178              : 
     179              :         // added for FMUExport
     180         1602 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
     181         3204 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables =
     182         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     183              : 
     184         1602 :         cCurrentModuleObject = "ExternalInterface:Actuator";
     185         3204 :         state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed =
     186         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     187              : 
     188              :         // added for FMUImport
     189         1602 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     190         3204 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed =
     191         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     192              : 
     193              :         // added for FMUExport
     194         1602 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
     195         3204 :         state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed =
     196         1602 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     197              : 
     198         1602 :         cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
     199         1602 :         state.dataRuntimeLang->NumEMSConstructionIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     200              : 
     201         1602 :         cCurrentModuleObject = "Output:EnergyManagementSystem";
     202         1602 :         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         1602 :         int numPythonPlugins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PythonPlugin:Instance");
     206         1602 :         int numActiveCallbacks = PluginManagement::PluginManager::numActiveCallbacks(state);
     207              : 
     208              :         // added for FMU
     209         1602 :         if ((state.dataRuntimeLang->NumSensors + state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumProgramCallManagers +
     210         1602 :              state.dataRuntimeLang->NumErlPrograms + state.dataRuntimeLang->NumErlSubroutines + state.dataRuntimeLang->NumUserGlobalVariables +
     211         1602 :              state.dataRuntimeLang->NumEMSOutputVariables + state.dataRuntimeLang->NumEMSCurveIndices +
     212         1602 :              state.dataRuntimeLang->NumExternalInterfaceGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     213         1602 :              state.dataRuntimeLang->NumEMSConstructionIndices + state.dataRuntimeLang->NumEMSMeteredOutputVariables +
     214         1602 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     215         1602 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
     216         1602 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed +
     217         1602 :              state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables + NumOutputEMSs + numPythonPlugins +
     218         1602 :              numActiveCallbacks) > 0) {
     219          152 :             state.dataGlobal->AnyEnergyManagementSystemInModel = true;
     220              :         } else {
     221         1450 :             state.dataGlobal->AnyEnergyManagementSystemInModel = false;
     222              :         }
     223              : 
     224              :         // turn on EMS capability if we are running with an external HVAC manager or via API
     225         1602 :         state.dataGlobal->AnyEnergyManagementSystemInModel =
     226         1602 :             state.dataGlobal->AnyEnergyManagementSystemInModel || state.dataGlobal->externalHVACManager || state.dataGlobal->eplusRunningViaAPI;
     227              : 
     228         1602 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
     229              : 
     230          456 :             General::ScanForReports(state, "EnergyManagementSystem", state.dataRuntimeLang->OutputEDDFile);
     231          152 :             if (state.dataRuntimeLang->OutputEDDFile) {
     232              :                 // open up output file for EMS EDD file  EMS Data and Debug
     233          246 :                 state.files.edd.ensure_open(state, "CheckIFAnyEMS", state.files.outputControl.edd);
     234              :             }
     235              :         } else {
     236         4350 :             General::ScanForReports(state, "EnergyManagementSystem", state.dataRuntimeLang->OutputEDDFile);
     237         1450 :             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         1602 :     }
     245              : 
     246              :     // MODULE SUBROUTINES:
     247              : 
     248     35544426 :     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     35544426 :         anyProgramRan = false;
     264     35544426 :         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     265     29599802 :             return; // quick return if nothing to do
     266              :         }
     267              : 
     268      5944624 :         if (iCalledFrom == EMSCallFrom::BeginNewEnvironment) {
     269          148 :             RuntimeLanguageProcessor::BeginEnvrnInitializeRuntimeLanguage(state);
     270          148 :             PluginManagement::onBeginEnvironment(state);
     271              :         }
     272              : 
     273      5944624 :         InitEMS(state, iCalledFrom);
     274              : 
     275              :         // also call plugins and callbacks here for convenience
     276      5944624 :         if (iCalledFrom != EMSCallFrom::UserDefinedComponentModel) { // don't run user-defined component plugins this way
     277      5514393 :             bool anyPluginsOrCallbacksRan = false;
     278      5514393 :             PluginManagement::runAnyRegisteredCallbacks(state, iCalledFrom, anyPluginsOrCallbacksRan);
     279      5514393 :             if (anyPluginsOrCallbacksRan) {
     280       206630 :                 anyProgramRan = true;
     281              :             }
     282              :         }
     283              : 
     284      5944624 :         if (iCalledFrom == EMSCallFrom::SetupSimulation) {
     285           75 :             ProcessEMSInput(state, true);
     286           75 :             return;
     287              :         }
     288              : 
     289              :         // Run the Erl programs depending on calling point.
     290              : 
     291      5944549 :         if (iCalledFrom != EMSCallFrom::UserDefinedComponentModel) {
     292     30379718 :             for (int ProgramManagerNum = 1; ProgramManagerNum <= state.dataRuntimeLang->NumProgramCallManagers; ++ProgramManagerNum) {
     293              : 
     294     24865401 :                 if (state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).CallingPoint == iCalledFrom) {
     295      4121652 :                     for (int ErlProgramNum = 1; ErlProgramNum <= state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).NumErlPrograms;
     296              :                          ++ErlProgramNum) {
     297      2125230 :                         RuntimeLanguageProcessor::EvaluateStack(
     298      2125230 :                             state, state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerNum).ErlProgramARR(ErlProgramNum));
     299      2125229 :                         anyProgramRan = true;
     300              :                     }
     301              :                 }
     302              :             }
     303              :         } else { // call specific program manager
     304       430231 :             if (present(ProgramManagerToRun)) {
     305      1300564 :                 for (int ErlProgramNum = 1; ErlProgramNum <= state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerToRun).NumErlPrograms;
     306              :                      ++ErlProgramNum) {
     307       870333 :                     RuntimeLanguageProcessor::EvaluateStack(
     308       870333 :                         state, state.dataRuntimeLang->EMSProgramCallManager(ProgramManagerToRun).ErlProgramARR(ErlProgramNum));
     309       870333 :                     anyProgramRan = true;
     310              :                 }
     311              :             }
     312              :         }
     313              : 
     314      5944548 :         if (iCalledFrom == EMSCallFrom::ExternalInterface) {
     315       106848 :             anyProgramRan = true;
     316              :         }
     317              : 
     318      5944548 :         if (!anyProgramRan) {
     319      4734664 :             return;
     320              :         }
     321              : 
     322              :         // Set actuated variables with new values
     323     25529495 :         for (int ActuatorUsedLoop = 1;
     324     25529495 :              ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     325     25529495 :                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     326     25529495 :                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
     327              :              ++ActuatorUsedLoop) {
     328     24319611 :             auto const &thisActuatorUsed = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop);
     329              : 
     330     24319611 :             int ErlVariableNum = thisActuatorUsed.ErlVariableNum;
     331     24319611 :             if (ErlVariableNum <= 0) {
     332            0 :                 continue; // this can happen for good reason during sizing
     333              :             }
     334              : 
     335     24319611 :             int EMSActuatorVariableNum = thisActuatorUsed.ActuatorVariableNum;
     336     24319611 :             if (EMSActuatorVariableNum <= 0) {
     337        87112 :                 continue; // this can happen for good reason during sizing
     338              :             }
     339              : 
     340     24232499 :             auto const &thisErlVar = state.dataRuntimeLang->ErlVariable(ErlVariableNum);
     341     24232499 :             auto const &thisActuatorAvail = state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum);
     342              : 
     343     24232499 :             if (thisErlVar.Value.Type == DataRuntimeLanguage::Value::Null) {
     344      2294382 :                 *thisActuatorAvail.Actuated = false;
     345              :             } else {
     346              :                 // Set the value and the actuated flag remotely on the actuated object via the pointer
     347     21938117 :                 switch (thisActuatorAvail.PntrVarTypeUsed) {
     348     21703526 :                 case DataRuntimeLanguage::PtrDataType::Real: {
     349     21703526 :                     *thisActuatorAvail.Actuated = true;
     350     21703526 :                     *thisActuatorAvail.RealValue = thisErlVar.Value.Number;
     351     21703526 :                 } break;
     352       234591 :                 case DataRuntimeLanguage::PtrDataType::Integer: {
     353       234591 :                     *thisActuatorAvail.Actuated = true;
     354       234591 :                     int tmpInteger = std::floor(thisErlVar.Value.Number);
     355       234591 :                     *thisActuatorAvail.IntValue = tmpInteger;
     356       234591 :                 } 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      1209884 :         ReportEMS(state);
     374              :     }
     375              : 
     376      5944624 :     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      5944624 :         if (state.dataEMSMgr->GetEMSUserInput) {
     387           76 :             SetupZoneInfoAsInternalDataAvail(state);
     388           76 :             SetupWindowShadingControlActuators(state);
     389           76 :             SetupSurfaceConvectionActuators(state);
     390           76 :             SetupSurfaceConstructionActuators(state);
     391           76 :             SetupSurfaceOutdoorBoundaryConditionActuators(state);
     392           76 :             SetupZoneOutdoorBoundaryConditionActuators(state);
     393           76 :             GetEMSInput(state);
     394           76 :             state.dataEMSMgr->GetEMSUserInput = false;
     395              :         }
     396              : 
     397      5944624 :         if (!state.dataZoneCtrls->GetZoneAirStatsInputFlag && !state.dataEMSMgr->ZoneThermostatActuatorsHaveBeenSetup) {
     398           76 :             SetupThermostatActuators(state);
     399           76 :             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      5944624 :         if (state.dataEMSMgr->FinishProcessingUserInput && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     404           75 :             SetupNodeSetPointsAsActuators(state);
     405           75 :             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           75 :             state.dataEMSMgr->FinishProcessingUserInput = false;
     410              :         }
     411              : 
     412      5944624 :         RuntimeLanguageProcessor::InitializeRuntimeLanguage(state);
     413              : 
     414      5944624 :         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       441523 :             if (state.dataEMSMgr->FinishProcessingUserInput) {
     419         6735 :                 ProcessEMSInput(state, false);
     420              :             }
     421              : 
     422              :             // update internal data variables being used by Erl
     423     26108307 :             for (int InternalVarUsedNum = 1; InternalVarUsedNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternalVarUsedNum) {
     424     25666784 :                 int ErlVariableNum = state.dataRuntimeLang->EMSInternalVarsUsed(InternalVarUsedNum).ErlVariableNum;
     425     25666784 :                 int InternVarAvailNum = state.dataRuntimeLang->EMSInternalVarsUsed(InternalVarUsedNum).InternVarNum;
     426     25666784 :                 if (InternVarAvailNum <= 0) {
     427         7981 :                     continue; // sometimes executes before completely finished setting up.
     428              :                 }
     429     25658803 :                 if (ErlVariableNum <= 0) {
     430            0 :                     continue;
     431              :                 }
     432              : 
     433     25658803 :                 switch (state.dataRuntimeLang->EMSInternalVarsAvailable(InternVarAvailNum).PntrVarTypeUsed) {
     434     25658803 :                 case DataRuntimeLanguage::PtrDataType::Real: {
     435     25658803 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value =
     436     51317606 :                         RuntimeLanguageProcessor::SetErlValueNumber(*state.dataRuntimeLang->EMSInternalVarsAvailable(InternVarAvailNum).RealValue);
     437     25658803 :                 } 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     96860264 :         for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     450     90915640 :             int ErlVariableNum = state.dataRuntimeLang->Sensor(SensorNum).VariableNum;
     451     90915640 :             if ((ErlVariableNum > 0) && (state.dataRuntimeLang->Sensor(SensorNum).Index > -1)) {
     452     90915640 :                 if (state.dataRuntimeLang->Sensor(SensorNum).sched == nullptr) { // not a schedule so get from output processor
     453              : 
     454    178295544 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value = RuntimeLanguageProcessor::SetErlValueNumber(
     455              :                         GetInternalVariableValue(
     456     89147772 :                             state, state.dataRuntimeLang->Sensor(SensorNum).VariableType, state.dataRuntimeLang->Sensor(SensorNum).Index),
     457    178295544 :                         state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
     458              :                 } else { // schedule so use schedule service
     459              : 
     460      3535736 :                     state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value = RuntimeLanguageProcessor::SetErlValueNumber(
     461      3535736 :                         state.dataRuntimeLang->Sensor(SensorNum).sched->getCurrentVal(), state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
     462              :                 }
     463              :             }
     464              :         }
     465      5944624 :     }
     466              : 
     467      1209884 :     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      1209884 :         RuntimeLanguageProcessor::ReportRuntimeLanguage(state);
     480      1209884 :     }
     481              : 
     482           76 :     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           76 :         bool ErrorsFound(false);
     502           76 :         Array1D_string cAlphaFieldNames;
     503           76 :         Array1D_string cNumericFieldNames;
     504           76 :         Array1D_bool lNumericFieldBlanks;
     505           76 :         Array1D_bool lAlphaFieldBlanks;
     506           76 :         Array1D_string cAlphaArgs;
     507           76 :         Array1D<Real64> rNumericArgs;
     508           76 :         std::string cCurrentModuleObject;
     509              :         OutputProcessor::VariableType VarType;
     510           76 :         int TotalArgs(0); // argument for call to GetObjectDefMaxArgs
     511              :         bool errFlag;
     512              : 
     513           76 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     514           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     515           76 :         int MaxNumNumbers = NumNums;
     516           76 :         int MaxNumAlphas = NumAlphas;
     517           76 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     518           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     519           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     520           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     521           76 :         cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     522           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     523           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     524           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     525           76 :         cCurrentModuleObject = "EnergyManagementSystem:Program";
     526           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     527           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     528           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     529           76 :         cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
     530           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     531           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     532           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     533           76 :         cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
     534           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     535           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     536           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     537           76 :         cCurrentModuleObject = "ExternalInterface:Variable";
     538           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     539           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     540           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     541           76 :         cCurrentModuleObject = "ExternalInterface:Actuator";
     542           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     543           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     544           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     545           76 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
     546           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     547           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     548           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     549           76 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     550           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     551           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     552           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     553           76 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
     554           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     555           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     556           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     557           76 :         cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
     558           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     559           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     560           76 :         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           76 :         cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
     566           76 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     567           76 :         MaxNumNumbers = max(MaxNumNumbers, NumNums);
     568           76 :         MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
     569              : 
     570           76 :         cAlphaFieldNames.allocate(MaxNumAlphas);
     571           76 :         cAlphaArgs.allocate(MaxNumAlphas);
     572           76 :         lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
     573           76 :         cNumericFieldNames.allocate(MaxNumNumbers);
     574           76 :         rNumericArgs.dimension(MaxNumNumbers, 0.0);
     575           76 :         lNumericFieldBlanks.dimension(MaxNumNumbers, false);
     576              : 
     577           76 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     578           76 :         if (state.dataRuntimeLang->NumSensors > 0) {
     579           54 :             state.dataRuntimeLang->Sensor.allocate(state.dataRuntimeLang->NumSensors);
     580              : 
     581         1920 :             for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     582         1866 :                 auto &thisSensor = state.dataRuntimeLang->Sensor(SensorNum);
     583         1866 :                 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         1866 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     596         1866 :                 if (!errFlag) {
     597         1866 :                     thisSensor.Name = cAlphaArgs(1);
     598              : 
     599              :                     // really needs to check for conflicts with program and function names too...done later
     600         1866 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     601              : 
     602         1866 :                     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         1866 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     609         1866 :                         thisSensor.VariableNum = VariableNum;
     610         1866 :                         state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true;
     611              :                     }
     612              :                 }
     613              : 
     614         1866 :                 if (cAlphaArgs(2) == "*") {
     615            2 :                     cAlphaArgs(2).clear();
     616              :                 }
     617         1866 :                 thisSensor.UniqueKeyName = cAlphaArgs(2);
     618         1866 :                 thisSensor.OutputVarName = cAlphaArgs(3);
     619              : 
     620         1866 :                 int VarIndex = GetMeterIndex(state, cAlphaArgs(3));
     621         1866 :                 if (VarIndex > -1) {
     622           11 :                     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           11 :                         thisSensor.VariableType = OutputProcessor::VariableType::Meter;
     628           11 :                         thisSensor.Index = VarIndex;
     629           11 :                         thisSensor.CheckedOkay = true;
     630              :                     }
     631              :                 } else {
     632              :                     // Search for variable names
     633         1855 :                     GetVariableTypeAndIndex(state, cAlphaArgs(3), cAlphaArgs(2), VarType, VarIndex);
     634         1855 :                     if (VarType != OutputProcessor::VariableType::Invalid) {
     635          539 :                         thisSensor.VariableType = VarType;
     636          539 :                         if (VarIndex != -1) {
     637          539 :                             thisSensor.Index = VarIndex;
     638          539 :                             thisSensor.CheckedOkay = true;
     639              :                         }
     640              :                     }
     641              :                 }
     642              : 
     643              :             } // SensorNum
     644              :         }
     645              : 
     646           76 :         cCurrentModuleObject = "EnergyManagementSystem:Actuator";
     647              : 
     648           76 :         if (state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     649           76 :                 state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     650           76 :                 state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed >
     651              :             0) {
     652           94 :             state.dataRuntimeLang->EMSActuatorUsed.allocate(state.dataRuntimeLang->numActuatorsUsed +
     653           47 :                                                             state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     654           47 :                                                             state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     655           47 :                                                             state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed);
     656          780 :             for (int ActuatorNum = 1;
     657          780 :                  ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     658          780 :                                     state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
     659          780 :                                     state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
     660              :                  ++ActuatorNum) {
     661          733 :                 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          733 :                 if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed) {
     665          732 :                     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            1 :                 } 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            1 :                 } else if (ActuatorNum <= (state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
     692            1 :                                            state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed)) {
     693            1 :                     cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
     694            2 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
     695              :                                                                              cCurrentModuleObject,
     696            1 :                                                                              ActuatorNum - state.dataRuntimeLang->numActuatorsUsed -
     697            1 :                                                                                  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          733 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     728          733 :                 if (!errFlag) {
     729          733 :                     thisEMSactuator.Name = cAlphaArgs(1);
     730              : 
     731              :                     // really needs to check for conflicts with program and function names too...
     732          733 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     733              : 
     734          733 :                     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          733 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     741          733 :                         thisEMSactuator.ErlVariableNum = VariableNum;
     742              :                         // initialize Erl variable for actuator to null
     743          733 :                         state.dataRuntimeLang->ErlVariable(VariableNum).Value = state.dataRuntimeLang->Null;
     744          733 :                         if (ActuatorNum > state.dataRuntimeLang->numActuatorsUsed) {
     745              :                             // Initialize variables for the ExternalInterface variables
     746            1 :                             RuntimeLanguageProcessor::ExternalInterfaceInitializeErlVariable(
     747            2 :                                 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          733 :                 thisEMSactuator.ComponentTypeName = cAlphaArgs(3);
     754          733 :                 thisEMSactuator.UniqueIDName = cAlphaArgs(2);
     755          733 :                 thisEMSactuator.ControlTypeName = cAlphaArgs(4);
     756              : 
     757          733 :                 auto found = state.dataRuntimeLang->EMSActuatorAvailableMap.find(
     758          733 :                     std::make_tuple(thisEMSactuator.ComponentTypeName, thisEMSactuator.UniqueIDName, thisEMSactuator.ControlTypeName));
     759          733 :                 if (found != state.dataRuntimeLang->EMSActuatorAvailableMap.end()) {
     760              : 
     761              :                     // SetupNodeSetPointAsActuators has NOT been called yet at this point
     762          381 :                     thisEMSactuator.ActuatorVariableNum = found->second;
     763          381 :                     thisEMSactuator.CheckedOkay = true;
     764              : 
     765          381 :                     int nHandle = state.dataRuntimeLang->EMSActuatorAvailable(found->second).handleCount;
     766          381 :                     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          381 :                     ++state.dataRuntimeLang->EMSActuatorAvailable(found->second).handleCount;
     777              :                 }
     778          733 :             } // ActuatorNum
     779              :         }
     780              : 
     781           76 :         cCurrentModuleObject = "EnergyManagementSystem:InternalVariable";
     782           76 :         state.dataRuntimeLang->NumInternalVariablesUsed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     783           76 :         if (state.dataRuntimeLang->NumInternalVariablesUsed > 0) {
     784           30 :             state.dataRuntimeLang->EMSInternalVarsUsed.allocate(state.dataRuntimeLang->NumInternalVariablesUsed);
     785              : 
     786          588 :             for (int InternVarNum = 1; InternVarNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternVarNum) {
     787          558 :                 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          558 :                 DataRuntimeLanguage::ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
     801          558 :                 if (!errFlag) {
     802          558 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).Name = cAlphaArgs(1);
     803          558 :                     int VariableNum = RuntimeLanguageProcessor::FindEMSVariable(state, cAlphaArgs(1), 0);
     804          558 :                     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          558 :                         VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0);
     811          558 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).ErlVariableNum = VariableNum;
     812              :                     }
     813              : 
     814          558 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName = cAlphaArgs(2);
     815          558 :                     state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternalDataTypeName = cAlphaArgs(3);
     816              : 
     817          558 :                     bool FoundObjectName = false;
     818              :                     int InternalVarAvailNum; // do loop counter for internal variables available (inner)
     819        53932 :                     for (InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
     820        53629 :                         if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName, cAlphaArgs(3))) {
     821         3473 :                             if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName, cAlphaArgs(2))) {
     822          255 :                                 FoundObjectName = true;
     823          255 :                                 break; // InternalVarAvailNum now holds needed index pointer
     824              :                             }
     825              :                         }
     826              :                     }
     827              : 
     828          558 :                     if (FoundObjectName) {
     829          255 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternVarNum = InternalVarAvailNum;
     830          255 :                         state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay = true;
     831              :                     }
     832              :                 }
     833              :             }
     834              :         }
     835              : 
     836           76 :         RuntimeLanguageProcessor::InitializeRuntimeLanguage(
     837              :             state); // Loads built-in globals and functions, then performs GetInput for runtime language objects
     838              : 
     839           76 :         if (state.dataRuntimeLang->NumProgramCallManagers > 0) {
     840           56 :             cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
     841           56 :             state.dataRuntimeLang->EMSProgramCallManager.allocate(state.dataRuntimeLang->NumProgramCallManagers);
     842              : 
     843          618 :             for (int CallManagerNum = 1; CallManagerNum <= state.dataRuntimeLang->NumProgramCallManagers; ++CallManagerNum) {
     844              : 
     845          562 :                 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          562 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).Name = cAlphaArgs(1);
     859              : 
     860          562 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).CallingPoint =
     861         1124 :                     static_cast<EMSCallFrom>(getEnumValue(EMSCallFromNamesUC, Util::makeUPPER(cAlphaArgs(2))));
     862              : 
     863          562 :                 ErrorsFound = ErrorsFound || (state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).CallingPoint == EMSCallFrom::Invalid);
     864              : 
     865          562 :                 int NumErlProgramsThisManager = NumAlphas - 2; // temporary size of Erl programs in EMSProgramCallManager
     866          562 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).NumErlPrograms = NumErlProgramsThisManager;
     867          562 :                 state.dataRuntimeLang->EMSProgramCallManager(CallManagerNum).ErlProgramARR.allocate(NumErlProgramsThisManager);
     868          562 :                 int ManagerProgramNum = 0; // index counter for Erl programs inside EMSProgramCallManager
     869         1207 :                 for (int AlphaNum = 3; AlphaNum <= NumAlphas; ++AlphaNum) {
     870              :                     // find program name in Stack structure
     871          645 :                     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          645 :                     int StackNum = Util::FindItemInList(cAlphaArgs(AlphaNum), state.dataRuntimeLang->ErlStack);
     879              : 
     880          645 :                     if (StackNum > 0) { // found it
     881              :                         // check for duplicate and warn.
     882          932 :                         for (int Loop = 1; Loop <= ManagerProgramNum; ++Loop) {
     883          287 :                             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          645 :                         ++ManagerProgramNum;
     891              : 
     892          645 :                         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           20 :             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           76 :         cAlphaFieldNames.deallocate();
     912           76 :         cAlphaArgs.deallocate();
     913           76 :         lAlphaFieldBlanks.deallocate();
     914           76 :         cNumericFieldNames.deallocate();
     915           76 :         rNumericArgs.deallocate();
     916           76 :         lNumericFieldBlanks.deallocate();
     917              : 
     918           76 :         if (ErrorsFound) {
     919            0 :             ShowFatalError(state, "Errors found in getting Energy Management System input. Preceding condition causes termination.");
     920              :         }
     921           76 :     }
     922              : 
     923         6810 :     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         6810 :         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         6810 :         std::string cCurrentModuleObject;
     950              : 
     951         6810 :         cCurrentModuleObject = "EnergyManagementSystem:Sensor";
     952       172865 :         for (int SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
     953       166055 :             if (state.dataRuntimeLang->Sensor(SensorNum).CheckedOkay) {
     954       109019 :                 continue;
     955              :             }
     956              : 
     957              :             // try again to process sensor.
     958        57036 :             int VarIndex = GetMeterIndex(state, state.dataRuntimeLang->Sensor(SensorNum).OutputVarName);
     959        57036 :             if (VarIndex > -1) {
     960              : 
     961          394 :                 state.dataRuntimeLang->Sensor(SensorNum).VariableType = OutputProcessor::VariableType::Meter;
     962          394 :                 state.dataRuntimeLang->Sensor(SensorNum).Index = VarIndex;
     963              : 
     964              :             } else {
     965              :                 // Search for variable names
     966        56642 :                 GetVariableTypeAndIndex(state,
     967        56642 :                                         state.dataRuntimeLang->Sensor(SensorNum).OutputVarName,
     968        56642 :                                         state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName,
     969              :                                         VarType,
     970              :                                         VarIndex);
     971        56642 :                 if (VarType == OutputProcessor::VariableType::Invalid) {
     972        55336 :                     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         1306 :                 } 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         1306 :                     state.dataRuntimeLang->Sensor(SensorNum).VariableType = VarType;
     993         1306 :                     state.dataRuntimeLang->Sensor(SensorNum).Index = VarIndex;
     994         1306 :                     state.dataRuntimeLang->Sensor(SensorNum).CheckedOkay = true;
     995              :                     // If variable is Schedule Value, then get the schedule id to register it as being used
     996         1306 :                     if (Util::SameString(state.dataRuntimeLang->Sensor(SensorNum).OutputVarName, "Schedule Value")) {
     997           44 :                         state.dataRuntimeLang->Sensor(SensorNum).sched =
     998           44 :                             Sched::GetSchedule(state, state.dataRuntimeLang->Sensor(SensorNum).UniqueKeyName);
     999           44 :                         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         6810 :         auto &s_lang = state.dataRuntimeLang;
    1021              : 
    1022              :         // added for FMU
    1023        68678 :         for (int ActuatorNum = 1; ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
    1024        68678 :                                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed +
    1025        68678 :                                                      state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportActuatorsUsed;
    1026              :              ++ActuatorNum) {
    1027              :             // If we process the ExternalInterface actuators, all we need to do is to change the
    1028              : 
    1029        61868 :             if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed) {
    1030        61834 :                 cCurrentModuleObject = "EnergyManagementSystem:Actuator";
    1031           34 :             } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed) {
    1032            0 :                 cCurrentModuleObject = "ExternalInterface:Actuator";
    1033           34 :             } else if (ActuatorNum <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed +
    1034           34 :                                           state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportActuatorsUsed) {
    1035           34 :                 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        61868 :             auto &actuatorUsed = state.dataRuntimeLang->EMSActuatorUsed(ActuatorNum);
    1043        61868 :             if (actuatorUsed.CheckedOkay) {
    1044        45973 :                 continue;
    1045              :             }
    1046              : 
    1047        15895 :             auto found = s_lang->EMSActuatorAvailableMap.find(
    1048        15895 :                 std::make_tuple(actuatorUsed.ComponentTypeName, actuatorUsed.UniqueIDName, actuatorUsed.ControlTypeName));
    1049        15895 :             if (found == s_lang->EMSActuatorAvailableMap.end()) {
    1050        15543 :                 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          352 :                 actuatorUsed.ActuatorVariableNum = found->second;
    1067          352 :                 actuatorUsed.CheckedOkay = true;
    1068          352 :                 int nHandle = s_lang->EMSActuatorAvailable(found->second).handleCount;
    1069          352 :                 if (nHandle > 0) {
    1070            8 :                     EnergyPlus::ShowWarningError(state, format("Seems like you already tried to get a Handle on this Actuator {}times.", nHandle));
    1071           16 :                     EnergyPlus::ShowContinueError(state,
    1072           16 :                                                   format("Occurred for componentType='{}', controlType='{}', uniqueKey='{}'.",
    1073            8 :                                                          actuatorUsed.ComponentTypeName,
    1074            8 :                                                          actuatorUsed.ControlTypeName,
    1075            8 :                                                          actuatorUsed.UniqueIDName));
    1076           24 :                     EnergyPlus::ShowContinueError(state, "You should take note that there is a risk of overwritting.");
    1077              :                 }
    1078          352 :                 ++s_lang->EMSActuatorAvailable(found->second).handleCount;
    1079              : 
    1080              :                 // Warn if actuator applied to an air boundary surface
    1081          352 :                 if (Util::SameString(actuatorUsed.ComponentTypeName, "AIRFLOW NETWORK WINDOW/DOOR OPENING")) {
    1082            1 :                     int actuatedSurfNum = Util::FindItemInList(actuatorUsed.UniqueIDName, state.dataSurface->Surface);
    1083            1 :                     if (actuatedSurfNum > 0) {
    1084            1 :                         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        15895 :         } // ActuatorNum
    1094              : 
    1095         6810 :         cCurrentModuleObject = "EnergyManagementSystem:InternalVariable";
    1096        56102 :         for (InternVarNum = 1; InternVarNum <= state.dataRuntimeLang->NumInternalVariablesUsed; ++InternVarNum) {
    1097        49292 :             if (state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay) {
    1098        41008 :                 continue;
    1099              :             }
    1100         8284 :             FoundObjectType = false;
    1101         8284 :             FoundObjectName = false;
    1102      2084833 :             for (InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    1103      2076852 :                 if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName,
    1104      2076852 :                                      state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternalDataTypeName)) {
    1105         2159 :                     FoundObjectType = true;
    1106         2159 :                     if (Util::SameString(state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName,
    1107         2159 :                                          state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName)) {
    1108          303 :                         FoundObjectName = true;
    1109          303 :                         break; // InternalVarAvailNum now holds needed index pointer
    1110              :                     }
    1111              :                 }
    1112              :             }
    1113              : 
    1114         8284 :             if (!FoundObjectType) {
    1115         6701 :                 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         8284 :             if (!FoundObjectName) {
    1127         7981 :                 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          303 :                 state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).InternVarNum = InternalVarAvailNum;
    1138          303 :                 state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).CheckedOkay = true;
    1139              :             }
    1140              :         }
    1141         6810 :         if (reportErrors) {
    1142           75 :             EchoOutActuatorKeyChoices(state);
    1143           75 :             EchoOutInternalVariableChoices(state);
    1144              :         }
    1145              : 
    1146         6810 :         if (ErrorsFound) {
    1147            0 :             ShowFatalError(state, "Errors found in processing Energy Management System input. Preceding condition causes termination.");
    1148              :         }
    1149              : 
    1150         6810 :         if (reportErrors) {
    1151           75 :             RuntimeLanguageProcessor::BeginEnvrnInitializeRuntimeLanguage(state);
    1152              :         }
    1153         6810 :     }
    1154              : 
    1155        58497 :     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        58497 :         Constant::Units units = Constant::Units::None;
    1175        58497 :         Array1D_string keyName;
    1176        58497 :         Array1D_int KeyIndex;
    1177              : 
    1178        58497 :         VarType = OutputProcessor::VariableType::Invalid;
    1179        58497 :         VarIndex = -1;
    1180        58497 :         GetVariableKeyCountandType(state, VarName, NumKeys, VarType, AvgOrSum, StepType, units);
    1181              : 
    1182              :         // note that schedules are not getting VarType set right...
    1183              : 
    1184        58497 :         if (NumKeys > 0) {
    1185         1845 :             KeyIndex.allocate(NumKeys);
    1186         1845 :             keyName.allocate(NumKeys);
    1187         1845 :             GetVariableKeys(state, VarName, VarType, keyName, KeyIndex);
    1188              : 
    1189         1845 :             if (VarType == OutputProcessor::VariableType::Schedule) {
    1190            0 :                 VarIndex = KeyIndex(1);
    1191         1845 :             } else if (keyName(1) == "ENVIRONMENT") {
    1192           44 :                 VarIndex = KeyIndex(1);
    1193              :             } else {
    1194        72384 :                 for (int KeyNum = 1; KeyNum <= NumKeys; ++KeyNum) {
    1195        72384 :                     if (state.dataOutputProcessor->outVars[KeyIndex(KeyNum)]->keyUC == VarKeyName) {
    1196         1801 :                         VarIndex = KeyIndex(KeyNum);
    1197         1801 :                         break;
    1198              :                     }
    1199              :                 }
    1200              :             }
    1201         1845 :             KeyIndex.deallocate();
    1202         1845 :             keyName.deallocate();
    1203              :         }
    1204        58497 :     }
    1205              : 
    1206           75 :     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           75 :         if (state.dataRuntimeLang->OutputEMSActuatorAvailFull) {
    1221              : 
    1222           40 :             print(state.files.edd, "! <EnergyManagementSystem:Actuator Available>, Component Unique Name, Component Type,  Control Type, Units\n");
    1223        64403 :             for (int ActuatorLoop = 1; ActuatorLoop <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorLoop) {
    1224        64363 :                 print(state.files.edd,
    1225              :                       "EnergyManagementSystem:Actuator Available,{},{},{},{}\n",
    1226        64363 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).UniqueIDName,
    1227        64363 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ComponentTypeName,
    1228        64363 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).ControlTypeName,
    1229        64363 :                       state.dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop).Units);
    1230              :             }
    1231           35 :         } 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           75 :     }
    1261              : 
    1262           75 :     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           75 :         if (state.dataRuntimeLang->OutputEMSInternalVarsFull) {
    1276              : 
    1277           40 :             print(state.files.edd, "! <EnergyManagementSystem:InternalVariable Available>, Unique Name, Internal Data Type, Units \n");
    1278        10899 :             for (int InternalDataLoop = 1; InternalDataLoop <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalDataLoop) {
    1279        10859 :                 print(state.files.edd,
    1280              :                       "EnergyManagementSystem:InternalVariable Available,{},{},{}\n",
    1281        10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).UniqueIDName,
    1282        10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).DataTypeName,
    1283        10859 :                       state.dataRuntimeLang->EMSInternalVarsAvailable(InternalDataLoop).Units);
    1284              :             }
    1285              : 
    1286           35 :         } 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           75 :     }
    1306              : 
    1307           75 :     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           75 :         state.dataEMSMgr->lDummy = false;
    1323              : 
    1324           75 :         if (state.dataLoopNodes->NumOfNodes > 0) {
    1325              : 
    1326        16575 :             for (int LoopNode = 1; LoopNode <= state.dataLoopNodes->NumOfNodes; ++LoopNode) {
    1327              :                 // setup the setpoint for each type of variable that can be controlled
    1328        33004 :                 SetupEMSActuator(state,
    1329              :                                  "System Node Setpoint",
    1330        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1331              :                                  "Temperature Setpoint",
    1332              :                                  "[C]",
    1333        16502 :                                  state.dataEMSMgr->lDummy,
    1334        16502 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPoint);
    1335        33004 :                 SetupEMSActuator(state,
    1336              :                                  "System Node Setpoint",
    1337        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1338              :                                  "Temperature Minimum Setpoint",
    1339              :                                  "[C]",
    1340        16502 :                                  state.dataEMSMgr->lDummy,
    1341        16502 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPointLo);
    1342        33004 :                 SetupEMSActuator(state,
    1343              :                                  "System Node Setpoint",
    1344        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1345              :                                  "Temperature Maximum Setpoint",
    1346              :                                  "[C]",
    1347        16502 :                                  state.dataEMSMgr->lDummy,
    1348        16502 :                                  state.dataLoopNodes->Node(LoopNode).TempSetPointHi);
    1349        33004 :                 SetupEMSActuator(state,
    1350              :                                  "System Node Setpoint",
    1351        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1352              :                                  "Humidity Ratio Setpoint",
    1353              :                                  "[kgWater/kgDryAir]",
    1354        16502 :                                  state.dataEMSMgr->lDummy,
    1355        16502 :                                  state.dataLoopNodes->Node(LoopNode).HumRatSetPoint);
    1356        33004 :                 SetupEMSActuator(state,
    1357              :                                  "System Node Setpoint",
    1358        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1359              :                                  "Humidity Ratio Maximum Setpoint",
    1360              :                                  "[kgWater/kgDryAir]",
    1361        16502 :                                  state.dataEMSMgr->lDummy,
    1362        16502 :                                  state.dataLoopNodes->Node(LoopNode).HumRatMax);
    1363        33004 :                 SetupEMSActuator(state,
    1364              :                                  "System Node Setpoint",
    1365        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1366              :                                  "Humidity Ratio Minimum Setpoint",
    1367              :                                  "[kgWater/kgDryAir]",
    1368        16502 :                                  state.dataEMSMgr->lDummy,
    1369        16502 :                                  state.dataLoopNodes->Node(LoopNode).HumRatMin);
    1370        33004 :                 SetupEMSActuator(state,
    1371              :                                  "System Node Setpoint",
    1372        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1373              :                                  "Mass Flow Rate Setpoint",
    1374              :                                  "[kg/s]",
    1375        16502 :                                  state.dataEMSMgr->lDummy,
    1376        16502 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateSetPoint);
    1377        33004 :                 SetupEMSActuator(state,
    1378              :                                  "System Node Setpoint",
    1379        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1380              :                                  "Mass Flow Rate Maximum Available Setpoint",
    1381              :                                  "[kg/s]",
    1382        16502 :                                  state.dataEMSMgr->lDummy,
    1383        16502 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateMaxAvail);
    1384        33004 :                 SetupEMSActuator(state,
    1385              :                                  "System Node Setpoint",
    1386        16502 :                                  state.dataLoopNodes->NodeID(LoopNode),
    1387              :                                  "Mass Flow Rate Minimum Available Setpoint",
    1388              :                                  "[kg/s]",
    1389        16502 :                                  state.dataEMSMgr->lDummy,
    1390        16502 :                                  state.dataLoopNodes->Node(LoopNode).MassFlowRateMinAvail);
    1391              :             }
    1392              : 
    1393              :         } // NumOfNodes > 0
    1394              : 
    1395           75 :         if (state.dataOutAirNodeMgr->NumOutsideAirNodes > 0) {
    1396          880 :             for (int OutsideAirNodeNum = 1; OutsideAirNodeNum <= state.dataOutAirNodeMgr->NumOutsideAirNodes; ++OutsideAirNodeNum) {
    1397          816 :                 int NodeNum = state.dataOutAirNodeMgr->OutsideAirNodeList(OutsideAirNodeNum);
    1398         1632 :                 SetupEMSActuator(state,
    1399              :                                  "Outdoor Air System Node",
    1400          816 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1401              :                                  "Drybulb Temperature",
    1402              :                                  "[C]",
    1403          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb,
    1404          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirDryBulb);
    1405         1632 :                 SetupEMSActuator(state,
    1406              :                                  "Outdoor Air System Node",
    1407          816 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1408              :                                  "Wetbulb Temperature",
    1409              :                                  "[C]",
    1410          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb,
    1411          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWetBulb);
    1412         1632 :                 SetupEMSActuator(state,
    1413              :                                  "Outdoor Air System Node",
    1414          816 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1415              :                                  "Wind Speed",
    1416              :                                  "[m/s]",
    1417          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindSpeed,
    1418          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindSpeed);
    1419         1632 :                 SetupEMSActuator(state,
    1420              :                                  "Outdoor Air System Node",
    1421          816 :                                  state.dataLoopNodes->NodeID(NodeNum),
    1422              :                                  "Wind Direction",
    1423              :                                  "[degree]",
    1424          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindDir,
    1425          816 :                                  state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindDir);
    1426         8877 :                 for (int ActuatorUsedLoop = 1; ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed; ActuatorUsedLoop++) {
    1427         8197 :                     if (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ComponentTypeName, "Outdoor Air System Node") &&
    1428          128 :                         Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).UniqueIDName,
    1429          128 :                                          state.dataLoopNodes->NodeID(NodeNum))) {
    1430            8 :                         state.dataLoopNodes->Node(NodeNum).IsLocalNode = true;
    1431            8 :                         break;
    1432              :                     }
    1433              :                 }
    1434              :             }
    1435              :         }
    1436           75 :     }
    1437              : 
    1438      2828211 :     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      2828211 :         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1455      2406768 :             return;
    1456              :         }
    1457       421443 :         if (state.dataRuntimeLang->NumErlTrendVariables == 0) {
    1458       412182 :             return;
    1459              :         }
    1460              : 
    1461        23736 :         for (int TrendNum = 1; TrendNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendNum) {
    1462        14475 :             int ErlVarNum = state.dataRuntimeLang->TrendVariable(TrendNum).ErlVariablePointer;
    1463        14475 :             int TrendDepth = state.dataRuntimeLang->TrendVariable(TrendNum).LogDepth;
    1464        14475 :             if ((ErlVarNum > 0) && (TrendDepth > 0)) {
    1465        14475 :                 Real64 currentVal = state.dataRuntimeLang->ErlVariable(ErlVarNum).Value.Number;
    1466              :                 // push into trend
    1467        14475 :                 state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR = state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR;
    1468        14475 :                 state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR(1) = currentVal;
    1469        28950 :                 state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR({2, TrendDepth}) =
    1470        43425 :                     state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR({1, TrendDepth - 1});
    1471              :             }
    1472              :         }
    1473              :     }
    1474              : 
    1475         2009 :     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         2009 :         bool FoundControl(false);
    1488              : 
    1489         2009 :         std::string cNodeName = state.dataLoopNodes->NodeID(NodeNum);
    1490         2009 :         std::string cComponentTypeName = "System Node Setpoint";
    1491         2009 :         std::string_view cControlTypeName = controlTypeNames[(int)ctrlVar];
    1492              : 
    1493         2009 :         if (byHandle) {
    1494        44242 :             for (int Loop = 1; Loop <= state.dataRuntimeLang->numEMSActuatorsAvailable; ++Loop) {
    1495        44727 :                 if ((state.dataRuntimeLang->EMSActuatorAvailable(Loop).handleCount > 0) &&
    1496          732 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).ComponentTypeName, cComponentTypeName)) &&
    1497        44974 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).UniqueIDName, cNodeName)) &&
    1498           28 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorAvailable(Loop).ControlTypeName, cControlTypeName))) {
    1499           28 :                     FoundControl = true;
    1500           28 :                     break;
    1501              :                 }
    1502              :             }
    1503           28 :             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         8585 :             for (int Loop = 1; Loop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed; ++Loop) {
    1509         7901 :                 if ((Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).ComponentTypeName, cComponentTypeName)) &&
    1510         7901 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).UniqueIDName, cNodeName)) &&
    1511           82 :                     (Util::SameString(state.dataRuntimeLang->EMSActuatorUsed(Loop).ControlTypeName, cControlTypeName))) {
    1512           82 :                     FoundControl = true;
    1513           82 :                     break;
    1514              :                 }
    1515              :             }
    1516              :         }
    1517              : 
    1518         2009 :         return FoundControl;
    1519         2009 :     }
    1520              : 
    1521         1981 :     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         1981 :         bool FoundControl = CheckIfNodeSetPointManaged(state, NodeNum, ctrlVar, false);
    1536              : 
    1537         1981 :         if ((!ErrorFlag) && (!FoundControl)) {
    1538         1899 :             int numPythonPlugins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "PythonPlugin:Instance");
    1539         1899 :             int numActiveCallbacks = PluginManagement::PluginManager::numActiveCallbacks(state); // errorCallback;
    1540         1899 :             if ((numPythonPlugins + numActiveCallbacks) == 0) {
    1541         1397 :                 ErrorFlag = true;
    1542              :             } else {
    1543              :                 // We'll defer to checking at the end whether a Plugin / API called getActuatorHandle on it
    1544          502 :                 auto &nodeSetpointCheck = state.dataLoopNodes->NodeSetpointCheck(NodeNum);
    1545          502 :                 nodeSetpointCheck.needsSetpointChecking = true;
    1546          502 :                 nodeSetpointCheck.checkSetPoint[(int)ctrlVar] = true;
    1547              :             }
    1548              :         }
    1549              : 
    1550         1981 :         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          799 :     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          799 :         bool FatalErrorFlag = false;
    1578              : 
    1579        65796 :         for (int NodeNum = 1; NodeNum <= state.dataLoopNodes->NumOfNodes; ++NodeNum) {
    1580        64997 :             auto &nodeSetpointCheck = state.dataLoopNodes->NodeSetpointCheck(NodeNum);
    1581              : 
    1582        64997 :             if (nodeSetpointCheck.needsSetpointChecking) {
    1583              :                 // Start by setting it to false (assume matched)
    1584           28 :                 nodeSetpointCheck.needsSetpointChecking = false;
    1585              : 
    1586          280 :                 for (int iCtrlVar = 0; iCtrlVar < (int)HVAC::CtrlVarType::Num; ++iCtrlVar) {
    1587          252 :                     if (nodeSetpointCheck.checkSetPoint[iCtrlVar]) {
    1588           28 :                         nodeSetpointCheck.needsSetpointChecking |=
    1589           28 :                             !CheckIfNodeSetPointManaged(state, NodeNum, static_cast<HVAC::CtrlVarType>(iCtrlVar), true);
    1590              :                     }
    1591              :                 }
    1592              : 
    1593           28 :                 if (nodeSetpointCheck.needsSetpointChecking) {
    1594            0 :                     FatalErrorFlag = true;
    1595              :                 }
    1596              :             }
    1597              :         }
    1598              : 
    1599          799 :         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          799 :     }
    1605              : 
    1606       259988 :     bool CheckIfNodeMoreInfoSensedByEMS(EnergyPlusData &state,
    1607              :                                         int const nodeNum, // index of node being checked.
    1608              :                                         std::string const &varName)
    1609              :     {
    1610       259988 :         bool returnValue = false;
    1611      5395708 :         for (int loop = 1; loop <= state.dataRuntimeLang->NumSensors; ++loop) {
    1612      5137380 :             if (state.dataRuntimeLang->Sensor(loop).UniqueKeyName == state.dataLoopNodes->NodeID(nodeNum) &&
    1613         1660 :                 Util::SameString(state.dataRuntimeLang->Sensor(loop).OutputVarName, varName)) {
    1614            1 :                 returnValue = true;
    1615              :             }
    1616              :         }
    1617              : 
    1618       259988 :         return returnValue;
    1619              :     }
    1620              : 
    1621           75 :     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           75 :         state.dataEMSMgr->lDummy2 = false;
    1632              : 
    1633           75 :         if (allocated(state.dataAirLoop->PriAirSysAvailMgr)) {
    1634           63 :             int numAirLoops = isize(state.dataAirLoop->PriAirSysAvailMgr);
    1635          408 :             for (int Loop = 1; Loop <= numAirLoops; ++Loop) {
    1636          690 :                 SetupEMSActuator(state,
    1637              :                                  "AirLoopHVAC",
    1638          345 :                                  state.dataAirSystemsData->PrimaryAirSystems(Loop).Name,
    1639              :                                  "Availability Status",
    1640              :                                  "[ ]",
    1641          345 :                                  state.dataEMSMgr->lDummy2,
    1642          345 :                                  (int &)state.dataAirLoop->PriAirSysAvailMgr(Loop).availStatus);
    1643              :             }
    1644              :         }
    1645           75 :     }
    1646              : 
    1647           76 :     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        12149 :         for (int loopSurfNum = 1; loopSurfNum <= state.dataSurface->TotSurfaces; ++loopSurfNum) {
    1661        12073 :             auto &surf = state.dataSurface->Surface(loopSurfNum);
    1662              : 
    1663        12073 :             if (surf.Class != DataSurfaces::SurfaceClass::Window) {
    1664        10253 :                 continue;
    1665              :             }
    1666         1820 :             if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
    1667            0 :                 continue;
    1668              :             }
    1669         1820 :             if (!surf.HasShadeControl) {
    1670         1808 :                 continue;
    1671              :             }
    1672              : 
    1673           12 :             if (state.dataSurface->SurfWinHasShadeOrBlindLayer(loopSurfNum)) {
    1674           30 :                 SetupEMSActuator(state,
    1675              :                                  "Window Shading Control",
    1676           10 :                                  state.dataSurface->Surface(loopSurfNum).Name,
    1677              :                                  "Control Status",
    1678              :                                  "[ShadeStatus]",
    1679           10 :                                  state.dataSurface->SurfWinShadingFlagEMSOn(loopSurfNum),
    1680           10 :                                  state.dataSurface->SurfWinShadingFlagEMSValue(loopSurfNum));
    1681              : 
    1682           10 :                 auto &surfShade = state.dataSurface->surfShades(loopSurfNum);
    1683           10 :                 if (surfShade.blind.movableSlats) {
    1684            0 :                     SetupEMSActuator(state,
    1685              :                                      "Window Shading Control",
    1686              :                                      surf.Name,
    1687              :                                      "Slat Angle",
    1688              :                                      "[degrees]",
    1689            0 :                                      surfShade.blind.slatAngDegEMSon,
    1690            0 :                                      surfShade.blind.slatAngDegEMSValue);
    1691              :                 }
    1692            2 :             } 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            2 :                 if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(loopSurfNum).activeWindowShadingControl).ShadingType !=
    1703              :                     DataSurfaces::WinShadingType::SwitchableGlazing) {
    1704            0 :                     ShowSevereError(state,
    1705            0 :                                     format("Missing shade or blind layer in window construction name = '{}', surface name = '{}'.",
    1706            0 :                                            state.dataConstruction->Construct(state.dataSurface->Surface(loopSurfNum).activeShadedConstruction).Name,
    1707            0 :                                            state.dataSurface->Surface(loopSurfNum).Name));
    1708            0 :                     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            0 :                     ShowContinueError(state, "...Add shade or blind layer to this construction in order to be able to apply EMS Actuator.");
    1712              :                 }
    1713              :             }
    1714              :         }
    1715           76 :     }
    1716              : 
    1717           76 :     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         1226 :         for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
    1731         2300 :             SetupEMSActuator(state,
    1732              :                              "Zone Temperature Control",
    1733         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).ZoneName,
    1734              :                              "Heating Setpoint",
    1735              :                              "[C]",
    1736         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideHeatingSetPointOn,
    1737         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideHeatingSetPointValue);
    1738         2300 :             SetupEMSActuator(state,
    1739              :                              "Zone Temperature Control",
    1740         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).ZoneName,
    1741              :                              "Cooling Setpoint",
    1742              :                              "[C]",
    1743         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideCoolingSetPointOn,
    1744         1150 :                              state.dataZoneCtrls->TempControlledZone(Loop).EMSOverrideCoolingSetPointValue);
    1745              :         }
    1746              : 
    1747          103 :         for (int Loop = 1; Loop <= state.dataZoneCtrls->NumHumidityControlZones; ++Loop) {
    1748           54 :             SetupEMSActuator(state,
    1749              :                              "Zone Humidity Control",
    1750           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).ZoneName,
    1751              :                              "Relative Humidity Humidifying Setpoint",
    1752              :                              "[%]",
    1753           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideHumidifySetPointOn,
    1754           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideHumidifySetPointValue);
    1755           54 :             SetupEMSActuator(state,
    1756              :                              "Zone Humidity Control",
    1757           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).ZoneName,
    1758              :                              "Relative Humidity Dehumidifying Setpoint",
    1759              :                              "[%]",
    1760           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideDehumidifySetPointOn,
    1761           27 :                              state.dataZoneCtrls->HumidityControlZone(Loop).EMSOverrideDehumidifySetPointValue);
    1762              :         }
    1763              : 
    1764           76 :         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           76 :     }
    1781              : 
    1782           76 :     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        12149 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1793        24146 :             SetupEMSActuator(state,
    1794              :                              "Surface",
    1795        12073 :                              state.dataSurface->Surface(SurfNum).Name,
    1796              :                              "Interior Surface Convection Heat Transfer Coefficient",
    1797              :                              "[W/m2-K]",
    1798        12073 :                              state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum),
    1799        12073 :                              state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum));
    1800        24146 :             SetupEMSActuator(state,
    1801              :                              "Surface",
    1802        12073 :                              state.dataSurface->Surface(SurfNum).Name,
    1803              :                              "Exterior Surface Convection Heat Transfer Coefficient",
    1804              :                              "[W/m2-K]",
    1805        12073 :                              state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum),
    1806        12073 :                              state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum));
    1807              :         }
    1808           76 :     }
    1809              : 
    1810           76 :     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        12149 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1821              : 
    1822        12073 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
    1823           78 :                 continue;
    1824              :             }
    1825              : 
    1826        35985 :             SetupEMSActuator(state,
    1827              :                              "Surface",
    1828        11995 :                              state.dataSurface->Surface(SurfNum).Name,
    1829              :                              "Construction State",
    1830              :                              "[ ]",
    1831        11995 :                              state.dataSurface->SurfEMSConstructionOverrideON(SurfNum),
    1832        11995 :                              state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum));
    1833              :         }
    1834              : 
    1835              :         // Setup error checking storage
    1836              : 
    1837           76 :         if (!allocated(state.dataRuntimeLang->EMSConstructActuatorChecked)) {
    1838           76 :             state.dataRuntimeLang->EMSConstructActuatorChecked.allocate(state.dataHeatBal->TotConstructs, state.dataSurface->TotSurfaces);
    1839              :         }
    1840           76 :         state.dataRuntimeLang->EMSConstructActuatorChecked = false;
    1841              : 
    1842           76 :         if (!allocated(state.dataRuntimeLang->EMSConstructActuatorIsOkay)) {
    1843           76 :             state.dataRuntimeLang->EMSConstructActuatorIsOkay.allocate(state.dataHeatBal->TotConstructs, state.dataSurface->TotSurfaces);
    1844              :         }
    1845           76 :         state.dataRuntimeLang->EMSConstructActuatorIsOkay = false;
    1846           76 :     }
    1847              : 
    1848           76 :     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        12149 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1862              : 
    1863        12073 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
    1864           78 :                 continue;
    1865              :             }
    1866        11995 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond != DataSurfaces::ExternalEnvironment) {
    1867         7751 :                 continue;
    1868              :             }
    1869              : 
    1870         8488 :             SetupEMSActuator(state,
    1871              :                              "Surface",
    1872         4244 :                              state.dataSurface->Surface(SurfNum).Name,
    1873              :                              "View Factor To Ground",
    1874              :                              "[ ]",
    1875         4244 :                              state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum),
    1876         4244 :                              state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum));
    1877              : 
    1878         8488 :             SetupEMSActuator(state,
    1879              :                              "Surface",
    1880         4244 :                              state.dataSurface->Surface(SurfNum).Name,
    1881              :                              "Outdoor Air Drybulb Temperature",
    1882              :                              "[C]",
    1883         4244 :                              state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum),
    1884         4244 :                              state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum));
    1885              : 
    1886         8488 :             SetupEMSActuator(state,
    1887              :                              "Surface",
    1888         4244 :                              state.dataSurface->Surface(SurfNum).Name,
    1889              :                              "Outdoor Air Wetbulb Temperature",
    1890              :                              "[C]",
    1891         4244 :                              state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum),
    1892         4244 :                              state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum));
    1893         4244 :             if (state.dataSurface->Surface(SurfNum).ExtWind) {
    1894         8474 :                 SetupEMSActuator(state,
    1895              :                                  "Surface",
    1896         4237 :                                  state.dataSurface->Surface(SurfNum).Name,
    1897              :                                  "Outdoor Air Wind Speed",
    1898              :                                  "[m/s]",
    1899         4237 :                                  state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum),
    1900         4237 :                                  state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum));
    1901         8474 :                 SetupEMSActuator(state,
    1902              :                                  "Surface",
    1903         4237 :                                  state.dataSurface->Surface(SurfNum).Name,
    1904              :                                  "Outdoor Air Wind Direction",
    1905              :                                  "[degree]",
    1906         4237 :                                  state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum),
    1907         4237 :                                  state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum));
    1908              :             }
    1909              :         }
    1910           76 :     }
    1911              : 
    1912           76 :     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           76 :         if (!state.dataHeatBal->Zone.empty()) {
    1923         1329 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1924         1253 :                 auto &zone = state.dataHeatBal->Zone(ZoneNum);
    1925              : 
    1926         1253 :                 SetupEMSInternalVariable(state, "Zone Floor Area", zone.Name, "[m2]", zone.FloorArea);
    1927         1253 :                 SetupEMSInternalVariable(state, "Zone Air Volume", zone.Name, "[m3]", zone.Volume);
    1928         1253 :                 SetupEMSInternalVariable(state, "Zone Multiplier", zone.Name, "[ ]", zone.Multiplier);
    1929         1253 :                 SetupEMSInternalVariable(state, "Zone List Multiplier", zone.Name, "[ ]", zone.ListMultiplier);
    1930              :             }
    1931              :         }
    1932           76 :     }
    1933              : 
    1934           76 :     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         1329 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1948         1253 :             auto &zone = state.dataHeatBal->Zone(ZoneNum);
    1949              : 
    1950         1253 :             SetupEMSActuator(state,
    1951              :                              "Zone",
    1952              :                              zone.Name,
    1953              :                              "Outdoor Air Drybulb Temperature",
    1954              :                              "[C]",
    1955         1253 :                              zone.OutDryBulbTempEMSOverrideOn,
    1956         1253 :                              zone.OutDryBulbTempEMSOverrideValue);
    1957         1253 :             SetupEMSActuator(state,
    1958              :                              "Zone",
    1959              :                              zone.Name,
    1960              :                              "Outdoor Air Wetbulb Temperature",
    1961              :                              "[C]",
    1962         1253 :                              zone.OutWetBulbTempEMSOverrideOn,
    1963         1253 :                              zone.OutWetBulbTempEMSOverrideValue);
    1964         1253 :             SetupEMSActuator(
    1965         1253 :                 state, "Zone", zone.Name, "Outdoor Air Wind Speed", "[m/s]", zone.WindSpeedEMSOverrideOn, zone.WindSpeedEMSOverrideValue);
    1966         1253 :             SetupEMSActuator(
    1967         1253 :                 state, "Zone", zone.Name, "Outdoor Air Wind Direction", "[degree]", zone.WindDirEMSOverrideOn, zone.WindDirEMSOverrideValue);
    1968              :         }
    1969           76 :     }
    1970              : 
    1971          799 :     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         1531 :         for (int actuatorUsedLoop = 1; actuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed; ++actuatorUsedLoop) {
    1976          732 :             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          799 :     }
    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       242561 : 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       242561 :     auto &s_lang = state.dataRuntimeLang;
    2021              : 
    2022       242561 :     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       242561 :     if (s_lang->EMSActuatorAvailableMap.find(tup) != s_lang->EMSActuatorAvailableMap.end()) {
    2026           43 :         return;
    2027              :     }
    2028              : 
    2029       242518 :     if (s_lang->numEMSActuatorsAvailable == 0) {
    2030           76 :         s_lang->EMSActuatorAvailable.allocate(s_lang->varsAvailableAllocInc);
    2031           76 :         s_lang->numEMSActuatorsAvailable = 1;
    2032           76 :         s_lang->maxEMSActuatorsAvailable = s_lang->varsAvailableAllocInc;
    2033              :     } else {
    2034       242442 :         if (s_lang->numEMSActuatorsAvailable + 1 > s_lang->maxEMSActuatorsAvailable) {
    2035           92 :             s_lang->EMSActuatorAvailable.redimension(s_lang->maxEMSActuatorsAvailable *= 2);
    2036              :         }
    2037       242442 :         ++s_lang->numEMSActuatorsAvailable;
    2038              :     }
    2039              : 
    2040       242518 :     auto &actuator = s_lang->EMSActuatorAvailable(s_lang->numEMSActuatorsAvailable);
    2041       242518 :     actuator.ComponentTypeName = objType;
    2042       242518 :     actuator.UniqueIDName = objName;
    2043       242518 :     actuator.ControlTypeName = controlTypeName;
    2044       242518 :     actuator.Units = cUnits;
    2045       242518 :     actuator.Actuated = &lEMSActuated; // Pointer assigment
    2046       242518 :     actuator.RealValue = &rValue;      // Pointer assigment
    2047       242518 :     actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Real;
    2048       242518 :     s_lang->EMSActuatorAvailableMap.insert_or_assign(std::move(tup), s_lang->numEMSActuatorsAvailable);
    2049       242561 : }
    2050              : 
    2051        12350 : 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        12350 :     auto &s_lang = state.dataRuntimeLang;
    2073              : 
    2074        12350 :     std::string const objType = Util::makeUPPER(cComponentTypeName);
    2075        12350 :     std::string const objName = Util::makeUPPER(cUniqueIDName);
    2076        12350 :     std::string const actuatorName = Util::makeUPPER(cControlTypeName);
    2077              : 
    2078              :     // DataRuntimeLanguage::EMSActuatorKey const key(UpperCaseObjectType, UpperCaseObjectName, UpperCaseActuatorName);
    2079              : 
    2080        12350 :     if (s_lang->EMSActuatorAvailableMap.find(std::make_tuple(objType, objName, actuatorName)) == s_lang->EMSActuatorAvailableMap.end()) {
    2081        12350 :         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        12350 :             if (s_lang->numEMSActuatorsAvailable + 1 > s_lang->maxEMSActuatorsAvailable) {
    2087            8 :                 s_lang->EMSActuatorAvailable.redimension(s_lang->maxEMSActuatorsAvailable *= 2);
    2088              :             }
    2089        12350 :             ++s_lang->numEMSActuatorsAvailable;
    2090              :         }
    2091              : 
    2092        12350 :         auto &actuator(s_lang->EMSActuatorAvailable(s_lang->numEMSActuatorsAvailable));
    2093        12350 :         actuator.ComponentTypeName = cComponentTypeName;
    2094        12350 :         actuator.UniqueIDName = cUniqueIDName;
    2095        12350 :         actuator.ControlTypeName = cControlTypeName;
    2096        12350 :         actuator.Units = cUnits;
    2097        12350 :         actuator.Actuated = &lEMSActuated; // Pointer assigment
    2098        12350 :         actuator.IntValue = &iValue;       // Pointer assigment
    2099        12350 :         actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Integer;
    2100        12350 :         s_lang->EMSActuatorAvailableMap.insert_or_assign(std::make_tuple(objType, objName, actuatorName), s_lang->numEMSActuatorsAvailable);
    2101              :     }
    2102        12350 : }
    2103              : 
    2104            0 : 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            0 :     auto &s_lang = state.dataRuntimeLang;
    2126              : 
    2127            0 :     std::string const objType = Util::makeUPPER(cComponentTypeName);
    2128            0 :     std::string const objName = Util::makeUPPER(cUniqueIDName);
    2129            0 :     std::string const actuatorName = Util::makeUPPER(cControlTypeName);
    2130              : 
    2131              :     // DataRuntimeLanguage::EMSActuatorKey const key(UpperCaseObjectType, UpperCaseObjectName, UpperCaseActuatorName);
    2132              : 
    2133            0 :     if (s_lang->EMSActuatorAvailableMap.find(std::make_tuple(objType, objName, actuatorName)) == s_lang->EMSActuatorAvailableMap.end()) {
    2134            0 :         if (s_lang->numEMSActuatorsAvailable == 0) {
    2135            0 :             s_lang->EMSActuatorAvailable.allocate(s_lang->varsAvailableAllocInc);
    2136            0 :             s_lang->numEMSActuatorsAvailable = 1;
    2137            0 :             s_lang->maxEMSActuatorsAvailable = s_lang->varsAvailableAllocInc;
    2138              :         } else {
    2139            0 :             if (s_lang->numEMSActuatorsAvailable + 1 > s_lang->maxEMSActuatorsAvailable) {
    2140            0 :                 s_lang->EMSActuatorAvailable.redimension(s_lang->maxEMSActuatorsAvailable *= 2);
    2141              :             }
    2142            0 :             ++s_lang->numEMSActuatorsAvailable;
    2143              :         }
    2144              : 
    2145            0 :         auto &actuator(s_lang->EMSActuatorAvailable(s_lang->numEMSActuatorsAvailable));
    2146            0 :         actuator.ComponentTypeName = cComponentTypeName;
    2147            0 :         actuator.UniqueIDName = cUniqueIDName;
    2148            0 :         actuator.ControlTypeName = cControlTypeName;
    2149            0 :         actuator.Units = cUnits;
    2150            0 :         actuator.Actuated = &lEMSActuated; // Pointer assigment
    2151            0 :         actuator.LogValue = &lValue;       // Pointer assigment
    2152            0 :         actuator.PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Logical;
    2153            0 :         s_lang->EMSActuatorAvailableMap.insert_or_assign(std::make_tuple(objType, objName, actuatorName), s_lang->numEMSActuatorsAvailable);
    2154              :     }
    2155            0 : }
    2156              : 
    2157        38334 : 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        38334 :     bool FoundDuplicate = false;
    2170              : 
    2171     38966088 :     for (int InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    2172     39961967 :         if ((Util::SameString(cDataTypeName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName)) &&
    2173      1034213 :             (Util::SameString(cUniqueIDName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName))) {
    2174            0 :             FoundDuplicate = true;
    2175            0 :             break;
    2176              :         }
    2177              :     }
    2178              : 
    2179        38334 :     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        38334 :         if (state.dataRuntimeLang->numEMSInternalVarsAvailable == 0) {
    2186          362 :             state.dataRuntimeLang->EMSInternalVarsAvailable.allocate(state.dataRuntimeLang->varsAvailableAllocInc);
    2187          362 :             state.dataRuntimeLang->numEMSInternalVarsAvailable = 1;
    2188          362 :             state.dataRuntimeLang->maxEMSInternalVarsAvailable = state.dataRuntimeLang->varsAvailableAllocInc;
    2189              :         } else {
    2190        37972 :             if (state.dataRuntimeLang->numEMSInternalVarsAvailable + 1 > state.dataRuntimeLang->maxEMSInternalVarsAvailable) {
    2191           36 :                 state.dataRuntimeLang->EMSInternalVarsAvailable.redimension(state.dataRuntimeLang->maxEMSInternalVarsAvailable +=
    2192           18 :                                                                             state.dataRuntimeLang->varsAvailableAllocInc);
    2193              :             }
    2194        37972 :             ++state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2195              :         }
    2196              : 
    2197        38334 :         int InternalVarAvailNum = state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2198        38334 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName = cDataTypeName;
    2199        38334 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName = cUniqueIDName;
    2200        38334 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).Units = cUnits;
    2201        38334 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).RealValue = &rValue;
    2202        38334 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Real;
    2203              :     }
    2204        38334 : }
    2205              : 
    2206         2506 : 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         2506 :     bool FoundDuplicate = false;
    2219              : 
    2220       768641 :     for (int InternalVarAvailNum = 1; InternalVarAvailNum <= state.dataRuntimeLang->numEMSInternalVarsAvailable; ++InternalVarAvailNum) {
    2221       840985 :         if ((Util::SameString(cDataTypeName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName)) &&
    2222        74850 :             (Util::SameString(cUniqueIDName, state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName))) {
    2223            0 :             FoundDuplicate = true;
    2224            0 :             break;
    2225              :         }
    2226              :     }
    2227              : 
    2228         2506 :     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         2506 :         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         2506 :             if (state.dataRuntimeLang->numEMSInternalVarsAvailable + 1 > state.dataRuntimeLang->maxEMSInternalVarsAvailable) {
    2240            0 :                 state.dataRuntimeLang->EMSInternalVarsAvailable.redimension(state.dataRuntimeLang->maxEMSInternalVarsAvailable +=
    2241            0 :                                                                             state.dataRuntimeLang->varsAvailableAllocInc);
    2242              :             }
    2243         2506 :             ++state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2244              :         }
    2245              : 
    2246         2506 :         int InternalVarAvailNum = state.dataRuntimeLang->numEMSInternalVarsAvailable;
    2247         2506 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).DataTypeName = cDataTypeName;
    2248         2506 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).UniqueIDName = cUniqueIDName;
    2249         2506 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).Units = cUnits;
    2250         2506 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).IntValue = &iValue;
    2251         2506 :         state.dataRuntimeLang->EMSInternalVarsAvailable(InternalVarAvailNum).PntrVarTypeUsed = DataRuntimeLanguage::PtrDataType::Integer;
    2252              :     }
    2253         2506 : }
    2254              : 
    2255              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1