From 8623d71fc1bf171caee291b7727416fff670bcdf Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 29 Jan 2026 16:00:39 -0700 Subject: [PATCH 01/21] Add failing EMS unit test to demonstrate that variable initialized after reference does not throw error. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 121 ++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 9814a590449..76b09370ced 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -52,6 +52,7 @@ // EnergyPlus Headers #include "Fixtures/EnergyPlusFixture.hh" +#include #include #include #include @@ -936,7 +937,7 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) state->dataEMSMgr->FinishProcessingUserInput = true; bool anyRan; EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); - // Expect the variable to not yet be initialized, call EvaluateExpresssion and check argument + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument ErlValueType ReturnValue; bool seriousErrorFound = false; @@ -958,6 +959,124 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) EXPECT_FALSE(seriousErrorFound); } +TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) +{ + // this tests the variable is initialized before it is referenced, for issue #11360 + std::string const idf_objects = delimited_string({ + "Version," + DataStringGlobals::MatchVersion + ";", + + "RunPeriod,", + " Run Period 1, !- Name", + " 1, !- Begin Month", + " 1, !- Begin Day of Month", + " 2007, !- Begin Year", + " 1, !- End Month", + " 1, !- End Day of Month", + " 2007, !- End Year", + " Monday, !- Day of Week for Start Day", + " No, !- Use Weather File Holidays and Special Days", + " No, !- Use Weather File Daylight Saving Period", + " No, !- Apply Weekend Holiday Rule", + " Yes, !- Use Weather File Rain Indicators", + " Yes; !- Use Weather File Snow Indicators", + + "SimulationControl,", + " No, !- Do Zone Sizing Calculation", + " No, !- Do System Sizing Calculation", + " No, !- Do Plant Sizing Calculation", + " No, !- Run Simulation for Sizing Periods", + " Yes, !- Run Simulation for Weather File Run Periods", + " , !- Do HVAC Sizing Simulation for Sizing Periods", + " ; !- Maximum Number of HVAC Sizing Simulation Passes", + + "Site:Location,", + " Denver Stapleton Intl Arpt CO USA WMO=724690, !- Name", + " 39.77, !- Latitude {deg}", + " -104.87, !- Longitude {deg}", + " -7.00, !- Time Zone {hr}", + " 1611.00; !- Elevation {m}", + + "Material,", + " Concrete Block, !- Name", + " MediumRough, !- Roughness", + " 0.1014984, !- Thickness {m}", + " 0.3805070, !- Conductivity {W/m-K}", + " 608.7016, !- Density {kg/m3}", + " 836.8000; !- Specific Heat {J/kg-K}", + + "Construction,", + " ConcConstruction, !- Name", + " Concrete Block; !- Outside Layer", + + "BuildingSurface:Detailed," + " Wall, !- Name", + " Wall, !- Surface Type", + " ConcConstruction, !- Construction Name", + " Zone, !- Zone Name", + " , !- Space Name", + " Outdoors, !- Outside Boundary Condition", + " , !- Outside Boundary Condition Object", + " SunExposed, !- Sun Exposure", + " WindExposed, !- Wind Exposure", + " 0.5000000, !- View Factor to Ground", + " 4, !- Number of Vertices", + " 0.000000,0.000000,10.00000, !- X,Y,Z ==> Vertex 1 {m}", + " 0.000000,0.000000,0, !- X,Y,Z ==> Vertex 2 {m}", + " 10.00000,0.000000,0, !- X,Y,Z ==> Vertex 3 {m}", + " 10.00000,0.000000,10.00000; !- X,Y,Z ==> Vertex 4 {m}", + + "Zone," + " Zone, !- Name", + " 0, !- Direction of Relative North {deg}", + " 6.000000, !- X Origin {m}", + " 6.000000, !- Y Origin {m}", + " 0, !- Z Origin {m}", + " 1, !- Type", + " 1, !- Multiplier", + " autocalculate, !- Ceiling Height {m}", + " autocalculate; !- Volume {m3}", + + "EnergyManagementSystem:Actuator,", + " battery_discharge_power_act, !- Name", + " Wall, !- Actuated Component Unique Name", + " Surface, !- Actuated Component Type", + " View Factor To Ground; !- Actuated Component Control Type", + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1, !- Program Line 2", + " Set battery_discharge_power_act = power_mult; !- Program Line 3", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + state->dataWeather->WeatherFileExists = true; + state->files.inputWeatherFilePath.filePath = configured_source_directory() / "weather/USA_CO_Golden-NREL.724666_TMY3.epw"; + + SimulationManager::ManageSimulation(*state); + + int wallSurfNum = Util::FindItemInList("WALL", state->dataSurface->Surface); + bool anyRan; + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()); + // EXPECT_EQ(state->dataSurface->Surface(wallSurfNum).ViewFactorGround, 0.1); + + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument + ErlValueType ReturnValue; + bool seriousErrorFound = false; + ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + *state, + state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, + seriousErrorFound); + EXPECT_TRUE(seriousErrorFound); +} + TEST_F(EnergyPlusFixture, EMSManager_CheckIfAnyEMS_OutEMS) { std::string const idf_objects = delimited_string({ From ead50b6fb20eee0a6957e2f4baf2ca8ff76414cc Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 29 Jan 2026 16:03:15 -0700 Subject: [PATCH 02/21] Formatting. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 76b09370ced..23446efc7a7 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -971,7 +971,7 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) " 1, !- Begin Day of Month", " 2007, !- Begin Year", " 1, !- End Month", - " 1, !- End Day of Month", + " 1, !- End Day of Month", " 2007, !- End Year", " Monday, !- Day of Week for Start Day", " No, !- Use Weather File Holidays and Special Days", @@ -1038,20 +1038,20 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) "EnergyManagementSystem:Actuator,", " battery_discharge_power_act, !- Name", - " Wall, !- Actuated Component Unique Name", - " Surface, !- Actuated Component Type", - " View Factor To Ground; !- Actuated Component Control Type", + " Wall, !- Actuated Component Unique Name", + " Surface, !- Actuated Component Type", + " View Factor To Ground; !- Actuated Component Control Type", "EnergyManagementSystem:Program,", - " ev_discharge_program, !- Name", - " Set power_mult = site_temp_adj, !- Program Line 1", - " Set site_temp_adj = 0.1, !- Program Line 2", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1, !- Program Line 2", " Set battery_discharge_power_act = power_mult; !- Program Line 3", "EnergyManagementSystem:ProgramCallingManager,", - " ev_discharge_pcm, !- Name", + " ev_discharge_pcm, !- Name", " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", - " ev_discharge_program; !- Program Name 1", + " ev_discharge_program; !- Program Name 1", }); ASSERT_TRUE(process_idf(idf_objects)); From 65966b8c2bef9458407048d49fbaeb70edf0da60 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Thu, 29 Jan 2026 18:44:35 -0700 Subject: [PATCH 03/21] fix uninitialized var --- tst/EnergyPlus/unit/EMSManager.unit.cc | 31 +++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 23446efc7a7..4bd8cffac53 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -966,19 +966,19 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) "Version," + DataStringGlobals::MatchVersion + ";", "RunPeriod,", - " Run Period 1, !- Name", - " 1, !- Begin Month", - " 1, !- Begin Day of Month", - " 2007, !- Begin Year", - " 1, !- End Month", - " 1, !- End Day of Month", - " 2007, !- End Year", - " Monday, !- Day of Week for Start Day", - " No, !- Use Weather File Holidays and Special Days", - " No, !- Use Weather File Daylight Saving Period", - " No, !- Apply Weekend Holiday Rule", - " Yes, !- Use Weather File Rain Indicators", - " Yes; !- Use Weather File Snow Indicators", + " Run Period 1, !- Name", + " 1, !- Begin Month", + " 1, !- Begin Day of Month", + " 2007, !- Begin Year", + " 1, !- End Month", + " 1, !- End Day of Month", + " 2007, !- End Year", + " Monday, !- Day of Week for Start Day", + " No, !- Use Weather File Holidays and Special Days", + " No, !- Use Weather File Daylight Saving Period", + " No, !- Apply Weekend Holiday Rule", + " Yes, !- Use Weather File Rain Indicators", + " Yes; !- Use Weather File Snow Indicators", "SimulationControl,", " No, !- Do Zone Sizing Calculation", @@ -1065,12 +1065,11 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) int wallSurfNum = Util::FindItemInList("WALL", state->dataSurface->Surface); bool anyRan; EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()); - // EXPECT_EQ(state->dataSurface->Surface(wallSurfNum).ViewFactorGround, 0.1); + EXPECT_EQ(state->dataSurface->Surface(wallSurfNum).ViewFactorGround, 0.1); // Expect the variable to not yet be initialized, call EvaluateExpression and check argument - ErlValueType ReturnValue; bool seriousErrorFound = false; - ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( *state, state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, seriousErrorFound); From d039752d9d84b0a46884c5527c41fed4b67971b0 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 30 Jan 2026 15:30:04 -0700 Subject: [PATCH 04/21] Add test to show difference between calling ManageEMS individually vs just ManageSimulation. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 92 +++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 4bd8cffac53..bea8e75b045 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -960,6 +960,74 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) } TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) +{ + // this tests the variable is initialized before it is referenced, for issue #11360 + std::string const idf_objects = delimited_string({ + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1; !- Program Line 2", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + bool anyRan; + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument + bool seriousErrorFound = false; + ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + *state, + state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, + seriousErrorFound); + EXPECT_TRUE(seriousErrorFound); + + const std::string expected_error = delimited_string({ + " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", + " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", + " ** ~~~ ** Erl program line number: 1", + " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", + " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", + " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", + " ** Fatal ** Previous EMS error caused program termination.", + " ...Summary of Errors that led to program termination:", + " ..... Reference severe error count=1", + " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", + }); + + compare_err_stream(expected_error); +} + +TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable4) { // this tests the variable is initialized before it is referenced, for issue #11360 std::string const idf_objects = delimited_string({ @@ -1036,17 +1104,10 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) " autocalculate, !- Ceiling Height {m}", " autocalculate; !- Volume {m3}", - "EnergyManagementSystem:Actuator,", - " battery_discharge_power_act, !- Name", - " Wall, !- Actuated Component Unique Name", - " Surface, !- Actuated Component Type", - " View Factor To Ground; !- Actuated Component Control Type", - "EnergyManagementSystem:Program,", " ev_discharge_program, !- Name", " Set power_mult = site_temp_adj, !- Program Line 1", - " Set site_temp_adj = 0.1, !- Program Line 2", - " Set battery_discharge_power_act = power_mult; !- Program Line 3", + " Set site_temp_adj = 0.1; !- Program Line 2", "EnergyManagementSystem:ProgramCallingManager,", " ev_discharge_pcm, !- Name", @@ -1060,12 +1121,23 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) state->dataWeather->WeatherFileExists = true; state->files.inputWeatherFilePath.filePath = configured_source_directory() / "weather/USA_CO_Golden-NREL.724666_TMY3.epw"; + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + EXPECT_EQ(0, state->dataRuntimeLang->NumSensors); SimulationManager::ManageSimulation(*state); + EXPECT_GT(state->dataRuntimeLang->NumSensors, 0); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_TRUE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - int wallSurfNum = Util::FindItemInList("WALL", state->dataSurface->Surface); bool anyRan; EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()); - EXPECT_EQ(state->dataSurface->Surface(wallSurfNum).ViewFactorGround, 0.1); + + ASSERT_GT(internalVarNum, 0); + EXPECT_TRUE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); // Expect the variable to not yet be initialized, call EvaluateExpression and check argument bool seriousErrorFound = false; From 69e2e71cd85c77a3f6de91fe1d6c9b314714ca74 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 9 Feb 2026 10:08:44 -0700 Subject: [PATCH 05/21] Add AlwaysFindSeriousError to EMS manager data struct. --- src/EnergyPlus/EMSManager.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/EnergyPlus/EMSManager.hh b/src/EnergyPlus/EMSManager.hh index b80064a2cee..4cb517d44af 100644 --- a/src/EnergyPlus/EMSManager.hh +++ b/src/EnergyPlus/EMSManager.hh @@ -198,6 +198,7 @@ struct EMSManagerData : BaseGlobalStruct bool GetEMSUserInput = true; // Flag to prevent input from being read multiple times bool ZoneThermostatActuatorsHaveBeenSetup = false; bool FinishProcessingUserInput = true; // Flag to indicate still need to process input + bool AlwaysFindSeriousError = false; bool lDummy = false; // dummy pointer location bool lDummy2 = false; // dummy pointer location @@ -215,6 +216,7 @@ struct EMSManagerData : BaseGlobalStruct GetEMSUserInput = true; ZoneThermostatActuatorsHaveBeenSetup = false; FinishProcessingUserInput = true; + AlwaysFindSeriousError = false; this->lDummy = false; this->lDummy2 = false; } From c1c2bee162c1185bf14fa424f5750f00241dbd96 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 9 Feb 2026 10:09:21 -0700 Subject: [PATCH 06/21] Update EvaluateStack to use new AlwaysFindSeriousError. --- src/EnergyPlus/RuntimeLanguageProcessor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index b2a0a2d29ed..2e07a191874 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -816,7 +816,6 @@ ErlValueType EvaluateStack(EnergyPlusData &state, int const StackNum) ReturnValue.Number = 0.0; auto const &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum); - InstructionNum = 1; while (InstructionNum <= thisErlStack.NumInstructions) { @@ -1801,7 +1800,8 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, } else { // value has never been set ReturnValue.Type = Value::Error; ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; - if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) { + + if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (state.dataEMSMgr->AlwaysFindSeriousError)) { // check if this is an arg in CurveValue, if (thisErlExpression.Operator != From 68543c1682354556174d41b543829b7bc131978b Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 9 Feb 2026 10:09:59 -0700 Subject: [PATCH 07/21] Update ManageSimulation to use new AlwaysFindSeriousError around SetupSimulation. --- src/EnergyPlus/SimulationManager.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/EnergyPlus/SimulationManager.cc b/src/EnergyPlus/SimulationManager.cc index 50927c01252..66e202a4f3e 100644 --- a/src/EnergyPlus/SimulationManager.cc +++ b/src/EnergyPlus/SimulationManager.cc @@ -268,7 +268,10 @@ namespace SimulationManager { state.dataGlobal->KickOffSimulation = true; Weather::ResetEnvironmentCounter(state); + + state.dataEMSMgr->AlwaysFindSeriousError = true; SetupSimulation(state, ErrorsFound); + state.dataEMSMgr->AlwaysFindSeriousError = false; FaultsManager::CheckAndReadFaults(state); @@ -330,6 +333,7 @@ namespace SimulationManager { ReportNodeConnections(state); } SystemReports::CreateEnergyReportStructure(state); + bool anyEMSRan; // point to finish setup processing EMS, sensor ready now EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::SetupSimulation, anyEMSRan, ObjexxFCL::Optional_int_const()); From cf65f570b3adb908290c673248bead5f7ec4b5ba Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 9 Feb 2026 10:10:23 -0700 Subject: [PATCH 08/21] Clean up new EMS variable unit tests. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 156 +++++++++++-------------- 1 file changed, 71 insertions(+), 85 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index bea8e75b045..f1ad43d8b34 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -959,77 +959,77 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) EXPECT_FALSE(seriousErrorFound); } -TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable3) +TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef1) { - // this tests the variable is initialized before it is referenced, for issue #11360 - std::string const idf_objects = delimited_string({ - - "EnergyManagementSystem:Program,", - " ev_discharge_program, !- Name", - " Set power_mult = site_temp_adj, !- Program Line 1", - " Set site_temp_adj = 0.1; !- Program Line 2", - - "EnergyManagementSystem:ProgramCallingManager,", - " ev_discharge_pcm, !- Name", - " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", - " ev_discharge_program; !- Program Name 1", - }); - - ASSERT_TRUE(process_idf(idf_objects)); - state->init_state(*state); - - int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - EXPECT_EQ(internalVarNum, 0); - - bool anyRan; - EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); - EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); - EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); - ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - // Expect the variable to not yet be initialized, call EvaluateExpression and check argument - bool seriousErrorFound = false; - ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( - *state, - state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, - seriousErrorFound); - EXPECT_TRUE(seriousErrorFound); - - const std::string expected_error = delimited_string({ - " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", - " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", - " ** ~~~ ** Erl program line number: 1", - " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", - " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", - " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", - " ** Fatal ** Previous EMS error caused program termination.", - " ...Summary of Errors that led to program termination:", - " ..... Reference severe error count=1", - " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", - }); - - compare_err_stream(expected_error); + // test for #11360 - EMS variable initialized after reference, outside of ManageSimulation + std::string const idf_objects = delimited_string({ + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1; !- Program Line 2", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + bool anyRan; + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument + bool seriousErrorFound = false; + ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + *state, + state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, + seriousErrorFound); + EXPECT_TRUE(seriousErrorFound); + + const std::string expected_error = delimited_string({ + " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", + " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", + " ** ~~~ ** Erl program line number: 1", + " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", + " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", + " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", + " ** Fatal ** Previous EMS error caused program termination.", + " ...Summary of Errors that led to program termination:", + " ..... Reference severe error count=1", + " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", + }); + + compare_err_stream(expected_error); } -TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable4) +TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef2) { - // this tests the variable is initialized before it is referenced, for issue #11360 + // test for #11360 - EMS variable initialized after reference, within ManageSimulation std::string const idf_objects = delimited_string({ "Version," + DataStringGlobals::MatchVersion + ";", @@ -1125,27 +1125,13 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable4) EXPECT_EQ(internalVarNum, 0); EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); - EXPECT_EQ(0, state->dataRuntimeLang->NumSensors); - SimulationManager::ManageSimulation(*state); - EXPECT_GT(state->dataRuntimeLang->NumSensors, 0); + EXPECT_FALSE(state->dataEMSMgr->AlwaysFindSeriousError); + ASSERT_THROW(SimulationManager::ManageSimulation(*state), EnergyPlus::FatalError); + EXPECT_TRUE(state->dataEMSMgr->AlwaysFindSeriousError); internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); ASSERT_GT(internalVarNum, 0); - EXPECT_TRUE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - bool anyRan; - EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()); - - ASSERT_GT(internalVarNum, 0); - EXPECT_TRUE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - // Expect the variable to not yet be initialized, call EvaluateExpression and check argument - bool seriousErrorFound = false; - ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( - *state, - state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, - seriousErrorFound); - EXPECT_TRUE(seriousErrorFound); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); } TEST_F(EnergyPlusFixture, EMSManager_CheckIfAnyEMS_OutEMS) From 9f9c099882b54f194f0a68e26d8632f7d9551a93 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 9 Feb 2026 15:00:52 -0700 Subject: [PATCH 09/21] Check for global variable instead of forcing error find. --- src/EnergyPlus/DataRuntimeLanguage.hh | 3 ++- src/EnergyPlus/EMSManager.hh | 2 -- src/EnergyPlus/RuntimeLanguageProcessor.cc | 4 +++- src/EnergyPlus/SimulationManager.cc | 2 -- tst/EnergyPlus/unit/EMSManager.unit.cc | 2 -- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/EnergyPlus/DataRuntimeLanguage.hh b/src/EnergyPlus/DataRuntimeLanguage.hh index 42410612235..8aa51eee788 100644 --- a/src/EnergyPlus/DataRuntimeLanguage.hh +++ b/src/EnergyPlus/DataRuntimeLanguage.hh @@ -394,9 +394,10 @@ namespace DataRuntimeLanguage { ErlValueType Value; // values taken by Erl variables bool ReadOnly; // true if Erl variable is read-only bool SetByExternalInterface; // set to true if value is set by ExternalInterface + bool SetByGlobalVariable; // Default Constructor - ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false) + ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false), SetByGlobalVariable(false) { } }; diff --git a/src/EnergyPlus/EMSManager.hh b/src/EnergyPlus/EMSManager.hh index 4cb517d44af..b80064a2cee 100644 --- a/src/EnergyPlus/EMSManager.hh +++ b/src/EnergyPlus/EMSManager.hh @@ -198,7 +198,6 @@ struct EMSManagerData : BaseGlobalStruct bool GetEMSUserInput = true; // Flag to prevent input from being read multiple times bool ZoneThermostatActuatorsHaveBeenSetup = false; bool FinishProcessingUserInput = true; // Flag to indicate still need to process input - bool AlwaysFindSeriousError = false; bool lDummy = false; // dummy pointer location bool lDummy2 = false; // dummy pointer location @@ -216,7 +215,6 @@ struct EMSManagerData : BaseGlobalStruct GetEMSUserInput = true; ZoneThermostatActuatorsHaveBeenSetup = false; FinishProcessingUserInput = true; - AlwaysFindSeriousError = false; this->lDummy = false; this->lDummy2 = false; } diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 2e07a191874..1f48cfcc5f5 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -1801,7 +1801,7 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, ReturnValue.Type = Value::Error; ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; - if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (state.dataEMSMgr->AlwaysFindSeriousError)) { + if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (!thisErlVar.SetByGlobalVariable)) { // check if this is an arg in CurveValue, if (thisErlExpression.Operator != @@ -2972,6 +2972,8 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) // Initialize variables for the ExternalInterface variables. // This object requires an initial value. ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false); + } else { + state.dataRuntimeLang->ErlVariable(VariableNum).SetByGlobalVariable = true; } } } diff --git a/src/EnergyPlus/SimulationManager.cc b/src/EnergyPlus/SimulationManager.cc index 66e202a4f3e..b4103f19a86 100644 --- a/src/EnergyPlus/SimulationManager.cc +++ b/src/EnergyPlus/SimulationManager.cc @@ -269,9 +269,7 @@ namespace SimulationManager { Weather::ResetEnvironmentCounter(state); - state.dataEMSMgr->AlwaysFindSeriousError = true; SetupSimulation(state, ErrorsFound); - state.dataEMSMgr->AlwaysFindSeriousError = false; FaultsManager::CheckAndReadFaults(state); diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index f1ad43d8b34..e48de4e2432 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -1125,9 +1125,7 @@ TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef2) EXPECT_EQ(internalVarNum, 0); EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); - EXPECT_FALSE(state->dataEMSMgr->AlwaysFindSeriousError); ASSERT_THROW(SimulationManager::ManageSimulation(*state), EnergyPlus::FatalError); - EXPECT_TRUE(state->dataEMSMgr->AlwaysFindSeriousError); internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); ASSERT_GT(internalVarNum, 0); From 590e0adfdde450fd6ebd701e8da55645b54c89a0 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 10 Feb 2026 16:40:13 -0700 Subject: [PATCH 10/21] Check for internal variable as well. --- src/EnergyPlus/DataRuntimeLanguage.hh | 3 ++- src/EnergyPlus/EMSManager.cc | 1 + src/EnergyPlus/RuntimeLanguageProcessor.cc | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/EnergyPlus/DataRuntimeLanguage.hh b/src/EnergyPlus/DataRuntimeLanguage.hh index 8aa51eee788..c6f9ad55272 100644 --- a/src/EnergyPlus/DataRuntimeLanguage.hh +++ b/src/EnergyPlus/DataRuntimeLanguage.hh @@ -395,9 +395,10 @@ namespace DataRuntimeLanguage { bool ReadOnly; // true if Erl variable is read-only bool SetByExternalInterface; // set to true if value is set by ExternalInterface bool SetByGlobalVariable; + bool SetByInternalVariable; // Default Constructor - ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false), SetByGlobalVariable(false) + ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false), SetByGlobalVariable(false), SetByInternalVariable(false) { } }; diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 9abcd0a99c6..13975a73c00 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -809,6 +809,7 @@ namespace EMSManager { } else { VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0); state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).ErlVariableNum = VariableNum; + state.dataRuntimeLang->ErlVariable(VariableNum).SetByInternalVariable = true; } state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName = cAlphaArgs(2); diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 1f48cfcc5f5..95ca0ddc393 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -1801,7 +1801,8 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, ReturnValue.Type = Value::Error; ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; - if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (!thisErlVar.SetByGlobalVariable)) { + if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || + (!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) { // check if this is an arg in CurveValue, if (thisErlExpression.Operator != @@ -2973,6 +2974,8 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) // This object requires an initial value. ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false); } else { + DisplayString(state, cCurrentModuleObject); + DisplayString(state, cAlphaArgs(ErlVarLoop)); state.dataRuntimeLang->ErlVariable(VariableNum).SetByGlobalVariable = true; } } From 836fd7e9f5e43e276d0bfd42946da823855c884a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 10 Feb 2026 16:40:28 -0700 Subject: [PATCH 11/21] Formatting in new unit test. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 128 ++++++++++++------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index e48de4e2432..53c810e9e04 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -961,70 +961,70 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef1) { - // test for #11360 - EMS variable initialized after reference, outside of ManageSimulation - std::string const idf_objects = delimited_string({ - - "EnergyManagementSystem:Program,", - " ev_discharge_program, !- Name", - " Set power_mult = site_temp_adj, !- Program Line 1", - " Set site_temp_adj = 0.1; !- Program Line 2", - - "EnergyManagementSystem:ProgramCallingManager,", - " ev_discharge_pcm, !- Name", - " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", - " ev_discharge_program; !- Program Name 1", - }); - - ASSERT_TRUE(process_idf(idf_objects)); - state->init_state(*state); - - int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - EXPECT_EQ(internalVarNum, 0); - - bool anyRan; - EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); - EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); - EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); - ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); - - internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); - ASSERT_GT(internalVarNum, 0); - EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); - - // Expect the variable to not yet be initialized, call EvaluateExpression and check argument - bool seriousErrorFound = false; - ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( - *state, - state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, - seriousErrorFound); - EXPECT_TRUE(seriousErrorFound); - - const std::string expected_error = delimited_string({ - " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", - " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", - " ** ~~~ ** Erl program line number: 1", - " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", - " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", - " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", - " ** Fatal ** Previous EMS error caused program termination.", - " ...Summary of Errors that led to program termination:", - " ..... Reference severe error count=1", - " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", - }); - - compare_err_stream(expected_error); + // test for #11360 - EMS variable initialized after reference, outside of ManageSimulation + std::string const idf_objects = delimited_string({ + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1; !- Program Line 2", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + bool anyRan; + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument + bool seriousErrorFound = false; + ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + *state, + state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, + seriousErrorFound); + EXPECT_TRUE(seriousErrorFound); + + const std::string expected_error = delimited_string({ + " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", + " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", + " ** ~~~ ** Erl program line number: 1", + " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", + " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", + " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", + " ** Fatal ** Previous EMS error caused program termination.", + " ...Summary of Errors that led to program termination:", + " ..... Reference severe error count=1", + " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", + }); + + compare_err_stream(expected_error); } TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef2) From b0bb17cb67de955fd484ece984f530ef9821ca0a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 10 Feb 2026 16:40:51 -0700 Subject: [PATCH 12/21] Temporary debugging changes in some testfiles. --- testfiles/LrgOff_GridStorageEMSSmoothing.idf | 2 +- testfiles/RetailPackagedTESCoil.idf | 6 +++--- testfiles/_ResidentialBase.idf | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/testfiles/LrgOff_GridStorageEMSSmoothing.idf b/testfiles/LrgOff_GridStorageEMSSmoothing.idf index 7e95d35677b..863e8a8cc4a 100644 --- a/testfiles/LrgOff_GridStorageEMSSmoothing.idf +++ b/testfiles/LrgOff_GridStorageEMSSmoothing.idf @@ -9887,7 +9887,7 @@ Output:EnergyManagementSystem, Verbose, !- Actuator Availability Dictionary Reporting Verbose, !- Internal Variable Availability Dictionary Reporting - ErrorsOnly; !- EMS Runtime Language Debug Output Level + Verbose; !- EMS Runtime Language Debug Output Level EnergyManagementSystem:Sensor, CurntFacilityElectDemand,!- Name diff --git a/testfiles/RetailPackagedTESCoil.idf b/testfiles/RetailPackagedTESCoil.idf index 4117d73a7dd..57dc097d9d8 100644 --- a/testfiles/RetailPackagedTESCoil.idf +++ b/testfiles/RetailPackagedTESCoil.idf @@ -8114,8 +8114,7 @@ Run SumIntakeMassFlowHeatCap, !- Run SumReliefAirMCTterm, !- Run CalcWindTerms, !- - Run CalcBouyancyTerms, !- - SEt Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- + Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- Set Troof = Numerator / Denominator, !- IF Ta < 2.0, !- @@ -8123,7 +8122,8 @@ ENDIF, !- IF Troof < Twb, !- Set Twb = Troof - 0.2, !- - ENDIF; !- + ENDIF, !- + Run CalcBouyancyTerms; !- EnergyManagementSystem:Program, ApplyMicroClimeActuators,!- Name diff --git a/testfiles/_ResidentialBase.idf b/testfiles/_ResidentialBase.idf index fc17d29a393..f6aeb9559f4 100644 --- a/testfiles/_ResidentialBase.idf +++ b/testfiles/_ResidentialBase.idf @@ -8143,6 +8143,11 @@ Yes, !- Output ExtShd Yes; !- Output Tarcog + Output:EnergyManagementSystem, + Verbose, !- Actuator Availability Dictionary Reporting + Verbose, !- Internal Variable Availability Dictionary Reporting + Verbose; !- EMS Runtime Language Debug Output Level + !- =========== ALL OBJECTS IN CLASS: OUTPUT:JSON =========== Output:JSON, From bf8e227aa104964899d915348a3eeb5a1149b815 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 11 Feb 2026 15:55:14 -0700 Subject: [PATCH 13/21] Set Type and Error only if serious error found. --- src/EnergyPlus/RuntimeLanguageProcessor.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 95ca0ddc393..2d3e623b96a 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -1798,12 +1798,12 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, if (thisErlVar.Value.initialized) { // check that value has been initialized thisOperand = thisErlVar.Value; } else { // value has never been set - ReturnValue.Type = Value::Error; - ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; - if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) { + ReturnValue.Type = Value::Error; + ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; + // check if this is an arg in CurveValue, if (thisErlExpression.Operator != ErlFunc::CurveValue) { // padding the argument list for CurveValue is too common to fatal on. only reported to EDD @@ -2974,8 +2974,6 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) // This object requires an initial value. ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false); } else { - DisplayString(state, cCurrentModuleObject); - DisplayString(state, cAlphaArgs(ErlVarLoop)); state.dataRuntimeLang->ErlVariable(VariableNum).SetByGlobalVariable = true; } } From 98171715c86251c2a5a6211cef6db02ba01b97f5 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 11 Feb 2026 16:01:11 -0700 Subject: [PATCH 14/21] Minor calling point changes in a few testfiles. --- testfiles/HospitalBaselineReheatReportEMS.idf | 11 ++++++++--- testfiles/LrgOff_GridStorageEMSSmoothing.idf | 2 +- testfiles/_ResidentialBase.idf | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/testfiles/HospitalBaselineReheatReportEMS.idf b/testfiles/HospitalBaselineReheatReportEMS.idf index f5ccd6a8798..4b746536a51 100644 --- a/testfiles/HospitalBaselineReheatReportEMS.idf +++ b/testfiles/HospitalBaselineReheatReportEMS.idf @@ -74050,19 +74050,24 @@ EnergyManagementSystem:ProgramCallingManager, Reheat_Sum_Call, !- Name - EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point + BeginNewEnvironment, !- EnergyPlus Model Calling Point Reheat_Sum_Program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, Heat_Sum_Call, !- Name - EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point + BeginNewEnvironment, !- EnergyPlus Model Calling Point Heat_Sum_Program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, AHU_Heat_Sum_Call, !- Name - EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point + BeginNewEnvironment, !- EnergyPlus Model Calling Point AHU_Heat_Energy_Program; !- Program Name 1 + Output:EnergyManagementSystem, + Verbose, !- Actuator Availability Dictionary Reporting + Verbose, !- Internal Variable Availability Dictionary Reporting + Verbose; !- EMS Runtime Language Debug Output Level + !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:PROGRAM =========== EnergyManagementSystem:Program, diff --git a/testfiles/LrgOff_GridStorageEMSSmoothing.idf b/testfiles/LrgOff_GridStorageEMSSmoothing.idf index 863e8a8cc4a..7e95d35677b 100644 --- a/testfiles/LrgOff_GridStorageEMSSmoothing.idf +++ b/testfiles/LrgOff_GridStorageEMSSmoothing.idf @@ -9887,7 +9887,7 @@ Output:EnergyManagementSystem, Verbose, !- Actuator Availability Dictionary Reporting Verbose, !- Internal Variable Availability Dictionary Reporting - Verbose; !- EMS Runtime Language Debug Output Level + ErrorsOnly; !- EMS Runtime Language Debug Output Level EnergyManagementSystem:Sensor, CurntFacilityElectDemand,!- Name diff --git a/testfiles/_ResidentialBase.idf b/testfiles/_ResidentialBase.idf index f6aeb9559f4..de3cbd0b946 100644 --- a/testfiles/_ResidentialBase.idf +++ b/testfiles/_ResidentialBase.idf @@ -7296,7 +7296,7 @@ EnergyManagementSystem:ProgramCallingManager, central_ac_and_furnace_airloop_0_duct_program calling manager, !- Name - EndOfSystemTimestepAfterHVACReporting, !- EnergyPlus Model Calling Point + BeginZoneTimestepBeforeInitHeatBalance, !- EnergyPlus Model Calling Point central_ac_and_furnace_airloop_0_duct_program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, @@ -8146,7 +8146,7 @@ Output:EnergyManagementSystem, Verbose, !- Actuator Availability Dictionary Reporting Verbose, !- Internal Variable Availability Dictionary Reporting - Verbose; !- EMS Runtime Language Debug Output Level + Verbose; !- EMS Runtime Language Debug Output Level !- =========== ALL OBJECTS IN CLASS: OUTPUT:JSON =========== From 4d1b4aa1a31e8ea2ff12a37a30067ca0f187342d Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 12 Feb 2026 12:10:22 -0700 Subject: [PATCH 15/21] Remove extra EMS output from idf test files. --- testfiles/HospitalBaselineReheatReportEMS.idf | 5 ----- testfiles/_ResidentialBase.idf | 5 ----- 2 files changed, 10 deletions(-) diff --git a/testfiles/HospitalBaselineReheatReportEMS.idf b/testfiles/HospitalBaselineReheatReportEMS.idf index 4b746536a51..1a89f8617cb 100644 --- a/testfiles/HospitalBaselineReheatReportEMS.idf +++ b/testfiles/HospitalBaselineReheatReportEMS.idf @@ -74063,11 +74063,6 @@ BeginNewEnvironment, !- EnergyPlus Model Calling Point AHU_Heat_Energy_Program; !- Program Name 1 - Output:EnergyManagementSystem, - Verbose, !- Actuator Availability Dictionary Reporting - Verbose, !- Internal Variable Availability Dictionary Reporting - Verbose; !- EMS Runtime Language Debug Output Level - !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:PROGRAM =========== EnergyManagementSystem:Program, diff --git a/testfiles/_ResidentialBase.idf b/testfiles/_ResidentialBase.idf index de3cbd0b946..db268bcc9c1 100644 --- a/testfiles/_ResidentialBase.idf +++ b/testfiles/_ResidentialBase.idf @@ -8143,11 +8143,6 @@ Yes, !- Output ExtShd Yes; !- Output Tarcog - Output:EnergyManagementSystem, - Verbose, !- Actuator Availability Dictionary Reporting - Verbose, !- Internal Variable Availability Dictionary Reporting - Verbose; !- EMS Runtime Language Debug Output Level - !- =========== ALL OBJECTS IN CLASS: OUTPUT:JSON =========== Output:JSON, From 0ed3853b7d16da36c20cc406d439d380ec3f272a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 12 Feb 2026 12:11:05 -0700 Subject: [PATCH 16/21] Add summary comments to EvaluateExpression around uninitialized error throw. --- src/EnergyPlus/RuntimeLanguageProcessor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 2d3e623b96a..1f9028331a7 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -1798,6 +1798,9 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, if (thisErlVar.Value.initialized) { // check that value has been initialized thisOperand = thisErlVar.Value; } else { // value has never been set + // during setup (before simulation), we want to avoid initializing variables to zero without throwing an error + // throw the error, and write it to edd file, if variable is uninitialized and is *not* a global or internal variable + // assumption is that if we made it here for a global variable, it is initialized in another program if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) { From e63954f049051ebe9d4509aa9970a106f8b23b40 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 12 Feb 2026 12:11:30 -0700 Subject: [PATCH 17/21] Formatting for new unit test. --- tst/EnergyPlus/unit/EMSManager.unit.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index 53c810e9e04..94a5c3627c6 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -997,7 +997,8 @@ TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef1) EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); - ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), EnergyPlus::FatalError); + ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), + EnergyPlus::FatalError); internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); ASSERT_GT(internalVarNum, 0); @@ -1016,7 +1017,8 @@ TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef1) " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", " ** ~~~ ** Erl program line number: 1", " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", - " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! *** ", + " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! " + "*** ", " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", " ** Fatal ** Previous EMS error caused program termination.", " ...Summary of Errors that led to program termination:", From 7ab44a1b18b34eeab35e9860c474d0df6c89d2d8 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 18 Feb 2026 09:50:55 -0700 Subject: [PATCH 18/21] For RetailPackagedTESCoil.idf, try moving only the Troof block above CalcBouyancyTerms. --- testfiles/RetailPackagedTESCoil.idf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testfiles/RetailPackagedTESCoil.idf b/testfiles/RetailPackagedTESCoil.idf index 57dc097d9d8..1ce8cde2539 100644 --- a/testfiles/RetailPackagedTESCoil.idf +++ b/testfiles/RetailPackagedTESCoil.idf @@ -8114,16 +8114,16 @@ Run SumIntakeMassFlowHeatCap, !- Run SumReliefAirMCTterm, !- Run CalcWindTerms, !- - Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- - Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- - Set Troof = Numerator / Denominator, !- IF Ta < 2.0, !- Set Troof = Ta, !- ENDIF, !- + Run CalcBouyancyTerms, !- + Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- + Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- + Set Troof = Numerator / Denominator, !- IF Troof < Twb, !- Set Twb = Troof - 0.2, !- - ENDIF, !- - Run CalcBouyancyTerms; !- + ENDIF; !- EnergyManagementSystem:Program, ApplyMicroClimeActuators,!- Name From 00da99c6496eae257ec6484016d1f055a0a4a514 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 18 Feb 2026 12:57:46 -0700 Subject: [PATCH 19/21] Revert program changes in RetailPackagedTESCoil.idf; instead just initialize Troof along with the other global vars. --- testfiles/RetailPackagedTESCoil.idf | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/testfiles/RetailPackagedTESCoil.idf b/testfiles/RetailPackagedTESCoil.idf index 1ce8cde2539..0478e103eda 100644 --- a/testfiles/RetailPackagedTESCoil.idf +++ b/testfiles/RetailPackagedTESCoil.idf @@ -7949,7 +7949,8 @@ SET SumReliefMCT = SumReliefMCT + (h_Relief_4 * mdotRelief_4 ); !- EnergyManagementSystem:Program, - IntializeParameters, !- Name + InitializeParameters, !- Name + Set Troof = 0.0, !- Set CV_Height = 1.0, !- Program Line 1 Set CV_effWidth = 40.0, !- Program Line 2 Set CV_crossSectArea = CV_Height * CV_effWidth, !- @@ -8101,7 +8102,7 @@ EnergyManagementSystem:ProgramCallingManager, Model Flat Roof Microclimate, !- Name BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point - IntializeParameters, !- Program Name 1 + InitializeParameters, !- Program Name 1 ModelFlatRoofMicroClime, !- Program Name 2 ApplyMicroClimeActuators;!- Program Name 3 @@ -8114,13 +8115,13 @@ Run SumIntakeMassFlowHeatCap, !- Run SumReliefAirMCTterm, !- Run CalcWindTerms, !- - IF Ta < 2.0, !- - Set Troof = Ta, !- - ENDIF, !- Run CalcBouyancyTerms, !- Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- Set Troof = Numerator / Denominator, !- + IF Ta < 2.0, !- + Set Troof = Ta, !- + ENDIF, !- IF Troof < Twb, !- Set Twb = Troof - 0.2, !- ENDIF; !- From d60fe2cf4e242496091b18ff4e1715d2ae58d748 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 20 Feb 2026 10:58:06 -0700 Subject: [PATCH 20/21] Elaborate EvaluateExpression explanation; add unrelated closing quotation marks for some error statements. --- src/EnergyPlus/RuntimeLanguageProcessor.cc | 53 +++++++++++----------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 1f9028331a7..db34d0c0259 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -1798,9 +1798,10 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, if (thisErlVar.Value.initialized) { // check that value has been initialized thisOperand = thisErlVar.Value; } else { // value has never been set - // during setup (before simulation), we want to avoid initializing variables to zero without throwing an error - // throw the error, and write it to edd file, if variable is uninitialized and is *not* a global or internal variable - // assumption is that if we made it here for a global variable, it is initialized in another program + // During setup (before simulation), we want to avoid initializing variables to zero without throwing an error. + // Throw the error, and write it to edd file, if variable is uninitialized and is *not* a global or internal variable. + // The assumption is that if we made it here for a global variable, it is initialized in another program. + // E.g., if it's initialized in a program with BeginNewEnvironment calling point, setup won't set it but simulation will. if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || (!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) { @@ -3013,7 +3014,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (!errFlag) { VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0); if (VariableNum > 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1))); ShowContinueError(state, "Name conflicts with an existing variable name"); ErrorsFound = true; @@ -3028,11 +3029,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) int CurveIndexNum = GetCurveIndex(state, cAlphaArgs(2)); // curve name if (CurveIndexNum == 0) { if (lAlphaFieldBlanks(2)) { - ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2))); ShowContinueError(state, "Blank entry for curve or table name is not allowed"); } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Curve or table was not found."); } @@ -3073,7 +3074,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (!errFlag) { VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0); if (VariableNum > 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1))); ShowContinueError(state, "Name conflicts with an existing variable name"); ErrorsFound = true; @@ -3091,11 +3092,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) if (ConstructNum == 0) { if (lAlphaFieldBlanks(2)) { - ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2))); ShowContinueError(state, "Blank entry for construction name is not allowed"); } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Construction was not found."); } @@ -3210,7 +3211,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) VariableNum = FindEMSVariable(state, cAlphaArgs(2), 0); // Still need to check for conflicts with program and function names too if (VariableNum == 0) { // did not find it - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Did not find a match with an EMS variable name"); ErrorsFound = true; @@ -3244,7 +3245,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop - 1) - state.dataGlobal->TimeStepZone; // fractional hours } } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={:.2T}", cNumericFieldNames(1), rNumericArgs(1))); ShowContinueError(state, "must be greater than zero"); ErrorsFound = true; @@ -3341,7 +3342,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!UnitsA.empty() && !UnitsB.empty()) { if (UnitsA != UnitsB) { - ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA)); ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(6), UnitsB)); } @@ -3367,7 +3368,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!Found) { StackNum = 0; - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5))); ShowContinueError(state, "EMS program or subroutine not found."); ErrorsFound = true; @@ -3380,11 +3381,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) if (VariableNum == 0) { if (lAlphaFieldBlanks(5)) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "EMS variable not found among global variables."); } else if (StackNum != 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5))); } @@ -3403,7 +3404,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(3) == "SUMMED") { sovStoreType = OutputProcessor::StoreType::Sum; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(3), cAlphaArgs(3))); ShowContinueError(state, "...valid values are Averaged or Summed."); ErrorsFound = true; @@ -3414,7 +3415,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(4) == "SYSTEMTIMESTEP") { sovTimeStepType = OutputProcessor::TimeStepType::System; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep."); ErrorsFound = true; @@ -3514,7 +3515,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!UnitsA.empty() && !UnitsB.empty()) { if (UnitsA != UnitsB) { - ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA)); ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(9), UnitsB)); } @@ -3540,7 +3541,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!Found) { StackNum = 0; - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "EMS program or subroutine not found."); ErrorsFound = true; @@ -3552,11 +3553,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum); if (VariableNum == 0) { if (lAlphaFieldBlanks(4)) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "EMS variable not found among global variables."); } else if (StackNum != 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5))); } @@ -3577,7 +3578,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(3) == "SYSTEMTIMESTEP") { sovTimeStepType = OutputProcessor::TimeStepType::System; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep."); ErrorsFound = true; @@ -3588,7 +3589,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) static_cast(getEnumValue(Constant::eResourceNamesUC, Util::makeUPPER(cAlphaArgs(5)))); if (resource == Constant::eResource::Invalid) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5))); ErrorsFound = true; } @@ -3605,7 +3606,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(6) == "SYSTEM") { sovGroup = OutputProcessor::Group::HVAC; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(6), cAlphaArgs(6))); ErrorsFound = true; } @@ -3656,7 +3657,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(7) == "HEATRECOVERYFORHEATING") { sovEndUseCat = OutputProcessor::EndUseCat::HeatRecoveryForHeating; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(7), cAlphaArgs(7))); ErrorsFound = true; } @@ -3667,7 +3668,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) sovEndUseCat == OutputProcessor::EndUseCat::Chillers || sovEndUseCat == OutputProcessor::EndUseCat::Boilers || sovEndUseCat == OutputProcessor::EndUseCat::Baseboard || sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForCooling || sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForHeating)) { - ShowWarningError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={} for {}={}", cAlphaFieldNames(5), cAlphaArgs(5), cAlphaFieldNames(7), cAlphaArgs(7))); ShowContinueError(state, format("Field {} is reset from {} to EnergyTransfer", cAlphaFieldNames(5), cAlphaArgs(5))); From 58cddd570ed7b20bca0e3e382bbc31fdb2becb11 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 20 Feb 2026 10:59:50 -0700 Subject: [PATCH 21/21] Revert sample file calling point changes; instead, make offending operands global to avoid regressions. --- testfiles/HospitalBaselineReheatReportEMS.idf | 43 +++++++++++++++++-- testfiles/RetailPackagedTESCoil.idf | 7 +-- testfiles/_ResidentialBase.idf | 7 ++- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/testfiles/HospitalBaselineReheatReportEMS.idf b/testfiles/HospitalBaselineReheatReportEMS.idf index 1a89f8617cb..e30e1ff97f4 100644 --- a/testfiles/HospitalBaselineReheatReportEMS.idf +++ b/testfiles/HospitalBaselineReheatReportEMS.idf @@ -74050,17 +74050,17 @@ EnergyManagementSystem:ProgramCallingManager, Reheat_Sum_Call, !- Name - BeginNewEnvironment, !- EnergyPlus Model Calling Point + EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point Reheat_Sum_Program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, Heat_Sum_Call, !- Name - BeginNewEnvironment, !- EnergyPlus Model Calling Point + EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point Heat_Sum_Program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, AHU_Heat_Sum_Call, !- Name - BeginNewEnvironment, !- EnergyPlus Model Calling Point + EndofZoneTimestepAfterZoneReporting, !- EnergyPlus Model Calling Point AHU_Heat_Energy_Program; !- Program Name 1 !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:PROGRAM =========== @@ -77655,6 +77655,43 @@ Flr_1_Stor_DT2, !- Flr_1_Waiting_DT2; !- + EnergyManagementSystem:GlobalVariable, + A, !- Erl Variable 1 Name + B, !- Erl Variable 2 Name + C, !- Erl Variable 3 Name + D, !- + E, !- + F, !- + G, !- + H, !- + I, !- + J, !- + K, !- + L, !- + M, !- + N, !- + O, !- + P, !- + Q, !- + R, !- + S, !- + T, !- + U, !- + V, !- + W, !- + X, !- + Y, !- + Z, !- + AA, !- + BB, !- + CC, !- + DD, !- + EE, !- + FF, !- + GG, !- + HH, !- + II; !- + !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:OUTPUTVARIABLE =========== EnergyManagementSystem:OutputVariable, diff --git a/testfiles/RetailPackagedTESCoil.idf b/testfiles/RetailPackagedTESCoil.idf index 0478e103eda..d4bb2ebb435 100644 --- a/testfiles/RetailPackagedTESCoil.idf +++ b/testfiles/RetailPackagedTESCoil.idf @@ -7950,7 +7950,6 @@ EnergyManagementSystem:Program, InitializeParameters, !- Name - Set Troof = 0.0, !- Set CV_Height = 1.0, !- Program Line 1 Set CV_effWidth = 40.0, !- Program Line 2 Set CV_crossSectArea = CV_Height * CV_effWidth, !- @@ -8067,8 +8066,10 @@ EnergyManagementSystem:GlobalVariable, Troof, !- Erl Variable 1 Name - CV_Height, !- Erl Variable 2 Name - CV_crossSectArea, !- Erl Variable 3 Name + DeltaT, !- Erl Variable 2 Name + ratioT, !- Erl Variable 3 Name + CV_Height, !- + CV_crossSectArea, !- C_v, !- rhoAir, !- CpAir, !- diff --git a/testfiles/_ResidentialBase.idf b/testfiles/_ResidentialBase.idf index db268bcc9c1..701e3cbcac0 100644 --- a/testfiles/_ResidentialBase.idf +++ b/testfiles/_ResidentialBase.idf @@ -7296,7 +7296,7 @@ EnergyManagementSystem:ProgramCallingManager, central_ac_and_furnace_airloop_0_duct_program calling manager, !- Name - BeginZoneTimestepBeforeInitHeatBalance, !- EnergyPlus Model Calling Point + EndOfSystemTimestepAfterHVACReporting, !- EnergyPlus Model Calling Point central_ac_and_furnace_airloop_0_duct_program; !- Program Name 1 EnergyManagementSystem:ProgramCallingManager, @@ -7785,6 +7785,11 @@ EnergyManagementSystem:GlobalVariable, natural_vent_program_Qwhf; !- Erl Variable 1 Name + EnergyManagementSystem:GlobalVariable, + Qducts, !- Erl Variable 1 Name + Qsupply, !- Erl Variable 2 Name + Qexhaust; !- Erl Variable 3 Name + !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:OUTPUTVARIABLE =========== EnergyManagementSystem:OutputVariable,