From 8623d71fc1bf171caee291b7727416fff670bcdf Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 29 Jan 2026 16:00:39 -0700 Subject: [PATCH 01/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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,