add plugged() for manually-aligned ports
This commit is contained in:
parent
bb054b9eee
commit
94aa853a49
@ -4,6 +4,7 @@ import traceback
|
|||||||
import logging
|
import logging
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
@ -249,6 +250,75 @@ class PortList(metaclass=ABCMeta):
|
|||||||
self.ports.update(new_ports)
|
self.ports.update(new_ports)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def plugged(
|
||||||
|
self,
|
||||||
|
connections: dict[str, str],
|
||||||
|
) -> Self:
|
||||||
|
"""
|
||||||
|
Verify that the ports specified by `connections` are coincident and have opposing
|
||||||
|
rotations, then remove the ports.
|
||||||
|
|
||||||
|
This is used when ports have been "manually" aligned as part of some other routing,
|
||||||
|
but for whatever reason were not eliminated via `plug()`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connections: Pairs of ports which "plug" each other (same offset, opposing directions)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
self
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
`PortError` if the ports are not properly aligned.
|
||||||
|
"""
|
||||||
|
a_names, b_names = list(zip(*connections.items()))
|
||||||
|
a_ports = [self.ports[pp] for pp in a_names]
|
||||||
|
b_ports = [self.ports[pp] for pp in b_names]
|
||||||
|
|
||||||
|
a_types = [pp.ptype for pp in a_ports]
|
||||||
|
b_types = [pp.ptype for pp in b_ports]
|
||||||
|
type_conflicts = numpy.array([at != bt and at != 'unk' and bt != 'unk'
|
||||||
|
for at, bt in zip(a_types, b_types)])
|
||||||
|
|
||||||
|
if type_conflicts.any():
|
||||||
|
msg = 'Ports have conflicting types:\n'
|
||||||
|
for nn, (k, v) in enumerate(connections.items()):
|
||||||
|
if type_conflicts[nn]:
|
||||||
|
msg += f'{k} | {a_types[nn]}:{b_types[nn]} | {v}\n'
|
||||||
|
msg = ''.join(traceback.format_stack()) + '\n' + msg
|
||||||
|
warnings.warn(msg, stacklevel=2)
|
||||||
|
|
||||||
|
a_offsets = numpy.array([pp.offset for pp in a_ports])
|
||||||
|
b_offsets = numpy.array([pp.offset for pp in b_ports])
|
||||||
|
a_rotations = numpy.array([pp.rotation if pp.rotation is not None else 0 for pp in a_ports])
|
||||||
|
b_rotations = numpy.array([pp.rotation if pp.rotation is not None else 0 for pp in b_ports])
|
||||||
|
a_has_rot = numpy.array([pp.rotation is not None for pp in a_ports], dtype=bool)
|
||||||
|
b_has_rot = numpy.array([pp.rotation is not None for pp in b_ports], dtype=bool)
|
||||||
|
has_rot = a_has_rot & b_has_rot
|
||||||
|
|
||||||
|
if has_rot.any():
|
||||||
|
rotations = numpy.mod(a_rotations - b_rotations - pi, 2 * pi)
|
||||||
|
rotations[~has_rot] = rotations[has_rot][0]
|
||||||
|
|
||||||
|
if not numpy.allclose(rotations, 0):
|
||||||
|
rot_deg = numpy.rad2deg(rotations)
|
||||||
|
msg = 'Port orientations do not match:\n'
|
||||||
|
for nn, (k, v) in enumerate(connections.items()):
|
||||||
|
if not numpy.isclose(rot_deg[nn], 0):
|
||||||
|
msg += f'{k} | {rot_deg[nn]:g} | {v}\n'
|
||||||
|
raise PortError(msg)
|
||||||
|
|
||||||
|
translations = a_offsets - b_offsets
|
||||||
|
if not numpy.allclose(translations, 0):
|
||||||
|
msg = 'Port translations do not match:\n'
|
||||||
|
for nn, (k, v) in enumerate(connections.items()):
|
||||||
|
if not numpy.allclose(translations[nn], 0):
|
||||||
|
msg += f'{k} | {translations[nn]} | {v}\n'
|
||||||
|
raise PortError(msg)
|
||||||
|
|
||||||
|
for pp in chain(a_names, b_names):
|
||||||
|
del self.ports[pp]
|
||||||
|
return self
|
||||||
|
|
||||||
def check_ports(
|
def check_ports(
|
||||||
self,
|
self,
|
||||||
other_names: Iterable[str],
|
other_names: Iterable[str],
|
||||||
|
Loading…
Reference in New Issue
Block a user