Skip to content

Preprocessing API

Functions for expanding template and preprocessor objects before simulation.

EnergyPlus models may contain high-level template objects that must be expanded into their low-level equivalents before a simulation can run. Three preprocessors are supported:

Function Preprocessor Objects handled
expand_objects() ExpandObjects HVACTemplate:*
run_slab_preprocessor() Slab GroundHeatTransfer:Slab:*
run_basement_preprocessor() Basement GroundHeatTransfer:Basement:*
run_preprocessing() All of the above Combined pipeline
needs_ground_heat_preprocessing() Detection helper

All functions return a new IDFDocument — the original model is never mutated. If the model contains no objects for a given preprocessor, a copy is returned immediately without invoking any external process.

Note

simulate() calls run_preprocessing() automatically when expand_objects=True (the default) and the model contains ground heat-transfer objects. Use the individual functions only when you need to inspect or modify the preprocessed model before simulation.

expand_objects

idfkit.simulation.expand.expand_objects(model, *, energyplus=None, timeout=120.0)

Run the EnergyPlus ExpandObjects preprocessor and return the expanded document.

ExpandObjects replaces HVACTemplate:* objects with their fully specified low-level HVAC equivalents. The original model is not mutated.

If the document contains no HVACTemplate:* objects a copy is returned immediately without invoking the preprocessor (no EnergyPlus installation required).

Parameters:

Name Type Description Default
model IDFDocument

The EnergyPlus model to expand.

required
energyplus EnergyPlusConfig | None

Pre-configured EnergyPlus installation. If None, find_energyplus is used for auto-discovery.

None
timeout float

Maximum time in seconds to wait for the preprocessor (default 120).

120.0

Returns:

Type Description
IDFDocument

A new IDFDocument containing the expanded

IDFDocument

objects.

Raises:

Type Description
EnergyPlusNotFoundError

If no EnergyPlus installation (and therefore no ExpandObjects executable) can be found.

ExpandObjectsError

If the ExpandObjects executable is missing from the installation or the preprocessor exits with an error.

Source code in src/idfkit/simulation/expand.py
def expand_objects(
    model: IDFDocument,
    *,
    energyplus: EnergyPlusConfig | None = None,
    timeout: float = 120.0,
) -> IDFDocument:
    """Run the EnergyPlus *ExpandObjects* preprocessor and return the expanded document.

    ``ExpandObjects`` replaces ``HVACTemplate:*`` objects with their fully
    specified low-level HVAC equivalents.  The original *model* is **not**
    mutated.

    If the document contains no ``HVACTemplate:*`` objects a
    [copy][idfkit.document.IDFDocument.copy] is returned immediately without
    invoking the preprocessor (no EnergyPlus installation required).

    Args:
        model: The EnergyPlus model to expand.
        energyplus: Pre-configured EnergyPlus installation.  If ``None``,
            [find_energyplus][idfkit.simulation.config.find_energyplus] is used for
            auto-discovery.
        timeout: Maximum time in seconds to wait for the preprocessor
            (default 120).

    Returns:
        A new [IDFDocument][idfkit.document.IDFDocument] containing the expanded
        objects.

    Raises:
        EnergyPlusNotFoundError: If no EnergyPlus installation (and therefore
            no ``ExpandObjects`` executable) can be found.
        ExpandObjectsError: If the ``ExpandObjects`` executable is missing
            from the installation or the preprocessor exits with an error.
    """
    if not _needs_expansion(model):
        return model.copy()

    config = energyplus if energyplus is not None else find_energyplus()
    run_dir = _prepare_run_dir(model)
    try:
        _run_expand_objects(config, run_dir, timeout=timeout)
        return _parse_expanded(run_dir)
    finally:
        shutil.rmtree(run_dir, ignore_errors=True)

run_slab_preprocessor

idfkit.simulation.expand.run_slab_preprocessor(model, *, energyplus=None, weather=None, timeout=120.0)

Run the Slab ground heat-transfer preprocessor and return the expanded document.

