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

Generated by: LCOV version 2.0-1