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.

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

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
