masque/examples/tutorial/library.py

135 lines
4.5 KiB
Python
Raw Normal View History

2022-02-27 21:21:44 -08:00
from typing import Tuple, Sequence, Callable
from pprint import pformat
import numpy
from numpy import pi
2023-01-24 23:25:10 -08:00
from masque import Pattern, Builder, WrapLibrary, LazyLibrary, Library
2022-02-27 21:21:44 -08:00
from masque.file.gdsii import writefile, load_libraryfile
import pcgen
import basic_shapes
import devices
from devices import ports_to_data, data_to_ports
2022-02-27 21:21:44 -08:00
from basic_shapes import GDS_OPTS
def main() -> None:
2023-01-24 23:25:10 -08:00
# Define a `LazyLibrary`, which provides lazy evaluation for generating
# patterns and lazy-loading of GDS contents.
lib = LazyLibrary()
2022-02-27 21:21:44 -08:00
#
# Load some devices from a GDS file
#
# Scan circuit.gds and prepare to lazy-load its contents
gds_lib, _properties = load_libraryfile('circuit.gds', postprocess=data_to_ports)
2022-02-27 21:21:44 -08:00
# Add it into the device library by providing a way to read port info
# This maintains the lazy evaluation from above, so no patterns
# are actually read yet.
2023-01-24 23:25:10 -08:00
lib.add(gds_lib)
2022-02-27 21:21:44 -08:00
2023-01-24 23:25:10 -08:00
print('Patterns loaded from GDS into library:\n' + pformat(list(lib.keys())))
2022-02-27 21:21:44 -08:00
#
# Add some new devices to the library, this time from python code rather than GDS
#
2023-01-24 23:25:10 -08:00
lib['triangle'] = lambda: basic_shapes.triangle(devices.RADIUS)
opts = dict(
lattice_constant = devices.LATTICE_CONSTANT,
hole = 'triangle',
)
2022-02-27 21:21:44 -08:00
# Triangle-based variants. These are defined here, but they won't run until they're
# retrieved from the library.
2023-01-24 23:25:10 -08:00
lib['tri_wg10'] = lambda: devices.waveguide(length=10, mirror_periods=5, **opts)
lib['tri_wg05'] = lambda: devices.waveguide(length=5, mirror_periods=5, **opts)
lib['tri_wg28'] = lambda: devices.waveguide(length=28, mirror_periods=5, **opts)
lib['tri_bend0'] = lambda: devices.bend(mirror_periods=5, **opts)
lib['tri_ysplit'] = lambda: devices.y_splitter(mirror_periods=5, **opts)
lib['tri_l3cav'] = lambda: devices.perturbed_l3(xy_size=(4, 10), **opts, hole_lib=lib)
2022-02-27 21:21:44 -08:00
#
# Build a mixed waveguide with an L3 cavity in the middle
#
# Immediately start building from an instance of the L3 cavity
2023-01-24 23:25:10 -08:00
circ2 = Builder(library=lib, ports='tri_l3cav')
# First way to get abstracts is `lib.abstract(name)`
2023-01-24 23:25:10 -08:00
circ2.plug(lib.abstract('wg10'), {'input': 'right'})
2022-02-27 21:21:44 -08:00
# Second way to get abstracts is to use an AbstractView
abstracts = lib.abstract_view()
2023-01-24 23:25:10 -08:00
circ2.plug(abstracts['wg10'], {'output': 'left'})
# Third way to specify an abstract works by automatically getting
# it from the library already within the Builder object:
# Just pass the pattern name!
circ2.plug('tri_wg10', {'input': 'right'})
circ2.plug('tri_wg10', {'output': 'left'})
2022-02-27 21:21:44 -08:00
# Add the circuit to the device library.
# It has already been generated, so we can use `set_const` as a shorthand for
2023-01-24 23:25:10 -08:00
# `lib['mixed_wg_cav'] = lambda: circ2.pattern`
lib.set_const('mixed_wg_cav', circ2.pattern)
2022-02-27 21:21:44 -08:00
#
# Build a device that could plug into our mixed_wg_cav and joins the two ports
#
# We'll be designing against an existing device's interface...
2023-01-24 23:25:10 -08:00
circ3 = Builder.interface(source=circ2)
2022-02-27 21:21:44 -08:00
# ... that lets us continue from where we left off.
circ3.plug('tri_bend0', {'input': 'right'})
circ3.plug('tri_bend0', {'input': 'left'}, mirrored=(True, False)) # mirror since no tri y-symmetry
circ3.plug('tri_bend0', {'input': 'right'})
circ3.plug('bend0', {'output': 'left'})
circ3.plug('bend0', {'output': 'left'})
circ3.plug('bend0', {'output': 'left'})
circ3.plug('tri_wg10', {'input': 'right'})
circ3.plug('tri_wg28', {'input': 'right'})
circ3.plug('tri_wg10', {'input': 'right', 'output': 'left'})
2023-01-24 23:25:10 -08:00
lib.set_const('loop_segment', circ3.pattern)
2022-02-27 21:21:44 -08:00
#
# Write all devices into a GDS file
#
2023-01-24 23:25:10 -08:00
print('Writing library to file...')
writefile(lib, 'library.gds', **GDS_OPTS)
2022-02-27 21:21:44 -08:00
if __name__ == '__main__':
main()
#
#class prout:
# def place(
# self,
2023-01-24 23:25:10 -08:00
# other: Pattern,
2022-02-27 21:21:44 -08:00
# label_layer: layer_t = 'WATLAYER',
# *,
# port_map: Optional[Dict[str, Optional[str]]] = None,
# **kwargs,
# ) -> 'prout':
#
2023-01-24 23:25:10 -08:00
# Pattern.place(self, other, port_map=port_map, **kwargs)
2022-02-27 21:21:44 -08:00
# name: Optional[str]
# for name in other.ports:
# if port_map:
# assert(name is not None)
# name = port_map.get(name, name)
# if name is None:
# continue
# self.pattern.labels += [
# Label(string=name, offset=self.ports[name].offset, layer=layer)]
# return self
#