Lumicron Documentation
DocumentationPDK authoringThe physical stack

The physical stack

The LayerStack records authored layer thicknesses, vertical positions, and optical material data. Lumicron packages these declarations for technology inspection and simulation consumers. A stack declaration alone does not run a field solver; Maple execution remains disabled in this alpha.

If your PDK doesn’t have public stack data (e.g. NDA’d foundry process), you can ship the layer table only and add the stack later. Components and routing don’t depend on it.

A complete stack

"""A physical layer stack with Sellmeier dispersion.

The `LayerStack` describes the physical reality of the process — what
sits on what, how thick each layer is, and the material's dispersive
refractive index. Simulators (mode solvers, FDTD wrappers) read the
stack to set up their cross-section.
"""
import lumicron as lm
import lumicron_pdk as lpdk

LAYER = lpdk.LayerTable(
    BOX  = lpdk.Layer(1, 0, color="#87ceeb"),
    SILC = lpdk.Layer(9, 0, color="#008000", min_width=0.2,
                    min_spacing=0.2, min_radius=5.0),
    SILN = lpdk.Layer(5, 0, color="#ff69b4", min_width=0.4,
                    min_spacing=0.3, min_radius=10.0),
    CLAD = lpdk.Layer(2, 0, color="#aac7e8"),
    MTL1 = lpdk.Layer(4, 0, color="#ffd700"),
)

# Sellmeier coefficients describe n(λ) for a material. The form is
# n²(λ) − 1 = Σ B_i · λ² / (λ² − C_i).
SiO2 = lpdk.Sellmeier(
    B=[0.6962, 0.4079, 0.8975],
    C=[0.0684**2, 0.1162**2, 9.8962**2],
)
Si = lpdk.Sellmeier(
    B=[10.6684, 0.0030, 1.5413],
    C=[0.3015**2, 1.1348**2, 1104.0**2],
)
SiN = lpdk.Sellmeier(B=[2.8939], C=[0.1397**2])

STACK = lpdk.LayerStack(
    lpdk.StackLayer("BOX",      layer=LAYER.BOX,  thickness=2.0,  sellmeier=SiO2),
    lpdk.StackLayer("core_si",  layer=LAYER.SILC, thickness=0.22, sellmeier=Si),
    lpdk.StackLayer("core_sin", layer=LAYER.SILN, thickness=0.4,  sellmeier=SiN),
    lpdk.StackLayer("clad",     layer=LAYER.CLAD, thickness=2.0,  sellmeier=SiO2),
    lpdk.StackLayer("metal1",   layer=LAYER.MTL1, thickness=1.0,  n=0.0),
)


@lm.pcell
def StackPreview():
    """A layout that exposes the stack's process layers as a strip."""
    c = lm.CELL("StackPreview")
    for i, name in enumerate(["BOX", "SILC", "SILN", "CLAD", "MTL1"]):
        rect = lm.Rectangle(x_dim=80, y_dim=20, layer=getattr(LAYER, name))
        h = c.add(rect)
        c.Place(h).at((0, i * 30))
    return c


if __name__ == "__main__":
    StackPreview().to_gds("stack_preview.gds")
Output of 02_layer_stack.py - process layers as horizontal swatches.

The material and stack building blocks:

Type Purpose
Sellmeier Coefficients for n²(λ) = 1 + Σ B_i · λ² / (λ² − C_i).
TabulatedIndex Validated wavelength samples; use bulk material data for a stack layer.
StackLayer One physical layer: name, GDS layer ref, thickness, optical model.
LayerStack Ordered collection of StackLayers, bottom to top.

Sellmeier coefficients

The Sellmeier equation is the standard way to express dispersive n(λ) for transparent dielectrics. lumicron.Sellmeier(B=[…], C=[…]) takes the textbook coefficients in Bᵢ / λ²-units. SiO2, Si, and SiN have well-known constants - copy them from a reference (Palik, Malitson, IUPAC) so your end users get accurate dispersion.

For a declared constant real index approximation, pass n= directly:

lpdk.StackLayer("cladding", layer=LAYER.OXID, thickness=1.0, n=1.44)

Use only one of n, sellmeier, or tabulated on each layer. tabulated must describe a bulk material, not a waveguide effective index. If optical properties are unavailable, leave them unspecified; n=0 is not a special declaration of a metal or perfect conductor.

Layer order

When z_start is omitted, the first layer starts at zero and each following layer starts at the preceding layer’s end. An explicit z_start is preserved, including zero or negative positions, and can express a gap or overlap. z_min and z_max report the resulting stack envelope. A typical authored SOI sequence might be:

  1. BOX (buried oxide)
  2. Silicon waveguide core
  3. (optional) silicon nitride strip
  4. Top oxide cladding
  5. Metal-1
  6. Inter-metal oxide
  7. Metal-2

Match your foundry’s PDK datasheet exactly. Off-by-one errors here are subtle - they don’t break compilation, just mode-solver results.

When the stack matters at runtime

Routing geometry is declared by profiles and components; the stack provides separate physical technology metadata. It is serialized into the PDK manifest and available through pdk.STACK. Use pdk.STACK.print_stack(), iterate its layers, or inspect a named layer’s thickness, z_start, and n_at(wavelength) value. A LayerStack.cross_section(at=...) method is not part of the current API.

Publish only material and dimensional values supported by your process data. Missing optical data should remain missing, rather than being filled with a placeholder that could be mistaken for a validated simulation input.

Note

The stack does not describe processing steps (e.g. “after litho on SILC, etch is partial”). It’s a finished-process model. Process-history modeling, when it matters (TCAD-style flows), lives outside the PDK in tooling that consumes the stack as a starting point.

Search documentation

Type to search all guides and API references.

↑ ↓ to select · Enter to open · Esc to close