Extension of the ports
The Extended class can be used to implement the device port in situations where the device port extension is required. A detailed illustration of this function definition is given in gpdk> routing > extended.py
Extended
Full script
from numbers import Number
from typing import List, Mapping, Optional, Tuple
from fnpcell import all as fp
from gpdk.components.straight.straight import Straight
from gpdk.routing.auto_transitioned.auto_transitioned import AutoTransitioned
from gpdk.technology import get_technology
class Extended(fp.PCell):
"""
Attributes:
device: device whose ports need to be extended
lengths: dict with port name as key, length as value, "*" means every other port
waveguide_type: type of generated waveguide
Examples:
```python
TECH = get_technology()
device = Extended(device=Mmi(waveguide_type=TECH.WG.FWG.C.WIRE), lengths={"*": 10, "op_0": 20, "op_1": 30})
fp.plot(device)
```

"""
device: fp.IDevice = fp.DeviceParam()
lengths: Mapping[str, float] = fp.MappingParam(K=str, V=Number, immutable=True)
waveguide_type: Optional[fp.IWaveguideType] = fp.WaveguideTypeParam(required=False)
def build(self) -> Tuple[fp.InstanceSet, fp.ElementSet, fp.PortSet]:
insts, elems, ports = super().build()
device = self.device
lengths = self.lengths
waveguide_type = self.waveguide_type
instance = device if waveguide_type is None else AutoTransitioned(device=device, waveguide_types={key: waveguide_type for key in lengths})
joints: List[Tuple[fp.IOwnedTerminal, fp.IOwnedTerminal]] = []
straight_ports: List[fp.IOwnedTerminal] = []
for port in instance.ports:
if isinstance(port, fp.IOwnedPort) and not port.disabled:
length = lengths.get(port.name) or lengths.get("*")
if length is not None:
if waveguide_type is not None:
length -= fp.distance_between(device[port.name].position, instance[port.name].position)
assert length > 0 or fp.is_zero(length), f"extend length of {port.name} is too short"
if length > 0:
s = Straight(length=length, waveguide_type=port.waveguide_type)
joints.append(port <= s["op_0"])
port_name = port.name
straight_ports.append(s["op_1"].with_name(fp.Hidden(port_name) if port.hidden else port_name))
used_port_names = set(port.name for port in straight_ports)
unused_ports = [port for port in instance.ports if port.name not in used_port_names]
connected = fp.Connected(
joints=joints,
ports=straight_ports + unused_ports,
)
insts += connected
ports += connected.ports
return insts, elems, ports
if __name__ == "__main__":
from gpdk.util.path import local_output_file
gds_file = local_output_file(__file__).with_suffix(".gds")
library = fp.Library()
TECH = get_technology()
# =============================================================
# fmt: off
from gpdk.components.mmi.mmi import Mmi
from gpdk.components.ring_resonator.ring_resonator import RingResonator
library += Extended(device=Mmi(waveguide_type=TECH.WG.FWG.C.WIRE), lengths={"*": 10, "op_0": 20, "op_1": 30})
library += Extended(device=RingResonator(ring_radius=10, bottom_spacing=0.1, top_spacing=0.1, ring_type=TECH.WG.FWG.C.WIRE, bottom_type=TECH.WG.FWG.C.WIRE, top_type=TECH.WG.FWG.C.WIRE), lengths={"op_0": 1, "op_1": 1, "op_2": 1, "op_3": 1})
# fmt: on
# =============================================================
fp.export_gds(library, file=gds_file)
# fp.plot(library)
Section Script Definition
Create extended ports and export layout
if __name__ == "__main__":
from pathlib import Path
gds_file = Path(__file__).parent / "local" / Path(__file__).with_suffix(".gds").name
library = fp.Library()
TECH = get_technology()
# =============================================================
# fmt: off
from gpdk.components.mmi.mmi import Mmi
from gpdk.components.ring_resonator.ring_resonator import RingResonator
library += Extended(device=Mmi(waveguide_type=TECH.WG.FWG.C.WIRE), lengths={"*": 10, "op_0": 20, "op_1": 30})
library += Extended(device=RingResonator(ring_radius=10, bottom_spacing=0.1, top_spacing=0.1, ring_type=TECH.WG.FWG.C.WIRE, bottom_type=TECH.WG.FWG.C.WIRE, top_type=TECH.WG.FWG.C.WIRE), lengths={"op_0": 1, "op_1": 1, "op_2": 1, "op_3": 1})
# fmt: on
# =============================================================
fp.export_gds(library, file=gds_file)
# fp.plot(library)
Here we implement the device port extension by using the Extended class, where device receives the devices that need to be extended, waveguide_type receives the type of the extended waveguide, and lengths receives the length of each port that needs to be extended. The following figure shows the result of extending the port along.
GDS Layout