Routing to IO#

Routing electrical#

For routing low speed DC electrical ports you can use sharp corners instead of smooth bends.

You can also define port.orientation = None to ignore the port orientation for low speed DC ports.

For single route between ports you can use get_route_electrical

get_route_electrical#

get_route_electrical has bend = wire_corner with a 90deg bend corner.

from functools import partial

import gdsfactory as gf
from gdsfactory.generic_tech import get_generic_pdk
from gdsfactory.samples.big_device import big_device

gf.config.rich_output()

c = gf.Component("pads")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((70, 200))
c.plot()

../_images/2845c9f947362ec6597a841420027454cfbfdd579e08ecabe153652c4e80de9e.png
c = gf.Component("pads_with_routes_with_bends")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((70, 200))
route = gf.routing.get_route_electrical(
    pt.ports["e11"], pb.ports["e11"], bend="bend_euler", radius=30
)
c.add(route.references)
c.plot()

../_images/abbceab72108b2c20cb5d6338624bd161b9b2caa079da0112ceae605a82a7291.png
c = gf.Component("pads_with_routes_with_wire_corners")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((70, 200))
route = gf.routing.get_route_electrical(
    pt.ports["e11"], pb.ports["e11"], bend="wire_corner"
)
c.add(route.references)
c.plot()

../_images/abbceab72108b2c20cb5d6338624bd161b9b2caa079da0112ceae605a82a7291.png
c = gf.Component("pads_with_routes_with_wire_corners_no_orientation")
pt = c << gf.components.pad_array(orientation=None, columns=3)
pb = c << gf.components.pad_array(orientation=None, columns=3)
pt.move((70, 200))
route = gf.routing.get_route_electrical(
    pt.ports["e11"], pb.ports["e11"], bend="wire_corner"
)
c.add(route.references)
c.plot()

../_images/94fdfdaecb6c13c6c31ee8dcfb762e5dc7d142dd39d089f775bbc07579e77368.png
c = gf.Component("multi-layer")
columns = 2
ptop = c << gf.components.pad_array(columns=columns)
pbot = c << gf.components.pad_array(orientation=90, columns=columns)

ptop.movex(300)
ptop.movey(300)
route = gf.routing.get_route_electrical_multilayer(
    ptop.ports["e11"],
    pbot.ports["e11"],
    end_straight_length=100,
)
c.add(route.references)
c.plot()

../_images/8bfc463d4d284277699091024ae41084c77eac5be7bfac990011466d3db49cfd.png

There is also bend = wire_corner45 for 45deg bend corner with parametrizable “radius”:

c = gf.Component("pads_with_routes_with_wire_corner45")
pt = c << gf.components.pad_array(orientation=270, columns=1)
pb = c << gf.components.pad_array(orientation=90, columns=1)
pt.move((300, 300))
route = gf.routing.get_route_electrical(
    pt.ports["e11"], pb.ports["e11"], bend="wire_corner45", radius=30
)
c.add(route.references)
c.plot()

../_images/ab44e7c754bec1cce3819a109a51fadb027a4868ff624fa01981b501acdc93cf.png
c = gf.Component("pads_with_routes_with_wire_corner45")
pt = c << gf.components.pad_array(orientation=270, columns=1)
pb = c << gf.components.pad_array(orientation=90, columns=1)
pt.move((300, 300))
route = gf.routing.get_route_electrical(
    pt.ports["e11"], pb.ports["e11"], bend="wire_corner45", radius=100
)
c.add(route.references)
c.plot()

../_images/ab44e7c754bec1cce3819a109a51fadb027a4868ff624fa01981b501acdc93cf.png

route_quad#

c = gf.Component("pads_route_quad")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((100, 200))
route = c << gf.routing.route_quad(pt.ports["e11"], pb.ports["e11"], layer=(49, 0))
c.plot()

../_images/62a557780635d66b71607bf0de355764aa6fec712f4df35d70f575eb19621e4c.png

get_route_from_steps#

c = gf.Component("pads_route_from_steps")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((100, 200))
route = gf.routing.get_route_from_steps(
    pb.ports["e11"],
    pt.ports["e11"],
    steps=[
        {"y": 200},
    ],
    cross_section="xs_metal_routing",
    bend=gf.components.wire_corner,
)
c.add(route.references)
c.plot()

