Skip to content

Array Routing

This notebook demonstrates how to route between arrayed instances using doroutes' array indexing support.

Array instances allow placing multiple copies of a component in a grid. Ports on individual elements are accessed with <ia.ib> syntax, where ia is the column index and ib is the row index.

Imports

from functools import partial

import gdsfactory as gf
from gdsfactory.gpdk import get_generic_pdk
from kfactory.kcell import KCell

from doroutes import add_bundle_astar, add_bundle_from_corners
from doroutes.util import expand_port_list, get_port_position

PDK = get_generic_pdk()
PDK.activate()

Create Pad Arrays

We place two rows of pads as array instances. Each row has 3 pads spaced 200 µm apart.

def dies():
    c = gf.Component()
    pad = gf.get_component("pad")

    top = c.add_ref(pad, name="top", columns=3, rows=1, column_pitch=200, row_pitch=0)
    top.dmove((0, 500))

    bot = c.add_ref(pad, name="bot", columns=3, rows=1, column_pitch=200, row_pitch=0)

    for i in range(3):
        c.add_port(f"e{i + 1}", port=top.ports["e4", i, 0])
        c.add_port(f"e{i + 4}", port=bot.ports["e2", i, 0])

    return c

Astar Route

Route from the bottom ports (e4, facing south) of the top pads to the top ports (e2, facing north) of the bottom pads. We use wire_corner as the bend and straight with a metal_routing cross-section.

c = dies()
ports1 = [p for p in c.ports if p.name in ["e1", "e2", "e3"]]
ports2 = [p for p in c.ports if p.name in ["e4", "e5", "e6"]]

add_bundle_astar(
    component=c,
    ports1=ports1,
    ports2=ports2,
    spacing=20,
    bend=partial(gf.get_component, "wire_corner", cross_section="metal_routing"),
    straight=partial(gf.get_component, "straight", cross_section="metal_routing"),
    layers=[(49, 0)],
    grid_unit=2500,
)

c
API key for organization 'DoPlayDo' found.

png

Corners Route

Route the same pad configuration using add_bundle_from_corners with two explicit corner points. The bundle takes a Z-shaped detour: south, then east, then south again.

c = dies()
ports1 = [p for p in c.ports if p.name in ["e1", "e2", "e3"]]
ports2 = [p for p in c.ports if p.name in ["e4", "e5", "e6"]]

inv_dbu = int(1 / c.kcl.dbu)

add_bundle_from_corners(
    component=c,
    ports1=ports1,
    ports2=ports2,
    corners=[(300 * inv_dbu, 250 * inv_dbu), (150 * inv_dbu, 250 * inv_dbu)],
    spacing=20,
    bend=partial(gf.c.wire_corner, cross_section="metal_routing"),
    straight=partial(gf.c.straight, cross_section="metal_routing"),
)

c

png

Steps Route

Instead of providing absolute corner coordinates, you can use steps (relative offsets via dx/dy) to define the route shape. The steps are resolved relative to the centroid of the start ports.

c = dies()
ports1 = [p for p in c.ports if p.name in ["e1", "e2", "e3"]]
ports2 = [p for p in c.ports if p.name in ["e4", "e5", "e6"]]

inv_dbu = int(1 / c.kcl.dbu)

# Steps are relative to the centroid of ports1.
# The first (and last) step may be diagonal to offset the
# fan-in point away from the ports.
add_bundle_from_corners(
    component=c,
    ports1=ports1,
    ports2=ports2,
    steps=[
        {
            "dx": 100 * inv_dbu,
            "dy": -200 * inv_dbu,
        },  # first step may be diagonal to determine fan-in coordinates
        {"dx": -150 * inv_dbu},
    ],
    spacing=20,
    bend=partial(gf.c.wire_corner, cross_section="metal_routing"),
    straight=partial(gf.c.straight, cross_section="metal_routing"),
)

c

png