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/4326ad6e92e1d67f47ee9a176351e6f0ca6b57280d2c48bb8b6dfafe87ad87d2.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/59a430a9cb92b5aacc162a747720013b301152551e803708003dee732057c752.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/59a430a9cb92b5aacc162a747720013b301152551e803708003dee732057c752.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/7de2a408dbf019a36f26c8dc685b510bcf2b1fd21657a5a789a0718e9c51f108.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/4a722435d3ff62a5e79019100afde89e8a8f92ea8355df7910575cdec4bc4a1c.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/48f3f71d39470adfd34be21e31e21865f8772af9e0e7f61e6752c2459986f72e.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/48f3f71d39470adfd34be21e31e21865f8772af9e0e7f61e6752c2459986f72e.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/cc7dc9c335f33d1b599af4db8925cbad9e79bd44ca7e58f0e774da25da2efadd.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/f2162d27a482fbc405a4edec1767ef4125d8b05c3400ab436d78507fef727154.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/a8a8faa08f7d82cc526c24da43eb600b28d8b71a2810f3b5e07a040b99a5536a.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/8146a9065ac99385c6dfef0cfef82bd56f407161e69227da1ec26f7110b2d9c7.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/66db0ba6529acc46a974014c0971676b33fc444d40f1f7460d7d11bcf5079da1.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/bac6d299d804223c556eda9f5bff8b00c1e8aba42d3ff0a3f15b61c9e30962fb.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/0825659bf16c53d1eb142120cf82b814794c61da5a7ee7edecbdf26a22db5ff6.png
c = gf.components.straight_heater_metal(length=100.0)
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/1c09dac6c52fccc84e0739373825f11e73ba39e82101637681403a4c70a56762.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/8b1163016df8c8a3bc488ced1afa0691ffa3c117c40b75ac5e7ba299f9141e5f.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/2697097d5ab53f0ea6d82b2bf379000898a787742aa7a5a9ae7fe657f61442b8.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/1c22eb5b6ce8d56cd581f7b2e90cb7c4eeb8e2007073c43a068f234df2ca0397.png
cc = gf.routing.add_pads_top(component=c)
cc.plot()

../_images/f3633438ace56cef5de31d60488c84773eba32818b673a295f2c63ff11f27789.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/3a7779385b8cc21f9816b47fdb02b74723e3d0bb10c44e738ff66aa3d7ee4a49.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/8f416759971a4179d9cf8bdc3a83bbf8c1b3dd76c18c320958198b90e6a7a5c0.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/f9ba245b116573f65d4d0e8c76f2ce7c9b2a4c5cfea0c8484a7ffb4a05c4eb71.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-04-27 01:05:20.468 | WARNING  | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?

../_images/32edda295efcd343443c73ee8e6534be5ecae1a2d616a07feb4df10f00f61111.png