Running Simulations¶
The simulate() function executes EnergyPlus as a subprocess and returns
a structured SimulationResult with access to all output files.
Basic Usage¶
from idfkit import load_idf
from idfkit.simulation import simulate
model = load_idf("building.idf")
result = simulate(model, "weather.epw")
print(f"Success: {result.success}")
print(f"Runtime: {result.runtime_seconds:.1f}s")
print(f"Output directory: {result.run_dir}")
Simulation Modes¶
Design-Day Only¶
Fast simulation using only design day conditions:
Annual Simulation¶
Full-year simulation:
Default Mode¶
Without flags, EnergyPlus uses whatever run periods are defined in the model:
Preprocessing¶
Some EnergyPlus models contain high-level template objects that must be expanded into their low-level equivalents before simulation. idfkit provides standalone preprocessing functions for this.
Expanding HVAC Templates¶
HVACTemplate:* objects are shorthand for complex HVAC systems.
expand_objects() converts them into their fully specified equivalents:
from idfkit.simulation import expand_objects
expanded = expand_objects(model)
# HVACTemplate:Zone:IdealLoadsAirSystem → ZoneHVAC:IdealLoadsAirSystem + ...
Note
simulate() runs ExpandObjects automatically when expand_objects=True
(the default). Call expand_objects() directly only when you need to
inspect or modify the expanded model before simulation.
Ground Heat Transfer (Slab & Basement)¶
Models with GroundHeatTransfer:Slab:* or GroundHeatTransfer:Basement:*
objects need the Slab or Basement preprocessor to compute ground temperatures.
Note
simulate() automatically runs the Slab and/or Basement
preprocessors when expand_objects=True (the default) and the model
contains the corresponding ground heat-transfer objects. In most
cases you do not need to call these functions yourself.
Preprocessor Timeout¶
Each preprocessor stage (ExpandObjects, Slab, Basement) gets its own
subprocess timeout, separate from the EnergyPlus timeout. Override it
per call with preprocessor_timeout:
Or set a process-wide default with the IDFKIT_PREPROCESSOR_TIMEOUT
environment variable — useful for slow shared hardware (raise it) or
fast CI where you want to catch hangs quickly (lower it):
export IDFKIT_PREPROCESSOR_TIMEOUT=600 # slow shared hardware
export IDFKIT_PREPROCESSOR_TIMEOUT=30 # fail fast in CI
The default is 120 seconds per subprocess. timeout and
preprocessor_timeout are independent budgets — there is no shared
wall-clock cap across the pipeline, so a long preprocessor_timeout
will not trip the simulation's timeout and vice versa.
For cases where you need to inspect or modify the preprocessed model before simulation, standalone functions are available:
from idfkit.simulation import run_slab_preprocessor, run_basement_preprocessor
# Slab-on-grade foundation
expanded = run_slab_preprocessor(model, weather="weather.epw")
# Basement walls and floors
expanded = run_basement_preprocessor(model, weather="weather.epw")
Each function runs ExpandObjects first (to extract the ground heat-transfer
input), then the Fortran solver, and returns a new IDFDocument with the
computed temperature schedules appended.
All preprocessing functions raise
ExpandObjectsError on failure, with
structured preprocessor, exit_code, and stderr fields for
programmatic error handling.
See the Preprocessing API reference for full details.
Function Signature¶
def simulate(
model: IDFDocument,
weather: str | Path,
*,
output_dir: str | Path | None = None,
energyplus: EnergyPlusConfig | None = None,
expand_objects: bool = True,
annual: bool = False,
design_day: bool = False,
output_prefix: str = "eplus",
output_suffix: Literal["C", "L", "D"] = "C",
readvars: bool = False,
timeout: float = 3600.0,
preprocessor_timeout: float | None = None,
extra_args: list[str] | None = None,
cache: SimulationCache | None = None,
fs: FileSystem | None = None,
on_progress: Callable[[SimulationProgress], Any] | Literal["tqdm"] | None = None,
auto_migrate: bool = False,
) -> SimulationResult:
Parameters¶
Required¶
| Parameter | Description |
|---|---|
model |
The EnergyPlus model to simulate |
weather |
Path to the weather file (.epw) |
Optional¶
| Parameter | Default | Description |
|---|---|---|
output_dir |
Auto temp | Directory for output files |
energyplus |
Auto-detect | Pre-configured EnergyPlus installation |
expand_objects |
True |
Run ExpandObjects (and Slab/Basement if needed) before simulation |
annual |
False |
Run annual simulation (-a flag) |
design_day |
False |
Run design-day-only (-D flag) |
output_prefix |
"eplus" |
Prefix for output files |
output_suffix |
"C" |
Output naming style (C/L/D) |
readvars |
False |
Run ReadVarsESO after simulation |
timeout |
3600.0 |
Maximum runtime in seconds (main EnergyPlus subprocess only) |
preprocessor_timeout |
None |
Per-subprocess timeout for ExpandObjects / Slab / Basement. None reads IDFKIT_PREPROCESSOR_TIMEOUT, defaulting to 120 s |
extra_args |
None |
Additional command-line arguments |
cache |
None |
Simulation cache for result reuse |
fs |
None |
File system backend for cloud storage |
on_progress |
None |
Callback or "tqdm" for real-time progress updates |
auto_migrate |
False |
Forward-migrate the model when its version differs from the installed EnergyPlus (see Migrating Versions) |
EnergyPlus Discovery¶
By default, simulate() auto-discovers EnergyPlus:
# Auto-discovery
result = simulate(model, weather)
# Explicit path
from idfkit.simulation import find_energyplus
config = find_energyplus("/custom/path/EnergyPlus-24-1-0")
result = simulate(model, weather, energyplus=config)
# Environment variable
# Set ENERGYPLUS_DIR=/path/to/EnergyPlus before running
result = simulate(model, weather)
Discovery priority:
- Explicit
energyplusparameter ENERGYPLUS_DIRenvironment variable- System PATH
- Platform default directories
Output Directory¶
Automatic Temporary Directory¶
By default, outputs go to an auto-generated temp directory:
Explicit Directory¶
Specify where to store outputs:
The directory is created if it doesn't exist.
Error Handling¶
Simulation Errors¶
from idfkit.exceptions import SimulationError
try:
result = simulate(model, weather)
except SimulationError as e:
print(f"Simulation failed: {e}")
print(f"Exit code: {e.exit_code}")
print(f"Stderr: {e.stderr}")
Timeout¶
try:
result = simulate(model, weather, timeout=60.0) # 1 minute max
except SimulationError as e:
if e.exit_code is None:
print("Simulation timed out")
Checking Success¶
result = simulate(model, weather)
if not result.success:
print(f"Exit code: {result.exit_code}")
print(f"Stderr: {result.stderr}")
for err in result.errors.fatal:
print(f"Error: {err.message}")
Model Safety¶
simulate() copies your model before running — the original is never modified:
model = load_idf("building.idf")
original_count = len(model)
result = simulate(model, weather)
# Model unchanged
assert len(model) == original_count
assert "Output:SQLite" not in model
Command-Line Options¶
Output Suffix Modes¶
| Value | Description |
|---|---|
"C" |
Combined table files (default) |
"L" |
Legacy separate table files |
"D" |
Timestamped separate files |
Extra Arguments¶
Pass additional EnergyPlus flags:
Cloud Storage¶
For remote storage backends (S3, etc.):
from idfkit.simulation import S3FileSystem
fs = S3FileSystem(bucket="my-bucket", prefix="runs/")
result = simulate(
model,
weather,
output_dir="run-001", # Required with fs
fs=fs,
)
See Cloud & Remote Storage for details.
Caching¶
Enable content-addressed caching to avoid redundant simulations:
from idfkit.simulation import SimulationCache
cache = SimulationCache()
# First run: executes simulation
result1 = simulate(model, weather, cache=cache)
# Second run: instant cache hit
result2 = simulate(model, weather, cache=cache)
See Caching for details.
Version Migration¶
When model.version differs from the installed EnergyPlus,
simulate() raises VersionMismatchError
by default. Pass auto_migrate=True to forward-migrate the model
transparently before the run; the resulting
MigrationReport is attached to
SimulationResult.migration_report.
See Migrating Versions for the full workflow.
See Also¶
- Migrating Versions — Forward-migrate IDF models across EnergyPlus releases
- Progress Tracking — Real-time progress with
on_progress - Parsing Results — Working with
SimulationResult - Batch Processing — Running multiple simulations
- Error Handling — Understanding error reports