Path-Length Matching
Path-length matching equalises the optical path lengths of a group of routes by splicing squiggle loops into the shorter routes until all routes are equally long.
DoRoutes matches exact placed lengths — the sum of every straight and bend
cell's info["length"] along a route — rather than backbone scalar
approximations. That matters because routes with different bend counts but
identical backbone extents are not the same length: bend arclengths differ
from the corner-to-corner straight they replace. DoRoutes also supports
group-index–weighted optical lengths for PDKs where bends and straights
of different widths have different group indices, so that matching can equalise
group delay rather than geometric length.
The implementation reuses kfactory's loop-insertion geometry via an adapter
layer, then rips and re-places each route's cells along the updated backbone.
All mutations happen in place so caller-held Route references stay valid.
Imports
import gdsfactory as gf
from gdsfactory.gpdk import PDK
import gdsfactoryplus as gfp
dr = gfp.routing.doroutes
from gdsfactoryplus.routing.doroutes.pathlength import LoopPosition, LoopSide
PDK.activate()
STRAIGHT = "straight"
BEND = {"component": "bend_euler", "settings": {"radius": 5}}
Baseline — unmatched routes
We start with two U-shaped Manhattan routes that share the same start-x and
stop-x and the same number of interior corners (4 bends each), but take
different-depth detours south so their total lengths differ by 30 µm.
r1 dips 25 µm below y = 0; r2 dips 40 µm below y = −60 µm.
Coordinates: start/stop are (x, y) tuples in database units
(1 dbu = 1 nm for gdsfactory.gpdk, so 100 µm = 100 000 dbu).
corners are (x, y) floats in microns.
c_base = gf.Component()
r1_base = dr.add_route_manual(
c_base,
(0, 0),
(100_000, 0),
corners=[(30.0, 0.0), (30.0, -25.0), (60.0, -25.0), (60.0, 0.0)],
straight=STRAIGHT,
bend=BEND,
)
r2_base = dr.add_route_manual(
c_base,
(0, -60_000),
(100_000, -60_000),
corners=[(30.0, -60.0), (30.0, -100.0), (60.0, -100.0), (60.0, -60.0)],
straight=STRAIGHT,
bend=BEND,
)
print(f"r1 length: {r1_base.length:.3f} µm (n_bend90={r1_base.n_bend90})")
print(f"r2 length: {r2_base.length:.3f} µm (n_bend90={r2_base.n_bend90})")
print(f"Δ = {abs(r1_base.length - r2_base.length):.3f} µm — unmatched")
dr.util.show_cell(c_base)
r1 length: 143.272 µm (n_bend90=4)
r2 length: 173.272 µm (n_bend90=4)
Δ = 30.000 µm — unmatched