various fixes and cleanup

mainly involving ports_to_data and data_to_ports
This commit is contained in:
Jan Petykiewicz 2023-01-25 23:57:02 -08:00 committed by jan
parent 16567c8a66
commit 963918d1d9
13 changed files with 62 additions and 54 deletions

View File

@ -8,7 +8,7 @@ from masque import (
layer_t, Pattern, Ref, Label, Builder, Port, Polygon, layer_t, Pattern, Ref, Label, Builder, Port, Polygon,
WrapLibrary, Library, WrapLibrary, Library,
) )
from masque.builder import port_utils from masque.utils import ports2data
from masque.file.gdsii import writefile, check_valid_names from masque.file.gdsii import writefile, check_valid_names
import pcgen import pcgen
@ -20,20 +20,20 @@ LATTICE_CONSTANT = 512
RADIUS = LATTICE_CONSTANT / 2 * 0.75 RADIUS = LATTICE_CONSTANT / 2 * 0.75
def dev2pat(dev: Pattern) -> Pattern: def ports_to_data(pat: Pattern) -> Pattern:
""" """
Bake port information into the pattern. Bake port information into the pattern.
This places a label at each port location on layer (3, 0) with text content This places a label at each port location on layer (3, 0) with text content
'name:ptype angle_deg' 'name:ptype angle_deg'
""" """
return port_utils.dev2pat(dev, layer=(3, 0)) return ports2data.ports_to_data(pat, layer=(3, 0))
def pat2dev(lib: Mapping[str, Pattern], name: str, pat: Pattern) -> Pattern: def data_to_ports(lib: Mapping[str, Pattern], name: str, pat: Pattern) -> Pattern:
""" """
Scans the Pattern to determine port locations. Same format as `dev2pat` Scans the Pattern to determine port locations. Same port format as `ports_to_data`
""" """
return port_utils.pat2dev(layers=[(3, 0)], library=lib, pattern=pat, name=name) return ports2data.data_to_ports(layers=[(3, 0)], library=lib, pattern=pat, name=name)
def perturbed_l3( def perturbed_l3(
@ -103,7 +103,7 @@ def perturbed_l3(
output=Port((extent, 0), rotation=pi, ptype='pcwg'), output=Port((extent, 0), rotation=pi, ptype='pcwg'),
) )
dev2pat(pat) ports_to_data(pat)
return pat return pat
@ -142,8 +142,8 @@ def waveguide(
left=Port((-extent, 0), rotation=0, ptype='pcwg'), left=Port((-extent, 0), rotation=0, ptype='pcwg'),
right=Port((extent, 0), rotation=pi, ptype='pcwg'), right=Port((extent, 0), rotation=pi, ptype='pcwg'),
) )
dev2pat(pat)
print(pat) ports_to_data(pat)
return pat return pat
@ -183,7 +183,7 @@ def bend(
extent * numpy.sqrt(3) / 2), extent * numpy.sqrt(3) / 2),
rotation=pi * 4 / 3, ptype='pcwg'), rotation=pi * 4 / 3, ptype='pcwg'),
) )
dev2pat(pat) ports_to_data(pat)
return pat return pat
@ -222,7 +222,7 @@ def y_splitter(
'bot': Port((extent / 2, -extent * numpy.sqrt(3) / 2), rotation=pi * 2 / 3, ptype='pcwg'), 'bot': Port((extent / 2, -extent * numpy.sqrt(3) / 2), rotation=pi * 2 / 3, ptype='pcwg'),
} }
dev2pat(pat) ports_to_data(pat)
return pat return pat
@ -311,7 +311,7 @@ def main(interactive: bool = True) -> None:
# We can also add text labels for our circuit's ports. # We can also add text labels for our circuit's ports.
# They will appear at the uppermost hierarchy level, while the individual # They will appear at the uppermost hierarchy level, while the individual
# device ports will appear further down, in their respective cells. # device ports will appear further down, in their respective cells.
dev2pat(circ.pattern) ports_to_data(circ.pattern)
# Add the pattern into our library # Add the pattern into our library
lib['my_circuit'] = circ.pattern lib['my_circuit'] = circ.pattern

View File

