Skip to content

How to query simulation SQL output

The SQLResult class provides structured access to EnergyPlus's SQLite output database, containing time-series data, tabular reports, and metadata.

Python only, permanently

Running a locally installed EnergyPlus and reading its results belongs to Python alone. JavaScript is not waiting on a port and will not gain a counterpart: this is a permanent boundary, so no issue tracks it, and moving the capability out of that state takes a constitutional amendment rather than a ledger edit.

Requires an EnergyPlus installation on the machine and a subprocess to drive it, then reads the eplusout files that run leaves on disk. Neither the installation nor the subprocess is available in a browser, which is the runtime the JavaScript library targets. JavaScript reaches EnergyPlus by the other mechanism instead: see browser-simulation, which is not a workaround for this entry but a different capability.

The full entry, including the vocabulary this capability owns, is on the capability parity page.

Opening the Database

from idfkit.simulation import simulate

result = simulate(model, weather)

sql = result.sql
if sql is not None:
    # Query data...

Or open directly:

from idfkit.simulation import SQLResult

sql = SQLResult("/path/to/eplusout.sql")

Time-Series Data

Basic Query

ts = sql.get_timeseries(
    variable_name="Zone Mean Air Temperature",
    key_value="THERMAL ZONE 1",
)

print(f"Variable: {ts.variable_name}")
print(f"Key: {ts.key_value}")
print(f"Units: {ts.units}")
print(f"Frequency: {ts.frequency}")
print(f"Data points: {len(ts.values)}")
print(f"Min: {min(ts.values):.1f}, Max: {max(ts.values):.1f}")

A query returns a TimeSeriesResult. For its full list of attributes and methods, see the TimeSeriesResult reference.

Filtering by Environment

Specify which simulation environment to query:

# Design day results only (use for design_day=True simulations)
ts = sql.get_timeseries(
    "Zone Mean Air Temperature",
    "ZONE 1",
    environment="sizing",
)

# Annual/run period results only (default)
ts = sql.get_timeseries(
    "Zone Mean Air Temperature",
    "ZONE 1",
    environment="annual",
)

# All environments (design days + run periods)
ts = sql.get_timeseries(
    "Zone Mean Air Temperature",
    "ZONE 1",
    environment=None,
)

The environment parameter accepts:

Value Description
None All data from all environments (default)
"annual" Weather-file run period data only
"sizing" Design day data only

Converting to DataFrame

df = ts.to_dataframe()
print(df.head())
#                              Zone Mean Air Temperature
# timestamp
# 2017-01-01 01:00:00                               21.2
# 2017-01-01 02:00:00                               21.1
# ...

Requires pandas: pip install idfkit[dataframes]

Plotting Time Series

fig = ts.plot()  # Auto-detects matplotlib/plotly

Requires matplotlib or plotly: pip install idfkit[plot]

Tabular Data

Query Tabular Reports

rows = sql.get_tabular_data(report_name="AnnualBuildingUtilityPerformanceSummary")

for row in rows[:5]:
    print(f"{row.table_name} | {row.row_name} | {row.column_name}: {row.value}")

Each row is a TabularRow. For its full list of attributes, see the TabularRow reference.

Filter by Table

rows = sql.get_tabular_data(
    report_name="AnnualBuildingUtilityPerformanceSummary",
    table_name="Site and Source Energy",
)

Common Reports

Report Name Description
AnnualBuildingUtilityPerformanceSummary Energy use summary
InputVerificationandResultsSummary Model summary
EnvelopeSummary Building envelope details
LightingSummary Lighting power densities
EquipmentSummary Equipment capacities
HVACSizingSummary HVAC sizing results
ZoneComponentLoadSummary Zone load components

Variable Metadata

List Available Variables

variables = sql.list_variables()

for var in variables[:10]:
    print(f"{var.name} ({var.key_value}) [{var.units}] - {var.frequency}")

Each entry is a VariableInfo. For its full list of attributes, see the VariableInfo reference.

Search Variables

# By name pattern
temp_vars = [v for v in variables if "Temperature" in v.name]

# By key
zone1_vars = [v for v in variables if v.key_value == "ZONE 1"]

Environment Metadata

List Environments

environments = sql.list_environments()

for env in environments:
    print(f"{env.index}: {env.name} (type={env.environment_type})")

Environment Types

Type Value Description
Design Day 1 SizingPeriod:DesignDay simulation
Design Run Period 2 SizingPeriod:WeatherFileDays
Weather File Run Period 3 Regular RunPeriod simulation

Each environment is an EnvironmentInfo. For its full list of attributes, see the EnvironmentInfo reference.

Timestamps

EnergyPlus uses a fixed reference year (2017) for timestamps. The SQLResult automatically converts database timestamps to Python datetime objects.

EnergyPlus Time Convention

  • Hour 24 in the database → midnight of the next day
  • Warmup days are filtered out automatically
ts = sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")

# Timestamps are proper Python datetime objects
first = ts.timestamps[0]
print(f"Year: {first.year}")  # 2017 (reference year)
print(f"Month: {first.month}")
print(f"Day: {first.day}")
print(f"Hour: {first.hour}")

Context Manager

SQLResult is a context manager for clean database cleanup:

with SQLResult("/path/to/eplusout.sql") as sql:
    ts = sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
    # Connection automatically closed on exit

SimulationResult — the usual entry point via simulate() — is also a context manager. Exiting the with block closes the SQLite connection that result.sql opened lazily, which matters on Windows where the open connection locks eplus.sql and blocks deleting the run directory:

with simulate(model, weather) as result:
    ts = result.sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
    # SQLite connection closed on exit; the run directory can be deleted

See Releasing File Handles for details.

Error Handling

def read_zone_temperature(result: SimulationResult) -> None:
    sql = result.sql
    if sql is None:
        print("No SQL output - was Output:SQLite in the model?")
        return

    # Get time series (raises KeyError if not found)
    try:
        ts = sql.get_timeseries("Nonexistent Variable", "ZONE 1")
    except KeyError as e:
        print(f"Variable not found: {e}")

Performance Tips

  1. Filter early — Use the environment parameter to reduce data size
  2. Query once — Store results in variables rather than re-querying
  3. Use lazy loading — Don't access result.sql if you don't need it

See Also