waveguide factory.py

This script mainly provides a more intelligent solution for implementing port acquisition and bend routing in automatic waveguide routing. The main components are

Straight

Define class StraightFactory

@dataclass(frozen=True)
class StraightFactory(fpt.IStraightWaveguideFactory):
    def __call__(self, type: fpt.IWaveguideType, length: float):
        from gpdk.components.straight.straight import Straight

        straight = Straight(length=length, waveguide_type=type)
        return straight, ("op_0", "op_1")

Returns straight waveguide in gpdk > components > straight > Straight and port information to provide support for port connections during automatic routing.

CircularBend

Define class CircularBendFactory:

@dataclass(frozen=True)
class CircularBendFactory(fpt.IBendWaveguideFactory):
    radius_eff: float
    waveguide_type: fpt.IWaveguideType = field(repr=False, compare=False)

    def __call__(self, central_angle: float):
        from gpdk.components.bend.bend_circular import BendCircular, BendCircular90_FWG_C_WIRE, BendCircular90_FWG_C_EXPANDED
        from gpdk.technology import get_technology

        TECH = get_technology()

        radius_eff = self.radius_eff
        bend = None
        if fp.is_close(abs(central_angle), math.pi / 2):
            if self.waveguide_type == TECH.WG.FWG.C.WIRE:
                bend = BendCircular90_FWG_C_WIRE()
            elif self.waveguide_type == TECH.WG.FWG.C.EXPANDED:
                bend = BendCircular90_FWG_C_EXPANDED()

            if bend and central_angle < 0:
                bend = bend.v_mirrored()

        if bend is None:
            bend = BendCircular(degrees=math.degrees(central_angle), radius=radius_eff, waveguide_type=self.waveguide_type)

        return bend, radius_eff, ("op_0", "op_1")

The parameters of the CircularBendFactory that can be set optionally are

  • radius_eff

  • waveguide_type

There are two options to apply this bend factory to waveguide routing.

  • Assign CircularBendFactory(waveguide_type=waveguide_type, radius_eff=radius_eff) to the parameter bend_factory in the routing function e.g., Linked, create_links and LinkBetween.

  • Implement CircularBendFactory to each waveguide class (please see wg.py) and set TECH.WG.FWG.C.WIRE.BEND_CIRCULAR once you’ve return CircularBendFactory to BEND_CIRCULAR under the class WG.FWG.C.WIRE.

By giving a certain condition (certain waveguide type and certain bending angle, TECH.WG.FWG.C.WIRE and 90 degree bend for example), users are allowed to assign a fixed bend (either a GDS import cell or fixed cell) to this waveguide type.

This means that when the bend angle is 90 degree and the waveguide type of two connected ports are also FWG.C.WIRE, BendCircular90_FWG_C_WIRE will be automatically use.

Implementation

There are two ways to implement waveguide_factory for further use, one is to set it as default for every waveguide type, and another is to define a waveguide_factory by themselves and use it for auto-routing.

  • Set as default in wg.py

    Here we use the class named CircularBendFactory which we just defined. You can set radius_eff parameter to a value according to the technical specifications. We recommend that implementing bend_factory for every waveguide_type that you created so that you can set up several types of bend_factory as units in routing function.

    straight_factory and bend_factory are defined in wg.py to automatically use the PCell of straight and bend in the routing.

    class WG:
        class FWG:
            class C(FWG_C):
                @fpt.staticconst
                def WIRE():
                    class WIRE(__class__):
                        core_design_width: float = FWG_C_WIRE_WIDTH
                        cladding_design_width: float = FWG_C_WIRE_WIDTH + FWG_C_TRENCH_WIDTH * 2
    
                        @fpt.const_property
                        def bend_factory(self):
                            return self.BEND_EULER
    
    
                        @fpt.const_property
                        def BEND_CIRCULAR(self):
                            return CircularBendFactory(radius_eff=self.cladding_width / 2 + 1, waveguide_type=self)
    
                        @fpt.const_property
                        def BEND_EULER(self):
                            return EulerBendFactory(radius_min=self.cladding_width / 2 + 1, l_max=5, waveguide_type=self)
    
                    return WIRE()
    
  • Manually define bend_factory

    Below scripts show how to generate a user-defined bend_factory.

    @dataclass(frozen=True)
    class user_defined_bendfactory(fpt.IBendWaveguideFactory):
        radius_eff: float
        waveguide_type: fpt.IWaveguideType = field(repr=False, compare=False)
    
        def __call__(self, central_angle: float):
            from gpdk.components.bend.bend_circular import BendCircular
            radius_eff = self.radius_eff
            bend = BendCircular(degrees=math.degrees(central_angle), radius=radius_eff, waveguide_type=self.waveguide_type)
            return bend, radius_eff, ("op_0", "op_1")
    
    user_defined_bend_factory = user_defined_bendfactory(radius_eff=10, waveguide_type=TECH.WG.SWG.C.WIRE)
    

    Then users can decide to use the defined user_defined_bendfactory in the link function or they can simply enter TECH.WG.FWG.C.WIRE.BEND_CIRCULAR if they define BEND_CIRCULAR and BEND_EULER under TECH.WG.FWG.C.WIRE. The choose of use depends entirely on the user’s consideration of the performance of the device:

    link1 = fp.create_links(
        link_type=TECH.WG.FWG.C.EXPANDED,
        # bend_factory=TECH.WG.FWG.C.WIRE.BEND_CIRCULAR,
        bend_factory=user_defined_bend_factory,
        specs=[
            wg1["op_0"] >> wg2["op_1"],
            wg1["op_1"] >> wg3["op_1"],
        ],
    )