Skip to content

ADR-010: Convert2IDF

Status: Accepted (owner's scope answers D-112; the controller's realisation choices provisional pending the owner's reading); superseded in part by ADR-019 (EnergyPlus 26.2, weather, outputs, the ground rule, convex outdoor surfaces, and the shading of unmodelled storeys, D-130), by ADR-017 (infiltration is written once per zone from the envelope preset, not as a program load, D-124) and by ADR-018 (heat fractions, activity, people fractions, water temperatures, and single-sided thermostats come from the program, and the run period follows the building's calendar, D-126), and refined by D-143 (a removed slab's internal mass is written as a half slice per exposed face)

Date: 2026-10-02

Decisions: D-016, D-017, D-020, D-023, D-031, D-038, D-041, D-047, D-069, D-077, D-079, D-091, D-111, D-112; applies ADR-002, ADR-003, ADR-005, ADR-007, ADR-013, ADR-014

Context

Convert2IDF (S6) writes an EnergyPlus input file from an IGeneratedBuilding, the second converter after Convert2BEM (D-020). The building carries zones with their parts, programs (loads, schedules, thermostat), multipliers, surfaces with boundary conditions and explicit windows, and internal masses, but no constructions, no HVAC, and no simulation settings. EnergyPlus is not installed where the project is built and tested, and the owner does not want simulations run yet (D-112).

Decision

Scope (owner, D-112)

  • EnergyPlus 25.x. The writer targets EnergyPlus 25.2 (Version, 25.2;) and its object and field layout. No EnergyPlus is run by tests or by the component; correctness is checked on the text (see Tests).
  • Constructions come from an envelope preset. A new typed EnvelopePreset in Lod.Core (beside the program presets) holds one construction for each envelope role: exterior wall, roof, ground floor, exposed floor (added in S6 part B: floors facing outdoors over an overhang or an unsupported storey, D-074, need a construction of their own), interior wall, interior floor/ceiling, internal mass, and the window (simple glazing: U-value, solar heat gain coefficient, visible transmittance). A construction is a list of layers (thickness, conductivity, density, specific heat); values are illustrative and documented like the program presets (D-023) until sourced values exist. The same preset feeds Convert2IDF and Convert2BEM, so both outputs describe one envelope; it is the same at every level of detail, so geometry effects are not confounded with envelope changes (GLOBAL.md scientific rule 4). A default component Envelope Preset exposes it in Grasshopper.
  • HVAC is ideal loads. Every conditioned zone gets ZoneHVAC:IdealLoadsAirSystem with unlimited capacity and the zone's thermostat (D-038); unconditioned zones get no HVAC and no thermostat, but keep their loads and infiltration.
  • No simulation scope yet. The file holds the minimum to run once weather and outputs are chosen: Version, SimulationControl (no sizing, run on the weather-file period), Building, Timestep 6, RunPeriod for one full year starting on the presets' first day of the year, GlobalGeometryRules, and basic meters (heating, cooling, electricity, gas). No weather file, design day, or climate is chosen; location comes from the weather file at run time. Outputs and climates are decided when simulations are run (D-112).

Realisation (controller, provisional)

  • Writer. Lod.Export holds a pure C# writer (no RhinoCommon, no Grasshopper): objects are built as typed records and written as text with invariant culture, fixed number formatting (S6 part C: fifteen significant digits, G15, which .NET Framework 4.8 and .NET 8 format identically, unlike the round-trip format; the rounding, at most 5e-15 relative, is far below every tolerance), and a stable order (zones, then surfaces in model order); names are unique, at most 100 characters, and derived from zone and surface IDs. A header comment block carries the provenance and every zone's source zones and multiplier (GLOBAL.md scientific rule 2).
  • Constructions by role. ConstructionRoles.Of in Lod.Core.Conversion maps a surface and the boundary written for it (HeatTransferOptions.Exported) to its role, so both converters give a surface the same construction; the options never change a role. Construction layers are listed from the outside to the inside; an interior floor is listed from the zone below to the zone above, as the floor above sees it, and the ceiling below uses the reversed construction (Construction.Reversed, "<name> Reversed", the construction itself when symmetric), so the two sides of a slab list the same layers in opposite order. Of the two walls between two zones, the one whose zone ID sorts after the adjacent zone's ID (ordinal comparison) uses the reversed interior wall, so the two sides of a partition do too; this rule in ConstructionRoles is the only place that picks the reversed side, for both converters. A surface without a role (an unresolved boundary, a wall or ceiling on the ground) is the error NoConstructionRole, never an exception, because an overridden validation can let one through. Envelope names are written as they are and must be valid IDF names (EnvelopeName: at most 100 characters, no , ; !).
  • Validation blocks conversion unless Override is set, and the override is recorded, as in Convert2BEM (GLOBAL.md scientific rule 6).
  • Heat transfer between zones follows the shared HeatTransferOptions and ExportedBoundary (D-069, D-077): with an option off, the surfaces it covers are adiabatic; with it on, each interzone surface is written with its partner in the adjacent zone, the partner's vertices in reverse order. A surface between zones of different multipliers is written adiabatic even with the option on, and a warning names it (EnergyPlus cannot pair a multiplied zone with a single one meaningfully).
  • Zone multipliers go to the zone's Multiplier field (StackedFloorZoneMultiplier, ADR-013).
  • Surfaces without holes. EnergyPlus surfaces cannot have holes, and footprints and zones may (courts, ring zones, ring cores). Every horizontal polygon with holes is split deterministically into hole-free pieces with the same total area, each piece one surface, and interzone partners are split identically. Non-convex surfaces stay as they are; the building uses SolarDistribution FullExterior, which does not need convex zones. Collinear vertices that the pipeline keeps (ADR-002) are removed on export. (S6 part C: the split cuts the polygon by one line parallel to the y axis through the middle of each hole's x-range and clips it to the strips between the cuts; every hole is crossed by its own cut, so no strip encloses one. The first surface of an interzone pair in building order is split, and its partner takes the same pieces reversed. A piece narrower than the distance tolerance, which clipping on the grid leaves where rotated storeys touch along an edge (D-090, about 1e-6 m², below the area tolerance, so validation passes), cannot be an EnergyPlus surface: it is omitted on both sides with the warning SliverOmitted (GLOBAL.md quality rule 6). Split surfaces are reported with the info SurfaceSplit. Review of part C: a sliver is a piece whose cleaned ring has fewer than three vertices or an area of at most the distance tolerance times its perimeter; zero-width spikes and excursions through a repeated vertex, which clipping leaves on rotated stepped storeys, are removed (a ring still not simple is rebuilt as the union of its region; if the rebuilt rings that are not slivers do not keep the piece's area within the area tolerance plus the rebuilt slivers' area, the ring crosses itself and the conversion fails with DegeneratePolygon), with the same warning, which names the zone, floor or ceiling, elevation, and the areas removed; a floor or ceiling that is only slivers is omitted before partners are matched, because its two sides can clip to no overlap. Edges shorter than the 0.01 m at which EnergyPlus merges vertices are warned (ShortEdge); none occurs in the tests. 2026-10-03: the pipeline clips floors and ceilings from conformed footprints (ADR-002), so generated plans, rotated or not, no longer carry slivers, spikes, or excursions and no conversion of the tests warns SliverOmitted; the handling stays as a guard.)
  • Geometry rules. Vertices are counter-clockwise seen from outside the zone, starting at the upper-left corner, in the building's own coordinates, consistent with the orientation rule of D-091; windows are FenestrationSurface:Detailed on their wall. (Changed in S6 part C: the draft wrote world coordinates with a north axis of 0 "because plans are rotated in their geometry (D-070)". That holds only for Transform Plan: every generator also has OrientationDegrees, the clockwise rotation of plan north from true north, which the geometry does not apply and which validation adds to every wall azimuth (glazing per orientation). EnergyPlus ignores the building's north axis in world coordinates, so the writer uses relative coordinates with every zone origin at 0 and no zone rotation, which leaves the coordinates as they are, and writes the orientation as the building's north axis. EnergyPlus then sees the azimuths validation sees, and the vertices stay those of the pipeline and Convert2BEM.) Every zone states its volume and floor area, because a zone spanning storeys has no surfaces for the slabs inside it (D-031) and EnergyPlus would compute too small a floor area.
  • Loads.
  • Occupancy maps to People (people per floor area) with an activity schedule: a default metabolic rate of 120 W per person unless the preset gives one.
  • Lighting maps to Lights; electric and gas equipment to ElectricEquipment and GasEquipment, each in W per floor area with default radiant, latent, and lost fractions documented in the writer.
  • Infiltration and ventilation in air changes per hour map to ZoneInfiltration:DesignFlowRate and ZoneVentilation:DesignFlowRate.
  • Hot water is written as WaterUse:Equipment only when a preset defines it (none does yet).
  • A load basis the writer cannot express is an error, never silently dropped (ADR-007). (S6 part C: a basis EnergyPlus has no field for, such as per exterior wall area, per person for infiltration, or any basis of hot water, is written as the absolute design magnitude of one zone instance, value × basis quantity, which EnergyPlus applies identically because every design-level method resolves to a fixed level of the zone; so every basis is expressed and none is an error. Infiltration and ventilation have the coefficients 1, 0, 0, 0, so the flow is the design flow times the schedule; ventilation is balanced with no fan. Load objects follow zone by zone in program order, one per load component, D-047.)
  • Schedules are exact. Each 8760-value schedule (ADR-003) is written as Schedule:Year over Schedule:Week:Daily and Schedule:Day:Hourly objects, one per distinct day and week, so aggregated schedules are reproduced hour by hour (to fifteen significant digits since review of part C, far below the schedule tolerance); fraction schedules use a 0–1 ScheduleTypeLimits, setpoints a temperature limit. Holidays are not modelled. (S6 part C: the week schedules are seven-day blocks from 1 January, so any 8760 values are reproduced exactly whatever their profile; the last block, 31 December, takes its other weekdays from the block before it, and holidays, design days, and custom days use the Sunday day schedule. The run period is a calendar year that is not a leap year and starts on the presets' first day of the year (2018 for Monday), with the weather file's holidays and daylight saving off, because a leap year or a daylight-saving shift would move the hourly values off their days.)
  • Ground floors use Ground with monthly Site:GroundTemperature:BuildingSurface defaults (documented); terrace roof pieces are outdoor roofs (ADR-015).
  • Internal mass records (D-031) become InternalMass objects with the envelope preset's internal-mass construction and their slab area times their exposed faces. (Refined by D-143, 2026-10-16: an EnergyPlus InternalMass is one-sided with an adiabatic back, so Convert2IDF writes each exposed face as a half slice of the slab, Construction.Sliced, on slab area × faces: massive layers at half thickness, massless layers and air gaps at half resistance. The IDF then holds the slab's heat capacity once, which D-031's rule (storage and exchange area kept) requires; the whole slab on twice its area stored the capacity twice. The record, the rule, and Convert2BEM's exposed area are unchanged.)

Tests (no EnergyPlus run)

Snapshot IDFs of the canonical linear plan for every simplifier × aggregator combination, with both heat-transfer settings (S6 part C: one full file per combination would be tens of thousands of lines, so the snapshots are the minimal linear plan and four combinations covering each simplifier, each aggregator, and both settings once; all thirty-two combinations are read back and checked); a parser in the tests reads the IDF back and checks object counts and references (every surface's zone and construction exist, every partner pairs back, every schedule exists), and the research invariants against the building: floor area, glazing area per orientation, installed loads per type, and multiplier × area totals. Footprints with holes (enclosed court, court cluster, office plate ring) and a multi-storey plan (stepped band) are converted and checked the same way. The checks also cover planar, simple, outward-facing surfaces, hourly scheduled loads per type from the expanded IDF schedules, unique names, and reversed partner constructions; negative tests show that each check fails on a file broken in its way. Details: convert2idf.md.

To verify on the first EnergyPlus run (D-112)

  • Per-area loads in zones spanning storeys (Single Zone per Floor Type, Single Zone Building) rely on EnergyPlus using the zone floor area the file states (the slabs inside the zone have no surfaces), as it scales space floor areas to the stated Zone Floor Area.
  • The window construction is named like its glazing material (Construction and WindowMaterial:SimpleGlazingSystem share the name); the IDD keeps the two in separate reference lists.

The field layouts are no longer on this list: every class the writer uses was compared with the EnergyPlus 25.2.0 IDD, every object is written at least to its \min-fields with the IDD defaults explicit, and every file the tests convert passes scripts/idd-check (convert2idf.md).

Options considered

  • Run EnergyPlus in tests: rejected for now (D-112, not installed); the parse-back checks stand in until simulations are run.
  • Constructions inside each program preset: rejected; envelope would then change with zoning and merge rules, confounding geometry effects.
  • Schedule:Compact or Schedule:File: compact cannot reproduce aggregated hourly schedules exactly; a CSV beside the IDF makes the file not self-contained. The year/week/day objects are exact and self-contained.
  • Triangulating surfaces with holes: valid but produces many small surfaces; a split into a few hole-free pieces keeps the file readable.

Consequences

  • Lod.Export gains its first code; Lod.Core gains EnvelopePreset; Convert2BEM gains an envelope input and a constructions output.
  • Outputs, climates, and weather are open until simulations are run (D-112); the metabolic rate and load fractions are writer defaults until presets carry them.