NatLabRockies / NatLabRockies/OpenStudio

Feature request: warn at the SDK level when a Construction has an AirGap material as its outermost/innermost layer (EnergyPlus currently fails with a FATAL error, discovered only after translate + run)

Open
#5,630 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Triage
Dominant language
C++
Stars
646
Forks
237
Avg merge
3d 11h
Merged PRs (30d)
10

Description

Description
Summary

If a Construction's outermost layer (facing outdoors) or innermost
layer (facing the zone interior) is an OS:Material:AirGap, the model
translates to IDF without any warning, but EnergyPlus then fails with
a FATAL error very early in GetSurfaceData, well before any
useful diagnostics run:

** Severe  ** CheckAndSetConstructionProperties: Outside Layer is Air for construction EXTERIOR WALL
**   ~~~   **   Error in material F04 WALL AIR SPACE RESISTANCE
**  Fatal  ** GetSurfaceData: Errors discovered, program terminates.

EnergyPlus's own check (CheckAndSetConstructionProperties) already
knows this is invalid — but the OpenStudio SDK has no equivalent check
at authoring time (e.g. in Construction::setLayers, or as part of
Model.validityReport). Anyone building Construction objects
programmatically from an external material/layer list (import
pipelines, generative scripts, measures) can silently produce an
invalid model that only fails much later, after a full
translate-and-run cycle, with no indication of which construction or
why until they go digging in eplusout.err.

A warning (or a validityReport entry) raised directly when
setLayers is called with an AirGap in position 0 or position N-1
would let people catch this immediately, in their own script/measure,
instead of discovering it downstream in EnergyPlus.

Minimal reproduction (self-contained, no external files needed)

Built entirely from OpenStudio's own bundled example model — no
external geometry or project data involved. Python shown, same idea
applies in Ruby via OpenStudio::Model.exampleModel:

import openstudio

m = openstudio.model.exampleModel()
constructions = {c.name().get(): c for c in m.getConstructions()}
c = constructions["Exterior Wall"].to_Construction().get()

layers = list(c.layers())
# "F04 Wall air space resistance" is already an AirGap material in the
# example model, just correctly placed in the middle of the stack.
airgap = [l for l in layers if not l.to_AirGap().isNull()][0]
others = [l for l in layers if l.handle() != airgap.handle()]

# Move it to the front (outermost layer) -- this is what triggers the
# fatal error. No warning/error is raised at this point.
c.setLayers(openstudio.model.MaterialVector([airgap] + others))

m.save(openstudio.path("broken_airgap_outer.osm"), True)
ft = openstudio.energyplus.ForwardTranslator()
ft.translateModel(m).save(openstudio.path("broken_airgap_outer.idf"), True)

Then running that IDF through EnergyPlus (design-day only is enough,
no need for an annual run) with any weather file reproduces the fatal
error above.

Attached in eplus_airgap_repro.zip:

  • baseline_ok.idf / baseline_ok_eplusout.err — the unmodified
    example model, completes successfully (73 Warning, 0 Severe).
  • broken_airgap_outer.idf / broken_airgap_outer_eplusout.err — same
    model, only the "Exterior Wall" construction's layer order changed
    as shown above, fails FATAL.
  • USA_CO_Golden-NREL.724666_TMY3.epw — the weather file used (NREL's
    own standard sample EPW, bundled with the SDK/Application install).
Expected behavior

Either Construction::setLayers (C++ SDK) rejects/warns when an
AirGap-derived material ends up at index 0 or the last index, or at
minimum Model.validityReport(StrictnessLevel.Draft) (or equivalent)
flags it — so this shows up while authoring the model, not after a
full EnergyPlus run.

Actual behavior

No warning anywhere in the OpenStudio SDK (Ruby or Python) when
building/saving such a Construction, or during ForwardTranslator.
The only signal is EnergyPlus's own fatal error, several steps removed
from the actual mistake.

Versions
  • OpenStudio SDK (pip openstudio): 3.11.0
  • OpenStudio Application: 1.11.0-rc2
  • EnergyPlus: 25.2.0
Additional context

Ran into the EnergyPlus-side version of this while building an
external BIM → OpenStudio import pipeline: a construction whose layer
order came from imported data ended up with an air-gap layer at the
boundary, and the only symptom was this fatal error after a full
translate + run. Worth noting EnergyPlus's message itself is already
reasonably clear once you reach it (names the construction and the
offending material) — the gap is that nothing catches it earlier, at
the SDK level, for anyone assembling constructions programmatically.

by jmcaamanog

eplus_airgap_repro.zip

Current Behavior

No warning anywhere in the OpenStudio SDK (Ruby or Python) when
building/saving such a Construction, or during ForwardTranslator.
The only signal is EnergyPlus's own fatal error, several steps removed
from the actual mistake:

** Severe ** CheckAndSetConstructionProperties: Outside Layer is Air for construction EXTERIOR WALL
** ~~~ ** Error in material F04 WALL AIR SPACE RESISTANCE
** Fatal ** GetSurfaceData: Errors discovered, program terminates.

Expected Behavior

Either Construction::setLayers (C++ SDK) rejects/warns when an
AirGap-derived material ends up at index 0 or the last index, or at
minimum Model.validityReport (or equivalent) flags it -- so this shows
up while authoring the model, not after a full EnergyPlus run.

Steps to reproduce
  1. Take the OSM attached (broken_airgap_outer.osm.txt) -- it's
    OpenStudio's own bundled example model (openstudio.model.exampleModel()
    in the Python SDK / OpenStudio::Model.exampleModel in Ruby), with a
    single change: the "Exterior Wall" construction's layer order was
    modified so its AirGap material ("F04 Wall air space resistance",
    already present in the unmodified example model) is now the
    outermost layer instead of the middle of the stack.

  2. No warning or error appears when building/saving this model, nor
    when running it through the ForwardTranslator to IDF.

  3. Run the resulting IDF through EnergyPlus with any weather file
    (design-day-only is enough, no need for a full annual run) -- it
    fails FATAL during GetSurfaceData (see Current Behavior above).

  4. For contrast, baseline_ok.osm.txt is the exact same model with the
    layer order untouched -- it completes successfully (73 Warning, 0
    Severe).

Minimal code used to produce the difference (Python; same idea with
OpenStudio::Model.exampleModel in Ruby):

import openstudio

m = openstudio.model.exampleModel()
constructions = {c.name().get(): c for c in m.getConstructions()}
c = constructions["Exterior Wall"].to_Construction().get()

layers = list(c.layers())
airgap = [l for l in layers if not l.to_AirGap().isNull()][0]
others = [l for l in layers if l.handle() != airgap.handle()]

# Moves the air gap to the front (outermost layer) -- no warning
# raised here, but this is what makes EnergyPlus fail fatally later.
c.setLayers(openstudio.model.MaterialVector([airgap] + others))
Possible Solution

No response

Operating System affected

Windows 11

Environment

OS: Windows 11 Home, build 10.0.22631 (x86_64)
OpenStudio SDK: 3.11.0 (Python bindings, pip install openstudio)
Python: 3.13.14
EnergyPlus: 25.2.0-cf7368216c

Version of OpenStudio

3.11.0

Context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Construction::setLayers and Model.validityReport, using the provided exampleModel reproduction to follow how an AirGap reaches the outermost or innermost layer. Compare the SDK behavior with the ForwardTranslator path and EnergyPlus failure described in the issue. Done means the invalid boundary placement is reported during SDK authoring or model validation, before translation and execution.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python, ruby
Domain
api
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.