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