../_images/8a2ef5065cdc8d968dae575c72851a82312cc8bb854014cff77e15507a777f17.png
c = gf.Component("pads_route_from_steps_None_orientation")
pt = c << gf.components.pad_array(orientation=None, columns=3)
pb = c << gf.components.pad_array(orientation=None, columns=3)
pt.move((100, 200))
route = gf.routing.get_route_from_steps(
    pb.ports["e11"],
    pt.ports["e11"],
    steps=[
        {"y": 200},
    ],
    cross_section="xs_metal_routing",
    bend=gf.components.wire_corner,
)
c.add(route.references)
c.plot()

../_images/8be11684453e039a9450322bd09dcd9af2fb1cabc185e48301ad9628ef1482ea.png

get_bundle_electrical#

For routing groups of ports you can use get_bundle that returns a bundle of routes using a bundle router (also known as bus or river router)

c = gf.Component("pads_bundle")
pt = c << gf.components.pad_array(orientation=270, columns=3)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((100, 200))

routes = gf.routing.get_bundle_electrical(
    pb.ports, pt.ports, end_straight_length=60, separation=30
)

for route in routes:
    c.add(route.references)
c.plot()

../_images/9c70ca59bcde53ff3ac9b2c35ecc7f117625d1daeb160170ebb2cf65f2fc4e2c.png

get_bundle_from_steps_electrical#

c = gf.Component("pads_bundle_steps")
pt = c << gf.components.pad_array(
    partial(gf.components.pad, size=(30, 30)),
    orientation=270,
    columns=3,
    spacing=(50, 0),
)
pb = c << gf.components.pad_array(orientation=90, columns=3)
pt.move((300, 500))

routes = gf.routing.get_bundle_from_steps_electrical(
    pb.ports, pt.ports, end_straight_length=60, separation=30, steps=[{"dy": 100}]
)

for route in routes:
    c.add(route.references)

c.plot()

../_images/6ce288b8a55684d451b84a91dd96160d439b0e392e1a0743e3c14486e1de5b80.png

get_bundle_electrical_multilayer#

To avoid metal crossings you can use one metal layer.

c = gf.Component("get_bundle_multi_layer")
columns = 2
ptop = c << gf.components.pad_array(columns=columns)
pbot = c << gf.components.pad_array(orientation=90, columns=columns)

ptop.movex(300)
ptop.movey(300)
routes = gf.routing.get_bundle_electrical_multilayer(
    ptop.ports, pbot.ports, end_straight_length=100, separation=20
)
for route in routes:
    c.add(route.references)
c.plot()

../_images/9a0d5d8eb32ff8751de3745ec42a632c39b289c82c9d06fa8f22797282c82410.png

Routing to pads#

You can also route to electrical pads.

c = gf.components.straight_heater_metal(length=100.0)
cc = gf.routing.add_pads_bot(component=c, port_names=("l_e4", "r_e4"), fanout_length=50)
cc.plot()

../_images/a350f199a1667b8d40824195c9483c71febf549105839453968e42dd7476915c.png
c = gf.components.straight_heater_metal(length=100.0)
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/a97c11ddbd55bdd1921b99f26cd35a3a7ec4553098228f7752761ab41bc61cdd.png
c = gf.components.straight_heater_metal(length=100.0)
cc = gf.routing.add_pads_top(component=c, port_names=("l_e2", "r_e2"))
cc.plot()

../_images/af8d88e6fee79c74e4dc48de9631f319f43f51a67edfa5ff1a021deb0ef95902.png
c = gf.c.nxn(
    xsize=600,
    ysize=200,
    north=2,
    south=3,
    wg_width=10,
    layer="M3",
    port_type="electrical",
)
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/334650245297766dc23000eca0fe8cae2146f30cddf88e5112e8f80fd55a0142.png
n = west = north = south = east = 10
spacing = 20
c = gf.components.nxn(
    xsize=n * spacing,
    ysize=n * spacing,
    west=west,
    east=east,
    north=north,
    south=south,
    port_type="electrical",
    wg_width=10,
)
c.plot()

../_images/357866af100e3511710f7be0bb63a6ea11cf197350a6f69c1feb1190b97ffee8.png
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/f8ecd44a7d009d67e24468c3440724e722f178aead4496408325b177cb14bb89.png

Routing to optical terminations#

