Compare commits
4 Commits
master
...
build_path
Author | SHA1 | Date | |
---|---|---|---|
fff20b3da9 | |||
4bae737630 | |||
9891ba9e47 | |||
df320e80cc |
@ -1,2 +1,3 @@
|
||||
from .devices import Port, Device
|
||||
from .utils import ell
|
||||
from .tools import Tool
|
||||
|
@ -15,6 +15,8 @@ from ..subpattern import SubPattern
|
||||
from ..traits import PositionableImpl, Rotatable, PivotableImpl, Copyable, Mirrorable
|
||||
from ..utils import AutoSlots, rotation_matrix_2d
|
||||
from ..error import DeviceError
|
||||
from .tools import Tool
|
||||
from .utils import ell
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -157,7 +159,7 @@ class Device(Copyable, Mirrorable):
|
||||
renamed to 'gnd' so that further routing can use this signal or net name
|
||||
rather than the port name on the original `pad` device.
|
||||
"""
|
||||
__slots__ = ('pattern', 'ports', '_dead')
|
||||
__slots__ = ('pattern', 'ports', 'tools', '_dead')
|
||||
|
||||
pattern: Pattern
|
||||
""" Layout of this device """
|
||||
@ -165,6 +167,12 @@ class Device(Copyable, Mirrorable):
|
||||
ports: Dict[str, Port]
|
||||
""" Uniquely-named ports which can be used to snap to other Device instances"""
|
||||
|
||||
tools: Dict[Optional[str], Tool]
|
||||
"""
|
||||
Tool objects are used to dynamically generate new single-use Devices
|
||||
(e.g wires or waveguides) to be plugged into this device.
|
||||
"""
|
||||
|
||||
_dead: bool
|
||||
""" If True, plug()/place() are skipped (for debugging)"""
|
||||
|
||||
@ -173,6 +181,7 @@ class Device(Copyable, Mirrorable):
|
||||
pattern: Optional[Pattern] = None,
|
||||
ports: Optional[Dict[str, Port]] = None,
|
||||
*,
|
||||
tools: Union[None, Tool, Dict[Optional[str], Tool]] = None,
|
||||
name: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
@ -198,6 +207,13 @@ class Device(Copyable, Mirrorable):
|
||||
else:
|
||||
self.ports = copy.deepcopy(ports)
|
||||
|
||||
if tools is None:
|
||||
self.tools = {}
|
||||
elif isinstance(tools, Tool):
|
||||
self.tools = {None: tools}
|
||||
else:
|
||||
self.tools = tools
|
||||
|
||||
self._dead = False
|
||||
|
||||
@overload
|
||||
@ -205,7 +221,7 @@ class Device(Copyable, Mirrorable):
|
||||
pass
|
||||
|
||||
@overload
|
||||
def __getitem__(self, key: Union[List[str], Tuple[str], KeysView[str], ValuesView[str]]) -> Dict[str, Port]:
|
||||
def __getitem__(self, key: Union[List[str], Tuple[str, ...], KeysView[str], ValuesView[str]]) -> Dict[str, Port]:
|
||||
pass
|
||||
|
||||
def __getitem__(self, key: Union[str, Iterable[str]]) -> Union[Port, Dict[str, Port]]:
|
||||
@ -333,7 +349,7 @@ class Device(Copyable, Mirrorable):
|
||||
"""
|
||||
pat = Pattern(name)
|
||||
pat.addsp(self.pattern)
|
||||
new = Device(pat, ports=self.ports)
|
||||
new = Device(pat, ports=self.ports, tools=self.tools)
|
||||
return new
|
||||
|
||||
def as_interface(
|
||||
@ -408,7 +424,7 @@ class Device(Copyable, Mirrorable):
|
||||
if duplicates:
|
||||
raise DeviceError(f'Duplicate keys after prefixing, try a different prefix: {duplicates}')
|
||||
|
||||
new = Device(name=name, ports={**ports_in, **ports_out})
|
||||
new = Device(name=name, ports={**ports_in, **ports_out}, tools=self.tools)
|
||||
return new
|
||||
|
||||
def plug(
|
||||
@ -752,6 +768,118 @@ class Device(Copyable, Mirrorable):
|
||||
s += ']>'
|
||||
return s
|
||||
|
||||
def retool(
|
||||
self: D,
|
||||
tool: Tool,
|
||||
keys: Union[Optional[str], Sequence[Optional[str]]] = None,
|
||||
) -> D:
|
||||
if keys is None or isinstance(keys, str):
|
||||
self.tools[keys] = tool
|
||||
else:
|
||||
for key in keys:
|
||||
self.tools[key] = tool
|
||||
return self
|
||||
|
||||
def path(
|
||||
self: D,
|
||||
portspec: str,
|
||||
ccw: Optional[bool],
|
||||
length: float,
|
||||
*,
|
||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||
**kwargs,
|
||||
) -> D:
|
||||
if self._dead:
|
||||
logger.error('Skipping path() since device is dead')
|
||||
return self
|
||||
|
||||
tool = self.tools.get(portspec, self.tools[None])
|
||||
in_ptype = self.ports[portspec].ptype
|
||||
dev = tool.path(ccw, length, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
|
||||
return self.plug(dev, {portspec: tool_port_names[0]})
|
||||
|
||||
def path_to(
|
||||
self: D,
|
||||
portspec: str,
|
||||
ccw: Optional[bool],
|
||||
position: float,
|
||||
*,
|
||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||
**kwargs,
|
||||
) -> D:
|
||||
if self._dead:
|
||||
logger.error('Skipping path_to() since device is dead')
|
||||
return self
|
||||
|
||||
port = self.ports[portspec]
|
||||
x, y = port.offset
|
||||
if port.rotation is None:
|
||||
raise DeviceError(f'Port {portspec} has no rotation and cannot be used for path_to()')
|
||||
|
||||
if not numpy.isclose(port.rotation % (pi / 2), 0):
|
||||
raise DeviceError('path_to was asked to route from non-manhattan port')
|
||||
|
||||
is_horizontal = numpy.isclose(port.rotation % pi, 0)
|
||||
if is_horizontal:
|
||||
if numpy.sign(numpy.cos(port.rotation)) == numpy.sign(position - x):
|
||||
raise DeviceError(f'path_to routing to behind source port: x={x:g} to {position:g}')
|
||||
length = numpy.abs(position - x)
|
||||
else:
|
||||
if numpy.sign(numpy.sin(port.rotation)) == numpy.sign(position - y):
|
||||
raise DeviceError(f'path_to routing to behind source port: y={y:g} to {position:g}')
|
||||
length = numpy.abs(position - y)
|
||||
|
||||
return self.path(portspec, ccw, length, tool_port_names=tool_port_names, **kwargs)
|
||||
|
||||
def busL(
|
||||
self: D,
|
||||
portspec: Union[str, Sequence[str]],
|
||||
ccw: Optional[bool],
|
||||
*,
|
||||
spacing: Optional[Union[float, ArrayLike]] = None,
|
||||
set_rotation: Optional[float] = None,
|
||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||
container_name: str = '_busL',
|
||||
force_container: bool = False,
|
||||
**kwargs,
|
||||
) -> D:
|
||||
if self._dead:
|
||||
logger.error('Skipping busL() since device is dead')
|
||||
return self
|
||||
|
||||
bound_types = set()
|
||||
if 'bound_type' in kwargs:
|
||||
bound_types.add(kwargs['bound_type'])
|
||||
bound = kwargs['bound']
|
||||
for bt in ('emin', 'emax', 'pmin', 'pmax', 'min_past_furthest'):
|
||||
if bt in kwargs:
|
||||
bound_types.add(bt)
|
||||
bound = kwargs[bt]
|
||||
|
||||
if not bound_types:
|
||||
raise DeviceError('No bound type specified for busL')
|
||||
elif len(bound_types) > 1:
|
||||
raise DeviceError(f'Too many bound types specified for busL: {bound_types}')
|
||||
bound_type = tuple(bound_types)[0]
|
||||
|
||||
if isinstance(portspec, str):
|
||||
portspec = [portspec]
|
||||
ports = self[tuple(portspec)]
|
||||
|
||||
extensions = ell(ports, ccw, spacing=spacing, bound=bound, bound_type=bound_type, set_rotation=set_rotation)
|
||||
|
||||
if len(ports) == 1 and not force_container:
|
||||
# Not a bus, so having a container just adds noise to the layout
|
||||
port_name = tuple(portspec)[0]
|
||||
return self.path(port_name, ccw, extensions[port_name], tool_port_names=tool_port_names)
|
||||
else:
|
||||
dev = Device(name='', ports=ports, tools=self.tools).as_interface(container_name)
|
||||
for name, length in extensions.items():
|
||||
dev.path(name, ccw, length, tool_port_names=tool_port_names)
|
||||
return self.plug(dev, {sp: 'in_' + sp for sp in ports.keys()}) # TODO safe to use 'in_'?
|
||||
|
||||
# TODO def path_join() and def bus_join()?
|
||||
|
||||
|
||||
def rotate_offsets_around(
|
||||
offsets: NDArray[numpy.float64],
|
||||
|
22
masque/builder/tools.py
Normal file
22
masque/builder/tools.py
Normal file
@ -0,0 +1,22 @@
|
||||
"""
|
||||
Tools are objects which dynamically generate simple single-use devices (e.g. wires or waveguides)
|
||||
"""
|
||||
from typing import TYPE_CHECKING, Optional, Sequence
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .devices import Device
|
||||
|
||||
|
||||
class Tool:
|
||||
def path(
|
||||
self,
|
||||
ccw: Optional[bool],
|
||||
length: float,
|
||||
*,
|
||||
in_ptype: Optional[str] = None,
|
||||
out_ptype: Optional[str] = None,
|
||||
port_names: Sequence[str] = ('A', 'B'),
|
||||
**kwargs,
|
||||
) -> 'Device':
|
||||
raise NotImplementedError(f'path() not implemented for {type(self)}')
|
||||
|
Loading…
Reference in New Issue
Block a user