# Stackup XML Format
This document describes the XML file format read by `util_stackup_reader.read_substrate()`.
It defines the process stackup used to build a 3D simulation model from GDSII: materials,
the dielectric stack, the drawn metal/via layers and their GDSII layer numbers, optional
derived (computed) layers, and optional thermal-conductivity tables.
Reference files in this repo: [`SG13G2_200um.xml`](../workflow/SG13G2_200um.xml) (basic
stackup) and [`SG13G2_with_resistors_200um.xml`](../more_examples/resistors_sg13g2/SG13G2_with_resistors_200um.xml)
(adds resistor materials and derived-layer examples using `AND`/`OR`/`NOT`).
## Top-level structure
```xml
...
...
...
...
...
```
`schemaVersion` doesn't change how the reader parses a file (no attribute's meaning branches
on it) — but `read_substrate()` does print a warning if a file declares a `schemaVersion`
newer than `util_stackup_reader.SUPPORTED_SCHEMA_VERSION` (currently `"3.0"`), since such a
file may use attributes this version of the reader doesn't know about yet.
## ``
One `` element per material, referenced by name from `` and ``
elements later in the file.
> **Note:** `Density`, `ThermalConductivity`, and `ThermalConductivityTable` are **not used by
> S-parameter simulation**. They are only read when this XML file is used in a thermal
> simulation flow — leaving them at their defaults (or omitting them) has no effect on EM
> simulation results.
| Attribute | Required | Default | Description |
|----------------------------|----------|---------|--------------|
| `Name` | yes | — | Material name, referenced elsewhere as `Material="..."`. |
| `Type` | yes | — | `Conductor`, `Dielectric`, `Semiconductor`, or `Resistor`. |
| `Permittivity` | no | `1` | Relative permittivity (εr). |
| `DielectricLossTangent` | no | `0` | Loss tangent. |
| `Conductivity` | no | `0` | Conductivity in S/m. Used for `Conductor`/`Semiconductor` materials. |
| `Rs` | no | `0` | Sheet resistance in Ω/square. Used for `Resistor` materials (paired with a zero-thickness `Type="sheet"` layer). |
| `Density` | no | `1` | Mass density, used by thermal simulation setup. |
| `ThermalConductivity` | no | `0` | Constant thermal conductivity, used by thermal simulation setup. |
| `ThermalConductivityTable` | no | — | Name of a `` (see [Tables](#tables-thermal-conductivity) below) to use instead of a constant value, for temperature-dependent conductivity. |
| `Color` | no | — | Hex RGB color (no `#`), used for 3D preview / GUI display. |
> **Built-in default `"AIR"`:** if the file has no `` entry, one is added
> automatically (`Type="Dielectric" Permittivity="1.0" DielectricLossTangent="0.0"
> Conductivity="0" Color="d0d0d0"` — the same values used across the example stackups in this
> repo), so `Material="AIR"` just works on a ``/`` without declaring it
> explicitly. Defining your own `` overrides this default.
```xml
```
## ``
Container for the dielectric stack and drawn layers. `LengthUnit` sets the unit for all
`Thickness`/`Zmin`/`Zmax`/`Offset`/`Oversize` values in this section (typically `"um"`).
### ``
Defines the vertical dielectric stack, independent of GDSII — these layers exist everywhere
and are not drawn as polygons. Order in the file is **top to bottom**. Three ways to position
a ``, in the order they take priority:
1. **Absolute** — both `Zmin` and `Zmax` given (no `Reference`).
2. **Reference-relative** — `Reference` given (see below).
3. **Implicit stacking** (the default/legacy behavior) — neither of the above: z-positions are
computed automatically by stacking `Thickness` values from the top down
(`calculate_zpositions()` walks the list in reverse).
| Attribute | Required | Default | Description |
|-----------------|----------|---------|--------------|
| `Name` | yes | — | Dielectric name. Must be unique across ``. |
| `Material` | yes | — | References a `` by name. |
| `Thickness` | yes* | — | Layer thickness. Used to auto-stack this dielectric relative to its neighbors, or (with `Reference`) to size it from the reference edge. |
| `Zmin`/`Zmax` | no | — | Absolute z-position instead of `Thickness` (both required together); or, with `Reference` set, offsets from the reference edge (both optional there — see below). |
| `Reference` | no | — | Name of another `` to position this one relative to. |
| `ReferenceEdge` | no | `Top` | `Top` or `Bottom` (case-insensitive). Only meaningful with `Reference` set. |
| `Boundary` | no | — | GDSII layer number that defines this dielectric's finite (x,y) extent in the model. Optional — omit for a dielectric that simply fills the whole simulation domain. |
\* `Thickness` is required unless `Zmin`/`Zmax` are both given (absolute mode), or `Zmax` is
given (`Reference` mode).
```xml
```
With an explicit boundary layer instead of the full domain:
```xml
```
#### Reference-relative positioning (Dielectrics)
Like ``'s `Reference` (below), but Dielectrics keep `Thickness` as their primary size
instead of requiring both `Zmin`/`Zmax`: `Zmin` defaults to `0` (start right at the reference
edge — the common case) and `Zmax` defaults to `Zmin + Thickness`. Either can still be given
explicitly to override — e.g. a small designed gap before this dielectric starts.
```xml
```
`Reference` on a Dielectric can only target another `` — never a `` (Layers
are resolved after Dielectrics, so the reverse would be a circular pipeline dependency).
**Implicit stacking, made explicit internally:** the reader auto-assigns an in-memory
`Reference` (to the nearest dielectric below it in file order that is *also* using implicit
stacking, `ReferenceEdge="Top"`) to every dielectric that has neither an explicit `Reference`
nor an absolute position — this is purely descriptive (it does not change the computed
z-position, and by default it is **not** written back into the XML file). It lets other code
treat every dielectric's positioning uniformly through `.reference`/`.reference_edge`, and lets
the Stackup Editor's Dielectrics tab show a live Reference-style relationship even for
old-style, purely `Thickness`-stacked files. The Stackup Editor offers, once per file per
editing session at Save time, to write these auto-assigned references into the XML — declining
leaves the file exactly as implicit as before (same resulting z-positions either way).
Note one legacy quirk this auto-assignment deliberately preserves: an absolute-position or
explicit-`Reference` dielectric sitting between two implicit ones is transparent to implicit
stacking — implicit dielectrics keep stacking against each other as if it weren't there, not
against its own `Zmax`. Mixing absolute/Reference dielectrics with implicit ones is uncommon;
if you rely on one sitting directly beneath an implicit dielectric, give that implicit
dielectric an explicit `Reference` instead of relying on file order.
### ``
Drawn layers: metals, vias, sheet resistors, and dielectric "bricks" that are read from
specific GDSII layer numbers instead of being implied by the dielectric stack.
An optional `` element shifts the z-position of every `` by
a fixed amount (used e.g. to place the drawn stack on top of a backside/substrate region
that is itself modeled with negative z).
| Attribute | Required | Default | Description |
|-----------|----------|---------|--------------|
| `Name` | yes | — | Layer name, used for lookups (`getbylayername`) and in port definitions (`from_layername`/`to_layername` etc. elsewhere in the pipeline). Must be unique across ``, and must not collide with a `` name (see `Reference` below). |
| `Type` | yes | — | `conductor`, `via`, `dielectric`, or `sheet` (see below). |
| `Material`| yes | — | References a `` by name, or the reserved keyword `"PEC"` (see below). |
| `Zmin` | yes | — | Bottom z-position — absolute, or an offset from `Reference`'s edge if `Reference` is set (see below). |
| `Zmax` | yes | — | Top z-position, same absolute-vs-offset rule as `Zmin`. Equal to `Zmin` forces `Type` to `sheet` regardless of the stated `Type`. |
| `Layer` | yes | — | GDSII layer number. Also used as the target layer number for a [derived layer](#derivedlayers-boolean-operations-on-layers), in which case its geometry does not need to exist directly in the GDSII file. |
| `Reference` | no | — | Name of another `` or `` to position this layer relative to. When set, `Zmin`/`Zmax` are reinterpreted as offsets from the resolved reference edge instead of absolute z (positive = up). Dielectric and Layer names share one namespace for this lookup, so a name must not exist as both. |
| `ReferenceEdge` | no | `Top` | `Top` or `Bottom` (case-insensitive). Only meaningful with `Reference` set. For a `` target: its top/bottom z. For a `` target: its `Zmax`/`Zmin`. |
Layer `Type` meanings:
- **`conductor`** — a normal metal layer with thickness (`Zmax > Zmin`).
- **`via`** — a vertical connection between two conductor layers; eligible for via-array
merging (`merge_polygon_size` in `read_gds()`).
- **`dielectric`** — a drawn (GDSII-sourced) dielectric region, as opposed to the implicit
stack in ``.
- **`sheet`** — zero-thickness layer (`Zmin == Zmax`), typically paired with a `Resistor`
material for sheet-resistance elements.
> **Reserved keyword `Material="PEC"`:** valid on a `conductor`, `via`, or `sheet` layer with no
> matching `` entry at all — it bypasses the `` list entirely and is
> modeled as a literal ideal conductor (`CSX.AddMetal(...)`), for the polygon/volume itself in
> all three cases — openEMS is FDTD, so unlike an FEM solver it has no "domain vs. boundary"
> distinction that would make a PEC via any less exact than a PEC sheet or metal.
```xml
```
#### Reference-relative positioning (Layers)
Instead of an absolute z-position, a `` can position itself relative to the top or
bottom edge of a named `` or another ``, by setting `Reference`
(+ optional `ReferenceEdge`, default `Top`). `Zmin`/`Zmax` are then offsets from that edge
(positive = up), not absolute z — the layer may lie fully inside, fully outside, or straddle
the reference's own z-range. This avoids hand-recomputing every dependent ``'s z-position
whenever a `` changes; a `` can itself be a `Reference`
target for another ``, chaining any number of levels deep (resolved in dependency order,
regardless of file order).
```xml
```
Two rules apply:
- **Shared namespace**: `Reference` is looked up against `` names and ``
names together, so a name must not exist as both — and `` names must be unique (unlike
the general case, this is enforced when `Reference` is used).
- **Mutual exclusivity with ``**: a file must not mix
`Reference`-based `` positioning with a nonzero `` — it would
be ambiguous whether the offset applies before or after reference resolution. Use `Reference`
to point at a backside dielectric's edge directly instead of using `Offset`.
`Reference` is orthogonal to [``](#derivedlayers-boolean-operations-on-layers) —
a derived layer's own `` entry (the one giving it a Z-position/material) can use
`Reference` like any other layer.
### `` (boolean operations on layers)
Defines new layer numbers whose geometry is *computed* from other layers (boolean
operations and/or resizing) instead of being read directly from GDSII — e.g. an overlap
between two drawn layers, used here to derive resistor geometry from poly/implant/contact
layers. Full reference, including chaining and self-touching polygon handling, is in
[`derived_layers.md`](derived_layers.md); summary:
- Give the derived layer's target `Layer` number a normal `` entry too (as above),
so it gets a Z-position/material and is included in `metals_list.getlayernumbers()`.
- `Operation` is one of `AND`, `OR`, `XOR`, `NOT` (≥2 `` children, folded pairwise
in order — order matters for `NOT`), or `SIZE` (exactly 1 operand, requires non-zero
`Oversize`, pure resize with no boolean op).
- `Oversize` (optional, any operation) grows (positive) or shrinks (negative) the result by
a fixed distance in layout units, applied after the boolean step.
- An `` can reference a native GDSII layer number or another derived
layer's number; dependencies are resolved automatically regardless of definition order.
```xml
```
Three or more operands are allowed for `AND`/`OR`/`XOR`, folded left to right — used here to
intersect three layers into one resistor recognition layer:
```xml
```
## `` (thermal conductivity)
Optional, sibling of `` and `` directly under ``. Defines named
temperature/value lookup tables for materials whose thermal conductivity depends on
temperature (referenced from `` instead of a
constant `ThermalConductivity`).
```xml
```
```xml
```
## What `read_substrate()` returns
```python
materials_list, dielectrics_list, metals_list = stackup_reader.read_substrate(XML_filename)
```
- `materials_list` — all `` entries (`stackup_materials_list`).
- `dielectrics_list` — all `` entries, with z-positions resolved
(`dielectric_layers_list`).
- `metals_list` — all `` entries, sorted by z with above/below neighbors resolved
(`metal_layers_list`). `metals_list.getlayernumbers()` is the layer list normally passed to
`gds_reader.read_gds()`.
- `metals_list.derived_layers` — parsed `` entries (empty if the XML has none).
Not a separate return value, so this signature stays compatible with older 3-value call
sites; `read_gds()` picks it up automatically from `metals_list` if not passed explicitly.