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
|