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