Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Array2D.hh>
55 : #include <ObjexxFCL/ArrayS.functions.hh>
56 : // #include <ObjexxFCL/Fmath.hh>
57 : #include <ObjexxFCL/char.functions.hh>
58 : #include <ObjexxFCL/random.hh>
59 : #include <ObjexxFCL/string.functions.hh>
60 : #include <ObjexxFCL/time.hh>
61 :
62 : // EnergyPlus Headers
63 : #include <EnergyPlus/Construction.hh>
64 : #include <EnergyPlus/CurveManager.hh>
65 : #include <EnergyPlus/Data/EnergyPlusData.hh>
66 : #include <EnergyPlus/DataEnvironment.hh>
67 : #include <EnergyPlus/DataHVACGlobals.hh>
68 : #include <EnergyPlus/DataIPShortCuts.hh>
69 : #include <EnergyPlus/DataSystemVariables.hh>
70 : #include <EnergyPlus/EMSManager.hh>
71 : #include <EnergyPlus/General.hh>
72 : #include <EnergyPlus/GlobalNames.hh>
73 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/Psychrometrics.hh>
76 : #include <EnergyPlus/RuntimeLanguageProcessor.hh>
77 : #include <EnergyPlus/UtilityRoutines.hh>
78 : #include <EnergyPlus/WeatherManager.hh>
79 :
80 : namespace EnergyPlus::RuntimeLanguageProcessor {
81 :
82 : // MODULE INFORMATION:
83 : // AUTHOR Peter Graham Ellis
84 : // DATE WRITTEN June 2006
85 : // MODIFIED Brent Griffith, May - August 2009
86 : // RE-ENGINEERED na
87 :
88 : // Using/Aliasing
89 : using namespace DataRuntimeLanguage;
90 :
91 1467466 : void InitializeRuntimeLanguage(EnergyPlusData &state)
92 : {
93 :
94 : // SUBROUTINE INFORMATION:
95 : // AUTHOR Peter Graham Ellis
96 : // DATE WRITTEN June 2006
97 : // MODIFIED Rui Zhang February 2010
98 : // RE-ENGINEERED na
99 :
100 : // METHODOLOGY EMPLOYED:
101 : // One time run. Must be run BEFORE anything gets parsed.
102 :
103 : // Using/Aliasing
104 1467466 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
105 1467466 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
106 :
107 1467466 : Real64 tmpCurrentTime(0.0);
108 1467466 : Real64 tmpMinutes(0.0);
109 1467466 : Real64 tmpHours(0.0);
110 1467466 : Real64 tmpCurEnvirNum(0.0);
111 1467466 : Array1D_int datevalues(8);
112 : // value(1) Current year
113 : // value(2) Current month
114 : // value(3) Current day
115 : // value(4) Time difference with respect to UTC in minutes (0-59)
116 : // value(5) Hour of the day (0-23)
117 : // value(6) Minutes (0-59)
118 : // value(7) Seconds (0-59)
119 : // value(8) Milliseconds (0-999)
120 :
121 1467466 : if (state.dataRuntimeLangProcessor->InitializeOnce) {
122 :
123 46 : std::string datestring; // supposedly returns blank when no date available.
124 :
125 46 : state.dataRuntimeLang->emsVarBuiltInStart = state.dataRuntimeLang->NumErlVariables + 1;
126 :
127 46 : state.dataRuntimeLang->False = SetErlValueNumber(0.0);
128 46 : state.dataRuntimeLang->True = SetErlValueNumber(1.0);
129 :
130 : // Create constant built-in variables
131 138 : state.dataRuntimeLangProcessor->NullVariableNum = NewEMSVariable(state, "NULL", 0, SetErlValueNumber(0.0));
132 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->NullVariableNum).Value.Type = Value::Null;
133 138 : state.dataRuntimeLangProcessor->FalseVariableNum = NewEMSVariable(state, "FALSE", 0, state.dataRuntimeLang->False);
134 138 : state.dataRuntimeLangProcessor->TrueVariableNum = NewEMSVariable(state, "TRUE", 0, state.dataRuntimeLang->True);
135 138 : state.dataRuntimeLangProcessor->OffVariableNum = NewEMSVariable(state, "OFF", 0, state.dataRuntimeLang->False);
136 138 : state.dataRuntimeLangProcessor->OnVariableNum = NewEMSVariable(state, "ON", 0, state.dataRuntimeLang->True);
137 138 : state.dataRuntimeLangProcessor->PiVariableNum = NewEMSVariable(state, "PI", 0, SetErlValueNumber(Constant::Pi));
138 92 : state.dataRuntimeLangProcessor->TimeStepsPerHourVariableNum =
139 138 : NewEMSVariable(state, "TIMESTEPSPERHOUR", 0, SetErlValueNumber(double(state.dataGlobal->TimeStepsInHour)));
140 :
141 : // Create dynamic built-in variables
142 138 : state.dataRuntimeLangProcessor->YearVariableNum = NewEMSVariable(state, "YEAR", 0);
143 138 : state.dataRuntimeLangProcessor->CalendarYearVariableNum = NewEMSVariable(state, "CALENDARYEAR", 0);
144 138 : state.dataRuntimeLangProcessor->MonthVariableNum = NewEMSVariable(state, "MONTH", 0);
145 138 : state.dataRuntimeLangProcessor->DayOfMonthVariableNum = NewEMSVariable(state, "DAYOFMONTH", 0); // 'DAYOFMONTH'?
146 138 : state.dataRuntimeLangProcessor->DayOfWeekVariableNum = NewEMSVariable(state, "DAYOFWEEK", 0);
147 138 : state.dataRuntimeLangProcessor->DayOfYearVariableNum = NewEMSVariable(state, "DAYOFYEAR", 0);
148 138 : state.dataRuntimeLangProcessor->HourVariableNum = NewEMSVariable(state, "HOUR", 0);
149 138 : state.dataRuntimeLangProcessor->TimeStepNumVariableNum = NewEMSVariable(state, "TIMESTEPNUM", 0);
150 138 : state.dataRuntimeLangProcessor->MinuteVariableNum = NewEMSVariable(state, "MINUTE", 0);
151 138 : state.dataRuntimeLangProcessor->HolidayVariableNum = NewEMSVariable(state, "HOLIDAY", 0);
152 138 : state.dataRuntimeLangProcessor->DSTVariableNum = NewEMSVariable(state, "DAYLIGHTSAVINGS", 0);
153 138 : state.dataRuntimeLangProcessor->CurrentTimeVariableNum = NewEMSVariable(state, "CURRENTTIME", 0);
154 138 : state.dataRuntimeLangProcessor->SunIsUpVariableNum = NewEMSVariable(state, "SUNISUP", 0);
155 138 : state.dataRuntimeLangProcessor->IsRainingVariableNum = NewEMSVariable(state, "ISRAINING", 0);
156 138 : state.dataRuntimeLangProcessor->SystemTimeStepVariableNum = NewEMSVariable(state, "SYSTEMTIMESTEP", 0);
157 138 : state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum = NewEMSVariable(state, "ZONETIMESTEP", 0);
158 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum).Value =
159 92 : SetErlValueNumber(state.dataGlobal->TimeStepZone);
160 138 : state.dataRuntimeLangProcessor->CurrentEnvironmentPeriodNum = NewEMSVariable(state, "CURRENTENVIRONMENT", 0);
161 138 : state.dataRuntimeLangProcessor->ActualDateAndTimeNum = NewEMSVariable(state, "ACTUALDATEANDTIME", 0);
162 138 : state.dataRuntimeLangProcessor->ActualTimeNum = NewEMSVariable(state, "ACTUALTIME", 0);
163 138 : state.dataRuntimeLangProcessor->WarmUpFlagNum = NewEMSVariable(state, "WARMUPFLAG", 0);
164 :
165 : // update the end of the built-in range so we can ignore those on API calls
166 46 : state.dataRuntimeLang->emsVarBuiltInEnd = state.dataRuntimeLang->NumErlVariables;
167 :
168 46 : GetRuntimeLanguageUserInput(state); // Load and parse all runtime language objects
169 :
170 46 : date_and_time(datestring, _, _, datevalues);
171 46 : if (datestring != "") {
172 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ActualDateAndTimeNum).Value =
173 92 : SetErlValueNumber(double(sum(datevalues)));
174 : // datevalues(1)+datevalues(2)+datevalues(3)+ &
175 : // datevalues(5)+datevalues(6)+datevalues(7)+datevalues(8)
176 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ActualTimeNum).Value =
177 92 : SetErlValueNumber(double(sum(datevalues({5, 8}))));
178 : // datevalues(5)+datevalues(6)+datevalues(7)+datevalues(8)
179 : // ELSE
180 : // ErlVariable(ActualDateAndTimeNum)%Value = SetErlValueNumber(REAL(RANDOM_NUMBER(X=509),r64))
181 : // ErlVariable(ActualTimeNum)%Value = SetErlValueNumber(REAL(RANDOM_NUMBER(X=400),r64))
182 : }
183 :
184 46 : state.dataRuntimeLangProcessor->InitializeOnce = false;
185 46 : }
186 :
187 : // Update built-in variables
188 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->YearVariableNum).Value = SetErlValueNumber(double(state.dataEnvrn->Year));
189 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CalendarYearVariableNum).Value =
190 2934932 : SetErlValueNumber(double(state.dataGlobal->CalendarYear));
191 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->MonthVariableNum).Value = SetErlValueNumber(double(state.dataEnvrn->Month));
192 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfMonthVariableNum).Value =
193 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfMonth));
194 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfWeekVariableNum).Value =
195 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfWeek));
196 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfYearVariableNum).Value =
197 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfYear));
198 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->TimeStepNumVariableNum).Value =
199 2934932 : SetErlValueNumber(double(state.dataGlobal->TimeStep));
200 :
201 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DSTVariableNum).Value =
202 2934932 : SetErlValueNumber(double(state.dataEnvrn->DSTIndicator));
203 : // DSTadjust = REAL(DSTIndicator, r64)
204 1467466 : tmpHours = double(state.dataGlobal->HourOfDay - 1); // no, just stay on 0..23+ DSTadjust ! offset by 1 and daylight savings time
205 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HourVariableNum).Value = SetErlValueNumber(tmpHours);
206 :
207 1467466 : if (TimeStepSys < state.dataGlobal->TimeStepZone) {
208 : // CurrentTime is for end of zone timestep, need to account for system timestep
209 102784 : tmpCurrentTime = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed + TimeStepSys;
210 : } else {
211 1364682 : tmpCurrentTime = state.dataGlobal->CurrentTime;
212 : }
213 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CurrentTimeVariableNum).Value = SetErlValueNumber(tmpCurrentTime);
214 1467466 : tmpMinutes = ((tmpCurrentTime - double(state.dataGlobal->HourOfDay - 1)) * 60.0); // -1.0 // off by 1
215 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->MinuteVariableNum).Value = SetErlValueNumber(tmpMinutes);
216 : // Subtract 7 from HolidayIndex to maintain compatability for EMS where 1=Holiday,2=SummerDesignDay, 3=WinterDesignDay, 4=CustomDay1,
217 : // 5=CustomDay2, but not <0
218 1467466 : if (state.dataEnvrn->HolidayIndex == 0) {
219 635 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HolidayVariableNum).Value = SetErlValueNumber(0.0);
220 : } else {
221 1466831 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HolidayVariableNum).Value =
222 2933662 : SetErlValueNumber(double(state.dataEnvrn->HolidayIndex - 7));
223 : }
224 1467466 : if (state.dataEnvrn->SunIsUp) {
225 706926 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SunIsUpVariableNum).Value = SetErlValueNumber(1.0);
226 : } else {
227 760540 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SunIsUpVariableNum).Value = SetErlValueNumber(0.0);
228 : }
229 1467466 : if (state.dataEnvrn->IsRain) {
230 0 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->IsRainingVariableNum).Value = SetErlValueNumber(1.0);
231 : } else {
232 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->IsRainingVariableNum).Value = SetErlValueNumber(0.0);
233 : }
234 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SystemTimeStepVariableNum).Value = SetErlValueNumber(TimeStepSys);
235 :
236 1467466 : tmpCurEnvirNum = double(state.dataEnvrn->CurEnvirNum);
237 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CurrentEnvironmentPeriodNum).Value = SetErlValueNumber(tmpCurEnvirNum);
238 1467466 : if (state.dataGlobal->WarmupFlag) {
239 1338648 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->WarmUpFlagNum).Value = SetErlValueNumber(1.0);
240 : } else {
241 128818 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->WarmUpFlagNum).Value = SetErlValueNumber(0.0);
242 : }
243 1467466 : }
244 :
245 90 : void BeginEnvrnInitializeRuntimeLanguage(EnergyPlusData &state)
246 : {
247 :
248 : // SUBROUTINE INFORMATION:
249 : // AUTHOR B. Griffith
250 : // DATE WRITTEN March 2010
251 : // MODIFIED B. Griffith, added Sensor initialation
252 : // RE-ENGINEERED na
253 :
254 : // PURPOSE OF THIS SUBROUTINE:
255 : // re initialize Erl for new simulation environment period
256 :
257 : // METHODOLOGY EMPLOYED:
258 : // na
259 :
260 : // REFERENCES:
261 : // na
262 :
263 : // Using/Aliasing
264 : using OutputProcessor::SetInternalVariableValue;
265 :
266 : // Locals
267 : // SUBROUTINE ARGUMENT DEFINITIONS:
268 : // na
269 :
270 : // SUBROUTINE PARAMETER DEFINITIONS:
271 : // na
272 :
273 : // INTERFACE BLOCK SPECIFICATIONS:
274 : // na
275 :
276 : // DERIVED TYPE DEFINITIONS:
277 : // na
278 :
279 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
280 : int ActuatorUsedLoop;
281 : int EMSActuatorVariableNum;
282 : int ErlVariableNum;
283 : int TrendVarNum;
284 : int SensorNum;
285 : int TrendDepth;
286 : int loop;
287 : bool CycleThisVariable;
288 :
289 : // reinitialize state of Erl variable values to zero, this gets sensors and internal variables used
290 3093 : for (ErlVariableNum = 1; ErlVariableNum <= state.dataRuntimeLang->NumErlVariables; ++ErlVariableNum) {
291 : // but skip constant built-in variables so don't overwrite them
292 3003 : if (ErlVariableNum == state.dataRuntimeLangProcessor->NullVariableNum) {
293 90 : continue;
294 : }
295 2913 : if (ErlVariableNum == state.dataRuntimeLangProcessor->FalseVariableNum) {
296 90 : continue;
297 : }
298 2823 : if (ErlVariableNum == state.dataRuntimeLangProcessor->TrueVariableNum) {
299 90 : continue;
300 : }
301 2733 : if (ErlVariableNum == state.dataRuntimeLangProcessor->OffVariableNum) {
302 90 : continue;
303 : }
304 2643 : if (ErlVariableNum == state.dataRuntimeLangProcessor->OnVariableNum) {
305 90 : continue;
306 : }
307 2553 : if (ErlVariableNum == state.dataRuntimeLangProcessor->PiVariableNum) {
308 90 : continue;
309 : }
310 2463 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum) {
311 90 : continue;
312 : }
313 2373 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ActualDateAndTimeNum) {
314 90 : continue;
315 : }
316 2283 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ActualTimeNum) {
317 90 : continue;
318 : }
319 :
320 : // need to preserve curve index variables
321 2193 : CycleThisVariable = false;
322 4593 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSCurveIndices; ++loop) {
323 2400 : if (ErlVariableNum == state.dataRuntimeLangProcessor->CurveIndexVariableNums(loop)) {
324 15 : CycleThisVariable = true;
325 : }
326 : }
327 2193 : if (CycleThisVariable) {
328 15 : continue;
329 : }
330 2178 : CycleThisVariable = false;
331 2346 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSConstructionIndices; ++loop) {
332 168 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ConstructionIndexVariableNums(loop)) {
333 8 : CycleThisVariable = true;
334 : }
335 : }
336 2178 : if (CycleThisVariable) {
337 8 : continue;
338 : }
339 :
340 2170 : if (state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value.initialized) {
341 2057 : state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value =
342 4114 : SetErlValueNumber(0.0, state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
343 : }
344 : }
345 : // reinitialize state of actuators
346 160 : for (ActuatorUsedLoop = 1; ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed;
347 : ++ActuatorUsedLoop) {
348 70 : EMSActuatorVariableNum = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ActuatorVariableNum;
349 70 : ErlVariableNum = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ErlVariableNum;
350 70 : state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value.Type = Value::Null;
351 70 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).Actuated = false;
352 70 : switch (state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).PntrVarTypeUsed) {
353 66 : case PtrDataType::Real:
354 66 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).RealValue = 0.0;
355 66 : break;
356 4 : case PtrDataType::Integer:
357 4 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).IntValue = 0;
358 4 : break;
359 0 : case PtrDataType::Logical:
360 0 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).LogValue = false;
361 0 : break;
362 0 : default:
363 0 : break; // nothing to do for those
364 : }
365 : }
366 :
367 : // reinitialize trend variables so old data are purged
368 91 : for (TrendVarNum = 1; TrendVarNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendVarNum) {
369 1 : TrendDepth = state.dataRuntimeLang->TrendVariable(TrendVarNum).LogDepth;
370 1 : state.dataRuntimeLang->TrendVariable(TrendVarNum).TrendValARR({1, TrendDepth}) = 0.0;
371 : }
372 :
373 : // reinitilize sensors
374 113 : for (SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
375 46 : SetInternalVariableValue(
376 23 : state, state.dataRuntimeLang->Sensor(SensorNum).VariableType, state.dataRuntimeLang->Sensor(SensorNum).Index, 0.0, 0);
377 : }
378 90 : }
379 :
380 37 : void ParseStack(EnergyPlusData &state, int const StackNum)
381 : {
382 :
383 : // SUBROUTINE INFORMATION:
384 : // AUTHOR Peter Graham Ellis
385 : // DATE WRITTEN June 2006
386 : // MODIFIED Brent Griffith June 2009
387 : // Brent Griffith March 2012, add WHILE loops
388 : // RE-ENGINEERED na
389 :
390 : // PURPOSE OF THIS SUBROUTINE:
391 : // Parsing a block of text creates a program stack in DataRuntimeLanguage.
392 : // This routine only executes once for each Erl program.
393 :
394 : // METHODOLOGY EMPLOYED:
395 : // Loop over each line of Erl code and parse based on statement keyword
396 :
397 : // Using/Aliasing
398 :
399 : // Locals
400 : // SUBROUTINE ARGUMENT DEFINITIONS:
401 :
402 : // SUBROUTINE PARAMETER DEFINITIONS:
403 37 : int constexpr IfDepthAllowed(5); // depth of IF block nesting
404 37 : int constexpr ELSEIFLengthAllowed(200); // number of ELSEIFs allowed
405 37 : int constexpr WhileDepthAllowed(1); // depth of While block nesting
406 :
407 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
408 : int LineNum;
409 : int StackNum2;
410 : std::string::size_type Pos;
411 : int ExpressionNum;
412 : int VariableNum;
413 37 : std::string Line; // local copy of a single line of Erl program code
414 37 : std::string Keyword; // local copy of statement keyword parsed from line (Run, Set, If, etc)
415 37 : std::string Remainder; // local copy of what is left for text in the line after keyword
416 37 : std::string Expression;
417 37 : std::string Variable;
418 : int NestedIfDepth; // indicates depth into If statement,
419 : int NestedWhileDepth; // indicates depth into While statement
420 : int InstructionNum;
421 : int InstructionNum2;
422 : int GotoNum;
423 37 : Array1D_int SavedIfInstructionNum(IfDepthAllowed); // index is depth of If statements
424 37 : Array2D_int SavedGotoInstructionNum(ELSEIFLengthAllowed, IfDepthAllowed);
425 37 : Array1D_int NumGotos(IfDepthAllowed); // index is depth of If statements,
426 : int SavedWhileInstructionNum;
427 : int SavedWhileExpressionNum;
428 : int NumWhileGotos;
429 37 : Array1D_bool ReadyForElse(IfDepthAllowed);
430 37 : Array1D_bool ReadyForEndif(IfDepthAllowed);
431 :
432 37 : LineNum = 1;
433 37 : NestedIfDepth = 0;
434 37 : ReadyForElse = false;
435 37 : ReadyForEndif = false;
436 37 : SavedIfInstructionNum = 0;
437 37 : SavedGotoInstructionNum = 0;
438 37 : NumGotos = 0;
439 37 : NestedWhileDepth = 0;
440 37 : SavedWhileInstructionNum = 0;
441 37 : SavedWhileExpressionNum = 0;
442 37 : NumWhileGotos = 0;
443 :
444 37 : auto &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
445 :
446 451 : while (LineNum <= thisErlStack.NumLines) {
447 :
448 414 : Line = stripped(thisErlStack.Line(LineNum));
449 414 : if (len(Line) == 0) {
450 0 : ++LineNum;
451 0 : continue; // Blank lines can be skipped
452 : }
453 :
454 414 : Pos = scan(Line, ' ');
455 414 : if (Pos == std::string::npos) {
456 48 : Pos = len(Line);
457 48 : Remainder.clear();
458 : } else {
459 366 : Remainder = stripped(Line.substr(Pos + 1));
460 : }
461 : // Keyword = Util::makeUPPER(Line(1:Pos-1))
462 414 : Keyword = Line.substr(0, Pos);
463 :
464 : // the functionality in each block of this parser structure is so different that a regular IF block seems reasonable
465 414 : if (Keyword == "RETURN") {
466 1 : if (state.dataSysVars->DeveloperFlag) {
467 0 : print(state.files.debug, "RETURN \"{}\"\n", Line);
468 : }
469 1 : if (Remainder.empty()) {
470 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, RuntimeLanguageProcessor::ErlKeywordParam::Return);
471 : } else {
472 0 : ParseExpression(state, Remainder, StackNum, ExpressionNum, Line);
473 0 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Return, ExpressionNum);
474 : }
475 :
476 413 : } else if (Keyword == "SET") {
477 333 : if (state.dataSysVars->DeveloperFlag) {
478 0 : print(state.files.debug, "SET \"{}\"\n", Line);
479 : }
480 333 : Pos = scan(Remainder, '=');
481 333 : if (Pos == std::string::npos) {
482 0 : AddError(state, StackNum, LineNum, "Equal sign missing for the SET instruction.");
483 333 : } else if (Pos == 0) {
484 0 : AddError(state, StackNum, LineNum, "Variable name missing for the SET instruction.");
485 : } else {
486 333 : Variable = stripped(Remainder.substr(0, Pos)); // VariableName would be more expressive
487 333 : VariableNum = NewEMSVariable(state, Variable, StackNum);
488 : // Check for invalid variable name
489 :
490 333 : if (Pos + 1 < Remainder.length()) {
491 333 : Expression = stripped(Remainder.substr(Pos + 1));
492 : } else {
493 0 : Expression.clear();
494 : }
495 333 : if (Expression.empty()) {
496 0 : AddError(state, StackNum, LineNum, "Expression missing for the SET instruction.");
497 : } else {
498 333 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
499 333 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Set, VariableNum, ExpressionNum);
500 : }
501 : }
502 :
503 80 : } else if (Keyword == "RUN") {
504 1 : if (state.dataSysVars->DeveloperFlag) {
505 0 : print(state.files.debug, "RUN \"{}\"\n", Line);
506 : }
507 1 : if (Remainder.empty()) {
508 0 : AddError(state, StackNum, LineNum, "Program or Subroutine name missing for the RUN instruction.");
509 : } else {
510 1 : Pos = scan(Remainder, ' ');
511 1 : if (Pos == std::string::npos) {
512 1 : Pos = Remainder.length();
513 : }
514 1 : Variable = Util::makeUPPER(stripped(Remainder.substr(0, Pos))); // really the subroutine, or reference to instruction set
515 1 : StackNum2 = Util::FindItemInList(Variable, state.dataRuntimeLang->ErlStack);
516 1 : if (StackNum2 == 0) {
517 0 : AddError(state, StackNum, LineNum, "Program or Subroutine name [" + Variable + "] not found for the RUN instruction.");
518 : } else {
519 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Run, StackNum2);
520 : }
521 : }
522 :
523 79 : } else if (Keyword == "IF") {
524 26 : if (state.dataSysVars->DeveloperFlag) {
525 0 : print(state.files.debug, "IF \"{}\"\n", Line);
526 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
527 : }
528 26 : if (Remainder.empty()) {
529 0 : AddError(state, StackNum, LineNum, "Expression missing for the IF instruction.");
530 0 : ExpressionNum = 0;
531 : } else {
532 26 : Expression = stripped(Remainder);
533 26 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
534 : }
535 :
536 26 : ++NestedIfDepth;
537 26 : ReadyForElse(NestedIfDepth) = true;
538 26 : ReadyForEndif(NestedIfDepth) = true;
539 26 : if (NestedIfDepth > IfDepthAllowed) {
540 0 : AddError(state, StackNum, LineNum, "Detected IF nested deeper than is allowed; need to terminate an earlier IF instruction.");
541 0 : break;
542 : } else {
543 26 : InstructionNum = AddInstruction(state,
544 : StackNum,
545 : LineNum,
546 : DataRuntimeLanguage::ErlKeywordParam::If,
547 : ExpressionNum); // Arg2 added at next ELSEIF, ELSE, ENDIF
548 26 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
549 : }
550 :
551 53 : } else if (Keyword == "ELSEIF") {
552 5 : if (state.dataSysVars->DeveloperFlag) {
553 0 : print(state.files.debug, "ELSEIF \"{}\"\n", Line);
554 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
555 : }
556 5 : if (NestedIfDepth == 0) {
557 0 : AddError(state, StackNum, LineNum, "Starting IF instruction missing for the ELSEIF instruction.");
558 0 : break; // Getting strange error on DEALLOCATE for the next instruction that I try to add, so doing EXIT here
559 : }
560 :
561 : // Complete the preceding block with a GOTO instruction
562 5 : InstructionNum = AddInstruction(state, StackNum, 0, DataRuntimeLanguage::ErlKeywordParam::Goto); // Arg2 is added at the ENDIF
563 5 : ++NumGotos(NestedIfDepth);
564 5 : if (NumGotos(NestedIfDepth) > ELSEIFLengthAllowed) {
565 0 : AddError(state, StackNum, LineNum, "Detected ELSEIF series that is longer than allowed; terminate earlier IF instruction.");
566 0 : break;
567 : } else {
568 5 : SavedGotoInstructionNum(NumGotos(NestedIfDepth), NestedIfDepth) = InstructionNum;
569 : }
570 :
571 5 : if (Remainder.empty()) {
572 0 : AddError(state, StackNum, LineNum, "Expression missing for the ELSEIF instruction.");
573 0 : ExpressionNum = 0;
574 : } else {
575 5 : Expression = stripped(Remainder);
576 5 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
577 : }
578 :
579 5 : InstructionNum = AddInstruction(state,
580 : StackNum,
581 : LineNum,
582 : DataRuntimeLanguage::ErlKeywordParam::If,
583 : ExpressionNum); // Arg2 added at next ELSEIF, ELSE, ENDIF
584 5 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
585 5 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
586 :
587 48 : } else if (Keyword == "ELSE") {
588 20 : if (state.dataSysVars->DeveloperFlag) {
589 0 : print(state.files.debug, "ELSE \"{}\"\n", Line);
590 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
591 : }
592 20 : if (NestedIfDepth == 0) {
593 0 : AddError(state, StackNum, LineNum, "Starting IF instruction missing for the ELSE instruction.");
594 0 : break; // Getting strange error on DEALLOCATE for the next instruction that I try to add, so doing EXIT here
595 : }
596 20 : if (!ReadyForElse(NestedIfDepth)) {
597 0 : AddError(state, StackNum, LineNum, "ELSE statement without corresponding IF statement.");
598 : }
599 20 : ReadyForElse(NestedIfDepth) = false;
600 :
601 : // Complete the preceding block with a GOTO instruction
602 20 : InstructionNum = AddInstruction(state, StackNum, 0, DataRuntimeLanguage::ErlKeywordParam::Goto); // Arg2 is added at the ENDIF
603 20 : ++NumGotos(NestedIfDepth);
604 20 : if (NumGotos(NestedIfDepth) > ELSEIFLengthAllowed) {
605 0 : AddError(state, StackNum, LineNum, "Detected ELSEIF-ELSE series that is longer than allowed.");
606 0 : break;
607 : } else {
608 20 : SavedGotoInstructionNum(NumGotos(NestedIfDepth), NestedIfDepth) = InstructionNum;
609 : }
610 :
611 20 : if (!Remainder.empty()) {
612 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ELSE instruction.");
613 : }
614 :
615 20 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Else); // can make this into a KeywordIf?
616 20 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
617 20 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
618 :
619 28 : } else if (Keyword == "ENDIF") {
620 26 : if (state.dataSysVars->DeveloperFlag) {
621 0 : print(state.files.debug, "ENDIF \"{}\"\n", Line);
622 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
623 : }
624 26 : if (NestedIfDepth == 0) {
625 0 : AddError(state, StackNum, LineNum, "Starting IF instruction missing for the ENDIF instruction.");
626 0 : break; // PE Getting strange error on DEALLOCATE for the next instruction that I try to add, so doing EXIT here
627 : }
628 :
629 26 : if (!ReadyForEndif(NestedIfDepth)) {
630 0 : AddError(state, StackNum, LineNum, "ENDIF statement without corresponding IF stetement.");
631 : }
632 26 : ReadyForEndif(NestedIfDepth) = false;
633 26 : ReadyForElse(NestedIfDepth) = false;
634 :
635 26 : if (!Remainder.empty()) {
636 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ENDIF instruction.");
637 : }
638 :
639 26 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::EndIf);
640 26 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
641 :
642 : // Go back and complete all of the GOTOs that terminate each IF and ELSEIF block
643 51 : for (GotoNum = 1; GotoNum <= NumGotos(NestedIfDepth); ++GotoNum) {
644 25 : InstructionNum2 = SavedGotoInstructionNum(GotoNum, NestedIfDepth);
645 25 : thisErlStack.Instruction(InstructionNum2).Argument1 = InstructionNum;
646 25 : SavedGotoInstructionNum(GotoNum, NestedIfDepth) = 0;
647 : }
648 :
649 26 : NumGotos(NestedIfDepth) = 0;
650 26 : SavedIfInstructionNum(NestedIfDepth) = 0;
651 26 : --NestedIfDepth;
652 :
653 2 : } else if (Keyword == "WHILE") {
654 1 : if (state.dataSysVars->DeveloperFlag) {
655 0 : print(state.files.debug, "WHILE \"{}\"\n", Line);
656 : }
657 1 : if (Remainder.empty()) {
658 0 : AddError(state, StackNum, LineNum, "Expression missing for the WHILE instruction.");
659 0 : ExpressionNum = 0;
660 : } else {
661 1 : Expression = stripped(Remainder);
662 1 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
663 : }
664 :
665 1 : ++NestedWhileDepth;
666 1 : if (NestedWhileDepth > WhileDepthAllowed) {
667 0 : AddError(state, StackNum, LineNum, "Detected WHILE nested deeper than is allowed; need to terminate an earlier WHILE instruction.");
668 0 : break;
669 : } else {
670 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::While, ExpressionNum);
671 1 : SavedWhileInstructionNum = InstructionNum;
672 1 : SavedWhileExpressionNum = ExpressionNum;
673 : }
674 :
675 1 : } else if (Keyword == "ENDWHILE") {
676 1 : if (state.dataSysVars->DeveloperFlag) {
677 0 : print(state.files.debug, "ENDWHILE \"{}\"\n", Line);
678 : }
679 1 : if (NestedWhileDepth == 0) {
680 0 : AddError(state, StackNum, LineNum, "Starting WHILE instruction missing for the ENDWHILE instruction.");
681 0 : break;
682 : }
683 1 : if (!Remainder.empty()) {
684 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ENDWHILE instruction.");
685 : }
686 :
687 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::EndWhile);
688 1 : thisErlStack.Instruction(SavedWhileInstructionNum).Argument2 = InstructionNum;
689 1 : thisErlStack.Instruction(InstructionNum).Argument1 = SavedWhileExpressionNum;
690 1 : thisErlStack.Instruction(InstructionNum).Argument2 = SavedWhileInstructionNum;
691 :
692 1 : NestedWhileDepth = 0;
693 1 : SavedWhileInstructionNum = 0;
694 1 : SavedWhileExpressionNum = 0;
695 :
696 : } else {
697 0 : if (state.dataSysVars->DeveloperFlag) {
698 0 : print(state.files.debug, "ERROR \"{}\"\n", Line);
699 : }
700 0 : AddError(state, StackNum, LineNum, "Unknown keyword [" + Keyword + "].");
701 : }
702 :
703 414 : ++LineNum;
704 : } // LineNum
705 :
706 37 : if (NestedIfDepth == 1) {
707 0 : AddError(state, StackNum, 0, "Missing an ENDIF instruction needed to terminate an earlier IF instruction.");
708 37 : } else if (NestedIfDepth > 1) {
709 0 : AddError(state, StackNum, 0, format("Missing {} ENDIF instructions needed to terminate earlier IF instructions.", NestedIfDepth));
710 : }
711 :
712 : // ALLOCATE(DummyError(ErlStack(StackNum)%NumErrors))
713 : // DummyError = ErlStack(StackNum)%Error
714 37 : }
715 :
716 439 : int AddInstruction(EnergyPlusData &state,
717 : int const StackNum,
718 : int const LineNum,
719 : DataRuntimeLanguage::ErlKeywordParam Keyword,
720 : ObjexxFCL::Optional_int_const Argument1, // Erl variable index
721 : ObjexxFCL::Optional_int_const Argument2)
722 : {
723 :
724 : // SUBROUTINE INFORMATION:
725 : // AUTHOR Peter Graham Ellis
726 : // DATE WRITTEN June 2006
727 : // MODIFIED na
728 : // RE-ENGINEERED na
729 :
730 : // PURPOSE OF THIS SUBROUTINE:
731 : // Adds an instruction to a stack.
732 :
733 : // METHODOLOGY EMPLOYED:
734 :
735 : // Return value
736 : int InstructionNum;
737 :
738 : // Locals
739 : // SUBROUTINE ARGUMENT DEFINITIONS:
740 :
741 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
742 :
743 : // Object Data
744 439 : ErlStackType TempStack;
745 :
746 439 : auto &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
747 :
748 439 : if (thisErlStack.NumInstructions == 0) {
749 37 : thisErlStack.Instruction.allocate(1);
750 37 : thisErlStack.NumInstructions = 1;
751 : } else {
752 402 : TempStack = thisErlStack;
753 402 : thisErlStack.Instruction.deallocate();
754 402 : thisErlStack.Instruction.allocate(thisErlStack.NumInstructions + 1);
755 402 : thisErlStack.Instruction({1, thisErlStack.NumInstructions}) = TempStack.Instruction({1, thisErlStack.NumInstructions});
756 402 : ++thisErlStack.NumInstructions;
757 : }
758 :
759 439 : InstructionNum = thisErlStack.NumInstructions;
760 439 : thisErlStack.Instruction(InstructionNum).LineNum = LineNum;
761 439 : thisErlStack.Instruction(InstructionNum).Keyword = Keyword;
762 :
763 439 : if (present(Argument1)) {
764 366 : thisErlStack.Instruction(InstructionNum).Argument1 = Argument1;
765 : }
766 439 : if (present(Argument2)) {
767 333 : thisErlStack.Instruction(InstructionNum).Argument2 = Argument2;
768 : }
769 :
770 439 : return InstructionNum;
771 439 : }
772 :
773 0 : void AddError(EnergyPlusData &state,
774 : int const StackNum, // index pointer to location in ErlStack structure
775 : int const LineNum, // Erl program line number
776 : std::string const &Error // error message to be added to ErlStack
777 : )
778 : {
779 :
780 : // SUBROUTINE INFORMATION:
781 : // AUTHOR Peter Graham Ellis
782 : // DATE WRITTEN June 2006
783 : // MODIFIED na
784 : // RE-ENGINEERED na
785 :
786 : // PURPOSE OF THIS SUBROUTINE:
787 : // Adds an error message to a stack.
788 :
789 : // METHODOLOGY EMPLOYED:
790 :
791 : // Locals
792 : // SUBROUTINE ARGUMENT DEFINITIONS:
793 :
794 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
795 : int ErrorNum; // local count of errors for this ErlStack
796 :
797 : // Object Data
798 0 : ErlStackType TempStack; // temporary copy of single ErlStack
799 :
800 0 : auto &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
801 0 : if (thisErlStack.NumErrors == 0) {
802 0 : thisErlStack.Error.allocate(1);
803 0 : thisErlStack.NumErrors = 1;
804 : } else {
805 0 : TempStack = thisErlStack;
806 0 : thisErlStack.Error.deallocate();
807 0 : thisErlStack.Error.allocate(thisErlStack.NumErrors + 1);
808 0 : thisErlStack.Error({1, thisErlStack.NumErrors}) = TempStack.Error({1, thisErlStack.NumErrors});
809 0 : ++thisErlStack.NumErrors;
810 : }
811 :
812 0 : ErrorNum = thisErlStack.NumErrors;
813 0 : if (LineNum > 0) {
814 0 : thisErlStack.Error(ErrorNum) = format("Line {}: {} \"{}\"", LineNum, Error, thisErlStack.Line(LineNum));
815 : } else {
816 0 : thisErlStack.Error(ErrorNum) = Error;
817 : }
818 0 : }
819 :
820 27370 : ErlValueType EvaluateStack(EnergyPlusData &state, int const StackNum)
821 : {
822 :
823 : // SUBROUTINE INFORMATION:
824 : // AUTHOR Peter Graham Ellis
825 : // DATE WRITTEN June 2006
826 : // MODIFIED Brent Griffith, May 2009
827 : // Brent Griffith, March 2012, add While loop support
828 : // RE-ENGINEERED na
829 :
830 : // PURPOSE OF THIS SUBROUTINE:
831 : // Runs a stack with the interpreter.
832 :
833 : // Return value
834 27370 : ErlValueType ReturnValue;
835 :
836 : // Locals
837 : // SUBROUTINE ARGUMENT DEFINITIONS:
838 :
839 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
840 : int InstructionNum;
841 : int InstructionNum2;
842 : int ExpressionNum;
843 : int ESVariableNum;
844 : int WhileLoopExitCounter; // to avoid infinite loop in While loop
845 27370 : bool seriousErrorFound(false); // once it gets set true (inside EvaluateExpresssion) it will trigger a fatal (in WriteTrace)
846 :
847 27370 : WhileLoopExitCounter = 0;
848 27370 : ReturnValue.Type = Value::Number;
849 27370 : ReturnValue.Number = 0.0;
850 :
851 27370 : auto const &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
852 :
853 27370 : InstructionNum = 1;
854 834244 : while (InstructionNum <= thisErlStack.NumInstructions) {
855 :
856 810998 : auto const &thisInstruction = thisErlStack.Instruction(InstructionNum);
857 :
858 : {
859 810998 : DataRuntimeLanguage::ErlKeywordParam const SELECT_CASE_var = thisInstruction.Keyword;
860 :
861 810998 : if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::None) {
862 : // There probably shouldn't be any of these
863 :
864 810998 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Return) {
865 4124 : if (thisInstruction.Argument1 > 0) {
866 0 : ReturnValue = EvaluateExpression(state, thisInstruction.Argument1, seriousErrorFound);
867 : }
868 4124 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
869 4124 : break; // RETURN always terminates an instruction stack
870 :
871 806874 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Set) {
872 :
873 610835 : ESVariableNum = thisInstruction.Argument1;
874 610835 : auto &thisErlVar = state.dataRuntimeLang->ErlVariable(ESVariableNum);
875 610835 : ReturnValue = EvaluateExpression(state, thisInstruction.Argument2, seriousErrorFound);
876 610835 : if ((!thisErlVar.ReadOnly) && (!thisErlVar.Value.TrendVariable)) {
877 : // #10279 - We don't do `thisErlVar.Value = ReturnValue;` because we don't want to copy TrendVariable stuff
878 610831 : thisErlVar.Value.Type = ReturnValue.Type;
879 610831 : thisErlVar.Value.Number = ReturnValue.Number;
880 : // thisErlVar.Value.String = ReturnValue.String;
881 610831 : thisErlVar.Value.Error = ReturnValue.Error;
882 610831 : thisErlVar.Value.initialized = ReturnValue.initialized;
883 4 : } else if (thisErlVar.Value.TrendVariable) {
884 4 : thisErlVar.Value.Number = ReturnValue.Number;
885 4 : thisErlVar.Value.Error = ReturnValue.Error;
886 : }
887 :
888 610835 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
889 :
890 196039 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Run) {
891 2 : ReturnValue.Type = Value::String;
892 2 : ReturnValue.String = "";
893 2 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
894 2 : ReturnValue = EvaluateStack(state, thisInstruction.Argument1);
895 196037 : } else if ((SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::If) ||
896 : (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Else)) { // same???
897 74518 : ExpressionNum = thisInstruction.Argument1;
898 74518 : InstructionNum2 = thisInstruction.Argument2;
899 74518 : if (ExpressionNum > 0) { // could be 0 if this was an ELSE
900 72197 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
901 72197 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
902 72197 : if (ReturnValue.Number == 0.0) { // This is the FALSE case
903 : // Eventually should handle strings and arrays too
904 31215 : InstructionNum = InstructionNum2;
905 31215 : continue;
906 : }
907 : } else {
908 : // KeywordELSE -- kind of a kludge
909 2321 : ReturnValue.Type = Value::Number;
910 2321 : ReturnValue.Number = 1.0;
911 2321 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
912 : }
913 121519 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Goto) {
914 20132 : InstructionNum = thisInstruction.Argument1;
915 :
916 : // For debug purposes only...
917 20132 : ReturnValue.Type = Value::String;
918 20132 : ReturnValue.String = ""; // IntegerToString(InstructionNum)
919 :
920 20132 : continue;
921 : // PE if this ever went out of bounds, would the DO loop save it? or need check here?
922 :
923 101387 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::EndIf) {
924 68055 : ReturnValue.Type = Value::String;
925 68055 : ReturnValue.String = "";
926 68055 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
927 :
928 33332 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::While) {
929 : // evaluate expression at while, skip to past endwhile if not true
930 16666 : ExpressionNum = thisInstruction.Argument1;
931 16666 : InstructionNum2 = thisInstruction.Argument2;
932 16666 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
933 16666 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
934 16666 : if (ReturnValue.Number == 0.0) { // This is the FALSE case
935 : // Eventually should handle strings and arrays too
936 0 : InstructionNum = InstructionNum2;
937 : // CYCLE
938 : }
939 16666 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::EndWhile) {
940 :
941 : // reevaluate expression at While and goto there if true, otherwise continue
942 16666 : ExpressionNum = thisInstruction.Argument1;
943 16666 : InstructionNum2 = thisInstruction.Argument2;
944 16666 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
945 16666 : if ((ReturnValue.Number != 0.0) && (WhileLoopExitCounter <= MaxWhileLoopIterations)) { // This is the True case
946 : // Eventually should handle strings and arrays too
947 12596 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound); // duplicative?
948 12596 : InstructionNum = InstructionNum2;
949 12596 : ++WhileLoopExitCounter;
950 :
951 12596 : continue;
952 : } else { // false, leave while block
953 4070 : if (WhileLoopExitCounter > MaxWhileLoopIterations) {
954 0 : WhileLoopExitCounter = 0;
955 0 : ReturnValue.Type = Value::Error;
956 0 : ReturnValue.Error = "Maximum WHILE loop iteration limit reached";
957 0 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
958 : } else {
959 4070 : ReturnValue.Type = Value::Number;
960 4070 : ReturnValue.Number = 0.0;
961 4070 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
962 4070 : WhileLoopExitCounter = 0;
963 : }
964 : }
965 : } else {
966 0 : ShowFatalError(state, "Fatal error in RunStack: Unknown keyword.");
967 : }
968 : }
969 :
970 742931 : ++InstructionNum;
971 : } // InstructionNum
972 :
973 54740 : return ReturnValue;
974 0 : }
975 :
976 790866 : void WriteTrace(EnergyPlusData &state, int const StackNum, int const InstructionNum, ErlValueType const &ReturnValue, bool const seriousErrorFound)
977 : {
978 :
979 : // SUBROUTINE INFORMATION:
980 : // AUTHOR Peter Graham Ellis
981 : // DATE WRITTEN June 2006
982 : // MODIFIED Brent Griffith, May 2009
983 : // Brent Griffith, May 2016, added bool and fatal error messages for runtime problems with math and unitialized vars
984 : // RE-ENGINEERED na
985 :
986 : // PURPOSE OF THIS SUBROUTINE:
987 :
988 : // METHODOLOGY EMPLOYED:
989 :
990 : // Using/Aliasing
991 : using General::CreateSysTimeIntervalString;
992 :
993 : // Locals
994 : // SUBROUTINE ARGUMENT DEFINITIONS:
995 :
996 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
997 : int LineNum;
998 790866 : std::string NameString;
999 790866 : std::string LineNumString;
1000 790866 : std::string LineString;
1001 790866 : std::string cValueString;
1002 790866 : std::string TimeString;
1003 790866 : std::string DuringWarmup;
1004 :
1005 790866 : if ((!state.dataRuntimeLang->OutputFullEMSTrace) && (!state.dataRuntimeLang->OutputEMSErrors) && (!seriousErrorFound)) {
1006 7445 : return;
1007 : }
1008 :
1009 783421 : if ((state.dataRuntimeLang->OutputEMSErrors) && (!state.dataRuntimeLang->OutputFullEMSTrace) && (!seriousErrorFound)) {
1010 : // see if error needs to be reported.
1011 783414 : if (ReturnValue.Type != Value::Error) {
1012 783414 : return;
1013 : }
1014 : }
1015 :
1016 7 : if (!state.dataRuntimeLangProcessor->WriteTraceMyOneTimeFlag) {
1017 3 : print(state.files.edd, "**** Begin EMS Language Processor Error and Trace Output *** \n");
1018 3 : print(state.files.edd, "<Erl program name, line #, line text, result, occurrence timing information ... >\n");
1019 3 : state.dataRuntimeLangProcessor->WriteTraceMyOneTimeFlag = true;
1020 : }
1021 : // if have not return'd yet then write out full trace
1022 :
1023 7 : NameString = state.dataRuntimeLang->ErlStack(StackNum).Name;
1024 7 : LineNum = state.dataRuntimeLang->ErlStack(StackNum).Instruction(InstructionNum).LineNum;
1025 7 : LineNumString = fmt::to_string(LineNum);
1026 7 : LineString = state.dataRuntimeLang->ErlStack(StackNum).Line(LineNum);
1027 7 : cValueString = ValueToString(ReturnValue);
1028 :
1029 : // put together timestamp info
1030 7 : if (state.dataGlobal->WarmupFlag) {
1031 0 : if (!state.dataGlobal->DoingSizing) {
1032 0 : DuringWarmup = " During Warmup, Occurrence info=";
1033 : } else {
1034 0 : DuringWarmup = " During Warmup & Sizing, Occurrence info=";
1035 : }
1036 : } else {
1037 7 : if (!state.dataGlobal->DoingSizing) {
1038 7 : DuringWarmup = " Occurrence info=";
1039 : } else {
1040 0 : DuringWarmup = " During Sizing, Occurrence info=";
1041 : }
1042 : }
1043 7 : TimeString = DuringWarmup + state.dataEnvrn->EnvironmentName + ", " + state.dataEnvrn->CurMnDy + ' ' + CreateSysTimeIntervalString(state);
1044 :
1045 7 : if (state.dataRuntimeLang->OutputFullEMSTrace || (state.dataRuntimeLang->OutputEMSErrors && (ReturnValue.Type == Value::Error))) {
1046 7 : print(state.files.edd, "{},Line {},{},{},{}\n", NameString, LineNumString, LineString, cValueString, TimeString);
1047 : }
1048 :
1049 7 : if (seriousErrorFound) { // throw EnergyPlus severe then fatal
1050 0 : ShowSevereError(state, "Problem found in EMS EnergyPlus Runtime Language.");
1051 0 : ShowContinueError(state, format("Erl program name: {}", NameString));
1052 0 : ShowContinueError(state, format("Erl program line number: {}", LineNumString));
1053 0 : ShowContinueError(state, format("Erl program line text: {}", LineString));
1054 0 : ShowContinueError(state, format("Error message: {}", cValueString));
1055 0 : ShowContinueErrorTimeStamp(state, "");
1056 0 : ShowFatalError(state, "Previous EMS error caused program termination.");
1057 : }
1058 4745161 : }
1059 :
1060 : //******************************************************************************************
1061 :
1062 : // Expression Processor
1063 :
1064 : //******************************************************************************************
1065 :
1066 365 : void ParseExpression(EnergyPlusData &state,
1067 : std::string const &InString, // String of expression text written in the Runtime Language
1068 : int const StackNum, // Parent StackNum??
1069 : int &ExpressionNum, // index of expression in structure
1070 : std::string const &Line // Actual line from string
1071 : )
1072 : {
1073 :
1074 : // SUBROUTINE INFORMATION:
1075 : // AUTHOR Peter Graham Ellis
1076 : // DATE WRITTEN June 2006
1077 : // MODIFIED Brent Griffith, May 2009
1078 : // RE-ENGINEERED na
1079 :
1080 : // PURPOSE OF THIS SUBROUTINE:
1081 : // Parsing string into a series of tokens
1082 :
1083 : // METHODOLOGY EMPLOYED:
1084 :
1085 : // Using/Aliasing
1086 :
1087 : // Locals
1088 : // SUBROUTINE PARAMETER DEFINITIONS:
1089 365 : int constexpr MaxDoLoopCounts(500);
1090 :
1091 : // SUBROUTINE ARGUMENT DEFINITIONS:
1092 :
1093 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1094 : // CHARACTER(len=120), DIMENSION(MaxErrors) :: Error ! Errors should be stored with the stack
1095 : int NumErrors;
1096 : std::string::size_type Pos;
1097 365 : std::string StringToken;
1098 : char NextChar;
1099 : bool PeriodFound;
1100 : bool MinusFound;
1101 : bool PlusFound;
1102 : bool MultFound;
1103 : bool DivFound;
1104 : bool ErrorFlag;
1105 : bool OperatorProcessing;
1106 : int CountDoLooping;
1107 : bool LastED; // last character in a numeric was an E or D
1108 :
1109 365 : CountDoLooping = 0;
1110 365 : NumErrors = 0;
1111 : // Error = 'No errors.'
1112 :
1113 : // Break the string into tokens
1114 365 : int NumTokens(0);
1115 365 : std::string String(InString);
1116 :
1117 : // Following is a workaround to parse unitary operators as first value in the expression.
1118 : // i.e. Set X = -1
1119 : // this creates Set X = 0-1
1120 : // and seems to work.
1121 :
1122 365 : assert(!String.empty());
1123 365 : if (String[0] == '-') {
1124 9 : String = "0" + String;
1125 356 : } else if (String[0] == '+') {
1126 0 : String = "0" + String;
1127 : }
1128 365 : std::string::size_type LastPos(String.length());
1129 365 : Pos = 0;
1130 365 : OperatorProcessing = false; // true when an operator is found until terminated by non-operator
1131 365 : MinusFound = false;
1132 365 : MultFound = false;
1133 365 : DivFound = false;
1134 1993 : while (Pos < LastPos) {
1135 1628 : ++CountDoLooping;
1136 1628 : if (CountDoLooping > MaxDoLoopCounts) {
1137 0 : ShowSevereError(state, format("EMS ParseExpression: Entity={}", state.dataRuntimeLang->ErlStack(StackNum).Name));
1138 0 : ShowContinueError(state, format("...Line={}", Line));
1139 0 : ShowContinueError(state, format("...Failed to process String=\"{}\".", String));
1140 0 : ShowFatalError(state, "...program terminates due to preceding condition.");
1141 : }
1142 1628 : NextChar = String[Pos];
1143 1628 : if (NextChar == ' ') {
1144 544 : ++Pos;
1145 544 : continue;
1146 : }
1147 :
1148 : // Extend the token array
1149 1084 : state.dataRuntimeLangProcessor->PEToken.redimension(++NumTokens);
1150 :
1151 : // Get the next token
1152 1084 : StringToken = "";
1153 1084 : PeriodFound = false;
1154 1084 : PlusFound = false;
1155 1084 : ErrorFlag = false;
1156 1084 : LastED = false;
1157 1084 : if (is_any_of(NextChar, "0123456789.")) {
1158 : // Parse a number literal token
1159 300 : ++Pos;
1160 300 : StringToken += NextChar;
1161 300 : OperatorProcessing = false;
1162 300 : MultFound = false;
1163 300 : DivFound = false;
1164 :
1165 300 : if (NextChar == '.') {
1166 0 : PeriodFound = true;
1167 : }
1168 :
1169 1011 : while (Pos < LastPos) {
1170 828 : NextChar = String[Pos];
1171 828 : if (is_any_of(NextChar, "0123456789.eEdD")) {
1172 711 : ++Pos;
1173 711 : if (NextChar == '.') {
1174 206 : if (PeriodFound) {
1175 : // ERROR: two periods appearing in a number literal!
1176 0 : ShowSevereError(state, format("EMS Parse Expression, for \"{}\".", state.dataRuntimeLang->ErlStack(StackNum).Name));
1177 0 : ShowContinueError(state, format("...Line=\"{}\".", Line));
1178 0 : ShowContinueError(state, format("...Bad String=\"{}\".", String));
1179 0 : ShowContinueError(state, "...Two decimal points detected in String.");
1180 0 : ++NumErrors;
1181 0 : ErrorFlag = true;
1182 0 : break;
1183 : } else {
1184 206 : PeriodFound = true;
1185 : }
1186 : }
1187 711 : if (is_any_of(NextChar, "eEdD")) {
1188 0 : StringToken += NextChar;
1189 0 : if (LastED) {
1190 0 : ShowSevereError(state, format("EMS Parse Expression, for \"{}\".", state.dataRuntimeLang->ErlStack(StackNum).Name));
1191 0 : ShowContinueError(state, format("...Line=\"{}\".", Line));
1192 0 : ShowContinueError(state, format("...Bad String=\"{}\".", String));
1193 0 : ShowContinueError(state, "...Two D/E in numeric String.");
1194 0 : ++NumErrors;
1195 0 : ErrorFlag = true;
1196 : // error
1197 0 : break;
1198 : } else {
1199 0 : LastED = true;
1200 : }
1201 : } else {
1202 711 : StringToken += NextChar;
1203 : }
1204 117 : } else if (is_any_of(NextChar, "+-")) { // +/- following an ED is okay.
1205 19 : if (LastED) {
1206 0 : StringToken += NextChar;
1207 0 : ++Pos;
1208 0 : LastED = false;
1209 : } else {
1210 : // +/- will be processed on next pass, nothing needs to be done after a numeral
1211 19 : break;
1212 : }
1213 98 : } else if (is_any_of(NextChar, " +-*/^=<>)")) { // Any binary operator is okay
1214 98 : break; // End of token
1215 : } else {
1216 : // Error: strange sequence of characters: return TokenString//NextChar e.g., 234.44a or 234.44%
1217 0 : StringToken += NextChar;
1218 0 : break;
1219 : }
1220 : }
1221 :
1222 : // Save the number token
1223 300 : if (!ErrorFlag) {
1224 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Number;
1225 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1226 300 : if (state.dataSysVars->DeveloperFlag) {
1227 0 : print(state.files.debug, "Number=\"{}\"\n", StringToken);
1228 : }
1229 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Number = Util::ProcessNumber(StringToken, ErrorFlag);
1230 300 : if (state.dataSysVars->DeveloperFlag && ErrorFlag) {
1231 0 : print(state.files.debug, "{}\n", "Numeric error flagged");
1232 : }
1233 300 : if (MinusFound) {
1234 0 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Number = -state.dataRuntimeLangProcessor->PEToken(NumTokens).Number;
1235 0 : MinusFound = false;
1236 : }
1237 300 : if (ErrorFlag) {
1238 : // Error: something wrong with this number!
1239 0 : ShowSevereError(state, format("EMS Parse Expression, for \"{}\".", state.dataRuntimeLang->ErlStack(StackNum).Name));
1240 0 : ShowContinueError(state, format("...Line=\"{}\".", Line));
1241 0 : ShowContinueError(state, format("...Bad String=\"{}\".", String));
1242 0 : ShowContinueError(state, format("Invalid numeric=\"{}\".", StringToken));
1243 0 : ++NumErrors;
1244 : }
1245 : }
1246 :
1247 784 : } else if (is_any_of(NextChar, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
1248 : // Parse an undetermined string token (could be a variable, subroutine, or named operator)
1249 346 : ++Pos;
1250 346 : StringToken += NextChar;
1251 346 : OperatorProcessing = false;
1252 346 : MultFound = false;
1253 346 : DivFound = false;
1254 :
1255 3451 : while (Pos < LastPos) {
1256 3304 : NextChar = String[Pos];
1257 3304 : if (is_any_of(NextChar, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")) {
1258 3105 : ++Pos;
1259 3105 : StringToken += NextChar;
1260 199 : } else if (is_any_of(NextChar, " +-*/^=<>()")) {
1261 199 : break; // End of token
1262 : } else {
1263 : // Error: bad syntax: return TokenString//NextChar e.g., var1$ or b%
1264 0 : break;
1265 : }
1266 : }
1267 :
1268 : // Save the variable token
1269 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Variable;
1270 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1271 346 : if (state.dataSysVars->DeveloperFlag) {
1272 0 : print(state.files.debug, "Variable=\"{}\"\n", StringToken);
1273 : }
1274 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Variable = NewEMSVariable(state, StringToken, StackNum);
1275 :
1276 438 : } else if (is_any_of(NextChar, "+-*/^=<>@|&")) {
1277 : // Parse an operator token
1278 300 : if (NextChar == '-') {
1279 64 : StringToken = "-";
1280 64 : if (MultFound) {
1281 0 : ShowSevereError(state, format("EMS Parse Expression, for \"{}\".", state.dataRuntimeLang->ErlStack(StackNum).Name));
1282 0 : ShowContinueError(state, format("...Line = \"{}\".", Line));
1283 0 : ShowContinueError(state, "...Minus sign used on the right side of multiplication sign.");
1284 0 : ShowContinueError(state, "...Use parenthesis to wrap appropriate variables. For example, X * ( -Y ).");
1285 0 : ++NumErrors;
1286 0 : MultFound = false;
1287 64 : } else if (DivFound) {
1288 0 : ShowSevereError(state, format("EMS Parse Expression, for \"{}\".", state.dataRuntimeLang->ErlStack(StackNum).Name));
1289 0 : ShowContinueError(state, format("...Line = \"{}\".", Line));
1290 0 : ShowContinueError(state, "...Minus sign used on the right side of division sign.");
1291 0 : ShowContinueError(state, "...Use parenthesis to wrap appropriate variables. For example, X / ( -Y ).");
1292 0 : ++NumErrors;
1293 0 : DivFound = false;
1294 64 : } else if (OperatorProcessing && (NextChar == '-')) {
1295 : // if operator was deterined last pass and this character is a -, then insert a 0 before the minus and treat as subtraction
1296 : // example: change "Var == -1" to "Var == 0-1"
1297 13 : OperatorProcessing = false;
1298 13 : String.insert(Pos, "0");
1299 13 : ++LastPos;
1300 13 : StringToken = "0";
1301 13 : MultFound = false;
1302 13 : DivFound = false;
1303 : } else {
1304 51 : StringToken = NextChar;
1305 51 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Operator;
1306 : }
1307 : } else { // any other character process as operator
1308 236 : StringToken = NextChar;
1309 236 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Operator;
1310 : }
1311 :
1312 : // parse an operator if found,
1313 : // returns true and increments position, other wise returns false and leaves state untouched
1314 6071 : const auto parse = [&](const char *string, ErlFunc op, bool case_insensitive) {
1315 6071 : const size_t len = strlen(string);
1316 6071 : const std::string potential_match = String.substr(Pos, len);
1317 :
1318 6071 : if ((case_insensitive && Util::SameString(potential_match, string)) || (!case_insensitive && potential_match == string)) {
1319 152 : if (state.dataSysVars->DeveloperFlag) {
1320 0 : print(state.files.debug, "OPERATOR \"{}\"\n", potential_match);
1321 : }
1322 152 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = op;
1323 152 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = potential_match;
1324 152 : Pos += (len - 1);
1325 152 : return true;
1326 : } else {
1327 5919 : return false;
1328 : }
1329 6071 : };
1330 :
1331 : // case insensitive wrapper call to parse
1332 4371 : const auto i_parse = [&](const char *string, const ErlFunc op) { return parse(string, op, true); };
1333 :
1334 : // First check for two character operators: == <> <= >= || &&
1335 300 : std::string const cc(String.substr(Pos, 2));
1336 590 : if (parse("==", ErlFunc::Equal, false) || parse("<>", ErlFunc::NotEqual, false) || parse("<=", ErlFunc::LessOrEqual, false) ||
1337 590 : parse(">=", ErlFunc::GreaterOrEqual, false) || parse("||", ErlFunc::LogicalOR, false) || parse("&&", ErlFunc::LogicalAND, false)) {
1338 : // One of the comparision / logical operators
1339 32 : OperatorProcessing = true;
1340 :
1341 268 : } else if (String[Pos] == '@') { // next check for builtin functions signaled by "@"
1342 :
1343 239 : if (i_parse("@Round", ErlFunc::Round) || i_parse("@Mod", ErlFunc::Mod) || i_parse("@Sin", ErlFunc::Sin) ||
1344 113 : i_parse("@Cos", ErlFunc::Cos) || i_parse("@ArcCos", ErlFunc::ArcCos) || i_parse("@ArcSin", ErlFunc::ArcSin) ||
1345 109 : i_parse("@DegToRad", ErlFunc::DegToRad) || i_parse("@RadToDeg", ErlFunc::RadToDeg) || i_parse("@Exp", ErlFunc::Exp) ||
1346 104 : i_parse("@Ln", ErlFunc::Ln) || i_parse("@Max", ErlFunc::Max) || i_parse("@Min", ErlFunc::Min) || i_parse("@Abs", ErlFunc::ABS) ||
1347 92 : i_parse("@RANDOMUNIFORM", ErlFunc::RandU) || i_parse("@RANDOMNORMAL", ErlFunc::RandG) ||
1348 90 : i_parse("@SEEDRANDOM", ErlFunc::RandSeed) || i_parse("@RhoAirFnPbTdbW", ErlFunc::RhoAirFnPbTdbW) ||
1349 87 : i_parse("@CpAirFnW", ErlFunc::CpAirFnW) || i_parse("@HfgAirFnWTdb", ErlFunc::HfgAirFnWTdb) ||
1350 85 : i_parse("@HgAirFnWTdb", ErlFunc::HgAirFnWTdb) || i_parse("@TdpFnTdbTwbPb", ErlFunc::TdpFnTdbTwbPb) ||
1351 83 : i_parse("@TdpFnWPb", ErlFunc::TdpFnWPb) || i_parse("@HFnTdbW", ErlFunc::HFnTdbW) || i_parse("@HFnTdbRhPb", ErlFunc::HFnTdbRhPb) ||
1352 76 : i_parse("@TdbFnHW", ErlFunc::TdbFnHW) || i_parse("@RhovFnTdbRhLBnd0C", ErlFunc::RhovFnTdbRhLBnd0C) ||
1353 70 : i_parse("@RhovFnTdbRh", ErlFunc::RhovFnTdbRh) || i_parse("@RhovFnTdbWPb", ErlFunc::RhovFnTdbWPb) ||
1354 68 : i_parse("@RhFnTdbRhovLBnd0C", ErlFunc::RhFnTdbRhovLBnd0C) || i_parse("@RhFnTdbRhov", ErlFunc::RhFnTdbRhov) ||
1355 66 : i_parse("@RhFnTdbWPb", ErlFunc::RhFnTdbWPb) || i_parse("@TwbFnTdbWPb", ErlFunc::TwbFnTdbWPb) ||
1356 63 : i_parse("@VFnTdbWPb", ErlFunc::VFnTdbWPb) || i_parse("@WFnTdpPb", ErlFunc::WFnTdpPb) || i_parse("@WFnTdbH", ErlFunc::WFnTdbH) ||
1357 58 : i_parse("@WFnTdbTwbPb", ErlFunc::WFnTdbTwbPb) || i_parse("@WFnTdbRhPb", ErlFunc::WFnTdbRhPb) ||
1358 56 : i_parse("@PsatFnTemp", ErlFunc::PsatFnTemp) || i_parse("@TsatFnHPb", ErlFunc::TsatFnHPb) ||
1359 53 : i_parse("@TsatFnPb", ErlFunc::TsatFnPb) || i_parse("@CpCW", ErlFunc::CpCW) || i_parse("@CpHW", ErlFunc::CpHW) ||
1360 51 : i_parse("@RhoH2O", ErlFunc::RhoH2O) || i_parse("@FATALHALTEP", ErlFunc::FatalHaltEp) ||
1361 50 : i_parse("@SEVEREWARNEP", ErlFunc::SevereWarnEp) || i_parse("@WARNEP", ErlFunc::WarnEp) ||
1362 48 : i_parse("@TRENDVALUE", ErlFunc::TrendValue) || i_parse("@TRENDAVERAGE", ErlFunc::TrendAverage) ||
1363 42 : i_parse("@TRENDMAX", ErlFunc::TrendMax) || i_parse("@TRENDMIN", ErlFunc::TrendMin) ||
1364 38 : i_parse("@TRENDDIRECTION", ErlFunc::TrendDirection) || i_parse("@TRENDSUM", ErlFunc::TrendSum) ||
1365 34 : i_parse("@CURVEVALUE", ErlFunc::CurveValue) || i_parse("@TODAYISRAIN", ErlFunc::TodayIsRain) ||
1366 27 : i_parse("@TODAYISSNOW", ErlFunc::TodayIsSnow) || i_parse("@TODAYOUTDRYBULBTEMP", ErlFunc::TodayOutDryBulbTemp) ||
1367 25 : i_parse("@TODAYOUTDEWPOINTTEMP", ErlFunc::TodayOutDewPointTemp) || i_parse("@TODAYOUTBAROPRESS", ErlFunc::TodayOutBaroPress) ||
1368 23 : i_parse("@TODAYOUTRELHUM", ErlFunc::TodayOutRelHum) || i_parse("@TODAYWINDSPEED", ErlFunc::TodayWindSpeed) ||
1369 21 : i_parse("@TODAYWINDDIR", ErlFunc::TodayWindDir) || i_parse("@TODAYSKYTEMP", ErlFunc::TodaySkyTemp) ||
1370 19 : i_parse("@TODAYHORIZIRSKY", ErlFunc::TodayHorizIRSky) || i_parse("@TODAYBEAMSOLARRAD", ErlFunc::TodayBeamSolarRad) ||
1371 17 : i_parse("@TODAYDIFSOLARRAD", ErlFunc::TodayDifSolarRad) || i_parse("@TODAYALBEDO", ErlFunc::TodayAlbedo) ||
1372 15 : i_parse("@TODAYLIQUIDPRECIP", ErlFunc::TodayLiquidPrecip) || i_parse("@TOMORROWISRAIN", ErlFunc::TomorrowIsRain) ||
1373 13 : i_parse("@TOMORROWISSNOW", ErlFunc::TomorrowIsSnow) || i_parse("@TOMORROWOUTDRYBULBTEMP", ErlFunc::TomorrowOutDryBulbTemp) ||
1374 11 : i_parse("@TOMORROWOUTDEWPOINTTEMP", ErlFunc::TomorrowOutDewPointTemp) ||
1375 10 : i_parse("@TOMORROWOUTBAROPRESS", ErlFunc::TomorrowOutBaroPress) || i_parse("@TOMORROWOUTRELHUM", ErlFunc::TomorrowOutRelHum) ||
1376 8 : i_parse("@TOMORROWWINDSPEED", ErlFunc::TomorrowWindSpeed) || i_parse("@TOMORROWWINDDIR", ErlFunc::TomorrowWindDir) ||
1377 6 : i_parse("@TOMORROWSKYTEMP", ErlFunc::TomorrowSkyTemp) || i_parse("@TOMORROWHORIZIRSKY", ErlFunc::TomorrowHorizIRSky) ||
1378 4 : i_parse("@TOMORROWBEAMSOLARRAD", ErlFunc::TomorrowBeamSolarRad) ||
1379 240 : i_parse("@TOMORROWDIFSOLARRAD", ErlFunc::TomorrowDifSolarRad) || i_parse("@TOMORROWALBEDO", ErlFunc::TomorrowAlbedo) ||
1380 1 : i_parse("@TOMORROWLIQUIDPRECIP", ErlFunc::TomorrowLiquidPrecip)) {
1381 : // was a built in function operator
1382 : } else { // throw error
1383 0 : if (state.dataSysVars->DeveloperFlag) {
1384 0 : print(state.files.debug, "ERROR \"{}\"\n", String);
1385 : }
1386 0 : ShowFatalError(state, format("EMS Runtime Language: did not find valid input for built-in function ={}", String));
1387 : }
1388 : } else {
1389 : // Check for remaining single character operators
1390 148 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1391 148 : MultFound = false;
1392 148 : DivFound = false;
1393 :
1394 148 : if (state.dataSysVars->DeveloperFlag) {
1395 0 : print(state.files.debug, "OPERATOR \"{}\"\n", StringToken);
1396 : }
1397 :
1398 148 : if (StringToken == "+") {
1399 14 : if (!OperatorProcessing) {
1400 14 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Add;
1401 14 : OperatorProcessing = true;
1402 : } else {
1403 0 : PlusFound = true;
1404 0 : OperatorProcessing = false;
1405 : }
1406 134 : } else if (StringToken == "-") {
1407 51 : if (!OperatorProcessing) {
1408 51 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Subtract;
1409 51 : OperatorProcessing = true;
1410 : } else {
1411 0 : MinusFound = true;
1412 0 : OperatorProcessing = false;
1413 : }
1414 83 : } else if (StringToken == "*") {
1415 38 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Multiply;
1416 38 : MultFound = true;
1417 38 : OperatorProcessing = true;
1418 45 : } else if (StringToken == "/") {
1419 18 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Divide;
1420 18 : DivFound = true;
1421 18 : OperatorProcessing = true;
1422 27 : } else if (StringToken == "<") {
1423 5 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::LessThan;
1424 5 : OperatorProcessing = true;
1425 22 : } else if (StringToken == ">") {
1426 9 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::GreaterThan;
1427 9 : OperatorProcessing = true;
1428 13 : } else if (StringToken == "^") {
1429 0 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::RaiseToPower;
1430 0 : OperatorProcessing = true;
1431 13 : } else if (StringToken == "0" && (NextChar == '-')) {
1432 : // process string insert = "0"
1433 13 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Number;
1434 13 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1435 : } else {
1436 : // Uh OH, this should never happen! throw error
1437 0 : if (state.dataSysVars->DeveloperFlag) {
1438 0 : print(state.files.debug, "ERROR \"{}\"\n", StringToken);
1439 : }
1440 0 : ShowFatalError(state, format("EMS, caught unexpected token = \"{}\" ; while parsing string={}", StringToken, String));
1441 : }
1442 : }
1443 :
1444 300 : ++Pos;
1445 :
1446 438 : } else if (is_any_of(NextChar, "()")) {
1447 : // Parse a parenthesis token
1448 138 : ++Pos;
1449 138 : StringToken = NextChar;
1450 138 : if (state.dataSysVars->DeveloperFlag) {
1451 0 : print(state.files.debug, "PAREN \"{}\"\n", StringToken);
1452 : }
1453 138 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Parenthesis;
1454 138 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1455 138 : if (NextChar == '(') {
1456 69 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Parenthesis = Token::ParenthesisLeft;
1457 69 : OperatorProcessing = true;
1458 : }
1459 138 : if (NextChar == ')') {
1460 69 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Parenthesis = Token::ParenthesisRight;
1461 : }
1462 :
1463 0 : } else if (is_any_of(NextChar, "\"")) {
1464 : // Parse a string literal token
1465 0 : if (state.dataSysVars->DeveloperFlag) {
1466 0 : print(state.files.debug, "{}\n", "LITERAL STRING");
1467 : }
1468 0 : ++Pos;
1469 :
1470 : } else {
1471 : // Error: bad start to the token
1472 : }
1473 : }
1474 :
1475 365 : if (NumErrors > 0) {
1476 0 : if (state.dataSysVars->DeveloperFlag) {
1477 0 : print(state.files.debug, "{}\n", "ERROR OUT");
1478 : }
1479 0 : ShowFatalError(state, "EMS, previous errors cause termination.");
1480 : }
1481 :
1482 365 : ExpressionNum = ProcessTokens(state, state.dataRuntimeLangProcessor->PEToken, NumTokens, StackNum, String);
1483 365 : }
1484 :
1485 434 : int ProcessTokens(
1486 : EnergyPlusData &state, const Array1D<TokenType> &TokenIN, int const NumTokensIN, int const StackNum, std::string const &ParsingString)
1487 : {
1488 :
1489 : // SUBROUTINE INFORMATION:
1490 : // AUTHOR Peter Graham Ellis
1491 : // DATE WRITTEN June 2006
1492 : // MODIFIED na
1493 : // RE-ENGINEERED na
1494 :
1495 : // PURPOSE OF THIS SUBROUTINE:
1496 : // Processes tokens into expressions.
1497 :
1498 : // METHODOLOGY EMPLOYED:
1499 : // Uses recursion to handle tokens with compound expressions
1500 :
1501 : // Return value
1502 : int ExpressionNum;
1503 :
1504 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1505 : int Pos;
1506 : int LastPos;
1507 : int TokenNum;
1508 : int NumTokens;
1509 : int Depth;
1510 : int NumSubTokens;
1511 : int NewNumTokens;
1512 : int OperatorNum;
1513 : int NumOperands;
1514 : int ParenthWhileCounter; // used to trap for unbalanced parentheses
1515 :
1516 : // Object Data
1517 434 : Array1D<TokenType> Token(TokenIN);
1518 434 : Array1D<TokenType> SubTokenList;
1519 :
1520 434 : ExpressionNum = 0;
1521 434 : NumTokens = NumTokensIN;
1522 :
1523 : // Process parentheses
1524 434 : Pos = 0;
1525 1337 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1526 957 : if (Token(TokenNum).Type == Token::Parenthesis) {
1527 54 : Pos = TokenNum;
1528 54 : break;
1529 : }
1530 : }
1531 :
1532 434 : ParenthWhileCounter = 0;
1533 :
1534 503 : while ((Pos > 0) && (ParenthWhileCounter < 50)) {
1535 69 : ++ParenthWhileCounter;
1536 69 : Depth = 0;
1537 487 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1538 487 : if (Token(TokenNum).Type == Token::Parenthesis) {
1539 174 : if (Token(TokenNum).Parenthesis == Token::ParenthesisLeft) {
1540 87 : if (Depth == 0) {
1541 69 : Pos = TokenNum; // Record position of first left parenthesis
1542 : }
1543 87 : ++Depth;
1544 : }
1545 174 : if (Token(TokenNum).Parenthesis == Token::ParenthesisRight) {
1546 87 : --Depth;
1547 87 : if (Depth == 0) {
1548 69 : LastPos = TokenNum;
1549 69 : NumSubTokens = LastPos - Pos - 1;
1550 69 : SubTokenList.allocate(NumSubTokens);
1551 69 : SubTokenList({1, NumSubTokens}) = Token({Pos + 1, LastPos - 1}); // Need to check that these don't exceed bounds
1552 69 : ExpressionNum = ProcessTokens(state, SubTokenList, NumSubTokens, StackNum, ParsingString);
1553 69 : SubTokenList.deallocate();
1554 :
1555 : // Replace the parenthetical tokens with one expression token
1556 69 : NewNumTokens = NumTokens - NumSubTokens - 1;
1557 69 : if (NewNumTokens > 0) {
1558 69 : if (LastPos + 1 <= NumTokens) {
1559 84 : Token({Pos + 1, NewNumTokens}) = Token({LastPos + 1, _});
1560 : }
1561 69 : Token.redimension(NewNumTokens);
1562 69 : Token(Pos).Type = Token::Expression;
1563 69 : Token(Pos).Expression = ExpressionNum;
1564 69 : Token(Pos).String = "Expr";
1565 69 : NumTokens = NewNumTokens;
1566 : }
1567 :
1568 : // Reset loop for next parenthetical set
1569 69 : break;
1570 : }
1571 : }
1572 : }
1573 : }
1574 :
1575 : // This repeats code again... Just checks to see if there are any more parentheses to be found
1576 69 : Pos = 0;
1577 233 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1578 179 : if (Token(TokenNum).Type == Token::Parenthesis) {
1579 15 : Pos = TokenNum;
1580 15 : break;
1581 : }
1582 : }
1583 : }
1584 :
1585 434 : if (ParenthWhileCounter == 50) { // symptom of mismatched parenthesis
1586 0 : ShowSevereError(state, "EMS error parsing parentheses, check that parentheses are balanced");
1587 0 : ShowContinueError(state, format("String being parsed=\"{}\".", ParsingString));
1588 0 : ShowFatalError(state, "Program terminates due to preceding error.");
1589 : }
1590 :
1591 : // Process operators and builtin functions
1592 : // Loop thru all operators and group expressions in the order of precedence
1593 42098 : for (OperatorNum = 1; OperatorNum <= NumPossibleOperators; ++OperatorNum) {
1594 :
1595 : // Find the next occurrence of the operator
1596 41664 : Pos = 0; // position in sequence of tokens
1597 108335 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1598 66947 : if ((Token(TokenNum).Type == Token::Operator) && (Token(TokenNum).Operator == static_cast<ErlFunc>(OperatorNum))) {
1599 276 : Pos = TokenNum;
1600 276 : break;
1601 : }
1602 : }
1603 :
1604 41831 : while (Pos > 0) {
1605 287 : if (Pos == 1) {
1606 : // if first token is for a built-in function starting with "@" then okay, otherwise the operator needs a LHS
1607 120 : if (static_cast<int>(Token(TokenNum).Operator) > static_cast<int>(ErlFunc::LogicalOR)) { // we have a function expression to set up
1608 120 : ExpressionNum = NewExpression(state);
1609 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = static_cast<ErlFunc>(OperatorNum);
1610 120 : NumOperands = ErlFuncNumOperands[OperatorNum];
1611 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = NumOperands;
1612 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(NumOperands);
1613 :
1614 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(Pos + 1).Type));
1615 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(Pos + 1).Number;
1616 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Expression = Token(Pos + 1).Expression;
1617 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(Pos + 1).Variable;
1618 120 : if (Token(Pos + 1).Variable > 0) {
1619 71 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).TrendVariable =
1620 71 : state.dataRuntimeLang->ErlVariable(Token(Pos + 1).Variable).Value.TrendVariable;
1621 71 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).TrendVarPointer =
1622 71 : state.dataRuntimeLang->ErlVariable(Token(Pos + 1).Variable).Value.TrendVarPointer;
1623 : }
1624 120 : if ((NumOperands >= 2) && (NumTokens >= 3)) {
1625 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Type =
1626 94 : static_cast<Value>(static_cast<int>(Token(Pos + 2).Type));
1627 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Number = Token(Pos + 2).Number;
1628 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Expression = Token(Pos + 2).Expression;
1629 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Variable = Token(Pos + 2).Variable;
1630 : }
1631 :
1632 120 : if ((NumOperands >= 3) && (NumTokens >= 4)) {
1633 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Type =
1634 17 : static_cast<Value>(static_cast<int>(Token(Pos + 3).Type));
1635 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Number = Token(Pos + 3).Number;
1636 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Expression = Token(Pos + 3).Expression;
1637 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Variable = Token(Pos + 3).Variable;
1638 17 : if ((NumOperands == 3) && (NumTokens - 4 > 0)) { // too many tokens for this non-binary operator
1639 0 : ShowFatalError(state, "EMS error parsing tokens, too many for built-in function");
1640 : }
1641 : }
1642 :
1643 120 : if ((NumOperands >= 4) && (NumTokens >= 5)) {
1644 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Type =
1645 6 : static_cast<Value>(static_cast<int>(Token(Pos + 4).Type));
1646 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Number = Token(Pos + 4).Number;
1647 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Expression = Token(Pos + 4).Expression;
1648 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Variable = Token(Pos + 4).Variable;
1649 6 : if ((NumOperands == 4) && (NumTokens - 5 > 0)) { // too many tokens for this non-binary operator
1650 0 : ShowFatalError(state, "EMS error parsing tokens, too many for built-in function");
1651 : }
1652 : }
1653 :
1654 120 : if ((NumOperands == 5) && (NumTokens >= 6)) {
1655 0 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Type =
1656 0 : static_cast<Value>(static_cast<int>(Token(Pos + 5).Type));
1657 0 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Number = Token(Pos + 5).Number;
1658 0 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Expression = Token(Pos + 5).Expression;
1659 0 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Variable = Token(Pos + 5).Variable;
1660 0 : if ((NumOperands == 5) && (NumTokens - 6 > 0)) { // too many tokens for this non-binary operator
1661 0 : ShowFatalError(state, "EMS error parsing tokens, too many for built-in function");
1662 : }
1663 : }
1664 120 : break;
1665 : } else {
1666 0 : ShowSevereError(state, format("The operator \"{}\" is missing the left-hand operand!", ErlFuncNamesUC[OperatorNum]));
1667 0 : ShowContinueError(state, format("String being parsed=\"{}\".", ParsingString));
1668 0 : break;
1669 : }
1670 167 : } else if (Pos == NumTokens) {
1671 0 : ShowSevereError(state, format("The operator \"{}\" is missing the right-hand operand!", ErlFuncNamesUC[OperatorNum]));
1672 0 : ShowContinueError(state, format("String being parsed=\"{}\".", ParsingString));
1673 0 : break;
1674 : } else {
1675 :
1676 167 : ExpressionNum = NewExpression(state);
1677 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = static_cast<ErlFunc>(OperatorNum);
1678 167 : NumOperands = ErlFuncNumOperands[OperatorNum];
1679 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = NumOperands;
1680 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(NumOperands);
1681 :
1682 : // PE commment: Need a right-hand and left-hand check for these, not just number of operators
1683 : // Unification of TYPEs would turn these into one-liners
1684 :
1685 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(Pos - 1).Type));
1686 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(Pos - 1).Number;
1687 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Expression = Token(Pos - 1).Expression;
1688 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(Pos - 1).Variable;
1689 :
1690 167 : if (NumOperands >= 2) {
1691 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Type = static_cast<Value>(static_cast<int>(Token(Pos + 1).Type));
1692 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Number = Token(Pos + 1).Number;
1693 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Expression = Token(Pos + 1).Expression;
1694 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Variable = Token(Pos + 1).Variable;
1695 : }
1696 :
1697 : // Replace the three tokens with one expression token
1698 167 : if ((NumOperands == 2) && (NumTokens - 2 > 0)) {
1699 167 : if (Pos + 2 <= NumTokens) {
1700 48 : Token({Pos, NumTokens - 2}) = Token({Pos + 2, _});
1701 : }
1702 167 : Token(Pos - 1).Type = Token::Expression;
1703 167 : Token(Pos - 1).Expression = ExpressionNum;
1704 167 : Token(Pos - 1).String = "Expr";
1705 167 : NumTokens -= 2;
1706 167 : Token.redimension(NumTokens);
1707 : }
1708 : }
1709 :
1710 : // Find the next occurrence of the operator (this repeats code, but don't have better idea)
1711 167 : Pos = 0;
1712 392 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1713 236 : if ((Token(TokenNum).Type == Token::Operator) && (Token(TokenNum).Operator == static_cast<ErlFunc>(OperatorNum))) {
1714 11 : Pos = TokenNum;
1715 11 : break;
1716 : }
1717 : }
1718 : }
1719 : }
1720 :
1721 : // Should be down to just one token now
1722 434 : if (Token(1).Type == Token::Number) {
1723 91 : ExpressionNum = NewExpression(state);
1724 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = ErlFunc::Literal;
1725 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = 1;
1726 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(1);
1727 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(1).Type));
1728 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(1).Number;
1729 343 : } else if (Token(1).Type == Token::Variable) {
1730 69 : ExpressionNum = NewExpression(state);
1731 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = ErlFunc::Literal;
1732 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = 1;
1733 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(1);
1734 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(1).Type));
1735 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(1).Variable;
1736 : }
1737 :
1738 434 : Token.deallocate();
1739 :
1740 434 : return ExpressionNum;
1741 478 : }
1742 :
1743 447 : int NewExpression(EnergyPlusData &state)
1744 : {
1745 :
1746 : // FUNCTION INFORMATION:
1747 : // AUTHOR Peter Graham Ellis
1748 : // DATE WRITTEN June 2006
1749 : // MODIFIED na
1750 : // RE-ENGINEERED na
1751 :
1752 : // PURPOSE OF THIS FUNCTION:
1753 : // Creates a new expression.
1754 :
1755 : // METHODOLOGY EMPLOYED:
1756 :
1757 : // Return value
1758 :
1759 : // Locals
1760 : // FUNCTION ARGUMENT DEFINITIONS:
1761 :
1762 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1763 :
1764 : // Object Data
1765 :
1766 447 : if (state.dataRuntimeLang->NumExpressions == 0) {
1767 25 : state.dataRuntimeLang->ErlExpression.allocate(1);
1768 25 : state.dataRuntimeLang->NumExpressions = 1;
1769 : } else {
1770 422 : state.dataRuntimeLang->ErlExpression.redimension(++state.dataRuntimeLang->NumExpressions);
1771 : }
1772 :
1773 447 : return state.dataRuntimeLang->NumExpressions;
1774 : }
1775 :
1776 1054238 : ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, bool &seriousErrorFound)
1777 : {
1778 :
1779 : // FUNCTION INFORMATION:
1780 : // AUTHOR Peter Graham Ellis
1781 : // DATE WRITTEN June 2006
1782 : // MODIFIED Brent Griffith, May 2009
1783 : // RE-ENGINEERED na
1784 :
1785 : // PURPOSE OF THIS FUNCTION:
1786 : // Evaluates an expression.
1787 :
1788 : // METHODOLOGY EMPLOYED:
1789 :
1790 : // USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY : IEEE_IS_NAN ! Use IEEE_IS_NAN when GFortran supports it
1791 : // Using/Aliasing
1792 : using namespace Psychrometrics;
1793 : using Curve::CurveValue;
1794 :
1795 : // Return value
1796 1054238 : ErlValueType ReturnValue;
1797 :
1798 : // Locals
1799 : // FUNCTION ARGUMENT DEFINITIONS:
1800 :
1801 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1802 : int thisTrend; // local temporary
1803 : int thisIndex; // local temporary
1804 : Real64 thisAverage; // local temporary
1805 : int loop; // local temporary
1806 : Real64 thisSlope; // local temporary
1807 : Real64 thisMax; // local temporary
1808 : Real64 thisMin; // local temporary
1809 : int OperandNum;
1810 : int SeedN; // number of digits in the number used to seed the generator
1811 1054238 : Array1D_int SeedIntARR; // local temporary for random seed
1812 : Real64 tmpRANDU1; // local temporary for uniform random number
1813 : Real64 tmpRANDU2; // local temporary for uniform random number
1814 : Real64 tmpRANDG; // local temporary for gaussian random number
1815 : Real64 UnitCircleTest; // local temporary for Box-Muller algo
1816 : Real64 TestValue; // local temporary
1817 :
1818 : // Object Data
1819 1054238 : Array1D<ErlValueType> Operand;
1820 :
1821 1054238 : constexpr std::string_view EMSBuiltInFunction = "EMS Built-In Function";
1822 :
1823 1054238 : ReturnValue.Type = Value::Number;
1824 1054238 : ReturnValue.Number = 0.0;
1825 :
1826 1054238 : if (ExpressionNum > 0) {
1827 1054238 : auto const &thisErlExpression = state.dataRuntimeLang->ErlExpression(ExpressionNum);
1828 : // is there a way to keep these and not allocate and deallocate all the time?
1829 1054238 : Operand.allocate(thisErlExpression.NumOperands);
1830 : // Reduce operands down to literals
1831 2972166 : for (OperandNum = 1; OperandNum <= thisErlExpression.NumOperands; ++OperandNum) {
1832 1917928 : auto &thisOperand = Operand(OperandNum);
1833 1917928 : thisOperand = thisErlExpression.Operand(OperandNum);
1834 1917928 : if (thisOperand.Type == Value::Expression) {
1835 337865 : thisOperand = EvaluateExpression(state, thisOperand.Expression, seriousErrorFound); // recursive call
1836 : // check if recursive call found an error in nested expression, want to preserve error message from that
1837 337865 : if (seriousErrorFound) {
1838 0 : ReturnValue.Type = Value::Error;
1839 0 : ReturnValue.Error = thisOperand.Error;
1840 : }
1841 :
1842 1580063 : } else if (thisOperand.Type == Value::Variable) {
1843 1271725 : auto const &thisErlVar = state.dataRuntimeLang->ErlVariable(thisOperand.Variable);
1844 1271725 : if (thisErlVar.Value.initialized) { // check that value has been initialized
1845 1271724 : thisOperand = thisErlVar.Value;
1846 : } else { // value has never been set
1847 1 : ReturnValue.Type = Value::Error;
1848 1 : ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!";
1849 1 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1850 :
1851 : // check if this is an arg in CurveValue,
1852 1 : if (thisErlExpression.Operator !=
1853 : ErlFunc::CurveValue) { // padding the argument list for CurveValue is too common to fatal on. only reported to EDD
1854 1 : seriousErrorFound = true;
1855 : }
1856 : }
1857 : }
1858 : }
1859 : }
1860 :
1861 1054238 : if (ReturnValue.Type != Value::Error) {
1862 :
1863 : // Perform the operation
1864 :
1865 1054237 : switch (thisErlExpression.Operator) {
1866 :
1867 247128 : case ErlFunc::Literal:
1868 247128 : ReturnValue = Operand(1);
1869 247128 : ReturnValue.initialized = true;
1870 247128 : break;
1871 :
1872 0 : case ErlFunc::Negative: // unary minus sign. parsing does not work yet
1873 0 : ReturnValue = SetErlValueNumber(-1.0 * Operand(1).Number);
1874 0 : break;
1875 :
1876 90421 : case ErlFunc::Divide:
1877 90421 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1878 90421 : if (Operand(2).Number == 0.0) {
1879 0 : ReturnValue.Type = Value::Error;
1880 0 : ReturnValue.Error = "EvaluateExpression: Divide By Zero in EMS Program!";
1881 0 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1882 0 : seriousErrorFound = true;
1883 : }
1884 : } else {
1885 90421 : ReturnValue = SetErlValueNumber(Operand(1).Number / Operand(2).Number);
1886 : }
1887 : }
1888 90421 : break;
1889 :
1890 186886 : case ErlFunc::Multiply:
1891 186886 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1892 186886 : ReturnValue = SetErlValueNumber(Operand(1).Number * Operand(2).Number);
1893 : }
1894 186886 : break;
1895 :
1896 136272 : case ErlFunc::Subtract:
1897 136272 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1898 136272 : ReturnValue = SetErlValueNumber(Operand(1).Number - Operand(2).Number);
1899 : }
1900 136272 : break;
1901 :
1902 78880 : case ErlFunc::Add:
1903 78880 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1904 78880 : ReturnValue = SetErlValueNumber(Operand(1).Number + Operand(2).Number);
1905 : }
1906 78880 : break;
1907 :
1908 33061 : case ErlFunc::Equal:
1909 33061 : if (Operand(1).Type == Operand(2).Type) {
1910 33061 : if (Operand(1).Type == Value::Null) {
1911 0 : ReturnValue = state.dataRuntimeLang->True;
1912 33061 : } else if ((Operand(1).Type == Value::Number) && (Operand(1).Number == Operand(2).Number)) {
1913 8254 : ReturnValue = state.dataRuntimeLang->True;
1914 : } else {
1915 24807 : ReturnValue = state.dataRuntimeLang->False;
1916 : }
1917 : } else {
1918 0 : ReturnValue = state.dataRuntimeLang->False;
1919 : }
1920 33061 : break;
1921 :
1922 4076 : case ErlFunc::NotEqual:
1923 4076 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1924 4076 : if (Operand(1).Number != Operand(2).Number) {
1925 4070 : ReturnValue = state.dataRuntimeLang->True;
1926 : } else {
1927 6 : ReturnValue = state.dataRuntimeLang->False;
1928 : }
1929 : }
1930 4076 : break;
1931 :
1932 1380 : case ErlFunc::LessOrEqual:
1933 1380 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1934 1380 : if (Operand(1).Number <= Operand(2).Number) {
1935 1362 : ReturnValue = state.dataRuntimeLang->True;
1936 : } else {
1937 18 : ReturnValue = state.dataRuntimeLang->False;
1938 : }
1939 : }
1940 1380 : break;
1941 :
1942 1362 : case ErlFunc::GreaterOrEqual:
1943 1362 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1944 1362 : if (Operand(1).Number >= Operand(2).Number) {
1945 1362 : ReturnValue = state.dataRuntimeLang->True;
1946 : } else {
1947 0 : ReturnValue = state.dataRuntimeLang->False;
1948 : }
1949 : }
1950 1362 : break;
1951 :
1952 49666 : case ErlFunc::LessThan:
1953 49666 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1954 49666 : if (Operand(1).Number < Operand(2).Number) {
1955 47720 : ReturnValue = state.dataRuntimeLang->True;
1956 : } else {
1957 1946 : ReturnValue = state.dataRuntimeLang->False;
1958 : }
1959 : }
1960 49666 : break;
1961 :
1962 50696 : case ErlFunc::GreaterThan:
1963 50696 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1964 50696 : if (Operand(1).Number > Operand(2).Number) {
1965 42188 : ReturnValue = state.dataRuntimeLang->True;
1966 : } else {
1967 8508 : ReturnValue = state.dataRuntimeLang->False;
1968 : }
1969 : }
1970 50696 : break;
1971 :
1972 0 : case ErlFunc::RaiseToPower:
1973 0 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1974 0 : TestValue = std::pow(Operand(1).Number, Operand(2).Number);
1975 0 : if (std::isnan(TestValue)) {
1976 : // throw Error
1977 0 : ReturnValue.Type = Value::Error;
1978 : ReturnValue.Error =
1979 0 : format("EvaluateExpression: Attempted to raise to power with incompatible numbers: {:.6T} raised to {:.6T}",
1980 0 : Operand(1).Number,
1981 0 : Operand(2).Number);
1982 0 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1983 0 : seriousErrorFound = true;
1984 : }
1985 : } else {
1986 0 : ReturnValue = SetErlValueNumber(TestValue);
1987 : }
1988 : }
1989 0 : break;
1990 :
1991 34712 : case ErlFunc::LogicalAND:
1992 34712 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1993 34712 : if ((Operand(1).Number == state.dataRuntimeLang->True.Number) && (Operand(2).Number == state.dataRuntimeLang->True.Number)) {
1994 30624 : ReturnValue = state.dataRuntimeLang->True;
1995 : } else {
1996 4088 : ReturnValue = state.dataRuntimeLang->False;
1997 : }
1998 : }
1999 34712 : break;
2000 :
2001 0 : case ErlFunc::LogicalOR:
2002 0 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
2003 0 : if ((Operand(1).Number == state.dataRuntimeLang->True.Number) || (Operand(2).Number == state.dataRuntimeLang->True.Number)) {
2004 0 : ReturnValue = state.dataRuntimeLang->True;
2005 : } else {
2006 0 : ReturnValue = state.dataRuntimeLang->False;
2007 : }
2008 : }
2009 0 : break;
2010 :
2011 2 : case ErlFunc::Round:
2012 2 : ReturnValue = SetErlValueNumber(nint(Operand(1).Number));
2013 2 : break;
2014 :
2015 6 : case ErlFunc::Mod:
2016 6 : ReturnValue = SetErlValueNumber(mod(Operand(1).Number, Operand(2).Number));
2017 6 : break;
2018 :
2019 2 : case ErlFunc::Sin:
2020 2 : ReturnValue = SetErlValueNumber(std::sin(Operand(1).Number));
2021 2 : break;
2022 :
2023 2 : case ErlFunc::Cos:
2024 2 : ReturnValue = SetErlValueNumber(std::cos(Operand(1).Number));
2025 2 : break;
2026 :
2027 2 : case ErlFunc::ArcSin:
2028 2 : ReturnValue = SetErlValueNumber(std::asin(Operand(1).Number));
2029 2 : break;
2030 :
2031 2 : case ErlFunc::ArcCos:
2032 2 : ReturnValue = SetErlValueNumber(std::acos(Operand(1).Number));
2033 2 : break;
2034 :
2035 2 : case ErlFunc::DegToRad:
2036 2 : ReturnValue = SetErlValueNumber(Operand(1).Number * Constant::DegToRad);
2037 2 : break;
2038 :
2039 2 : case ErlFunc::RadToDeg:
2040 2 : ReturnValue = SetErlValueNumber(Operand(1).Number / Constant::DegToRad);
2041 2 : break;
2042 :
2043 4079 : case ErlFunc::Exp:
2044 4079 : if ((Operand(1).Number < 700.0) && (Operand(1).Number > -20.0)) {
2045 4075 : ReturnValue = SetErlValueNumber(std::exp(Operand(1).Number));
2046 4 : } else if (Operand(1).Number <= -20.0) {
2047 2 : ReturnValue = SetErlValueNumber(0.0);
2048 : } else {
2049 : // throw Error
2050 : ReturnValue.Error =
2051 2 : format("EvaluateExpression: Attempted to calculate exponential value of too large a number: {:.4T}", Operand(1).Number);
2052 2 : ReturnValue.Type = Value::Error;
2053 2 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
2054 2 : seriousErrorFound = true;
2055 : }
2056 : }
2057 4079 : break;
2058 :
2059 4072 : case ErlFunc::Ln:
2060 4072 : if (Operand(1).Number > 0.0) {
2061 4072 : ReturnValue = SetErlValueNumber(std::log(Operand(1).Number));
2062 : } else {
2063 : // throw error,
2064 0 : ReturnValue.Type = Value::Error;
2065 0 : ReturnValue.Error = format("EvaluateExpression: Natural Log of zero or less! ln of value = {:.4T}", Operand(1).Number);
2066 0 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
2067 0 : seriousErrorFound = true;
2068 : }
2069 : }
2070 4072 : break;
2071 :
2072 2 : case ErlFunc::Max:
2073 2 : ReturnValue = SetErlValueNumber(max(Operand(1).Number, Operand(2).Number));
2074 2 : break;
2075 :
2076 20738 : case ErlFunc::Min:
2077 20738 : ReturnValue = SetErlValueNumber(min(Operand(1).Number, Operand(2).Number));
2078 20738 : break;
2079 :
2080 24810 : case ErlFunc::ABS:
2081 24810 : ReturnValue = SetErlValueNumber(std::abs(Operand(1).Number));
2082 24810 : break;
2083 :
2084 2 : case ErlFunc::RandU:
2085 2 : RANDOM_NUMBER(tmpRANDU1);
2086 2 : tmpRANDU1 = Operand(1).Number + (Operand(2).Number - Operand(1).Number) * tmpRANDU1;
2087 2 : ReturnValue = SetErlValueNumber(tmpRANDU1);
2088 2 : break;
2089 :
2090 2 : case ErlFunc::RandG:
2091 : while (true) { // Box-Muller algorithm
2092 2 : RANDOM_NUMBER(tmpRANDU1);
2093 2 : RANDOM_NUMBER(tmpRANDU2);
2094 2 : tmpRANDU1 = 2.0 * tmpRANDU1 - 1.0;
2095 2 : tmpRANDU2 = 2.0 * tmpRANDU2 - 1.0;
2096 2 : UnitCircleTest = square(tmpRANDU1) + square(tmpRANDU2);
2097 2 : if (UnitCircleTest > 0.0 && UnitCircleTest < 1.0) {
2098 2 : break;
2099 : }
2100 : }
2101 2 : tmpRANDG = std::sqrt(-2.0 * std::log(UnitCircleTest) / UnitCircleTest);
2102 2 : tmpRANDG *= tmpRANDU1; // standard normal ran
2103 : // x = ran * sigma + mean
2104 2 : tmpRANDG = tmpRANDG * Operand(2).Number + Operand(1).Number;
2105 2 : tmpRANDG = max(tmpRANDG, Operand(3).Number); // min limit
2106 2 : tmpRANDG = min(tmpRANDG, Operand(4).Number); // max limit
2107 2 : ReturnValue = SetErlValueNumber(tmpRANDG);
2108 2 : break;
2109 :
2110 2 : case ErlFunc::RandSeed:
2111 : // convert arg to an integer array for the seed.
2112 2 : RANDOM_SEED(SeedN); // obtains processor's use size as output
2113 2 : SeedIntARR.allocate(SeedN);
2114 6 : for (loop = 1; loop <= SeedN; ++loop) {
2115 4 : if (loop == 1) {
2116 2 : SeedIntARR(loop) = std::floor(Operand(1).Number);
2117 : } else {
2118 2 : SeedIntARR(loop) = std::floor(Operand(1).Number) * loop;
2119 : }
2120 : }
2121 2 : RANDOM_SEED(_, SeedIntARR);
2122 2 : ReturnValue = SetErlValueNumber(double(SeedIntARR(1))); // just return first number pass as seed
2123 2 : SeedIntARR.deallocate();
2124 2 : break;
2125 :
2126 4072 : case ErlFunc::RhoAirFnPbTdbW:
2127 12216 : ReturnValue = SetErlValueNumber(PsyRhoAirFnPbTdbW(state,
2128 4072 : Operand(1).Number,
2129 4072 : Operand(2).Number,
2130 4072 : Operand(3).Number,
2131 4072 : EMSBuiltInFunction)); // result => density of moist air (kg/m3) | pressure
2132 : // (Pa) | drybulb (C) | Humidity ratio (kg water
2133 : // vapor/kg dry air) | called from
2134 4072 : break;
2135 :
2136 2 : case ErlFunc::CpAirFnW:
2137 2 : ReturnValue = SetErlValueNumber(PsyCpAirFnW(Operand(1).Number)); // result => heat capacity of air
2138 : // {J/kg-C} | Humidity ratio (kg water vapor/kg dry air)
2139 2 : break;
2140 :
2141 2 : case ErlFunc::HfgAirFnWTdb:
2142 : // BG comment these two psych funct seems confusing (?) is this the enthalpy of water in the air?
2143 2 : ReturnValue = SetErlValueNumber(PsyHfgAirFnWTdb(Operand(1).Number, Operand(2).Number)); // result => heat of vaporization
2144 : // for moist air {J/kg} | Humidity
2145 : // ratio (kg water vapor/kg dry air) |
2146 : // drybulb (C)
2147 2 : break;
2148 :
2149 2 : case ErlFunc::HgAirFnWTdb:
2150 : // confusing ? seems like this is really classical Hfg, heat of vaporization
2151 2 : ReturnValue = SetErlValueNumber(PsyHgAirFnWTdb(Operand(1).Number, Operand(2).Number)); // result => enthalpy of the gas
2152 : // {units?} | Humidity ratio (kg water
2153 : // vapor/kg dry air) | drybulb (C)
2154 2 : break;
2155 :
2156 2 : case ErlFunc::TdpFnTdbTwbPb:
2157 6 : ReturnValue = SetErlValueNumber(
2158 : PsyTdpFnTdbTwbPb(state,
2159 2 : Operand(1).Number,
2160 2 : Operand(2).Number,
2161 2 : Operand(3).Number,
2162 2 : EMSBuiltInFunction)); // result => dew-point temperature {C} | drybulb (C) | wetbulb (C) | pressure (Pa)
2163 2 : break;
2164 :
2165 2 : case ErlFunc::TdpFnWPb:
2166 6 : ReturnValue = SetErlValueNumber(PsyTdpFnWPb(
2167 : state,
2168 2 : Operand(1).Number,
2169 2 : Operand(2).Number,
2170 2 : EMSBuiltInFunction)); // result => dew-point temperature {C} | Humidity ratio (kg water vapor/kg dry air) | pressure (Pa)
2171 2 : break;
2172 :
2173 16282 : case ErlFunc::HFnTdbW:
2174 48846 : ReturnValue = SetErlValueNumber(
2175 16282 : PsyHFnTdbW(Operand(1).Number,
2176 32564 : Operand(2).Number)); // result => enthalpy (J/kg) | drybulb (C) | Humidity ratio (kg water vapor/kg dry air)
2177 16282 : break;
2178 :
2179 2 : case ErlFunc::HFnTdbRhPb:
2180 6 : ReturnValue = SetErlValueNumber(PsyHFnTdbRhPb(
2181 : state,
2182 2 : Operand(1).Number,
2183 2 : Operand(2).Number,
2184 2 : Operand(3).Number,
2185 2 : EMSBuiltInFunction)); // result => enthalpy (J/kg) | drybulb (C) | relative humidity value (0.0 - 1.0) | pressure (Pa)
2186 2 : break;
2187 :
2188 28878 : case ErlFunc::TdbFnHW:
2189 86634 : ReturnValue = SetErlValueNumber(PsyTdbFnHW(
2190 28878 : Operand(1).Number,
2191 57756 : Operand(2).Number)); // result => dry-bulb temperature {C} | enthalpy (J/kg) | Humidity ratio (kg water vapor/kg dry air)
2192 28878 : break;
2193 :
2194 2 : case ErlFunc::RhovFnTdbRh:
2195 6 : ReturnValue = SetErlValueNumber(PsyRhovFnTdbRh(
2196 : state,
2197 2 : Operand(1).Number,
2198 2 : Operand(2).Number,
2199 2 : EMSBuiltInFunction)); // result => Vapor density in air (kg/m3) | drybulb (C) | relative humidity value (0.0 - 1.0)
2200 2 : break;
2201 :
2202 2 : case ErlFunc::RhovFnTdbRhLBnd0C:
2203 6 : ReturnValue = SetErlValueNumber(PsyRhovFnTdbRhLBnd0C(
2204 2 : Operand(1).Number,
2205 4 : Operand(2).Number)); // result => Vapor density in air (kg/m3) | drybulb (C) | relative humidity value (0.0 - 1.0)
2206 2 : break;
2207 :
2208 2 : case ErlFunc::RhovFnTdbWPb:
2209 6 : ReturnValue = SetErlValueNumber(
2210 4 : PsyRhovFnTdbWPb(Operand(1).Number, Operand(2).Number, Operand(3).Number)); // result => Vapor density in air (kg/m3) |
2211 : // drybulb (C) | Humidity ratio (kg water
2212 : // vapor/kg dry air) | pressure (Pa)
2213 2 : break;
2214 :
2215 2 : case ErlFunc::RhFnTdbRhov:
2216 6 : ReturnValue = SetErlValueNumber(
2217 : PsyRhFnTdbRhov(state,
2218 2 : Operand(1).Number,
2219 2 : Operand(2).Number,
2220 2 : EMSBuiltInFunction)); // result => relative humidity value (0.0-1.0) | drybulb (C) | vapor density in air (kg/m3)
2221 2 : break;
2222 :
2223 2 : case ErlFunc::RhFnTdbRhovLBnd0C:
2224 6 : ReturnValue = SetErlValueNumber(
2225 : PsyRhFnTdbRhovLBnd0C(state,
2226 2 : Operand(1).Number,
2227 2 : Operand(2).Number,
2228 2 : EMSBuiltInFunction)); // relative humidity value (0.0-1.0) | drybulb (C) | vapor density in air (kg/m3)
2229 2 : break;
2230 :
2231 2 : case ErlFunc::RhFnTdbWPb:
2232 6 : ReturnValue = SetErlValueNumber(PsyRhFnTdbWPb(state,
2233 2 : Operand(1).Number,
2234 2 : Operand(2).Number,
2235 2 : Operand(3).Number,
2236 2 : EMSBuiltInFunction)); // result => relative humidity value (0.0-1.0) | drybulb
2237 : // (C) | Humidity ratio (kg water vapor/kg dry air) |
2238 : // pressure (Pa)
2239 2 : break;
2240 :
2241 4072 : case ErlFunc::TwbFnTdbWPb:
2242 12216 : ReturnValue = SetErlValueNumber(PsyTwbFnTdbWPb(state,
2243 4072 : Operand(1).Number,
2244 4072 : Operand(2).Number,
2245 4072 : Operand(3).Number,
2246 4072 : EMSBuiltInFunction)); // result=> Temperature Wet-Bulb {C} | drybulb (C) |
2247 : // Humidity ratio (kg water vapor/kg dry air) | pressure
2248 : // (Pa)
2249 4072 : break;
2250 :
2251 2 : case ErlFunc::VFnTdbWPb:
2252 6 : ReturnValue = SetErlValueNumber(PsyVFnTdbWPb(state,
2253 2 : Operand(1).Number,
2254 2 : Operand(2).Number,
2255 2 : Operand(3).Number,
2256 2 : EMSBuiltInFunction)); // result=> specific volume {m3/kg} | drybulb (C) |
2257 : // Humidity ratio (kg water vapor/kg dry air) | pressure
2258 : // (Pa)
2259 2 : break;
2260 :
2261 2 : case ErlFunc::WFnTdpPb:
2262 6 : ReturnValue = SetErlValueNumber(PsyWFnTdpPb(
2263 : state,
2264 2 : Operand(1).Number,
2265 2 : Operand(2).Number,
2266 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) | dew point temperature (C) | pressure (Pa)
2267 2 : break;
2268 :
2269 8142 : case ErlFunc::WFnTdbH:
2270 24426 : ReturnValue = SetErlValueNumber(
2271 : PsyWFnTdbH(state,
2272 8142 : Operand(1).Number,
2273 8142 : Operand(2).Number,
2274 8142 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) | drybulb (C) | enthalpy (J/kg)
2275 8142 : break;
2276 :
2277 2 : case ErlFunc::WFnTdbTwbPb:
2278 6 : ReturnValue = SetErlValueNumber(PsyWFnTdbTwbPb(state,
2279 2 : Operand(1).Number,
2280 2 : Operand(2).Number,
2281 2 : Operand(3).Number,
2282 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) |
2283 : // drybulb (C) | wet-bulb temperature {C} | pressure (Pa)
2284 2 : break;
2285 :
2286 2 : case ErlFunc::WFnTdbRhPb:
2287 6 : ReturnValue = SetErlValueNumber(PsyWFnTdbRhPb(state,
2288 2 : Operand(1).Number,
2289 2 : Operand(2).Number,
2290 2 : Operand(3).Number,
2291 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) |
2292 : // drybulb (C) | relative humidity value (0.0-1.0) |
2293 : // pressure (Pa)
2294 2 : break;
2295 :
2296 2 : case ErlFunc::PsatFnTemp:
2297 6 : ReturnValue = SetErlValueNumber(
2298 4 : PsyPsatFnTemp(state, Operand(1).Number, EMSBuiltInFunction)); // result=> saturation pressure {Pascals} | drybulb (C)
2299 2 : break;
2300 :
2301 4072 : case ErlFunc::TsatFnHPb:
2302 : ReturnValue =
2303 12216 : SetErlValueNumber(PsyTsatFnHPb(state,
2304 4072 : Operand(1).Number,
2305 4072 : Operand(2).Number,
2306 4072 : EMSBuiltInFunction)); // result=> saturation temperature {C} | enthalpy {J/kg} | pressure (Pa)
2307 4072 : break;
2308 :
2309 : // I'm not sure why FuncTsatFnPb was commented out, but it goes all the way back to the Fortran implementation, so it's staying like that
2310 : // for now.
2311 : // CASE (FuncTsatFnPb)
2312 : // ReturnValue = NumberValue( & ! result=> saturation temperature {C}
2313 : // PsyTsatFnPb(Operand(1)%Number, & ! pressure (Pa)
2314 : // 'EMS Built-In Function') )
2315 2 : case ErlFunc::CpCW:
2316 : ReturnValue =
2317 2 : SetErlValueNumber(CPCW(Operand(1).Number)); // result => specific heat of water (J/kg-K) = 4180.d0 | temperature (C) unused
2318 2 : break;
2319 :
2320 2 : case ErlFunc::CpHW:
2321 : ReturnValue =
2322 2 : SetErlValueNumber(CPHW(Operand(1).Number)); // result => specific heat of water (J/kg-K) = 4180.d0 | temperature (C) unused
2323 2 : break;
2324 :
2325 2 : case ErlFunc::RhoH2O:
2326 2 : ReturnValue = SetErlValueNumber(RhoH2O(Operand(1).Number)); // result => density of water (kg/m3) | temperature (C)
2327 2 : break;
2328 :
2329 0 : case ErlFunc::FatalHaltEp:
2330 0 : ShowSevereError(state, "EMS user program found serious problem and is halting simulation");
2331 0 : ShowContinueErrorTimeStamp(state, "");
2332 0 : ShowFatalError(state, format("EMS user program halted simulation with error code = {:.2T}", Operand(1).Number));
2333 0 : ReturnValue = SetErlValueNumber(Operand(1).Number); // returns back the error code
2334 0 : break;
2335 :
2336 2 : case ErlFunc::SevereWarnEp:
2337 2 : ShowSevereError(state, format("EMS user program issued severe warning with error code = {:.2T}", Operand(1).Number));
2338 4 : ShowContinueErrorTimeStamp(state, "");
2339 2 : ReturnValue = SetErlValueNumber(Operand(1).Number); // returns back the error code
2340 2 : break;
2341 :
2342 2 : case ErlFunc::WarnEp:
2343 2 : ShowWarningError(state, format("EMS user program issued warning with error code = {:.2T}", Operand(1).Number));
2344 4 : ShowContinueErrorTimeStamp(state, "");
2345 2 : ReturnValue = SetErlValueNumber(Operand(1).Number); // returns back the error code
2346 2 : break;
2347 :
2348 8 : case ErlFunc::TrendValue:
2349 : // find TrendVariable , first operand is ErlVariable
2350 8 : if (Operand(1).TrendVariable) {
2351 8 : thisTrend = Operand(1).TrendVarPointer;
2352 : // second operand is number for index
2353 8 : thisIndex = std::floor(Operand(2).Number);
2354 8 : if (thisIndex >= 1) {
2355 8 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2356 8 : ReturnValue = SetErlValueNumber(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(thisIndex), Operand(1));
2357 : } else {
2358 0 : ReturnValue.Type = Value::Error;
2359 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2360 : }
2361 : } else {
2362 0 : ReturnValue.Type = Value::Error;
2363 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2364 : }
2365 : } else { // not registered as a trend variable
2366 0 : ReturnValue.Type = Value::Error;
2367 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2368 : }
2369 8 : break;
2370 :
2371 4 : case ErlFunc::TrendAverage:
2372 : // find TrendVariable , first operand is ErlVariable
2373 4 : if (Operand(1).TrendVariable) {
2374 4 : thisTrend = Operand(1).TrendVarPointer;
2375 4 : thisIndex = std::floor(Operand(2).Number);
2376 4 : if (thisIndex >= 1) {
2377 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2378 : // calculate average
2379 4 : thisAverage = sum(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})) / double(thisIndex);
2380 4 : ReturnValue = SetErlValueNumber(thisAverage, Operand(1));
2381 : } else {
2382 0 : ReturnValue.Type = Value::Error;
2383 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2384 : }
2385 : } else {
2386 0 : ReturnValue.Type = Value::Error;
2387 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2388 : }
2389 : } else { // not registered as a trend variable
2390 0 : ReturnValue.Type = Value::Error;
2391 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2392 : }
2393 4 : break;
2394 :
2395 4 : case ErlFunc::TrendMax:
2396 4 : if (Operand(1).TrendVariable) {
2397 4 : thisTrend = Operand(1).TrendVarPointer;
2398 4 : thisIndex = std::floor(Operand(2).Number);
2399 4 : if (thisIndex >= 1) {
2400 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2401 4 : thisMax = 0.0;
2402 4 : if (thisIndex == 1) {
2403 0 : thisMax = state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1);
2404 : } else {
2405 16 : for (loop = 2; loop <= thisIndex; ++loop) {
2406 12 : if (loop == 2) {
2407 4 : thisMax = max(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1),
2408 4 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(2));
2409 : } else {
2410 8 : thisMax = max(thisMax, state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(loop));
2411 : }
2412 : }
2413 : }
2414 4 : ReturnValue = SetErlValueNumber(thisMax, Operand(1));
2415 : } else {
2416 0 : ReturnValue.Type = Value::Error;
2417 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2418 : }
2419 : } else {
2420 0 : ReturnValue.Type = Value::Error;
2421 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2422 : }
2423 : } else { // not registered as a trend variable
2424 0 : ReturnValue.Type = Value::Error;
2425 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2426 : }
2427 4 : break;
2428 :
2429 4 : case ErlFunc::TrendMin:
2430 4 : if (Operand(1).TrendVariable) {
2431 4 : thisTrend = Operand(1).TrendVarPointer;
2432 4 : thisIndex = std::floor(Operand(2).Number);
2433 4 : if (thisIndex >= 1) {
2434 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2435 4 : thisMin = 0.0;
2436 4 : if (thisIndex == 1) {
2437 0 : thisMin = state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1);
2438 : } else {
2439 16 : for (loop = 2; loop <= thisIndex; ++loop) {
2440 12 : if (loop == 2) {
2441 4 : thisMin = min(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1),
2442 4 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(2));
2443 : } else {
2444 8 : thisMin = min(thisMin, state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(loop));
2445 : }
2446 : }
2447 : }
2448 4 : ReturnValue = SetErlValueNumber(thisMin, Operand(1));
2449 :
2450 : } else {
2451 0 : ReturnValue.Type = Value::Error;
2452 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2453 : }
2454 :
2455 : } else {
2456 0 : ReturnValue.Type = Value::Error;
2457 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2458 : }
2459 : } else { // not registered as a trend variable
2460 0 : ReturnValue.Type = Value::Error;
2461 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2462 : }
2463 4 : break;
2464 :
2465 4 : case ErlFunc::TrendDirection:
2466 4 : if (Operand(1).TrendVariable) {
2467 : // do a linear least squares fit and get slope of line
2468 4 : thisTrend = Operand(1).TrendVarPointer;
2469 4 : thisIndex = std::floor(Operand(2).Number);
2470 4 : if (thisIndex >= 1) {
2471 :
2472 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2473 : // closed form solution for slope of linear least squares fit
2474 4 : thisSlope = (sum(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex})) *
2475 8 : sum(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})) -
2476 8 : thisIndex * sum((state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}) *
2477 8 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})))) /
2478 8 : (pow_2(sum(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}))) -
2479 4 : thisIndex * sum(pow(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}), 2)));
2480 4 : ReturnValue = SetErlValueNumber(thisSlope, Operand(1)); // rate of change per hour
2481 : } else {
2482 0 : ReturnValue.Type = Value::Error;
2483 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2484 : }
2485 :
2486 : } else {
2487 0 : ReturnValue.Type = Value::Error;
2488 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2489 : }
2490 : } else { // not registered as a trend variable
2491 0 : ReturnValue.Type = Value::Error;
2492 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2493 : }
2494 4 : break;
2495 :
2496 4 : case ErlFunc::TrendSum:
2497 4 : if (Operand(1).TrendVariable) {
2498 :
2499 4 : thisTrend = Operand(1).TrendVarPointer;
2500 4 : thisIndex = std::floor(Operand(2).Number);
2501 4 : if (thisIndex >= 1) {
2502 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2503 : ReturnValue =
2504 4 : SetErlValueNumber(sum(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})), Operand(1));
2505 : } else {
2506 0 : ReturnValue.Type = Value::Error;
2507 0 : ReturnValue.Error = "Built-in trend function called with index larger than what is being logged";
2508 : }
2509 : } else {
2510 0 : ReturnValue.Type = Value::Error;
2511 0 : ReturnValue.Error = "Built-in trend function called with index less than 1";
2512 : }
2513 : } else { // not registered as a trend variable
2514 0 : ReturnValue.Type = Value::Error;
2515 0 : ReturnValue.Error = "Variable used with built-in trend function is not associated with a registered trend variable";
2516 : }
2517 4 : break;
2518 :
2519 20352 : case ErlFunc::CurveValue:
2520 20354 : if (Operand(3).Type == Value::Null && Operand(4).Type == Value::Null && Operand(5).Type == Value::Null &&
2521 2 : Operand(6).Type == Value::Null) {
2522 : ReturnValue =
2523 2 : SetErlValueNumber(CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number)); // curve index | X value | Y
2524 : // value, 2nd independent | Z
2525 : // Value, 3rd independent | 4th
2526 : // independent | 5th independent
2527 20350 : } else if (Operand(4).Type == Value::Null && Operand(5).Type == Value::Null && Operand(6).Type == Value::Null) {
2528 0 : Real64 curveVal = 0.0;
2529 0 : switch (state.dataCurveManager->curves(std::floor(Operand(1).Number))->numDims) {
2530 0 : case 1:
2531 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number);
2532 0 : break;
2533 0 : case 2:
2534 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number);
2535 0 : break;
2536 : }
2537 0 : ReturnValue = SetErlValueNumber(curveVal);
2538 20350 : } else if (Operand(5).Type == Value::Null && Operand(6).Type == Value::Null) {
2539 20350 : Real64 curveVal = 0.0;
2540 20350 : switch (state.dataCurveManager->curves(std::floor(Operand(1).Number))->numDims) {
2541 12210 : case 1:
2542 12210 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number);
2543 12210 : break;
2544 8140 : case 2:
2545 8140 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number);
2546 8140 : break;
2547 0 : case 3:
2548 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number, Operand(4).Number);
2549 0 : break;
2550 : }
2551 20350 : ReturnValue = SetErlValueNumber(curveVal);
2552 0 : } else if (Operand(6).Type == Value::Null) {
2553 0 : Real64 curveVal = 0.0;
2554 0 : switch (state.dataCurveManager->curves(std::floor(Operand(1).Number))->numDims) {
2555 0 : case 1:
2556 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number);
2557 0 : break;
2558 0 : case 2:
2559 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number);
2560 0 : break;
2561 0 : case 3:
2562 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number, Operand(4).Number);
2563 0 : break;
2564 0 : case 4:
2565 0 : curveVal = CurveValue(
2566 0 : state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number, Operand(4).Number, Operand(5).Number);
2567 0 : break;
2568 : }
2569 0 : ReturnValue = SetErlValueNumber(curveVal);
2570 : } else {
2571 0 : Real64 curveVal = 0.0;
2572 0 : switch (state.dataCurveManager->curves(std::floor(Operand(1).Number))->numDims) {
2573 0 : case 1:
2574 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number);
2575 0 : break;
2576 0 : case 2:
2577 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number);
2578 0 : break;
2579 0 : case 3:
2580 0 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number, Operand(4).Number);
2581 0 : break;
2582 0 : case 4:
2583 0 : curveVal = CurveValue(
2584 0 : state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number, Operand(4).Number, Operand(5).Number);
2585 0 : break;
2586 0 : case 5:
2587 0 : curveVal = CurveValue(state,
2588 0 : std::floor(Operand(1).Number),
2589 0 : Operand(2).Number,
2590 0 : Operand(3).Number,
2591 0 : Operand(4).Number,
2592 0 : Operand(5).Number,
2593 0 : Operand(6).Number);
2594 0 : break;
2595 : }
2596 0 : ReturnValue = SetErlValueNumber(curveVal);
2597 : }
2598 20352 : break;
2599 :
2600 14 : case ErlFunc::TodayIsRain:
2601 : case ErlFunc::TodayIsSnow:
2602 : case ErlFunc::TodayOutDryBulbTemp:
2603 : case ErlFunc::TodayOutDewPointTemp:
2604 : case ErlFunc::TodayOutBaroPress:
2605 : case ErlFunc::TodayOutRelHum:
2606 : case ErlFunc::TodayWindSpeed:
2607 : case ErlFunc::TodayWindDir:
2608 : case ErlFunc::TodaySkyTemp:
2609 : case ErlFunc::TodayHorizIRSky:
2610 : case ErlFunc::TodayBeamSolarRad:
2611 : case ErlFunc::TodayDifSolarRad:
2612 : case ErlFunc::TodayAlbedo:
2613 : case ErlFunc::TodayLiquidPrecip: {
2614 14 : int iHour = (Operand(1).Number + 1); // Operand 1 is hour from 0:23
2615 14 : int iTimeStep = Operand(2).Number;
2616 14 : if ((iHour > 0) && (iHour <= 24) && (iTimeStep > 0) && (iTimeStep <= state.dataGlobal->TimeStepsInHour)) {
2617 14 : auto const &today = state.dataWeather->wvarsHrTsToday(iTimeStep, iHour);
2618 14 : ReturnValue.initialized = true;
2619 14 : ReturnValue.Type = Value::Number;
2620 14 : switch (thisErlExpression.Operator) {
2621 1 : case ErlFunc::TodayIsRain: {
2622 1 : ReturnValue.Number = today.IsRain ? 1.0 : 0.0;
2623 1 : } break;
2624 1 : case ErlFunc::TodayIsSnow: {
2625 1 : ReturnValue.Number = today.IsSnow ? 1.0 : 0.0;
2626 1 : } break;
2627 1 : case ErlFunc::TodayOutDryBulbTemp: {
2628 1 : ReturnValue.Number = today.OutDryBulbTemp;
2629 1 : } break;
2630 1 : case ErlFunc::TodayOutDewPointTemp: {
2631 1 : ReturnValue.Number = today.OutDewPointTemp;
2632 1 : } break;
2633 1 : case ErlFunc::TodayOutBaroPress: {
2634 1 : ReturnValue.Number = today.OutBaroPress;
2635 1 : } break;
2636 1 : case ErlFunc::TodayOutRelHum: {
2637 1 : ReturnValue.Number = today.OutRelHum;
2638 1 : } break;
2639 1 : case ErlFunc::TodayWindSpeed: {
2640 1 : ReturnValue.Number = today.WindSpeed;
2641 1 : } break;
2642 1 : case ErlFunc::TodayWindDir: {
2643 1 : ReturnValue.Number = today.WindDir;
2644 1 : } break;
2645 1 : case ErlFunc::TodaySkyTemp: {
2646 1 : ReturnValue.Number = today.SkyTemp;
2647 1 : } break;
2648 1 : case ErlFunc::TodayHorizIRSky: {
2649 1 : ReturnValue.Number = today.HorizIRSky;
2650 1 : } break;
2651 1 : case ErlFunc::TodayBeamSolarRad: {
2652 1 : ReturnValue.Number = today.BeamSolarRad;
2653 1 : } break;
2654 1 : case ErlFunc::TodayDifSolarRad: {
2655 1 : ReturnValue.Number = today.DifSolarRad;
2656 1 : } break;
2657 1 : case ErlFunc::TodayAlbedo: {
2658 1 : ReturnValue.Number = today.Albedo;
2659 1 : } break;
2660 1 : case ErlFunc::TodayLiquidPrecip: {
2661 1 : ReturnValue.Number = today.LiquidPrecip;
2662 1 : } break;
2663 0 : default: {
2664 0 : assert(false);
2665 : } break;
2666 : }
2667 : } else {
2668 0 : ReturnValue.Type = DataRuntimeLanguage::Value::Error;
2669 0 : ReturnValue.Error = format("{} function called with invalid arguments: Hour={:.1R}, Timestep={:.1R}",
2670 0 : ErlFuncNamesUC[(int)thisErlExpression.Operator],
2671 0 : Operand(1).Number,
2672 0 : Operand(2).Number);
2673 : }
2674 14 : } break;
2675 :
2676 14 : case ErlFunc::TomorrowIsRain:
2677 : case ErlFunc::TomorrowIsSnow:
2678 : case ErlFunc::TomorrowOutDryBulbTemp:
2679 : case ErlFunc::TomorrowOutDewPointTemp:
2680 : case ErlFunc::TomorrowOutBaroPress:
2681 : case ErlFunc::TomorrowOutRelHum:
2682 : case ErlFunc::TomorrowWindSpeed:
2683 : case ErlFunc::TomorrowWindDir:
2684 : case ErlFunc::TomorrowSkyTemp:
2685 : case ErlFunc::TomorrowHorizIRSky:
2686 : case ErlFunc::TomorrowBeamSolarRad:
2687 : case ErlFunc::TomorrowDifSolarRad:
2688 : case ErlFunc::TomorrowAlbedo:
2689 : case ErlFunc::TomorrowLiquidPrecip: {
2690 14 : int iHour = (Operand(1).Number + 1); // Operand 1 is hour from 0:23
2691 14 : int iTimeStep = Operand(2).Number;
2692 14 : if ((iHour > 0) && (iHour <= Constant::iHoursInDay) && (iTimeStep > 0) && (iTimeStep <= state.dataGlobal->TimeStepsInHour)) {
2693 14 : auto const &tomorrow = state.dataWeather->wvarsHrTsTomorrow(iTimeStep, iHour);
2694 14 : ReturnValue.initialized = true;
2695 14 : ReturnValue.Type = Value::Number;
2696 14 : switch (thisErlExpression.Operator) {
2697 1 : case ErlFunc::TomorrowIsRain: {
2698 1 : ReturnValue.Number = tomorrow.IsRain ? 1.0 : 0.0;
2699 1 : } break;
2700 1 : case ErlFunc::TomorrowIsSnow: {
2701 1 : ReturnValue.Number = tomorrow.IsSnow ? 1.0 : 0.0;
2702 1 : } break;
2703 1 : case ErlFunc::TomorrowOutDryBulbTemp: {
2704 1 : ReturnValue.Number = tomorrow.OutDryBulbTemp;
2705 1 : } break;
2706 1 : case ErlFunc::TomorrowOutDewPointTemp: {
2707 1 : ReturnValue.Number = tomorrow.OutDewPointTemp;
2708 1 : } break;
2709 1 : case ErlFunc::TomorrowOutBaroPress: {
2710 1 : ReturnValue.Number = tomorrow.OutBaroPress;
2711 1 : } break;
2712 1 : case ErlFunc::TomorrowOutRelHum: {
2713 1 : ReturnValue.Number = tomorrow.OutRelHum;
2714 1 : } break;
2715 1 : case ErlFunc::TomorrowWindSpeed: {
2716 1 : ReturnValue.Number = tomorrow.WindSpeed;
2717 1 : } break;
2718 1 : case ErlFunc::TomorrowWindDir: {
2719 1 : ReturnValue.Number = tomorrow.WindDir;
2720 1 : } break;
2721 1 : case ErlFunc::TomorrowSkyTemp: {
2722 1 : ReturnValue.Number = tomorrow.SkyTemp;
2723 1 : } break;
2724 1 : case ErlFunc::TomorrowHorizIRSky: {
2725 1 : ReturnValue.Number = tomorrow.HorizIRSky;
2726 1 : } break;
2727 1 : case ErlFunc::TomorrowBeamSolarRad: {
2728 1 : ReturnValue.Number = tomorrow.BeamSolarRad;
2729 1 : } break;
2730 1 : case ErlFunc::TomorrowDifSolarRad: {
2731 1 : ReturnValue.Number = tomorrow.DifSolarRad;
2732 1 : } break;
2733 1 : case ErlFunc::TomorrowAlbedo: {
2734 1 : ReturnValue.Number = tomorrow.Albedo;
2735 1 : } break;
2736 1 : case ErlFunc::TomorrowLiquidPrecip: {
2737 1 : ReturnValue.Number = tomorrow.LiquidPrecip;
2738 1 : } break;
2739 0 : default: {
2740 0 : assert(false);
2741 : } break;
2742 : }
2743 : } else {
2744 0 : ReturnValue.Type = DataRuntimeLanguage::Value::Error;
2745 0 : ReturnValue.Error = format("{} function called with invalid arguments: Hour={:.1R}, Timestep={:.1R}",
2746 0 : ErlFuncNamesUC[(int)thisErlExpression.Operator],
2747 0 : Operand(1).Number,
2748 0 : Operand(2).Number);
2749 : }
2750 14 : } break;
2751 :
2752 0 : case ErlFunc::Invalid:
2753 : case ErlFunc::Null:
2754 : case ErlFunc::TsatFnPb:
2755 : case ErlFunc::Num: {
2756 : // throw Error, these cases are not supported -- they all make sense except TsatFnPb which was commented out above a long time ago
2757 0 : ShowFatalError(state, "caught unexpected Expression(ExpressionNum)%Operator in EvaluateExpression");
2758 0 : } break;
2759 : } // switch (FunctionCode)
2760 : }
2761 1054238 : Operand.deallocate();
2762 : }
2763 :
2764 2108476 : return ReturnValue;
2765 1054238 : }
2766 :
2767 47 : void GetRuntimeLanguageUserInput(EnergyPlusData &state)
2768 : {
2769 :
2770 : // SUBROUTINE INFORMATION:
2771 : // AUTHOR Peter Graham Ellis
2772 : // DATE WRITTEN June 2006
2773 : // MODIFIED Brent Griffith April 2009
2774 : // RE-ENGINEERED na
2775 :
2776 : // PURPOSE OF THIS SUBROUTINE:
2777 : // Gets the runtime language objects from the input file.
2778 : // GetInput is called from other modules that reference runtime language objects.
2779 : // The runtime language objects are all loaded in one pass
2780 :
2781 : // METHODOLOGY EMPLOYED:
2782 : // The runtime language objects are all loaded in one step, names registered, etc. They are parsed in a second step
2783 : // once all the object names are known.
2784 :
2785 : // Using/Aliasing
2786 : using Curve::GetCurveIndex;
2787 :
2788 : // Locals
2789 : // SUBROUTINE PARAMETER DEFINITIONS:
2790 47 : constexpr std::string_view RoutineName = "GetRuntimeLanguageUserInput: ";
2791 :
2792 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2793 : int GlobalNum;
2794 : int StackNum;
2795 : int ErrorNum;
2796 : int NumAlphas; // Number of elements in the alpha array
2797 : int NumNums; // Number of elements in the numeric array
2798 : int IOStat; // IO Status when calling get input subroutine
2799 47 : bool ErrorsFound(false);
2800 47 : int VariableNum(0); // temporary
2801 : int RuntimeReportVarNum;
2802 : bool Found;
2803 : OutputProcessor::TimeStepType sovTimeStepType; // temporary
2804 : OutputProcessor::StoreType sovStoreType; // temporary
2805 47 : std::string EndUseSubCatString;
2806 :
2807 : int TrendNum;
2808 : int NumTrendSteps;
2809 : int loop;
2810 : int ErlVarLoop;
2811 : int CurveIndexNum;
2812 47 : int MaxNumAlphas(0); // argument for call to GetObjectDefMaxArgs
2813 47 : int MaxNumNumbers(0); // argument for call to GetObjectDefMaxArgs
2814 47 : int TotalArgs(0); // argument for call to GetObjectDefMaxArgs
2815 47 : Array1D_string cAlphaFieldNames;
2816 47 : Array1D_string cNumericFieldNames;
2817 47 : Array1D_bool lNumericFieldBlanks;
2818 47 : Array1D_bool lAlphaFieldBlanks;
2819 47 : Array1D_string cAlphaArgs;
2820 47 : Array1D<Real64> rNumericArgs;
2821 47 : std::string cCurrentModuleObject;
2822 : int ConstructNum;
2823 : bool errFlag;
2824 : std::string::size_type lbracket;
2825 47 : std::string UnitsA;
2826 47 : std::string UnitsB;
2827 47 : Constant::Units curUnit(Constant::Units::None);
2828 : std::string::size_type ptr;
2829 :
2830 47 : if (state.dataRuntimeLangProcessor->GetInput) { // GetInput check is redundant with the InitializeRuntimeLanguage routine
2831 47 : state.dataRuntimeLangProcessor->GetInput = false;
2832 :
2833 47 : cCurrentModuleObject = "EnergyManagementSystem:Sensor";
2834 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2835 47 : MaxNumNumbers = NumNums;
2836 47 : MaxNumAlphas = NumAlphas;
2837 47 : cCurrentModuleObject = "EnergyManagementSystem:Actuator";
2838 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2839 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2840 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2841 47 : cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
2842 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2843 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2844 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2845 47 : cCurrentModuleObject = "EnergyManagementSystem:Program";
2846 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2847 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2848 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2849 47 : cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
2850 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2851 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2852 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2853 47 : cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
2854 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2855 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2856 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2857 47 : cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
2858 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2859 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2860 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2861 47 : cCurrentModuleObject = "ExternalInterface:Variable";
2862 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2863 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2864 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2865 47 : cCurrentModuleObject = "ExternalInterface:Actuator";
2866 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2867 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2868 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2869 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
2870 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2871 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2872 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2873 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
2874 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2875 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2876 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2877 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
2878 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2879 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2880 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2881 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
2882 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2883 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2884 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2885 : // cCurrentModuleObject = 'EnergyManagementSystem:Sensor'
2886 : // CALL state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(cCurrentModuleObject,TotalArgs,NumAlphas,NumNums)
2887 : // MaxNumNumbers=MAX(MaxNumNumbers,NumNums)
2888 : // MaxNumAlphas=MAX(MaxNumAlphas,NumAlphas)
2889 47 : cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
2890 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2891 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2892 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2893 47 : cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
2894 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2895 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2896 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2897 47 : cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
2898 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2899 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2900 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2901 :
2902 47 : cAlphaFieldNames.allocate(MaxNumAlphas);
2903 47 : cAlphaArgs.allocate(MaxNumAlphas);
2904 47 : lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
2905 47 : cNumericFieldNames.allocate(MaxNumNumbers);
2906 47 : rNumericArgs.dimension(MaxNumNumbers, 0.0);
2907 47 : lNumericFieldBlanks.dimension(MaxNumNumbers, false);
2908 :
2909 47 : cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
2910 :
2911 47 : if (state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2912 47 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
2913 47 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables >
2914 : 0) {
2915 57 : for (GlobalNum = 1;
2916 57 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2917 57 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
2918 57 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables;
2919 : ++GlobalNum) {
2920 : // If we process the ExternalInterface actuators, all we need to do is to change the
2921 : // name of the module object, and add an offset for the variable number
2922 : // This is done in the following IF/THEN section.
2923 33 : if (GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables) {
2924 33 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2925 : cCurrentModuleObject,
2926 : GlobalNum,
2927 : cAlphaArgs,
2928 : NumAlphas,
2929 : rNumericArgs,
2930 : NumNums,
2931 : IOStat,
2932 : lNumericFieldBlanks,
2933 : lAlphaFieldBlanks,
2934 : cAlphaFieldNames,
2935 : cNumericFieldNames);
2936 0 : } else if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables &&
2937 0 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables) {
2938 0 : cCurrentModuleObject = "ExternalInterface:Variable";
2939 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2940 : cCurrentModuleObject,
2941 0 : GlobalNum - state.dataRuntimeLang->NumUserGlobalVariables,
2942 : cAlphaArgs,
2943 : NumAlphas,
2944 : rNumericArgs,
2945 : NumNums,
2946 : IOStat,
2947 : lNumericFieldBlanks,
2948 : lAlphaFieldBlanks,
2949 : cAlphaFieldNames,
2950 : cNumericFieldNames);
2951 0 : } else if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables &&
2952 0 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2953 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables) {
2954 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
2955 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2956 : cCurrentModuleObject,
2957 0 : GlobalNum - state.dataRuntimeLang->NumUserGlobalVariables -
2958 0 : state.dataRuntimeLang->NumExternalInterfaceGlobalVariables,
2959 : cAlphaArgs,
2960 : NumAlphas,
2961 : rNumericArgs,
2962 : NumNums,
2963 : IOStat,
2964 : lNumericFieldBlanks,
2965 : lAlphaFieldBlanks,
2966 : cAlphaFieldNames,
2967 : cNumericFieldNames);
2968 :
2969 0 : } else if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2970 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables &&
2971 0 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2972 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
2973 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables) {
2974 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
2975 0 : state.dataInputProcessing->inputProcessor->getObjectItem(
2976 : state,
2977 : cCurrentModuleObject,
2978 0 : GlobalNum - state.dataRuntimeLang->NumUserGlobalVariables - state.dataRuntimeLang->NumExternalInterfaceGlobalVariables -
2979 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables,
2980 : cAlphaArgs,
2981 : NumAlphas,
2982 : rNumericArgs,
2983 : NumNums,
2984 : IOStat,
2985 : lNumericFieldBlanks,
2986 : lAlphaFieldBlanks,
2987 : cAlphaFieldNames,
2988 : cNumericFieldNames);
2989 : }
2990 :
2991 : // loop over each alpha and register variable named as global Erl variable
2992 86 : for (ErlVarLoop = 1; ErlVarLoop <= NumAlphas; ++ErlVarLoop) {
2993 53 : if ((cCurrentModuleObject.compare("ExternalInterface:FunctionalMockupUnitImport:To:Variable") == 0)) {
2994 0 : if (ErlVarLoop == 1) {
2995 : // Only validate first field of object ExternalInterface:FunctionalMockupUnitImport:To:Variable.
2996 : // This object is allowed to contain fields that do not need to be valid EMS fields (e.g. path to the FMU).
2997 0 : ValidateEMSVariableName(
2998 0 : state, cCurrentModuleObject, cAlphaArgs(ErlVarLoop), cAlphaFieldNames(ErlVarLoop), errFlag, ErrorsFound);
2999 : }
3000 : } else {
3001 53 : ValidateEMSVariableName(
3002 53 : state, cCurrentModuleObject, cAlphaArgs(ErlVarLoop), cAlphaFieldNames(ErlVarLoop), errFlag, ErrorsFound);
3003 : }
3004 53 : if (lAlphaFieldBlanks(ErlVarLoop)) {
3005 0 : ShowWarningError(state, format("{}{}", RoutineName, cCurrentModuleObject));
3006 0 : ShowContinueError(state, format("Blank {}", cAlphaFieldNames(1)));
3007 0 : ShowContinueError(state, "Blank entry will be skipped, and the simulation continues");
3008 53 : } else if (!errFlag) {
3009 53 : VariableNum = FindEMSVariable(state, cAlphaArgs(ErlVarLoop), 0);
3010 : // Still need to check for conflicts with program and function names too
3011 :
3012 53 : if (VariableNum > 0) {
3013 0 : ShowSevereError(state, format("{}{}, invalid entry.", RoutineName, cCurrentModuleObject));
3014 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(ErlVarLoop), cAlphaArgs(ErlVarLoop)));
3015 0 : ShowContinueError(state, "Name conflicts with an existing global variable name");
3016 0 : ErrorsFound = true;
3017 : } else {
3018 53 : VariableNum = NewEMSVariable(state, cAlphaArgs(ErlVarLoop), 0);
3019 53 : if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables) {
3020 : // Initialize variables for the ExternalInterface variables.
3021 : // This object requires an initial value.
3022 0 : ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false);
3023 : }
3024 : }
3025 : }
3026 : }
3027 : }
3028 : }
3029 :
3030 47 : cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
3031 47 : state.dataRuntimeLang->NumEMSCurveIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3032 47 : if (state.dataRuntimeLang->NumEMSCurveIndices > 0) {
3033 1 : state.dataRuntimeLangProcessor->CurveIndexVariableNums.dimension(state.dataRuntimeLang->NumEMSCurveIndices, 0);
3034 6 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSCurveIndices; ++loop) {
3035 5 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3036 : cCurrentModuleObject,
3037 : loop,
3038 : cAlphaArgs,
3039 : NumAlphas,
3040 : rNumericArgs,
3041 : NumNums,
3042 : IOStat,
3043 : lNumericFieldBlanks,
3044 : lAlphaFieldBlanks,
3045 : cAlphaFieldNames,
3046 : cNumericFieldNames);
3047 :
3048 : // check if variable name is unique and well formed
3049 5 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
3050 5 : if (lAlphaFieldBlanks(1)) {
3051 0 : ShowSevereError(state, format("{}{}", RoutineName, cCurrentModuleObject));
3052 0 : ShowContinueError(state, format("Blank {}", cAlphaFieldNames(1)));
3053 0 : ShowContinueError(state, "Blank entry for Erl variable name is not allowed");
3054 0 : ErrorsFound = true;
3055 5 : } else if (!errFlag) {
3056 5 : VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0);
3057 5 : if (VariableNum > 0) {
3058 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3059 0 : ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1)));
3060 0 : ShowContinueError(state, "Name conflicts with an existing variable name");
3061 0 : ErrorsFound = true;
3062 : } else {
3063 : // create new EMS variable
3064 5 : VariableNum = NewEMSVariable(state, cAlphaArgs(1), 0);
3065 : // store variable num
3066 5 : state.dataRuntimeLangProcessor->CurveIndexVariableNums(loop) = VariableNum;
3067 : }
3068 : }
3069 :
3070 5 : CurveIndexNum = GetCurveIndex(state, cAlphaArgs(2)); // curve name
3071 5 : if (CurveIndexNum == 0) {
3072 0 : if (lAlphaFieldBlanks(2)) {
3073 0 : ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3074 0 : ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2)));
3075 0 : ShowContinueError(state, "Blank entry for curve or table name is not allowed");
3076 : } else {
3077 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3078 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3079 0 : ShowContinueError(state, "Curve or table was not found.");
3080 : }
3081 0 : ErrorsFound = true;
3082 : } else {
3083 : // fill Erl variable with curve index
3084 5 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = SetErlValueNumber(double(CurveIndexNum));
3085 : }
3086 : }
3087 :
3088 : } // NumEMSCurveIndices > 0
3089 :
3090 47 : cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
3091 47 : state.dataRuntimeLang->NumEMSConstructionIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3092 47 : if (state.dataRuntimeLang->NumEMSConstructionIndices > 0) {
3093 2 : state.dataRuntimeLangProcessor->ConstructionIndexVariableNums.dimension(state.dataRuntimeLang->NumEMSConstructionIndices, 0);
3094 6 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSConstructionIndices; ++loop) {
3095 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3096 : cCurrentModuleObject,
3097 : loop,
3098 : cAlphaArgs,
3099 : NumAlphas,
3100 : rNumericArgs,
3101 : NumNums,
3102 : IOStat,
3103 : lNumericFieldBlanks,
3104 : lAlphaFieldBlanks,
3105 : cAlphaFieldNames,
3106 : cNumericFieldNames);
3107 :
3108 : // check if variable name is unique and well formed
3109 4 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
3110 4 : if (lAlphaFieldBlanks(1)) {
3111 0 : ShowSevereError(state, format("{}{}", RoutineName, cCurrentModuleObject));
3112 0 : ShowContinueError(state, format("Blank {}", cAlphaFieldNames(1)));
3113 0 : ShowContinueError(state, "Blank entry for Erl variable name is not allowed");
3114 0 : ErrorsFound = true;
3115 4 : } else if (!errFlag) {
3116 4 : VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0);
3117 4 : if (VariableNum > 0) {
3118 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3119 0 : ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1)));
3120 0 : ShowContinueError(state, "Name conflicts with an existing variable name");
3121 0 : ErrorsFound = true;
3122 : } else {
3123 : // create new EMS variable
3124 4 : VariableNum = NewEMSVariable(state, cAlphaArgs(1), 0);
3125 : // store variable num
3126 4 : state.dataRuntimeLangProcessor->ConstructionIndexVariableNums(loop) = VariableNum;
3127 : }
3128 : } else {
3129 0 : continue;
3130 : }
3131 :
3132 4 : ConstructNum = Util::FindItemInList(cAlphaArgs(2), state.dataConstruction->Construct);
3133 :
3134 4 : if (ConstructNum == 0) {
3135 0 : if (lAlphaFieldBlanks(2)) {
3136 0 : ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3137 0 : ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2)));
3138 0 : ShowContinueError(state, "Blank entry for construction name is not allowed");
3139 : } else {
3140 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3141 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3142 0 : ShowContinueError(state, "Construction was not found.");
3143 : }
3144 0 : ErrorsFound = true;
3145 : } else {
3146 : // fill Erl variable with curve index
3147 4 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = SetErlValueNumber(double(ConstructNum));
3148 : }
3149 : }
3150 :
3151 : } // NumEMSConstructionIndices > 0
3152 :
3153 47 : state.dataRuntimeLang->NumErlStacks = state.dataRuntimeLang->NumErlPrograms + state.dataRuntimeLang->NumErlSubroutines;
3154 47 : state.dataRuntimeLang->ErlStack.allocate(state.dataRuntimeLang->NumErlStacks);
3155 47 : state.dataRuntimeLangProcessor->ErlStackUniqueNames.reserve(static_cast<unsigned>(state.dataRuntimeLang->NumErlStacks));
3156 :
3157 47 : if (state.dataRuntimeLang->NumErlPrograms > 0) {
3158 25 : cCurrentModuleObject = "EnergyManagementSystem:Program";
3159 61 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlPrograms; ++StackNum) {
3160 36 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3161 : cCurrentModuleObject,
3162 : StackNum,
3163 : cAlphaArgs,
3164 : NumAlphas,
3165 : rNumericArgs,
3166 : NumNums,
3167 : IOStat,
3168 : lNumericFieldBlanks,
3169 : lAlphaFieldBlanks,
3170 : cAlphaFieldNames,
3171 : cNumericFieldNames);
3172 36 : GlobalNames::VerifyUniqueInterObjectName(state,
3173 36 : state.dataRuntimeLangProcessor->ErlStackUniqueNames,
3174 36 : cAlphaArgs(1),
3175 : cCurrentModuleObject,
3176 36 : cAlphaFieldNames(1),
3177 : ErrorsFound);
3178 :
3179 36 : ValidateEMSProgramName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), "Programs", errFlag, ErrorsFound);
3180 36 : if (!errFlag) {
3181 36 : state.dataRuntimeLang->ErlStack(StackNum).Name = cAlphaArgs(1);
3182 : }
3183 :
3184 36 : if (NumAlphas > 1) {
3185 36 : state.dataRuntimeLang->ErlStack(StackNum).Line.allocate(NumAlphas - 1);
3186 36 : state.dataRuntimeLang->ErlStack(StackNum).NumLines = NumAlphas - 1;
3187 36 : state.dataRuntimeLang->ErlStack(StackNum).Line({1, NumAlphas - 1}) = cAlphaArgs({2, NumAlphas}); // note array assignment
3188 : }
3189 :
3190 : } // ProgramNum
3191 : }
3192 :
3193 47 : if (state.dataRuntimeLang->NumErlSubroutines > 0) {
3194 1 : cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
3195 2 : for (StackNum = state.dataRuntimeLang->NumErlPrograms + 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3196 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3197 : cCurrentModuleObject,
3198 1 : StackNum - state.dataRuntimeLang->NumErlPrograms,
3199 : cAlphaArgs,
3200 : NumAlphas,
3201 : rNumericArgs,
3202 : NumNums,
3203 : IOStat,
3204 : lNumericFieldBlanks,
3205 : lAlphaFieldBlanks,
3206 : cAlphaFieldNames,
3207 : cNumericFieldNames);
3208 1 : GlobalNames::VerifyUniqueInterObjectName(state,
3209 1 : state.dataRuntimeLangProcessor->ErlStackUniqueNames,
3210 1 : cAlphaArgs(1),
3211 : cCurrentModuleObject,
3212 1 : cAlphaFieldNames(1),
3213 : ErrorsFound);
3214 :
3215 1 : ValidateEMSProgramName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), "Subroutines", errFlag, ErrorsFound);
3216 1 : if (!errFlag) {
3217 1 : state.dataRuntimeLang->ErlStack(StackNum).Name = cAlphaArgs(1);
3218 : }
3219 :
3220 1 : if (NumAlphas > 1) {
3221 1 : state.dataRuntimeLang->ErlStack(StackNum).Line.allocate(NumAlphas - 1);
3222 1 : state.dataRuntimeLang->ErlStack(StackNum).NumLines = NumAlphas - 1;
3223 1 : state.dataRuntimeLang->ErlStack(StackNum).Line({1, NumAlphas - 1}) = cAlphaArgs({2, NumAlphas}); // note array assignment
3224 : }
3225 : }
3226 : }
3227 :
3228 47 : cCurrentModuleObject = "EnergyManagementSystem:TrendVariable";
3229 47 : state.dataRuntimeLang->NumErlTrendVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3230 47 : if (state.dataRuntimeLang->NumErlTrendVariables > 0) {
3231 2 : state.dataRuntimeLang->TrendVariable.allocate(state.dataRuntimeLang->NumErlTrendVariables);
3232 9 : for (TrendNum = 1; TrendNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendNum) {
3233 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3234 : cCurrentModuleObject,
3235 : TrendNum,
3236 : cAlphaArgs,
3237 : NumAlphas,
3238 : rNumericArgs,
3239 : NumNums,
3240 : IOStat,
3241 : lNumericFieldBlanks,
3242 : lAlphaFieldBlanks,
3243 : cAlphaFieldNames,
3244 : cNumericFieldNames);
3245 7 : Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
3246 :
3247 7 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
3248 7 : if (!errFlag) {
3249 7 : state.dataRuntimeLang->TrendVariable(TrendNum).Name = cAlphaArgs(1);
3250 : }
3251 :
3252 7 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), 0);
3253 : // Still need to check for conflicts with program and function names too
3254 7 : if (VariableNum == 0) { // did not find it
3255 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3256 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3257 0 : ShowContinueError(state, "Did not find a match with an EMS variable name");
3258 0 : ErrorsFound = true;
3259 : } else { // found it.
3260 7 : state.dataRuntimeLang->TrendVariable(TrendNum).ErlVariablePointer = VariableNum;
3261 : // register the trend pointer in ErlVariable.
3262 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.TrendVariable = true;
3263 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.TrendVarPointer = TrendNum;
3264 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true; // Cannot figure out how to get around needing this,
3265 : }
3266 :
3267 7 : NumTrendSteps = std::floor(rNumericArgs(1));
3268 7 : if (NumTrendSteps > 0) {
3269 7 : state.dataRuntimeLang->TrendVariable(TrendNum).LogDepth = NumTrendSteps;
3270 : // setup data arrays using NumTrendSteps
3271 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR.allocate(NumTrendSteps);
3272 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR = 0.0; // array init
3273 7 : state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR.allocate(NumTrendSteps);
3274 7 : state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR = 0.0; // array init
3275 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR.allocate(NumTrendSteps);
3276 : // construct time data array for use with other calculations later
3277 : // current time is zero, each value in trend log array is one zone timestep further back in time
3278 : // units are hours. all terms negative, getting increasingly negative the further back in time
3279 : // further back in time is higher index in array
3280 43 : for (loop = 1; loop <= NumTrendSteps; ++loop) {
3281 36 : if (loop == 1) {
3282 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop) = -state.dataGlobal->TimeStepZone;
3283 7 : continue;
3284 : } else {
3285 29 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop) =
3286 29 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop - 1) - state.dataGlobal->TimeStepZone; // fractional hours
3287 : }
3288 : }
3289 : } else {
3290 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3291 0 : ShowContinueError(state, format("Invalid {}={:.2T}", cNumericFieldNames(1), rNumericArgs(1)));
3292 0 : ShowContinueError(state, "must be greater than zero");
3293 0 : ErrorsFound = true;
3294 : }
3295 :
3296 : } // trendnum
3297 : }
3298 :
3299 47 : if (ErrorsFound) {
3300 0 : ShowFatalError(state, "Errors found in getting EMS Runtime Language input. Preceding condition causes termination.");
3301 : }
3302 :
3303 : // Parse the runtime language code
3304 84 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3305 37 : ParseStack(state, StackNum);
3306 :
3307 37 : if (state.dataRuntimeLang->ErlStack(StackNum).NumErrors > 0) {
3308 0 : ShowSevereError(
3309 : state,
3310 0 : format("Errors found parsing EMS Runtime Language program or subroutine = {}", state.dataRuntimeLang->ErlStack(StackNum).Name));
3311 0 : for (ErrorNum = 1; ErrorNum <= state.dataRuntimeLang->ErlStack(StackNum).NumErrors; ++ErrorNum) {
3312 0 : ShowContinueError(state, state.dataRuntimeLang->ErlStack(StackNum).Error(ErrorNum));
3313 : }
3314 0 : ErrorsFound = true;
3315 : }
3316 : } // StackNum
3317 :
3318 47 : if (ErrorsFound) {
3319 0 : ShowFatalError(state, "Errors found in parsing EMS Runtime Language input. Preceding condition causes termination.");
3320 : }
3321 :
3322 47 : if ((state.dataRuntimeLang->NumEMSOutputVariables > 0) || (state.dataRuntimeLang->NumEMSMeteredOutputVariables > 0)) {
3323 12 : state.dataRuntimeLangProcessor->RuntimeReportVar.allocate(state.dataRuntimeLang->NumEMSOutputVariables +
3324 6 : state.dataRuntimeLang->NumEMSMeteredOutputVariables);
3325 : }
3326 :
3327 47 : if (state.dataRuntimeLang->NumEMSOutputVariables > 0) {
3328 6 : cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
3329 21 : for (RuntimeReportVarNum = 1; RuntimeReportVarNum <= state.dataRuntimeLang->NumEMSOutputVariables; ++RuntimeReportVarNum) {
3330 15 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3331 : cCurrentModuleObject,
3332 : RuntimeReportVarNum,
3333 : cAlphaArgs,
3334 : NumAlphas,
3335 : rNumericArgs,
3336 : NumNums,
3337 : IOStat,
3338 : lNumericFieldBlanks,
3339 : lAlphaFieldBlanks,
3340 : cAlphaFieldNames,
3341 : cNumericFieldNames);
3342 15 : GlobalNames::VerifyUniqueInterObjectName(state,
3343 15 : state.dataRuntimeLangProcessor->RuntimeReportVarUniqueNames,
3344 15 : cAlphaArgs(1),
3345 : cCurrentModuleObject,
3346 15 : cAlphaFieldNames(1),
3347 : ErrorsFound);
3348 :
3349 15 : lbracket = index(cAlphaArgs(1), '[');
3350 15 : if (lbracket == std::string::npos) {
3351 15 : UnitsA = "";
3352 : // if (lAlphaFieldBlanks(6)) then
3353 : // CALL ShowWarningError(state, RoutineName//TRIM(cCurrentModuleObject)//'="'//TRIM(cAlphaArgs(1))//' no units
3354 : // indicated.') CALL ShowContinueError(state, '...no units indicated for this variable. [] is assumed.')
3355 : // cAlphaArgs(1)=TRIM(cAlphaArgs(1))//' []'
3356 : // endif
3357 15 : UnitsB = cAlphaArgs(6);
3358 15 : lbracket = index(UnitsB, '[');
3359 15 : ptr = index(UnitsB, ']');
3360 15 : if (lbracket != std::string::npos) {
3361 0 : UnitsB[lbracket] = ' ';
3362 0 : if (ptr != std::string::npos) {
3363 0 : UnitsB[ptr] = ' ';
3364 : }
3365 0 : strip(UnitsB);
3366 : }
3367 : } else { // units shown on Name field (7.2 and pre versions)
3368 0 : ptr = index(cAlphaArgs(1), ']');
3369 0 : if (ptr != std::string::npos) {
3370 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1, ptr - lbracket - 1);
3371 : } else {
3372 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1);
3373 : }
3374 0 : cAlphaArgs(1).erase(lbracket - 1);
3375 0 : UnitsB = cAlphaArgs(6);
3376 0 : lbracket = index(UnitsB, '[');
3377 0 : ptr = index(UnitsB, ']');
3378 0 : if (lbracket != std::string::npos) {
3379 0 : UnitsB[lbracket] = ' ';
3380 0 : if (ptr != std::string::npos) {
3381 0 : UnitsB[ptr] = ' ';
3382 : }
3383 0 : strip(UnitsB);
3384 : }
3385 0 : if (UnitsA != "" && UnitsB != "") {
3386 0 : if (UnitsA != UnitsB) {
3387 0 : ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3388 0 : ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA));
3389 0 : ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(6), UnitsB));
3390 : }
3391 0 : } else if (UnitsB == "" && UnitsA != "") {
3392 0 : UnitsB = UnitsA;
3393 0 : ShowWarningError(state,
3394 0 : format("{}{}=\"{}\" using deprecated units designation.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3395 0 : ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA));
3396 : }
3397 : }
3398 15 : curUnit = static_cast<Constant::Units>(getEnumValue(Constant::unitNamesUC, Util::makeUPPER(UnitsB)));
3399 :
3400 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Name = cAlphaArgs(1);
3401 :
3402 15 : if (!lAlphaFieldBlanks(5)) {
3403 : // Lookup the Runtime Language Context, i.e., PROGRAM, FUNCTION, or global
3404 5 : Found = false;
3405 23 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3406 23 : if (state.dataRuntimeLang->ErlStack(StackNum).Name == cAlphaArgs(5)) {
3407 5 : Found = true;
3408 5 : break;
3409 : }
3410 : }
3411 5 : if (!Found) {
3412 0 : StackNum = 0;
3413 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3414 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5)));
3415 0 : ShowContinueError(state, "EMS program or subroutine not found.");
3416 0 : ErrorsFound = true;
3417 : }
3418 : } else {
3419 10 : StackNum = 0;
3420 : }
3421 :
3422 15 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum);
3423 :
3424 15 : if (VariableNum == 0) {
3425 0 : if (lAlphaFieldBlanks(5)) {
3426 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3427 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3428 0 : ShowContinueError(state, "EMS variable not found among global variables.");
3429 0 : } else if (StackNum != 0) {
3430 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3431 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3432 0 : ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5)));
3433 : }
3434 0 : ErrorsFound = true;
3435 : // ELSEIF (INDEX('0123456789',cAlphaArgs(2)(1:1)) > 0) THEN
3436 : // CALL ShowSevereError(state, 'Invalid '//TRIM(cAlphaFieldNames(2))//'='//TRIM(cAlphaArgs(2)))
3437 : // CALL ShowContinueError(state, 'Entered in '//TRIM(cCurrentModuleObject)//'='//TRIM(cAlphaArgs(1)))
3438 : // CALL ShowContinueError(state, 'Names used as Erl output variables cannot start with numeric characters.')
3439 : // ErrorsFound = .TRUE.
3440 : } else {
3441 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum = VariableNum;
3442 : }
3443 :
3444 15 : if (cAlphaArgs(3) == "AVERAGED") {
3445 15 : sovStoreType = OutputProcessor::StoreType::Average;
3446 0 : } else if (cAlphaArgs(3) == "SUMMED") {
3447 0 : sovStoreType = OutputProcessor::StoreType::Sum;
3448 : } else {
3449 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3450 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(3), cAlphaArgs(3)));
3451 0 : ShowContinueError(state, "...valid values are Averaged or Summed.");
3452 0 : ErrorsFound = true;
3453 : }
3454 :
3455 15 : if (cAlphaArgs(4) == "ZONETIMESTEP") {
3456 2 : sovTimeStepType = OutputProcessor::TimeStepType::Zone;
3457 13 : } else if (cAlphaArgs(4) == "SYSTEMTIMESTEP") {
3458 13 : sovTimeStepType = OutputProcessor::TimeStepType::System;
3459 : } else {
3460 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3461 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4)));
3462 0 : ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep.");
3463 0 : ErrorsFound = true;
3464 : }
3465 :
3466 15 : if (curUnit != Constant::Units::Invalid) {
3467 60 : SetupOutputVariable(state,
3468 15 : cAlphaArgs(1),
3469 : curUnit,
3470 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3471 : sovTimeStepType,
3472 : sovStoreType,
3473 : "EMS");
3474 : } else {
3475 0 : SetupOutputVariable(state,
3476 0 : cAlphaArgs(1),
3477 : Constant::Units::customEMS,
3478 0 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3479 : sovTimeStepType,
3480 : sovStoreType,
3481 : "EMS",
3482 : Constant::eResource::Invalid,
3483 : OutputProcessor::Group::Invalid,
3484 : OutputProcessor::EndUseCat::Invalid,
3485 : "", // EndUseSubCat
3486 : "", // ZoneName
3487 : 1, // ZoneMult
3488 : 1, // ZoneListMult
3489 : "", // SpaceType
3490 : -999, // indexGroupKey
3491 : UnitsB);
3492 : }
3493 : // Last field is index key, no indexing here so mimic weather output data
3494 :
3495 : } // RuntimeReportVarNum
3496 : } // NumEMSOutputVariables > 0
3497 :
3498 47 : if (state.dataRuntimeLang->NumEMSMeteredOutputVariables > 0) {
3499 1 : cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
3500 3 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSMeteredOutputVariables; ++loop) {
3501 2 : RuntimeReportVarNum = state.dataRuntimeLang->NumEMSOutputVariables + loop;
3502 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3503 : cCurrentModuleObject,
3504 : loop,
3505 : cAlphaArgs,
3506 : NumAlphas,
3507 : rNumericArgs,
3508 : NumNums,
3509 : IOStat,
3510 : lNumericFieldBlanks,
3511 : lAlphaFieldBlanks,
3512 : cAlphaFieldNames,
3513 : cNumericFieldNames);
3514 :
3515 2 : GlobalNames::VerifyUniqueInterObjectName(state,
3516 2 : state.dataRuntimeLangProcessor->RuntimeReportVarUniqueNames,
3517 2 : cAlphaArgs(1),
3518 : cCurrentModuleObject,
3519 2 : cAlphaFieldNames(1),
3520 : ErrorsFound);
3521 :
3522 2 : lbracket = index(cAlphaArgs(1), '[');
3523 2 : if (lbracket == std::string::npos) {
3524 2 : UnitsA = "";
3525 : // if (lAlphaFieldBlanks(9)) then
3526 : // CALL ShowWarningError(state, RoutineName//TRIM(cCurrentModuleObject)//'="'//TRIM(cAlphaArgs(1))//' no units
3527 : // indicated.') CALL ShowContinueError(state, '...no units indicated for this variable. [] is assumed.')
3528 : // cAlphaArgs(1)=TRIM(cAlphaArgs(1))//' []'
3529 : // endif
3530 2 : UnitsB = cAlphaArgs(9);
3531 2 : lbracket = index(UnitsB, '[');
3532 2 : ptr = index(UnitsB, ']');
3533 2 : if (lbracket != std::string::npos) {
3534 0 : UnitsB[lbracket] = ' ';
3535 0 : if (ptr != std::string::npos) {
3536 0 : UnitsB[ptr] = ' ';
3537 : }
3538 0 : strip(UnitsB);
3539 : }
3540 : } else { // units shown on Name field (7.2 and pre versions)
3541 0 : ptr = index(cAlphaArgs(1), ']');
3542 0 : if (ptr != std::string::npos) {
3543 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1, ptr - lbracket - 1);
3544 : } else {
3545 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1);
3546 : }
3547 0 : cAlphaArgs(1).erase(lbracket - 1);
3548 0 : UnitsB = cAlphaArgs(9);
3549 0 : lbracket = index(UnitsB, '[');
3550 0 : ptr = index(UnitsB, ']');
3551 0 : if (lbracket != std::string::npos) {
3552 0 : UnitsB[lbracket] = ' ';
3553 0 : if (ptr != std::string::npos) {
3554 0 : UnitsB[ptr] = ' ';
3555 : }
3556 0 : strip(UnitsB);
3557 : }
3558 0 : if (UnitsA != "" && UnitsB != "") {
3559 0 : if (UnitsA != UnitsB) {
3560 0 : ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3561 0 : ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA));
3562 0 : ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(9), UnitsB));
3563 : }
3564 0 : } else if (UnitsB == "" && UnitsA != "") {
3565 0 : UnitsB = UnitsA;
3566 0 : ShowWarningError(state,
3567 0 : format("{}{}=\"{}\" using deprecated units designation.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3568 0 : ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA));
3569 : }
3570 : }
3571 2 : curUnit = static_cast<Constant::Units>(getEnumValue(Constant::unitNamesUC, Util::makeUPPER(UnitsB)));
3572 :
3573 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Name = cAlphaArgs(1);
3574 :
3575 2 : if (!lAlphaFieldBlanks(4)) {
3576 : // Lookup the Runtime Language Context, i.e., PROGRAM, FUNCTION, or global
3577 2 : Found = false;
3578 11 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3579 11 : if (state.dataRuntimeLang->ErlStack(StackNum).Name == cAlphaArgs(4)) {
3580 2 : Found = true;
3581 2 : break;
3582 : }
3583 : }
3584 2 : if (!Found) {
3585 0 : StackNum = 0;
3586 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3587 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4)));
3588 0 : ShowContinueError(state, "EMS program or subroutine not found.");
3589 0 : ErrorsFound = true;
3590 : }
3591 : } else {
3592 0 : StackNum = 0;
3593 : }
3594 :
3595 2 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum);
3596 2 : if (VariableNum == 0) {
3597 0 : if (lAlphaFieldBlanks(4)) {
3598 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3599 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3600 0 : ShowContinueError(state, "EMS variable not found among global variables.");
3601 0 : } else if (StackNum != 0) {
3602 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3603 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2)));
3604 0 : ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5)));
3605 : }
3606 0 : ErrorsFound = true;
3607 : // ELSEIF (INDEX('0123456789',cAlphaArgs(2)(1:1)) > 0) THEN
3608 : // CALL ShowSevereError(state, 'Invalid '//TRIM(cAlphaFieldNames(2))//'='//TRIM(cAlphaArgs(2)))
3609 : // CALL ShowContinueError(state, 'Entered in '//TRIM(cCurrentModuleObject)//'='//TRIM(cAlphaArgs(1)))
3610 : // CALL ShowContinueError(state, 'Names used as Erl output variables cannot start with numeric characters.')
3611 : // ErrorsFound = .TRUE.
3612 : } else {
3613 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum = VariableNum;
3614 : }
3615 :
3616 2 : sovStoreType = OutputProcessor::StoreType::Sum; // all metered vars are sum type
3617 :
3618 2 : if (cAlphaArgs(3) == "ZONETIMESTEP") {
3619 0 : sovTimeStepType = OutputProcessor::TimeStepType::Zone;
3620 2 : } else if (cAlphaArgs(3) == "SYSTEMTIMESTEP") {
3621 2 : sovTimeStepType = OutputProcessor::TimeStepType::System;
3622 : } else {
3623 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3624 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4)));
3625 0 : ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep.");
3626 0 : ErrorsFound = true;
3627 : }
3628 :
3629 : // Resource Type
3630 : Constant::eResource resource =
3631 2 : static_cast<Constant::eResource>(getEnumValue(Constant::eResourceNamesUC, Util::makeUPPER(cAlphaArgs(5))));
3632 :
3633 2 : if (resource == Constant::eResource::Invalid) {
3634 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3635 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5)));
3636 0 : ErrorsFound = true;
3637 : }
3638 :
3639 : // Group Type
3640 : OutputProcessor::Group sovGroup;
3641 :
3642 2 : if (cAlphaArgs(6) == "BUILDING") {
3643 0 : sovGroup = OutputProcessor::Group::Building;
3644 2 : } else if (cAlphaArgs(6) == "HVAC") {
3645 2 : sovGroup = OutputProcessor::Group::HVAC;
3646 0 : } else if (cAlphaArgs(6) == "PLANT") {
3647 0 : sovGroup = OutputProcessor::Group::Plant;
3648 0 : } else if (cAlphaArgs(6) == "SYSTEM") {
3649 0 : sovGroup = OutputProcessor::Group::HVAC;
3650 : } else {
3651 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3652 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(6), cAlphaArgs(6)));
3653 0 : ErrorsFound = true;
3654 : }
3655 :
3656 : // End Use Type
3657 : OutputProcessor::EndUseCat sovEndUseCat;
3658 :
3659 2 : if (cAlphaArgs(7) == "HEATING") {
3660 0 : sovEndUseCat = OutputProcessor::EndUseCat::Heating;
3661 2 : } else if (cAlphaArgs(7) == "COOLING") {
3662 2 : sovEndUseCat = OutputProcessor::EndUseCat::Cooling;
3663 0 : } else if (cAlphaArgs(7) == "INTERIORLIGHTS") {
3664 0 : sovEndUseCat = OutputProcessor::EndUseCat::InteriorLights;
3665 0 : } else if (cAlphaArgs(7) == "EXTERIORLIGHTS") {
3666 0 : sovEndUseCat = OutputProcessor::EndUseCat::ExteriorLights;
3667 0 : } else if (cAlphaArgs(7) == "INTERIOREQUIPMENT") {
3668 0 : sovEndUseCat = OutputProcessor::EndUseCat::InteriorEquipment;
3669 0 : } else if (cAlphaArgs(7) == "EXTERIOREQUIPMENT") {
3670 0 : sovEndUseCat = OutputProcessor::EndUseCat::ExteriorEquipment;
3671 0 : } else if (cAlphaArgs(7) == "FANS") {
3672 0 : sovEndUseCat = OutputProcessor::EndUseCat::Fans;
3673 0 : } else if (cAlphaArgs(7) == "PUMPS") {
3674 0 : sovEndUseCat = OutputProcessor::EndUseCat::Pumps;
3675 0 : } else if (cAlphaArgs(7) == "HEATREJECTION") {
3676 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRejection;
3677 0 : } else if (cAlphaArgs(7) == "HUMIDIFIER") {
3678 0 : sovEndUseCat = OutputProcessor::EndUseCat::Humidification;
3679 0 : } else if (cAlphaArgs(7) == "HEATRECOVERY") {
3680 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRecovery;
3681 0 : } else if (cAlphaArgs(7) == "WATERSYSTEMS") {
3682 0 : sovEndUseCat = OutputProcessor::EndUseCat::WaterSystem;
3683 0 : } else if (cAlphaArgs(7) == "REFRIGERATION") {
3684 0 : sovEndUseCat = OutputProcessor::EndUseCat::Refrigeration;
3685 0 : } else if (cAlphaArgs(7) == "ONSITEGENERATION") {
3686 0 : sovEndUseCat = OutputProcessor::EndUseCat::Cogeneration;
3687 0 : } else if (cAlphaArgs(7) == "HEATINGCOILS") {
3688 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatingCoils;
3689 0 : } else if (cAlphaArgs(7) == "COOLINGCOILS") {
3690 0 : sovEndUseCat = OutputProcessor::EndUseCat::CoolingCoils;
3691 0 : } else if (cAlphaArgs(7) == "CHILLERS") {
3692 0 : sovEndUseCat = OutputProcessor::EndUseCat::Chillers;
3693 0 : } else if (cAlphaArgs(7) == "BOILERS") {
3694 0 : sovEndUseCat = OutputProcessor::EndUseCat::Boilers;
3695 0 : } else if (cAlphaArgs(7) == "BASEBOARD") {
3696 0 : sovEndUseCat = OutputProcessor::EndUseCat::Baseboard;
3697 0 : } else if (cAlphaArgs(7) == "HEATRECOVERYFORCOOLING") {
3698 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRecoveryForCooling;
3699 0 : } else if (cAlphaArgs(7) == "HEATRECOVERYFORHEATING") {
3700 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRecoveryForHeating;
3701 : } else {
3702 0 : ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3703 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(7), cAlphaArgs(7)));
3704 0 : ErrorsFound = true;
3705 : }
3706 :
3707 : // Additional End Use Types Only Used for EnergyTransfer
3708 2 : if ((resource != Constant::eResource::EnergyTransfer) &&
3709 2 : (sovEndUseCat == OutputProcessor::EndUseCat::HeatingCoils || sovEndUseCat == OutputProcessor::EndUseCat::CoolingCoils ||
3710 2 : sovEndUseCat == OutputProcessor::EndUseCat::Chillers || sovEndUseCat == OutputProcessor::EndUseCat::Boilers ||
3711 2 : sovEndUseCat == OutputProcessor::EndUseCat::Baseboard || sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForCooling ||
3712 : sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForHeating)) {
3713 0 : ShowWarningError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3714 0 : ShowContinueError(state,
3715 0 : format("Invalid {}={} for {}={}", cAlphaFieldNames(5), cAlphaArgs(5), cAlphaFieldNames(7), cAlphaArgs(7)));
3716 0 : ShowContinueError(state, format("Field {} is reset from {} to EnergyTransfer", cAlphaFieldNames(5), cAlphaArgs(5)));
3717 0 : resource = Constant::eResource::EnergyTransfer;
3718 : }
3719 :
3720 2 : if (!lAlphaFieldBlanks(8)) {
3721 2 : EndUseSubCatString = cAlphaArgs(8);
3722 :
3723 8 : SetupOutputVariable(state,
3724 2 : cAlphaArgs(1),
3725 : curUnit,
3726 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3727 : sovTimeStepType,
3728 : sovStoreType,
3729 : "EMS",
3730 : resource,
3731 : sovGroup,
3732 : sovEndUseCat,
3733 : EndUseSubCatString);
3734 : } else { // no subcat
3735 0 : SetupOutputVariable(state,
3736 0 : cAlphaArgs(1),
3737 : curUnit,
3738 0 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3739 : sovTimeStepType,
3740 : sovStoreType,
3741 : "EMS",
3742 : resource,
3743 : sovGroup,
3744 : sovEndUseCat);
3745 : }
3746 : }
3747 : } // NumEMSMeteredOutputVariables > 0
3748 :
3749 47 : cAlphaFieldNames.deallocate();
3750 47 : cAlphaArgs.deallocate();
3751 47 : lAlphaFieldBlanks.deallocate();
3752 47 : cNumericFieldNames.deallocate();
3753 47 : rNumericArgs.deallocate();
3754 47 : lNumericFieldBlanks.deallocate();
3755 :
3756 47 : if (ErrorsFound) {
3757 0 : ShowFatalError(state, "Errors found in getting EMS Runtime Language input. Preceding condition causes termination.");
3758 : }
3759 :
3760 : } // GetInput
3761 47 : }
3762 :
3763 115066 : void ReportRuntimeLanguage(EnergyPlusData &state)
3764 : {
3765 :
3766 : // SUBROUTINE INFORMATION:
3767 : // AUTHOR Peter Graham Ellis
3768 : // DATE WRITTEN June 2006
3769 : // MODIFIED na
3770 : // RE-ENGINEERED na
3771 :
3772 : // PURPOSE OF THIS SUBROUTINE:
3773 :
3774 : // METHODOLOGY EMPLOYED:
3775 :
3776 : // USE STATEMENTS:
3777 :
3778 : // Locals
3779 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3780 : int RuntimeReportVarNum;
3781 : int VariableNum;
3782 :
3783 172766 : for (RuntimeReportVarNum = 1;
3784 172766 : RuntimeReportVarNum <= state.dataRuntimeLang->NumEMSOutputVariables + state.dataRuntimeLang->NumEMSMeteredOutputVariables;
3785 : ++RuntimeReportVarNum) {
3786 57700 : VariableNum = state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum;
3787 57700 : if (state.dataRuntimeLang->ErlVariable(VariableNum).Value.Type == Value::Number) {
3788 57699 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value =
3789 57699 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.Number;
3790 : } else {
3791 1 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value = 0.0;
3792 : }
3793 : }
3794 115066 : }
3795 :
3796 26065698 : ErlValueType SetErlValueNumber(Real64 const Number, ObjexxFCL::Optional<ErlValueType const> OrigValue)
3797 : {
3798 : // FUNCTION INFORMATION:
3799 : // AUTHOR P. Ellis
3800 : // DATE WRITTEN unknown
3801 :
3802 26065698 : ErlValueType newValue;
3803 :
3804 26065698 : if (present(OrigValue)) { // preserve other parts of structure and only updated Value%Number
3805 236299 : newValue = OrigValue;
3806 236299 : newValue.Number = Number;
3807 : } else {
3808 25829399 : newValue.Type = Value::Number;
3809 25829399 : newValue.Number = Number;
3810 : }
3811 :
3812 26065698 : newValue.initialized = true;
3813 26065698 : return newValue;
3814 0 : }
3815 :
3816 0 : ErlValueType StringValue(std::string const &String)
3817 : {
3818 : // FUNCTION INFORMATION:
3819 : // AUTHOR P. Ellis
3820 : // DATE WRITTEN unkown
3821 : // MODIFIED na
3822 : // RE-ENGINEERED na
3823 :
3824 : // PURPOSE OF THIS FUNCTION:
3825 : // convert string to Erl Value structure
3826 :
3827 : // METHODOLOGY EMPLOYED:
3828 : // <description>
3829 :
3830 : // REFERENCES:
3831 : // na
3832 :
3833 : // USE STATEMENTS:
3834 : // na
3835 :
3836 : // Return value
3837 0 : ErlValueType Value;
3838 :
3839 : // Locals
3840 : // FUNCTION ARGUMENT DEFINITIONS:
3841 : // na
3842 :
3843 : // FUNCTION PARAMETER DEFINITIONS:
3844 : // na
3845 :
3846 : // INTERFACE BLOCK SPECIFICATIONS:
3847 : // na
3848 :
3849 : // DERIVED TYPE DEFINITIONS:
3850 : // na
3851 :
3852 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3853 : // na
3854 :
3855 0 : Value.Type = Value::String;
3856 0 : Value.String = String;
3857 :
3858 0 : return Value;
3859 0 : }
3860 :
3861 7 : std::string ValueToString(ErlValueType const &Value)
3862 : {
3863 : // FUNCTION INFORMATION:
3864 : // AUTHOR P. Ellis
3865 : // DATE WRITTEN Unknown
3866 : // MODIFIED na
3867 : // RE-ENGINEERED na
3868 :
3869 : // PURPOSE OF THIS FUNCTION:
3870 : // <description>
3871 :
3872 : // METHODOLOGY EMPLOYED:
3873 : // <description>
3874 :
3875 : // REFERENCES:
3876 : // na
3877 :
3878 : // Using/Aliasing
3879 :
3880 : // Return value
3881 7 : std::string String;
3882 :
3883 : // Locals
3884 : // FUNCTION ARGUMENT DEFINITIONS:
3885 :
3886 7 : String = "";
3887 :
3888 7 : switch (Value.Type) {
3889 7 : case Value::Number:
3890 7 : if (Value.Number == 0.0) {
3891 1 : String = "0.0";
3892 : } else {
3893 6 : String = format("{:.6T}", Value.Number); //(String)
3894 : }
3895 7 : break;
3896 :
3897 0 : case Value::String:
3898 0 : String = Value.String;
3899 0 : break;
3900 :
3901 0 : case Value::Array:
3902 : // TBD
3903 0 : break;
3904 :
3905 0 : case Value::Error:
3906 0 : String = " *** Error: " + Value.Error + " *** ";
3907 0 : break;
3908 :
3909 0 : default:
3910 : // Nothing to do
3911 0 : break;
3912 : }
3913 :
3914 7 : return String;
3915 0 : }
3916 :
3917 2296 : int FindEMSVariable(EnergyPlusData &state,
3918 : std::string const &VariableName, // variable name in Erl
3919 : int const StackNum)
3920 : {
3921 :
3922 : // FUNCTION INFORMATION:
3923 : // AUTHOR Peter Graham Ellis
3924 : // DATE WRITTEN June 2006
3925 : // MODIFIED na
3926 : // RE-ENGINEERED na
3927 :
3928 : // PURPOSE OF THIS FUNCTION:
3929 :
3930 : // Return value
3931 : int VariableNum;
3932 :
3933 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3934 : bool Found;
3935 : int TrendVarNum;
3936 :
3937 2296 : Found = false;
3938 2296 : std::string const UppercaseName = Util::makeUPPER(VariableName);
3939 :
3940 : // check in ErlVariables
3941 81931 : for (VariableNum = 1; VariableNum <= state.dataRuntimeLang->NumErlVariables; ++VariableNum) {
3942 80174 : if (state.dataRuntimeLang->ErlVariable(VariableNum).Name == UppercaseName) {
3943 900 : if ((state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == StackNum) ||
3944 308 : (state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == 0)) {
3945 539 : Found = true;
3946 539 : break;
3947 : }
3948 : }
3949 : }
3950 :
3951 : // check in Trend variables
3952 2801 : for (TrendVarNum = 1; TrendVarNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendVarNum) {
3953 519 : if (state.dataRuntimeLang->TrendVariable(TrendVarNum).Name == UppercaseName) {
3954 14 : VariableNum = state.dataRuntimeLang->TrendVariable(TrendVarNum).ErlVariablePointer;
3955 28 : if ((state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == StackNum) ||
3956 14 : (state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == 0)) {
3957 14 : Found = true;
3958 14 : break;
3959 : }
3960 : }
3961 : }
3962 :
3963 2296 : if (!Found) {
3964 1743 : VariableNum = 0;
3965 : }
3966 :
3967 2296 : return VariableNum;
3968 2296 : }
3969 :
3970 2082 : int NewEMSVariable(EnergyPlusData &state, std::string const &VariableName, int const StackNum, ObjexxFCL::Optional<ErlValueType const> Value)
3971 : {
3972 :
3973 : // FUNCTION INFORMATION:
3974 : // AUTHOR Peter Graham Ellis
3975 : // DATE WRITTEN June 2006
3976 : // MODIFIED na
3977 : // RE-ENGINEERED na
3978 :
3979 : // PURPOSE OF THIS FUNCTION:
3980 : // Creates new variable if it doesn't exist. If exists, returns existing variable number.
3981 :
3982 2082 : int VariableNum = FindEMSVariable(state, VariableName, StackNum);
3983 :
3984 2082 : if (VariableNum == 0) { // Variable does not exist anywhere yet
3985 1582 : if (state.dataRuntimeLang->NumErlVariables == 0) {
3986 46 : state.dataRuntimeLang->ErlVariable.allocate(1);
3987 46 : state.dataRuntimeLang->NumErlVariables = 1;
3988 : } else { // Extend the variable array
3989 1536 : state.dataRuntimeLang->ErlVariable.redimension(++state.dataRuntimeLang->NumErlVariables);
3990 : }
3991 :
3992 : // Add the new variable
3993 1582 : VariableNum = state.dataRuntimeLang->NumErlVariables;
3994 1582 : auto &thisErlVar = state.dataRuntimeLang->ErlVariable(VariableNum);
3995 1582 : thisErlVar.Name = Util::makeUPPER(VariableName);
3996 1582 : thisErlVar.StackNum = StackNum;
3997 1582 : thisErlVar.Value.Type = Value::Number; // ErlVariable values are numbers
3998 : }
3999 :
4000 2082 : if (present(Value)) {
4001 322 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = Value;
4002 : }
4003 :
4004 2082 : return VariableNum;
4005 : }
4006 :
4007 0 : void ExternalInterfaceSetErlVariable(EnergyPlusData &state,
4008 : int const varNum, // The variable index to be written during run time
4009 : Real64 const value // The real time value of the vairable to be set
4010 : )
4011 : {
4012 :
4013 : // SUBROUTINE INFORMATION:
4014 : // AUTHOR Rui Zhang
4015 : // DATE WRITTEN February 2010
4016 : // MODIFIED na
4017 : // RE-ENGINEERED na
4018 :
4019 : // PURPOSE OF THIS SUBROUTINE:
4020 : // This is the ExternalInterface runtime write ErlVariable function
4021 :
4022 : // METHODOLOGY EMPLOYED:
4023 : // USE STATEMENTS:
4024 :
4025 : // Locals
4026 : // SUBROUTINE ARGUMENT DEFINITIONS:
4027 :
4028 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4029 :
4030 0 : state.dataRuntimeLang->ErlVariable(varNum).Value = SetErlValueNumber(value);
4031 0 : }
4032 :
4033 0 : void ExternalInterfaceInitializeErlVariable(EnergyPlusData &state,
4034 : int const varNum, // The variable index to be written during run time
4035 : ErlValueType const &initialValue, // The initial value
4036 : bool const setToNull // Flag, if true, value will be initialized to Null
4037 : )
4038 : {
4039 :
4040 : // SUBROUTINE INFORMATION:
4041 : // AUTHOR Michael Wetter
4042 : // DATE WRITTEN February 2010
4043 : // MODIFIED na
4044 : // RE-ENGINEERED na
4045 :
4046 : // PURPOSE OF THIS SUBROUTINE:
4047 : // This subroutine sets flags for ExternalInterface variables
4048 :
4049 : // METHODOLOGY EMPLOYED:
4050 : // USE STATEMENTS:
4051 :
4052 : // Locals
4053 : // SUBROUTINE ARGUMENT DEFINITIONS:
4054 :
4055 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4056 : // Set initial value
4057 0 : if (setToNull) {
4058 0 : state.dataRuntimeLang->ErlVariable(varNum).Value.Type = Value::Null;
4059 : } else {
4060 0 : state.dataRuntimeLang->ErlVariable(varNum).Value = initialValue;
4061 : }
4062 :
4063 : // Set variables to read-only as we don't want that other programs write to them
4064 0 : state.dataRuntimeLang->ErlVariable(varNum).ReadOnly = true;
4065 : // Set flag that it is used by the ExternalInterface. This is needed to make sure that the ExternalInterface
4066 : // interface writes only to ExternalInterface variables, and not to other ErlVariable
4067 0 : state.dataRuntimeLang->ErlVariable(varNum).SetByExternalInterface = true;
4068 0 : }
4069 :
4070 0 : bool isExternalInterfaceErlVariable(EnergyPlusData &state, int const varNum) // The variable index to be written during run time
4071 : {
4072 :
4073 : // SUBROUTINE INFORMATION:
4074 : // AUTHOR Michael Wetter
4075 : // DATE WRITTEN February 2010
4076 : // MODIFIED na
4077 : // RE-ENGINEERED na
4078 :
4079 : // PURPOSE OF THIS SUBROUTINE:
4080 : // This function checks if an Erl name obtained from the xml file
4081 : // is indeed specified as a ExternalInterface variable in the idf file
4082 :
4083 : // METHODOLOGY EMPLOYED:
4084 : // USE STATEMENTS:
4085 :
4086 : // Return value
4087 : bool isExternalInterfaceVar; // Set to true if the variable is a ExternalInterface variable
4088 :
4089 : // Locals
4090 : // SUBROUTINE ARGUMENT DEFINITIONS:
4091 :
4092 0 : isExternalInterfaceVar = state.dataRuntimeLang->ErlVariable(varNum).SetByExternalInterface;
4093 :
4094 0 : return isExternalInterfaceVar;
4095 : }
4096 :
4097 : } // namespace EnergyPlus::RuntimeLanguageProcessor
|