add_bundle_astar routes N parallel waveguides as a single bundle
between two port arrays, letting A* find a path that avoids
obstacles while keeping the bundle intact. It ties three pieces
together:
- a fan-in that converges the source ports onto a tight bundle line,
- an A* search that routes the bundle as a single thick wire
while avoiding the listed obstacle
layers, - a fan-out that re-spreads the bundle onto the destination ports.
Reach for it when you have N input ports and N output ports, you want them routed together as a unit (matched bend and length), and the exact shape of the path doesn't matter as long as it avoids obstacles.
Two helper layouts in dr.pcells cover the two common cases:
fanout_frame2— input and output sides face along the same axis (heretransition="ew": inputs east-facing, outputs west-facing).fanout_frame3— input and output sides are rotated 90° relative to each other, so the bundle has to make a corner.
This is optical routing: bends are bend_euler at the PDK
minimum radius (5 µm for cspdk.si220.cband). The bundle's
effective radius scales with the port count
(single_radius + (N-1)*spacing/2), so wide bundles need more
clearance to make a turn.
Imports
In-Line Bundle with Obstacles
fanout_frame2(transition="ew") puts inputs on the west edge and
outputs on the east edge of the frame. We drop two MMIs into the
routing channel as obstacles — the A* path has to weave around them
while keeping the bundle intact.
c = gf.Component()
ref = c << dr.pcells.fanout_frame2(transition="ew", add_frame=True)
c.add_ports(ref)
# Drop two MMIs into the routing channel as obstacles.
r = c << gf.components.mmi()
r.dmove((40, 120))
r = c << gf.components.mmi()
r.drotate(90)
r.dmove((60, 40))
dr.add_bundle_astar(
component=c,
ports1=[p for p in c.ports if str(p.name).startswith("in")],
ports2=[p for p in c.ports if str(p.name).startswith("out")],
spacing=1.0,
straight="straight",
bend={"component": "bend_euler", "settings": {"radius": 5}},
layers=["WG"],
)
dr.util.show_cell(c)
API key for organization 'DoPlayDo' found.
Bundle Around a 90° Corner
fanout_frame3 rotates the output side by 90°, so the bundle's start
and end orientations are perpendicular. The A* search has to turn
the bundle through a corner — and the bundle's effective radius (set
by port count and spacing) determines how much room that corner needs.
c = gf.Component()
ref = c << dr.pcells.fanout_frame3(transition="ew")
c.add_ports(ref)
dr.add_bundle_astar(
component=c,
ports1=[p for p in c.ports if str(p.name).startswith("in")],
ports2=[p for p in c.ports if str(p.name).startswith("out")],
spacing=1.0,
straight="straight",
bend={"component": "bend_euler", "settings": {"radius": 5}},
layers=["WG"],
)
dr.util.show_cell(c)
API key for organization 'DoPlayDo' found.
Next steps
- The fan-in stage has three strategies — see Fan-In for when to use each.
- Compare bundle strategies side-by-side on a shared topology in Bundle Routing Comparison.
- Drive bundle routing from a YAML netlist in Circuit From Netlist.