Skip to content

Port check

port_check

Port-pair connection check used by :mod:kfnetlist.extract.

PortCheck

Bases: IntFlag

Bitmask of pairwise port-port comparison results.

Source code in src/kfnetlist/port_check.py
12
13
14
15
16
17
18
19
20
21
22
23
class PortCheck(IntFlag):
    """Bitmask of pairwise port-port comparison results."""

    opposite = auto()
    same = auto()
    width = auto()
    layer = auto()
    cross_section = auto()
    port_type = auto()
    position = auto()
    all_opposite = opposite | width | port_type | layer
    all_overlap = width | port_type | layer

PortLike

Bases: Protocol

Duck-typed shape consumed by :func:check_connection.

Exactly one of trans / dcplx_trans must be set.

Source code in src/kfnetlist/port_check.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class PortLike(Protocol):
    """Duck-typed shape consumed by :func:`check_connection`.

    Exactly one of ``trans`` / ``dcplx_trans`` must be set.
    """

    @property
    def trans(self) -> kdb.Trans | None: ...
    @property
    def dcplx_trans(self) -> kdb.DCplxTrans | None: ...
    @property
    def cross_section(self) -> _CrossSectionLike: ...
    @property
    def port_type(self) -> str: ...
    @property
    def kcl(self) -> _KCLLike: ...

check_connection

check_connection(
    p1: PortLike,
    p2: PortLike,
    *,
    tolerance: float = 0.1,
    angle_tolerance: float = 0.01,
    snapped: bool = False,
) -> int

Compare two ports, returning a :class:PortCheck bitmask.

Integer transforms are used when both ports expose trans (or when snapped=True); otherwise the complex transforms are used with the supplied tolerances. cross_section implies layer and width.

Source code in src/kfnetlist/port_check.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def check_connection(
    p1: PortLike,
    p2: PortLike,
    *,
    tolerance: float = 0.1,
    angle_tolerance: float = 0.01,
    snapped: bool = False,
) -> int:
    """Compare two ports, returning a :class:`PortCheck` bitmask.

    Integer transforms are used when both ports expose ``trans`` (or when
    ``snapped=True``); otherwise the complex transforms are used with the
    supplied tolerances. ``cross_section`` implies ``layer`` and ``width``.
    """
    tol_um = p1.kcl.dbu * tolerance
    check = 0
    if snapped or (p1.trans is not None and p2.trans is not None):
        t1 = _get_trans(p1)
        t2 = _get_trans(p2)
        if t1.disp == t2.disp:
            check += PortCheck.position
        orientation = (t1.angle - t2.angle) % 4
        if orientation == 2:
            check += PortCheck.opposite
        elif orientation == 0:
            check += PortCheck.same
    else:
        dt1 = _get_dcplx_trans(p1)
        dt2 = _get_dcplx_trans(p2)
        if (dt1.disp - dt2.disp).length() < tol_um:
            check += PortCheck.position
        angle_diff = (dt1.angle - dt2.angle) % 360
        if abs(angle_diff - 180) < angle_tolerance:
            check += PortCheck.opposite
        elif abs(angle_diff) < angle_tolerance:
            check += PortCheck.same
    if p1.cross_section == p2.cross_section:
        check += PortCheck.cross_section
        check += PortCheck.layer
        check += PortCheck.width
    else:
        if p1.cross_section.main_layer.is_equivalent(p2.cross_section.main_layer):
            check += PortCheck.layer
        if p1.cross_section.width == p2.cross_section.width:
            check += PortCheck.width
    if p1.port_type == p2.port_type:
        check += PortCheck.port_type
    return check