The workflow is:

  1. ExpandObjects extracts GroundHeatTransfer:Slab:* objects from the model into GHTIn.idf.
  2. The Slab preprocessor reads GHTIn.idf and computes monthly ground surface temperatures, writing SLABSurfaceTemps.TXT.
  3. The resulting temperature schedules are appended to the expanded IDF.

The original model is not mutated.

If the document contains no GroundHeatTransfer:Slab:* objects a copy is returned immediately.

Parameters:

Name Type Description Default
model IDFDocument

The EnergyPlus model containing GroundHeatTransfer:Slab:* objects.

required
energyplus EnergyPlusConfig | None

Pre-configured EnergyPlus installation. If None, auto-discovery is used.

None
weather str | Path | None

Path to a weather file (.epw). Some Slab configurations may require weather data.

None
timeout float

Maximum time in seconds for each subprocess invocation (default 120).

120.0

Returns:

Type Description
IDFDocument

A new IDFDocument with slab ground

IDFDocument

temperatures appended.

Raises:

Type Description
EnergyPlusNotFoundError

If no EnergyPlus installation is found.

ExpandObjectsError

If any preprocessor step fails.

Source code in src/idfkit/simulation/expand.py
def run_slab_preprocessor(
    model: IDFDocument,
    *,
    energyplus: EnergyPlusConfig | None = None,
    weather: str | Path | None = None,
    timeout: float = 120.0,
) -> IDFDocument:
    """Run the *Slab* ground heat-transfer preprocessor and return the expanded document.

    The workflow is:

    1. ``ExpandObjects`` extracts ``GroundHeatTransfer:Slab:*`` objects from
       the model into ``GHTIn.idf``.
    2. The **Slab** preprocessor reads ``GHTIn.idf`` and computes monthly
       ground surface temperatures, writing ``SLABSurfaceTemps.TXT``.
    3. The resulting temperature schedules are appended to the expanded IDF.

    The original *model* is **not** mutated.

    If the document contains no ``GroundHeatTransfer:Slab:*`` objects a
    [copy][idfkit.document.IDFDocument.copy] is returned immediately.

    Args:
        model: The EnergyPlus model containing ``GroundHeatTransfer:Slab:*``
            objects.
        energyplus: Pre-configured EnergyPlus installation.  If ``None``,
            auto-discovery is used.
        weather: Path to a weather file (``.epw``).  Some Slab configurations
            may require weather data.
        timeout: Maximum time in seconds for each subprocess invocation
            (default 120).

    Returns:
        A new [IDFDocument][idfkit.document.IDFDocument] with slab ground
        temperatures appended.

    Raises:
        EnergyPlusNotFoundError: If no EnergyPlus installation is found.
        ExpandObjectsError: If any preprocessor step fails.
    """
    if not _has_slab_objects(model):
        return model.copy()

    config = energyplus if energyplus is not None else find_energyplus()
    run_dir = _prepare_run_dir(model, weather=weather)
    try:
        _run_expand_objects(config, run_dir, timeout=timeout)

        ght_input = run_dir / "GHTIn.idf"
        if not ght_input.is_file():
            msg = (
                "ExpandObjects did not produce GHTIn.idf.  "
                "Ensure the model contains GroundHeatTransfer:Slab:* objects and "
                "GroundHeatTransfer:Control has run_slab_preprocessor set to Yes."
            )
            raise ExpandObjectsError(msg, preprocessor="ExpandObjects")

        _run_slab_in_dir(config, run_dir, timeout=timeout)
        return _parse_expanded(run_dir)
    finally:
        shutil.rmtree(run_dir, ignore_errors=True)

run_basement_preprocessor

idfkit.simulation.expand.run_basement_preprocessor(model, *, energyplus=None, weather=None, timeout=120.0)

Run the Basement ground heat-transfer preprocessor and return the expanded document.

The workflow is:

  1. ExpandObjects extracts GroundHeatTransfer:Basement:* objects from the model into BasementGHTIn.idf.
  2. The Basement preprocessor reads BasementGHTIn.idf and computes ground temperatures, writing EPObjects.TXT.
  3. The resulting boundary conditions are appended to the expanded IDF.

The original model is not mutated.

If the document contains no GroundHeatTransfer:Basement:* objects a copy is returned immediately.

