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.
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,
extra_args: list[str] | None = None,
cache: SimulationCache | None = None,
fs: FileSystem | None = None,
on_progress: Callable[[SimulationProgress], Any] | Literal["tqdm"] | None = None,
) -> 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 |
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 |
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.
See Also¶
- Progress Tracking — Real-time progress with
on_progress - Parsing Results — Working with
SimulationResult - Batch Processing — Running multiple simulations
- Error Handling — Understanding error reports