Parsing Results¶
The SimulationResult class provides structured access to all EnergyPlus
output files with lazy loading for efficient memory usage.
SimulationResult Overview¶
from idfkit.simulation import simulate
result = simulate(model, weather)
# Basic info
print(f"Success: {result.success}")
print(f"Exit code: {result.exit_code}")
print(f"Runtime: {result.runtime_seconds:.1f}s")
print(f"Output dir: {result.run_dir}")
# Parsed outputs (lazy-loaded)
result.errors # ErrorReport from .err file
result.sql # SQLResult from .sql database
result.variables # OutputVariableIndex from .rdd/.mdd
result.csv # CSVResult from .csv file
result.html # HTMLResult from HTML tabular output
Output File Paths¶
Access paths to specific output files:
result.sql_path # Path to .sql database
result.err_path # Path to .err file
result.eso_path # Path to .eso file
result.csv_path # Path to .csv file
result.html_path # Path to HTML table file
result.rdd_path # Path to .rdd file
result.mdd_path # Path to .mdd file
Each returns None if the file wasn't produced.
Error Report¶
Parse warnings and errors from the .err file:
errors = result.errors
# Summary
print(errors.summary())
# Check for fatal errors
if errors.has_fatal:
for err in errors.fatal:
print(f"FATAL: {err.message}")
# Check for severe errors
if errors.has_severe:
for err in errors.severe:
print(f"SEVERE: {err.message}")
# All warnings
for warn in errors.warnings:
print(f"Warning: {warn.message}")
# Counts
print(f"Fatal: {errors.fatal_count}")
print(f"Severe: {errors.severe_count}")
print(f"Warnings: {errors.warning_count}")
See Error Handling for detailed error parsing.
SQL Database¶
Query time-series and tabular data from the SQLite output:
sql = result.sql
if sql is not None:
# Time-series data
ts = sql.get_timeseries(
variable_name="Zone Mean Air Temperature",
key_value="THERMAL ZONE 1",
)
print(f"Max: {max(ts.values):.1f}°C")
# Tabular reports
rows = sql.get_tabular_data(report_name="AnnualBuildingUtilityPerformanceSummary")
See SQL Output Queries for detailed SQL parsing.
Output Variables¶
Discover available output variables from .rdd/.mdd files:
variables = result.variables
if variables is not None:
# Search for variables
matches = variables.search("Temperature")
for var in matches:
print(f"{var.name} [{var.units}]")
# Add outputs to model for next run
variables.add_all_to_model(model, filter_pattern="Zone.*Temperature")
See Output Discovery for variable discovery.
CSV Output¶
Parse CSV time-series output:
csv_result = result.csv
if csv_result is not None:
# List all columns
for col in csv_result.columns:
print(f"{col.variable_name} ({col.key_value}) [{col.units}]")
# Get data for a specific column
values = csv_result.get_column_values("Zone Mean Air Temperature")
HTML Tabular Output¶
Parse the HTML tabular summary file (eplustbl.htm) that EnergyPlus
produces alongside every simulation:
html = result.html
if html is not None:
# Iterate all tables
for table in html:
print(f"{table.title}: {len(table.rows)} rows")
# eppy-compatible (title, rows) pairs
for title, rows in html.titletable():
print(title)
# Look up a table by title (case-insensitive substring match)
table = html.tablebyname("Site and Source Energy")
if table:
data = table.to_dict() # {row_key: {col_header: value}}
print(data)
# Get all tables from a specific report
annual = html.tablesbyreport("Annual Building Utility Performance Summary")
# Access by index
first = html.tablebyindex(0)
Each HTMLTable has these attributes:
| Attribute | Type | Description |
|---|---|---|
title |
str |
Bold title preceding the table |
header |
list[str] |
Column headers |
rows |
list[list[str]] |
Data rows |
report_name |
str |
Parent report name |
for_string |
str |
The "For:" qualifier (e.g. "Entire Facility") |
You can also parse a standalone HTML file without a full simulation:
from idfkit.simulation.parsers.html import HTMLResult
html = HTMLResult.from_file("eplustbl.htm")
html = HTMLResult.from_string(html_string)
This replaces eppy's readhtml module.
Lazy Loading¶
Output files are parsed only when accessed:
result = simulate(model, weather)
# Nothing parsed yet - only metadata stored
result.errors # NOW parses .err file
result.sql # NOW opens SQLite database
result.variables # NOW parses .rdd/.mdd files
result.html # NOW parses HTML tabular output
This keeps memory usage low, especially for batch simulations where you might only need specific outputs.
Releasing File Handles¶
Accessing result.sql opens a SQLite connection on first use and caches it.
That connection holds an OS-level file handle on eplus.sql. On Windows,
the handle locks the file, so deleting the run directory while the result is
alive fails with PermissionError [WinError 32] — typically when the run
directory lives inside a tempfile.TemporaryDirectory or is removed with
shutil.rmtree. POSIX systems don't lock on open, so this only affects
Windows.
SimulationResult is a context manager: exiting the with block calls
close(), which releases
the connection. Close the result before the run directory is removed:
# The result context exits first - closing the SQLite connection - then
# TemporaryDirectory cleans up, so rmtree succeeds even on Windows.
with tempfile.TemporaryDirectory() as tmp, simulate(model, weather, output_dir=Path(tmp) / "run") as result:
temps = result.sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
# Equivalent without a context manager:
result = simulate(model, weather)
try:
temps = result.sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
finally:
result.close() # idempotent; reopens lazily if you touch result.sql again
close() is idempotent and resets the cached connection, so touching
result.sql afterwards transparently reopens it. The other accessors
(errors, csv, eso, html, variables) read their files eagerly and
hold no handles, so they need no cleanup.
Reconstructing from Directory¶
Inspect results from a previous simulation:
from idfkit.simulation import SimulationResult
# From a local directory
result = SimulationResult.from_directory("/path/to/sim_output")
# From a cloud storage location
from idfkit.simulation import S3FileSystem
fs = S3FileSystem(bucket="my-bucket")
result = SimulationResult.from_directory("runs/run-001", fs=fs)
# Query data
ts = result.sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
Attributes Reference¶
| Attribute | Type | Description |
|---|---|---|
run_dir |
Path |
Directory containing output files |
success |
bool |
Whether simulation succeeded |
exit_code |
int | None |
Process exit code (None if timed out) |
stdout |
str |
Captured standard output |
stderr |
str |
Captured standard error |
runtime_seconds |
float |
Wall-clock execution time |
output_prefix |
str |
Output file prefix (default "eplus") |
Properties Reference¶
| Property | Type | Description |
|---|---|---|
errors |
ErrorReport |
Parsed error/warning report |
sql |
SQLResult | None |
SQL database accessor |
variables |
OutputVariableIndex | None |
Variable discovery |
csv |
CSVResult | None |
CSV output parser |
html |
HTMLResult | None |
HTML tabular output parser |
sql_path |
Path | None |
Path to .sql file |
err_path |
Path | None |
Path to .err file |
eso_path |
Path | None |
Path to .eso file |
csv_path |
Path | None |
Path to .csv file |
html_path |
Path | None |
Path to HTML file |
rdd_path |
Path | None |
Path to .rdd file |
mdd_path |
Path | None |
Path to .mdd file |
See Also¶
- SQL Output Queries — Detailed SQL database access
- Output Discovery — Finding available variables
- Error Handling — Parsing error reports