diff --git a/examples/tutorial/README.md b/examples/tutorial/README.md index 7210a93..6e5730b 100644 --- a/examples/tutorial/README.md +++ b/examples/tutorial/README.md @@ -18,11 +18,14 @@ Contents * Design a pattern which is meant to plug into an existing pattern (via `.interface()`) - [pather](pather.py) * Use `Pather` to route individual wires and wire bundles - * Use `BasicTool` to generate paths - * Use `BasicTool` to automatically transition between path types -- [renderpather](rendpather.py) + * Use `AutoTool` to generate paths + * Use `AutoTool` to automatically transition between path types +- [renderpather](renderpather.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. +- [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. diff --git a/examples/tutorial/basic_shapes.py b/examples/tutorial/basic_shapes.py index 5b5aab7..8664b4d 100644 --- a/examples/tutorial/basic_shapes.py +++ b/examples/tutorial/basic_shapes.py @@ -2,9 +2,8 @@ import numpy from numpy import pi -from masque import ( - layer_t, Pattern, Circle, Arc, Polygon, - ) +from masque import layer_t, Pattern, Circle, Arc, Polygon, Ref +from masque.repetition import Grid import masque.file.gdsii @@ -37,6 +36,45 @@ def hole( 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( radius: float, layer: layer_t = (1, 0), @@ -58,9 +96,7 @@ def triangle( ]) * radius pat = Pattern() - pat.shapes[layer].extend([ - Polygon(offset=(0, 0), vertices=vertices), - ]) + pat.polygon(layer, vertices=vertices) return pat @@ -109,9 +145,13 @@ def main() -> None: lib['smile'] = smile(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) lib['triangle'].visualize() + lib['grid'].visualize(lib) if __name__ == '__main__': diff --git a/examples/tutorial/pather.py b/examples/tutorial/pather.py index c212bc5..a9d9af9 100644 --- a/examples/tutorial/pather.py +++ b/examples/tutorial/pather.py @@ -239,7 +239,7 @@ def main() -> None: pather.path_to('GND', None, x=pather['VCC'].offset[0]) # 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 # 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 diff --git a/examples/tutorial/renderpather.py b/examples/tutorial/renderpather.py index 87e58f2..ecc8bc8 100644 --- a/examples/tutorial/renderpather.py +++ b/examples/tutorial/renderpather.py @@ -12,7 +12,7 @@ from pather import M1_WIDTH, V1_WIDTH, M2_WIDTH, map_layer, make_pad, make_via def main() -> None: # # 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 # a single `Path` shape. # @@ -34,7 +34,7 @@ def main() -> None: 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, # and what port type to present. M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire') @@ -77,6 +77,7 @@ def main() -> None: # to account for it. v1pat = library['v1_via'] via_size = abs(v1pat.ports['top'].x - v1pat.ports['bottom'].x) + # 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 rpather.path_to('VCC', None, -50_000 + via_size)