Skip to content

Conversation

@jmarrec
Copy link
Contributor

@jmarrec jmarrec commented Jun 24, 2025

Pull request overview

Description of the purpose of this PR

  • For now, I just registered one extra tests for each integration/performance test (it depends on it)
    • Will run a python script to check for uniqueness of FullName tables in html

Current failures

The following tests FAILED:
	 63 - integration.1ZoneUncontrolled_DD2009.EnsureUniqueTableNames (Failed)
	 65 - integration.1ZoneUncontrolled_DDChanges.EnsureUniqueTableNames (Failed)
	529 - integration.EMPD5ZoneWaterCooled_HighRHControl.EnsureUniqueTableNames (Failed)
	1423 - integration._5ZoneEvapCooled.EnsureUniqueTableNames (Failed)
	1459 - integration._FuelCellTest200.EnsureUniqueTableNames (Failed)
	1618 - integration.SingleFamilyHouse_HP_Slab.EnsureUniqueTableNames (Failed)
	1620 - integration.SingleFamilyHouse_HP_Slab_Dehumidification.EnsureUniqueTableNames (Failed)
	1622 - integration.US+SF+CZ4A+hp+crawlspace+IECC_2006_VRF.EnsureUniqueTableNames (Failed)
1/8 Test   #63: integration.1ZoneUncontrolled_DD2009.EnsureUniqueTableNames .....................***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle    | count |
|------------------------|-----------------|-------------|-------|
| Initialization Summary | Entire Facility | DaySchedule | 2     |

    Start   65: integration.1ZoneUncontrolled_DDChanges.EnsureUniqueTableNames
2/8 Test   #65: integration.1ZoneUncontrolled_DDChanges.EnsureUniqueTableNames ..................***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle    | count |
|------------------------|-----------------|-------------|-------|
| Initialization Summary | Entire Facility | DaySchedule | 2     |

    Start  529: integration.EMPD5ZoneWaterCooled_HighRHControl.EnsureUniqueTableNames
3/8 Test  #529: integration.EMPD5ZoneWaterCooled_HighRHControl.EnsureUniqueTableNames ...........***Failed    0.06 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle     | count |
|------------------------|-----------------|--------------|-------|
| Initialization Summary | Entire Facility | Material:Air | 2     |

    Start 1423: integration._5ZoneEvapCooled.EnsureUniqueTableNames
4/8 Test #1423: integration._5ZoneEvapCooled.EnsureUniqueTableNames .............................***Failed    0.06 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle                       | count |
|------------------------|-----------------|--------------------------------|-------|
| Initialization Summary | Entire Facility | Warmup Convergence Information | 2     |

    Start 1459: integration._FuelCellTest200.EnsureUniqueTableNames
5/8 Test #1459: integration._FuelCellTest200.EnsureUniqueTableNames .............................***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle    | count |
|------------------------|-----------------|-------------|-------|
| Initialization Summary | Entire Facility | Fuel Supply | 2     |

    Start 1618: integration.SingleFamilyHouse_HP_Slab.EnsureUniqueTableNames
6/8 Test #1618: integration.SingleFamilyHouse_HP_Slab.EnsureUniqueTableNames ....................***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle     | count |
|------------------------|-----------------|--------------|-------|
| Initialization Summary | Entire Facility | Material:Air | 2     |

    Start 1620: integration.SingleFamilyHouse_HP_Slab_Dehumidification.EnsureUniqueTableNames
7/8 Test #1620: integration.SingleFamilyHouse_HP_Slab_Dehumidification.EnsureUniqueTableNames ...***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle     | count |
|------------------------|-----------------|--------------|-------|
| Initialization Summary | Entire Facility | Material:Air | 2     |

    Start 1622: integration.US+SF+CZ4A+hp+crawlspace+IECC_2006_VRF.EnsureUniqueTableNames
