Skip to content

Catch EMS variables initialized after reference#11409

Merged
mitchute merged 26 commits intodevelopfrom
fix-ems-var-init-after-ref
Feb 24, 2026
Merged

Catch EMS variables initialized after reference#11409
mitchute merged 26 commits intodevelopfrom
fix-ems-var-init-after-ref

Conversation

@joseph-robertson
Copy link
Collaborator

Pull request overview

Description of the purpose of this PR

Pull Request Author

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies
  • If adding/removing any output files (e.g., eplustbl.*)
    • Update ..\scripts\Epl-run.bat
    • Update ..\scripts\RunEPlus.bat
    • Update ..\src\EPLaunch\ MainModule.bas, epl-ui.frm, and epl.vbp (VersionComments)
    • Update ...github\workflows\energyplus.py

Reviewer

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@joseph-robertson joseph-robertson self-assigned this Jan 29, 2026
@mitchute mitchute added the Defect Includes code to repair a defect in EnergyPlus label Jan 30, 2026
@mitchute
Copy link
Collaborator

As I understand it, Windows builds don't pick up uninitialized variables, which we treat as errors.

/home/mitchute/Projects/EnergyPlus/tst/EnergyPlus/unit/EMSManager.unit.cc:1065:9: error: unused variable ‘wallSurfNum’ [-Werror=unused-variable]
 1065 |     int wallSurfNum = Util::FindItemInList("WALL", state->dataSurface->Surface);
      |         ^~~~~~~~~~~

@rraustad
Copy link
Collaborator

rraustad commented Jan 30, 2026

I am using Windows 11 and do not get the unused variable warning for wallSurfNum, well, because it is initialized at line 1065 and used at 1068. If there is an issue with EMS initializing a variable before it's used (e.g., site_temp_adj) then this unit test should fail. But it doesn't, it passes with. wallSurfNum = 1, ViewFactorGround = 0.1 and seriousErrorFound = false (i.e., EXPECT_TRUE on line 1076 should be EXPECT_FASLE and line 1068 is correct). So what should happen here? I assume this unit test should check for whether site_temp_adj was initialized before it was used, but I don't see that in this unit test.

image

@joseph-robertson
Copy link
Collaborator Author

joseph-robertson commented Jan 30, 2026

This PR is about the EMS variable site_temp_adj, not wallSurfNum. The intent (i.e., 8623d71) was to commit a failing test, to demonstrate that the uninitialized site_temp_adj should throw an error but does not. The test fails on my machine.

Comment on lines 1047 to 1048
" Set power_mult = site_temp_adj, !- Program Line 1",
" Set site_temp_adj = 0.1, !- Program Line 2",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable site_temp_adj is being initialized after it is referenced. We should expect an error, right?

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);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally had this line commented out so that we could get to EXPECT_TRUE(seriousErrorFound); down below.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, feel free to do what you need. I won't interfere anymore until you need someone to look. I was just pointing out that the CI linux builds were failing due to to the unused variable, that we treat as an error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, understood.

@joseph-robertson
Copy link
Collaborator Author

Pretty sure I have this narrowed down. I think GetEMSInput can set state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true without calling EvaluateExpression first.


internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1);
ASSERT_GT(internalVarNum, 0);
EXPECT_TRUE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main difference with the first test; why is this suddenly initialized?

@joseph-robertson
Copy link
Collaborator Author

Pretty sure I have this narrowed down. I think GetEMSInput can set state.dataRuntimeLang->ErlVariable(VariableNum).Value.initialized = true without calling EvaluateExpression first.

It's not in GetEMSInput. It happens somewhere toward the beginning of ManageSimulation (likely in SetupSimulation whose purpose is to "... execute a few time steps of a simulation to facilitate setting up model ..."). I can confirm this by looking at RuntimeLanguageProcessor::FindEMSVariable(state, "site_temp_adj", StackNum); just after SetupSimulation, which shows the EMS variable is indeed initialized (yet EvaluateStack was never called for on the EMS program). Then it looks like the EMSManager::EMSCallFrom::SetupSimulation just below sets the variable back to 0.0.

I'm not totally sure what the fix is here. Perhaps EvaluateStack is being called via SetupSimulation, but with FinishProcessingUserInput=true?

Comment on lines 8146 to 8149
Output:EnergyManagementSystem,
Verbose, !- Actuator Availability Dictionary Reporting
Verbose, !- Internal Variable Availability Dictionary Reporting
Verbose; !- EMS Runtime Language Debug Output Level
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file has a program (BeginZoneTimestepAfterInitHeatBalance) that uses variables which are initialized in another program/subroutine (EndOfSystemTimestepAfterHVACReporting). I.e., initialized after reference.