@ -10,7 +10,7 @@ from masque.file.gdsii import writefile, load_libraryfile
import pcgen import pcgen
import basic_shapes import basic_shapes
import devices import devices
from devices import pat2dev, dev2pat from devices import ports_to_data, data_to_ports
from basic_shapes import GDS_OPTS from basic_shapes import GDS_OPTS
@ -24,7 +24,7 @@ def main() -> None:
# #
# Scan circuit.gds and prepare to lazy-load its contents # Scan circuit.gds and prepare to lazy-load its contents
gds_lib, _properties = load_libraryfile('circuit.gds', postprocess=pat2dev) gds_lib, _properties = load_libraryfile('circuit.gds', postprocess=data_to_ports)
# Add it into the device library by providing a way to read port info # Add it into the device library by providing a way to read port info
# This maintains the lazy evaluation from above, so no patterns # This maintains the lazy evaluation from above, so no patterns
@ -59,13 +59,18 @@ def main() -> None:
# Immediately start building from an instance of the L3 cavity # Immediately start building from an instance of the L3 cavity
circ2 = Builder(library=lib, ports='tri_l3cav') circ2 = Builder(library=lib, ports='tri_l3cav')
print(lib['wg10'].ports) # First way to get abstracts is `lib.abstract(name)`
circ2.plug(lib.abstract('wg10'), {'input': 'right'}) circ2.plug(lib.abstract('wg10'), {'input': 'right'})
abstracts = lib.abstract_view() # Alternate way to get abstracts # Second way to get abstracts is to use an AbstractView
abstracts = lib.abstract_view()
circ2.plug(abstracts['wg10'], {'output': 'left'}) circ2.plug(abstracts['wg10'], {'output': 'left'})
circ2.plug(abstracts['tri_wg10'], {'input': 'right'})
circ2.plug(abstracts['tri_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'})
# Add the circuit to the device library. # Add the circuit to the device library.
# It has already been generated, so we can use `set_const` as a shorthand for # It has already been generated, so we can use `set_const` as a shorthand for
@ -81,15 +86,15 @@ def main() -> None:
circ3 = Builder.interface(source=circ2) circ3 = Builder.interface(source=circ2)
# ... that lets us continue from where we left off. # ... that lets us continue from where we left off.
circ3.plug(abstracts['tri_bend0'], {'input': 'right'}) circ3.plug('tri_bend0', {'input': 'right'})
circ3.plug(abstracts['tri_bend0'], {'input': 'left'}, mirrored=(True, False)) # mirror since no tri y-symmetry circ3.plug('tri_bend0', {'input': 'left'}, mirrored=(True, False)) # mirror since no tri y-symmetry
circ3.plug(abstracts['tri_bend0'], {'input': 'right'}) circ3.plug('tri_bend0', {'input': 'right'})
circ3.plug(abstracts['bend0'], {'output': 'left'}) circ3.plug('bend0', {'output': 'left'})
circ3.plug(abstracts['bend0'], {'output': 'left'}) circ3.plug('bend0', {'output': 'left'})
circ3.plug(abstracts['bend0'], {'output': 'left'}) circ3.plug('bend0', {'output': 'left'})
circ3.plug(abstracts['tri_wg10'], {'input': 'right'}) circ3.plug('tri_wg10', {'input': 'right'})
circ3.plug(abstracts['tri_wg28'], {'input': 'right'}) circ3.plug('tri_wg28', {'input': 'right'})
circ3.plug(abstracts['tri_wg10'], {'input': 'right', 'output': 'left'}) circ3.plug('tri_wg10', {'input': 'right', 'output': 'left'})
lib.set_const('loop_segment', circ3.pattern) lib.set_const('loop_segment', circ3.pattern)

View File

