2026-04-02 12:19:51 -07:00
|
|
|
"""
|
2026-04-22 21:24:05 -07:00
|
|
|
Tutorial: authoring a mixed library with `BuildLibrary`.
|
2026-04-02 12:19:51 -07:00
|
|
|
|
|
|
|
|
This example assumes you have already read `devices.py` and generated the
|
|
|
|
|
`circuit.gds` file it writes. The goal here is not the photonic-crystal geometry
|
2026-04-22 21:24:05 -07:00
|
|
|
itself, but rather how Masque lets you combine imported GDS cells with
|
|
|
|
|
python-generated recipes, then turn that declaration set into a normal library
|
|
|
|
|
for downstream assembly and writing.
|
2026-04-02 12:19:51 -07:00
|
|
|
"""
|
2024-07-28 19:33:16 -07:00
|
|
|
from typing import Any
|
2022-02-27 21:21:44 -08:00
|
|
|
from pprint import pformat
|
|
|
|
|
|
|
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
from masque import BuildLibrary, Pather, Pattern, cell
|
2026-04-21 23:17:31 -07:00
|
|
|
from masque.file.gdsii import writefile
|
2026-04-22 21:24:05 -07:00
|
|
|
from masque.file.gdsii_lazy import readfile
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
import basic_shapes
|
|
|
|
|
import devices
|
|
|
|
|
from basic_shapes import GDS_OPTS
|
|
|
|
|
|
|
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
def make_mixed_waveguide(lib: BuildLibrary) -> Pattern:
|
|
|
|
|
"""
|
|
|
|
|
Recipe which assembles imported and generated cells behind the builder API.
|
|
|
|
|
"""
|
|
|
|
|
circ = Pather(library=lib, ports='tri_l3cav')
|
|
|
|
|
|
|
|
|
|
# First way to specify what we are plugging in: request an explicit abstract.
|
|
|
|
|
circ.plug(lib.abstract('wg10'), {'input': 'right'})
|
|
|
|
|
|
|
|
|
|
# Second way: use an AbstractView, which behaves like a mapping of names
|
|
|
|
|
# to abstracts.
|
|
|
|
|
abstracts = lib.abstract_view()
|
|
|
|
|
circ.plug(abstracts['wg10'], {'output': 'left'})
|
|
|
|
|
|
|
|
|
|
# Third way: let Pather resolve a pattern name through its own library.
|
|
|
|
|
circ.plug('tri_wg10', {'input': 'right'})
|
|
|
|
|
circ.plug('tri_wg10', {'output': 'left'})
|
|
|
|
|
|
|
|
|
|
return circ.pattern
|
|
|
|
|
|
|
|
|
|
|
2022-02-27 21:21:44 -08:00
|
|
|
def main() -> None:
|
2026-04-22 21:24:05 -07:00
|
|
|
builder = BuildLibrary()
|
|
|
|
|
cells = builder.cells
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Load some devices from a GDS file
|
|
|
|
|
#
|
|
|
|
|
|
2026-04-21 23:17:31 -07:00
|
|
|
# Scan circuit.gds and prepare to lazy-load its contents. Port labels are
|
2026-04-22 21:24:05 -07:00
|
|
|
# imported on first materialization, but the raw source remains untouched
|
|
|
|
|
# until we build the final library.
|
2026-04-21 23:17:31 -07:00
|
|
|
gds_lib, _properties = readfile('circuit.gds')
|
2026-04-22 21:24:05 -07:00
|
|
|
builder.add_source(gds_lib.with_ports_from_data(layers=[(3, 0)], max_depth=1))
|
2022-02-27 21:21:44 -08:00
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
print('Registered imported cells:\n' + pformat(list(gds_lib.keys())))
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
#
|
2026-04-22 21:24:05 -07:00
|
|
|
# Register some new devices, this time from python code rather than GDS.
|
2022-02-27 21:21:44 -08:00
|
|
|
#
|
|
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
cells.triangle = basic_shapes.triangle(devices.RADIUS)
|
2023-07-17 20:22:04 -07:00
|
|
|
opts: dict[str, Any] = dict(
|
2026-04-22 21:24:05 -07:00
|
|
|
lattice_constant=devices.LATTICE_CONSTANT,
|
|
|
|
|
hole='triangle',
|
|
|
|
|
)
|
2022-02-27 21:21:44 -08:00
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
cells.tri_wg10 = cell(devices.waveguide)(length=10, mirror_periods=5, **opts)
|
|
|
|
|
cells.tri_wg05 = cell(devices.waveguide)(length=5, mirror_periods=5, **opts)
|
|
|
|
|
cells.tri_wg28 = cell(devices.waveguide)(length=28, mirror_periods=5, **opts)
|
|
|
|
|
cells.tri_bend0 = cell(devices.bend)(mirror_periods=5, **opts)
|
|
|
|
|
cells.tri_ysplit = cell(devices.y_splitter)(mirror_periods=5, **opts)
|
|
|
|
|
cells.tri_l3cav = cell(devices.perturbed_l3)(xy_size=(4, 10), **opts, hole_lib=builder)
|
|
|
|
|
cells.mixed_wg_cav = cell(make_mixed_waveguide)(builder)
|
|
|
|
|
|
|
|
|
|
print('Declared cells waiting to be built:\n' + pformat(list(builder.keys())))
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
#
|
2026-04-22 21:24:05 -07:00
|
|
|
# Build the declaration set into a normal library.
|
2022-02-27 21:21:44 -08:00
|
|
|
#
|
|
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
built = builder.build()
|
|
|
|
|
print('Built library contains:\n' + pformat(list(built.keys())))
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
#
|
2026-04-22 21:24:05 -07:00
|
|
|
# Continue designing against the built library.
|
2022-02-27 21:21:44 -08:00
|
|
|
#
|
|
|
|
|
|
2026-04-22 21:24:05 -07:00
|
|
|
# The built result behaves like a normal mutable library, so downstream code
|
|
|
|
|
# can use Pather, abstract views, and writing without going back through the
|
|
|
|
|
# builder interface.
|
|
|
|
|
circ = Pather.interface(source='mixed_wg_cav', library=built)
|
|
|
|
|
circ.plug('tri_bend0', {'input': 'right'})
|
|
|
|
|
circ.plug('tri_bend0', {'input': 'left'}, mirrored=True) # mirror since no tri y-symmetry
|
|
|
|
|
circ.plug('tri_bend0', {'input': 'right'})
|
|
|
|
|
circ.plug('bend0', {'output': 'left'})
|
|
|
|
|
circ.plug('bend0', {'output': 'left'})
|
|
|
|
|
circ.plug('bend0', {'output': 'left'})
|
|
|
|
|
circ.plug('tri_wg10', {'input': 'right'})
|
|
|
|
|
circ.plug('tri_wg28', {'input': 'right'})
|
|
|
|
|
circ.plug('tri_wg10', {'input': 'right', 'output': 'left'})
|
|
|
|
|
built['loop_segment'] = circ.pattern
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
#
|
2026-04-22 21:24:05 -07:00
|
|
|
# Write all devices into a GDS file.
|
2022-02-27 21:21:44 -08:00
|
|
|
#
|
2023-01-24 23:25:10 -08:00
|
|
|
print('Writing library to file...')
|
2026-04-22 21:24:05 -07:00
|
|
|
writefile(built, 'library.gds', **GDS_OPTS)
|
2022-02-27 21:21:44 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|