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) ``` ![Extended](images/extended.png) """ 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 ----------------- .. image:: ../images/extend1.png