Parameters:

Name Type Description Default
model IDFDocument

The EnergyPlus model containing GroundHeatTransfer:Basement:* objects.

required
energyplus EnergyPlusConfig | None

Pre-configured EnergyPlus installation. If None, auto-discovery is used.

None
weather str | Path | None

Path to a weather file (.epw). The Basement preprocessor requires weather data to compute ground temperatures.

None
timeout float

Maximum time in seconds for each subprocess invocation (default 120).

120.0

Returns:

Type Description
IDFDocument

A new IDFDocument with basement ground

IDFDocument

temperatures appended.

Raises:

Type Description
EnergyPlusNotFoundError

If no EnergyPlus installation is found.

ExpandObjectsError

If any preprocessor step fails.

Source code in src/idfkit/simulation/expand.py
def run_basement_preprocessor(
    model: IDFDocument,
    *,
    energyplus: EnergyPlusConfig | None = None,
    weather: str | Path | None = None,
    timeout: float = 120.0,
) -> IDFDocument:
    """Run the *Basement* ground heat-transfer preprocessor and return the expanded document.

    The workflow is:

    1. ``ExpandObjects`` extracts ``GroundHeatTransfer:Basement:*`` objects
       from the model into ``BasementGHTIn.idf``.
    2. The **Basement** preprocessor reads ``BasementGHTIn.idf`` and computes
       ground temperatures, writing ``EPObjects.TXT``.
    3. The resulting boundary conditions are appended to the expanded IDF.

    The original *model* is **not** mutated.

    If the document contains no ``GroundHeatTransfer:Basement:*`` objects a
    [copy][idfkit.document.IDFDocument.copy] is returned immediately.

    Args:
        model: The EnergyPlus model containing
            ``GroundHeatTransfer:Basement:*`` objects.
        energyplus: Pre-configured EnergyPlus installation.  If ``None``,
            auto-discovery is used.
        weather: Path to a weather file (``.epw``).  The Basement preprocessor
            requires weather data to compute ground temperatures.
        timeout: Maximum time in seconds for each subprocess invocation
            (default 120).

    Returns:
        A new [IDFDocument][idfkit.document.IDFDocument] with basement ground
        temperatures appended.

    Raises:
        EnergyPlusNotFoundError: If no EnergyPlus installation is found.
        ExpandObjectsError: If any preprocessor step fails.
    """
    if not _has_basement_objects(model):
        return model.copy()

    config = energyplus if energyplus is not None else find_energyplus()
    run_dir = _prepare_run_dir(model, weather=weather)
    try:
        _run_expand_objects(config, run_dir, timeout=timeout)

        ght_input = run_dir / "BasementGHTIn.idf"
        if not ght_input.is_file():
            msg = (
                "ExpandObjects did not produce BasementGHTIn.idf.  "
                "Ensure the model contains GroundHeatTransfer:Basement:* objects and "
                "GroundHeatTransfer:Control has run_basement_preprocessor set to Yes."
            )
            raise ExpandObjectsError(msg, preprocessor="ExpandObjects")

        _run_basement_in_dir(config, run_dir, timeout=timeout)
        return _parse_expanded(run_dir)
    finally:
        shutil.rmtree(run_dir, ignore_errors=True)

run_preprocessing

idfkit.simulation.expand.run_preprocessing(model, *, energyplus=None, weather=None, timeout=120.0)

Run ExpandObjects and any required ground heat-transfer preprocessors.

This is a convenience function that runs all needed preprocessors in a single call. It runs ExpandObjects once, then checks which preprocessor input files were produced (GHTIn.idf and/or BasementGHTIn.idf) and runs the corresponding Fortran solvers.

simulate calls this automatically when the model contains ground heat-transfer objects and expand_objects is True. Call it directly only when you need to inspect or modify the preprocessed model before simulation.

Parameters:

Name Type Description Default
model IDFDocument

The EnergyPlus model to preprocess.

required
energyplus EnergyPlusConfig | None

Pre-configured EnergyPlus installation. If None, auto-discovery is used.

None
weather str | Path | None

Path to a weather file (.epw). Required by the Slab and Basement solvers.

None
timeout float

