""" Tutorial: authoring a mixed library with `BuildLibrary`. 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 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. """ from typing import Any from pprint import pformat from masque import BuildLibrary, Pather, Pattern, cell from masque.file.gdsii import writefile from masque.file.gdsii_lazy import readfile import basic_shapes import devices from basic_shapes import GDS_OPTS 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 def main() -> None: builder = BuildLibrary() cells = builder.cells # # Load some devices from a GDS file # # Scan circuit.gds and prepare to lazy-load its contents. Port labels are # imported on first materialization, but the raw source remains untouched # until we build the final library. gds_lib, _properties = readfile('circuit.gds') builder.add_source(gds_lib.with_ports_from_data(layers=[(3, 0)], max_depth=1)) print('Registered imported cells:\n' + pformat(list(gds_lib.keys()))) # # Register some new devices, this time from python code rather than GDS. # cells.triangle = basic_shapes.triangle(devices.RADIUS) opts: dict[str, Any] = dict( lattice_constant=devices.LATTICE_CONSTANT, hole='triangle', ) 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()))) # # Build the declaration set into a normal library. # built = builder.build() print('Built library contains:\n' + pformat(list(built.keys()))) # # Continue designing against the built library. # # 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 # # Write all devices into a GDS file. # print('Writing library to file...') writefile(built, 'library.gds', **GDS_OPTS) if __name__ == '__main__': main()