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/7e99a74c762ddec5604a38746b736f17cb4f0e9d71a64aed46677097b448ede3.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/05872723583b7c658d15ec0d08b7258c360bd1b0b0da33bf37f03754e513a0bd.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/05872723583b7c658d15ec0d08b7258c360bd1b0b0da33bf37f03754e513a0bd.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/55350f9d6138299dd41a4e3050ecb04f8ae92a0bba03838a327eb8e54cec76de.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/50fd83f16bbc614f13bc51366732164aa648214d39eb06564fc3c34518067908.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/80ee29ba42062a6dd1fb6c7d137d61195f2a8acfe05962651039e2e6690d0e3f.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/80ee29ba42062a6dd1fb6c7d137d61195f2a8acfe05962651039e2e6690d0e3f.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/5d00cb0b50b1a603b55d80e20e52a676b69e64bbf4c3ee89de35bff45927f7d8.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/738ccf69e22734116a5d99212ee62b183e168ca15a8a7fdc55ec5c991b042480.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/1374e6edb5eb78357847f63bc3788daa69ccb934358ccb062e8e9fce35a699c4.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/36f5e3ee7f9ffc69262a266a1510d111d79785e103fd4eefe3973bf785fd0d99.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/5105c4770a809b46175616ee57c75361e54476d17c0daeb3d1c8a180f281ba0e.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/8eb6480ba5daa9b8f62a881500f2f28e93ef27bf92a9383bc8f1922e3b08f1f4.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/262dc4ae8a4c33013e99e042ba360d52bbb19f739138ea82be92903c92e731f5.png
c = gf.components.straight_heater_metal(length=100.0)
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/c1db0ea81dd7081e381890ec60e6bce42c024ae3daaf385b276040ab8123fd70.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/a669ce1919fddd963afe46a689fb75c097f4430ecaafa219692cbe34fe70d8dc.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/15fdda21e9f2f5a4e311d2b6f3419fd80bc6d5143ff9472766b6dfbae7ecb348.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/fc2f596cdc86987b61a757925f045f227faf9e2c13fd527dc81af9026da51928.png
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/77e100fe4857568f2aeb52cdd907b6a48fa54705ed0932d01a43b9056f991ab8.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/562241f906730940b7b0f2ae928cc8ae062cb86dff49f9a3c84729a34ca0f6c2.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/392d500d3d08ad0d9442062aac8841548babcbdeeaf9aadc341e30dbfbb3e441.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/74ad8852dec628b8db9626fcc8ebdc4582dcf6fc3ea99ad0f8e57f6a5e9d779b.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-12-09 17:21:13.974 | WARNING  | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?

../_images/60e39f96528bbaf032bb2c45772de40b5476c121fd739f350639a8ad9349f819.png