Registry and physical test manifests
Registry connects design intent to a physical test manifest. It does not run a laser, probe station or measurement recipe.
Two operations define the workflow:
lm.register(cell, ...)marks an exact cell definition as a testable DUT.lm.build_registry(root)finds its registered placed occurrences anywhere inside that root’s hierarchy.
An unregistered container does not stop discovery. If both a module and its children are registered, they are separate entries. The supplied root itself is a definition, not a placed occurrence, and is excluded. Building a DOE’s Registry therefore gives its local DUTs; building TOP’s Registry includes those DUTs through every placement of the DOE. No forwarding or publication step is required.
Declare named test ports
import lumicron as lm
core = lm.LayerSpec(layer=1)
dut = lm.CELL("LOSS_DUT")
guide = dut.add(lm.Waveguide([(0, 0), (200, 0)], width=0.5, layer=core))
guide.promote({"i1": "input", "o1": "output"})
lm.register(dut, ports=["input", "output"],
data={"test_type": "spectral", "recipe": "cutback", "notes": "Reference first"})
doe = lm.CELL("LOSS_DOE")
first = doe.add(dut)
second = doe.add(dut)
doe.Place(second).at((0, 100))
top = lm.CELL("TOP")
block = top.add(doe)
top.Place(block).at((1000, 500))
local = lm.build_registry(doe) # two occurrences, DOE coordinates
registry = lm.build_registry(top) # two occurrences, TOP coordinates
print(registry.status)
for issue in registry.issues:
print(issue.instance_path, issue.message)
registry.write_csv("test-manifest.csv")
registry.write_json("test-manifest.json")
top.to_gds("top.gds")ports accepts a nonempty list or tuple of unique, nonempty strings. Names are exact and belong to the registered DUT’s own declared interface. Missing ports make the entry and Registry incomplete; the DUT remains visible with an issue. Registry never searches descendants for an equal name. Use normal explicit port promotion when the DUT must expose a deeper interface.
Each port record contains its name, transformed position, outward direction, width, GDS layer/datatype, port type and route-profile name when present. Lengths are micrometres. Directions are degrees counter-clockwise from +X. Positions, directions and widths include every ancestor translation, rotation, reflection and magnification in the supplied root’s frame. Port records are distinct from the DUT’s reference origin and transform.
Existing physical I/O sites
lm.register(dut, io=GratingCoupler, data={"recipe": "fiber_alignment"})The established io=Factory form selects exact @pcell/@gdscell factories below a DUT. These records retain the physical I/O instance origins, which may be fiber landing sites. They are not aliases for named PORT centers. The search remains recursive; a nested registered DUT owns its own I/O subtree and its sites are not also attributed to the outer DUT. Both registered DUTs still appear in the Registry. No matching site produces an explicit incomplete entry.
Supply exactly one of io or ports. Supplying both is an error. Re-registering the same definition intentionally replaces its declaration. A registration is shared by placements of that exact definition; an occurrence-specific metadata override is not provided in this phase.
Identity, hierarchy and validity
Entries use the existing authored instance path, not coordinates or a sibling slot, for DUT identity. Repeated placements remain separate. Moving a supported authored occurrence changes coordinates without transferring its identity. Hierarchy display names are context, not an identity substitute.
The existing provenance limits still apply: ambiguous repeated source assignments and arbitrary raw Python executions cannot establish regeneration continuity. Use unambiguous authored handles in the supported Script execution context, or persist an existing authored model. Registry does not invent identity matching.
ARRAY is geometry-only. Registry does not manufacture independently testable array occurrences. An array containing registered definitions produces an unsupported-target issue; use real placements for independently testable DUTs. Old schema-1/2 snapshots containing array records remain readable as historical unvalidated projections, not newly qualified test targets.
status is complete or incomplete for schema 3. A complete empty Registry is different from one whose child definition is missing. Structural issues identify missing definitions, unavailable selected interfaces and unsupported test targets. Malformed declarations, invalid data, duplicate authored identities and hierarchy cycles can reject the build outright. Neither path reports a valid partial result. Registry validation is not DRC, LVS or fabrication qualification.
data remains an opaque, deeply copied JSON dictionary. Strings, finite numbers, booleans, null, lists and string-keyed dictionaries are supported. Recipes are identifiers, not executable instructions. CELL.add_info() is independent; its values are never copied automatically into the manifest.
Native Registry Viewer
Generate a semantic layout after build_registry(top), then use Registry in the Layout document bar. Rows retain hierarchy paths, validity, interface counts and physical locations. The Within filter narrows the already resolved Registry to a container; coordinates remain in the explicitly displayed Registry root frame. To obtain DOE-local coordinates, build/open the DOE’s own layout.
DUT overlays outline the entire loaded DUT bounding box, transformed into the Registry root frame; they are display annotations, not mask geometry. Selecting a row centers that physical occurrence through the existing Layout navigation and shows a separate Registry summary in Inspector. Legacy I/O markers stay at their distinct site origins. Missing geometry does not acquire an invented box. Named test ports and opaque metadata are inspectable there. Reverse selection is available when the selected authored reference resolves to exactly one Registry occurrence; ambiguous repeated definition-local selections are not guessed. A non-geometric issue does not acquire an invented marker.
Export writes CSV or JSON from the same resolved model. Incomplete exports remain visibly incomplete. Consumers must check status and issues. Old snapshots show Legacy / unvalidated rather than claiming modern validation.
Deterministic exports
Schema 3 JSON records the root, coordinateFrame: "root-cell", units: "um", status/issues and entries. An entry contains authored path, hierarchy, composed transform, selected/resolved named ports, separate legacy io sites and opaque data. Keys and interface/entry ordering are canonicalized. No timestamp or memory address is included. JSON/YAML snapshots are unattested; only embedding in a validated semantic artifact binds a projection to exact generated geometry.
CSV has one row per resolved named port or I/O site, a DUT row when no interface resolved, and issue rows for failures without a resolved DUT. Column order is:
schema_version, root_cell, coordinate_frame, units, registry_status,
registration_id, authored_instance_path, instance_path, cell_name, status,
interface_kind, interface_id, port_name, x_um, y_um, direction_deg,
width_um, layer, datatype, route_profile, port_type, metadata_json, issues_json
Entries sort by ID; ports by name; sites by ID. Metadata/issues use escaped JSON cells rather than inventing team-specific columns. Unknown fields are blank. UTF-8 preserves Unicode. LF ends rows. Fields containing quotes, commas or newlines are quoted with doubled internal quotes. Numbers use each producer’s locale-independent round-trip decimal representation; compare numeric values across Python and native exports, not their float formatting. Equivalent models produce stable bytes within each producer. CSV and JSON retain the same evidence.
Persistence and freshness
Authored source owns reproducible declarations; serialized internal Layout state retains declarations and authored IDs. GDS semantic sidecars and .lum retain resolved projections for inspection. A portable .lum is not a complete source project. Raw GDS import does not recreate registration intent. Imported cells can be explicitly registered after their supported ports are supplied.
Build again after edits. A new build uses current transforms and interfaces; deleted occurrences disappear, and removed selected ports create issues. Export recomputes an existing Registry rather than stamping old coordinates onto new geometry. Earlier returned Registry objects remain snapshots. File replacement is staged after serialization; process-kill/power-loss durability is not claimed.
Complete qualification example
Examples/Phase10Registry contains MZI, ring, loss and legacy calibration DUTs, separate TOP/DOE builds, exports, failure/move fixtures and consume.py. The consumer uses only the Python standard library. It refuses incomplete/legacy inputs and produces a deterministic hypothetical queue with interfaces and metadata. No instrument is operated, and the fixture is not fabrication-qualified.