LCOV - code coverage report
Current view: top level - EnergyPlus - RuntimeLanguageProcessor.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 72.7 % 2233 1623
Test Date: 2025-06-02 12:03:30 Functions: 78.3 % 23 18

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

Generated by: LCOV version 2.0-1