Convert2IDF output¶
Status: Provisional (ADR-010, realisation pending the owner's reading); program fields, single-sided thermostats, and the calendar-based run period since D-126 (ADR-018); EnergyPlus 26.2, the weather file, the research outputs, the ground temperatures, and the site record since D-130 (the stage note) · Since: S6 (version 0.9.0, D-113) · Component: Convert2IDF (
2IDF), panel 5 Convert, GUID56dd6611-90b2-4299-b53c-650652843a1a· Code:Lod.Export.Idf(src/Lod.Export/Idf/)
Purpose¶
Convert2IDF is the second converter of the pipeline (D-020). It writes an EnergyPlus 26.2 input file (IDF) from an IGeneratedBuilding and an envelope preset, as ADR-010 specifies, ready to simulate with the weather file it names (D-130, the stage note). The converter does not run EnergyPlus: a run is not a pipeline step. Correctness is checked by reading the file back (see Tests).
Lod.Export is a plain C# library (netstandard2.0) that depends only on Lod.Core, never on RhinoCommon or Grasshopper (AGENTS.md). Its tests (tests/Lod.Export.Tests) run with dotnet test.
Interface¶
Result<IdfDocument> result = new IdfWriter(ToleranceSettings.Default)
.Write(building, ExampleEnvelopePresets.Example, new IdfOptions(new HeatTransferOptions(false, false)));
string idf = result.Value.ToText();
| Type | Role |
|---|---|
IdfWriter |
Write(building, envelope, options): validates the building, then builds the document; returns Result<IdfDocument> with diagnostics. Write(building, constructions, options) takes a ConstructionSet instead (D-137, Construction sets); an envelope preset is written as the set ConstructionSet.FromEnvelope(envelope), which gives exactly the text the preset alone gave. |
IdfOptions |
HeatTransfer (HeatTransferOptions, D-069, both off by default), OverrideValidation (default false), FirstDayOfYear (weekday of 1 January of the schedules; unset by default, which takes it from the building's calendar, else Monday, as every example preset; a weekday given here must agree with the calendar, D-126), Weather (IdfWeather?, the weather file the IDF is written for, D-130; none by default). IdfOptions.Default has all defaults. |
IdfDocument |
Header (comment lines), Objects (typed objects in file order), ToText() (the IDF text with \n line ends). |
IIdfObject and the Idf… records |
One typed record per EnergyPlus class (IdfZone, IdfBuildingSurface, IdfScheduleYear, …), each giving its fields in EnergyPlus 26.2 order. |
IdfDefaults |
Every modelling default of the writer, in one place (table below). |
Convert2Idf |
Run(building, envelope, options, file, weatherPath): the service behind the component. Reads the weather file when weatherPath is given (fully qualified, as the IDF path; otherwise InvalidParameter; unreadable or malformed: InvalidWeatherFile; either gives no text), validates once, writes the document, saves it with IdfFile when IdfFileRequest.Write is set, and returns IdfConversion (text or null when blocked, provenance, whether the file was written, all diagnostics). |
IdfWeather |
FromBytes(fileName, bytes): the weather file's header (EpwHeader), its file name, and the SHA-256 of its bytes (64 lower-case hexadecimal digits), so that the IDF records the file it was written for (GLOBAL.md scientific rule 2). |
IdfFile |
Save(path, text, overwrite): UTF-8 without a byte-order mark, only to an absolute path in an existing folder (the folder is not created), never over an existing file unless overwrite. |
EpwHeader |
Parse(text): the header of an EnergyPlus weather file (D-130), read from text so that tests need no file: the LOCATION line (EpwLocation: city, state or province, country, source, WMO number, latitude, longitude, time zone, elevation), the GROUND TEMPERATURES line (EpwGroundTemperatures: each depth and its twelve monthly values), and a check of the DATA PERIODS line that the data are hourly. Only the first eight lines are read. A missing or short line, a field that is not a number, a location outside the limits of Site:Location in the 26.2 IDD (latitude ±90°, longitude ±180°, time zone −12 to +14 h, elevation −300 m to below 8900 m), or data that are not hourly is the error InvalidWeatherFile, naming the line and the field. |
IdfFormat |
Number formatting: invariant culture, fifteen significant digits (G15), 0 for negative zero. Fifteen digits are formatted identically by .NET Framework 4.8 and .NET 8 (the round-trip format R is not), and the rounding, at most 5e-15 relative, is far below every tolerance of ToleranceSettings. |
Component¶
Convert2IDF (2IDF) in panel 5 Convert is a thin adaptor over Convert2Idf (GLOBAL.md architecture rule 3): it reads its inputs, runs the service, shows every diagnostic as a runtime message (errors, warnings, info as remarks), and sets its outputs. The component does not run EnergyPlus.
| Index | Input | Nickname | Access | Content |
|---|---|---|---|---|
| 0 | Building | Bldg | item | An IGeneratedBuilding from a floor aggregator. |
| 1 | Envelope | Env | item, optional | An envelope preset, for example from Envelope Preset; the illustrative ExampleEnvelopePresets.Example when neither it nor Construction is connected; connecting both is an error. A connected input that yields no envelope preset (for example from an Envelope Preset with an error) also falls back to the example, with the warning Envelope is connected but yields no envelope preset; the Example Envelope is used instead. |
| 2 | EnableInternalWallHeatTransfer | IWHT | item | Boolean, default false (D-069): walls between zones paired, else adiabatic between two conditioned zones and paired where a zone has no HVAC (D-211). |
| 3 | EnableFloorHeatTransfer | FHT | item | Boolean, default false (D-069): floors and ceilings between zones paired, else adiabatic between two conditioned zones and paired where a zone has no HVAC (D-211). |
| 4 | Override | Ovr | item | Boolean, default false: convert even if legacy production validation fails; recorded in Provenance and in the IDF header. Cannot bypass the additional floor research gate when input 11 is true. |
| 5 | Path | P | item, optional | Fully qualified path of the IDF file (a drive letter and a separator, or a UNC path \\server\share\…), in an existing folder; used only when Write is true. Drive-relative (C:model.idf) and root-relative (\model.idf) paths are rejected (InvalidParameter), because they depend on the process's current folder. |
| 6 | Write | W | item | Boolean, default false: write the file; when false nothing is written. |
| 7 | Overwrite | O | item | Boolean, default false: replace an existing file; when false the existing file is kept and the error FileExists is shown. |
| 8 | Weather | Wthr | item, optional | Fully qualified path of an EnergyPlus weather file (.epw), appended in D-130: its location becomes Site:Location, and its name and SHA-256 are recorded (Weather). A construction set with an F-factor ground takes its Site:GroundTemperature:FCfactorMethod from the file's monthly mean dry-bulb (Native ground, D-145). Unset: no Site:Location and the info NoWeatherFile, and such a set is refused with GroundTemperatureWeatherMissing. A path that is not fully qualified is InvalidParameter, a missing, unreadable, or malformed file InvalidWeatherFile; either gives no IDF text and writes nothing. A definition saved before the input existed opens with it unset and without Grasshopper's IO dialog (the appended-parameter guard of D-126, ComponentSupport.ReadWithAppendedParameters). |
| 9 | Construction | Cons | item, optional | A construction set from Construction JSON, appended in D-137, used instead of Envelope (Construction sets); connecting both is an error. Its ground floors take the set's own ground method: F-factor floors on GroundFCfactorMethod, which need Weather, or layered ground at 18 °C every month; a Kiva or C-factor ground is GroundMethodNotSupported (Native ground). A connected input that yields no set (a Construction JSON with an error) stops the conversion with an error; it never falls back to the Example (ComponentSupport.Constructions). Override covers only a failed validation, not a failed or conflicting set. Like any item input, several sets on it convert once each. Opens unset in definitions saved before it. |
| 10 | Fill From Example | Fill | item | Boolean, default false, appended in D-140: a role or window the Construction set lacks but the building needs takes the Example envelope's construction with a warning; when false it is the error ConstructionMissing. No effect on an envelope preset. |
| 11 | Require Floor Research Eligibility | FloorCheck | item | Boolean, default false. Require source floors to preserve spatial conditioning, enabled thermostat sides, full-year control values and complete geometric source mapping. Missing/failed floors block writing even with Override. This is floor control/mapping scope only; it does not certify vertical/whole-building geometry, contacts, realized glazing, orientation or native thermal equivalence. See the reference contract. |
| 12 | Daylighting | Dayl | item | Boolean, default false, appended in D-233: write each zone's daylighting controls from its program at the reference points the 90.1 code rule places on the zone's own windows and skylights (Daylighting); when false no daylighting object is written, the LOD study's setting. |
| 13 | Lighting Cap | LCap | item | Boolean, default false, appended in D-256: write each zone's unoccupied lighting cap from its program as an EMS program (Unoccupied lighting cap); when false no EMS object is written, the LOD study's setting. |
| Index | Output | Nickname | Content |
|---|---|---|---|
| 0 | IDF | IDF | The IDF text; empty when the conversion is blocked. |
| 1 | Provenance | P | The building's provenance tree, the validation report, then OPTIONS: …, ENVELOPE: <preset name> or CONSTRUCTION SET: <set name>, INFILTRATION: <rate> <basis> (EnergyPlus <method>), schedule <name> (D-124), ENERGYPLUS: 26.2, WEATHER: <file name> sha256 <hex>; <location> or WEATHER: none given (…) or WEATHER: not read (see the error), GROUND: <rule>; <twelve values> (D-130; for a packet v7 construction set one line per ground temperature object written, or GROUND: not written (see the error), D-145), UNUSED: <components> (no geometry in BEMGen) for a construction set (D-145), SHADING: <count> surfaces of <n> unmodelled storeys (L<k>, …), <area> m² or SHADING: none (every storey is modelled) (the shading surfaces of unmodelled storeys, below), DAYLIGHTING: not written (option off, the default); … or DAYLIGHTING: written for k of n zone(s) … when the building's programs carry daylighting controls (D-233), OVERRIDE: converted despite failed validation when Override was used on a failed validation, and FILE: written <full path> or FILE: not written (<reason>) (Write is false, the file exists, the conversion was blocked, or see the error). Set on every solve that has a building. |
| 2 | Written | Wr | Whether the file was written in this solution. |
A file is written only when Write is true, Path is fully qualified and its folder exists, and the file does not exist or Overwrite is true; otherwise the error InvalidParameter, FileWriteFailed, or FileExists is shown, Written is false, and the IDF text is still output. Keep Write false while editing a definition: every solve with Write and Overwrite true rewrites the file.
Validation gate¶
BuildingValidator (with the writer's tolerances) runs first (GLOBAL.md scientific rule 6). A failed enforced check returns the error ValidationFailed, naming the failed checks, and no document. With OverrideValidation the file is written, the warning ValidationOverridden is returned, and the header records Validation: FAILED, every failed check (FAIL <check>: <detail>), and OVERRIDE: converted despite failed validation.
File layout¶
Every object is written at least up to its \min-fields in the EnergyPlus 26.2 IDD, the fields BEMGen does not set holding the IDD defaults explicitly (for ZoneHVAC:IdealLoadsAirSystem: no humidification, no outdoor air, no economizer, no heat recovery). Objects are written in a fixed order, each with one field per line and its field name as a comment (hourly values six to a line, a vertex's three coordinates on one line):
- Header comments: code version (
BuildInfo.InformationalVersion), the EnergyPlus version (26.2) and the weather file the IDF was written for, or that none was given, the weather record (Weather: …, D-130), the envelope preset, its infiltration (D-124; for exampleInfiltration: 0.3 AirChangesPerHour (EnergyPlus AirChanges/Hour), schedule Example Always On), the heat-transfer options, the four lines of the site record, the first day of the year, the calendar (D-126;none (BEMGen presets; run period 2007, 1 January a Monday)or, for example,2007 (1 January a Monday), holidays 01-01, 12-25), the ground temperatures (Ground temperatures: …, D-130), the validation result, the building's provenance tree, every zone with its multiplier and source zones (GLOBAL.md scientific rule 2), and the shading of unmodelled storeys (Shading: …, the text of the provenance lineSHADING:). Version(26.2),SimulationControl(no sizing, no HVAC sizing simulation; run on the weather-file run periods only; no design days are written),Building,Timestep(6),RunPeriod,GlobalGeometryRules,Site:Locationwhen a weather file is given (see Weather),Site:GroundTemperature:BuildingSurface(for a packet v7 construction set,Site:GroundTemperature:FCfactorMethodwith F-factor ground,Site:GroundTemperature:BuildingSurfaceat 18 °C with layered ground, Ground temperatures). A set'sConstruction:FfactorGroundFloorobjects follow its other constructions.ScheduleTypeLimits(BEMGen Fraction0–1,BEMGen Temperatureunbounded, and when neededBEMGen Activity Level, not negative, andBEMGen Control Type0–4),Schedule:Constant(the default activity levelBEMGen Activity Levelwhen a program uses it, and one control type schedule for each kind of thermostat used), then each schedule as its day, week, and year objects, in order of first use (zone by zone, loads before setpoints).- The opaque materials, each by its kind (
Material,Material:NoMass,Material:AirGap), then the window's materials (WindowMaterial:SimpleGlazingSystem, or eachWindowMaterial:GlazingandWindowMaterial:Gasonce), thenConstruction: only those used, in the envelope preset's order, then the slices of the removed slabs' construction ({name} Half, below). A layer without a roughness isMediumRough; its absorptances are written up to the last one given, blanks before it meaning EnergyPlus's defaults, and none when none is given. A simple glazing without visible transmittance leaves the field out, so EnergyPlus calculates it. The window construction is named after the window: a simple glazing's construction has the glazing as its one layer, a layered window's lists its glass and gas layers from the outside in. Zone, in building order.BuildingSurface:Detailedin building surface order (the pieces of a split surface one after another), thenFenestrationSurface:Detailed(wall windows and roof skylights in the order of their host surfaces), thenInternalMass(removed slabs, each exposed face a half slice of the slab, then a construction set's added masses), thenSurfaceProperty:IncidentSolarMultiplier(a construction set's, one per window), thenShading:Building:Detailed(the shading surfaces of unmodelled storeys).- Loads, zone by zone in program order, each zone's
ZoneInfiltration:DesignFlowRatefrom the envelope after its program loads (D-124); then, for every conditioned zone,ZoneControl:Thermostat, itsThermostatSetpoint:DualSetpoint,ThermostatSetpoint:SingleHeating, orThermostatSetpoint:SingleCooling(D-126),ZoneHVAC:IdealLoadsAirSystem,ZoneHVAC:EquipmentList, andZoneHVAC:EquipmentConnections. - The research outputs (
IdfOutputs.Research, D-130; see Outputs):Output:VariableDictionary,Output:SQLite,OutputControl:Table:Style,Output:Table:SummaryReports,Output:Surfaces:ListDetails,Output:Variable(hourly: every zone, and every ground-contact surface by name), andOutput:Meter(hourly, each only when the building uses it).
The same building, envelope, and options always give the same text.
Site record¶
Four header lines identify the site (experiment outputs §7, D-130), so that the record travels with the file: the EnergyPlus runner reads them back by these exact prefixes (IdfSiteRecord). Each is one line, deterministic, and free of code versions (the code version has its own header line); no other header line starts with Site.
| Line | Content |
|---|---|
Site building: floors P1x1,P1x2,P1x1; P1=[…] |
What identifies the building before zoning, from its provenance: each floor entry of the building in order, as its plan's number and its count, then each distinct plan, numbered in order of first use, as its provenance tree on one line: the generator or transform with its parameters (and seed, where a generator has one), the provenance of its inputs in braces. For example floors P1x1,P2x1,P1x1; P1=[LinearPlanGenerator CorridorWidth=2 …]; P2=[TransformPlan … {LinearPlanGenerator …}]. Every zoning of one building has the same line. |
Site zoning: simplifier …; aggregator …; IWHT=… FHT=… |
The distinct simplifiers of the floors with their parameters, the floor aggregator with its parameters except Multipliers and Storeys (which follow from the floors of the building line, so every building shares the zoning line of one configuration), and the heat-transfer options as true or false. For example simplifier PerimeterCore PerimeterDepth=4.57; aggregator SingleZonePerFloorType; IWHT=true FHT=true. |
Site weather: <file name> sha256 <hex> |
The weather file and the SHA-256 of its bytes (64 lower-case hexadecimal digits), or Site weather: none. |
Site envelope: <name> |
The envelope preset's name. |
Names¶
Names come from zone and surface IDs (L0/US1, L0/US1/W1); a split surface's pieces are <id>#1, <id>#2, … (a floor or ceiling split for its holes and then into convex pieces is numbered on across both splits); shading surfaces S<k>/<wall ID>, with k the storey's index in the assembled stack; windows <wall>/Win<k>; loads <zone> <LoadType> <LoadBasis>, or <zone> <LoadType> <end use> <LoadBasis> when the zone holds more than one end use of that type (D-126); infiltration <zone> Infiltration <InfiltrationBasis>; internal masses <zone> Internal Mass <k>; HVAC objects and nodes <zone> Thermostat, <zone> Ideal Loads, <zone> Supply Inlet, …; schedules keep their names, with Day <k> and Week <k> for their parts. Names are unique within each group in which EnergyPlus compares them, ignoring case (zones; surfaces, windows, internal masses, and shading surfaces together, EnergyPlus's AllShadingAndHTSurfNames; schedules; …): IDF's reserved characters (, ; !) become _, a name longer than 100 characters keeps its start and ends with ~ and an FNV-1a hash of the whole name, and a name already taken gets ~2, ~3, ….
Weather¶
A weather file (EPW) is given to Convert2Idf.Run as a path, or to the writer as IdfOptions.Weather (D-130). The writer reads only its header (EpwHeader) and passes nothing else on: the file itself is given to EnergyPlus when it runs.
- With a weather file, the IDF holds
Site:Locationfrom theLOCATIONline, named<city> <state or province> <country>(the empty parts left out, under the name rules), with its latitude, longitude, time zone, and elevation (the five fields of the IDD minimum). The header saysEnergyPlus 26.2 input file, written for the weather file <file name>.and recordsWeather: <file name>, SHA-256 <hex>; <city>, <state>, <country> (<source>, WMO <number>), latitude …, longitude …, time zone …, elevation … m. Provenance gainsWEATHER: <file name> sha256 <hex>; <the same location>. - Without one, there is no
Site:Location, EnergyPlus takes the location from the weather file it runs with, the header says so and recordsWeather: none, provenance recordsWEATHER: none given (EnergyPlus takes the location from the weather file it runs with), and the infoNoWeatherFileis returned. - The climate zone of the weather (D-213).
Convert2Idf.Runalso reads the weather file's companion.statfile, the file of the same name with the extension.statnext to it, when there is one, and takes the ASHRAE climate zone it states (- Climate type "5A" (ASHRAE Standard 196-2006 Climate Zone)**,EpwStat); older.statfiles state only the Köppen classification and give none. The header then recordsWeather climate zone: <zone> (ASHRAE, from <file name>.stat)after theWeather:line. - No simulation with an unresolved climate (D-213, the owner's rule). A program imported without a climate zone whose values differ by climate zone (loads, schedules, window ratios, daylighting by climate) records
ClimateZone.Unresolvedin its preset's provenance (ClimateResolution). The writer walks the building's provenance and refuses such a building with the errorClimateZoneUnresolved, naming each program and what differs, and, when the.statfile states one, the zone to give Program JSON's or the DOE Programs component's Climate Zone; Override does not apply. The zone cannot be taken at conversion instead: a window ratio by climate has already shaped the generated windows, and a merged zone's loads have already been aggregated. A building whose programs were resolved for another zone than the.statfile's gets the warningClimateZoneDiffersFromWeatherand is written as resolved. - The run period stays the building's calendar (Schedules): EnergyPlus reads the weather file's hours in order whatever years it records. No sizing:
SimulationControlkeeps sizing off and no design days are written, because the ideal loads have no capacity limit (D-112).
Outputs¶
The outputs follow Experiment outputs, which fixes what each site must yield and from which EnergyPlus output each quantity comes. They are one named set, IdfOutputs.Research (IdfOutputSet: its keys, frequency, surface reports, zone and ground-surface variables, and meters with the source each needs), so that a later selectable set needs no new mechanism; the set is not a component input. They are written after the HVAC objects, in this order:
Output:VariableDictionaryIDF, so that a reader can see what is available, andOutput:SQLiteSimpleAndTabular.OutputControl:Table:StyleCommaAndHTMLandOutput:Table:SummaryReportsAllSummary(the Building Area table with the total and net conditioned area, the zone summary, and the hours a setpoint is not met).Output:Surfaces:ListDetails, so thateplusout.eiolists every surface with its zone (theZone Surfacesline before it) and its outside boundary (ExtBoundCondition), from which the runner finds the ground surfaces (experiment outputs, ground heat transfer).Output:Variablewith key*atHourly:Zone Mean Air Temperature, always; and, when some zone is conditioned,Zone Ideal Loads Zone Sensible Heating EnergyandZone Ideal Loads Zone Sensible Cooling Energy(the raw outputs of the paired evaluation metrics, experiment outputs §10, D-156), andZone Ideal Loads Zone Total Heating EnergyandZone Ideal Loads Zone Total Cooling Energyas diagnostics. The writer leaves the ideal loads' availability schedules blank, so their conditioning is available every hour.Output:VariableSurface Inside Face Conduction Heat Transfer EnergyatHourly, one per ground-contact surface, keyed by the surface's name, in surface order: everyBuildingSurface:Detailedwritten onGroundorGroundFCfactorMethod(IdfBoundaries.IsGround), and no other. Keying by name, not*, keeps the.esosmall; paired, adiabatic, and outdoor surfaces are not requested. Every building has ground floors (ADR-010), so the requests are unconditional.Output:MeteratHourly, only for what the building uses, because EnergyPlus warns about a meter with nothing on it:
| Meters | Written when |
|---|---|
Heating:DistrictHeatingWater, Cooling:DistrictCooling, Heating:EnergyTransfer, Cooling:EnergyTransfer, DistrictHeatingWater:Facility, DistrictCooling:Facility |
some zone is conditioned |
Electricity:Facility |
some zone has lights or electric equipment |
InteriorLights:Electricity |
some zone has lights |
InteriorEquipment:Electricity |
some zone has electric equipment |
NaturalGas:Facility, InteriorEquipment:NaturalGas |
some zone has gas equipment |
WaterSystems:DistrictHeatingWater, DistrictHeatingWater:Facility |
some zone uses hot water |
A meter listed twice (DistrictHeatingWater:Facility) is written once, where it first applies. Whether a building uses a source is read from the objects written: an ideal-loads system, Lights, ElectricEquipment, GasEquipment, WaterUse:Equipment.
Ground temperatures¶
A building converted with an envelope preset, or with a construction set without foundation data, has the rule below (D-130), unchanged. A packet v7 construction set's native ground has its source's rules instead (below, D-145).
Site:GroundTemperature:BuildingSurface holds the rule "indoor minus 2 °C" (D-130; the owner's decision of 2026-10-11, the EnergyPlus documentation's rule of thumb for large slabs), computed by GroundTemperatureRule:
- T_g,m = T_in,m − 2 °C for each month m.
- T_in,m is the mean over the hours of month m, on the run calendar (hour 0 is 1 January of the non-leap run year), of the building's hourly setpoint: the mean over the conditioned zones weighted by floor area × multiplier. A zone's hourly setpoint is the midpoint of its heating and cooling setpoints where it has both, and the one it has otherwise.
- A building without a conditioned zone, or whose conditioned zones have no floor area (the zero-denominator guard), uses T_in = 20 °C, and so 18 °C, the value used before, with the info
GroundTemperatureDefault. - The envelope's ground-floor construction is kept, so both converters describe the ground floor alike. The weather file's own ground temperatures are read (
EpwHeader) but not used: the F-factor method that would use them waits for a sourced F-factor (D-023, the stage note's Part B.4). - The header records the rule and the twelve values (
Ground temperatures: indoor minus 2 C, …; January to December: …), and provenance the lineGROUND: indoor minus 2 C; <twelve values>(orGROUND: no conditioned zone, so 20 C indoor minus 2 C; …).
Native ground of a construction set (D-145)¶
A packet v7 set carries its foundation data (ConstructionSet.Foundation). Its ground floors take the set's own GroundFloor component, not the Example's ground floor (D-137 is superseded for such sets); ConstructionSet.Resolve gives the recipe as ResolvedConstructions.Ground (NativeGroundFloor).
- Matching. The physical boundary is matched before an IDF boundary is chosen: the one assignment whose
whencovers a floor on the ground at building-default scope (scopebuilding_default, boundary conditionGroundor none, and no space type, storey, window operation, or thermal host, which BEMGen cannot evaluate), or a unified recipe without a condition. - No covering assignment, or a
GroundFloorthe source marks not applicable (such asno_direct_ground_contact), is the errorConstructionMissing; with Fill From Example the ground floors take the Example's construction with the warningConstructionFromExample, and the ground temperatures are then D-130's. It is never silent. - A blocked
GroundFloorisConstructionBlocked. - Any other assignment of the component beside the covering one, whose condition BEMGen cannot evaluate (such as a
space_typerule), is set aside with the warningGroundAssignmentSetAside, which names the rule and its condition: every ground floor takes the building-default recipe, never silently. - A method the pipeline cannot place is
GroundMethodNotSupported, with or without Fill From Example:Kivaneeds foundation groups (a slab coupled to its foundation walls) andCFactorwalls below grade, neither of which BEMGen's geometry has; so are an assembly that does not fit its method and two assignments that cover the same ground. No building-scope packet set reaches these; the tests use modified documents. - F-factor (
FFactorwith anFFactorGroundFloorConstruction). Each written piece of a ground floor (a floor with holes is split into hole-free pieces, as before; ground surfaces are never split into convex pieces) takes aConstruction:FfactorGroundFloorwith the set's F, the piece's own area, and its exposed perimeter, on the boundaryGroundFCfactorMethod. - Exposed perimeter (
ExposedPerimeterinLod.Core.Conversion): the length of the piece's edges that no other ground piece of the same level shares. An edge is shared where another polygon's edge lies on it within the distance tolerance, measured at both ends of the stretch where they overlap, and only over that length, so a partial shared segment cancels by its length and an edge met by several neighbours cancels each part. Measuring where they overlap, not at the neighbour's far corners, lets a cut that a hole split leaves on the clipping grid cancel against a long neighbour's edge on a turned plan. The edges of an enclosed court count, since they face outdoors; a hole another floor fills does not. Zero is allowed (a core zone) and no positive minimum is ever added. The building's total is the footprint's outer and court perimeter on every zoning, so splitting and rejoining zones keeps it. - Area and perimeter are those of the actual surface. A zone multiplier repeats the surface as EnergyPlus repeats the zone; nothing is scaled in the construction.
- Next to the copy space of multiplied rooms (DOE geometry stage P5a, S8) the copies stand, so the ground storey's copy space
(
ExposedPerimeter.GroundCopySpace, the bottom floor entry's) is a neighbour: an edge toward it is not exposed, and only the edges on the plate's outline are, which EnergyPlus multiplies by the zone multiplier as the copies' own outer edges. - One construction is written per distinct (F, area, perimeter) as written, named by its values (
F-factor Ground Floor F <F> A <area> P <perimeter>); surfaces share one only when all three are equal, never because they share an assembly or method ID. Site:GroundTemperature:FCfactorMethod: the weather file's monthly mean dry-bulb (EpwDryBulb, field 7 of each hourly record grouped by its month), delayed three months so that January takes October's mean (OpenStudio Standards'rotate(-3)of the STAT file's monthly dry-bulb, computed from the EPW's hours since BEMGen takes no STAT file), each rounded to 0.1 °C with halves away from zero. For Chicago O'Hare TMY3 the monthly means are −4.6, −2.5, 3.8, 10.0, 15.3, 21.1, 24.1, 21.8, 18.1, 11.0, 4.7, −3.7 °C (the STAT file's daily averages), so January to December are 11.0, 4.7, −3.7, −4.6, −2.5, 3.8, 10.0, 15.3, 21.1, 24.1, 21.8, 18.1 °C.- Without a weather file, or with one whose hourly records do not give every month (a missing dry-bulb, 99.9, is not filled in), the set is refused with
GroundTemperatureWeatherMissing. - Layered ground (
LayeredGroundwith anative_opaque_layersassembly): the assembly's layers, the document's materials by ID, through the ordinary layered path, onGround. A material named Adiabatic is a finite resistance, not a boundary.Site:GroundTemperature:BuildingSurfaceis 18 °C in every month, the source's effective condition: EnergyPlus's default, which the source's prototypes ran with, since OpenStudio Standards writes no such object when it finds the STAT file. - Records. The header names the ground floor's source in its role lines (
GroundFloor: F-factor <F> W/m-K (assembly … by FFactor method …; …)orGroundFloor: <assembly> (assembly … by LayeredGround method …, on Ground)) and gives oneGround temperatures:line per object written, with its rule and twelve values; provenance gives the matchingGROUND: FCfactorMethod, monthly mean dry-bulb of <file> delayed three months, rounded to 0.1 C; …orGROUND: BuildingSurface, 18 C every month, the source's effective condition (…); …. A building without ground floors writes no ground temperature object for such a set. - Unused roles.
FoundationWall,FloorOverFoundation, andRimJoisthave no BEMGen geometry: those the source provides are listed with the set's other unused components in the header (Unused components (no geometry in BEMGen): …) and in provenance (UNUSED: … (no geometry in BEMGen), for every construction set).GroundFlooris never listed for a set imported by Construction JSON: every building has ground floors, which take it or refuse it. - Mass. Ground floors and their soil are not represented interior capacity and get no restoration (
ConstructionMassAccountingcounts only interior walls, the floor sides of slabs between storeys, and removed slabs); the shared mass contract's other rules are unchanged. - Wall vertices. Walls start at their top start corner and run down first (
UpperLeftCorner, counter-clockwise), so a wall's first edge is vertical with its true height, as EnergyPlus's C-factor height inference needs; a writer test checks a 6 m × 2 m wall.
Foundation objects outside the pipeline (construction foundation v7, Part D)¶
IdfFoundations.Write(FoundationModel) (Lod.Export) writes Part B's instances (FoundationInstantiator, FoundationModelScope.Combine) as EnergyPlus 26.2 objects for geometry a caller builds; Convert2IDF does not use it, since BEMGen's geometry has no foundation walls or foundation groups (D-145). It gives the objects and, per surface, an IdfFoundationPlacement (construction, reversed construction of a Surface boundary, boundary, Foundation:Kiva name, Kiva group):
Construction:FfactorGroundFloorper distinct (F, area, perimeter) andConstruction:CfactorUndergroundWallper distinct (C, height), named by their values, onGroundFCfactorMethod; layered definitions as aConstructionnamed after the first assembly that gives them, with their materials by ID, onGround(layered ground) or the declared boundary (Outdoors,Surfacewith the reversed construction for the partner face,Adiabatic);- one
Foundation:Kivaper Kiva instance, never shared between groups: the instance's initial temperature (Initial Indoor Air Temperature), insulation placements and their materials, wall height above grade, wall depth below slab, footing, and custom blocks; its slab'sSurfaceProperty:ExposedFoundationPerimeter(TotalExposedPerimeter); and oneFoundation:Kiva:Settingswith the soil's physics and the solver settings; the footing wall construction is left blank, since no packet method gives one, so a slab without walls takes EnergyPlus's<Default Footing Wall Construction>; - the model's
Site:GroundTemperature:FCfactorMethodandSite:GroundTemperature:BuildingSurfacerequests as given.
What EnergyPlus cannot hold is FoundationNotWritable, never repaired: a Kiva group with more than one slab (one floor per Foundation:Kiva), a Kiva layer, insulation, or block that is not a regular Material, more than ten custom blocks, a placement missing a depth or width the object needs, a material ID or name with two payloads, a surface ID that is not a valid IDF name, or a Kiva slab without an exposed perimeter. The importer-generated EnergyPlus runs (FoundationEndToEndTests, opt-in) and their results are in the stage's build log, Part D.
Across levels of detail (the owner, 2026-10-11). The mapping from the zones' setpoints to the ground temperature is fixed, and that is all the rule promises. Its result follows each zoning's own zones and their merged setpoints, so it may differ between zonings; that difference is one of the effects the study characterises, not a defect. Merges weight setpoints by floor area over the conditioned sources (ADR-005, ADR-018), and a merge that conditions an unconditioned zone gives it the merged setpoint. The tests check that the canonical linear plan (every conditioned program at 21 and 24 °C) gives the same twelve values under every simplifier and aggregator, within the central schedule tolerance, and so does the same plan with the dwellings at 20/26 °C and the corridor at 16/28 °C under every simplifier but Perimeter Core. Two cases differ, both found in the build and kept as characterisations:
- Perimeter Core with programs of different setpoints. It splits the unconditioned stair among perimeter zones, each of which takes the setpoint of its own conditioned sources over its whole floor area, so the stair's area is weighted with local setpoints instead of the building's mean. With the 20/26 and 16/28 °C presets, January's ground temperature is 20.880 °C under Perimeter Core against 20.889 °C in the reference (
IdfGroundTemperatureTestskeeps this as a characterisation). - A merge of zones with different sides, as the stage note foresaw: with the extended programs of
IdfExtendedProgramMatrixTests(a heating-only corridor), every merge that joins it with the dual-setpoint dwellings gives a January ground temperature of 20.889 °C against 20.444 °C in the reference, because the merged zone's heating setpoint averages over both programs and its cooling setpoint over the dwellings only.
Geometry¶
- Coordinates. Vertices are the building's own coordinates in metres, the same as the pipeline's and Convert2BEM's plan frame.
GlobalGeometryRulesuses relative coordinates with every zone origin at 0 and no zone rotation, so the coordinates are used as they are, andBuildingNorth Axis is the building's orientation (IGeneratedBuilding.OrientationDegrees, the clockwise rotation of plan north from true north). EnergyPlus therefore sees the same true azimuths as validation does. - Vertex order. Counter-clockwise seen from outside the zone, starting at the upper-left corner (D-091): a wall from its top start corner (the wall runs with its zone on the left, so its outside faces right); a ceiling or roof seen from above from its northernmost, then westernmost vertex; a floor seen from below from its northernmost, then easternmost vertex. Floors face down, ceilings and roofs up, walls and windows out of their zone.
- Surface types. Walls are
Wall; floorsFloor; ceilingsRoofwhen they face outdoors (roofs and terraces, ADR-015), otherwiseCeiling. - Zones. Every zone states its multiplier, volume, and floor area (one instance) instead of letting EnergyPlus compute them; a zone spanning storeys (Single Zone per Floor Type, Single Zone Building) has no surface for the slabs inside it. A zone of several pieces on one storey (Semantic Merge or Conditioned Merge with Join Pieces true, D-123) is one
Zoneas well: its floor area and volume are the sums over its pieces, and it holds the surfaces of every piece, the walls numbered on across the pieces and one floor and one ceiling per piece (<zone>/F1,<zone>/F2, …). EnergyPlus takes a zone as a set of surfaces and as one air volume, so the air of the pieces is one volume there. The writer needed no change for this. - Coplanar merge (D-191, ADR-034). Before anything is split, paired, or named, a zone's floors, ceilings, and roofs of one kind, elevation, boundary, and adjacent zone are merged pairwise in building order while two of them have a union that is one simple ring without holes and of their summed area (
IdfSurfaceMerge,IdfPolygons.Merge): pieces that touch only at a vertex, overlap, or would enclose a court stay apart, and pieces toward different zones never merge. An interzone group merges only together with its mirror in the adjacent zone, piece for piece, so both sides stay partners. Walls of one zone, boundary, adjacent zone, elevation, and height without windows merge in maximal straight runs. Surfaces with windows or skylights, self-adjacent surfaces, surfaces with holes, and a union with an edge or a nearly straight vertex within EnergyPlus's 0.01 m that no piece had are not merged. A merged surface keeps its first member's ID; the header lists every merge (Coplanar merge (D-191): <n> surfaces written as <m> …, then<written name> <- <members>), provenance recordsMERGED: …, and the infoSurfacesMergedcounts them; a file without a merge is unchanged. EnergyPlus's approximate view factors treat coplanar surfaces of a zone as unable to see each other, so a zone of many pieces with a large internal mass warnedFixViewFactors(D-187, D-190). Areas, and with them every invariant, the infiltration, and the mass ledger, do not change. - Collinear vertices, which the pipeline keeps where another zone's vertex meets an edge (ADR-002), are removed: a vertex within the distance tolerance of the segment joining its neighbours is dropped, from the start of the ring, until none is left.
- Zero-width parts. The pipeline no longer produces them on generated plans (floors and ceilings are clipped from conformed footprints, ADR-002, and
IdfTypologyTestsasserts that no rotated conversion warns), so this handling and the next are a guard for buildings from elsewhere. Clipping on the grid can leave a floor or ceiling with a part of no width (D-090): a spike, where the boundary runs out to a tip within the distance tolerance of the line through its neighbours and straight back, or an excursion out and back through a repeated vertex. A spike tip is removed with the collinear vertices; a ring still not simple (two vertices or two non-adjacent edges within the distance tolerance) is rebuilt as the union of its own region, which drops such parts, with its vertices put back on the original ones. The rebuilt rings that are not slivers must have the piece's area within the relative area tolerance plus the area of the rebuilt slivers (an excursion subtracts its thin area from the net area and the union adds it back as a sliver); otherwise the ring crosses itself or encloses area twice, is not a zero-width part, and the conversion fails with the errorDegeneratePolygoninstead of writing less area. Either repair is reported with the warningSliverOmitted, which names the zone, whether the surface is a floor or a ceiling, its elevation, the area of the slivers omitted, and the number of spikes and excursions removed with the area they changed; the region and its area do not change beyond the tolerance. - Holes. EnergyPlus surfaces cannot have holes. A floor or ceiling with holes (courts, ring zones, ring cores) is cut by one line parallel to the y axis through the middle of each hole's x-range and clipped to the strips between the cuts; every hole is crossed by its own cut, so no piece keeps a hole. The pieces have the polygon's area (checked within the relative area tolerance); clipping rounds to the distance grid, so piece vertices are put back on the polygon's own vertices. The info
SurfaceSplitnames every split surface. - Convex outdoor surfaces (design note 2026-10-11 part D.2). EnergyPlus projects every shading surface onto every receiving surface and clips the polygons, which is reliable only for convex surfaces: a non-convex casting surface is a severe error ("shadowing values may be inaccurate"), a non-convex receiving surface a warning. Every surface written
Outdoorsthat is not convex (roofs and exposed floors of L, U, court, and hub footprints, and the pieces a hole split leaves; walls are rectangles) and every shading surface is therefore cut into convex pieces with the same total area (IdfConvex), reported with the infoSurfaceSplit. Surfaces on the ground, adiabatic surfaces, and surfaces between zones take no part in shading and stay whole. The polygon is projected on its own plane; while a piece has a reflex vertex (one more than the distance tolerance inside the segment joining its neighbours), it is cut from that vertex along the extension of one of its two edges to the first point of the boundary met. The vertex is then no longer reflex in either piece and the point met adds none, so a polygon with r reflex vertices gives at most r + 1 pieces, and a rectilinear one gives rectangles. Of all candidate cuts, the one that leaves the fewest reflex vertices in its two pieces is taken, then the shortest, ties going to the first reflex vertex in ring order and to the extension of the edge into it, so the split is deterministic and gives few pieces: a T is cut along its bar's edge from one reflex vertex to the other into two pieces, where the shortest cuts alone gave three (D-191; the small hotel's top corridor). Polygon vertices are kept exactly, a cut's end on an edge is interpolated on it, and collinear vertices are removed from each piece. Each piece keeps the surface's orientation and starts at its upper-left corner seen from outside (D-091). A cut that would cross a window is not taken, and each window is written in the piece that holds it (its host is that piece); when every cut crosses a window, the conversion fails with the errorWindowBlocksConvexSplitnaming the wall, and no window is moved or dropped. Walls are rectangles in every building the pipeline makes, so no wall is split and no window changes host. A convex surface is written as before. The roof and exposed-floor areas, and with them every invariant and the infiltration (whose exterior areas come from the building), do not change. - Slivers. Where storeys touch along an edge, clipping on the grid can leave a piece of floor or ceiling narrower than the distance tolerance (about 1e-6 m wide and a few 1e-6 m² in area; D-090). A piece is a sliver when removing collinear vertices leaves fewer than three, or when its area is at most the distance tolerance times its perimeter (its mean width is then at most twice the tolerance; a real 1 m² surface has 4e-6 m² of this bound). It is not written, and the warning
SliverOmittednames its surface and area; its partner omits the same piece. A floor or ceiling that is nothing but slivers is omitted before partners are matched, so it is neither paired nor reported unpaired (the two sides of such a sliver can clip to no overlap at all). - Short edges. EnergyPlus merges vertices closer than about 0.01 m (
IdfDefaults.EnergyPlusVertexMergeDistance, EnergyPlus's own distance, not a BEMGen tolerance). Every written surface and window with an edge shorter than that gets the warningShortEdge; the file is still written. No conversion of the tests has one, the rotated and moved plans included. - Windows are
FenestrationSurface:Detailedrectangles in their wall at their offset and sill (D-039), with the wall's vertex order. A window in a wall that is not writtenOutdoorsis the errorInteriorWindow(no generator places one). - Skylights (DOE geometry note S5) are
FenestrationSurface:Detailedof typeWindowwith the skylight glazing, in the roof piece that holds them, named<roof piece>/Sky<k>, at the roof's elevation with the roof's vertex order (counter-clockwise from above, from the northernmost, then westernmost vertex). A roof with a court is split at a cut moved off its skylights (IdfPolygons.SplitHoles): a cut parallel to the y axis moved within the court's x-range, or, when a skylight covers some court's whole x-range, cuts parallel to the x axis through every court's y-range. A roof that is not convex is split into convex pieces with each skylight kept whole, as for walls, and a skylight on a surface not written as a roof isInteriorWindow. One limit remains: a skylight that covers the x-range of one court and the y-range of another leaves no axis that cuts both courts outside it; the skylight then lies in no hole-free piece, and the conversion stops withDegeneratePolygonrather than write it short (IdfSkylightTests). No generator's roof does this, which the skylit families ofIdfSkylightTestscheck. A skylight's zone counts as a zone with windows for the solar check of D-147. The skylight glazing (D-212, the owner's rule) is the envelope preset's window glazing for an envelope preset; for a construction set it is the set's ownSkylightglazing when the set has one, written as its ownWindowMaterial:SimpleGlazingSystemandConstructionwith the header role lineskylight: <assembly> (<assembly>), the skylights taking theSkylightassembly's incident solar multiplier and the wall windows the window's; a set without skylight glazing gives the skylights the window glazing with the warningSkylightGlazingFromWindowand the role lineskylight: <window> (the window's glazing; the set: <status>, <reason>); a blocked one refuses the building (ConstructionBlocked).Skylightleaves the header's and provenance's unused list when the building has skylights. A building without skylights is written as before, byte for byte.
Shading of unmodelled storeys¶
Unmodelled storeys cast shadows (design note 2026-10-11 part G). IdfShadingSurfaces writes the surfaces of the shared rule UnmodelledStoreyShading.Of (Lod.Core.Conversion, also used by Convert2BEM) as Shading:Building:Detailed: the outdoor walls of every storey of the assembled stack that no zone of the building covers in height, at their true elevations, windows included in the opaque surface. Under Stacked Floor Zone Multiplier these are the storeys its multiplied storeys stand for; Stack, Single Zone per Floor Type, and Single Zone Building model every storey and write none. Each is a wall's rectangle with a wall's vertex order (top of the start, bottom of the start, bottom of the end, top of the end), in building coordinates, so it rotates with the north axis as the building's surfaces do; the transmittance schedule is blank (always opaque). It goes through the convex split like an outdoor surface; a rectangle stays whole. The header line Shading: and the provenance line SHADING: record their count, storeys, and area. The shading is not part of the building: validation and every zone invariant ignore it.
Heat transfer between zones¶
Each surface's boundary comes from HeatTransferOptions.Exported (D-069, D-077), as in Convert2BEM:
| Building surface | Written |
|---|---|
Outdoors, Ground, Adiabatic |
the same keyword; Outdoors surfaces are sun and wind exposed, the others not |
| Interzone between two conditioned zones, its option off | Adiabatic |
| Interzone, its option on, or one of its zones without HVAC (D-211) | Surface, with its partner in the adjacent zone as boundary object |
| Interzone kept (option on, or a zone without HVAC), zones of different multipliers | Adiabatic on both sides, with the warning InterzoneMultiplierMismatch naming both |
SelfAdjacent (DOE geometry stage P5a, S8, ADR-026), any options |
Surface whose boundary object is the surface itself; each piece of a split floor or ceiling names itself |
A self-adjacent surface is a surface of a multiplied room toward a zone of another multiplier (on both sides) or toward the copy space where its undrawn copies stand: the space beyond is at the zone's own conditions, as in the DOE sources. It takes the interior construction of its kind (ConstructionRoles, a ceiling the reversed interior floor), is not sun or wind exposed, never carries windows, and is not split into convex pieces. A plan with room multipliers never gives a pair across different multipliers, because the plan builder, the simplifiers, and the stacking make those surfaces self-adjacent; InterzoneMultiplierMismatch stays the writer's guard for an interzone pair across multipliers from any other building. The IDF parse-back check (IdfChecks, IdfSelfAdjacentTests) counts the surfaces naming themselves against the building's self-adjacent pieces and keeps them out of the partner checks.
Partners are found in the building: a wall in the adjacent zone running the other way between the same end points, at the same elevation and height; a floor or ceiling of the other kind in the adjacent zone at the same elevation and with the same polygon (equal area and overlap within the relative area tolerance). A surface without a partner is the error UnpairedInterzoneSurface. The first surface of a pair in building order defines the geometry: its partner's pieces are its pieces, each with the vertices in reverse order. A floor uses the interior floor construction and the ceiling below it the reversed one; of two walls between zones, the one whose zone ID sorts after the other zone's ID (ordinal) uses the reversed interior wall (ConstructionRoles, the one rule for both converters, ADR-010), so both sides of every pair list the same layers in opposite order. Stacked Floor Zone Multiplier buildings have no floor or ceiling between storeys to pair: those pieces are adiabatic in the building itself (D-075).
Constructions¶
ConstructionRoles.Of (Lod.Core.Conversion) gives each surface its construction role from its kind and exported boundary, and the envelope preset its construction (convert2bem.md, envelope presets). Internal masses use the preset's internal-mass construction, written as a slice of it (below). Materials are written with roughness MediumRough and EnergyPlus's default absorptances (thermal 0.9, solar 0.7, visible 0.7) unless a layer's finish gives them.
Construction sets¶
A ConstructionSet (Lod.Core.Envelope, D-137) holds one construction or a status per role, the window, the infiltration, and optionally mass data and a window incident solar multiplier. Lod.ConstructionJson imports the atlas's unified construction JSON into one (design note). The writer:
- Resolves the set for the roles the building's surfaces and removed slabs use (
ConstructionSet.Resolve): - a role the set lacks is an error naming it (
ConstructionMissing, D-140), unlessIdfOptions.FillFromExample(Fill From Example) is on, when it takes the Example envelope's construction with a warning (ConstructionFromExample, D-138); - the ground floor of a set without foundation data is the Example's, information (
GroundConstructionFromExample, D-137); a packet v7 set's is its ownGroundFloormethod (Native ground, D-145); - a blocked role the building needs stops the conversion (
ConstructionBlocked). - Plans the added mass (
ConstructionMassAccounting,Lod.Core.Conversion). When wall mass is added, the building uses the interior wall role even without interior walls, so its fallback or block applies. A blocked furnishing, or a blocked floor-distributed mass where floor capacity falls short, stops the conversion (ConstructionBlocked). - Counted floor area is Σ zone floor area × multiplier.
- Represented interior wall capacity counts each wall between zones once; represented floor capacity counts the floor sides of slabs between storeys and each removed slab once, with the internal mass role's construction. The IDF holds each removed slab's capacity once as well (D-143, below). The ledger reads the building's surface areas; where the writer drops a horizontal sliver or splits a surface, the IDF's areas can differ from them by that much.
- Each family's budget is the set's capacity per counted floor area × the counted area.
- A shortfall becomes the recipe's area per m² of floor (the interior wall's for walls, the floor-distributed mass's for floors). An overshoot of a positive budget adds nothing and is a warning (
MassOverBudget); a zero budget, when the source has no such inventory, adds nothing and is information (NoMassBudget). - The furnishings are added at the set's rate.
- Each zone gets one
InternalMassper kind,{zone} Furnishing Mass,{zone} Wall Transfer Mass, and{zone} Floor Distributed Mass, with area rate × the zone's floor area, so the building's totals are exact. - Writes one
SurfaceProperty:IncidentSolarMultiplierper window when the set has a multiplier. EnergyPlus 26.2 applies it with a blank schedule: a year's transmitted solar was in the ratio 0.8276, the multiplier, with and without it (D-143). - Records the set in the header: its source (document, SHA-256, context, infiltration), whether Fill From Example was on, each role's construction and where it comes from, the mass ledger's operands, the multiplier, and the components the building has no geometry for.
Only a set of the whole-building scope reaches the writer: Construction JSON refuses a single-dwelling one, and a detailed document, or a single-dwelling set read with ConstructionJsonImporter.Read, gives ConstructionAssignmentUnavailable (construction-json.md, D-142). A packet v7 set (D-145) carries its foundation and ground data on ConstructionSet.Foundation; its ground floors take its own GroundFloor method, and the foundation roles without geometry are listed as unused (Native ground).
The test IdfConstructionJsonTests writes the packet's eight building-scope unified documents (medium office, warehouse, retained midrise apartment, tall and supertall building with F-factor ground; small data centre, legacy hospital with basement, and the hospital with a native C-factor wall with layered ground) on the linear plan through every simplifier, aggregator, and heat-transfer setting, with a synthetic year of weather, and without Fill From Example except for the data centre, whose source has no window. It checks from the IDF text that each family's represented and added capacity meets its budget, the removed slabs' internal masses as written included, that every ground floor takes the set's own method with the matching ground temperature object, and that the F-factor floors' exposed perimeters add up to the footprint's on every zoning. IdfNativeGroundTests covers the refusals, the temperatures, the provenance, and the unused roles.
Removed slabs as internal mass¶
A slab that a merge removes (D-031) keeps its heat storage and exchange area as internal mass: Lod.Core gives the area as the slab area and the number of exposed faces (two for a slab between two storeys merged into one zone). An EnergyPlus InternalMass is one-sided, with an adiabatic back, so writing the whole slab on slab area × faces would give each face the slab's full resistance and store its heat capacity twice. D-143 writes each face as a slice instead (Construction.Sliced(faces)):
- the object's area is the slab area × the faces, and its construction is
{name} Halffor two faces ({name} Slice of {n}for more), whose massive layers have1/facesof their thickness and whose massless layers and air gaps have1/facesof their resistance, each keeping its place and finish and taking the same suffix in its name; - the IDF then holds the slab's heat capacity once, each face sees the resistance to the slab's mid-plane, and the mass ledger's count of the slab's capacity once (ADR-021) agrees with the file;
- this is exact for a symmetric slab and an approximation for an asymmetric one, such as the Example interior floor (gypsum board, concrete, screed), whose halves keep every layer in order;
- a slice whose massless layer would fall below EnergyPlus's minimum resistance (0.001 m²·K/W) is the error
EnvelopeValue, naming the layer, and no document; so is a slice layer whose name (the layer's name plus the suffix) the envelope already gives to a material; - the slices are written after the construction set's own constructions, and one-face slabs use the slab construction itself;
- Convert2BEM's Internal Mass output is unchanged: it is the exposed area (convert2bem.md).
Loads¶
One object per load component (type, end use, and basis, D-047, D-126), with the load's own fraction schedule:
| Load type | Object | Basis written in its own field | Other bases |
|---|---|---|---|
| Occupancy | People |
per floor area (People/Area), absolute (People) |
per dwelling unit: the number of people of the zone's dwellings, absolute (value × dwelling count, D-126) |
| Lighting | Lights |
per floor area (Watts/Area), per person (Watts/Person), absolute (LightingLevel) |
absolute design magnitude, W (per dwelling unit: value × the zone's dwelling count) |
| Electric equipment | ElectricEquipment |
as lighting (EquipmentLevel) |
absolute design magnitude, W |
| Gas equipment | GasEquipment |
as lighting (EquipmentLevel) |
absolute design magnitude, W |
| Ventilation | ZoneVentilation:DesignFlowRate |
per floor area (Flow/Area), per person (Flow/Person), absolute (Flow/Zone), air changes (AirChanges/Hour) |
absolute design magnitude (Flow/Zone) |
| Domestic hot water | WaterUse:Equipment |
— | always the absolute peak flow of one zone instance, with the zone for its multiplier, the load's target temperature schedule and its inlet temperature schedule as the cold-water supply temperature (D-126), or a blank cold-water schedule when the inlet is the weather file's water mains (D-172), and no zone heat gains; written only when a preset defines it (the example presets do not; a program JSON usually does) |
Flows are converted from m³/h to m³/s. Where EnergyPlus has no field for a basis (for example lighting in air changes per hour), the writer writes the absolute design magnitude of one zone instance, value × basis quantity (ADR-007), which EnergyPlus applies identically, because every design-level method resolves to a fixed design level of the zone and the zones state their own floor area and volume. So no load is dropped and no basis is an error. Ventilation and infiltration have the coefficients 1, 0, 0, 0, so the flow is the design flow times the schedule whatever the weather; ventilation is Balanced with no fan (pressure rise 0, efficiency 1). Infiltration is not a program load since D-124; see the next section.
Program fields (D-126). The fractions and the people's properties that were fixed writer defaults in S6 are program fields now (domain-model.md, ADR-018), and their defaults are the old values, so a program that sets none is written exactly as before:
| Object | Fields written from the program |
|---|---|
Lights |
Return Air Fraction, Fraction Radiant, Fraction Visible from the load's heat fractions; Fraction Replaceable stays 1 (IdfDefaults.LightsFractionReplaceable, a daylighting field, not a program field) |
ElectricEquipment, GasEquipment |
Fraction Latent, Fraction Radiant, Fraction Lost from the load's heat fractions |
People |
Fraction Radiant and Sensible Heat Fraction (the number, or autocalculate) from the zone's people properties; Activity Level Schedule Name is the zone's activity schedule: the default (constant 120 W per person) as the Schedule:Constant BEMGen Activity Level, any other as a schedule under the type limits BEMGen Activity Level |
WaterUse:Equipment |
Target Temperature Schedule Name and Cold Water Supply Temperature Schedule Name from the load's water temperatures (they were blank, so EnergyPlus's defaults applied); Hot Water Supply Temperature Schedule Name stays blank, and the sensible and latent fraction schedules are not written, so water adds no zone heat, as the contract keeps plant and zone gains separate |
Water mains (D-172). A hot-water load whose inlet is the water mains temperature from the weather file (WaterTemperatures.InletFromWeatherFile, the atlas's CorrelationFromWeatherFile) leaves Cold Water Supply Temperature Schedule Name blank, so EnergyPlus takes the mains temperature, and the file gets one Site:WaterMainsTemperature with CorrelationFromWeatherFile (EnergyPlus correlates the mains from the weather file's annual mean and maximum monthly difference of outdoor temperature). A load with an inlet schedule is written as before, and a file without a mains inlet has no such object.
Daylighting (D-172, D-174)¶
Off by default (D-174, D-233). With Daylighting (input 12, IdfOptions.WriteDaylighting) false, the default, no IDF holds Daylighting:Controls, Daylighting:ReferencePoint, or any other daylighting object: daylight dimming is held fixed as part of the lighting load and never measured as a geometry effect, since dimming makes a zone's lighting energy depend on its windows and a zoning would no longer conserve the hourly lighting of its reference, which the evaluation metrics' pairing check requires (D-157, unchanged; GLOBAL.md scientific rules 1 and 4). This was the owner's decision D-174 ("let's not include dimming for our idf runs ever"), which D-233 keeps as the default; the LOD study keeps it off. A building whose programs carry daylighting controls (ZoneProgram.Daylighting, from a program JSON's lighting_controls, atlas handoff item 1) gets the header line Daylighting: not written (Convert2IDF's Daylighting option is off, the default; D-233); n zone(s) with controls in their programs, the provenance line DAYLIGHTING: not written (option off, the default); …, and the info DaylightingNotWritten naming the zones; a building without any is written as before. The export tests' parse-back checks fail any IDF with a daylighting object unless the test asks for daylighting, and ExpectedWarnings.Default does not expect EnergyPlus's warning about daylighting controls.
Code-rule daylighting on request (D-233, ADR-037)¶
With Daylighting true, the program says whether and how, and BEMGen's geometry says where (ADR-037, design note). For each zone whose program has daylighting controls and lights, CodeDaylighting (Lod.Core.Conversion) lays out the zone as openstudio-standards does for the DOE prototypes (space_daylighted_areas and the edition's space_daylighting_control_required? and space_daylighting_fractions_and_windows, openstudio-standards c8c1b9eb):
- Areas. Each window in an outdoor wall gives a primary sidelit rectangle from the wall to its head height in and a secondary one from one to two head heights in, both as wide as the window plus, each side, 2 ft (90.1-2010) or half the head height (90.1-2013 to 2019). Each skylight gives a toplit rectangle grown on every side by 0.7 × its height above the floor. The rectangles of a kind are united; the primary area loses the toplit area and the secondary area both; each is taken on the zone's own floor at the storey of its window or skylight (a zone's parts on one storey united, so a merged zone takes its own geometry; storeys added).
- Required controls. 90.1-2013 to 2019: primary when its area holds at least 150 W of the zone's lighting and the zone has at least 20 ft² of window; secondary when both sidelit areas hold at least 300 W, with the same window minimum; toplit when it holds at least 150 W. 90.1-2010: primary from 250 ft² of primary area, toplit from 900 ft² with a skylight effective aperture of at least 0.006, no secondary. The retail, strip mall, and apartment space types have their exceptions.
- Reference points. The edition's choice of what sensor 1 and sensor 2 control and at which window (south, west, east, north first) or skylight; the office whole-building non-geometry fractions scale them; the shares are rounded to three decimals and kept below 1. Sensor 1 stands 0.66 and sensor 2 1.33 head heights in from the centre of its window, or under the centre of its skylight, 0.8 m above the floor (the owner's height; openstudio-standards uses 2.5 ft); a point that falls outside the zone's floor moves to the interior point of the area it controls, which the header records.
- Objects. One
Daylighting:Controlsper such zone with the program's method, control type, minimum input power and light output fractions, steps, and setpoint at both points; availability blank (always: the program's "all days except design days", and the IDF runs no design days); glare at point 1, azimuth 0, DGI 22; and its one or twoDaylighting:ReferencePoints in the building's coordinates. The sun and sky come from the weather file andSite:Location(Weather). - No controls for a zone without a window or skylight, for a zone whose areas the edition does not require to be controlled, and for a program without a code rule (its template is not 90.1-2010 to 2019 or, since D-248, an IECC edition, which takes the 90.1-2019 rule; or openstudio-standards finds daylighting not appropriate for its space type), with the warning
DaylightingNoCodeRule. The program's recordedControlledLightingFractionis never written; it stays provenance. - Header.
Daylighting: written by the code rule on BEMGen's geometry (D-233); k of n zone(s) with controls in their programs have Daylighting:Controls, then one line per zone: its edition, toplit, primary, and secondary areas of its floor area, and its points with their shares and positions, ornone (no window or skylight),none (not required by <template> at <W/m2>: <areas>),none (required by <template> for the toplit and primary area(s), but openstudio-standards places no sensor for this combination: …)(D-236),none (the program has no code rule: …). The provenance lineDAYLIGHTING: written for k of n zone(s) …and the infoDaylightingWrittenfollow it. - Runs. EnergyPlus warns once per zone that its reference points control less than all of its lights;
ExpectedWarnings.ForIdfexpects that warning (PartialDaylightingControl) only for an IDF holdingDaylighting:Controls, ineplus-checkand the batch runner. Paired metrics of such sites can report them unpaired on internal loads (D-157).
D-172 had written, on request, one reference point and one Daylighting:Controls per glazed zone controlling the program's recorded fraction of its lights; D-174 removed that writer, the option, and the run check's PartialDaylightingControl entry. D-233 brought back an option of the same name with the code rule above, which places the controls by BEMGen's own windows and skylights instead of the source model's fraction.
A heat fraction in a field the EnergyPlus object lacks (latent or lost on lights, visible or return air on equipment) cannot reach the writer: a program with one is rejected when it is built (HeatFractionNotSupported). A per-dwelling load is the absolute design level value × the zone's dwelling count, for one zone instance; EnergyPlus applies the zone multiplier.
Unoccupied lighting cap (D-256, ADR-040)¶
Off by default. With Lighting Cap (input 13, IdfOptions.WriteUnoccupiedLightingCap, the suite spec's settings.unoccupied_lighting_cap) false, the default, no IDF holds an EMS object: the lighting follows its schedules, as D-233 holds daylighting fixed, since the cap makes a zone's lighting depend on when all of its (merged) occupants are absent and a zoning would no longer conserve its reference's hourly lighting (D-157). A building whose programs carry the cap (ZoneProgram.LightingCap, from program JSON 6.1.0) gets the header line Unoccupied lighting cap: not written (Convert2IDF's Lighting Cap option is off, the default; D-256); n zone(s) with the cap in their programs, the provenance line LIGHTING CAP: not written (option off, the default); …, and the info LightingCapNotWritten; a building without any is written as before, byte for byte, either way.
On. For each zone whose program has the cap, PNNL's EMS program of the 90.1-2019 prototypes (the atlas's ADR 0060 section 1):
EnergyManagementSystem:Sensors on thePeople Occupant Countof the People objects the rule reads (the zone's own; forother_zone_occupant_count_zero, those of every zone of the building whose name or ID is the rule'scondition_zone, summed) and on theLights Electricity Rateof each of the zone's Lights objects (summed: the comparison is all of its lighting, as PNNL'sZone Lights Electricity Rate);- an
EnergyManagementSystem:Actuator(Lights,Electricity Rate) on each general Lights object (end uselighting), and on the others when the rule sets the additional lighting (the strip mall's 0); - an
EnergyManagementSystem:ProgramCap<k>_Program:IF (occupants <= 0) && (lighting >= (threshold * area)), the first general lights set tocap * area(any other general ones to 0, the additional ones to their rate times the area),ELSEevery actuatorNULL, so the lights follow their schedules; the area is the zone's floor area per instance, as the sensors and actuators are; - one
EnergyManagementSystem:ProgramCallingManagerper calling point,UnoccupiedLightingCap_<calling point>(BeginTimestepBeforePredictor, or the large office'sAfterPredictorAfterHVACManagers).
Where it is not applied (the warning LightingCapNotApplied names each zone and why): a zone whose people the rule reads are zero at all times, no occupancy power or an all-zero schedule (the owner's G4: it would be capped permanently); a zone whose condition_zone is not a zone of the building (BEMGen's zones are not the source's: the DOE warehouse's office zone is Office, the prototype's Zone1 Office, so its storages are not capped; reading their own count instead would cap them for good); a zone without general lights. The rule's zone_conditions name single source zones (the offices' Perimeter_mid_ZN_2, capped only outside 07:00 to 16:00; the small office's Perimeter_ZN_2, only while the binary occupancy schedule is 0) and are not applied: every capped zone takes the rule without them, and the header lists them. A merged zone keeps the cap only when every source carries the same rule (program-json.md). The header gives one line per zone (its program, the cap and threshold, whose occupants, the calling point, or none (…)), then the added conditions; the provenance line LIGHTING CAP: written for k of n zone(s) … and the info LightingCapWritten follow. EnergyPlus 26.2 reports no warning for these objects (D-257).
Infiltration¶
The infiltration of the envelope preset (D-124, ADR-017) is written once per zone, after the zone's program loads, conditioned or not, unless the zone has none of the area its basis needs (below): a ZoneInfiltration:DesignFlowRate named <zone> Infiltration <InfiltrationBasis> with the envelope's fraction schedule (one schedule shared by every zone, written once under its own name), the coefficients 1, 0, 0, 0, and the rate in EnergyPlus's own method for its basis, so that EnergyPlus multiplies the rate by that zone's own quantity, per zone instance before the zone multiplier. The writer computes no flow: no zone merge aggregates infiltration, and EnergyPlus gives each zone the flow of the surfaces and volume the file states for it.
InfiltrationBasis |
Design Flow Rate Calculation Method | Rate written in | EnergyPlus multiplies it by |
|---|---|---|---|
PerExteriorSurfaceArea |
Flow/ExteriorArea |
Flow Rate per Exterior Surface Area, m³/s per m² (the rate in m³/h per m² divided by 3600) |
the zone's exterior surface area |
PerExteriorWallArea |
Flow/ExteriorWallArea |
the same field | the zone's exterior wall area |
AirChangesPerHour |
AirChanges/Hour |
Air Changes per Hour, 1/h |
the volume the Zone object states |
Zones without the area of the basis (D-130). A zone whose basis is per exterior surface area and which has no surface written Outdoors, or whose basis is per exterior wall area and which has no outdoor wall, gets no ZoneInfiltration:DesignFlowRate: its design flow is 0 in BEMGen (ZoneInfiltration.DesignFlow) and in EnergyPlus alike, so nothing is lost, and EnergyPlus would warn about the object (Exterior Surface Area = 0. 0 Infiltration will result., the first run's warning 4: the core zones of Perimeter Core). The info InfiltrationNotWritten names the zones. With air changes every zone has a volume and gets its object.
The exterior area of EnergyPlus (found by running 26.2). What EnergyPlus counts as a zone's exterior surface area was checked by running EnergyPlus 26.2, the version at hand, on converted files with a storey moved off the one below (the file targets 25.2, with its version line changed for the run; 25.2 itself has not been run, D-112). Each zone's design flow in the .eio was the rate times the zone's outdoor walls, roofs, and exposed floors, with windows included in the gross areas, and without its ground floor; with Flow/ExteriorWallArea it was the rate times its outdoor walls alone. Surfaces with the boundary Ground or Adiabatic, and surfaces between zones, are not counted. BEMGen writes every outdoor wall, roof, and exposed floor of a zone with the boundary Outdoors and its full area, so EnergyPlus uses the area of the zone's own surfaces facing outdoors; the slabs between storeys that Stacked Floor Zone Multiplier repeats are adiabatic, as in the building itself, and are not counted. The finding is recorded in the comments of IdfLoads.Infiltration, and ZoneInfiltration in Lod.Core.Conversion computes the same areas for Convert2BEM's Infiltration Flows (convert2bem.md).
HVAC and thermostats¶
Every conditioned zone (D-038) gets ZoneControl:Thermostat and the setpoint object of its sides (D-126): ThermostatSetpoint:DualSetpoint with control type 4 when it has both a heating and a cooling setpoint schedule, ThermostatSetpoint:SingleHeating with control type 1 when it has heating only, ThermostatSetpoint:SingleCooling with control type 2 when it has cooling only, each type with its own constant control type schedule (BEMGen Dual Setpoint Control, BEMGen Single Heating Control, BEMGen Single Cooling Control, written when used). Every zone also gets a ZoneHVAC:IdealLoadsAirSystem with no heating or cooling limit, in an equipment list connected to the zone. An unconditioned zone gets neither, but keeps its loads and infiltration.
Schedules¶
Every 8760-value schedule (ADR-003) is reproduced hour by hour, to fifteen significant digits, as Schedule:Year over Schedule:Week:Daily and Schedule:Day:Hourly: each distinct day of the schedule is one day schedule; the year is cut into seven-day blocks from 1 January, each block a week schedule giving every weekday the day schedule of its date in the block; consecutive equal blocks share one week schedule and one period. The last block, 31 December alone, takes the other weekdays from the block before it, so it merges with that block when its day agrees. A schedule from weekday and weekend profiles is thus two day schedules, one week schedule, and one period. The holiday, design-day, and custom-day types use the Sunday day schedule, and the writer defines no holiday or special day: a program's holidays (D-126) are already in its hourly values, which carry each date's own profile, so the run period applies them without a day type of their own. A program JSON's design-day profiles are not used (they are not days of the year); the design days of the weather file, when one is added, get the Sunday profile. A schedule is written once per name and values; another schedule with the same name but other values gets its own name.
The RunPeriod covers 1 January to 31 December of a non-leap year with the weather file's holidays and daylight saving off, so EnergyPlus applies the hourly values on the days they were made for. Since D-126 the year and the weekday come from the building's calendar (the one calendar its zones share, ProgramChecks.Calendar): a program JSON built on 2014 gives the year 2014 starting on a Wednesday. Without a calendar (BEMGen's own presets) the year is the one that starts on IdfOptions.FirstDayOfYear (Monday if unset): 2007 for Monday (it was 2018 before D-126, also a Monday), 2017 for Sunday, 2019 for Tuesday, 2014 for Wednesday, 2015 for Thursday, 2010 for Friday, and 2011 for Saturday. A weekday given in the options that contradicts the calendar is the error CalendarMismatch, and so are zones on different calendars, which no single run period fits (the validation override does not lift it).
Defaults¶
The writer's own are in IdfDefaults; they are defaults for a runnable file, not values from a standard (ADR-010). The rows marked as program defaults are held by the program since D-126, with the values the writer used before, and are written here only for completeness:
| Default | Value |
|---|---|
| Timesteps per hour | 6 |
| Terrain; solar distribution | Suburbs; FullExterior (no convex zones needed) |
| Convergence tolerances; warm-up days | 0.04 W and 0.4 K; 25 maximum (EnergyPlus defaults), 6 minimum (a writer choice kept since S6; the 26.2 IDD default is 1) |
| Ground temperature under the building | the building's monthly mean indoor setpoint minus 2 °C (IdfDefaults.GroundBelowIndoor); 20 °C indoors, so 18 °C, without a conditioned zone (IdfDefaults.DefaultIndoorTemperature); see Ground temperatures |
| Activity level | 120 W per person (program default since D-126: PeopleProperties.Default) |
| People | radiant fraction 0.3, sensible fraction autocalculated (program defaults) |
| Lights | return air 0, radiant 0.42, visible 0.18 (program defaults, HeatFractions.DefaultFor); replaceable 1 (writer default) |
| Electric equipment | latent 0, radiant 0.5, lost 0 (program defaults) |
| Gas equipment | latent 0, radiant 0.3, lost 0 (program defaults) |
| Hot-water temperatures | target 60 °C, inlet 10 °C (program defaults, WaterTemperatures.Default) |
| Run period without a calendar | 2007, starting on a Monday |
| Ideal loads | supply air 50 °C heating and 13 °C cooling, humidity ratios 0.0156 and 0.0077 (EnergyPlus defaults); no capacity limit |
| Outputs | the research set IdfOutputs.Research: the surface details report, and variables and meters hourly (Outputs) |
Diagnostics¶
| Code | Severity | When |
|---|---|---|
ValidationFailed |
Error | Validation failed and no override; no document |
ClimateZoneUnresolved |
Error | A program's values differ by climate zone and it was imported without a zone (D-213); no document, whatever the override |
ClimateZoneDiffersFromWeather |
Warning | The programs were resolved for another climate zone than the weather's .stat file states (D-213) |
ValidationOverridden |
Warning | Validation failed and the override was used; recorded in the header |
UnpairedInterzoneSurface |
Error | An interzone surface has no partner in the adjacent zone |
InterzoneMultiplierMismatch |
Warning | Two partners belong to zones of different multipliers; both written adiabatic |
InteriorWindow |
Error | A window lies in a wall not written Outdoors |
SurfaceSplit |
Info | A floor or ceiling with holes was written as hole-free pieces, or a surface written Outdoors or a shading surface that is not convex as convex pieces |
SurfacesMerged |
Info | Coplanar surfaces of a zone with the same boundary toward the same zone were written as one surface each group (D-191); the header lists them |
WindowBlocksConvexSplit |
Error | A surface written Outdoors that is not convex cannot be split into convex pieces without cutting through one of its windows; no document (no building of the pipeline has one, its walls being rectangles) |
SliverOmitted |
Warning | A floor or ceiling piece narrower than the distance tolerance, or a zero-width part of one, was not written |
ShortEdge |
Warning | A written surface or window has an edge shorter than the distance at which EnergyPlus merges vertices |
NoConstructionRole |
Error | A surface has no construction role (an unresolved boundary, a wall or ceiling on the ground), only possible on an overridden validation |
DaylightingNotWritten |
Info | Programs carry daylighting controls and Daylighting is off, the default (D-233); the zones are named |
DaylightingWritten |
Info | Daylighting is on: the code rule's controls were written for the zones it places points in; the header lists every zone (D-233) |
LightingCapNotWritten |
Info | Programs carry an unoccupied lighting cap and Lighting Cap is off, the default (D-256); the zones are named |
LightingCapWritten |
Info | Lighting Cap is on: the EMS programs were written; the header lists every zone (D-256) |
LightingCapNotApplied |
Warning | Lighting Cap is on and a zone gets no cap: the people its rule reads are zero at all times (G4), its condition zone is not a zone of the building, or it has no general lights (D-256) |
DaylightingNoCodeRule |
Warning | Daylighting is on and programs with controls have no code rule (not 90.1-2010 to 2019, or daylighting not appropriate for the space type); no controls for their zones (D-233) |
CalendarMismatch |
Error | The zones' programs were expanded on different calendars, or IdfOptions.FirstDayOfYear contradicts the building's calendar (D-126); no override |
InvalidParameter |
Error | Write is true but Path is not a fully qualified file path (the component) |
FileExists |
Error | The file exists and Overwrite is false; it is kept (the component) |
FileWriteFailed |
Error | The folder does not exist or the file could not be written (the component) |
DegeneratePolygon |
Error | Splitting (for holes or into convex pieces) or cleaning a polygon failed, or a floor or ceiling crosses itself so that rebuilding it would change its area (no building of the tests has one) |
NoWeatherFile |
Info | No weather file was given: the IDF has no Site:Location, and EnergyPlus takes the location from the weather file it runs with |
GroundTemperatureDefault |
Info | The building has no conditioned zone of any floor area: the ground temperatures use 20 °C indoors, so 18 °C |
InfiltrationNotWritten |
Info | Zones whose infiltration basis is an exterior area have none of it, so no infiltration object is written for them (design flow 0) |
InvalidWeatherFile |
Error | The weather file cannot be read or its header is malformed (EpwHeader); no document |
ConstructionFromExample |
Warning | A construction set has no construction for a role or the window that the building needs, and Fill From Example takes the Example envelope's (D-138, D-140) |
ConstructionAssignmentUnavailable |
Error | The construction set is a detailed construction JSON, which BEMGen reads as evidence and converts never (D-142); the message names the unified building-scope document to use; no document |
EnvelopeValue |
Error | A removed slab's construction cannot be split between its faces: the slice of a massless layer would fall below EnergyPlus's minimum resistance, 0.001 m²·K/W, or a slice layer's name is already a material of the envelope; the message names the layer (D-143); no document |
ConstructionMissing |
Error | A construction set has no construction for a role or the window that the building needs, and Fill From Example is off (D-140); no document |
GroundConstructionFromExample |
Info | A construction set without foundation data has no ground floor; ground floors take the Example envelope's (D-137) |
GroundMethodNotSupported |
Error | A construction set's GroundFloor cannot be placed on BEMGen's ground floors: Kiva or C-factor, an assembly that does not fit its method, or two covering assignments (D-145); Fill From Example does not lift it; no document |
GroundAssignmentSetAside |
Warning | A construction set's GroundFloor has, beside the building-default assignment that covers the ground, a rule BEMGen cannot evaluate (a space type, storey, window operation, or thermal host); it is set aside and named, and every ground floor takes the default recipe (D-145) |
ExampleWindowSolarNotAbsorbed |
Warning | The construction set has no window, so the windows are the Example's (Fill From Example), and in some zones with windows every floor is a ground floor whose inside layer has solar absorptance 0, as in the windowless source data centre: EnergyPlus finds no floor there for the windows' solar and reports a severe error per zone ("floor cannot absorb any solar gains"). The warning names the zones; the source's values are written as given (D-147) |
GroundTemperatureWeatherMissing |
Error | A construction set's F-factor ground needs the weather file's monthly mean dry-bulb, and no weather file with a full year of hourly records was given (D-145); no document |
FoundationNotWritable |
Error | IdfFoundations cannot write a resolved foundation as EnergyPlus objects (outside the pipeline, above); no objects |
ConstructionBlocked |
Error | A construction set marks a role, the window, the furnishings, or (with a floor shortfall) the floor-distributed mass blocked, and the building needs it; no document |
MassOverBudget |
Warning | The building represents more interior wall or floor capacity than the set's positive budget; no mass added for that family (D-137) |
NoMassBudget |
Info | The set has a zero budget for a family (its source has no such inventory); no mass added |
MassNotAdded |
Warning | A budget leaves capacity unrepresented, but the set has no recipe for it, the recipe has no capacity, or the building has no floor area |
Construction JSON has its own codes (ConstructionJsonDiagnosticCodes), among them the error ConstructionJsonScopeNotSupported for a unified document whose scope is not building (D-142, construction-json.md).
Tests¶
tests/Lod.Export.Tests checks every part on its own (text and names, schedules, geometry, loads, the writer), and whole files by reading them back with a small IDF parser (Support/IdfParser.cs, Support/IdfChecks.cs), without EnergyPlus:
- Counts and references: zones, ideal-loads systems, thermostats, windows, internal masses, and load objects as in the building; every surface's zone and construction, every construction's layers, every window's wall, every load's zone and schedule, every thermostat's schedules, and every year schedule's weeks and days exist; names are unique as EnergyPlus requires and at most 100 characters.
- Partners: every
Surfaceboundary points to a surface in another zone that points back, with its vertices reversed and its construction's layers reversed; with the options on, every surface between zones of equal multipliers is paired; with both off, none is. - Geometry: every surface and window is planar and simple (no hole, slit, or repeated vertex), walls are vertical, floors face down, ceilings and roofs up, and windows face as their wall does; every surface written
Outdoorsand every shading surface is convex (part D.2), and the shading surfaces are planar and simple and have the area ofUnmodelledStoreyShading.Of's surfaces (ShadingArea). - Invariants against the building, counting multipliers: floor area and volume, exterior wall, ground, roof, and exposed floor area, the floor and ceiling surface area by surface type and written boundary (ground, outdoors, partner surface, adiabatic), so a missing or extra piece shows even where the zone fields agree, internal-mass area, glazing in total and per orientation (from the window normals and the north axis), and installed and hourly scheduled magnitude per program load type, from the IDF's own design levels and expanded schedules (relative load tolerance), and the infiltration (D-124): one object per zone that has the quantity of the basis and none for the others (D-130), in the method of the envelope's basis, with the envelope's rate and schedule, whose flow from the IDF's own surfaces and volumes, as EnergyPlus reads them, equals
ZoneInfiltration.DesignFlowzone by zone, a zone without an object having a design flow of 0, and in the installed total over every zone (IdfInfiltrationTests,IdfChecks). - Coverage: the canonical linear plan (multipliers 1, 2, 1) through every simplifier and aggregator with both settings; the enclosed court, the court cluster, and the office plate (multipliers 1, 3, 1) and the stepped band (its three storeys) the same way; each of these five plans also rotated by 30° and moved by (5.3, −2.1) m, and the linear plan with an orientation of 30° (north axis and glazing per orientation end to end); on the rotated plans only zero-width parts may be omitted, and what is written of each such surface keeps its area. A plan with every load kind and basis (hot water, gas, ventilation; per person, absolute) is converted too, and the canonical linear plan through every combination with each infiltration basis. No conversion has a short edge. Negative tests break one thing in a correct file and expect the checks to name it.
- Snapshots (
tests/Lod.Export.Tests/Snapshots/idf-*.txt): the minimal linear plan in full, and four combinations of the canonical plan that cover each simplifier, each aggregator, and both settings once (one file per combination of the sixteen would be tens of thousands of lines; every combination is read back instead). Numbers are compared to the building within the tolerances ofToleranceSettings, because they are written with fifteen significant digits. Since D-124 every snapshot has the header lineInfiltration:, and in five of them (four of the canonical plan and the stair-bay bar's of D-123) the infiltration of every zone uses the one envelope schedule, written once, where each zone had its own aggregated schedule. - Convex split and shading (design note 2026-10-11, parts D.2 and G) (
IdfConvexTests,IdfGeometryTests,IdfShadingTests): L and U roofs and exposed floors, rotated or not, and a ring roof split for its hole and then into convex pieces give convex pieces of the same area, facing as the surface does, each from its upper-left corner, named<id>#k; ground, adiabatic, and interzone surfaces stay whole; a vertical L keeps a window whole by taking the cut that avoids it, and one whose every cut crosses a window is the errorWindowBlocksConvexSplit. The linear plan under Stacked Floor Zone Multiplier (1, 2, 1 and 1, 3, 1) writes the shading of its unmodelled storeys with a wall's vertices, after the internal masses and before the loads, with unique names and the header and provenance lines; the other aggregators write none; the enclosed court (also turned) and the office plate under Stacked Floor Zone Multiplier (1, 3, 1), both settings, read back with their shading. Negative tests: a non-convex roof, a non-convex shading surface, and a missing shading surface fail the checks. Without the convex split, 429 conversions of the test suite fail the convexity check, among themL1/Conditioned-1/F14, the exposed floor of the moved stair-bay bar of the first run's severe error. Every IDF snapshot gained the header lineShading:; the Stacked Floor Zone Multiplier snapshot (1, 2, 1) also gained the eight shading surfaces of its unmodelled storey L1. No snapshot has a non-convex outdoor surface, so no surface line changed. - Coplanar merge (D-191) (
IdfSurfaceMergeTests,IdfConvexTests): two ground floors sharing an edge become one; pieces touching at a vertex, of different kinds, elevations, or boundaries, toward different zones, with a skylight, or self-adjacent stay apart; an interzone pair merges on both sides alike; four strips around a court merge only until the union would enclose it; collinear walls merge and a wall with a window does not; the small hotel's top corridor has one floor and a two-piece roof; the single-zone stackers over the small hotel's rooms write under a quarter of the building's horizontal surfaces; the header and the info record the merge. The convex split cuts a T into two pieces. Two snapshots changed (No Simplification + Single Zone Building and Perimeter Core + Single Zone per Floor Type): their floors, ceilings, and roofs merge and the header lists the merges; no other line changed. - Program fields (D-126) (
IdfProgramPropertiesTests,IdfExtendedProgramMatrixTests,IdfProgramJsonTests): the heat fractions, people properties, water temperatures, and per-dwelling levels the IDF holds equal the program's; the three thermostat kinds and their control type schedules; two end uses of one type with their own names; the run period of a calendar and of no calendar; the options' weekday against the calendar; the Medium Office program JSON through the office plate, every plan simplifier, and every floor aggregator to a validated building and an IDF that reads back. Six IDF snapshots gained the header lineCalendar:and the run-period year 2007 in place of 2018, and nothing else. - Simulation-ready IDF (D-130) (
EpwHeaderTests,IdfWeatherTests,IdfGroundTemperatureTests,IdfOutputTests,IdfSiteRecordTests,IdfInfiltrationTests): the weather header and its errors (a missing or shortLOCATION, a field that is not a number, a location outside the IDD's limits, data that are not hourly, malformed ground temperatures);Site:Location, the header, and provenance with and without a weather file, and the service's weather path (not fully qualified, missing, malformed); the ground temperatures (a worked example with a time-varying and a heating-only zone, the monthly means on the run calendar, the default without a conditioned zone, the zero-denominator guard, the canonical plan under every simplifier and aggregator, and the finding under Perimeter Core); the outputs in order and the meters by use; the four site lines; and no infiltration object for a zone without the area of its basis. Every IDF snapshot changed in its version line, its header (the weather, ground-temperature, and site lines, and the EnergyPlus line), its twelve ground temperatures (18 → 20.5 °C, the example presets' 21/24 °C midpoint minus 2), and its outputs (the research set in place of four monthly meters); their geometry, load, and schedule lines did not change. - Removed slabs as slices (D-143) (
IdfWriterTests,LayerKindsTests,IdfConstructionJsonTests):Construction.Sliceddivides thickness and resistance by the face count and keeps order and finishes; a single-zone building writes each removed slab as{name} Halfon twice its area, whose heat capacity and resistance are half the slab's, so the internal masses hold the slab's capacity once and none uses the whole slab; a slab whose massless layer would fall below 0.001 m²·K/W is the errorEnvelopeValuenaming the layer; and the construction-set matrix counts the removed slabs' capacity from the internal masses as written. Two IDF snapshots changed: No Simplification with Single Zone Building, and Perimeter Core with Single Zone per Floor Type. - Ground heat transfer (constructions and ground note, Part B) (
IdfOutputTests,IdfWriterTests,IdfChecksTests): the research set holds the surface details report and the ground-surface variable; the outputs come in their order, withOutput:Surfaces:Listafter the summary reports and one keyedOutput:Variableper ground surface after the zone variables; exactly the surfaces onGroundorGroundFCfactorMethodare requested, never by*, under several simplifiers, aggregators, and settings; under Stacked Floor Zone Multiplier only the split-off ground storey (× 1, D-046) is requested; and the parse-back checks (IdfChecks, run on every converted file, F-factor sets included) fail a file that requests a paired surface or misses a ground one. Every IDF snapshot changed only by these added objects:Output:Surfaces:Listand oneOutput:Variableper ground surface. - Zones of several pieces (D-123) (
IdfMultiPartZoneTests): the stair-bay bar under Conditioned Merge with Join Pieces true, two storeys stacked, gives per storey one conditioned zone of four pieces and one unconditioned zone of three. With both heat-transfer settings its IDF reads back with consistent references and the building's invariants; each such zone is oneZonewith one floor surface per piece and the zone's floor area and volume; the interzone walls between the two zones are paired; and one snapshot holds the file (idf-StairBayBar-ConditionedMerge-JoinPieces-Stack-on.txt). With the upper storey moved so that every upper piece overhangs, each basis of the infiltration (D-124) is applied to the outdoor walls, roofs (C1,C2, …), and exposed floors of every piece of a zone, and the flow EnergyPlus computes from the IDF equalsZoneInfiltration.DesignFlowzone by zone.
IDD check¶
scripts/idd-check/idd_check.py checks IDF files against the EnergyPlus IDD (class names, field counts and \min-fields, required fields, choice keys, numeric limits, references, unique objects); the IDD stays outside the repository (scripts/idd-check/README.md). With BEMGEN_IDF_OUT set, the export tests write every file they convert. Last run: 2026-10-02, against the EnergyPlus 25.2.0 IDD (idd/Energy+.idd.in at the tag v25.2.0), 355 files (the 32 linear-plan combinations, the four plans with holes or storeys and all five plans rotated and moved, each through the 32 combinations, the linear plan with orientation 30°, the two load-kind plans, and the minimal plan): 0 problems. Every class the writer uses was also compared field by field with the IDD. Repeated on 2026-10-07 for D-124 against the same IDD (idd/Energy+.idd.in at v25.2.0): 579 files, now including the infiltration-basis tests written by IdfInfiltrationTests (16 files each in Flow/ExteriorArea and Flow/ExteriorWallArea, the rest in AirChanges/Hour): 0 problems. Repeated on 2026-10-07 for version 1.1.0 (D-125) on the integrated Conditioned Merge and program mix, again against the EnergyPlus 25.2.0 IDD: 1016 files, all three infiltration methods, 0 problems. The count is higher because 288 files of the joined merge modes, named after ConditionedMerge:JoinPieces and the like, had been written with a colon in the name; on Windows that makes an alternate data stream that a folder listing does not show, so the check had never seen them. The export tests now write every IDF under a plain name (IdfOut.FileName replaces each character a file name cannot hold with _). Repeated on 2026-10-11 for D-130 against the EnergyPlus 26.2.0 IDD (D:\EnergyPlusV26-2-0\Energy+.idd, !IDD_Version 26.2.0): 1074 files (the 1073 of 1.2.0 and the minimal plan with the Chicago weather file's Site:Location), 0 problems. Every class the writer uses, the new ones included (Site:Location, Output:VariableDictionary, Output:SQLite, OutputControl:Table:Style, Output:Table:SummaryReports, Output:Variable), was compared field by field with the 26.2.0 IDD: names, order, \min-fields, and keys agree. The one difference found is a default: the 26.2 IDD's Minimum Number of Warmup Days default is 1, where the writer writes 6 and called it the EnergyPlus default; the value 6 is kept as a writer choice and its description corrected. Eight of the files were run in EnergyPlus 26.2.0 with the Chicago TMY3 file (the minimal plan with and without its Site:Location, the linear plan under No Simplification and Stack with the options on and under Semantic Merge and Stacked Floor Zone Multiplier, the plan with every load kind, the extended programs, and Perimeter Core with both exterior-area infiltration bases): all completed with 0 severe errors and no version, meter, or infiltration warning; the only warning left is the expected zone floor area of Single Zone per Floor Type. Repeated on 2026-10-07 for version 1.2.0 (D-126) against the 25.2.0 IDD: 1073 files, 0 problems, now including single heating and single cooling thermostats, the water-use temperature fields, the people sensible fraction, the heat fractions of two lighting end uses, and per-dwelling loads written as absolute levels (the files of IdfProgramPropertiesTests, IdfExtendedProgramMatrixTests, and IdfProgramJsonTests). Repeated on 2026-10-15 for construction sets (D-137) against the 26.2.0 IDD: the 168 files of IdfConstructionJsonTests (the packet's three unified documents on the linear plan through every simplifier, aggregator, and heat-transfer setting), 0 problems once the IDD's own inconsistency on SurfaceProperty:IncidentSolarMultiplier is allowed (scripts/idd-check/README.md); all 168 ran in EnergyPlus 26.2.0 with the Golden TMY3 file through eplus-check: 168 passed, no severe error, no unexpected warning. Repeated on 2026-10-16 for D-143 (medium office, warehouse, and midrise apartment on the linear plan through every zoning and heat-transfer setting, without Fill From Example): 168 files, 0 problems; 11 of them (the single-zone ones, which hold half slabs, and the midrise apartment on Stack Floors) passed eplus-check in EnergyPlus 26.2 with no unexpected warning.
Headless Rhino check¶
scripts/rhino-smoke/specs/convert-idf.py runs the component in Rhino 8 for the linear plan and the enclosed court through every simplifier and aggregator, writing each file to a folder next to the result file, outside the repository; it also checks Write false, Overwrite, a missing path, a run with the Chicago weather file (BEMGEN_EPW, by default the EnergyPlus 26.2 installation's USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw), one without a weather file, and one with a missing weather file (D-130), a failed Envelope Preset wired into both converters (the warning), Envelope Preset, and Convert2BEM's envelope input and construction outputs. In Rhino the spec counts each IDF's objects and main classes and the files are then run through the IDD check (scripts/idd-check); the parse-back of references, partners, geometry, and invariants against the building runs in the unit tests (Lod.Export.Tests, Tests), not in Rhino. The 2026-10-02 run and the IDD check of the files it wrote are recorded in the smoke test S6 checklist. A failed validation cannot be produced from the components (every aggregator's building validates), so the blocking and the override are covered by the unit tests only (Convert2IdfTests, IdfWriterTests). merge-pieces.py (D-123) converts every merge mode of the Stair Bay Bar with every aggregator and checks one Zone object per zone of the building.
To verify on the first EnergyPlus run¶
Recorded in ADR-010 (D-112) and settled by the first run of 2026-10-11 (the stage note): EnergyPlus uses the floor area a zone spanning storeys states (with the expected warning Entered Zone Floor Area(s) differ more than 5% from the sum of the Space Floor Area(s)), and the window construction named like its glazing material runs without a message.
Not yet decided¶
Design days and sizing (no sizing is needed while the ideal loads have no capacity limit, D-112); the F-factor ground model for envelope presets, which waits for a sourced F-factor (D-023; construction sets have theirs since D-145); sourced envelope and program values (D-023); a selectable output set (the research set is the only one). The metabolic rate and the load fractions became program fields in D-126; shared services of the program JSON contract are not modelled.