[tutorial] include a repetition and update docs

This commit is contained in:
jan 2026-02-15 20:05:38 -08:00
commit 59e996e680
4 changed files with 56 additions and 12 deletions

View file

@ -18,11 +18,14 @@ Contents
* Design a pattern which is meant to plug into an existing pattern (via `.interface()`) * Design a pattern which is meant to plug into an existing pattern (via `.interface()`)
- [pather](pather.py) - [pather](pather.py)
* Use `Pather` to route individual wires and wire bundles * Use `Pather` to route individual wires and wire bundles
* Use `BasicTool` to generate paths * Use `AutoTool` to generate paths
* Use `BasicTool` to automatically transition between path types * Use `AutoTool` to automatically transition between path types
- [renderpather](rendpather.py) - [renderpather](renderpather.py)
* Use `RenderPather` and `PathTool` to build a layout similar to the one in [pather](pather.py), * Use `RenderPather` and `PathTool` to build a layout similar to the one in [pather](pather.py),
but using `Path` shapes instead of `Polygon`s. but using `Path` shapes instead of `Polygon`s.
- [port_pather](port_pather.py)
* Use `PortPather` and the `.at()` syntax for more concise routing
* Advanced port manipulation and connections
Additionaly, [pcgen](pcgen.py) is a utility module for generating photonic crystal lattices. Additionaly, [pcgen](pcgen.py) is a utility module for generating photonic crystal lattices.

View file

@ -2,9 +2,8 @@
import numpy import numpy
from numpy import pi from numpy import pi
from masque import ( from masque import layer_t, Pattern, Circle, Arc, Polygon, Ref
layer_t, Pattern, Circle, Arc, Polygon, from masque.repetition import Grid
)
import masque.file.gdsii import masque.file.gdsii
@ -37,6 +36,45 @@ def hole(
return pat return pat
def hole_array(
radius: float,
num_x: int = 5,
num_y: int = 3,
pitch: float = 2000,
layer: layer_t = (1, 0),
) -> Pattern:
"""
Generate an array of circular holes using `Repetition`.
Args:
radius: Circle radius.
num_x, num_y: Number of holes in x and y.
pitch: Center-to-center spacing.
layer: Layer to draw the holes on.
Returns:
Pattern containing a grid of holes.
"""
# First, make a pattern for a single hole
hpat = hole(radius, layer)
# Now, create a pattern that references it multiple times using a Grid
pat = Pattern()
pat.refs['hole'] = [
Ref(
offset=(0, 0),
repetition=Grid(a_vector=(pitch, 0), a_count=num_x,
b_vector=(0, pitch), b_count=num_y)
)]
# We can also add transformed references (rotation, mirroring, etc.)
pat.refs['hole'].append(
Ref(offset=(0, -pitch), rotation=pi / 4, mirrored=True)
)
return pat, hpat
def triangle( def triangle(
radius: float, radius: float,
layer: layer_t = (1, 0), layer: layer_t = (1, 0),
@ -58,9 +96,7 @@ def triangle(
]) * radius ]) * radius
pat = Pattern() pat = Pattern()
pat.shapes[layer].extend([ pat.polygon(layer, vertices=vertices)
Polygon(offset=(0, 0), vertices=vertices),
])
return pat return pat
@ -109,9 +145,13 @@ def main() -> None:
lib['smile'] = smile(1000) lib['smile'] = smile(1000)
lib['triangle'] = triangle(1000) lib['triangle'] = triangle(1000)
# Use a Grid to make many holes efficiently
lib['grid'], lib['hole'] = hole_array(1000)
masque.file.gdsii.writefile(lib, 'basic_shapes.gds', **GDS_OPTS) masque.file.gdsii.writefile(lib, 'basic_shapes.gds', **GDS_OPTS)
lib['triangle'].visualize() lib['triangle'].visualize()
lib['grid'].visualize(lib)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -239,7 +239,7 @@ def main() -> None:
pather.path_to('GND', None, x=pather['VCC'].offset[0]) pather.path_to('GND', None, x=pather['VCC'].offset[0])
# Now, start using M1_tool for GND. # Now, start using M1_tool for GND.
# Since we have defined an M2-to-M1 transition for BasicPather, we don't need to place one ourselves. # Since we have defined an M2-to-M1 transition for Pather, we don't need to place one ourselves.
# If we wanted to place our via manually, we could add `pather.plug('m1_via', {'GND': 'top'})` here # If we wanted to place our via manually, we could add `pather.plug('m1_via', {'GND': 'top'})` here
# and achieve the same result without having to define any transitions in M1_tool. # and achieve the same result without having to define any transitions in M1_tool.
# Note that even though we have changed the tool used for GND, the via doesn't get placed until # Note that even though we have changed the tool used for GND, the via doesn't get placed until

View file

@ -12,7 +12,7 @@ from pather import M1_WIDTH, V1_WIDTH, M2_WIDTH, map_layer, make_pad, make_via
def main() -> None: def main() -> None:
# #
# To illustrate the advantages of using `RenderPather`, we use `PathTool` instead # To illustrate the advantages of using `RenderPather`, we use `PathTool` instead
# of `BasicTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions) # of `AutoTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions)
# but when used with `RenderPather`, it can consolidate multiple routing steps into # but when used with `RenderPather`, it can consolidate multiple routing steps into
# a single `Path` shape. # a single `Path` shape.
# #
@ -34,7 +34,7 @@ def main() -> None:
ptype_top = 'm2wire', ptype_top = 'm2wire',
) )
# `PathTool` is more limited than `BasicTool`. It only generates one type of shape # `PathTool` is more limited than `AutoTool`. It only generates one type of shape
# (`Path`), so it only needs to know what layer to draw on, what width to draw with, # (`Path`), so it only needs to know what layer to draw on, what width to draw with,
# and what port type to present. # and what port type to present.
M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire') M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire')
@ -77,6 +77,7 @@ def main() -> None:
# to account for it. # to account for it.
v1pat = library['v1_via'] v1pat = library['v1_via']
via_size = abs(v1pat.ports['top'].x - v1pat.ports['bottom'].x) via_size = abs(v1pat.ports['top'].x - v1pat.ports['bottom'].x)
# alternatively, via_size = v1pat.ports['top'].measure_travel(v1pat.ports['bottom'])[0][0] # alternatively, via_size = v1pat.ports['top'].measure_travel(v1pat.ports['bottom'])[0][0]
# would take into account the port orientations if we didn't already know they're along x # would take into account the port orientations if we didn't already know they're along x
rpather.path_to('VCC', None, -50_000 + via_size) rpather.path_to('VCC', None, -50_000 + via_size)