Maximum time in seconds for each subprocess invocation (default 120).

120.0

Returns:

Type Description
IDFDocument

A new IDFDocument with all

IDFDocument

preprocessing applied.

Raises:

Type Description
EnergyPlusNotFoundError

If no EnergyPlus installation is found.

ExpandObjectsError

If any preprocessor step fails.

Source code in src/idfkit/simulation/expand.py
def run_preprocessing(
    model: IDFDocument,
    *,
    energyplus: EnergyPlusConfig | None = None,
    weather: str | Path | None = None,
    timeout: float = 120.0,
) -> IDFDocument:
    """Run ExpandObjects and any required ground heat-transfer preprocessors.

    This is a convenience function that runs all needed preprocessors in
    a single call.  It runs ExpandObjects once, then checks which
    preprocessor input files were produced (``GHTIn.idf`` and/or
    ``BasementGHTIn.idf``) and runs the corresponding Fortran solvers.

    [simulate][idfkit.simulation.runner.simulate] calls this automatically
    when the model contains ground heat-transfer objects and
    *expand_objects* is ``True``.  Call it directly only when you need to
    inspect or modify the preprocessed model before simulation.

    Args:
        model: The EnergyPlus model to preprocess.
        energyplus: Pre-configured EnergyPlus installation.  If ``None``,
            auto-discovery is used.
        weather: Path to a weather file (``.epw``).  Required by the
            Slab and Basement solvers.
        timeout: Maximum time in seconds for each subprocess invocation
            (default 120).

    Returns:
        A new [IDFDocument][idfkit.document.IDFDocument] with all
        preprocessing applied.

    Raises:
        EnergyPlusNotFoundError: If no EnergyPlus installation is found.
        ExpandObjectsError: If any preprocessor step fails.
    """
    config = energyplus if energyplus is not None else find_energyplus()
    run_dir = _prepare_run_dir(model, weather=weather)
    try:
        _run_expand_objects(config, run_dir, timeout=timeout)

        if (run_dir / "GHTIn.idf").is_file():
            _run_slab_in_dir(config, run_dir, timeout=timeout)

        if (run_dir / "BasementGHTIn.idf").is_file():
            _run_basement_in_dir(config, run_dir, timeout=timeout)

        return _parse_expanded(run_dir)
    finally:
        shutil.rmtree(run_dir, ignore_errors=True)

needs_ground_heat_preprocessing

idfkit.simulation.expand.needs_ground_heat_preprocessing(model)

Return True if model contains ground heat-transfer objects.

Checks for GroundHeatTransfer:Slab:* and GroundHeatTransfer:Basement:* objects that require the Slab or Basement preprocessor before simulation.

This is used by simulate to decide whether to auto-run the preprocessing pipeline.

Source code in src/idfkit/simulation/expand.py
def needs_ground_heat_preprocessing(model: IDFDocument) -> bool:
    """Return ``True`` if *model* contains ground heat-transfer objects.

    Checks for ``GroundHeatTransfer:Slab:*`` and
    ``GroundHeatTransfer:Basement:*`` objects that require the Slab or
    Basement preprocessor before simulation.

    This is used by [simulate][idfkit.simulation.runner.simulate] to decide
    whether to auto-run the preprocessing pipeline.
    """
    return _has_slab_objects(model) or _has_basement_objects(model)

Error Handling

All three functions raise ExpandObjectsError on failure. The exception carries structured fields for programmatic access:

from idfkit.exceptions import ExpandObjectsError

try:
    expanded = expand_objects(model)
except ExpandObjectsError as e:
    print(e.preprocessor)  # "ExpandObjects", "Slab", or "Basement"
    print(e.exit_code)     # Process exit code, or None for timeout/OS error
    print(e.stderr)        # Captured stderr (truncated to 500 chars)

Error modes

Failure preprocessor exit_code stderr
Executable not found Name None None
Process timeout Name None Partial output
OS error (permissions) Name None None
Process crash (SIGSEGV) Name 139 Signal info
Empty output (solver failure) Name 0 Solver output
Fatal PreprocessorMessage Name 0 Error message
Missing output file Name Exit code Process stderr