Working with PDKs
A process design kit packages everything a foundry’s process gives you:
- Named layers with design rules.
- Pre-made route profiles (
RP.silc_strip,RP.siln_strip, …). - Components with authored geometry and declared ports (
EdgeCouplerSi,NxM_MMI,PhotonicElevator, modulators, …). - A transition registry so cross-layer routes auto-insert the right PCell.
lumicron ships with elyon_demo, an internal PDK we use throughout this guide. Load foundry .lumpdk archives in Lumicron. For standalone Python use, install a corresponding Python distribution when the PDK publisher provides one; pip does not install .lumpdk archives.
Importing
import lumicron.pdks.elyon_demo.all as pdkThe .all re-export gives you the conventional namespaces:
| Namespace | Contents |
|---|---|
pdk.LAYER |
Named layers (SILC, SILN, MTL1, …). |
pdk.RP |
Route profiles (silc_strip, siln_strip, …). |
pdk.<Component> |
Components - EdgeCouplerSi, NxM_MMI, … |
The import line explicitly names the PDK the script targets. Keep it consistent with the PDK loaded into the active project. By convention, alias it to pdk as above.
Discovering what’s in a PDK
LAYER and RP support .print_rules() for a quick reference card:
pdk.LAYER.print_rules() # all layers + min_width / min_spacing / min_radius
pdk.RP.print_rules() # all profiles + their cross-sectionsIndividual layers also support .rules() and inspecting fields directly (layer.layer, layer.datatype, layer.color, layer.min_width).
Using PDK components
PDK components are @pcell-decorated factories. Call them like functions; the returned cell is parametrized and auto-named:
coupler = pdk.EdgeCouplerSi(width=0.5) # default-named cell
coupler_wide = pdk.EdgeCouplerSi(width=1.5) # different cell - different name auto-generated
a = c.add(coupler)
b = c.add(coupler_wide)
c.Place(a).at((0, 0))
c.Place(b).at((0, 1000))The @pcell decorator derives cell identity from its factory, source, PDK, and effective typed parameters. Every call constructs a cell; it does not return a cached mutable object. To place two instances of one constructed definition, keep that cell and call c.add(cell) twice.
Component ports
When component ports carry compatible route_profile declarations, c.Route(coupler.ports["o1"], modulator.ports["i1"]) can inherit routing defaults. Otherwise, provide a profile explicitly. Cross-layer routing requires a registered transition; the router does not infer an arbitrary physical transition from layer names.
Tip
This is the payoff for a well-curated PDK: scripts read like circuit diagrams. Once your team’s PDK has profile-tagged ports on every component, end-user scripts shrink dramatically.
Loading a PDK in Lumicron
Use File > Load PDK or Change PDK in the project inspector to choose a .lumpdk archive. The active project’s PDK metadata and Python package form the context for scripts, schematics, and layout inspection. Keep the script’s explicit import consistent with that PDK.
A PDK has a human display name and a Python import identity package-name in META. Use the import name shown by the active PDK; do not derive Python names from display text. The retired package_name authoring key is rejected. The demo import above is for examples, not a replacement for a foundry PDK.
Writing your own PDK
Defining new layers, components, and route profiles for an in-house process is covered in the separate PDK Authoring Guide. That document includes a full chapter on the @route_profile builder - the API for declaring custom cross-sections with continuous strokes (p.layer(...)) and periodic features (p.tooth(...)).