Comment on lines 8117 to 8126
Run CalcBouyancyTerms, !- <none>
SEt Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- <none>
Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- <none>
Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- <none>
Set Troof = Numerator / Denominator, !- <none>
IF Ta < 2.0, !- <none>
Set Troof = Ta, !- <none>
ENDIF, !- <none>
IF Troof < Twb, !- <none>
Set Twb = Troof - 0.2, !- <none>
ENDIF; !- <none>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something weird going on in this program. Here Troof is a function of, e.g., NatBouyMCT. Subroutine CalcBouyancyTerms needs Troof, which is used to calculate NatBouyMCT... am I missing something here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mitchute Any ideas here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. CalcBouyancyTerms should probably be moved above Numerator

Comment on lines +1804 to +1805
if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) ||
(!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) {
Copy link
Collaborator Author

@joseph-robertson joseph-robertson Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The basic idea here is to do what we were doing before, unless the uninitialized variable is either a global/internal variable. If it isn't global/internal, set seriousErrorFound = true. If it is, let it slide.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a reasonable approach.

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit f4e0687

Regression Summary
  • EDD: 2
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit f4e0687

Regression Summary
  • EDD: 2
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit d1a8173

Regression Summary
  • EDD: 7
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 2
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit d1a8173

Regression Summary
  • EDD: 7
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table Small Diffs: 1
  • Table String Diffs: 1

@joseph-robertson joseph-robertson marked this pull request as ready for review February 16, 2026 18:22
EnergyManagementSystem:ProgramCallingManager,
central_ac_and_furnace_airloop_0_duct_program calling manager, !- Name
EndOfSystemTimestepAfterHVACReporting, !- EnergyPlus Model Calling Point
BeginZoneTimestepBeforeInitHeatBalance, !- EnergyPlus Model Calling Point
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this IDF file change, and with the fix in this PR, you'd see ATTIC_UNVENTED_1_DUCT_LEAKAGE_IMBALANCE_INFIL_PROGRAM,Line 3,SET QDUCTS = QDUCTS + CENTRAL_AC_AND_FURNACE_AIRLOOP_0_DUCTIMBALLKEXHFANEQUIVDZ, *** Error: EvaluateExpression: Variable = 'QDUCTS' used in expression has not been initialized! *** , During Warmup, Occurrence info=DENVER CENTENNIAL GOLDEN N ANN HTG 99% CONDNS DB, 12/21 00:00 - 01:00 in the EDD file and the simulation fatals.

  EnergyManagementSystem:Program,
    attic_unvented_1_duct_leakage_imbalance_infil_program,  !- Name
    Set Qducts = 0,          !- Program Line 1
    Set Qducts = Qducts - central_ac_and_furnace_airloop_0_DuctImbalLkSupFanEquivDZ,  !- Program Line 2
    Set Qducts = Qducts + central_ac_and_furnace_airloop_0_DuctImbalLkExhFanEquivDZ,  !- <none>
    Set attic_unvented_1_duct_leakage_imbalance_infil_flow_act = (@Abs(Qducts));  !- <none>

Qducts is initialized on line 1. On line 2 the throw is skipped; central_ac_and_furnace_airloop_0_DuctImbalLkSupFanEquivDZ is uninitialized but doesn't fatal since central_ac_and_furnace_airloop_0_DuctImbalLkSupFanEquivDZ is a global variable. Then on line 3 Qducts is uninitialized (because of the preceding program line), and fatals since Qducts is not a global variable.

So basically the change in the above PCM from EndOfSystemTimestepAfterHVACReporting to BeginZoneTimestepBeforeInitHeatBalance causes both central_ac_and_furnace_airloop_0_DuctImbalLkSupFanEquivDZ and central_ac_and_furnace_airloop_0_DuctImbalLkExhFanEquivDZ to initialize so that program line 2 and 3 above don't leave Qducts uninitialized.

Copy link
Collaborator

@mitchute mitchute left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I'll let you decide on what to do regarding this: https://github.com/NatLabRockies/EnergyPlus/pull/11409/changes#r2790815597

@joseph-robertson
Copy link
Collaborator Author

joseph-robertson commented Feb 18, 2026

Looks good. I'll let you decide on what to do regarding this: https://github.com/NatLabRockies/EnergyPlus/pull/11409/changes#r2790815597

With this change, we can have CalcBouyancyTerms above Numerator. In either case the MODELFLATROOFMICROCLIME,Line 9,SET TROOF = NUMERATOR / DENOMINATOR, *** Error: EvaluateExpression: Divide By Zero in EMS Program! *** goes away, but this change seems more minimal.

Edit: Actually this change leads to the following in the ERR file:

+   ** Warning ** Calculated Humidity Ratio Invalid (PsyWFnTdbTwbPb)
+   **   ~~~   **  Routine=Unknown, Environment=CHICAGO ANN HTG 99.6% CONDNS DB, at Simulation time=01/21 06:10 - 06:20
+   **   ~~~   **  Dry-Bulb= -18.61 Wet-Bulb= -20.62 Pressure= 99063.00
+   **   ~~~   ** Calculated Humidity Ratio= -1.8069E-004, will recalculate Humidity Ratio using Relative Humidity .01% (and Dry-Bulb and Pressure as shown)

I'll just revert to the original program, and initialize Troof = 0.0. 00da99c

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 79da40f

Regression Summary
  • EDD: 7
  • EIO: 1
  • ERR: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 2
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 79da40f

Regression Summary
  • EDD: 7
  • EIO: 1
  • ERR: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 2
  • Table Small Diffs: 1

…tialize Troof along with the other global vars.
@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit ed75617

Regression Summary
  • EDD: 7
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 2
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit ed75617

Regression Summary
  • EDD: 7
  • EIO: 1
  • ESO Big Diffs: 1
  • MTR Big Diffs: 1
  • Table Big Diffs: 1
  • Table String Diffs: 2
  • Table Small Diffs: 1

EnergyManagementSystem:ProgramCallingManager,
central_ac_and_furnace_airloop_0_duct_program calling manager, !- Name
EndOfSystemTimestepAfterHVACReporting, !- EnergyPlus Model Calling Point
BeginZoneTimestepBeforeInitHeatBalance, !- EnergyPlus Model Calling Point
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the changes could instead be:

  • central_ac_and_furnace_airloop_0_duct_program calling manager: EndOfSystemTimestepAfterHVACReporting -> EndOfSystemTimestepBeforeHVACReporting
  • attic_unvented_1_duct_leakage_imbalance_infil_program calling manager: BeginZoneTimestepAfterInitHeatBalance -> EndOfSystemTimestepAfterHVACReporting
  • infil_program calling manager: BeginZoneTimestepAfterInitHeatBalance -> EndOfSystemTimestepAfterHVACReporting

@shorowit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some local testing/diffing, it appears this approach causes a slightly larger regression than EndOfSystemTimestepAfterHVACReporting -> BeginZoneTimestepBeforeInitHeatBalance for central_ac_and_furnace_airloop_0_duct_program calling manager.

So I suppose the question is whether we want to avoid regression or whether we think there's actually an issue in how the programs are set up.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can handle regressions if they are justified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I've been out of the office. I will take a look at this soon.

Comment on lines +7788 to +7791
EnergyManagementSystem:GlobalVariable,
Qducts, !- Erl Variable 1 Name
Qsupply, !- Erl Variable 2 Name
Qexhaust; !- Erl Variable 3 Name
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can avoid EvaluateExpression errors during setup.

Comment on lines +77658 to +77693
EnergyManagementSystem:GlobalVariable,
A, !- Erl Variable 1 Name
B, !- Erl Variable 2 Name
C, !- Erl Variable 3 Name
D, !- <none>
E, !- <none>
F, !- <none>
G, !- <none>
H, !- <none>
I, !- <none>
J, !- <none>
K, !- <none>
L, !- <none>
M, !- <none>
N, !- <none>
O, !- <none>
P, !- <none>
Q, !- <none>
R, !- <none>
S, !- <none>
T, !- <none>
U, !- <none>
V, !- <none>
W, !- <none>
X, !- <none>
Y, !- <none>
Z, !- <none>
AA, !- <none>
BB, !- <none>
CC, !- <none>
DD, !- <none>
EE, !- <none>
FF, !- <none>
GG, !- <none>
HH, !- <none>
II; !- <none>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can avoid EvaluateExpression errors during setup.

Comment on lines +8069 to +8070
DeltaT, !- Erl Variable 2 Name
ratioT, !- Erl Variable 3 Name
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can avoid EvaluateExpression errors during setup.

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 98089b8

Regression Summary
  • EDD: 7

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 28bae0c

Regression Summary
  • EDD: 7

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 28bae0c

Regression Summary
  • EDD: 7

@mitchute
Copy link
Collaborator

This looks like a good set of cleanups. We'll merge this next, assuming tests all are consistent with previous results.

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 8b146cb

Regression Summary
  • EDD: 7

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 8b146cb

Regression Summary
  • EDD: 7

@mitchute
Copy link
Collaborator

All good here. Merging.

@mitchute mitchute merged commit 82a12e2 into develop Feb 24, 2026
13 of 14 checks passed
@mitchute mitchute deleted the fix-ems-var-init-after-ref branch February 24, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Defect Includes code to repair a defect in EnergyPlus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unitialized EMS variable is misused

5 participants