Lumicron Documentation

Cheat sheet

A compact reference. Skim this once before reading anything else.

Boilerplate

import lumicron as lm
import lumicron.pdks.elyon_demo.all as pdk

chip = lm.CELL("Chip")
# ... build ...
chip.to_gds("chip.gds")

Cells & shapes

Call What you get
lm.CELL("Name") New cell
lm.Rectangle(x_dim=, y_dim=, layer=) Centered rectangle
lm.Rectangle(..., centered=False) Origin at lower-left
lm.Circle(radius=, layer=) Filled circle
lm.Ring(outer_radius=, width=, layer=) Annulus
lm.Polygon(points=[(x,y), …], layer=) Arbitrary polygon
lm.ARRAY(child, count=, pitch=(dx, dy)) Periodic array
c.add(thing) Add to cell, returns handle

Placement

Chain method Effect
.at((x, y)) Set the selected anchor’s target
.using("W"/"E"/"N"/"S"/"NE"/...) Use a child anchor instead of its origin
.using("C") (not .using(handle.C)) Select a local anchor; handle properties are world points
.rotate_by(deg) Rotate CCW
.move_by(dx, dy) Accumulate a parent-coordinate shift for references
.right_of(other), .left_of(other) Anchor-to-anchor align
.above(other), .below(other) Anchor-to-anchor align
.using("i1").at(other.ports["o1"]) Snap a port onto another (translate only)
Call Effect
c.Join(a.ports["in"], b.ports["out"]) Mate two ports: a’s cell moves + rotates onto b’s port; warns on width/layer mismatch

Ports

Call What it does
lm.PORT("name", position=, direction=, width=, layer=) Define a port
lm.PORT(..., port_type="electrical") Electrical (vs optical)
lm.PORT(..., route_profile=...) Attach a profile
c.ports["name"] / handle.ports["name"] Look up a port
handle.promote(ports=[...], prefix="...") Re-publish child ports
c.show_ports() Print port table

Direction: degrees CCW from +X. 0 = E, 90 = N, 180 = W, 270 = S.

Routing - global kwargs

chip.Route(a, b,
           radius=10,                  # bend radius (µm)
           bend="circular",            # "circular" | "euler" | CELL
           p=0.5,                      # euler fraction (0–1)
           profile=pdk.RP.silc_strip,  # cross-section recipe
           style=None,                 # automatic; or "manhattan", "direct", "sbend"
           start_straight=0,           # min straight after port_a
           end_straight=0,             # min straight before port_b
           clearance=0,                # detour around obstacles by this µm
           transition_offset=50,     # auto layer-transition position
           transitions=None)           # custom TransitionRegistry

Routing - chain methods

Method Effect
.go("E"/"N"/"W"/"S", by=, to=) Manhattan section
.go("NE"/"NW"/"SE"/"SW", by=(dx, dy)) S-bend section
.jog(dir, by=) U-shaped detour
.style(arg=, profile=, layer=, radius=, width=, bend=) Section-level style overrides
.style("default") Revert all section overrides
.radius(r) Override radius for next section
.bend(b, p=) Override bend type for next section
.width(w) Override width - auto-taper on boundary
.taper(offset=, width=, length=) Insert a positional taper
.start_taper(width=, length=) Configure port_a-side taper
.end_taper(width=, length=) Configure port_b-side taper
.match_length_to(other, delta=, …) Length-match this route to another

Routing bundles

bundle = chip.Route(ports_a, ports_b,
                    spacing=10, radius=15,
                    style="manhattan", sort=False)
bundle.match_lengths()     # target, delta, mirror, tolerance
first_channel = bundle.routes[0]

Then call .go(...) for Manhattan-mode bundles, or chain .taper(...) / .match_lengths(...) to broadcast.

Bookmarks

chip.Place(thing).at(...).add_bookmark(name="...", group="...", notes="...")
chip.add(lm.Bookmark("alignment", at=(x, y)))
chip.add(lm.Bookmark("dicing_lane", bbox=(xmin, ymin, xmax, ymax)))

Output

chip.to_gds("chip.gds")
chip.to_oas("chip.oas")        # OASIS
chip.to_gds(max_points=199)    # legacy GDS-II compat

Useful introspection

c.show_ports()
pdk.LAYER.print_rules()
pdk.RP.print_rules()
any_obj.rules()         # most objects support this

Search documentation

Type to search all guides and API references.

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