Skip to content

Instance ports

instance_ports

DInstancePorts

Bases: ProtoTInstancePorts[float]

Source code in kfactory/instance_ports.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
class DInstancePorts(ProtoTInstancePorts[float]):
    def __init__(self, instance: DInstance) -> None:
        """Creates the virtual ports object.

        Args:
            instance: The related instance
        """
        self.instance = instance

    @property
    def cell_ports(self) -> DPorts:
        return DPorts(kcl=self.instance.cell.kcl, bases=self.instance.cell.ports.bases)

    def filter(
        self,
        angle: int | None = None,
        orientation: float | None = None,
        layer: LayerEnum | int | None = None,
        port_type: str | None = None,
        regex: str | None = None,
    ) -> Sequence[DPort]:
        return [
            DPort(base=p.base)
            for p in super().filter(angle, orientation, layer, port_type, regex)
        ]

    def __getitem__(
        self, key: int | str | tuple[int | str | None, int, int] | None
    ) -> DPort:
        return DPort(base=super().__getitem__(key).base)

    def __iter__(self) -> Iterator[DPort]:
        yield from (p.to_dtype() for p in self.each_port())

__getitem__

__getitem__(
    key: int
    | str
    | tuple[int | str | None, int, int]
    | None,
) -> DPort

Returns port from instance.

The key can either be an integer, in which case the nth port is returned, or a string in which case the first port with a matching name is returned.

If the instance is an array, the key can also be a tuple in the form of c.ports[key_name, i_a, i_b], where i_a is the index in the instance.a direction and i_b the instance.b direction.

E.g. c.ports["a", 3, 5], accesses the ports of the instance which is 3 times in a direction (4th index in the array), and 5 times in b direction (5th index in the array).

Source code in kfactory/instance_ports.py
370
371
372
373
def __getitem__(
    self, key: int | str | tuple[int | str | None, int, int] | None
) -> DPort:
    return DPort(base=super().__getitem__(key).base)

__init__

__init__(instance: DInstance) -> None

Creates the virtual ports object.

Parameters:

Name Type Description Default
instance DInstance

The related instance

required
Source code in kfactory/instance_ports.py
345
346
347
348
349
350
351
def __init__(self, instance: DInstance) -> None:
    """Creates the virtual ports object.

    Args:
        instance: The related instance
    """
    self.instance = instance

filter