8/8 Test #1622: integration.US+SF+CZ4A+hp+crawlspace+IECC_2006_VRF.EnsureUniqueTableNames .......***Failed    0.05 sec
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle     | count |
|------------------------|-----------------|--------------|-------|
| Initialization Summary | Entire Facility | Material:Air | 2     |

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

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

@jmarrec jmarrec self-assigned this Jun 24, 2025
@jmarrec jmarrec added the Defect Includes code to repair a defect in EnergyPlus label Jun 24, 2025
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 69111bc

Regression Summary
  • EIO: 3
  • Table Big Diffs: 3

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 236933f

Regression Summary
  • EIO: 3
  • Table Big Diffs: 3

@jmarrec jmarrec marked this pull request as ready for review June 24, 2025 15:06
@jmarrec jmarrec requested a review from Myoldmopar June 24, 2025 15:06
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 81dacd9

Regression Summary
  • EIO: 305
  • Table Big Diffs: 61

Comment on lines +240 to +255
set(HTML_PATH "${OUTPUT_DIR_PATH}/eplustbl.htm")
if(EXISTS "${HTML_PATH}")
message("Checking uniqueness of HTML Table FullNames:")
message(STATUS "${Python_EXECUTABLE} ${SOURCE_DIR}/scripts/dev/ensure_unique_html_tables.py ${OUTPUT_DIR_PATH}")
execute_process(
COMMAND ${Python_EXECUTABLE} "${SOURCE_DIR}/scripts/dev/ensure_unique_html_tables.py" "${OUTPUT_DIR_PATH}"
RESULT_VARIABLE RESULT
ECHO_OUTPUT_VARIABLE
ECHO_ERROR_VARIABLE
)

if(NOT RESULT EQUAL 0)
message("Test Failed: HTML output tables are NOT unique")
return()
endif()
endif()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had initially defined a test named "${TEST_CATEGORY}.${IDF_NAME}.EnsureUniqueTableNames" which depended on each.

Pros:

  • Adds a clear output message about the failure
  • Cons: doubles the number of test. And you can rerun via ctest -R EnsureUniqueTableNames and will NOT rerun the integration tests it depends on

So I decided to move this inside RunSimulation.cmake.

cf f0f99f5

Copy link
Member

Choose a reason for hiding this comment

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

I will admit, I was taken aback when I saw a new parameter defined for RunSimulation, but after a couple seconds, I realized what you must be doing. Good stuff here.

Comment on lines +107 to +125
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Compare Output Reports.")
parser.add_argument("out_dir", type=Path, help="Output directory where to find the reports")
parser.add_argument(
"--skip-missing", action="store_true", default=False, help="Do not raise if the eplustbl.htm isn't found"
)
args = parser.parse_args()

out_dir = args.out_dir.resolve()
if not (out_dir.exists() and out_dir.is_dir()):
raise IOError(f"'{out_dir}' is not a valid directory")
html_path = out_dir / "eplustbl.htm"
if not html_path.exists():
if args.skip_missing:
print(f"Skipping missing HTML file: {html_path}")
exit(0)
raise IOError(f"HTML '{html_path}' does not exist")

ensure_unique_html_tables(html_path=html_path)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New script.

Comment on lines +63 to +104
RE_FULLNAME = re.compile(r"<!-- FullName:(?P<activeReportName>[^_]+)_(?P<activeForName>[^_]+)_(?P<subtitle>[^_]+)-->")


def format_row(row, col_widths):
return "| " + " | ".join(f"{str(cell):<{col_widths[i]}}" for i, cell in enumerate(row)) + " |"


def ensure_unique_html_tables(html_path: Path):
"""
Ensure that each HTML table in the report has a unique name.
If duplicates are found, append a number to the duplicate names.
"""
content = html_path.read_text()

matches = RE_FULLNAME.findall(content)
if not matches:
raise ValueError("No HTML tables found with FullName pattern")

