LCOV - code coverage report
Current view: top level - EnergyPlus - EMSManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 73.3 % 1054 773
Test Date: 2025-05-22 16:09:37 Functions: 96.7 % 30 29

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

Generated by: LCOV version 2.0-1