filter(
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[DPort]

Filter ports by name.

Parameters:

Name Type Description Default
angle int | None

Filter by angle. 0, 1, 2, 3.

None
orientation float | None

Filter by orientation in degrees.

None
layer LayerEnum | int | None

Filter by layer.

None
port_type str | None

Filter by port type.

None
regex str | None

Filter by regex of the name.

None
Source code in kfactory/instance_ports.py
357
358
359
360
361
362
363
364
365
366
367
368
def filter(
    self,
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[DPort]:
    return [
        DPort(base=p.base)
        for p in super().filter(angle, orientation, layer, port_type, regex)
    ]

InstancePorts

Bases: ProtoTInstancePorts[int]

Source code in kfactory/instance_ports.py
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
class InstancePorts(ProtoTInstancePorts[int]):
    def __init__(self, instance: Instance) -> None:
        """Creates the virtual ports object.

        Args:
            instance: The related instance
        """
        self.instance = instance

    @property
    def cell_ports(self) -> Ports:
        return Ports(kcl=self.instance.cell.kcl, bases=self.instance.cell.ports.bases)

    def filter(
        self,
        angle: int | None = None,
        orientation: float | None = None,
        layer: LayerEnum | int | None = None,
        port_type: str | None = None,
        regex: str | None = None,
    ) -> Sequence[Port]:
        return [
            Port(base=p.base)
            for p in super().filter(angle, orientation, layer, port_type, regex)
        ]

    def __getitem__(
        self, key: int | str | tuple[int | str | None, int, int] | None
    ) -> Port:
        return Port(base=super().__getitem__(key).base)

    def __iter__(self) -> Iterator[Port]:
        yield from (p.to_itype() for p in self.each_port())

__getitem__

__getitem__(
    key: int
    | str
    | tuple[int | str | None, int, int]
    | None,
) -> Port

Returns port from instance.

The key can either be an integer, in which case the nth port is returned, or a string in which case the first port with a matching name is returned.

If the instance is an array, the key can also be a tuple in the form of c.ports[key_name, i_a, i_b], where i_a is the index in the instance.a direction and i_b the instance.b direction.

E.g. c.ports["a", 3, 5], accesses the ports of the instance which is 3 times in a direction (4th index in the array), and 5 times in b direction (5th index in the array).

Source code in kfactory/instance_ports.py
335
336
337
338
def __getitem__(
    self, key: int | str | tuple[int | str | None, int, int] | None
) -> Port:
    return Port(base=super().__getitem__(key).base)

__init__

__init__(instance: Instance) -> None

Creates the virtual ports object.

Parameters:

Name Type Description Default
instance Instance

The related instance

required
Source code in kfactory/instance_ports.py
310
311
312
313
314
315
316
def __init__(self, instance: Instance) -> None:
    """Creates the virtual ports object.

    Args:
        instance: The related instance
    """
    self.instance = instance

filter

filter(
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[Port]

Filter ports by name.

Parameters:

Name Type Description Default
angle int | None

Filter by angle. 0, 1, 2, 3.

None
orientation float | None

Filter by orientation in degrees.

None
layer LayerEnum | int | None

Filter by layer.

None
port_type str | None

Filter by port type.

None
regex str | None

Filter by regex of the name.

None
Source code in kfactory/instance_ports.py
322
323
324
325
326
327
328
329
330
331
332
333
def filter(
    self,
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[Port]:
    return [
        Port(base=p.base)
        for p in super().filter(angle, orientation, layer, port_type, regex)
    ]

ProtoTInstancePorts

Bases: ProtoInstancePorts[T, ProtoTInstance[T]], ABC

Ports of an Instance.

These act as virtual ports as the centers needs to change if the instance changes etc.

Attributes:

Name Type Description
cell_ports ProtoPorts[T]

A pointer to the KCell.ports of the cell

instance ProtoTInstance[T]

A pointer to the Instance related to this. This provides a way to dynamically calculate the ports.

Source code in kfactory/instance_ports.py
 65
 66
 67
 68
 69
 70
 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
class ProtoTInstancePorts[T: (int, float)](
    ProtoInstancePorts[T, ProtoTInstance[T]], ABC
):
    """Ports of an Instance.

    These act as virtual ports as the centers needs to change if the
    instance changes etc.


    Attributes:
        cell_ports: A pointer to the [`KCell.ports`][kfactory.kcell.KCell.ports]
            of the cell
        instance: A pointer to the Instance related to this.
            This provides a way to dynamically calculate the ports.
    """

    instance: ProtoTInstance[T]

    def __len__(self) -> int:
        """Return Port count."""
        if not self.instance.instance.is_regular_array():
            return len(self.cell_ports)
        return len(self.cell_ports) * self.instance.na * self.instance.nb

    def __contains__(self, port: str | ProtoPort[Any]) -> bool:
        """Check whether a port is in this port collection."""
        if isinstance(port, ProtoPort):
            return port.base in [p.base for p in self.instance.ports]
        return any(_port.name == port for _port in self.instance.ports)

    @property
    def ports(self) -> ProtoTInstancePorts[T]:
        return self.instance.ports

    @property
    def bases(self) -> list[BasePort]:
        return [p.base for p in self.instance.ports]

    def filter(
        self,
        angle: int | None = None,
        orientation: float | None = None,
        layer: LayerEnum | int | None = None,
        port_type: str | None = None,
        regex: str | None = None,
    ) -> Sequence[ProtoPort[T]]:
        """Filter ports by name.

        Args:
            angle: Filter by angle. 0, 1, 2, 3.
            orientation: Filter by orientation in degrees.
            layer: Filter by layer.
            port_type: Filter by port type.
            regex: Filter by regex of the name.
        """
        ports: Iterable[ProtoPort[T]] = list(self.ports)
        if regex:
            ports = filter_regex(ports, regex)
        if layer is not None:
            ports = filter_layer(ports, layer)
        if port_type:
            ports = filter_port_type(ports, port_type)
        if angle is not None:
            ports = filter_direction(ports, angle)
        if orientation is not None:
            ports = filter_orientation(ports, orientation)
        return list(ports)

    def __getitem__(
        self, key: int | str | tuple[int | str | None, int, int] | None
    ) -> ProtoPort[T]:
        """Returns port from instance.

        The key can either be an integer, in which case the nth port is
        returned, or a string in which case the first port with a matching
        name is returned.

        If the instance is an array, the key can also be a tuple in the
        form of `c.ports[key_name, i_a, i_b]`, where `i_a` is the index in
        the `instance.a` direction and `i_b` the `instance.b` direction.

        E.g. `c.ports["a", 3, 5]`, accesses the ports of the instance which is
        3 times in `a` direction (4th index in the array), and 5 times in `b` direction
        (5th index in the array).
        """
        if not self.instance.is_regular_array():
            try:
                p = self.cell_ports[cast("int | str | None", key)]
                if not self.instance.is_complex():
                    return p.copy(self.instance.trans)
                return p.copy(self.instance.dcplx_trans)
            except KeyError as e:
                raise KeyError(
                    f"{key=} is not a valid port name or index. "
                    "Make sure the instance is an array when giving it a tuple. "
                    f"Available ports: {[v.name for v in self.cell_ports]}"
                ) from e
        else:
            if isinstance(key, tuple):
                key, i_a, i_b = key
                if i_a >= self.instance.na or i_b >= self.instance.nb:
                    raise IndexError(
                        f"The indexes {i_a=} and {i_b=} must be within the array size"
                        f" instance.na={self.instance.na} and"
                        f" instance.nb={self.instance.nb}"
                    )
            else:
                i_a = 0
                i_b = 0
            p = self.cell_ports[key]
            if not self.instance.is_complex():
                return p.copy(
                    kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                    * self.instance.trans
                )
            return p.copy(
                kdb.DCplxTrans(self.instance.da * i_a + self.instance.db * i_b)
                * self.instance.dcplx_trans
            )

    @property
    @abstractmethod
    def cell_ports(self) -> ProtoPorts[T]: ...

    def each_port(self) -> Iterator[ProtoPort[T]]:
        """Create a copy of the ports to iterate through."""
        if not self.instance.is_regular_array():
            if not self.instance.is_complex():
                yield from (p.copy(self.instance.trans) for p in self.cell_ports)
            else:
                yield from (p.copy(self.instance.dcplx_trans) for p in self.cell_ports)
        elif not self.instance.is_complex():
            yield from (
                p.copy(
                    kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                    * self.instance.trans
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for p in self.cell_ports
            )
        else:
            yield from (
                p.copy(
                    kdb.DCplxTrans(self.instance.da * i_a + self.instance.db * i_b)
                    * self.instance.dcplx_trans
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for p in self.cell_ports
            )

    @abstractmethod
    def __iter__(self) -> Iterator[ProtoPort[T]]: ...

    def each_by_array_coord(self) -> Iterator[tuple[int, int, ProtoPort[T]]]:
        if not self.instance.is_regular_array():
            if not self.instance.is_complex():
                yield from (
                    (0, 0, p.copy(self.instance.trans)) for p in self.cell_ports
                )
            else:
                yield from (
                    (0, 0, p.copy(self.instance.dcplx_trans)) for p in self.cell_ports
                )
        elif not self.instance.is_complex():
            yield from (
                (
                    i_a,
                    i_b,
                    p.copy(
                        kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                        * self.instance.trans
                    ),
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for p in self.cell_ports
            )
        else:
            yield from (
                (
                    i_a,
                    i_b,
                    p.copy(
                        kdb.DCplxTrans(self.instance.da * i_a + self.instance.db * i_b)
                        * self.instance.dcplx_trans
                    ),
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for p in self.cell_ports
            )

    def print(self) -> None:
        config.console.print(pprint_ports(self.copy()))

    def copy(
        self, rename_function: Callable[[list[Port]], None] | None = None
    ) -> Ports:
        """Creates a copy in the form of [Ports][kfactory.kcell.Ports]."""
        if not self.instance.is_regular_array():
            if not self.instance.is_complex():
                return Ports(
                    kcl=self.instance.kcl,
                    bases=[
                        b.transformed(trans=self.instance.trans)
                        for b in self.cell_ports.bases
                    ],
                )
            return Ports(
                kcl=self.instance.kcl,
                bases=[
                    b.transformed(trans=self.instance.dcplx_trans)
                    for b in self.cell_ports.bases
                ],
            )
        if not self.instance.is_complex():
            return Ports(
                kcl=self.instance.kcl,
                bases=[
                    b.transformed(
                        self.instance.trans
                        * kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                    )
                    for i_a in range(self.instance.na)
                    for i_b in range(self.instance.nb)
                    for b in self.cell_ports.bases
                ],
            )
        return Ports(
            kcl=self.instance.kcl,
            bases=[
                b.transformed(
                    self.instance.dcplx_trans
                    * kdb.DCplxTrans(self.instance.db * i_a + self.instance.db * i_b)
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for b in self.cell_ports.bases
            ],
        )

__contains__

__contains__(port: str | ProtoPort[Any]) -> bool

Check whether a port is in this port collection.

Source code in kfactory/instance_ports.py
89
90
91
92
93
def __contains__(self, port: str | ProtoPort[Any]) -> bool:
    """Check whether a port is in this port collection."""
    if isinstance(port, ProtoPort):
        return port.base in [p.base for p in self.instance.ports]
    return any(_port.name == port for _port in self.instance.ports)

__getitem__

__getitem__(
    key: int
    | str
    | tuple[int | str | None, int, int]
    | None,
) -> ProtoPort[T]

Returns port from instance.

The key can either be an integer, in which case the nth port is returned, or a string in which case the first port with a matching name is returned.

If the instance is an array, the key can also be a tuple in the form of c.ports[key_name, i_a, i_b], where i_a is the index in the instance.a direction and i_b the instance.b direction.

E.g. c.ports["a", 3, 5], accesses the ports of the instance which is 3 times in a direction (4th index in the array), and 5 times in b direction (5th index in the array).

Source code in kfactory/instance_ports.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
def __getitem__(
    self, key: int | str | tuple[int | str | None, int, int] | None
) -> ProtoPort[T]:
    """Returns port from instance.

    The key can either be an integer, in which case the nth port is
    returned, or a string in which case the first port with a matching
    name is returned.

    If the instance is an array, the key can also be a tuple in the
    form of `c.ports[key_name, i_a, i_b]`, where `i_a` is the index in
    the `instance.a` direction and `i_b` the `instance.b` direction.

    E.g. `c.ports["a", 3, 5]`, accesses the ports of the instance which is
    3 times in `a` direction (4th index in the array), and 5 times in `b` direction
    (5th index in the array).
    """
    if not self.instance.is_regular_array():
        try:
            p = self.cell_ports[cast("int | str | None", key)]
            if not self.instance.is_complex():
                return p.copy(self.instance.trans)
            return p.copy(self.instance.dcplx_trans)
        except KeyError as e:
            raise KeyError(
                f"{key=} is not a valid port name or index. "
                "Make sure the instance is an array when giving it a tuple. "
                f"Available ports: {[v.name for v in self.cell_ports]}"
            ) from e
    else:
        if isinstance(key, tuple):
            key, i_a, i_b = key
            if i_a >= self.instance.na or i_b >= self.instance.nb:
                raise IndexError(
                    f"The indexes {i_a=} and {i_b=} must be within the array size"
                    f" instance.na={self.instance.na} and"
                    f" instance.nb={self.instance.nb}"
                )
        else:
            i_a = 0
            i_b = 0
        p = self.cell_ports[key]
        if not self.instance.is_complex():
            return p.copy(
                kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                * self.instance.trans
            )
        return p.copy(
            kdb.DCplxTrans(self.instance.da * i_a + self.instance.db * i_b)
            * self.instance.dcplx_trans
        )

__len__

__len__() -> int

Return Port count.

Source code in kfactory/instance_ports.py
83
84
85
86
87
def __len__(self) -> int:
    """Return Port count."""
    if not self.instance.instance.is_regular_array():
        return len(self.cell_ports)
    return len(self.cell_ports) * self.instance.na * self.instance.nb

copy

copy(
    rename_function: Callable[[list[Port]], None]
    | None = None,
) -> Ports

Creates a copy in the form of Ports.

Source code in kfactory/instance_ports.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
def copy(
    self, rename_function: Callable[[list[Port]], None] | None = None
) -> Ports:
    """Creates a copy in the form of [Ports][kfactory.kcell.Ports]."""
    if not self.instance.is_regular_array():
        if not self.instance.is_complex():
            return Ports(
                kcl=self.instance.kcl,
                bases=[
                    b.transformed(trans=self.instance.trans)
                    for b in self.cell_ports.bases
                ],
            )
        return Ports(
            kcl=self.instance.kcl,
            bases=[
                b.transformed(trans=self.instance.dcplx_trans)
                for b in self.cell_ports.bases
            ],
        )
    if not self.instance.is_complex():
        return Ports(
            kcl=self.instance.kcl,
            bases=[
                b.transformed(
                    self.instance.trans
                    * kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                )
                for i_a in range(self.instance.na)
                for i_b in range(self.instance.nb)
                for b in self.cell_ports.bases
            ],
        )
    return Ports(
        kcl=self.instance.kcl,
        bases=[
            b.transformed(
                self.instance.dcplx_trans
                * kdb.DCplxTrans(self.instance.db * i_a + self.instance.db * i_b)
            )
            for i_a in range(self.instance.na)
            for i_b in range(self.instance.nb)
            for b in self.cell_ports.bases
        ],
    )

each_port

each_port() -> Iterator[ProtoPort[T]]

Create a copy of the ports to iterate through.

Source code in kfactory/instance_ports.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def each_port(self) -> Iterator[ProtoPort[T]]:
    """Create a copy of the ports to iterate through."""
    if not self.instance.is_regular_array():
        if not self.instance.is_complex():
            yield from (p.copy(self.instance.trans) for p in self.cell_ports)
        else:
            yield from (p.copy(self.instance.dcplx_trans) for p in self.cell_ports)
    elif not self.instance.is_complex():
        yield from (
            p.copy(
                kdb.Trans(self.instance.a * i_a + self.instance.b * i_b)
                * self.instance.trans
            )
            for i_a in range(self.instance.na)
            for i_b in range(self.instance.nb)
            for p in self.cell_ports
        )
    else:
        yield from (
            p.copy(
                kdb.DCplxTrans(self.instance.da * i_a + self.instance.db * i_b)
                * self.instance.dcplx_trans
            )
            for i_a in range(self.instance.na)
            for i_b in range(self.instance.nb)
            for p in self.cell_ports
        )

filter

filter(
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[ProtoPort[T]]

Filter ports by name.

Parameters:

Name Type Description Default
angle int | None

Filter by angle. 0, 1, 2, 3.

None
orientation float | None

Filter by orientation in degrees.

None
layer LayerEnum | int | None

Filter by layer.

None
port_type str | None

Filter by port type.

None
regex str | None

Filter by regex of the name.

None
Source code in kfactory/instance_ports.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def filter(
    self,
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> Sequence[ProtoPort[T]]:
    """Filter ports by name.

    Args:
        angle: Filter by angle. 0, 1, 2, 3.
        orientation: Filter by orientation in degrees.
        layer: Filter by layer.
        port_type: Filter by port type.
        regex: Filter by regex of the name.
    """
    ports: Iterable[ProtoPort[T]] = list(self.ports)
    if regex:
        ports = filter_regex(ports, regex)
    if layer is not None:
        ports = filter_layer(ports, layer)
    if port_type:
        ports = filter_port_type(ports, port_type)
    if angle is not None:
        ports = filter_direction(ports, angle)
    if orientation is not None:
        ports = filter_orientation(ports, orientation)
    return list(ports)

VInstancePorts

Bases: ProtoInstancePorts[float, VInstance]

Ports of an instance.

These act as virtual ports as the centers needs to change if the instance changes etc.

Attributes:

Name Type Description
cell_ports DPorts

A pointer to the KCell.ports of the cell

instance VInstance

A pointer to the Instance related to this. This provides a way to dynamically calculate the ports.

Source code in kfactory/instance_ports.py
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
class VInstancePorts(ProtoInstancePorts[float, VInstance]):
    """Ports of an instance.

    These act as virtual ports as the centers needs to change if the
    instance changes etc.


    Attributes:
        cell_ports: A pointer to the [`KCell.ports`][kfactory.kcell.KCell.ports]
            of the cell
        instance: A pointer to the Instance related to this.
            This provides a way to dynamically calculate the ports.
    """

    instance: VInstance

    def __init__(self, instance: VInstance) -> None:
        """Creates the virtual ports object.

        Args:
            instance: The related instance
        """
        self.instance = instance

    @property
    def cell_ports(self) -> DPorts:
        return DPorts(
            kcl=self.instance.cell.ports.kcl, bases=self.instance.cell.ports.bases
        )

    def __len__(self) -> int:
        """Return Port count."""
        return len(self.cell_ports)

    def __getitem__(
        self, key: int | str | tuple[int | str | None, int, int] | None
    ) -> DPort:
        if isinstance(key, tuple):
            return self.cell_ports[key[0]].copy(
                kdb.DCplxTrans(
                    (self.instance.na - 1) * self.instance.a
                    + (self.instance.nb - 1) * self.instance.b
                )
                * self.instance.trans
            )
        return self.cell_ports[key].copy(self.instance.trans)

    def __iter__(self) -> Iterator[DPort]:
        """Create a copy of the ports to iterate through."""
        yield from (p.copy(self.instance.trans) for p in self.cell_ports)

    def __contains__(self, port: str | ProtoPort[Any]) -> bool:
        """Check if a port is in the instance."""
        if isinstance(port, ProtoPort):
            return port.base in [p.base for p in self.instance.ports]
        return any(_port.name == port for _port in self.instance.ports)

    def filter(
        self,
        angle: int | None = None,
        orientation: float | None = None,
        layer: LayerEnum | int | None = None,
        port_type: str | None = None,
        regex: str | None = None,
    ) -> list[DPort]:
        """Filter ports by name.

        Args:
            angle: Filter by angle. 0, 1, 2, 3.
            orientation: Filter by orientation in degrees.
            layer: Filter by layer.
            port_type: Filter by port type.
            regex: Filter by regex of the name.
        """
        ports = list(self.instance.ports)
        if regex:
            ports = list(filter_regex(ports, regex))
        if layer is not None:
            ports = list(filter_layer(ports, layer))
        if port_type:
            ports = list(filter_port_type(ports, port_type))
        if angle is not None:
            ports = list(filter_direction(ports, angle))
        if orientation is not None:
            ports = list(filter_orientation(ports, orientation))
        return list(ports)

    def copy(self) -> DPorts:
        """Creates a copy in the form of [Ports][kfactory.kcell.Ports]."""
        return DPorts(
            kcl=self.instance.cell.kcl,
            bases=[b.transformed(self.instance.trans) for b in self.cell_ports.bases],
        )

    def print(self) -> None:
        config.console.print(pprint_ports(self.copy(), unit="um"))

__contains__

__contains__(port: str | ProtoPort[Any]) -> bool

Check if a port is in the instance.

Source code in kfactory/instance_ports.py
430
431
432
433
434
def __contains__(self, port: str | ProtoPort[Any]) -> bool:
    """Check if a port is in the instance."""
    if isinstance(port, ProtoPort):
        return port.base in [p.base for p in self.instance.ports]
    return any(_port.name == port for _port in self.instance.ports)

__init__

__init__(instance: VInstance) -> None

Creates the virtual ports object.

Parameters:

Name Type Description Default
instance VInstance

The related instance

required
Source code in kfactory/instance_ports.py
395
396
397
398
399
400
401
def __init__(self, instance: VInstance) -> None:
    """Creates the virtual ports object.

    Args:
        instance: The related instance
    """
    self.instance = instance

__iter__

__iter__() -> Iterator[DPort]

Create a copy of the ports to iterate through.

Source code in kfactory/instance_ports.py
426
427
428
def __iter__(self) -> Iterator[DPort]:
    """Create a copy of the ports to iterate through."""
    yield from (p.copy(self.instance.trans) for p in self.cell_ports)

__len__

__len__() -> int

Return Port count.

Source code in kfactory/instance_ports.py
409
410
411
def __len__(self) -> int:
    """Return Port count."""
    return len(self.cell_ports)

copy

copy() -> DPorts

Creates a copy in the form of Ports.

Source code in kfactory/instance_ports.py
466
467
468
469
470
471
def copy(self) -> DPorts:
    """Creates a copy in the form of [Ports][kfactory.kcell.Ports]."""
    return DPorts(
        kcl=self.instance.cell.kcl,
        bases=[b.transformed(self.instance.trans) for b in self.cell_ports.bases],
    )

filter

filter(
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> list[DPort]

Filter ports by name.

Parameters:

Name Type Description Default
angle int | None

Filter by angle. 0, 1, 2, 3.

None
orientation float | None

Filter by orientation in degrees.

None
layer LayerEnum | int | None

Filter by layer.

None
port_type str | None

Filter by port type.

None
regex str | None

Filter by regex of the name.

None
Source code in kfactory/instance_ports.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def filter(
    self,
    angle: int | None = None,
    orientation: float | None = None,
    layer: LayerEnum | int | None = None,
    port_type: str | None = None,
    regex: str | None = None,
) -> list[DPort]:
    """Filter ports by name.

    Args:
        angle: Filter by angle. 0, 1, 2, 3.
        orientation: Filter by orientation in degrees.
        layer: Filter by layer.
        port_type: Filter by port type.
        regex: Filter by regex of the name.
    """
    ports = list(self.instance.ports)
    if regex:
        ports = list(filter_regex(ports, regex))
    if layer is not None:
        ports = list(filter_layer(ports, layer))
    if port_type:
        ports = list(filter_port_type(ports, port_type))
    if angle is not None:
        ports = list(filter_direction(ports, angle))
    if orientation is not None:
        ports = list(filter_orientation(ports, orientation))
    return list(ports)