# Filter only duplicates (count > 1)
duplicates = [
(activeReportName, activeForName, subtitle, count)
for (activeReportName, activeForName, subtitle), count in Counter(matches).items()
if count > 1
]

# Include header row in width calculation
if duplicates:
print(f"Found {len(duplicates)} duplicate HTML table(s) based on FullName\n")
header = [("activeReportName", "activeForName", "subtitle", "count")]
rows = header + duplicates
# Compute max width for each column
col_widths = [max(len(str(row[i])) for row in rows) for i in range(len(header[0]))]

print(format_row(rows[0], col_widths))
print("|-" + "-|-".join("-" * w for w in col_widths) + "-|")
for row in duplicates:
print(format_row(row, col_widths))

exit(1)
else:
print("No duplicates found.")
exit(0)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pretty simple: parse the FUllName stuff into 3-tuples. Counter to find duplicates, format as markdown table, then exit 1.

$ python EnergyPlus/scripts/dev/ensure_unique_html_tables.py EnergyPlus-build-release/testfiles/SingleFamilyHouse_HP_Slab_Dehumidification/
Found 1 duplicate HTML table(s) based on FullName

| activeReportName       | activeForName   | subtitle     | count |
|------------------------|-----------------|--------------|-------|
| Initialization Summary | Entire Facility | Material:Air | 2     |
(py312)(3.2.2)julien@EnergyPlus-build-release$ echo $?
1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When running via ctest

741: Test command: /usr/bin/cmake "-DSOURCE_DIR=/home/julien/Software/Others/EnergyPlus" "-DBINARY_DIR=/home/julien/Software/Others/EnergyPlus-build-release" "-DENERGYPLUS_EXE=/home/julien/Software/Others/EnergyPlus-build-release/Products/energyplus-25.2.0" "-DIDF_FILE=_FuelCellTest200.idf" "-DEPW_FILE=USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw" "-DENERGYPLUS_FLAGS= -D -r" "-DBUILD_FORTRAN=ON" "-DTEST_FILE_FOLDER=testfiles" "-DRUN_CALLGRIND:BOOL=FALSE" "-DVALGRIND=" "-DRUN_PERF_STAT:BOOL=FALSE" "-DPERF=" "-DPython_EXECUTABLE=/home/julien/.pyenv/versions/3.12.2/bin/python3.12" "-P" "/home/julien/Software/Others/EnergyPlus/cmake/RunSimulation.cmake"
741: Working Directory: /home/julien/Software/Others/EnergyPlus-build-release/testfiles
741: Test timeout computed to be: 9999879
741: Running Simulation:
741: -- /home/julien/Software/Others/EnergyPlus-build-release/Products/energyplus-25.2.0 -w /home/julien/Software/Others/EnergyPlus/weather/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw -d /home/julien/Software/Others/EnergyPlus-build-release/testfiles/_FuelCellTest200/ -D -r /home/julien/Software/Others/EnergyPlus/testfiles/_FuelCellTest200.idf
741: EnergyPlus Starting
[....]
741: EnergyPlus Completed Successfully.
741: Checking uniqueness of HTML Table FullNames:
741: -- /home/julien/.pyenv/versions/3.12.2/bin/python3.12 /home/julien/Software/Others/EnergyPlus/scripts/dev/ensure_unique_html_tables.py /home/julien/Software/Others/EnergyPlus-build-release/testfiles/_FuelCellTest200/
741: Found 1 duplicate HTML table(s) based on FullName
741: 
741: | activeReportName       | activeForName   | subtitle    | count |
741: |------------------------|-----------------|-------------|-------|
741: | Initialization Summary | Entire Facility | Fuel Supply | 2     |
741: Test Failed: HTML output tables are NOT unique
1/1 Test #741: integration._FuelCellTest200 .....***Failed  Error regular expression found in output. Regex=[Test Failed]  0.65 sec

0% tests passed, 1 tests failed out of 1

