Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Array2D.hh>
55 : #include <ObjexxFCL/ArrayS.functions.hh>
56 : // #include <ObjexxFCL/Fmath.hh>
57 : #include <ObjexxFCL/char.functions.hh>
58 : #include <ObjexxFCL/random.hh>
59 : #include <ObjexxFCL/string.functions.hh>
60 : #include <ObjexxFCL/time.hh>
61 :
62 : // EnergyPlus Headers
63 : #include <EnergyPlus/Construction.hh>
64 : #include <EnergyPlus/CurveManager.hh>
65 : #include <EnergyPlus/Data/EnergyPlusData.hh>
66 : #include <EnergyPlus/DataEnvironment.hh>
67 : #include <EnergyPlus/DataHVACGlobals.hh>
68 : #include <EnergyPlus/DataIPShortCuts.hh>
69 : #include <EnergyPlus/DataSystemVariables.hh>
70 : #include <EnergyPlus/EMSManager.hh>
71 : #include <EnergyPlus/General.hh>
72 : #include <EnergyPlus/GlobalNames.hh>
73 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/Psychrometrics.hh>
76 : #include <EnergyPlus/RuntimeLanguageProcessor.hh>
77 : #include <EnergyPlus/UtilityRoutines.hh>
78 : #include <EnergyPlus/WeatherManager.hh>
79 :
80 : namespace EnergyPlus::RuntimeLanguageProcessor {
81 :
82 : // MODULE INFORMATION:
83 : // AUTHOR Peter Graham Ellis
84 : // DATE WRITTEN June 2006
85 : // MODIFIED Brent Griffith, May - August 2009
86 : // RE-ENGINEERED na
87 :
88 : // Using/Aliasing
89 : using namespace DataRuntimeLanguage;
90 :
91 1467466 : void InitializeRuntimeLanguage(EnergyPlusData &state)
92 : {
93 :
94 : // SUBROUTINE INFORMATION:
95 : // AUTHOR Peter Graham Ellis
96 : // DATE WRITTEN June 2006
97 : // MODIFIED Rui Zhang February 2010
98 : // RE-ENGINEERED na
99 :
100 : // METHODOLOGY EMPLOYED:
101 : // One time run. Must be run BEFORE anything gets parsed.
102 :
103 : // Using/Aliasing
104 1467466 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
105 1467466 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
106 :
107 1467466 : Real64 tmpCurrentTime(0.0);
108 1467466 : Real64 tmpMinutes(0.0);
109 1467466 : Real64 tmpHours(0.0);
110 1467466 : Real64 tmpCurEnvirNum(0.0);
111 1467466 : Array1D_int datevalues(8);
112 : // value(1) Current year
113 : // value(2) Current month
114 : // value(3) Current day
115 : // value(4) Time difference with respect to UTC in minutes (0-59)
116 : // value(5) Hour of the day (0-23)
117 : // value(6) Minutes (0-59)
118 : // value(7) Seconds (0-59)
119 : // value(8) Milliseconds (0-999)
120 :
121 1467466 : if (state.dataRuntimeLangProcessor->InitializeOnce) {
122 :
123 46 : std::string datestring; // supposedly returns blank when no date available.
124 :
125 46 : state.dataRuntimeLang->emsVarBuiltInStart = state.dataRuntimeLang->NumErlVariables + 1;
126 :
127 46 : state.dataRuntimeLang->False = SetErlValueNumber(0.0);
128 46 : state.dataRuntimeLang->True = SetErlValueNumber(1.0);
129 :
130 : // Create constant built-in variables
131 138 : state.dataRuntimeLangProcessor->NullVariableNum = NewEMSVariable(state, "NULL", 0, SetErlValueNumber(0.0));
132 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->NullVariableNum).Value.Type = Value::Null;
133 138 : state.dataRuntimeLangProcessor->FalseVariableNum = NewEMSVariable(state, "FALSE", 0, state.dataRuntimeLang->False);
134 138 : state.dataRuntimeLangProcessor->TrueVariableNum = NewEMSVariable(state, "TRUE", 0, state.dataRuntimeLang->True);
135 138 : state.dataRuntimeLangProcessor->OffVariableNum = NewEMSVariable(state, "OFF", 0, state.dataRuntimeLang->False);
136 138 : state.dataRuntimeLangProcessor->OnVariableNum = NewEMSVariable(state, "ON", 0, state.dataRuntimeLang->True);
137 138 : state.dataRuntimeLangProcessor->PiVariableNum = NewEMSVariable(state, "PI", 0, SetErlValueNumber(Constant::Pi));
138 92 : state.dataRuntimeLangProcessor->TimeStepsPerHourVariableNum =
139 138 : NewEMSVariable(state, "TIMESTEPSPERHOUR", 0, SetErlValueNumber(double(state.dataGlobal->TimeStepsInHour)));
140 :
141 : // Create dynamic built-in variables
142 138 : state.dataRuntimeLangProcessor->YearVariableNum = NewEMSVariable(state, "YEAR", 0);
143 138 : state.dataRuntimeLangProcessor->CalendarYearVariableNum = NewEMSVariable(state, "CALENDARYEAR", 0);
144 138 : state.dataRuntimeLangProcessor->MonthVariableNum = NewEMSVariable(state, "MONTH", 0);
145 138 : state.dataRuntimeLangProcessor->DayOfMonthVariableNum = NewEMSVariable(state, "DAYOFMONTH", 0); // 'DAYOFMONTH'?
146 138 : state.dataRuntimeLangProcessor->DayOfWeekVariableNum = NewEMSVariable(state, "DAYOFWEEK", 0);
147 138 : state.dataRuntimeLangProcessor->DayOfYearVariableNum = NewEMSVariable(state, "DAYOFYEAR", 0);
148 138 : state.dataRuntimeLangProcessor->HourVariableNum = NewEMSVariable(state, "HOUR", 0);
149 138 : state.dataRuntimeLangProcessor->TimeStepNumVariableNum = NewEMSVariable(state, "TIMESTEPNUM", 0);
150 138 : state.dataRuntimeLangProcessor->MinuteVariableNum = NewEMSVariable(state, "MINUTE", 0);
151 138 : state.dataRuntimeLangProcessor->HolidayVariableNum = NewEMSVariable(state, "HOLIDAY", 0);
152 138 : state.dataRuntimeLangProcessor->DSTVariableNum = NewEMSVariable(state, "DAYLIGHTSAVINGS", 0);
153 138 : state.dataRuntimeLangProcessor->CurrentTimeVariableNum = NewEMSVariable(state, "CURRENTTIME", 0);
154 138 : state.dataRuntimeLangProcessor->SunIsUpVariableNum = NewEMSVariable(state, "SUNISUP", 0);
155 138 : state.dataRuntimeLangProcessor->IsRainingVariableNum = NewEMSVariable(state, "ISRAINING", 0);
156 138 : state.dataRuntimeLangProcessor->SystemTimeStepVariableNum = NewEMSVariable(state, "SYSTEMTIMESTEP", 0);
157 138 : state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum = NewEMSVariable(state, "ZONETIMESTEP", 0);
158 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum).Value =
159 92 : SetErlValueNumber(state.dataGlobal->TimeStepZone);
160 138 : state.dataRuntimeLangProcessor->CurrentEnvironmentPeriodNum = NewEMSVariable(state, "CURRENTENVIRONMENT", 0);
161 138 : state.dataRuntimeLangProcessor->ActualDateAndTimeNum = NewEMSVariable(state, "ACTUALDATEANDTIME", 0);
162 138 : state.dataRuntimeLangProcessor->ActualTimeNum = NewEMSVariable(state, "ACTUALTIME", 0);
163 138 : state.dataRuntimeLangProcessor->WarmUpFlagNum = NewEMSVariable(state, "WARMUPFLAG", 0);
164 :
165 : // update the end of the built-in range so we can ignore those on API calls
166 46 : state.dataRuntimeLang->emsVarBuiltInEnd = state.dataRuntimeLang->NumErlVariables;
167 :
168 46 : GetRuntimeLanguageUserInput(state); // Load and parse all runtime language objects
169 :
170 46 : date_and_time(datestring, _, _, datevalues);
171 46 : if (datestring != "") {
172 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ActualDateAndTimeNum).Value =
173 92 : SetErlValueNumber(double(sum(datevalues)));
174 : // datevalues(1)+datevalues(2)+datevalues(3)+ &
175 : // datevalues(5)+datevalues(6)+datevalues(7)+datevalues(8)
176 46 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->ActualTimeNum).Value =
177 92 : SetErlValueNumber(double(sum(datevalues({5, 8}))));
178 : // datevalues(5)+datevalues(6)+datevalues(7)+datevalues(8)
179 : // ELSE
180 : // ErlVariable(ActualDateAndTimeNum)%Value = SetErlValueNumber(REAL(RANDOM_NUMBER(X=509),r64))
181 : // ErlVariable(ActualTimeNum)%Value = SetErlValueNumber(REAL(RANDOM_NUMBER(X=400),r64))
182 : }
183 :
184 46 : state.dataRuntimeLangProcessor->InitializeOnce = false;
185 46 : }
186 :
187 : // Update built-in variables
188 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->YearVariableNum).Value = SetErlValueNumber(double(state.dataEnvrn->Year));
189 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CalendarYearVariableNum).Value =
190 2934932 : SetErlValueNumber(double(state.dataGlobal->CalendarYear));
191 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->MonthVariableNum).Value = SetErlValueNumber(double(state.dataEnvrn->Month));
192 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfMonthVariableNum).Value =
193 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfMonth));
194 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfWeekVariableNum).Value =
195 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfWeek));
196 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DayOfYearVariableNum).Value =
197 2934932 : SetErlValueNumber(double(state.dataEnvrn->DayOfYear));
198 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->TimeStepNumVariableNum).Value =
199 2934932 : SetErlValueNumber(double(state.dataGlobal->TimeStep));
200 :
201 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->DSTVariableNum).Value =
202 2934932 : SetErlValueNumber(double(state.dataEnvrn->DSTIndicator));
203 : // DSTadjust = REAL(DSTIndicator, r64)
204 1467466 : tmpHours = double(state.dataGlobal->HourOfDay - 1); // no, just stay on 0..23+ DSTadjust ! offset by 1 and daylight savings time
205 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HourVariableNum).Value = SetErlValueNumber(tmpHours);
206 :
207 1467466 : if (TimeStepSys < state.dataGlobal->TimeStepZone) {
208 : // CurrentTime is for end of zone timestep, need to account for system timestep
209 102784 : tmpCurrentTime = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed + TimeStepSys;
210 : } else {
211 1364682 : tmpCurrentTime = state.dataGlobal->CurrentTime;
212 : }
213 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CurrentTimeVariableNum).Value = SetErlValueNumber(tmpCurrentTime);
214 1467466 : tmpMinutes = ((tmpCurrentTime - double(state.dataGlobal->HourOfDay - 1)) * 60.0); // -1.0 // off by 1
215 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->MinuteVariableNum).Value = SetErlValueNumber(tmpMinutes);
216 : // Subtract 7 from HolidayIndex to maintain compatability for EMS where 1=Holiday,2=SummerDesignDay, 3=WinterDesignDay, 4=CustomDay1,
217 : // 5=CustomDay2, but not <0
218 1467466 : if (state.dataEnvrn->HolidayIndex == 0) {
219 635 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HolidayVariableNum).Value = SetErlValueNumber(0.0);
220 : } else {
221 1466831 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->HolidayVariableNum).Value =
222 2933662 : SetErlValueNumber(double(state.dataEnvrn->HolidayIndex - 7));
223 : }
224 1467466 : if (state.dataEnvrn->SunIsUp) {
225 706926 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SunIsUpVariableNum).Value = SetErlValueNumber(1.0);
226 : } else {
227 760540 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SunIsUpVariableNum).Value = SetErlValueNumber(0.0);
228 : }
229 1467466 : if (state.dataEnvrn->IsRain) {
230 0 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->IsRainingVariableNum).Value = SetErlValueNumber(1.0);
231 : } else {
232 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->IsRainingVariableNum).Value = SetErlValueNumber(0.0);
233 : }
234 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->SystemTimeStepVariableNum).Value = SetErlValueNumber(TimeStepSys);
235 :
236 1467466 : tmpCurEnvirNum = double(state.dataEnvrn->CurEnvirNum);
237 1467466 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->CurrentEnvironmentPeriodNum).Value = SetErlValueNumber(tmpCurEnvirNum);
238 1467466 : if (state.dataGlobal->WarmupFlag) {
239 1338648 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->WarmUpFlagNum).Value = SetErlValueNumber(1.0);
240 : } else {
241 128818 : state.dataRuntimeLang->ErlVariable(state.dataRuntimeLangProcessor->WarmUpFlagNum).Value = SetErlValueNumber(0.0);
242 : }
243 1467466 : }
244 :
245 90 : void BeginEnvrnInitializeRuntimeLanguage(EnergyPlusData &state)
246 : {
247 :
248 : // SUBROUTINE INFORMATION:
249 : // AUTHOR B. Griffith
250 : // DATE WRITTEN March 2010
251 : // MODIFIED B. Griffith, added Sensor initialation
252 : // RE-ENGINEERED na
253 :
254 : // PURPOSE OF THIS SUBROUTINE:
255 : // re initialize Erl for new simulation environment period
256 :
257 : // METHODOLOGY EMPLOYED:
258 : // na
259 :
260 : // REFERENCES:
261 : // na
262 :
263 : // Using/Aliasing
264 : using OutputProcessor::SetInternalVariableValue;
265 :
266 : // Locals
267 : // SUBROUTINE ARGUMENT DEFINITIONS:
268 : // na
269 :
270 : // SUBROUTINE PARAMETER DEFINITIONS:
271 : // na
272 :
273 : // INTERFACE BLOCK SPECIFICATIONS:
274 : // na
275 :
276 : // DERIVED TYPE DEFINITIONS:
277 : // na
278 :
279 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
280 : int ActuatorUsedLoop;
281 : int EMSActuatorVariableNum;
282 : int ErlVariableNum;
283 : int TrendVarNum;
284 : int SensorNum;
285 : int TrendDepth;
286 : int loop;
287 : bool CycleThisVariable;
288 :
289 : // reinitialize state of Erl variable values to zero, this gets sensors and internal variables used
290 3093 : for (ErlVariableNum = 1; ErlVariableNum <= state.dataRuntimeLang->NumErlVariables; ++ErlVariableNum) {
291 : // but skip constant built-in variables so don't overwrite them
292 3003 : if (ErlVariableNum == state.dataRuntimeLangProcessor->NullVariableNum) continue;
293 2913 : if (ErlVariableNum == state.dataRuntimeLangProcessor->FalseVariableNum) continue;
294 2823 : if (ErlVariableNum == state.dataRuntimeLangProcessor->TrueVariableNum) continue;
295 2733 : if (ErlVariableNum == state.dataRuntimeLangProcessor->OffVariableNum) continue;
296 2643 : if (ErlVariableNum == state.dataRuntimeLangProcessor->OnVariableNum) continue;
297 2553 : if (ErlVariableNum == state.dataRuntimeLangProcessor->PiVariableNum) continue;
298 2463 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ZoneTimeStepVariableNum) continue;
299 2373 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ActualDateAndTimeNum) continue;
300 2283 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ActualTimeNum) continue;
301 :
302 : // need to preserve curve index variables
303 2193 : CycleThisVariable = false;
304 4593 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSCurveIndices; ++loop) {
305 2400 : if (ErlVariableNum == state.dataRuntimeLangProcessor->CurveIndexVariableNums(loop)) CycleThisVariable = true;
306 : }
307 2193 : if (CycleThisVariable) continue;
308 2178 : CycleThisVariable = false;
309 2346 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSConstructionIndices; ++loop) {
310 168 : if (ErlVariableNum == state.dataRuntimeLangProcessor->ConstructionIndexVariableNums(loop)) CycleThisVariable = true;
311 : }
312 2178 : if (CycleThisVariable) continue;
313 :
314 2170 : if (state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value.initialized) {
315 2057 : state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value =
316 4114 : SetErlValueNumber(0.0, state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value);
317 : }
318 : }
319 : // reinitialize state of actuators
320 160 : for (ActuatorUsedLoop = 1; ActuatorUsedLoop <= state.dataRuntimeLang->numActuatorsUsed + state.dataRuntimeLang->NumExternalInterfaceActuatorsUsed;
321 : ++ActuatorUsedLoop) {
322 70 : EMSActuatorVariableNum = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ActuatorVariableNum;
323 70 : ErlVariableNum = state.dataRuntimeLang->EMSActuatorUsed(ActuatorUsedLoop).ErlVariableNum;
324 70 : state.dataRuntimeLang->ErlVariable(ErlVariableNum).Value.Type = Value::Null;
325 70 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).Actuated = false;
326 70 : switch (state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).PntrVarTypeUsed) {
327 66 : case PtrDataType::Real:
328 66 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).RealValue = 0.0;
329 66 : break;
330 4 : case PtrDataType::Integer:
331 4 : *state.dataRuntimeLang->EMSActuatorAvailable(EMSActuatorVariableNum).IntValue = 0;
332 4 : 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 91 : for (TrendVarNum = 1; TrendVarNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendVarNum) {
343 1 : TrendDepth = state.dataRuntimeLang->TrendVariable(TrendVarNum).LogDepth;
344 1 : state.dataRuntimeLang->TrendVariable(TrendVarNum).TrendValARR({1, TrendDepth}) = 0.0;
345 : }
346 :
347 : // reinitilize sensors
348 113 : for (SensorNum = 1; SensorNum <= state.dataRuntimeLang->NumSensors; ++SensorNum) {
349 46 : SetInternalVariableValue(
350 23 : state, state.dataRuntimeLang->Sensor(SensorNum).VariableType, state.dataRuntimeLang->Sensor(SensorNum).Index, 0.0, 0);
351 : }
352 90 : }
353 :
354 37 : 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 37 : int constexpr IfDepthAllowed(5); // depth of IF block nesting
378 37 : int constexpr ELSEIFLengthAllowed(200); // number of ELSEIFs allowed
379 37 : 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 37 : std::string Line; // local copy of a single line of Erl program code
388 37 : std::string Keyword; // local copy of statement keyword parsed from line (Run, Set, If, etc)
389 37 : std::string Remainder; // local copy of what is left for text in the line after keyword
390 37 : std::string Expression;
391 37 : 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 37 : Array1D_int SavedIfInstructionNum(IfDepthAllowed); // index is depth of If statements
398 37 : Array2D_int SavedGotoInstructionNum(ELSEIFLengthAllowed, IfDepthAllowed);
399 37 : Array1D_int NumGotos(IfDepthAllowed); // index is depth of If statements,
400 : int SavedWhileInstructionNum;
401 : int SavedWhileExpressionNum;
402 : int NumWhileGotos;
403 37 : Array1D_bool ReadyForElse(IfDepthAllowed);
404 37 : Array1D_bool ReadyForEndif(IfDepthAllowed);
405 :
406 37 : LineNum = 1;
407 37 : NestedIfDepth = 0;
408 37 : ReadyForElse = false;
409 37 : ReadyForEndif = false;
410 37 : SavedIfInstructionNum = 0;
411 37 : SavedGotoInstructionNum = 0;
412 37 : NumGotos = 0;
413 37 : NestedWhileDepth = 0;
414 37 : SavedWhileInstructionNum = 0;
415 37 : SavedWhileExpressionNum = 0;
416 37 : NumWhileGotos = 0;
417 :
418 37 : auto &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
419 :
420 451 : while (LineNum <= thisErlStack.NumLines) {
421 :
422 414 : Line = stripped(thisErlStack.Line(LineNum));
423 414 : if (len(Line) == 0) {
424 0 : ++LineNum;
425 0 : continue; // Blank lines can be skipped
426 : }
427 :
428 414 : Pos = scan(Line, ' ');
429 414 : if (Pos == std::string::npos) {
430 48 : Pos = len(Line);
431 48 : Remainder.clear();
432 : } else {
433 366 : Remainder = stripped(Line.substr(Pos + 1));
434 : }
435 : // Keyword = Util::makeUPPER(Line(1:Pos-1))
436 414 : 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 414 : if (Keyword == "RETURN") {
440 1 : if (state.dataSysVars->DeveloperFlag) {
441 0 : print(state.files.debug, "RETURN \"{}\"\n", Line);
442 : }
443 1 : if (Remainder.empty()) {
444 1 : 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 413 : } else if (Keyword == "SET") {
451 333 : if (state.dataSysVars->DeveloperFlag) {
452 0 : print(state.files.debug, "SET \"{}\"\n", Line);
453 : }
454 333 : Pos = scan(Remainder, '=');
455 333 : if (Pos == std::string::npos) {
456 0 : AddError(state, StackNum, LineNum, "Equal sign missing for the SET instruction.");
457 333 : } else if (Pos == 0) {
458 0 : AddError(state, StackNum, LineNum, "Variable name missing for the SET instruction.");
459 : } else {
460 333 : Variable = stripped(Remainder.substr(0, Pos)); // VariableName would be more expressive
461 333 : VariableNum = NewEMSVariable(state, Variable, StackNum);
462 : // Check for invalid variable name
463 :
464 333 : if (Pos + 1 < Remainder.length()) {
465 333 : Expression = stripped(Remainder.substr(Pos + 1));
466 : } else {
467 0 : Expression.clear();
468 : }
469 333 : if (Expression.empty()) {
470 0 : AddError(state, StackNum, LineNum, "Expression missing for the SET instruction.");
471 : } else {
472 333 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
473 333 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Set, VariableNum, ExpressionNum);
474 : }
475 : }
476 :
477 80 : } else if (Keyword == "RUN") {
478 1 : if (state.dataSysVars->DeveloperFlag) {
479 0 : print(state.files.debug, "RUN \"{}\"\n", Line);
480 : }
481 1 : if (Remainder.empty()) {
482 0 : AddError(state, StackNum, LineNum, "Program or Subroutine name missing for the RUN instruction.");
483 : } else {
484 1 : Pos = scan(Remainder, ' ');
485 1 : if (Pos == std::string::npos) Pos = Remainder.length();
486 1 : Variable = Util::makeUPPER(stripped(Remainder.substr(0, Pos))); // really the subroutine, or reference to instruction set
487 1 : StackNum2 = Util::FindItemInList(Variable, state.dataRuntimeLang->ErlStack);
488 1 : if (StackNum2 == 0) {
489 0 : AddError(state, StackNum, LineNum, "Program or Subroutine name [" + Variable + "] not found for the RUN instruction.");
490 : } else {
491 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Run, StackNum2);
492 : }
493 : }
494 :
495 79 : } else if (Keyword == "IF") {
496 26 : if (state.dataSysVars->DeveloperFlag) {
497 0 : print(state.files.debug, "IF \"{}\"\n", Line);
498 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
499 : }
500 26 : if (Remainder.empty()) {
501 0 : AddError(state, StackNum, LineNum, "Expression missing for the IF instruction.");
502 0 : ExpressionNum = 0;
503 : } else {
504 26 : Expression = stripped(Remainder);
505 26 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
506 : }
507 :
508 26 : ++NestedIfDepth;
509 26 : ReadyForElse(NestedIfDepth) = true;
510 26 : ReadyForEndif(NestedIfDepth) = true;
511 26 : 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 26 : InstructionNum = AddInstruction(state,
516 : StackNum,
517 : LineNum,
518 : DataRuntimeLanguage::ErlKeywordParam::If,
519 : ExpressionNum); // Arg2 added at next ELSEIF, ELSE, ENDIF
520 26 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
521 : }
522 :
523 53 : } else if (Keyword == "ELSEIF") {
524 5 : if (state.dataSysVars->DeveloperFlag) {
525 0 : print(state.files.debug, "ELSEIF \"{}\"\n", Line);
526 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
527 : }
528 5 : 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 5 : InstructionNum = AddInstruction(state, StackNum, 0, DataRuntimeLanguage::ErlKeywordParam::Goto); // Arg2 is added at the ENDIF
535 5 : ++NumGotos(NestedIfDepth);
536 5 : 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 5 : SavedGotoInstructionNum(NumGotos(NestedIfDepth), NestedIfDepth) = InstructionNum;
541 : }
542 :
543 5 : if (Remainder.empty()) {
544 0 : AddError(state, StackNum, LineNum, "Expression missing for the ELSEIF instruction.");
545 0 : ExpressionNum = 0;
546 : } else {
547 5 : Expression = stripped(Remainder);
548 5 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
549 : }
550 :
551 5 : InstructionNum = AddInstruction(state,
552 : StackNum,
553 : LineNum,
554 : DataRuntimeLanguage::ErlKeywordParam::If,
555 : ExpressionNum); // Arg2 added at next ELSEIF, ELSE, ENDIF
556 5 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
557 5 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
558 :
559 48 : } else if (Keyword == "ELSE") {
560 20 : if (state.dataSysVars->DeveloperFlag) {
561 0 : print(state.files.debug, "ELSE \"{}\"\n", Line);
562 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
563 : }
564 20 : 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 20 : if (!ReadyForElse(NestedIfDepth)) {
569 0 : AddError(state, StackNum, LineNum, "ELSE statement without corresponding IF statement.");
570 : }
571 20 : ReadyForElse(NestedIfDepth) = false;
572 :
573 : // Complete the preceding block with a GOTO instruction
574 20 : InstructionNum = AddInstruction(state, StackNum, 0, DataRuntimeLanguage::ErlKeywordParam::Goto); // Arg2 is added at the ENDIF
575 20 : ++NumGotos(NestedIfDepth);
576 20 : 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 20 : SavedGotoInstructionNum(NumGotos(NestedIfDepth), NestedIfDepth) = InstructionNum;
581 : }
582 :
583 20 : if (!Remainder.empty()) {
584 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ELSE instruction.");
585 : }
586 :
587 20 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::Else); // can make this into a KeywordIf?
588 20 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
589 20 : SavedIfInstructionNum(NestedIfDepth) = InstructionNum;
590 :
591 28 : } else if (Keyword == "ENDIF") {
592 26 : if (state.dataSysVars->DeveloperFlag) {
593 0 : print(state.files.debug, "ENDIF \"{}\"\n", Line);
594 0 : print(state.files.debug, "NestedIf={}\n", NestedIfDepth);
595 : }
596 26 : 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 26 : if (!ReadyForEndif(NestedIfDepth)) {
602 0 : AddError(state, StackNum, LineNum, "ENDIF statement without corresponding IF stetement.");
603 : }
604 26 : ReadyForEndif(NestedIfDepth) = false;
605 26 : ReadyForElse(NestedIfDepth) = false;
606 :
607 26 : if (!Remainder.empty()) {
608 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ENDIF instruction.");
609 : }
610 :
611 26 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::EndIf);
612 26 : thisErlStack.Instruction(SavedIfInstructionNum(NestedIfDepth)).Argument2 = InstructionNum;
613 :
614 : // Go back and complete all of the GOTOs that terminate each IF and ELSEIF block
615 51 : for (GotoNum = 1; GotoNum <= NumGotos(NestedIfDepth); ++GotoNum) {
616 25 : InstructionNum2 = SavedGotoInstructionNum(GotoNum, NestedIfDepth);
617 25 : thisErlStack.Instruction(InstructionNum2).Argument1 = InstructionNum;
618 25 : SavedGotoInstructionNum(GotoNum, NestedIfDepth) = 0;
619 : }
620 :
621 26 : NumGotos(NestedIfDepth) = 0;
622 26 : SavedIfInstructionNum(NestedIfDepth) = 0;
623 26 : --NestedIfDepth;
624 :
625 2 : } else if (Keyword == "WHILE") {
626 1 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "WHILE \"{}\"\n", Line);
627 1 : if (Remainder.empty()) {
628 0 : AddError(state, StackNum, LineNum, "Expression missing for the WHILE instruction.");
629 0 : ExpressionNum = 0;
630 : } else {
631 1 : Expression = stripped(Remainder);
632 1 : ParseExpression(state, Expression, StackNum, ExpressionNum, Line);
633 : }
634 :
635 1 : ++NestedWhileDepth;
636 1 : 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 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::While, ExpressionNum);
641 1 : SavedWhileInstructionNum = InstructionNum;
642 1 : SavedWhileExpressionNum = ExpressionNum;
643 : }
644 :
645 1 : } else if (Keyword == "ENDWHILE") {
646 1 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "ENDWHILE \"{}\"\n", Line);
647 1 : if (NestedWhileDepth == 0) {
648 0 : AddError(state, StackNum, LineNum, "Starting WHILE instruction missing for the ENDWHILE instruction.");
649 0 : break;
650 : }
651 1 : if (!Remainder.empty()) {
652 0 : AddError(state, StackNum, LineNum, "Nothing is allowed to follow the ENDWHILE instruction.");
653 : }
654 :
655 1 : InstructionNum = AddInstruction(state, StackNum, LineNum, DataRuntimeLanguage::ErlKeywordParam::EndWhile);
656 1 : thisErlStack.Instruction(SavedWhileInstructionNum).Argument2 = InstructionNum;
657 1 : thisErlStack.Instruction(InstructionNum).Argument1 = SavedWhileExpressionNum;
658 1 : thisErlStack.Instruction(InstructionNum).Argument2 = SavedWhileInstructionNum;
659 :
660 1 : NestedWhileDepth = 0;
661 1 : SavedWhileInstructionNum = 0;
662 1 : 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 414 : ++LineNum;
670 : } // LineNum
671 :
672 37 : if (NestedIfDepth == 1) {
673 0 : AddError(state, StackNum, 0, "Missing an ENDIF instruction needed to terminate an earlier IF instruction.");
674 37 : } 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 37 : }
681 :
682 439 : 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 439 : ErlStackType TempStack;
711 :
712 439 : auto &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
713 :
714 439 : if (thisErlStack.NumInstructions == 0) {
715 37 : thisErlStack.Instruction.allocate(1);
716 37 : thisErlStack.NumInstructions = 1;
717 : } else {
718 402 : TempStack = thisErlStack;
719 402 : thisErlStack.Instruction.deallocate();
720 402 : thisErlStack.Instruction.allocate(thisErlStack.NumInstructions + 1);
721 402 : thisErlStack.Instruction({1, thisErlStack.NumInstructions}) = TempStack.Instruction({1, thisErlStack.NumInstructions});
722 402 : ++thisErlStack.NumInstructions;
723 : }
724 :
725 439 : InstructionNum = thisErlStack.NumInstructions;
726 439 : thisErlStack.Instruction(InstructionNum).LineNum = LineNum;
727 439 : thisErlStack.Instruction(InstructionNum).Keyword = Keyword;
728 :
729 439 : if (present(Argument1)) {
730 366 : thisErlStack.Instruction(InstructionNum).Argument1 = Argument1;
731 : }
732 439 : if (present(Argument2)) {
733 333 : thisErlStack.Instruction(InstructionNum).Argument2 = Argument2;
734 : }
735 :
736 439 : return InstructionNum;
737 439 : }
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 27370 : 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 27370 : 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 27370 : bool seriousErrorFound(false); // once it gets set true (inside EvaluateExpresssion) it will trigger a fatal (in WriteTrace)
812 :
813 27370 : WhileLoopExitCounter = 0;
814 27370 : ReturnValue.Type = Value::Number;
815 27370 : ReturnValue.Number = 0.0;
816 :
817 27370 : auto const &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum);
818 :
819 27370 : InstructionNum = 1;
820 834244 : while (InstructionNum <= thisErlStack.NumInstructions) {
821 :
822 810998 : auto const &thisInstruction = thisErlStack.Instruction(InstructionNum);
823 :
824 : {
825 810998 : DataRuntimeLanguage::ErlKeywordParam const SELECT_CASE_var = thisInstruction.Keyword;
826 :
827 810998 : if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::None) {
828 : // There probably shouldn't be any of these
829 :
830 810998 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Return) {
831 4124 : if (thisInstruction.Argument1 > 0) ReturnValue = EvaluateExpression(state, thisInstruction.Argument1, seriousErrorFound);
832 4124 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
833 4124 : break; // RETURN always terminates an instruction stack
834 :
835 806874 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Set) {
836 :
837 610835 : ESVariableNum = thisInstruction.Argument1;
838 610835 : auto &thisErlVar = state.dataRuntimeLang->ErlVariable(ESVariableNum);
839 610835 : ReturnValue = EvaluateExpression(state, thisInstruction.Argument2, seriousErrorFound);
840 610835 : 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 610831 : thisErlVar.Value.Type = ReturnValue.Type;
843 610831 : thisErlVar.Value.Number = ReturnValue.Number;
844 : // thisErlVar.Value.String = ReturnValue.String;
845 610831 : thisErlVar.Value.Error = ReturnValue.Error;
846 610831 : thisErlVar.Value.initialized = ReturnValue.initialized;
847 4 : } else if (thisErlVar.Value.TrendVariable) {
848 4 : thisErlVar.Value.Number = ReturnValue.Number;
849 4 : thisErlVar.Value.Error = ReturnValue.Error;
850 : }
851 :
852 610835 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
853 :
854 196039 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Run) {
855 2 : ReturnValue.Type = Value::String;
856 2 : ReturnValue.String = "";
857 2 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
858 2 : ReturnValue = EvaluateStack(state, thisInstruction.Argument1);
859 196037 : } else if ((SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::If) ||
860 : (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Else)) { // same???
861 74518 : ExpressionNum = thisInstruction.Argument1;
862 74518 : InstructionNum2 = thisInstruction.Argument2;
863 74518 : if (ExpressionNum > 0) { // could be 0 if this was an ELSE
864 72197 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
865 72197 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
866 72197 : if (ReturnValue.Number == 0.0) { // This is the FALSE case
867 : // Eventually should handle strings and arrays too
868 31215 : InstructionNum = InstructionNum2;
869 31215 : continue;
870 : }
871 : } else {
872 : // KeywordELSE -- kind of a kludge
873 2321 : ReturnValue.Type = Value::Number;
874 2321 : ReturnValue.Number = 1.0;
875 2321 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
876 : }
877 121519 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::Goto) {
878 20132 : InstructionNum = thisInstruction.Argument1;
879 :
880 : // For debug purposes only...
881 20132 : ReturnValue.Type = Value::String;
882 20132 : ReturnValue.String = ""; // IntegerToString(InstructionNum)
883 :
884 20132 : continue;
885 : // PE if this ever went out of bounds, would the DO loop save it? or need check here?
886 :
887 101387 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::EndIf) {
888 68055 : ReturnValue.Type = Value::String;
889 68055 : ReturnValue.String = "";
890 68055 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
891 :
892 33332 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::While) {
893 : // evaluate expression at while, skip to past endwhile if not true
894 16666 : ExpressionNum = thisInstruction.Argument1;
895 16666 : InstructionNum2 = thisInstruction.Argument2;
896 16666 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
897 16666 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
898 16666 : 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 16666 : } else if (SELECT_CASE_var == DataRuntimeLanguage::ErlKeywordParam::EndWhile) {
904 :
905 : // reevaluate expression at While and goto there if true, otherwise continue
906 16666 : ExpressionNum = thisInstruction.Argument1;
907 16666 : InstructionNum2 = thisInstruction.Argument2;
908 16666 : ReturnValue = EvaluateExpression(state, ExpressionNum, seriousErrorFound);
909 16666 : if ((ReturnValue.Number != 0.0) && (WhileLoopExitCounter <= MaxWhileLoopIterations)) { // This is the True case
910 : // Eventually should handle strings and arrays too
911 12596 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound); // duplicative?
912 12596 : InstructionNum = InstructionNum2;
913 12596 : ++WhileLoopExitCounter;
914 :
915 12596 : continue;
916 : } else { // false, leave while block
917 4070 : 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 4070 : ReturnValue.Type = Value::Number;
924 4070 : ReturnValue.Number = 0.0;
925 4070 : WriteTrace(state, StackNum, InstructionNum, ReturnValue, seriousErrorFound);
926 4070 : WhileLoopExitCounter = 0;
927 : }
928 : }
929 : } else {
930 0 : ShowFatalError(state, "Fatal error in RunStack: Unknown keyword.");
931 : }
932 : }
933 :
934 742931 : ++InstructionNum;
935 : } // InstructionNum
936 :
937 54740 : return ReturnValue;
938 0 : }
939 :
940 790866 : 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 790866 : std::string NameString;
963 790866 : std::string LineNumString;
964 790866 : std::string LineString;
965 790866 : std::string cValueString;
966 790866 : std::string TimeString;
967 790866 : std::string DuringWarmup;
968 :
969 790866 : if ((!state.dataRuntimeLang->OutputFullEMSTrace) && (!state.dataRuntimeLang->OutputEMSErrors) && (!seriousErrorFound)) return;
970 :
971 783421 : if ((state.dataRuntimeLang->OutputEMSErrors) && (!state.dataRuntimeLang->OutputFullEMSTrace) && (!seriousErrorFound)) {
972 : // see if error needs to be reported.
973 783414 : if (ReturnValue.Type != Value::Error) return;
974 : }
975 :
976 7 : if (!state.dataRuntimeLangProcessor->WriteTraceMyOneTimeFlag) {
977 3 : print(state.files.edd, "**** Begin EMS Language Processor Error and Trace Output *** \n");
978 3 : print(state.files.edd, "<Erl program name, line #, line text, result, occurrence timing information ... >\n");
979 3 : state.dataRuntimeLangProcessor->WriteTraceMyOneTimeFlag = true;
980 : }
981 : // if have not return'd yet then write out full trace
982 :
983 7 : NameString = state.dataRuntimeLang->ErlStack(StackNum).Name;
984 7 : LineNum = state.dataRuntimeLang->ErlStack(StackNum).Instruction(InstructionNum).LineNum;
985 7 : LineNumString = fmt::to_string(LineNum);
986 7 : LineString = state.dataRuntimeLang->ErlStack(StackNum).Line(LineNum);
987 7 : cValueString = ValueToString(ReturnValue);
988 :
989 : // put together timestamp info
990 7 : if (state.dataGlobal->WarmupFlag) {
991 0 : if (!state.dataGlobal->DoingSizing) {
992 0 : DuringWarmup = " During Warmup, Occurrence info=";
993 : } else {
994 0 : DuringWarmup = " During Warmup & Sizing, Occurrence info=";
995 : }
996 : } else {
997 7 : if (!state.dataGlobal->DoingSizing) {
998 7 : DuringWarmup = " Occurrence info=";
999 : } else {
1000 0 : DuringWarmup = " During Sizing, Occurrence info=";
1001 : }
1002 : }
1003 7 : TimeString = DuringWarmup + state.dataEnvrn->EnvironmentName + ", " + state.dataEnvrn->CurMnDy + ' ' + CreateSysTimeIntervalString(state);
1004 :
1005 7 : if (state.dataRuntimeLang->OutputFullEMSTrace || (state.dataRuntimeLang->OutputEMSErrors && (ReturnValue.Type == Value::Error))) {
1006 7 : print(state.files.edd, "{},Line {},{},{},{}\n", NameString, LineNumString, LineString, cValueString, TimeString);
1007 : }
1008 :
1009 7 : if (seriousErrorFound) { // throw EnergyPlus severe then fatal
1010 0 : ShowSevereError(state, "Problem found in EMS EnergyPlus Runtime Language.");
1011 0 : ShowContinueError(state, format("Erl program name: {}", NameString));
1012 0 : ShowContinueError(state, format("Erl program line number: {}", LineNumString));
1013 0 : ShowContinueError(state, format("Erl program line text: {}", LineString));
1014 0 : ShowContinueError(state, format("Error message: {}", cValueString));
1015 0 : ShowContinueErrorTimeStamp(state, "");
1016 0 : ShowFatalError(state, "Previous EMS error caused program termination.");
1017 : }
1018 4745161 : }
1019 :
1020 : //******************************************************************************************
1021 :
1022 : // Expression Processor
1023 :
1024 : //******************************************************************************************
1025 :
1026 365 : 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 365 : 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 365 : 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 365 : CountDoLooping = 0;
1070 365 : NumErrors = 0;
1071 : // Error = 'No errors.'
1072 :
1073 : // Break the string into tokens
1074 365 : int NumTokens(0);
1075 365 : 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 365 : assert(!String.empty());
1083 365 : if (String[0] == '-') {
1084 9 : String = "0" + String;
1085 356 : } else if (String[0] == '+') {
1086 0 : String = "0" + String;
1087 : }
1088 365 : std::string::size_type LastPos(String.length());
1089 365 : Pos = 0;
1090 365 : OperatorProcessing = false; // true when an operator is found until terminated by non-operator
1091 365 : MinusFound = false;
1092 365 : MultFound = false;
1093 365 : DivFound = false;
1094 1993 : while (Pos < LastPos) {
1095 1628 : ++CountDoLooping;
1096 1628 : 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 1628 : NextChar = String[Pos];
1103 1628 : if (NextChar == ' ') {
1104 544 : ++Pos;
1105 544 : continue;
1106 : }
1107 :
1108 : // Extend the token array
1109 1084 : state.dataRuntimeLangProcessor->PEToken.redimension(++NumTokens);
1110 :
1111 : // Get the next token
1112 1084 : StringToken = "";
1113 1084 : PeriodFound = false;
1114 1084 : PlusFound = false;
1115 1084 : ErrorFlag = false;
1116 1084 : LastED = false;
1117 1084 : if (is_any_of(NextChar, "0123456789.")) {
1118 : // Parse a number literal token
1119 300 : ++Pos;
1120 300 : StringToken += NextChar;
1121 300 : OperatorProcessing = false;
1122 300 : MultFound = false;
1123 300 : DivFound = false;
1124 :
1125 300 : if (NextChar == '.') PeriodFound = true;
1126 :
1127 1011 : while (Pos < LastPos) {
1128 828 : NextChar = String[Pos];
1129 828 : if (is_any_of(NextChar, "0123456789.eEdD")) {
1130 711 : ++Pos;
1131 711 : if (NextChar == '.') {
1132 206 : 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 206 : PeriodFound = true;
1143 : }
1144 : }
1145 711 : if (is_any_of(NextChar, "eEdD")) {
1146 0 : StringToken += NextChar;
1147 0 : 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 0 : LastED = true;
1158 : }
1159 : } else {
1160 711 : StringToken += NextChar;
1161 : }
1162 117 : } else if (is_any_of(NextChar, "+-")) { // +/- following an ED is okay.
1163 19 : if (LastED) {
1164 0 : StringToken += NextChar;
1165 0 : ++Pos;
1166 0 : LastED = false;
1167 : } else {
1168 : // +/- will be processed on next pass, nothing needs to be done after a numeral
1169 19 : break;
1170 : }
1171 98 : } else if (is_any_of(NextChar, " +-*/^=<>)")) { // Any binary operator is okay
1172 98 : 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 300 : if (!ErrorFlag) {
1182 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Number;
1183 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1184 300 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "Number=\"{}\"\n", StringToken);
1185 300 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Number = Util::ProcessNumber(StringToken, ErrorFlag);
1186 300 : if (state.dataSysVars->DeveloperFlag && ErrorFlag) print(state.files.debug, "{}\n", "Numeric error flagged");
1187 300 : if (MinusFound) {
1188 0 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Number = -state.dataRuntimeLangProcessor->PEToken(NumTokens).Number;
1189 0 : MinusFound = false;
1190 : }
1191 300 : 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 784 : } else if (is_any_of(NextChar, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
1202 : // Parse an undetermined string token (could be a variable, subroutine, or named operator)
1203 346 : ++Pos;
1204 346 : StringToken += NextChar;
1205 346 : OperatorProcessing = false;
1206 346 : MultFound = false;
1207 346 : DivFound = false;
1208 :
1209 3451 : while (Pos < LastPos) {
1210 3304 : NextChar = String[Pos];
1211 3304 : if (is_any_of(NextChar, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")) {
1212 3105 : ++Pos;
1213 3105 : StringToken += NextChar;
1214 199 : } else if (is_any_of(NextChar, " +-*/^=<>()")) {
1215 199 : 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 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Variable;
1224 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1225 346 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "Variable=\"{}\"\n", StringToken);
1226 346 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Variable = NewEMSVariable(state, StringToken, StackNum);
1227 :
1228 438 : } else if (is_any_of(NextChar, "+-*/^=<>@|&")) {
1229 : // Parse an operator token
1230 300 : if (NextChar == '-') {
1231 64 : StringToken = "-";
1232 64 : 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 64 : } 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 64 : } 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 13 : OperatorProcessing = false;
1250 13 : String.insert(Pos, "0");
1251 13 : ++LastPos;
1252 13 : StringToken = "0";
1253 13 : MultFound = false;
1254 13 : DivFound = false;
1255 : } else {
1256 51 : StringToken = NextChar;
1257 51 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Operator;
1258 : }
1259 : } else { // any other character process as operator
1260 236 : StringToken = NextChar;
1261 236 : 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 6071 : const auto parse = [&](const char *string, ErlFunc op, bool case_insensitive) {
1267 6071 : const size_t len = strlen(string);
1268 6071 : const std::string potential_match = String.substr(Pos, len);
1269 :
1270 6071 : if ((case_insensitive && Util::SameString(potential_match, string)) || (!case_insensitive && potential_match == string)) {
1271 152 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "OPERATOR \"{}\"\n", potential_match);
1272 152 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = op;
1273 152 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = potential_match;
1274 152 : Pos += (len - 1);
1275 152 : return true;
1276 : } else {
1277 5919 : return false;
1278 : }
1279 6071 : };
1280 :
1281 : // case insensitive wrapper call to parse
1282 4371 : const auto i_parse = [&](const char *string, const ErlFunc op) { return parse(string, op, true); };
1283 :
1284 : // First check for two character operators: == <> <= >= || &&
1285 300 : std::string const cc(String.substr(Pos, 2));
1286 590 : if (parse("==", ErlFunc::Equal, false) || parse("<>", ErlFunc::NotEqual, false) || parse("<=", ErlFunc::LessOrEqual, false) ||
1287 590 : parse(">=", ErlFunc::GreaterOrEqual, false) || parse("||", ErlFunc::LogicalOR, false) || parse("&&", ErlFunc::LogicalAND, false)) {
1288 : // One of the comparision / logical operators
1289 32 : OperatorProcessing = true;
1290 :
1291 268 : } else if (String[Pos] == '@') { // next check for builtin functions signaled by "@"
1292 :
1293 239 : if (i_parse("@Round", ErlFunc::Round) || i_parse("@Mod", ErlFunc::Mod) || i_parse("@Sin", ErlFunc::Sin) ||
1294 113 : i_parse("@Cos", ErlFunc::Cos) || i_parse("@ArcCos", ErlFunc::ArcCos) || i_parse("@ArcSin", ErlFunc::ArcSin) ||
1295 109 : i_parse("@DegToRad", ErlFunc::DegToRad) || i_parse("@RadToDeg", ErlFunc::RadToDeg) || i_parse("@Exp", ErlFunc::Exp) ||
1296 104 : i_parse("@Ln", ErlFunc::Ln) || i_parse("@Max", ErlFunc::Max) || i_parse("@Min", ErlFunc::Min) || i_parse("@Abs", ErlFunc::ABS) ||
1297 92 : i_parse("@RANDOMUNIFORM", ErlFunc::RandU) || i_parse("@RANDOMNORMAL", ErlFunc::RandG) ||
1298 90 : i_parse("@SEEDRANDOM", ErlFunc::RandSeed) || i_parse("@RhoAirFnPbTdbW", ErlFunc::RhoAirFnPbTdbW) ||
1299 87 : i_parse("@CpAirFnW", ErlFunc::CpAirFnW) || i_parse("@HfgAirFnWTdb", ErlFunc::HfgAirFnWTdb) ||
1300 85 : i_parse("@HgAirFnWTdb", ErlFunc::HgAirFnWTdb) || i_parse("@TdpFnTdbTwbPb", ErlFunc::TdpFnTdbTwbPb) ||
1301 83 : i_parse("@TdpFnWPb", ErlFunc::TdpFnWPb) || i_parse("@HFnTdbW", ErlFunc::HFnTdbW) || i_parse("@HFnTdbRhPb", ErlFunc::HFnTdbRhPb) ||
1302 76 : i_parse("@TdbFnHW", ErlFunc::TdbFnHW) || i_parse("@RhovFnTdbRhLBnd0C", ErlFunc::RhovFnTdbRhLBnd0C) ||
1303 70 : i_parse("@RhovFnTdbRh", ErlFunc::RhovFnTdbRh) || i_parse("@RhovFnTdbWPb", ErlFunc::RhovFnTdbWPb) ||
1304 68 : i_parse("@RhFnTdbRhovLBnd0C", ErlFunc::RhFnTdbRhovLBnd0C) || i_parse("@RhFnTdbRhov", ErlFunc::RhFnTdbRhov) ||
1305 66 : i_parse("@RhFnTdbWPb", ErlFunc::RhFnTdbWPb) || i_parse("@TwbFnTdbWPb", ErlFunc::TwbFnTdbWPb) ||
1306 63 : i_parse("@VFnTdbWPb", ErlFunc::VFnTdbWPb) || i_parse("@WFnTdpPb", ErlFunc::WFnTdpPb) || i_parse("@WFnTdbH", ErlFunc::WFnTdbH) ||
1307 58 : i_parse("@WFnTdbTwbPb", ErlFunc::WFnTdbTwbPb) || i_parse("@WFnTdbRhPb", ErlFunc::WFnTdbRhPb) ||
1308 56 : i_parse("@PsatFnTemp", ErlFunc::PsatFnTemp) || i_parse("@TsatFnHPb", ErlFunc::TsatFnHPb) ||
1309 53 : i_parse("@TsatFnPb", ErlFunc::TsatFnPb) || i_parse("@CpCW", ErlFunc::CpCW) || i_parse("@CpHW", ErlFunc::CpHW) ||
1310 51 : i_parse("@RhoH2O", ErlFunc::RhoH2O) || i_parse("@FATALHALTEP", ErlFunc::FatalHaltEp) ||
1311 50 : i_parse("@SEVEREWARNEP", ErlFunc::SevereWarnEp) || i_parse("@WARNEP", ErlFunc::WarnEp) ||
1312 48 : i_parse("@TRENDVALUE", ErlFunc::TrendValue) || i_parse("@TRENDAVERAGE", ErlFunc::TrendAverage) ||
1313 42 : i_parse("@TRENDMAX", ErlFunc::TrendMax) || i_parse("@TRENDMIN", ErlFunc::TrendMin) ||
1314 38 : i_parse("@TRENDDIRECTION", ErlFunc::TrendDirection) || i_parse("@TRENDSUM", ErlFunc::TrendSum) ||
1315 34 : i_parse("@CURVEVALUE", ErlFunc::CurveValue) || i_parse("@TODAYISRAIN", ErlFunc::TodayIsRain) ||
1316 27 : i_parse("@TODAYISSNOW", ErlFunc::TodayIsSnow) || i_parse("@TODAYOUTDRYBULBTEMP", ErlFunc::TodayOutDryBulbTemp) ||
1317 25 : i_parse("@TODAYOUTDEWPOINTTEMP", ErlFunc::TodayOutDewPointTemp) || i_parse("@TODAYOUTBAROPRESS", ErlFunc::TodayOutBaroPress) ||
1318 23 : i_parse("@TODAYOUTRELHUM", ErlFunc::TodayOutRelHum) || i_parse("@TODAYWINDSPEED", ErlFunc::TodayWindSpeed) ||
1319 21 : i_parse("@TODAYWINDDIR", ErlFunc::TodayWindDir) || i_parse("@TODAYSKYTEMP", ErlFunc::TodaySkyTemp) ||
1320 19 : i_parse("@TODAYHORIZIRSKY", ErlFunc::TodayHorizIRSky) || i_parse("@TODAYBEAMSOLARRAD", ErlFunc::TodayBeamSolarRad) ||
1321 17 : i_parse("@TODAYDIFSOLARRAD", ErlFunc::TodayDifSolarRad) || i_parse("@TODAYALBEDO", ErlFunc::TodayAlbedo) ||
1322 15 : i_parse("@TODAYLIQUIDPRECIP", ErlFunc::TodayLiquidPrecip) || i_parse("@TOMORROWISRAIN", ErlFunc::TomorrowIsRain) ||
1323 13 : i_parse("@TOMORROWISSNOW", ErlFunc::TomorrowIsSnow) || i_parse("@TOMORROWOUTDRYBULBTEMP", ErlFunc::TomorrowOutDryBulbTemp) ||
1324 11 : i_parse("@TOMORROWOUTDEWPOINTTEMP", ErlFunc::TomorrowOutDewPointTemp) ||
1325 10 : i_parse("@TOMORROWOUTBAROPRESS", ErlFunc::TomorrowOutBaroPress) || i_parse("@TOMORROWOUTRELHUM", ErlFunc::TomorrowOutRelHum) ||
1326 8 : i_parse("@TOMORROWWINDSPEED", ErlFunc::TomorrowWindSpeed) || i_parse("@TOMORROWWINDDIR", ErlFunc::TomorrowWindDir) ||
1327 6 : i_parse("@TOMORROWSKYTEMP", ErlFunc::TomorrowSkyTemp) || i_parse("@TOMORROWHORIZIRSKY", ErlFunc::TomorrowHorizIRSky) ||
1328 4 : i_parse("@TOMORROWBEAMSOLARRAD", ErlFunc::TomorrowBeamSolarRad) ||
1329 240 : i_parse("@TOMORROWDIFSOLARRAD", ErlFunc::TomorrowDifSolarRad) || i_parse("@TOMORROWALBEDO", ErlFunc::TomorrowAlbedo) ||
1330 1 : 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 148 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1339 148 : MultFound = false;
1340 148 : DivFound = false;
1341 :
1342 148 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "OPERATOR \"{}\"\n", StringToken);
1343 :
1344 148 : if (StringToken == "+") {
1345 14 : if (!OperatorProcessing) {
1346 14 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Add;
1347 14 : OperatorProcessing = true;
1348 : } else {
1349 0 : PlusFound = true;
1350 0 : OperatorProcessing = false;
1351 : }
1352 134 : } else if (StringToken == "-") {
1353 51 : if (!OperatorProcessing) {
1354 51 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Subtract;
1355 51 : OperatorProcessing = true;
1356 : } else {
1357 0 : MinusFound = true;
1358 0 : OperatorProcessing = false;
1359 : }
1360 83 : } else if (StringToken == "*") {
1361 38 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Multiply;
1362 38 : MultFound = true;
1363 38 : OperatorProcessing = true;
1364 45 : } else if (StringToken == "/") {
1365 18 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::Divide;
1366 18 : DivFound = true;
1367 18 : OperatorProcessing = true;
1368 27 : } else if (StringToken == "<") {
1369 5 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::LessThan;
1370 5 : OperatorProcessing = true;
1371 22 : } else if (StringToken == ">") {
1372 9 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::GreaterThan;
1373 9 : OperatorProcessing = true;
1374 13 : } else if (StringToken == "^") {
1375 0 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Operator = ErlFunc::RaiseToPower;
1376 0 : OperatorProcessing = true;
1377 13 : } else if (StringToken == "0" && (NextChar == '-')) {
1378 : // process string insert = "0"
1379 13 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Number;
1380 13 : 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 300 : ++Pos;
1389 :
1390 438 : } else if (is_any_of(NextChar, "()")) {
1391 : // Parse a parenthesis token
1392 138 : ++Pos;
1393 138 : StringToken = NextChar;
1394 138 : if (state.dataSysVars->DeveloperFlag) print(state.files.debug, "PAREN \"{}\"\n", StringToken);
1395 138 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Type = Token::Parenthesis;
1396 138 : state.dataRuntimeLangProcessor->PEToken(NumTokens).String = StringToken;
1397 138 : if (NextChar == '(') {
1398 69 : state.dataRuntimeLangProcessor->PEToken(NumTokens).Parenthesis = Token::ParenthesisLeft;
1399 69 : OperatorProcessing = true;
1400 : }
1401 138 : 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 365 : 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 365 : ExpressionNum = ProcessTokens(state, state.dataRuntimeLangProcessor->PEToken, NumTokens, StackNum, String);
1419 365 : }
1420 :
1421 434 : 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 434 : Array1D<TokenType> Token(TokenIN);
1454 434 : Array1D<TokenType> SubTokenList;
1455 :
1456 434 : ExpressionNum = 0;
1457 434 : NumTokens = NumTokensIN;
1458 :
1459 : // Process parentheses
1460 434 : Pos = 0;
1461 1337 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1462 957 : if (Token(TokenNum).Type == Token::Parenthesis) {
1463 54 : Pos = TokenNum;
1464 54 : break;
1465 : }
1466 : }
1467 :
1468 434 : ParenthWhileCounter = 0;
1469 :
1470 503 : while ((Pos > 0) && (ParenthWhileCounter < 50)) {
1471 69 : ++ParenthWhileCounter;
1472 69 : Depth = 0;
1473 487 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1474 487 : if (Token(TokenNum).Type == Token::Parenthesis) {
1475 174 : if (Token(TokenNum).Parenthesis == Token::ParenthesisLeft) {
1476 87 : if (Depth == 0) Pos = TokenNum; // Record position of first left parenthesis
1477 87 : ++Depth;
1478 : }
1479 174 : if (Token(TokenNum).Parenthesis == Token::ParenthesisRight) {
1480 87 : --Depth;
1481 87 : if (Depth == 0) {
1482 69 : LastPos = TokenNum;
1483 69 : NumSubTokens = LastPos - Pos - 1;
1484 69 : SubTokenList.allocate(NumSubTokens);
1485 69 : SubTokenList({1, NumSubTokens}) = Token({Pos + 1, LastPos - 1}); // Need to check that these don't exceed bounds
1486 69 : ExpressionNum = ProcessTokens(state, SubTokenList, NumSubTokens, StackNum, ParsingString);
1487 69 : SubTokenList.deallocate();
1488 :
1489 : // Replace the parenthetical tokens with one expression token
1490 69 : NewNumTokens = NumTokens - NumSubTokens - 1;
1491 69 : if (NewNumTokens > 0) {
1492 69 : if (LastPos + 1 <= NumTokens) {
1493 84 : Token({Pos + 1, NewNumTokens}) = Token({LastPos + 1, _});
1494 : }
1495 69 : Token.redimension(NewNumTokens);
1496 69 : Token(Pos).Type = Token::Expression;
1497 69 : Token(Pos).Expression = ExpressionNum;
1498 69 : Token(Pos).String = "Expr";
1499 69 : NumTokens = NewNumTokens;
1500 : }
1501 :
1502 : // Reset loop for next parenthetical set
1503 69 : 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 69 : Pos = 0;
1511 233 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1512 179 : if (Token(TokenNum).Type == Token::Parenthesis) {
1513 15 : Pos = TokenNum;
1514 15 : break;
1515 : }
1516 : }
1517 : }
1518 :
1519 434 : 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 42098 : for (OperatorNum = 1; OperatorNum <= NumPossibleOperators; ++OperatorNum) {
1528 :
1529 : // Find the next occurrence of the operator
1530 41664 : Pos = 0; // position in sequence of tokens
1531 108335 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1532 66947 : if ((Token(TokenNum).Type == Token::Operator) && (Token(TokenNum).Operator == static_cast<ErlFunc>(OperatorNum))) {
1533 276 : Pos = TokenNum;
1534 276 : break;
1535 : }
1536 : }
1537 :
1538 41831 : while (Pos > 0) {
1539 287 : if (Pos == 1) {
1540 : // if first token is for a built-in function starting with "@" then okay, otherwise the operator needs a LHS
1541 120 : if (static_cast<int>(Token(TokenNum).Operator) > static_cast<int>(ErlFunc::LogicalOR)) { // we have a function expression to set up
1542 120 : ExpressionNum = NewExpression(state);
1543 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = static_cast<ErlFunc>(OperatorNum);
1544 120 : NumOperands = ErlFuncNumOperands[OperatorNum];
1545 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = NumOperands;
1546 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(NumOperands);
1547 :
1548 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(Pos + 1).Type));
1549 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(Pos + 1).Number;
1550 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Expression = Token(Pos + 1).Expression;
1551 120 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(Pos + 1).Variable;
1552 120 : if (Token(Pos + 1).Variable > 0) {
1553 71 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).TrendVariable =
1554 71 : state.dataRuntimeLang->ErlVariable(Token(Pos + 1).Variable).Value.TrendVariable;
1555 71 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).TrendVarPointer =
1556 71 : state.dataRuntimeLang->ErlVariable(Token(Pos + 1).Variable).Value.TrendVarPointer;
1557 : }
1558 120 : if ((NumOperands >= 2) && (NumTokens >= 3)) {
1559 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Type =
1560 94 : static_cast<Value>(static_cast<int>(Token(Pos + 2).Type));
1561 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Number = Token(Pos + 2).Number;
1562 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Expression = Token(Pos + 2).Expression;
1563 94 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Variable = Token(Pos + 2).Variable;
1564 : }
1565 :
1566 120 : if ((NumOperands >= 3) && (NumTokens >= 4)) {
1567 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Type =
1568 17 : static_cast<Value>(static_cast<int>(Token(Pos + 3).Type));
1569 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Number = Token(Pos + 3).Number;
1570 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Expression = Token(Pos + 3).Expression;
1571 17 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(3).Variable = Token(Pos + 3).Variable;
1572 17 : 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 120 : if ((NumOperands >= 4) && (NumTokens >= 5)) {
1578 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Type =
1579 6 : static_cast<Value>(static_cast<int>(Token(Pos + 4).Type));
1580 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Number = Token(Pos + 4).Number;
1581 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Expression = Token(Pos + 4).Expression;
1582 6 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(4).Variable = Token(Pos + 4).Variable;
1583 6 : 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 120 : 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 120 : 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 167 : } 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 167 : ExpressionNum = NewExpression(state);
1611 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = static_cast<ErlFunc>(OperatorNum);
1612 167 : NumOperands = ErlFuncNumOperands[OperatorNum];
1613 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = NumOperands;
1614 167 : 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 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(Pos - 1).Type));
1620 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(Pos - 1).Number;
1621 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Expression = Token(Pos - 1).Expression;
1622 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(Pos - 1).Variable;
1623 :
1624 167 : if (NumOperands >= 2) {
1625 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Type = static_cast<Value>(static_cast<int>(Token(Pos + 1).Type));
1626 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Number = Token(Pos + 1).Number;
1627 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Expression = Token(Pos + 1).Expression;
1628 167 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(2).Variable = Token(Pos + 1).Variable;
1629 : }
1630 :
1631 : // Replace the three tokens with one expression token
1632 167 : if ((NumOperands == 2) && (NumTokens - 2 > 0)) {
1633 167 : if (Pos + 2 <= NumTokens) {
1634 48 : Token({Pos, NumTokens - 2}) = Token({Pos + 2, _});
1635 : }
1636 167 : Token(Pos - 1).Type = Token::Expression;
1637 167 : Token(Pos - 1).Expression = ExpressionNum;
1638 167 : Token(Pos - 1).String = "Expr";
1639 167 : NumTokens -= 2;
1640 167 : Token.redimension(NumTokens);
1641 : }
1642 : }
1643 :
1644 : // Find the next occurrence of the operator (this repeats code, but don't have better idea)
1645 167 : Pos = 0;
1646 392 : for (TokenNum = 1; TokenNum <= NumTokens; ++TokenNum) {
1647 236 : if ((Token(TokenNum).Type == Token::Operator) && (Token(TokenNum).Operator == static_cast<ErlFunc>(OperatorNum))) {
1648 11 : Pos = TokenNum;
1649 11 : break;
1650 : }
1651 : }
1652 : }
1653 : }
1654 :
1655 : // Should be down to just one token now
1656 434 : if (Token(1).Type == Token::Number) {
1657 91 : ExpressionNum = NewExpression(state);
1658 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = ErlFunc::Literal;
1659 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = 1;
1660 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(1);
1661 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(1).Type));
1662 91 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Number = Token(1).Number;
1663 343 : } else if (Token(1).Type == Token::Variable) {
1664 69 : ExpressionNum = NewExpression(state);
1665 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operator = ErlFunc::Literal;
1666 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).NumOperands = 1;
1667 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand.allocate(1);
1668 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Type = static_cast<Value>(static_cast<int>(Token(1).Type));
1669 69 : state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(1).Variable = Token(1).Variable;
1670 : }
1671 :
1672 434 : Token.deallocate();
1673 :
1674 434 : return ExpressionNum;
1675 478 : }
1676 :
1677 447 : 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 447 : if (state.dataRuntimeLang->NumExpressions == 0) {
1701 25 : state.dataRuntimeLang->ErlExpression.allocate(1);
1702 25 : state.dataRuntimeLang->NumExpressions = 1;
1703 : } else {
1704 422 : state.dataRuntimeLang->ErlExpression.redimension(++state.dataRuntimeLang->NumExpressions);
1705 : }
1706 :
1707 447 : return state.dataRuntimeLang->NumExpressions;
1708 : }
1709 :
1710 1054238 : 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 1054238 : 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 1054238 : 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 1054238 : Array1D<ErlValueType> Operand;
1754 :
1755 1054238 : constexpr std::string_view EMSBuiltInFunction = "EMS Built-In Function";
1756 :
1757 1054238 : ReturnValue.Type = Value::Number;
1758 1054238 : ReturnValue.Number = 0.0;
1759 :
1760 1054238 : if (ExpressionNum > 0) {
1761 1054238 : auto const &thisErlExpression = state.dataRuntimeLang->ErlExpression(ExpressionNum);
1762 : // is there a way to keep these and not allocate and deallocate all the time?
1763 1054238 : Operand.allocate(thisErlExpression.NumOperands);
1764 : // Reduce operands down to literals
1765 2972166 : for (OperandNum = 1; OperandNum <= thisErlExpression.NumOperands; ++OperandNum) {
1766 1917928 : auto &thisOperand = Operand(OperandNum);
1767 1917928 : thisOperand = thisErlExpression.Operand(OperandNum);
1768 1917928 : if (thisOperand.Type == Value::Expression) {
1769 337865 : 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 337865 : if (seriousErrorFound) {
1772 0 : ReturnValue.Type = Value::Error;
1773 0 : ReturnValue.Error = thisOperand.Error;
1774 : }
1775 :
1776 1580063 : } else if (thisOperand.Type == Value::Variable) {
1777 1271725 : auto const &thisErlVar = state.dataRuntimeLang->ErlVariable(thisOperand.Variable);
1778 1271725 : if (thisErlVar.Value.initialized) { // check that value has been initialized
1779 1271724 : thisOperand = thisErlVar.Value;
1780 : } else { // value has never been set
1781 1 : ReturnValue.Type = Value::Error;
1782 1 : ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!";
1783 1 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1784 :
1785 : // check if this is an arg in CurveValue,
1786 1 : if (thisErlExpression.Operator !=
1787 : ErlFunc::CurveValue) { // padding the argument list for CurveValue is too common to fatal on. only reported to EDD
1788 1 : seriousErrorFound = true;
1789 : }
1790 : }
1791 : }
1792 : }
1793 : }
1794 :
1795 1054238 : if (ReturnValue.Type != Value::Error) {
1796 :
1797 : // Perform the operation
1798 :
1799 1054237 : switch (thisErlExpression.Operator) {
1800 :
1801 247128 : case ErlFunc::Literal:
1802 247128 : ReturnValue = Operand(1);
1803 247128 : ReturnValue.initialized = true;
1804 247128 : 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 90421 : case ErlFunc::Divide:
1811 90421 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1812 90421 : if (Operand(2).Number == 0.0) {
1813 0 : ReturnValue.Type = Value::Error;
1814 0 : ReturnValue.Error = "EvaluateExpression: Divide By Zero in EMS Program!";
1815 0 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1816 0 : seriousErrorFound = true;
1817 : }
1818 : } else {
1819 90421 : ReturnValue = SetErlValueNumber(Operand(1).Number / Operand(2).Number);
1820 : }
1821 : }
1822 90421 : break;
1823 :
1824 186886 : case ErlFunc::Multiply:
1825 186886 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1826 186886 : ReturnValue = SetErlValueNumber(Operand(1).Number * Operand(2).Number);
1827 : }
1828 186886 : break;
1829 :
1830 136272 : case ErlFunc::Subtract:
1831 136272 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1832 136272 : ReturnValue = SetErlValueNumber(Operand(1).Number - Operand(2).Number);
1833 : }
1834 136272 : break;
1835 :
1836 78880 : case ErlFunc::Add:
1837 78880 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1838 78880 : ReturnValue = SetErlValueNumber(Operand(1).Number + Operand(2).Number);
1839 : }
1840 78880 : break;
1841 :
1842 33061 : case ErlFunc::Equal:
1843 33061 : if (Operand(1).Type == Operand(2).Type) {
1844 33061 : if (Operand(1).Type == Value::Null) {
1845 0 : ReturnValue = state.dataRuntimeLang->True;
1846 33061 : } else if ((Operand(1).Type == Value::Number) && (Operand(1).Number == Operand(2).Number)) {
1847 8254 : ReturnValue = state.dataRuntimeLang->True;
1848 : } else {
1849 24807 : ReturnValue = state.dataRuntimeLang->False;
1850 : }
1851 : } else {
1852 0 : ReturnValue = state.dataRuntimeLang->False;
1853 : }
1854 33061 : break;
1855 :
1856 4076 : case ErlFunc::NotEqual:
1857 4076 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1858 4076 : if (Operand(1).Number != Operand(2).Number) {
1859 4070 : ReturnValue = state.dataRuntimeLang->True;
1860 : } else {
1861 6 : ReturnValue = state.dataRuntimeLang->False;
1862 : }
1863 : }
1864 4076 : break;
1865 :
1866 1380 : case ErlFunc::LessOrEqual:
1867 1380 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1868 1380 : if (Operand(1).Number <= Operand(2).Number) {
1869 1362 : ReturnValue = state.dataRuntimeLang->True;
1870 : } else {
1871 18 : ReturnValue = state.dataRuntimeLang->False;
1872 : }
1873 : }
1874 1380 : break;
1875 :
1876 1362 : case ErlFunc::GreaterOrEqual:
1877 1362 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1878 1362 : if (Operand(1).Number >= Operand(2).Number) {
1879 1362 : ReturnValue = state.dataRuntimeLang->True;
1880 : } else {
1881 0 : ReturnValue = state.dataRuntimeLang->False;
1882 : }
1883 : }
1884 1362 : break;
1885 :
1886 49666 : case ErlFunc::LessThan:
1887 49666 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1888 49666 : if (Operand(1).Number < Operand(2).Number) {
1889 47720 : ReturnValue = state.dataRuntimeLang->True;
1890 : } else {
1891 1946 : ReturnValue = state.dataRuntimeLang->False;
1892 : }
1893 : }
1894 49666 : break;
1895 :
1896 50696 : case ErlFunc::GreaterThan:
1897 50696 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1898 50696 : if (Operand(1).Number > Operand(2).Number) {
1899 42188 : ReturnValue = state.dataRuntimeLang->True;
1900 : } else {
1901 8508 : ReturnValue = state.dataRuntimeLang->False;
1902 : }
1903 : }
1904 50696 : break;
1905 :
1906 0 : case ErlFunc::RaiseToPower:
1907 0 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1908 0 : TestValue = std::pow(Operand(1).Number, Operand(2).Number);
1909 0 : 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 0 : ReturnValue = SetErlValueNumber(TestValue);
1921 : }
1922 : }
1923 0 : break;
1924 :
1925 34712 : case ErlFunc::LogicalAND:
1926 34712 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1927 34712 : if ((Operand(1).Number == state.dataRuntimeLang->True.Number) && (Operand(2).Number == state.dataRuntimeLang->True.Number)) {
1928 30624 : ReturnValue = state.dataRuntimeLang->True;
1929 : } else {
1930 4088 : ReturnValue = state.dataRuntimeLang->False;
1931 : }
1932 : }
1933 34712 : break;
1934 :
1935 0 : case ErlFunc::LogicalOR:
1936 0 : if ((Operand(1).Type == Value::Number) && (Operand(2).Type == Value::Number)) {
1937 0 : if ((Operand(1).Number == state.dataRuntimeLang->True.Number) || (Operand(2).Number == state.dataRuntimeLang->True.Number)) {
1938 0 : ReturnValue = state.dataRuntimeLang->True;
1939 : } else {
1940 0 : ReturnValue = state.dataRuntimeLang->False;
1941 : }
1942 : }
1943 0 : break;
1944 :
1945 2 : case ErlFunc::Round:
1946 2 : ReturnValue = SetErlValueNumber(nint(Operand(1).Number));
1947 2 : break;
1948 :
1949 6 : case ErlFunc::Mod:
1950 6 : ReturnValue = SetErlValueNumber(mod(Operand(1).Number, Operand(2).Number));
1951 6 : break;
1952 :
1953 2 : case ErlFunc::Sin:
1954 2 : ReturnValue = SetErlValueNumber(std::sin(Operand(1).Number));
1955 2 : break;
1956 :
1957 2 : case ErlFunc::Cos:
1958 2 : ReturnValue = SetErlValueNumber(std::cos(Operand(1).Number));
1959 2 : break;
1960 :
1961 2 : case ErlFunc::ArcSin:
1962 2 : ReturnValue = SetErlValueNumber(std::asin(Operand(1).Number));
1963 2 : break;
1964 :
1965 2 : case ErlFunc::ArcCos:
1966 2 : ReturnValue = SetErlValueNumber(std::acos(Operand(1).Number));
1967 2 : break;
1968 :
1969 2 : case ErlFunc::DegToRad:
1970 2 : ReturnValue = SetErlValueNumber(Operand(1).Number * Constant::DegToRad);
1971 2 : break;
1972 :
1973 2 : case ErlFunc::RadToDeg:
1974 2 : ReturnValue = SetErlValueNumber(Operand(1).Number / Constant::DegToRad);
1975 2 : break;
1976 :
1977 4079 : case ErlFunc::Exp:
1978 4079 : if ((Operand(1).Number < 700.0) && (Operand(1).Number > -20.0)) {
1979 4075 : ReturnValue = SetErlValueNumber(std::exp(Operand(1).Number));
1980 4 : } else if (Operand(1).Number <= -20.0) {
1981 2 : ReturnValue = SetErlValueNumber(0.0);
1982 : } else {
1983 : // throw Error
1984 : ReturnValue.Error =
1985 2 : format("EvaluateExpression: Attempted to calculate exponential value of too large a number: {:.4T}", Operand(1).Number);
1986 2 : ReturnValue.Type = Value::Error;
1987 2 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
1988 2 : seriousErrorFound = true;
1989 : }
1990 : }
1991 4079 : break;
1992 :
1993 4072 : case ErlFunc::Ln:
1994 4072 : if (Operand(1).Number > 0.0) {
1995 4072 : ReturnValue = SetErlValueNumber(std::log(Operand(1).Number));
1996 : } else {
1997 : // throw error,
1998 0 : ReturnValue.Type = Value::Error;
1999 0 : ReturnValue.Error = format("EvaluateExpression: Natural Log of zero or less! ln of value = {:.4T}", Operand(1).Number);
2000 0 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) {
2001 0 : seriousErrorFound = true;
2002 : }
2003 : }
2004 4072 : break;
2005 :
2006 2 : case ErlFunc::Max:
2007 2 : ReturnValue = SetErlValueNumber(max(Operand(1).Number, Operand(2).Number));
2008 2 : break;
2009 :
2010 20738 : case ErlFunc::Min:
2011 20738 : ReturnValue = SetErlValueNumber(min(Operand(1).Number, Operand(2).Number));
2012 20738 : break;
2013 :
2014 24810 : case ErlFunc::ABS:
2015 24810 : ReturnValue = SetErlValueNumber(std::abs(Operand(1).Number));
2016 24810 : break;
2017 :
2018 2 : case ErlFunc::RandU:
2019 2 : RANDOM_NUMBER(tmpRANDU1);
2020 2 : tmpRANDU1 = Operand(1).Number + (Operand(2).Number - Operand(1).Number) * tmpRANDU1;
2021 2 : ReturnValue = SetErlValueNumber(tmpRANDU1);
2022 2 : break;
2023 :
2024 2 : case ErlFunc::RandG:
2025 : while (true) { // Box-Muller algorithm
2026 2 : RANDOM_NUMBER(tmpRANDU1);
2027 2 : RANDOM_NUMBER(tmpRANDU2);
2028 2 : tmpRANDU1 = 2.0 * tmpRANDU1 - 1.0;
2029 2 : tmpRANDU2 = 2.0 * tmpRANDU2 - 1.0;
2030 2 : UnitCircleTest = square(tmpRANDU1) + square(tmpRANDU2);
2031 2 : if (UnitCircleTest > 0.0 && UnitCircleTest < 1.0) break;
2032 : }
2033 2 : tmpRANDG = std::sqrt(-2.0 * std::log(UnitCircleTest) / UnitCircleTest);
2034 2 : tmpRANDG *= tmpRANDU1; // standard normal ran
2035 : // x = ran * sigma + mean
2036 2 : tmpRANDG = tmpRANDG * Operand(2).Number + Operand(1).Number;
2037 2 : tmpRANDG = max(tmpRANDG, Operand(3).Number); // min limit
2038 2 : tmpRANDG = min(tmpRANDG, Operand(4).Number); // max limit
2039 2 : ReturnValue = SetErlValueNumber(tmpRANDG);
2040 2 : break;
2041 :
2042 2 : case ErlFunc::RandSeed:
2043 : // convert arg to an integer array for the seed.
2044 2 : RANDOM_SEED(SeedN); // obtains processor's use size as output
2045 2 : SeedIntARR.allocate(SeedN);
2046 6 : for (loop = 1; loop <= SeedN; ++loop) {
2047 4 : if (loop == 1) {
2048 2 : SeedIntARR(loop) = std::floor(Operand(1).Number);
2049 : } else {
2050 2 : SeedIntARR(loop) = std::floor(Operand(1).Number) * loop;
2051 : }
2052 : }
2053 2 : RANDOM_SEED(_, SeedIntARR);
2054 2 : ReturnValue = SetErlValueNumber(double(SeedIntARR(1))); // just return first number pass as seed
2055 2 : SeedIntARR.deallocate();
2056 2 : break;
2057 :
2058 4072 : case ErlFunc::RhoAirFnPbTdbW:
2059 12216 : ReturnValue = SetErlValueNumber(PsyRhoAirFnPbTdbW(state,
2060 4072 : Operand(1).Number,
2061 4072 : Operand(2).Number,
2062 4072 : Operand(3).Number,
2063 4072 : 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 4072 : break;
2067 :
2068 2 : case ErlFunc::CpAirFnW:
2069 2 : ReturnValue = SetErlValueNumber(PsyCpAirFnW(Operand(1).Number)); // result => heat capacity of air
2070 : // {J/kg-C} | Humidity ratio (kg water vapor/kg dry air)
2071 2 : break;
2072 :
2073 2 : case ErlFunc::HfgAirFnWTdb:
2074 : // BG comment these two psych funct seems confusing (?) is this the enthalpy of water in the air?
2075 2 : 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 2 : break;
2080 :
2081 2 : case ErlFunc::HgAirFnWTdb:
2082 : // confusing ? seems like this is really classical Hfg, heat of vaporization
2083 2 : 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 2 : break;
2087 :
2088 2 : case ErlFunc::TdpFnTdbTwbPb:
2089 6 : ReturnValue = SetErlValueNumber(
2090 : PsyTdpFnTdbTwbPb(state,
2091 2 : Operand(1).Number,
2092 2 : Operand(2).Number,
2093 2 : Operand(3).Number,
2094 2 : EMSBuiltInFunction)); // result => dew-point temperature {C} | drybulb (C) | wetbulb (C) | pressure (Pa)
2095 2 : break;
2096 :
2097 2 : case ErlFunc::TdpFnWPb:
2098 6 : ReturnValue = SetErlValueNumber(PsyTdpFnWPb(
2099 : state,
2100 2 : Operand(1).Number,
2101 2 : Operand(2).Number,
2102 2 : EMSBuiltInFunction)); // result => dew-point temperature {C} | Humidity ratio (kg water vapor/kg dry air) | pressure (Pa)
2103 2 : break;
2104 :
2105 16282 : case ErlFunc::HFnTdbW:
2106 48846 : ReturnValue = SetErlValueNumber(
2107 16282 : PsyHFnTdbW(Operand(1).Number,
2108 32564 : Operand(2).Number)); // result => enthalpy (J/kg) | drybulb (C) | Humidity ratio (kg water vapor/kg dry air)
2109 16282 : break;
2110 :
2111 2 : case ErlFunc::HFnTdbRhPb:
2112 6 : ReturnValue = SetErlValueNumber(PsyHFnTdbRhPb(
2113 : state,
2114 2 : Operand(1).Number,
2115 2 : Operand(2).Number,
2116 2 : Operand(3).Number,
2117 2 : EMSBuiltInFunction)); // result => enthalpy (J/kg) | drybulb (C) | relative humidity value (0.0 - 1.0) | pressure (Pa)
2118 2 : break;
2119 :
2120 28878 : case ErlFunc::TdbFnHW:
2121 86634 : ReturnValue = SetErlValueNumber(PsyTdbFnHW(
2122 28878 : Operand(1).Number,
2123 57756 : Operand(2).Number)); // result => dry-bulb temperature {C} | enthalpy (J/kg) | Humidity ratio (kg water vapor/kg dry air)
2124 28878 : break;
2125 :
2126 2 : case ErlFunc::RhovFnTdbRh:
2127 6 : ReturnValue = SetErlValueNumber(PsyRhovFnTdbRh(
2128 : state,
2129 2 : Operand(1).Number,
2130 2 : Operand(2).Number,
2131 2 : EMSBuiltInFunction)); // result => Vapor density in air (kg/m3) | drybulb (C) | relative humidity value (0.0 - 1.0)
2132 2 : break;
2133 :
2134 2 : case ErlFunc::RhovFnTdbRhLBnd0C:
2135 6 : ReturnValue = SetErlValueNumber(PsyRhovFnTdbRhLBnd0C(
2136 2 : Operand(1).Number,
2137 4 : Operand(2).Number)); // result => Vapor density in air (kg/m3) | drybulb (C) | relative humidity value (0.0 - 1.0)
2138 2 : break;
2139 :
2140 2 : case ErlFunc::RhovFnTdbWPb:
2141 6 : ReturnValue = SetErlValueNumber(
2142 4 : 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 2 : break;
2146 :
2147 2 : case ErlFunc::RhFnTdbRhov:
2148 6 : ReturnValue = SetErlValueNumber(
2149 : PsyRhFnTdbRhov(state,
2150 2 : Operand(1).Number,
2151 2 : Operand(2).Number,
2152 2 : EMSBuiltInFunction)); // result => relative humidity value (0.0-1.0) | drybulb (C) | vapor density in air (kg/m3)
2153 2 : break;
2154 :
2155 2 : case ErlFunc::RhFnTdbRhovLBnd0C:
2156 6 : ReturnValue = SetErlValueNumber(
2157 : PsyRhFnTdbRhovLBnd0C(state,
2158 2 : Operand(1).Number,
2159 2 : Operand(2).Number,
2160 2 : EMSBuiltInFunction)); // relative humidity value (0.0-1.0) | drybulb (C) | vapor density in air (kg/m3)
2161 2 : break;
2162 :
2163 2 : case ErlFunc::RhFnTdbWPb:
2164 6 : ReturnValue = SetErlValueNumber(PsyRhFnTdbWPb(state,
2165 2 : Operand(1).Number,
2166 2 : Operand(2).Number,
2167 2 : Operand(3).Number,
2168 2 : EMSBuiltInFunction)); // result => relative humidity value (0.0-1.0) | drybulb
2169 : // (C) | Humidity ratio (kg water vapor/kg dry air) |
2170 : // pressure (Pa)
2171 2 : break;
2172 :
2173 4072 : case ErlFunc::TwbFnTdbWPb:
2174 12216 : ReturnValue = SetErlValueNumber(PsyTwbFnTdbWPb(state,
2175 4072 : Operand(1).Number,
2176 4072 : Operand(2).Number,
2177 4072 : Operand(3).Number,
2178 4072 : EMSBuiltInFunction)); // result=> Temperature Wet-Bulb {C} | drybulb (C) |
2179 : // Humidity ratio (kg water vapor/kg dry air) | pressure
2180 : // (Pa)
2181 4072 : break;
2182 :
2183 2 : case ErlFunc::VFnTdbWPb:
2184 6 : ReturnValue = SetErlValueNumber(PsyVFnTdbWPb(state,
2185 2 : Operand(1).Number,
2186 2 : Operand(2).Number,
2187 2 : Operand(3).Number,
2188 2 : EMSBuiltInFunction)); // result=> specific volume {m3/kg} | drybulb (C) |
2189 : // Humidity ratio (kg water vapor/kg dry air) | pressure
2190 : // (Pa)
2191 2 : break;
2192 :
2193 2 : case ErlFunc::WFnTdpPb:
2194 6 : ReturnValue = SetErlValueNumber(PsyWFnTdpPb(
2195 : state,
2196 2 : Operand(1).Number,
2197 2 : Operand(2).Number,
2198 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) | dew point temperature (C) | pressure (Pa)
2199 2 : break;
2200 :
2201 8142 : case ErlFunc::WFnTdbH:
2202 24426 : ReturnValue = SetErlValueNumber(
2203 : PsyWFnTdbH(state,
2204 8142 : Operand(1).Number,
2205 8142 : Operand(2).Number,
2206 8142 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) | drybulb (C) | enthalpy (J/kg)
2207 8142 : break;
2208 :
2209 2 : case ErlFunc::WFnTdbTwbPb:
2210 6 : ReturnValue = SetErlValueNumber(PsyWFnTdbTwbPb(state,
2211 2 : Operand(1).Number,
2212 2 : Operand(2).Number,
2213 2 : Operand(3).Number,
2214 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) |
2215 : // drybulb (C) | wet-bulb temperature {C} | pressure (Pa)
2216 2 : break;
2217 :
2218 2 : case ErlFunc::WFnTdbRhPb:
2219 6 : ReturnValue = SetErlValueNumber(PsyWFnTdbRhPb(state,
2220 2 : Operand(1).Number,
2221 2 : Operand(2).Number,
2222 2 : Operand(3).Number,
2223 2 : EMSBuiltInFunction)); // result=> humidity ratio (kg water vapor/kg dry air) |
2224 : // drybulb (C) | relative humidity value (0.0-1.0) |
2225 : // pressure (Pa)
2226 2 : break;
2227 :
2228 2 : case ErlFunc::PsatFnTemp:
2229 6 : ReturnValue = SetErlValueNumber(
2230 4 : PsyPsatFnTemp(state, Operand(1).Number, EMSBuiltInFunction)); // result=> saturation pressure {Pascals} | drybulb (C)
2231 2 : break;
2232 :
2233 4072 : case ErlFunc::TsatFnHPb:
2234 : ReturnValue =
2235 12216 : SetErlValueNumber(PsyTsatFnHPb(state,
2236 4072 : Operand(1).Number,
2237 4072 : Operand(2).Number,
2238 4072 : EMSBuiltInFunction)); // result=> saturation temperature {C} | enthalpy {J/kg} | pressure (Pa)
2239 4072 : 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 2 : case ErlFunc::CpCW:
2248 : ReturnValue =
2249 2 : SetErlValueNumber(CPCW(Operand(1).Number)); // result => specific heat of water (J/kg-K) = 4180.d0 | temperature (C) unused
2250 2 : break;
2251 :
2252 2 : case ErlFunc::CpHW:
2253 : ReturnValue =
2254 2 : SetErlValueNumber(CPHW(Operand(1).Number)); // result => specific heat of water (J/kg-K) = 4180.d0 | temperature (C) unused
2255 2 : break;
2256 :
2257 2 : case ErlFunc::RhoH2O:
2258 2 : ReturnValue = SetErlValueNumber(RhoH2O(Operand(1).Number)); // result => density of water (kg/m3) | temperature (C)
2259 2 : 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 2 : case ErlFunc::SevereWarnEp:
2269 2 : ShowSevereError(state, format("EMS user program issued severe warning with error code = {:.2T}", Operand(1).Number));
2270 4 : ShowContinueErrorTimeStamp(state, "");
2271 2 : ReturnValue = SetErlValueNumber(Operand(1).Number); // returns back the error code
2272 2 : break;
2273 :
2274 2 : case ErlFunc::WarnEp:
2275 2 : ShowWarningError(state, format("EMS user program issued warning with error code = {:.2T}", Operand(1).Number));
2276 4 : ShowContinueErrorTimeStamp(state, "");
2277 2 : ReturnValue = SetErlValueNumber(Operand(1).Number); // returns back the error code
2278 2 : break;
2279 :
2280 8 : case ErlFunc::TrendValue:
2281 : // find TrendVariable , first operand is ErlVariable
2282 8 : if (Operand(1).TrendVariable) {
2283 8 : thisTrend = Operand(1).TrendVarPointer;
2284 : // second operand is number for index
2285 8 : thisIndex = std::floor(Operand(2).Number);
2286 8 : if (thisIndex >= 1) {
2287 8 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2288 8 : 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 8 : break;
2302 :
2303 4 : case ErlFunc::TrendAverage:
2304 : // find TrendVariable , first operand is ErlVariable
2305 4 : if (Operand(1).TrendVariable) {
2306 4 : thisTrend = Operand(1).TrendVarPointer;
2307 4 : thisIndex = std::floor(Operand(2).Number);
2308 4 : if (thisIndex >= 1) {
2309 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2310 : // calculate average
2311 4 : thisAverage = sum(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})) / double(thisIndex);
2312 4 : 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 4 : break;
2326 :
2327 4 : case ErlFunc::TrendMax:
2328 4 : if (Operand(1).TrendVariable) {
2329 4 : thisTrend = Operand(1).TrendVarPointer;
2330 4 : thisIndex = std::floor(Operand(2).Number);
2331 4 : if (thisIndex >= 1) {
2332 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2333 4 : thisMax = 0.0;
2334 4 : if (thisIndex == 1) {
2335 0 : thisMax = state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1);
2336 : } else {
2337 16 : for (loop = 2; loop <= thisIndex; ++loop) {
2338 12 : if (loop == 2) {
2339 4 : thisMax = max(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1),
2340 4 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(2));
2341 : } else {
2342 8 : thisMax = max(thisMax, state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(loop));
2343 : }
2344 : }
2345 : }
2346 4 : 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 4 : break;
2360 :
2361 4 : case ErlFunc::TrendMin:
2362 4 : if (Operand(1).TrendVariable) {
2363 4 : thisTrend = Operand(1).TrendVarPointer;
2364 4 : thisIndex = std::floor(Operand(2).Number);
2365 4 : if (thisIndex >= 1) {
2366 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2367 4 : thisMin = 0.0;
2368 4 : if (thisIndex == 1) {
2369 0 : thisMin = state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1);
2370 : } else {
2371 16 : for (loop = 2; loop <= thisIndex; ++loop) {
2372 12 : if (loop == 2) {
2373 4 : thisMin = min(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(1),
2374 4 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(2));
2375 : } else {
2376 8 : thisMin = min(thisMin, state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR(loop));
2377 : }
2378 : }
2379 : }
2380 4 : 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 4 : break;
2396 :
2397 4 : case ErlFunc::TrendDirection:
2398 4 : if (Operand(1).TrendVariable) {
2399 : // do a linear least squares fit and get slope of line
2400 4 : thisTrend = Operand(1).TrendVarPointer;
2401 4 : thisIndex = std::floor(Operand(2).Number);
2402 4 : if (thisIndex >= 1) {
2403 :
2404 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2405 : // closed form solution for slope of linear least squares fit
2406 4 : thisSlope = (sum(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex})) *
2407 8 : sum(state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})) -
2408 8 : thisIndex * sum((state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}) *
2409 8 : state.dataRuntimeLang->TrendVariable(thisTrend).TrendValARR({1, thisIndex})))) /
2410 8 : (pow_2(sum(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}))) -
2411 4 : thisIndex * sum(pow(state.dataRuntimeLang->TrendVariable(thisTrend).TimeARR({1, thisIndex}), 2)));
2412 4 : 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 4 : break;
2427 :
2428 4 : case ErlFunc::TrendSum:
2429 4 : if (Operand(1).TrendVariable) {
2430 :
2431 4 : thisTrend = Operand(1).TrendVarPointer;
2432 4 : thisIndex = std::floor(Operand(2).Number);
2433 4 : if (thisIndex >= 1) {
2434 4 : if (thisIndex <= state.dataRuntimeLang->TrendVariable(thisTrend).LogDepth) {
2435 : ReturnValue =
2436 4 : 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 4 : break;
2450 :
2451 20352 : case ErlFunc::CurveValue:
2452 20354 : if (Operand(3).Type == Value::Null && Operand(4).Type == Value::Null && Operand(5).Type == Value::Null &&
2453 2 : Operand(6).Type == Value::Null) {
2454 : ReturnValue =
2455 2 : 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 20350 : } 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->curves(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 20350 : } else if (Operand(5).Type == Value::Null && Operand(6).Type == Value::Null) {
2471 20350 : Real64 curveVal = 0.0;
2472 20350 : switch (state.dataCurveManager->curves(std::floor(Operand(1).Number))->numDims) {
2473 12210 : case 1:
2474 12210 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number);
2475 12210 : break;
2476 8140 : case 2:
2477 8140 : curveVal = CurveValue(state, std::floor(Operand(1).Number), Operand(2).Number, Operand(3).Number);
2478 8140 : 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 20350 : ReturnValue = SetErlValueNumber(curveVal);
2484 0 : } else if (Operand(6).Type == Value::Null) {
2485 0 : Real64 curveVal = 0.0;
2486 0 : switch (state.dataCurveManager->curves(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->curves(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 20352 : break;
2531 :
2532 14 : 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 14 : int iHour = (Operand(1).Number + 1); // Operand 1 is hour from 0:23
2547 14 : int iTimeStep = Operand(2).Number;
2548 14 : if ((iHour > 0) && (iHour <= 24) && (iTimeStep > 0) && (iTimeStep <= state.dataGlobal->TimeStepsInHour)) {
2549 14 : auto const &today = state.dataWeather->wvarsHrTsToday(iTimeStep, iHour);
2550 14 : ReturnValue.initialized = true;
2551 14 : ReturnValue.Type = Value::Number;
2552 14 : switch (thisErlExpression.Operator) {
2553 1 : case ErlFunc::TodayIsRain: {
2554 1 : ReturnValue.Number = today.IsRain ? 1.0 : 0.0;
2555 1 : } break;
2556 1 : case ErlFunc::TodayIsSnow: {
2557 1 : ReturnValue.Number = today.IsSnow ? 1.0 : 0.0;
2558 1 : } break;
2559 1 : case ErlFunc::TodayOutDryBulbTemp: {
2560 1 : ReturnValue.Number = today.OutDryBulbTemp;
2561 1 : } break;
2562 1 : case ErlFunc::TodayOutDewPointTemp: {
2563 1 : ReturnValue.Number = today.OutDewPointTemp;
2564 1 : } break;
2565 1 : case ErlFunc::TodayOutBaroPress: {
2566 1 : ReturnValue.Number = today.OutBaroPress;
2567 1 : } break;
2568 1 : case ErlFunc::TodayOutRelHum: {
2569 1 : ReturnValue.Number = today.OutRelHum;
2570 1 : } break;
2571 1 : case ErlFunc::TodayWindSpeed: {
2572 1 : ReturnValue.Number = today.WindSpeed;
2573 1 : } break;
2574 1 : case ErlFunc::TodayWindDir: {
2575 1 : ReturnValue.Number = today.WindDir;
2576 1 : } break;
2577 1 : case ErlFunc::TodaySkyTemp: {
2578 1 : ReturnValue.Number = today.SkyTemp;
2579 1 : } break;
2580 1 : case ErlFunc::TodayHorizIRSky: {
2581 1 : ReturnValue.Number = today.HorizIRSky;
2582 1 : } break;
2583 1 : case ErlFunc::TodayBeamSolarRad: {
2584 1 : ReturnValue.Number = today.BeamSolarRad;
2585 1 : } break;
2586 1 : case ErlFunc::TodayDifSolarRad: {
2587 1 : ReturnValue.Number = today.DifSolarRad;
2588 1 : } break;
2589 1 : case ErlFunc::TodayAlbedo: {
2590 1 : ReturnValue.Number = today.Albedo;
2591 1 : } break;
2592 1 : case ErlFunc::TodayLiquidPrecip: {
2593 1 : ReturnValue.Number = today.LiquidPrecip;
2594 1 : } 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 14 : } break;
2607 :
2608 14 : 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 14 : int iHour = (Operand(1).Number + 1); // Operand 1 is hour from 0:23
2623 14 : int iTimeStep = Operand(2).Number;
2624 14 : if ((iHour > 0) && (iHour <= Constant::iHoursInDay) && (iTimeStep > 0) && (iTimeStep <= state.dataGlobal->TimeStepsInHour)) {
2625 14 : auto const &tomorrow = state.dataWeather->wvarsHrTsTomorrow(iTimeStep, iHour);
2626 14 : ReturnValue.initialized = true;
2627 14 : ReturnValue.Type = Value::Number;
2628 14 : switch (thisErlExpression.Operator) {
2629 1 : case ErlFunc::TomorrowIsRain: {
2630 1 : ReturnValue.Number = tomorrow.IsRain ? 1.0 : 0.0;
2631 1 : } break;
2632 1 : case ErlFunc::TomorrowIsSnow: {
2633 1 : ReturnValue.Number = tomorrow.IsSnow ? 1.0 : 0.0;
2634 1 : } break;
2635 1 : case ErlFunc::TomorrowOutDryBulbTemp: {
2636 1 : ReturnValue.Number = tomorrow.OutDryBulbTemp;
2637 1 : } break;
2638 1 : case ErlFunc::TomorrowOutDewPointTemp: {
2639 1 : ReturnValue.Number = tomorrow.OutDewPointTemp;
2640 1 : } break;
2641 1 : case ErlFunc::TomorrowOutBaroPress: {
2642 1 : ReturnValue.Number = tomorrow.OutBaroPress;
2643 1 : } break;
2644 1 : case ErlFunc::TomorrowOutRelHum: {
2645 1 : ReturnValue.Number = tomorrow.OutRelHum;
2646 1 : } break;
2647 1 : case ErlFunc::TomorrowWindSpeed: {
2648 1 : ReturnValue.Number = tomorrow.WindSpeed;
2649 1 : } break;
2650 1 : case ErlFunc::TomorrowWindDir: {
2651 1 : ReturnValue.Number = tomorrow.WindDir;
2652 1 : } break;
2653 1 : case ErlFunc::TomorrowSkyTemp: {
2654 1 : ReturnValue.Number = tomorrow.SkyTemp;
2655 1 : } break;
2656 1 : case ErlFunc::TomorrowHorizIRSky: {
2657 1 : ReturnValue.Number = tomorrow.HorizIRSky;
2658 1 : } break;
2659 1 : case ErlFunc::TomorrowBeamSolarRad: {
2660 1 : ReturnValue.Number = tomorrow.BeamSolarRad;
2661 1 : } break;
2662 1 : case ErlFunc::TomorrowDifSolarRad: {
2663 1 : ReturnValue.Number = tomorrow.DifSolarRad;
2664 1 : } break;
2665 1 : case ErlFunc::TomorrowAlbedo: {
2666 1 : ReturnValue.Number = tomorrow.Albedo;
2667 1 : } break;
2668 1 : case ErlFunc::TomorrowLiquidPrecip: {
2669 1 : ReturnValue.Number = tomorrow.LiquidPrecip;
2670 1 : } 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 14 : } 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 1054238 : Operand.deallocate();
2694 : }
2695 :
2696 2108476 : return ReturnValue;
2697 1054238 : }
2698 :
2699 47 : 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 47 : 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 47 : bool ErrorsFound(false);
2732 47 : int VariableNum(0); // temporary
2733 : int RuntimeReportVarNum;
2734 : bool Found;
2735 : OutputProcessor::TimeStepType sovTimeStepType; // temporary
2736 : OutputProcessor::StoreType sovStoreType; // temporary
2737 47 : std::string EndUseSubCatString;
2738 :
2739 : int TrendNum;
2740 : int NumTrendSteps;
2741 : int loop;
2742 : int ErlVarLoop;
2743 : int CurveIndexNum;
2744 47 : int MaxNumAlphas(0); // argument for call to GetObjectDefMaxArgs
2745 47 : int MaxNumNumbers(0); // argument for call to GetObjectDefMaxArgs
2746 47 : int TotalArgs(0); // argument for call to GetObjectDefMaxArgs
2747 47 : Array1D_string cAlphaFieldNames;
2748 47 : Array1D_string cNumericFieldNames;
2749 47 : Array1D_bool lNumericFieldBlanks;
2750 47 : Array1D_bool lAlphaFieldBlanks;
2751 47 : Array1D_string cAlphaArgs;
2752 47 : Array1D<Real64> rNumericArgs;
2753 47 : std::string cCurrentModuleObject;
2754 : int ConstructNum;
2755 : bool errFlag;
2756 : std::string::size_type lbracket;
2757 47 : std::string UnitsA;
2758 47 : std::string UnitsB;
2759 47 : Constant::Units curUnit(Constant::Units::None);
2760 : std::string::size_type ptr;
2761 :
2762 47 : if (state.dataRuntimeLangProcessor->GetInput) { // GetInput check is redundant with the InitializeRuntimeLanguage routine
2763 47 : state.dataRuntimeLangProcessor->GetInput = false;
2764 :
2765 47 : cCurrentModuleObject = "EnergyManagementSystem:Sensor";
2766 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2767 47 : MaxNumNumbers = NumNums;
2768 47 : MaxNumAlphas = NumAlphas;
2769 47 : cCurrentModuleObject = "EnergyManagementSystem:Actuator";
2770 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2771 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2772 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2773 47 : cCurrentModuleObject = "EnergyManagementSystem:ProgramCallingManager";
2774 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2775 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2776 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2777 47 : cCurrentModuleObject = "EnergyManagementSystem:Program";
2778 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2779 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2780 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2781 47 : cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
2782 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2783 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2784 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2785 47 : cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
2786 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2787 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2788 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2789 47 : cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
2790 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2791 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2792 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2793 47 : cCurrentModuleObject = "ExternalInterface:Variable";
2794 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2795 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2796 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2797 47 : cCurrentModuleObject = "ExternalInterface:Actuator";
2798 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2799 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2800 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2801 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
2802 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2803 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2804 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2805 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
2806 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2807 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2808 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2809 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Variable";
2810 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2811 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2812 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2813 47 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitExport:To:Actuator";
2814 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2815 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2816 47 : 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 47 : cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
2822 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2823 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2824 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2825 47 : cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
2826 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2827 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2828 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2829 47 : cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
2830 47 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
2831 47 : MaxNumNumbers = max(MaxNumNumbers, NumNums);
2832 47 : MaxNumAlphas = max(MaxNumAlphas, NumAlphas);
2833 :
2834 47 : cAlphaFieldNames.allocate(MaxNumAlphas);
2835 47 : cAlphaArgs.allocate(MaxNumAlphas);
2836 47 : lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
2837 47 : cNumericFieldNames.allocate(MaxNumNumbers);
2838 47 : rNumericArgs.dimension(MaxNumNumbers, 0.0);
2839 47 : lNumericFieldBlanks.dimension(MaxNumNumbers, false);
2840 :
2841 47 : cCurrentModuleObject = "EnergyManagementSystem:GlobalVariable";
2842 :
2843 47 : if (state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2844 47 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
2845 47 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitExportGlobalVariables >
2846 : 0) {
2847 57 : for (GlobalNum = 1;
2848 57 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2849 57 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables +
2850 57 : 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 33 : if (GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables) {
2856 33 : 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 0 : } else if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables &&
2869 0 : 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 0 : } else if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables &&
2884 0 : GlobalNum <= state.dataRuntimeLang->NumUserGlobalVariables + state.dataRuntimeLang->NumExternalInterfaceGlobalVariables +
2885 0 : state.dataRuntimeLang->NumExternalInterfaceFunctionalMockupUnitImportGlobalVariables) {
2886 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
2887 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2888 : cCurrentModuleObject,
2889 0 : GlobalNum - state.dataRuntimeLang->NumUserGlobalVariables -
2890 0 : 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 86 : for (ErlVarLoop = 1; ErlVarLoop <= NumAlphas; ++ErlVarLoop) {
2925 53 : if ((cCurrentModuleObject.compare("ExternalInterface:FunctionalMockupUnitImport:To:Variable") == 0)) {
2926 0 : 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 0 : ValidateEMSVariableName(
2930 0 : state, cCurrentModuleObject, cAlphaArgs(ErlVarLoop), cAlphaFieldNames(ErlVarLoop), errFlag, ErrorsFound);
2931 : }
2932 : } else {
2933 53 : ValidateEMSVariableName(
2934 53 : state, cCurrentModuleObject, cAlphaArgs(ErlVarLoop), cAlphaFieldNames(ErlVarLoop), errFlag, ErrorsFound);
2935 : }
2936 53 : 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 53 : } else if (!errFlag) {
2941 53 : VariableNum = FindEMSVariable(state, cAlphaArgs(ErlVarLoop), 0);
2942 : // Still need to check for conflicts with program and function names too
2943 :
2944 53 : 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 53 : VariableNum = NewEMSVariable(state, cAlphaArgs(ErlVarLoop), 0);
2951 53 : if (GlobalNum > state.dataRuntimeLang->NumUserGlobalVariables) {
2952 : // Initialize variables for the ExternalInterface variables.
2953 : // This object requires an initial value.
2954 0 : ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false);
2955 : }
2956 : }
2957 : }
2958 : }
2959 : }
2960 : }
2961 :
2962 47 : cCurrentModuleObject = "EnergyManagementSystem:CurveOrTableIndexVariable";
2963 47 : state.dataRuntimeLang->NumEMSCurveIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
2964 47 : if (state.dataRuntimeLang->NumEMSCurveIndices > 0) {
2965 1 : state.dataRuntimeLangProcessor->CurveIndexVariableNums.dimension(state.dataRuntimeLang->NumEMSCurveIndices, 0);
2966 6 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSCurveIndices; ++loop) {
2967 5 : 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 5 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
2982 5 : 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 5 : } else if (!errFlag) {
2988 5 : VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0);
2989 5 : 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 5 : VariableNum = NewEMSVariable(state, cAlphaArgs(1), 0);
2997 : // store variable num
2998 5 : state.dataRuntimeLangProcessor->CurveIndexVariableNums(loop) = VariableNum;
2999 : }
3000 : }
3001 :
3002 5 : CurveIndexNum = GetCurveIndex(state, cAlphaArgs(2)); // curve name
3003 5 : 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 5 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = SetErlValueNumber(double(CurveIndexNum));
3017 : }
3018 : }
3019 :
3020 : } // NumEMSCurveIndices > 0
3021 :
3022 47 : cCurrentModuleObject = "EnergyManagementSystem:ConstructionIndexVariable";
3023 47 : state.dataRuntimeLang->NumEMSConstructionIndices = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3024 47 : if (state.dataRuntimeLang->NumEMSConstructionIndices > 0) {
3025 2 : state.dataRuntimeLangProcessor->ConstructionIndexVariableNums.dimension(state.dataRuntimeLang->NumEMSConstructionIndices, 0);
3026 6 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSConstructionIndices; ++loop) {
3027 4 : 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 4 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
3042 4 : 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 4 : } else if (!errFlag) {
3048 4 : VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0);
3049 4 : 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 4 : VariableNum = NewEMSVariable(state, cAlphaArgs(1), 0);
3057 : // store variable num
3058 4 : state.dataRuntimeLangProcessor->ConstructionIndexVariableNums(loop) = VariableNum;
3059 : }
3060 : } else {
3061 0 : continue;
3062 : }
3063 :
3064 4 : ConstructNum = Util::FindItemInList(cAlphaArgs(2), state.dataConstruction->Construct);
3065 :
3066 4 : 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 4 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = SetErlValueNumber(double(ConstructNum));
3080 : }
3081 : }
3082 :
3083 : } // NumEMSConstructionIndices > 0
3084 :
3085 47 : state.dataRuntimeLang->NumErlStacks = state.dataRuntimeLang->NumErlPrograms + state.dataRuntimeLang->NumErlSubroutines;
3086 47 : state.dataRuntimeLang->ErlStack.allocate(state.dataRuntimeLang->NumErlStacks);
3087 47 : state.dataRuntimeLangProcessor->ErlStackUniqueNames.reserve(static_cast<unsigned>(state.dataRuntimeLang->NumErlStacks));
3088 :
3089 47 : if (state.dataRuntimeLang->NumErlPrograms > 0) {
3090 25 : cCurrentModuleObject = "EnergyManagementSystem:Program";
3091 61 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlPrograms; ++StackNum) {
3092 36 : 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 36 : GlobalNames::VerifyUniqueInterObjectName(state,
3105 36 : state.dataRuntimeLangProcessor->ErlStackUniqueNames,
3106 36 : cAlphaArgs(1),
3107 : cCurrentModuleObject,
3108 36 : cAlphaFieldNames(1),
3109 : ErrorsFound);
3110 :
3111 36 : ValidateEMSProgramName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), "Programs", errFlag, ErrorsFound);
3112 36 : if (!errFlag) {
3113 36 : state.dataRuntimeLang->ErlStack(StackNum).Name = cAlphaArgs(1);
3114 : }
3115 :
3116 36 : if (NumAlphas > 1) {
3117 36 : state.dataRuntimeLang->ErlStack(StackNum).Line.allocate(NumAlphas - 1);
3118 36 : state.dataRuntimeLang->ErlStack(StackNum).NumLines = NumAlphas - 1;
3119 36 : state.dataRuntimeLang->ErlStack(StackNum).Line({1, NumAlphas - 1}) = cAlphaArgs({2, NumAlphas}); // note array assignment
3120 : }
3121 :
3122 : } // ProgramNum
3123 : }
3124 :
3125 47 : if (state.dataRuntimeLang->NumErlSubroutines > 0) {
3126 1 : cCurrentModuleObject = "EnergyManagementSystem:Subroutine";
3127 2 : for (StackNum = state.dataRuntimeLang->NumErlPrograms + 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3128 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3129 : cCurrentModuleObject,
3130 1 : StackNum - state.dataRuntimeLang->NumErlPrograms,
3131 : cAlphaArgs,
3132 : NumAlphas,
3133 : rNumericArgs,
3134 : NumNums,
3135 : IOStat,
3136 : lNumericFieldBlanks,
3137 : lAlphaFieldBlanks,
3138 : cAlphaFieldNames,
3139 : cNumericFieldNames);
3140 1 : GlobalNames::VerifyUniqueInterObjectName(state,
3141 1 : state.dataRuntimeLangProcessor->ErlStackUniqueNames,
3142 1 : cAlphaArgs(1),
3143 : cCurrentModuleObject,
3144 1 : cAlphaFieldNames(1),
3145 : ErrorsFound);
3146 :
3147 1 : ValidateEMSProgramName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), "Subroutines", errFlag, ErrorsFound);
3148 1 : if (!errFlag) {
3149 1 : state.dataRuntimeLang->ErlStack(StackNum).Name = cAlphaArgs(1);
3150 : }
3151 :
3152 1 : if (NumAlphas > 1) {
3153 1 : state.dataRuntimeLang->ErlStack(StackNum).Line.allocate(NumAlphas - 1);
3154 1 : state.dataRuntimeLang->ErlStack(StackNum).NumLines = NumAlphas - 1;
3155 1 : state.dataRuntimeLang->ErlStack(StackNum).Line({1, NumAlphas - 1}) = cAlphaArgs({2, NumAlphas}); // note array assignment
3156 : }
3157 : }
3158 : }
3159 :
3160 47 : cCurrentModuleObject = "EnergyManagementSystem:TrendVariable";
3161 47 : state.dataRuntimeLang->NumErlTrendVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3162 47 : if (state.dataRuntimeLang->NumErlTrendVariables > 0) {
3163 2 : state.dataRuntimeLang->TrendVariable.allocate(state.dataRuntimeLang->NumErlTrendVariables);
3164 9 : for (TrendNum = 1; TrendNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendNum) {
3165 7 : 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 7 : Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
3178 :
3179 7 : ValidateEMSVariableName(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(1), errFlag, ErrorsFound);
3180 7 : if (!errFlag) {
3181 7 : state.dataRuntimeLang->TrendVariable(TrendNum).Name = cAlphaArgs(1);
3182 : }
3183 :
3184 7 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), 0);
3185 : // Still need to check for conflicts with program and function names too
3186 7 : 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 7 : state.dataRuntimeLang->TrendVariable(TrendNum).ErlVariablePointer = VariableNum;
3193 : // register the trend pointer in ErlVariable.
3194 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.TrendVariable = true;
3195 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.TrendVarPointer = TrendNum;
3196 7 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true; // Cannot figure out how to get around needing this,
3197 : }
3198 :
3199 7 : NumTrendSteps = std::floor(rNumericArgs(1));
3200 7 : if (NumTrendSteps > 0) {
3201 7 : state.dataRuntimeLang->TrendVariable(TrendNum).LogDepth = NumTrendSteps;
3202 : // setup data arrays using NumTrendSteps
3203 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR.allocate(NumTrendSteps);
3204 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TrendValARR = 0.0; // array init
3205 7 : state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR.allocate(NumTrendSteps);
3206 7 : state.dataRuntimeLang->TrendVariable(TrendNum).tempTrendARR = 0.0; // array init
3207 7 : 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 43 : for (loop = 1; loop <= NumTrendSteps; ++loop) {
3213 36 : if (loop == 1) {
3214 7 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop) = -state.dataGlobal->TimeStepZone;
3215 7 : continue;
3216 : } else {
3217 29 : state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop) =
3218 29 : 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 47 : 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 84 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3237 37 : ParseStack(state, StackNum);
3238 :
3239 37 : 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 47 : if (ErrorsFound) {
3251 0 : ShowFatalError(state, "Errors found in parsing EMS Runtime Language input. Preceding condition causes termination.");
3252 : }
3253 :
3254 47 : if ((state.dataRuntimeLang->NumEMSOutputVariables > 0) || (state.dataRuntimeLang->NumEMSMeteredOutputVariables > 0)) {
3255 12 : state.dataRuntimeLangProcessor->RuntimeReportVar.allocate(state.dataRuntimeLang->NumEMSOutputVariables +
3256 6 : state.dataRuntimeLang->NumEMSMeteredOutputVariables);
3257 : }
3258 :
3259 47 : if (state.dataRuntimeLang->NumEMSOutputVariables > 0) {
3260 6 : cCurrentModuleObject = "EnergyManagementSystem:OutputVariable";
3261 21 : for (RuntimeReportVarNum = 1; RuntimeReportVarNum <= state.dataRuntimeLang->NumEMSOutputVariables; ++RuntimeReportVarNum) {
3262 15 : 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 15 : GlobalNames::VerifyUniqueInterObjectName(state,
3275 15 : state.dataRuntimeLangProcessor->RuntimeReportVarUniqueNames,
3276 15 : cAlphaArgs(1),
3277 : cCurrentModuleObject,
3278 15 : cAlphaFieldNames(1),
3279 : ErrorsFound);
3280 :
3281 15 : lbracket = index(cAlphaArgs(1), '[');
3282 15 : if (lbracket == std::string::npos) {
3283 15 : 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 15 : UnitsB = cAlphaArgs(6);
3290 15 : lbracket = index(UnitsB, '[');
3291 15 : ptr = index(UnitsB, ']');
3292 15 : 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 15 : curUnit = static_cast<Constant::Units>(getEnumValue(Constant::unitNamesUC, Util::makeUPPER(UnitsB)));
3331 :
3332 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Name = cAlphaArgs(1);
3333 :
3334 15 : if (!lAlphaFieldBlanks(5)) {
3335 : // Lookup the Runtime Language Context, i.e., PROGRAM, FUNCTION, or global
3336 5 : Found = false;
3337 23 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3338 23 : if (state.dataRuntimeLang->ErlStack(StackNum).Name == cAlphaArgs(5)) {
3339 5 : Found = true;
3340 5 : break;
3341 : }
3342 : }
3343 5 : 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 10 : StackNum = 0;
3352 : }
3353 :
3354 15 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum);
3355 :
3356 15 : 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 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum = VariableNum;
3374 : }
3375 :
3376 15 : if (cAlphaArgs(3) == "AVERAGED") {
3377 15 : sovStoreType = OutputProcessor::StoreType::Average;
3378 0 : } else if (cAlphaArgs(3) == "SUMMED") {
3379 0 : 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 15 : if (cAlphaArgs(4) == "ZONETIMESTEP") {
3388 2 : sovTimeStepType = OutputProcessor::TimeStepType::Zone;
3389 13 : } else if (cAlphaArgs(4) == "SYSTEMTIMESTEP") {
3390 13 : 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 15 : if (curUnit != Constant::Units::Invalid) {
3399 60 : SetupOutputVariable(state,
3400 15 : cAlphaArgs(1),
3401 : curUnit,
3402 15 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3403 : sovTimeStepType,
3404 : sovStoreType,
3405 : "EMS");
3406 : } else {
3407 0 : SetupOutputVariable(state,
3408 0 : cAlphaArgs(1),
3409 : Constant::Units::customEMS,
3410 0 : 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 47 : if (state.dataRuntimeLang->NumEMSMeteredOutputVariables > 0) {
3431 1 : cCurrentModuleObject = "EnergyManagementSystem:MeteredOutputVariable";
3432 3 : for (loop = 1; loop <= state.dataRuntimeLang->NumEMSMeteredOutputVariables; ++loop) {
3433 2 : RuntimeReportVarNum = state.dataRuntimeLang->NumEMSOutputVariables + loop;
3434 2 : 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 2 : GlobalNames::VerifyUniqueInterObjectName(state,
3448 2 : state.dataRuntimeLangProcessor->RuntimeReportVarUniqueNames,
3449 2 : cAlphaArgs(1),
3450 : cCurrentModuleObject,
3451 2 : cAlphaFieldNames(1),
3452 : ErrorsFound);
3453 :
3454 2 : lbracket = index(cAlphaArgs(1), '[');
3455 2 : if (lbracket == std::string::npos) {
3456 2 : 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 2 : UnitsB = cAlphaArgs(9);
3463 2 : lbracket = index(UnitsB, '[');
3464 2 : ptr = index(UnitsB, ']');
3465 2 : 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 0 : ptr = index(cAlphaArgs(1), ']');
3474 0 : if (ptr != std::string::npos) {
3475 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1, ptr - lbracket - 1);
3476 : } else {
3477 0 : UnitsA = cAlphaArgs(1).substr(lbracket + 1);
3478 : }
3479 0 : cAlphaArgs(1).erase(lbracket - 1);
3480 0 : UnitsB = cAlphaArgs(9);
3481 0 : lbracket = index(UnitsB, '[');
3482 0 : ptr = index(UnitsB, ']');
3483 0 : 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 0 : 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 0 : } else if (UnitsB == "" && UnitsA != "") {
3497 0 : UnitsB = UnitsA;
3498 0 : ShowWarningError(state,
3499 0 : format("{}{}=\"{}\" using deprecated units designation.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
3500 0 : ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA));
3501 : }
3502 : }
3503 2 : curUnit = static_cast<Constant::Units>(getEnumValue(Constant::unitNamesUC, Util::makeUPPER(UnitsB)));
3504 :
3505 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Name = cAlphaArgs(1);
3506 :
3507 2 : if (!lAlphaFieldBlanks(4)) {
3508 : // Lookup the Runtime Language Context, i.e., PROGRAM, FUNCTION, or global
3509 2 : Found = false;
3510 11 : for (StackNum = 1; StackNum <= state.dataRuntimeLang->NumErlStacks; ++StackNum) {
3511 11 : if (state.dataRuntimeLang->ErlStack(StackNum).Name == cAlphaArgs(4)) {
3512 2 : Found = true;
3513 2 : break;
3514 : }
3515 : }
3516 2 : 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 2 : VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum);
3528 2 : 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 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum = VariableNum;
3546 : }
3547 :
3548 2 : sovStoreType = OutputProcessor::StoreType::Sum; // all metered vars are sum type
3549 :
3550 2 : if (cAlphaArgs(3) == "ZONETIMESTEP") {
3551 0 : sovTimeStepType = OutputProcessor::TimeStepType::Zone;
3552 2 : } else if (cAlphaArgs(3) == "SYSTEMTIMESTEP") {
3553 2 : 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 2 : static_cast<Constant::eResource>(getEnumValue(Constant::eResourceNamesUC, Util::makeUPPER(cAlphaArgs(5))));
3564 :
3565 2 : 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 2 : if (cAlphaArgs(6) == "BUILDING") {
3575 0 : sovGroup = OutputProcessor::Group::Building;
3576 2 : } else if (cAlphaArgs(6) == "HVAC") {
3577 2 : sovGroup = OutputProcessor::Group::HVAC;
3578 0 : } else if (cAlphaArgs(6) == "PLANT") {
3579 0 : sovGroup = OutputProcessor::Group::Plant;
3580 0 : } else if (cAlphaArgs(6) == "SYSTEM") {
3581 0 : 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 2 : if (cAlphaArgs(7) == "HEATING") {
3592 0 : sovEndUseCat = OutputProcessor::EndUseCat::Heating;
3593 2 : } else if (cAlphaArgs(7) == "COOLING") {
3594 2 : sovEndUseCat = OutputProcessor::EndUseCat::Cooling;
3595 0 : } else if (cAlphaArgs(7) == "INTERIORLIGHTS") {
3596 0 : sovEndUseCat = OutputProcessor::EndUseCat::InteriorLights;
3597 0 : } else if (cAlphaArgs(7) == "EXTERIORLIGHTS") {
3598 0 : sovEndUseCat = OutputProcessor::EndUseCat::ExteriorLights;
3599 0 : } else if (cAlphaArgs(7) == "INTERIOREQUIPMENT") {
3600 0 : sovEndUseCat = OutputProcessor::EndUseCat::InteriorEquipment;
3601 0 : } else if (cAlphaArgs(7) == "EXTERIOREQUIPMENT") {
3602 0 : sovEndUseCat = OutputProcessor::EndUseCat::ExteriorEquipment;
3603 0 : } else if (cAlphaArgs(7) == "FANS") {
3604 0 : sovEndUseCat = OutputProcessor::EndUseCat::Fans;
3605 0 : } else if (cAlphaArgs(7) == "PUMPS") {
3606 0 : sovEndUseCat = OutputProcessor::EndUseCat::Pumps;
3607 0 : } else if (cAlphaArgs(7) == "HEATREJECTION") {
3608 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRejection;
3609 0 : } else if (cAlphaArgs(7) == "HUMIDIFIER") {
3610 0 : sovEndUseCat = OutputProcessor::EndUseCat::Humidification;
3611 0 : } else if (cAlphaArgs(7) == "HEATRECOVERY") {
3612 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatRecovery;
3613 0 : } else if (cAlphaArgs(7) == "WATERSYSTEMS") {
3614 0 : sovEndUseCat = OutputProcessor::EndUseCat::WaterSystem;
3615 0 : } else if (cAlphaArgs(7) == "REFRIGERATION") {
3616 0 : sovEndUseCat = OutputProcessor::EndUseCat::Refrigeration;
3617 0 : } else if (cAlphaArgs(7) == "ONSITEGENERATION") {
3618 0 : sovEndUseCat = OutputProcessor::EndUseCat::Cogeneration;
3619 0 : } else if (cAlphaArgs(7) == "HEATINGCOILS") {
3620 0 : sovEndUseCat = OutputProcessor::EndUseCat::HeatingCoils;
3621 0 : } else if (cAlphaArgs(7) == "COOLINGCOILS") {
3622 0 : 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 2 : if ((resource != Constant::eResource::EnergyTransfer) &&
3641 2 : (sovEndUseCat == OutputProcessor::EndUseCat::HeatingCoils || sovEndUseCat == OutputProcessor::EndUseCat::CoolingCoils ||
3642 2 : sovEndUseCat == OutputProcessor::EndUseCat::Chillers || sovEndUseCat == OutputProcessor::EndUseCat::Boilers ||
3643 2 : 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 2 : if (!lAlphaFieldBlanks(8)) {
3653 2 : EndUseSubCatString = cAlphaArgs(8);
3654 :
3655 8 : SetupOutputVariable(state,
3656 2 : cAlphaArgs(1),
3657 : curUnit,
3658 2 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3659 : sovTimeStepType,
3660 : sovStoreType,
3661 : "EMS",
3662 : resource,
3663 : sovGroup,
3664 : sovEndUseCat,
3665 : EndUseSubCatString);
3666 : } else { // no subcat
3667 0 : SetupOutputVariable(state,
3668 0 : cAlphaArgs(1),
3669 : curUnit,
3670 0 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value,
3671 : sovTimeStepType,
3672 : sovStoreType,
3673 : "EMS",
3674 : resource,
3675 : sovGroup,
3676 : sovEndUseCat);
3677 : }
3678 : }
3679 : } // NumEMSMeteredOutputVariables > 0
3680 :
3681 47 : cAlphaFieldNames.deallocate();
3682 47 : cAlphaArgs.deallocate();
3683 47 : lAlphaFieldBlanks.deallocate();
3684 47 : cNumericFieldNames.deallocate();
3685 47 : rNumericArgs.deallocate();
3686 47 : lNumericFieldBlanks.deallocate();
3687 :
3688 47 : if (ErrorsFound) {
3689 0 : ShowFatalError(state, "Errors found in getting EMS Runtime Language input. Preceding condition causes termination.");
3690 : }
3691 :
3692 : } // GetInput
3693 47 : }
3694 :
3695 115066 : 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 172766 : for (RuntimeReportVarNum = 1;
3716 172766 : RuntimeReportVarNum <= state.dataRuntimeLang->NumEMSOutputVariables + state.dataRuntimeLang->NumEMSMeteredOutputVariables;
3717 : ++RuntimeReportVarNum) {
3718 57700 : VariableNum = state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).VariableNum;
3719 57700 : if (state.dataRuntimeLang->ErlVariable(VariableNum).Value.Type == Value::Number) {
3720 57699 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value =
3721 57699 : state.dataRuntimeLang->ErlVariable(VariableNum).Value.Number;
3722 : } else {
3723 1 : state.dataRuntimeLangProcessor->RuntimeReportVar(RuntimeReportVarNum).Value = 0.0;
3724 : }
3725 : }
3726 115066 : }
3727 :
3728 26065698 : ErlValueType SetErlValueNumber(Real64 const Number, ObjexxFCL::Optional<ErlValueType const> OrigValue)
3729 : {
3730 : // FUNCTION INFORMATION:
3731 : // AUTHOR P. Ellis
3732 : // DATE WRITTEN unknown
3733 :
3734 26065698 : ErlValueType newValue;
3735 :
3736 26065698 : if (present(OrigValue)) { // preserve other parts of structure and only updated Value%Number
3737 236299 : newValue = OrigValue;
3738 236299 : newValue.Number = Number;
3739 : } else {
3740 25829399 : newValue.Type = Value::Number;
3741 25829399 : newValue.Number = Number;
3742 : }
3743 :
3744 26065698 : newValue.initialized = true;
3745 26065698 : 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 7 : 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 7 : std::string String;
3814 :
3815 : // Locals
3816 : // FUNCTION ARGUMENT DEFINITIONS:
3817 :
3818 7 : String = "";
3819 :
3820 7 : switch (Value.Type) {
3821 7 : case Value::Number:
3822 7 : if (Value.Number == 0.0) {
3823 1 : String = "0.0";
3824 : } else {
3825 6 : String = format("{:.6T}", Value.Number); //(String)
3826 : }
3827 7 : break;
3828 :
3829 0 : case Value::String:
3830 0 : String = Value.String;
3831 0 : break;
3832 :
3833 0 : case Value::Array:
3834 : // TBD
3835 0 : break;
3836 :
3837 0 : case Value::Error:
3838 0 : String = " *** Error: " + Value.Error + " *** ";
3839 0 : break;
3840 :
3841 0 : default:
3842 : // Nothing to do
3843 0 : break;
3844 : }
3845 :
3846 7 : return String;
3847 0 : }
3848 :
3849 2296 : 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 2296 : Found = false;
3870 2296 : std::string const UppercaseName = Util::makeUPPER(VariableName);
3871 :
3872 : // check in ErlVariables
3873 81931 : for (VariableNum = 1; VariableNum <= state.dataRuntimeLang->NumErlVariables; ++VariableNum) {
3874 80174 : if (state.dataRuntimeLang->ErlVariable(VariableNum).Name == UppercaseName) {
3875 900 : if ((state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == StackNum) ||
3876 308 : (state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == 0)) {
3877 539 : Found = true;
3878 539 : break;
3879 : }
3880 : }
3881 : }
3882 :
3883 : // check in Trend variables
3884 2801 : for (TrendVarNum = 1; TrendVarNum <= state.dataRuntimeLang->NumErlTrendVariables; ++TrendVarNum) {
3885 519 : if (state.dataRuntimeLang->TrendVariable(TrendVarNum).Name == UppercaseName) {
3886 14 : VariableNum = state.dataRuntimeLang->TrendVariable(TrendVarNum).ErlVariablePointer;
3887 28 : if ((state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == StackNum) ||
3888 14 : (state.dataRuntimeLang->ErlVariable(VariableNum).StackNum == 0)) {
3889 14 : Found = true;
3890 14 : break;
3891 : }
3892 : }
3893 : }
3894 :
3895 2296 : if (!Found) VariableNum = 0;
3896 :
3897 2296 : return VariableNum;
3898 2296 : }
3899 :
3900 2082 : 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 2082 : int VariableNum = FindEMSVariable(state, VariableName, StackNum);
3913 :
3914 2082 : if (VariableNum == 0) { // Variable does not exist anywhere yet
3915 1582 : if (state.dataRuntimeLang->NumErlVariables == 0) {
3916 46 : state.dataRuntimeLang->ErlVariable.allocate(1);
3917 46 : state.dataRuntimeLang->NumErlVariables = 1;
3918 : } else { // Extend the variable array
3919 1536 : state.dataRuntimeLang->ErlVariable.redimension(++state.dataRuntimeLang->NumErlVariables);
3920 : }
3921 :
3922 : // Add the new variable
3923 1582 : VariableNum = state.dataRuntimeLang->NumErlVariables;
3924 1582 : auto &thisErlVar = state.dataRuntimeLang->ErlVariable(VariableNum);
3925 1582 : thisErlVar.Name = Util::makeUPPER(VariableName);
3926 1582 : thisErlVar.StackNum = StackNum;
3927 1582 : thisErlVar.Value.Type = Value::Number; // ErlVariable values are numbers
3928 : }
3929 :
3930 2082 : if (present(Value)) {
3931 322 : state.dataRuntimeLang->ErlVariable(VariableNum).Value = Value;
3932 : }
3933 :
3934 2082 : return VariableNum;
3935 : }
3936 :
3937 0 : 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 0 : state.dataRuntimeLang->ErlVariable(varNum).Value = SetErlValueNumber(value);
3961 0 : }
3962 :
3963 0 : 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 0 : if (setToNull) {
3988 0 : state.dataRuntimeLang->ErlVariable(varNum).Value.Type = Value::Null;
3989 : } else {
3990 0 : 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 0 : 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 0 : state.dataRuntimeLang->ErlVariable(varNum).SetByExternalInterface = true;
3998 0 : }
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
|