Skip to content

How to cache simulation results

The SimulationCache provides content-addressed caching to avoid redundant simulations: identical inputs return a stored result instead of re-running EnergyPlus. For how the cache key is computed, what gets stored, and why invalidation is automatic, see Caching strategy.

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.

Basic Usage

from idfkit.simulation import simulate, SimulationCache

cache = SimulationCache()

# First run: executes EnergyPlus
result1 = simulate(model, "weather.epw", cache=cache)
print(f"Runtime: {result1.runtime_seconds:.1f}s")

# Second run: instant cache hit
result2 = simulate(model, "weather.epw", cache=cache)
print(f"Runtime: {result2.runtime_seconds:.1f}s")  # Near zero

Cache Location

Default locations by platform:

Platform Default Path
Linux ~/.cache/idfkit/simulation/
macOS ~/Library/Caches/idfkit/simulation/
Windows %LOCALAPPDATA%\idfkit\cache\simulation\

Custom Location

from pathlib import Path

cache = SimulationCache(cache_dir=Path("/data/sim_cache"))

Cache Operations

Check for Hit

key = cache.compute_key(model, weather, design_day=True)

if cache.contains(key):
    print("Would be a cache hit")
else:
    print("Would be a cache miss")

Manual Get/Put

# Compute key
key = cache.compute_key(model, weather)

# Check cache
cached_result = cache.get(key)
if cached_result is not None:
    print("Cache hit!")
else:
    # Run simulation
    result = simulate(model, weather)

    # Store in cache (only successful results)
    cache.put(key, result)

Clear Cache

# Remove all cached entries
cache.clear()

Batch Processing

Share a cache across batch simulations. The cache is thread- and process-safe (atomic writes via a temp directory and rename), so a shared cache is safe for concurrent simulate_batch() runs and across multiple processes:

from idfkit.simulation import simulate_batch, SimulationCache

cache = SimulationCache()

# All jobs share the same cache
batch1 = simulate_batch(jobs, cache=cache)

# Re-running unchanged jobs hits cache
batch2 = simulate_batch(jobs, cache=cache)  # Instant for unchanged

Storage Considerations

Disk Space

Each cached entry is a full copy of the run directory. Monitor usage:

du -sh ~/.cache/idfkit/simulation/

Cleanup

# Clear everything
cache.clear()

# Or manually delete specific entries
import shutil

shutil.rmtree(cache.cache_dir / "abc123...")

Disabling Caching

Pass cache=None (the default) to skip caching:

# No caching
result = simulate(model, weather)

# With caching
result = simulate(model, weather, cache=SimulationCache())

Best Practices

  1. Use for development — Cache during iterative testing
  2. Clear for production — Start fresh for final runs
  3. Share across batch — Pass same cache to simulate_batch()
  4. Monitor disk usage — Large studies can fill disk
  5. Custom location — Use fast SSD for better performance

See Also