Comment on lines 25 to 94
### EIO and HTML Table Output: Initialization Summary

A number of changes related to finding duplicated HTML tables (based on FullName) have been made.

See Pull Request [#11106](https://github.com/NREL/EnergyPlus/pull/11106).

#### Schedules

The `Output:Schedules` object controls whether the schedules are reported to the EIO, which would end up in the Initialization Summary report of the HTML if the `Output:Table:SummaryReports` asks for it.
The `Output:Schedules` object has a `Key Field` which can be either `Timestep` or `Hourly`, and it is **not** a unique object, meaning you can request **both**.

A few issues where occurring with the former EIO report (which is parsed to produce the HTML tables):

* The headers where not specific to a given `Key Field` (= Report Level), so if you requested both they would show in both reports in the HTML table
* The headers were NOT aligned with the data rows, so some tables were not present in the HTML (WeekSchedule, ScheduleTypeLimots=
* The `ScheduleTypeLimits` were issued in both `Timestep` and `Hourly` reports in the EIO

```diff
! <Output Reporting Tolerances>, Tolerance for Time Heating Setpoint Not Met, Tolerance for Zone Cooling Setpoint Not Met Time
Output Reporting Tolerances, 0.200, 0.200,
+! <ScheduleTypeLimits>,Name,Limited? {Yes/No},Minimum,Maximum,Continuous? {Yes/No - Discrete}
+ScheduleTypeLimits,FRACTION,Yes,0.00,1.00,Yes
+ScheduleTypeLimits,ANY NUMBER,No,N/A,N/A,N/A
! Schedule Details Report=Timestep =====================
-! <ScheduleType>,Name,Limited? {Yes/No},Minimum,Maximum,Continuous? {Yes/No - Discrete}
-! <DaySchedule>,Name,ScheduleType,Interpolated {Yes/No},Time (HH:MM) =>,00:15,00:30,[...],23:30,23:45,24:00
+! <DaySchedule - Timestep>,Name,ScheduleType,Interpolated {Average/Linear/No},Time (HH:MM) =>,00:15,00:30,[...],23:30,23:45,24:00
-! <WeekSchedule>,Name,Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Holiday,SummerDesignDay,WinterDesignDay,CustomDay1,CustomDay2
+! <WeekSchedule - Timestep>,Name,Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Holiday,SummerDesignDay,WinterDesignDay,CustomDay1,CustomDay2
-! <Schedule>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31
+! <Schedule - Timestep>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31
-ScheduleTypeLimits,FRACTION,Average,0.00,1.00,Yes
-ScheduleTypeLimits,ANY NUMBER,No,N/A,N/A,N/A
-DaySchedule,TDEFAULTPROFILE,FRACTION,No,Values:,0.88,0.88,[...],0.82,0.82
+DaySchedule - Timestep,TDEFAULTPROFILE,FRACTION,No,Values:,0.88,0.88,[...],0.82,0.82
-Schedule:Week:Daily,CT WEEKSCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE
+WeekSchedule - Timestep,CT WEEKSCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE
-Schedule,ZONE CONTROL TYPE SCHEDULE,CONTROLTYPE,Through Dec 31,CT WEEKSCHEDULE
+Schedule - Timestep,ZONE CONTROL TYPE SCHEDULE,CONTROLTYPE,Through Dec 31,CT WEEKSCHEDULE
! Schedule Details Report=Hourly =====================
-! <ScheduleType>,Name,Limited? {Yes/No},Minimum,Maximum,Continuous? {Yes/No - Discrete}
-! <DaySchedule>,Name,ScheduleType,Interpolated {Yes/No},Time (HH:MM) =>,01:00,02:00,[...],23:00,24:00
+! <DaySchedule - Hourly>,Name,ScheduleType,Interpolated {Average/Linear/No},Time (HH:MM) =>,01:00,02:00,[...],23:00,24:00
-! <WeekSchedule>,Name,Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Holiday,SummerDesignDay,WinterDesignDay,CustomDay1,CustomDay2
+! <WeekSchedule - Hourly>,Name,Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Holiday,SummerDesignDay,WinterDesignDay,CustomDay1,CustomDay2
-! <Schedule>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31
+! <Schedule - Hourly>,Name,ScheduleType,{Until Date,WeekSchedule}** Repeated until Dec 31
-ScheduleTypeLimits,FRACTION,Average,0.00,1.00,Yes
-ScheduleTypeLimits,ANY NUMBER,No,N/A,N/A,N/A
-DaySchedule,TDEFAULTPROFILE,FRACTION,No,Values:,0.88,0.92,[...],0.75,0.82
+DaySchedule - Hourly,TDEFAULTPROFILE,FRACTION,No,Values:,0.88,0.92,[...],0.75,0.82
-Schedule:Week:Daily,CT WEEKSCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE
+WeekSchedule - Hourly,CT WEEKSCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE,CT DAY SCHEDULE
-Schedule,ZONE CONTROL TYPE SCHEDULE,CONTROLTYPE,Through Dec 31,CT WEEKSCHEDULE
+Schedule - Hourly,ZONE CONTROL TYPE SCHEDULE,CONTROLTYPE,Through Dec 31,CT WEEKSCHEDULE
```

#### Warmup Convergence Information

When `Output:Diagnostics` has the `ReportDetailedWarmupConvergence` enabled, both the regular report and the detailed one were named `Warmup Convergence Information` resulting in duplicated HTML tables that would include lines from the other report.

The `ReportDetailedWarmupConvergence` report (the one that shows the status at each timestep/hour until convergence is reached) was renamed to `Warmup Convergence Information - Detailed`.

#### Material:Air

The `Output:Constructions` has two possible keys: `Materials` and `Constructions`. Both were adding a table named `Material:Air`. The Constructions one was renamed to `Material:Air CTF Summary` to match the surrounding tables.

#### Fuel Supply

When using `Generator:FuelSupply`, the header was written twice in the EIO Initialization Summary as `! <Fuel Supply>,...` leading to two identical tables in the HTML report.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Explain and document the changes

"! <Material CTF Summary>,Material Name,Thickness {{m}},Conductivity {{w/m-K}},Density {{kg/m3}},Specific Heat "
"{{J/kg-K}},ThermalResistance {{m2-K/w}}\n");
print(state.files.eio, "! <Material:Air>,Material Name,ThermalResistance {{m2-K/w}}\n");
print(state.files.eio, "! <Material:Air CTF Summary>,Material Name,ThermalResistance {{m2-K/w}}\n");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

DUplicated "Material:Air" table.

switch (thisMaterial->group) {
case Material::Group::AirGap: {
static constexpr std::string_view Format_702(" Material:Air,{},{:12.4N}\n");
static constexpr std::string_view Format_702(" Material:Air CTF Summary,{},{:12.4N}\n");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Duplicated Material:Air Table.

Output:Constructions,Materials; will add a table for each Material:Air.

Output:Constructions,Constructions; (this one) will add a SECOND table now called Material:Air CTF Summary.

Taking integration.SingleFamilyHouse_HP_Slab as example:

Originally, the Material:Air table for Materials has a duplicated row

image

The second is even worse, it includes everything

image


After

First, Materials table:

image

Second, COnstruction table

image

Comment on lines +666 to +668
print(state.files.eio,
"! <Fuel Supply>, Fuel Supply Name, Lower Heating Value [J/kmol], Lower Heating Value [kJ/kg], Higher "
"Heating Value [KJ/kg], Molecular Weight [g/mol] \n");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fuel Supply header was written twice, resulting in several identical tables (as many as the Generator:FuelSupply you have)

Taking _FuelCellTest200

Original:

image

After:

image

Comment on lines +2078 to +2081
// Report the ScheduleTypeLimits only once, not for each report level.
if (NumFields > 0) {
ReportScheduleTypeLimits(state);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This

Copy link
Member

Choose a reason for hiding this comment

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

Excellent.

Comment on lines +2096 to +2105
if (auto [it, inserted] = reportLevelSet.insert(reportLevel); inserted) {
// If this is the first time we see this report level, we need to report the details
ReportScheduleDetails(state, reportLevel);
} else {
ShowWarningCustom(state,
eoh,
format("Report level {} has already been processed. This report level will not be processed again.",
reportLevelNames[(int)reportLevel]));
continue;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Report only once for each ReportLevel, in case you put twice "Output:Schedules,Timestep;" for eg

Copy link
Contributor

Choose a reason for hiding this comment

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

Good

}
}

void ReportScheduleDetails(EnergyPlusData &state,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I completely revamped this function, using vectors instead of fortran arrays, etc.

I took 1ZoneUncontrolled_DD2009.idf and I added a couple more schedules for testing. Not sure if I should commit that change.

I added this

  Schedule:Day:List,
    Example Weather Temp,    !- Name
    Any Number,              !- Schedule Type Limits Name
    Average,                 !- Interpolate to Timestep
    15,                      !- Minutes per Item
    19.55,                   !- Value 1
    20.1,                    !- <none>
    20.65,                   !- <none>
    21.2,                    !- <none>
    21.25,                   !- <none>
    21.3,                    !- <none>
    21.35,                   !- <none>
    21.4,                    !- <none>
    21.25,                   !- <none>
    21.1,                    !- <none>
    20.95,                   !- <none>
    20.8,                    !- <none>
    20.625,                  !- <none>
    20.45,                   !- <none>
    20.275,                  !- <none>
    20.1,                    !- <none>
    19.95,                   !- <none>
    19.8,                    !- <none>
    19.65,                   !- <none>
    19.5,                    !- <none>
    19.625,                  !- <none>
    19.75,                   !- <none>
    19.875,                  !- <none>
    20,                      !- <none>
    20.25,                   !- <none>
    20.5,                    !- <none>
    20.75,                   !- <none>
    21,                      !- <none>
    21.1,                    !- <none>
    21.2,                    !- <none>
    21.3,                    !- <none>
    21.4,                    !- <none>
    21.8,                    !- <none>
    22.2,                    !- <none>
    22.6,                    !- <none>
    23,                      !- <none>
    23,                      !- <none>
    23,                      !- <none>
    23,                      !- <none>
    23,                      !- <none>
    23.375,                  !- <none>
    23.75,                   !- <none>
    24.125,                  !- <none>
    24.5,                    !- <none>
    24.45,                   !- <none>
    24.4,                    !- <none>
    24.35,                   !- <none>
    24.3,                    !- <none>
    24.225,                  !- <none>
    24.15,                   !- <none>
    24.075,                  !- <none>
    24,                      !- <none>
    23.95,                   !- <none>
    23.9,                    !- <none>
    23.85,                   !- <none>
    23.8,                    !- <none>
    23.85,                   !- <none>
    23.9,                    !- <none>
    23.95,                   !- <none>
    24,                      !- <none>
    24,                      !- <none>
    24,                      !- <none>
    24,                      !- <none>
    24,                      !- <none>
    23.825,                  !- <none>
    23.65,                   !- <none>
    23.475,                  !- <none>
    23.3,                    !- <none>
    23.1,                    !- <none>
    22.9,                    !- <none>
    22.7,                    !- <none>
    22.5,                    !- <none>
    22.275,                  !- <none>
    22.05,                   !- <none>
    21.825,                  !- <none>
    21.6,                    !- <none>
    21.4,                    !- <none>
    21.2,                    !- <none>
    21,                      !- <none>
    20.8,                    !- <none>
    20.7,                    !- <none>
    20.6,                    !- <none>
    20.5,                    !- <none>
    20.4,                    !- <none>
    20.3,                    !- <none>
    20.2,                    !- <none>
    20.1,                    !- <none>
    20,                      !- <none>
    20,                      !- <none>
    20,                      !- <none>
    20,                      !- <none>
    20,                      !- <none>
    19.75,                   !- <none>
    19.5,                    !- <none>
    19.25,                   !- <none>
    19;                      !- <none>

  ScheduleTypeLimits,
    ControlType,             !- Name
    0,                       !- Lower Limit Value
    4,                       !- Upper Limit Value
    DISCRETE;                !- Numeric Type

  Schedule:Day:Interval,
    CT Day Schedule,         !- Name
    ControlType,             !- Schedule Type Limits Name
    Linear,                  !- Interpolate to Timestep
    Until: 01:00,            !- Time 1
    2,                       !- Value Until Time 1
    Until: 03:00,            !- Time 2
    4,                       !- Value Until Time 2
    Until: 24:00,            !- Time 2
    4;                       !- Value Until Time 2

  Schedule:Week:Compact,
    CT WeekSchedule,         !- Name
    For: Alldays,            !- DayType List 1
    CT Day Schedule;         !- Schedule:Day Name 1

  Schedule:Year,
    Zone Control Type Schedule,  !- Name
    ControlType,             !- Schedule Type Limits Name
    CT WeekSchedule,         !- Schedule:Week Name 1
    1,                       !- Start Month 1
    1,                       !- Start Day 1
    12,                      !- End Month 1
    31;                      !- End Day 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Before I'm missing a bunch of tables because the Header doesn't match the data rows.

And I have a duplicated DaySchedule which will pick the Hourly rows to report in Timestep and vice versa, leading to completely wrong rows in both cases.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After:

image

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit bfc2443

Regression Summary
  • EIO: 305
  • Table Big Diffs: 61

@jmarrec
Copy link
Contributor Author

jmarrec commented Jun 25, 2025

Regressions are all ok

Notebook of the Regressions

Please see my jupyter notebook at https://gist.github.com/jmarrec/c907ca0bc00722356fb94b80176a82ca

305 EIO diffs

  • 281 of these diffs are Material:Air-> Material:Air CTF Summary changes
  • 1 is a duplicated <Fuel Supply>
  • That leaves 23 other diffs
diffs_not_ok = ['1ZoneUncontrolled_DD2009',
 '1ZoneUncontrolled_DDChanges',
 'Fault_HumidistatOffset_Supermarket',
 'Fault_HumidistatOffset_ThermostatOffset_Supermarket',
 'Flr_Rf_8Sides',
 'MicroCogeneration',
 'SuperMarketDetailed_DesuperHeatingCoil',
 'SuperMarket_DesuperHeatingCoil',
 'SuperMarket_DetailedEvapCondenser',
 'SuperMarket_DetailedWaterCondenser',
 'SuperMarket_EvapCondenser',
 'SuperMarket_SharedEvapCondenser',
 'SuperMarket_WaterCondenser',
 'Supermarket',
 'SupermarketSecondary',
 'SupermarketSubCoolersVariableSuction',
 'SupermarketTranscriticalCO2',
 'SupermarketTwoStageFlashIntercooler',
 'SupermarketTwoStageShellCoilIntercooler',
 'Supermarket_CascadeCond',
 'Supermarket_Detailed',
 'Supermarket_SharedAirCondenser',
 '_5ZoneEvapCooled']

I inspected these diffs manually, they're all related to the ScheduleManager refactor I did. see the notebook in the Gist

61 Table Big Diffs

37 are very short and cna be ruled out. I inspected the others manually, they all look fine.

from pathlib import Path

RE_FULLNAME = re.compile(r"<!-- FullName:(?P<activeReportName>[^_]+)_(?P<activeForName>[^_]+)_(?P<subtitle>[^_]+)-->")

Copy link
Contributor

Choose a reason for hiding this comment

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

I personally think using regular expressions makes this type of script more difficult to understand (but then again, I almost never choose to use regular expressions...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like regexes. this one is simple too.

Copy link
Member

Choose a reason for hiding this comment

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

@JasonGlazer if this script were going to need to be modified regularly with more complexity, I may lean away from a complex regex. In this case, I agree it's not too complicated, we won't need to edit this script almost ever, and when we do -- plenty of tools out there to explain the regex to us :)

if args.skip_missing:
print(f"Skipping missing HTML file: {html_path}")
exit(0)
raise IOError(f"HTML '{html_path}' does not exist")
Copy link
Contributor

Choose a reason for hiding this comment

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

Are there any files that produce tables and not HTML tables?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is more like we may have IDF files that turn it off.

Comment on lines +2096 to +2105
if (auto [it, inserted] = reportLevelSet.insert(reportLevel); inserted) {
// If this is the first time we see this report level, we need to report the details
ReportScheduleDetails(state, reportLevel);
} else {
ShowWarningCustom(state,
eoh,
format("Report level {} has already been processed. This report level will not be processed again.",
reportLevelNames[(int)reportLevel]));
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Good

Copy link
Member

@Myoldmopar Myoldmopar left a comment

Choose a reason for hiding this comment

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

This is great stuff. I'll test it out locally, and fix the tiny little typo in the output rules file, but this should be ready to go. And a great addition.

Comment on lines +240 to +255
set(HTML_PATH "${OUTPUT_DIR_PATH}/eplustbl.htm")
if(EXISTS "${HTML_PATH}")
message("Checking uniqueness of HTML Table FullNames:")
message(STATUS "${Python_EXECUTABLE} ${SOURCE_DIR}/scripts/dev/ensure_unique_html_tables.py ${OUTPUT_DIR_PATH}")
execute_process(
COMMAND ${Python_EXECUTABLE} "${SOURCE_DIR}/scripts/dev/ensure_unique_html_tables.py" "${OUTPUT_DIR_PATH}"
RESULT_VARIABLE RESULT
ECHO_OUTPUT_VARIABLE
ECHO_ERROR_VARIABLE
)

if(NOT RESULT EQUAL 0)
message("Test Failed: HTML output tables are NOT unique")
return()
endif()
endif()
Copy link
Member

Choose a reason for hiding this comment

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

I will admit, I was taken aback when I saw a new parameter defined for RunSimulation, but after a couple seconds, I realized what you must be doing. Good stuff here.

Comment on lines +2078 to +2081
// Report the ScheduleTypeLimits only once, not for each report level.
if (NumFields > 0) {
ReportScheduleTypeLimits(state);
}
Copy link
Member

Choose a reason for hiding this comment

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

Excellent.

The `Output:Schedules` object controls whether the schedules are reported to the EIO, which would end up in the Initialization Summary report of the HTML if the `Output:Table:SummaryReports` asks for it.
The `Output:Schedules` object has a `Key Field` which can be either `Timestep` or `Hourly`, and it is **not** a unique object, meaning you can request **both**.

A few issues where occurring with the former EIO report (which is parsed to produce the HTML tables):
Copy link
Member

Choose a reason for hiding this comment

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

Minor typo where -> were

@Myoldmopar
Copy link
Member

OK, I'll let the GHA instances spin up real quick, but no need to wait on them, I just fixed the typo. This is merging in a moment. Thanks @jmarrec .

@Myoldmopar Myoldmopar merged commit 8b80be6 into develop Jul 16, 2025
6 checks passed
@Myoldmopar Myoldmopar deleted the 11087_Duplicate_Table_Names branch July 16, 2025 20:41
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 3c0e149

Regression Summary
  • EIO: 305
  • Table Big Diffs: 61

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.

Duplicate Table Names in Tabular Output

6 participants