LCOV - code coverage report
Current view: top level - EnergyPlus - RuntimeLanguageProcessor.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1568 2197 71.4 %
Date: 2024-08-24 18:31:18 Functions: 20 23 87.0 %

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

Generated by: LCOV version 1.14