@ -27,12 +27,13 @@
""" """
from .utils import layer_t, annotations_t, SupportsBool
from .error import MasqueError, PatternError, LibraryError, BuildError from .error import MasqueError, PatternError, LibraryError, BuildError
from .shapes import Shape, Polygon, Path, Circle, Arc, Ellipse from .shapes import Shape, Polygon, Path, Circle, Arc, Ellipse
from .label import Label from .label import Label
from .ref import Ref from .ref import Ref
from .pattern import Pattern from .pattern import Pattern
from .utils import layer_t, annotations_t
from .library import Library, MutableLibrary, WrapROLibrary, WrapLibrary, LazyLibrary, AbstractView from .library import Library, MutableLibrary, WrapROLibrary, WrapLibrary, LazyLibrary, AbstractView
from .ports import Port, PortList from .ports import Port, PortList
from .abstract import Abstract from .abstract import Abstract

View File

@ -10,16 +10,16 @@ from abc import ABCMeta, abstractmethod
import numpy import numpy
from numpy.typing import ArrayLike, NDArray from numpy.typing import ArrayLike, NDArray
from .error import PatternError
from .utils import rotation_matrix_2d, AutoSlots
from .traits import Copyable, Scalable, Rotatable, Mirrorable from .traits import Copyable, Scalable, Rotatable, Mirrorable
from .error import PatternError
from .utils import rotation_matrix_2d
class Repetition(Copyable, Rotatable, Mirrorable, Scalable, metaclass=ABCMeta): class Repetition(Copyable, Rotatable, Mirrorable, Scalable, metaclass=ABCMeta):
""" """
Interface common to all objects which specify repetitions Interface common to all objects which specify repetitions
""" """
__slots__ = () __slots__ = () # Allow subclasses to use __slots__
@property @property
@abstractmethod @abstractmethod
@ -30,7 +30,7 @@ class Repetition(Copyable, Rotatable, Mirrorable, Scalable, metaclass=ABCMeta):
pass pass
class Grid(Repetition, metaclass=AutoSlots): class Grid(Repetition):
""" """
`Grid` describes a 2D grid formed by two basis vectors and two 'counts' (sizes). `Grid` describes a 2D grid formed by two basis vectors and two 'counts' (sizes).
@ -279,7 +279,7 @@ class Grid(Repetition, metaclass=AutoSlots):
return True return True
class Arbitrary(Repetition, metaclass=AutoSlots): class Arbitrary(Repetition):
""" """
`Arbitrary` is a simple list of (absolute) displacements for instances. `Arbitrary` is a simple list of (absolute) displacements for instances.

View File

@ -7,12 +7,12 @@ from numpy import pi
from numpy.typing import NDArray, ArrayLike from numpy.typing import NDArray, ArrayLike
from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..utils import is_scalar, layer_t, AutoSlots, annotations_t from ..utils import is_scalar, layer_t, annotations_t
class Arc(Shape, metaclass=AutoSlots): class Arc(Shape):
""" """
An elliptical arc, formed by cutting off an elliptical ring with two rays which exit from its An elliptical arc, formed by cutting off an elliptical ring with two rays which exit from its
center. It has a position, two radii, a start and stop angle, a rotation, and a width. center. It has a position, two radii, a start and stop angle, a rotation, and a width.

View File

@ -6,12 +6,12 @@ from numpy import pi
from numpy.typing import NDArray, ArrayLike from numpy.typing import NDArray, ArrayLike
from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..utils import is_scalar, layer_t, AutoSlots, annotations_t from ..utils import is_scalar, layer_t, annotations_t
class Circle(Shape, metaclass=AutoSlots): class Circle(Shape):
""" """
A circle, which has a position and radius. A circle, which has a position and radius.
""" """

View File

@ -7,12 +7,12 @@ from numpy import pi
from numpy.typing import ArrayLike, NDArray from numpy.typing import ArrayLike, NDArray
from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..utils import is_scalar, rotation_matrix_2d, layer_t, AutoSlots, annotations_t from ..utils import is_scalar, rotation_matrix_2d, layer_t, annotations_t
class Ellipse(Shape, metaclass=AutoSlots): class Ellipse(Shape):
""" """
An ellipse, which has a position, two radii, and a rotation. An ellipse, which has a position, two radii, and a rotation.
The rotation gives the angle from x-axis, counterclockwise, to the first (x) radius. The rotation gives the angle from x-axis, counterclockwise, to the first (x) radius.

View File