Route to Fiber Array#

You can route to a fiber array.

component = big_device(nports=10)
c = gf.routing.add_fiber_array(component=component, radius=10.0, fanout_length=60.0)
c.plot()

../_images/1ccb15600c8bcd1c704df764458570a979c8490c6ae9693a09d374ccd18e0faa.png

You can also mix and match TE and TM grating couplers. Notice that the TM polarization grating coupler is bigger.

import gdsfactory as gf

c = gf.components.mzi_phase_shifter()
gcte = gf.components.grating_coupler_te

cc = gf.routing.add_fiber_array(
    component=c,
    optical_routing_type=2,
    grating_coupler=[
        gf.components.grating_coupler_te,
        gf.components.grating_coupler_tm,
    ],
    radius=20,
)
cc.plot()

../_images/eff0e95c29836e08f58bcab2a1fdcb150a45246468260f319f234829b6814a09.png

Route to Single fibers#

You can route to a single fiber input and single fiber output.

c = gf.components.ring_single()
cc = gf.routing.add_fiber_single(component=c)
cc.plot()

../_images/00e2c0d1c10ed3bbb0f6aaf387dab8c05f43cbe13e55e81ccd8a65688cbab1ff.png

Route to edge couplers#

You can also route Edge couplers to a fiber array or to both sides of the chip.

For routing to both sides you can follow different strategies:

  1. Place the edge couplers and route your components to the edge couplers.

  2. Extend your component ports to each side.

  3. Anything you imagine …

import numpy as np

import gdsfactory as gf
from gdsfactory.generic_tech import LAYER


@gf.cell
def sample_die(size=(2e3, 2e3), y_spacing: float = 10) -> gf.Component:
    """Returns a sample die

    Args:
        size: size of the die.
        y_spacing: spacing between components.

    Returns:
        c: a sample die.

    """
    c = gf.Component()

    die = c << gf.c.rectangle(size=np.array(size), layer=LAYER.FLOORPLAN, centered=True)
    die = c << gf.c.rectangle(
        size=np.array(size) - 2 * np.array((50, 50)),
        layer=LAYER.FLOORPLAN,
        centered=True,
    )
    ymin = die.ymin
    ec = gf.components.edge_coupler_silicon()

    components = [
        "mzi",
        "mmi1x2",
        "spiral_racetrack",
        "coupler",
        "ring_single",
        "ring_double",
    ]

    cells = gf.get_active_pdk().cells

    for component in components:
        function = cells[component]
        ci = function()
        ci = (
            gf.routing.add_pads_top(
                ci,
                pad=gf.components.pad,
                pad_spacing=150,
            )
            if ci.get_ports_list(port_type="electrical")
            else ci
        )
        ref = c << ci
        ref.ymin = ymin
        ref.x = 0
        ymin = ref.ymax + y_spacing

        routes_left, ports_left = gf.routing.route_ports_to_side(
            ref.get_ports_list(orientation=180),
            cross_section="xs_sc",
            side="west",
            x=die.xmin + ec.xsize,
        )
        for route in routes_left:
            c.add(route.references)

        routes_right, ports_right = gf.routing.route_ports_to_side(
            ref.get_ports_list(orientation=0),
            cross_section="xs_sc",
            x=die.xmax - ec.xsize,
            side="east",
        )
        for route in routes_right:
            c.add(route.references)

        for port in ports_right:
            ref = c << ec
            ref.connect("o1", port)
            text = c << gf.c.text(
                text=f"{ci.name}-{port.name.split('_')[0]}", size=10, layer=LAYER.MTOP
            )
            text.xmax = ref.xmax - 10
            text.y = ref.y

        for port in ports_left:
            ref = c << ec
            ref.connect("o1", port)
            text = c << gf.c.text(
                text=f"{ci.name}-{port.name.split('_')[0]}", size=10, layer=LAYER.MTOP
            )
            text.xmin = ref.xmin + 10
            text.y = ref.y

    return c


c = sample_die()
gf.remove_from_cache(c.name)
c.show(show_ports=True)  # show in klayout
c.plot()  # plot in notebook
2024-10-31 18:39:26.392 | WARNING  | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?

../_images/c2fe3f6b1054b30f4bb7ed24a8a2b3f4dc8788ae6e426b3e8d5b334458bb864e.png