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