@ -7,9 +7,9 @@ from numpy import pi, inf
from numpy.typing import NDArray, ArrayLike from numpy.typing import NDArray, ArrayLike
from . import Shape, normalized_shape_tuple, Polygon, Circle from . import Shape, normalized_shape_tuple, Polygon, Circle
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..utils import is_scalar, rotation_matrix_2d, layer_t, AutoSlots from ..utils import is_scalar, rotation_matrix_2d, layer_t
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
@ -21,7 +21,7 @@ class PathCap(Enum):
# # defined by path.cap_extensions # # defined by path.cap_extensions
class Path(Shape, metaclass=AutoSlots): class Path(Shape):
""" """
A path, consisting of a bunch of vertices (Nx2 ndarray), a width, an end-cap shape, A path, consisting of a bunch of vertices (Nx2 ndarray), a width, an end-cap shape,
and an offset. and an offset.

View File

@ -6,13 +6,13 @@ from numpy import pi
from numpy.typing import NDArray, ArrayLike from numpy.typing import NDArray, ArrayLike
from . import Shape, normalized_shape_tuple from . import Shape, normalized_shape_tuple
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..utils import is_scalar, rotation_matrix_2d, layer_t, AutoSlots from ..utils import is_scalar, rotation_matrix_2d, layer_t
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
class Polygon(Shape, metaclass=AutoSlots): class Polygon(Shape):
""" """
A polygon, consisting of a bunch of vertices (Nx2 ndarray) which specify an A polygon, consisting of a bunch of vertices (Nx2 ndarray) which specify an
implicitly-closed boundary, and an offset. implicitly-closed boundary, and an offset.

View File

@ -6,10 +6,10 @@ from numpy import pi, inf
from numpy.typing import NDArray, ArrayLike from numpy.typing import NDArray, ArrayLike
from . import Shape, Polygon, normalized_shape_tuple from . import Shape, Polygon, normalized_shape_tuple
from .. import PatternError from ..error import PatternError
from ..repetition import Repetition from ..repetition import Repetition
from ..traits import RotatableImpl from ..traits import RotatableImpl
from ..utils import is_scalar, get_bit, normalize_mirror, layer_t, AutoSlots from ..utils import is_scalar, get_bit, normalize_mirror, layer_t
from ..utils import annotations_t from ..utils import annotations_t
# Loaded on use: # Loaded on use:
@ -17,7 +17,7 @@ from ..utils import annotations_t
# from matplotlib.path import Path # from matplotlib.path import Path
class Text(RotatableImpl, Shape, metaclass=AutoSlots): class Text(RotatableImpl, Shape):
""" """
Text (to be printed e.g. as a set of polygons). Text (to be printed e.g. as a set of polygons).
This is distinct from non-printed Label objects. This is distinct from non-printed Label objects.

View File

@ -35,7 +35,7 @@ class Positionable(metaclass=ABCMeta):
@offset.setter @offset.setter
@abstractmethod @abstractmethod
def offset(self, val: ArrayLike): def offset(self, val: ArrayLike) -> None:
pass pass
@abstractmethod @abstractmethod

View File

@ -1,4 +1,4 @@
from typing import TypeVar, cast from typing import TypeVar, cast, Any
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
import numpy import numpy
@ -114,6 +114,9 @@ class PivotableImpl(Pivotable, metaclass=ABCMeta):
""" """
__slots__ = () __slots__ = ()
offset: Any # TODO see if we can get around defining `offset` in PivotableImpl
""" `[x_offset, y_offset]` """
def rotate_around(self: J, pivot: ArrayLike, rotation: float) -> J: def rotate_around(self: J, pivot: ArrayLike, rotation: float) -> J:
pivot = numpy.array(pivot, dtype=float) pivot = numpy.array(pivot, dtype=float)
cast(Positionable, self).translate(-pivot) cast(Positionable, self).translate(-pivot)

View File

@ -2,7 +2,6 @@
Various helper functions, type definitions, etc. Various helper functions, type definitions, etc.
""" """
from .types import layer_t, annotations_t, SupportsBool from .types import layer_t, annotations_t, SupportsBool
from .array import is_scalar from .array import is_scalar
from .autoslots import AutoSlots from .autoslots import AutoSlots
from .deferreddict import DeferredDict from .deferreddict import DeferredDict