Skip to content

Changelog

Unreleased

Added

  • route_batch(enforce_endpoint_dirs=True) makes cardinal endpoint directions hard constraints: each route leaves its start along start_dir and arrives at its stop travelling stop_dir, the inverse of the stop port's outward normal. A route whose first or last step is blocked is not routed. Off by default, where the directions only label the result, so existing callers route as before.

1.5.0 — 2026-09-28

Added

  • Edge-midpoint port access for multilayer routing (RoutingConfig.port_access="edge", the new default): a route terminates just outside the port metal on the port normal, enters through the port's edge midpoint perpendicular to that edge, and abuts the port polygon flush (port_entry_depth_um, default 0). Every port polygon — pads included — is now a hard obstacle for every other net, so no net routes through another net's pad. port_access="center" restores the previous polygon-centre terminals.
  • A minimum straight run out of every port (RoutingConfig.port_access_straight_um, default three router grid units): the route leaves or enters a port along the port normal for that distance before it may turn or via, and the part of the run beyond clearance + wire/2 is reserved as an obstacle on every routing layer so no other net can sit on the port axis in front of the port.
  • Route+draw passes in the batch router (BatchRoutingParams.reroute_passes, default 6, stopping early when a pass makes no progress): nets whose planned geometry cannot be drawn are re-routed with all metal drawn so far as hard obstacles; a net the router cannot reach at all has the nets walling in its terminal ripped up (at most twice each) and re-routed with it; nets that failed in an earlier pass are drawn first in the next one.
  • Path passes for edge access: layer transitions the router reports at two XYs are rebuilt on the run's axis; a terminal run that sits up to two grid cells beside the port axis is slid onto it (or, when its far-end via cannot move, the jog is placed at the first clear row from the far end); every candidate is validated at draw time and the router's own path, with only metal-preserving cleanups, is the last fallback.
  • make_pin(component, name=..., port=...) designates a top-level pin: the port is promoted to the parent and the physical polygon it sits on becomes a virtual obstacle on every configured routing metal for all other nets, without drawing any metal. Search, draw-time validation and port fills honour it.

Changed

  • The corner-path cleanup pipeline both multilayer engines run (via-pair normalisation, jog coalescing, detour and staircase collapses, endpoint anchoring) lives in doroutes.multilayer.cleanup.PathCleanup; the serial engine no longer carries its own copy.
  • Route cells place their a/b endpoint ports exactly on the device ports they connect to (opposite orientation, same layer and width), so get_netlist() and elvis see the connection by abutment; endpoints are marked on the (layer, 16) pin datatype and no longer drawn as kfactory port triangles on the metal layer.
  • The batch router is told the drawn wire width: obstacle rasterisation uses the wire half-width in fixed-width mode too, and layer spacing/width handed to the DRT include the wire width, so two wires wider than the grid no longer land on adjacent cells.
  • Draw-time obstacle validation decomposes merged L/T-shaped obstacles into rectangles instead of using one bounding box per shape, which no longer fences off the empty corners next to a pad and its feed wire; it also sees other nets' reserved approaches, so a cleaned-up path cannot be drawn where the router was not allowed to go.
  • The router grid is aligned with the terminals (most common residue, stop terminals first), so a route leaves a port on the port axis instead of one half-cell beside it.
  • _coalesce_via_jogs absorbs jogs up to one grid unit (was: strictly shorter), moves a via off a terminal instead of skipping it, and never drags a via onto a terminal; _collapse_same_layer_staircases leaves a staircase that ends on the stop axis alone under edge access; a diagonal drawn next to a port bends away from the port.
  • A* routing (find_route_astar, add_route_astar, add_bundle_astar) no longer re-verifies the API key over the network on every call. A successful check is reused for 10 minutes per process, so repeated routes no longer wait about a second each, and the "API key … found." message is printed once instead of on every route. A missing or rejected key is still reported immediately

Fixed

  • Multilayer routes to pads no longer produce non-Manhattan metal wedges, sub-min-width slivers, or spacing violations at the pad boundary, and no longer short neighbouring pads on the pad layer.
  • Path-length matching no longer draws loops outside their segment. loop_side="center" is capacity-checked against its real footprint of (4·loops + 6)·br (it could extend past a short segment's ports), and loop_position="end" with element=0 no longer overruns the corner. Every spliced loop is checked to lie inside its segment before any route is re-placed
  • Path-length matching refuses routes that contain cells other than the given straight/bend (for example a bend of another radius or a straight of another width), which re-placement used to swap silently. Base bend counts are taken from the placed cells, not from n_bend90 metadata
  • element now stays on the intended segment when a +2-bend corner overshoot is inserted before it; such requests used to be refused with a misleading "segment too short" error
  • loop_longest=False with an absolute target below an existing route's length now raises before any route is modified, instead of after re-placing the others
  • The +2-bend overshoot error states the outgoing-segment length it needs, instead of suggesting ng= or loops
  • Reusing a PathLengthMatch instance no longer carries the previous call's target or tolerance into the next call

1.3.0 — 2026-08-10

Added

  • Path-length matching for Route objects through match_path_lengths and the PathLengthMatch constraint model, including exact placed-length matching, group-index weighting, loop and grouped methods, absolute targets, bend-count equalisation, and in-place route updates
  • A Path-Length Matching tutorial notebook and published documentation page
  • Static, dynamic, and fullscreen modes for the notebook GDS viewer

Changed

  • Upgraded the kfactory requirement to 3.0 or newer and adopted its native path-length target API
  • Migrated the documentation site to Zensical, reorganised reference navigation, and retained GitHub Pages as the deployment target
  • Updated gdsfactory-facing notebooks to use move and rotate while retaining dmove and drotate in library code for kfactory Instance compatibility
  • Updated release and documentation workflow dependencies

Fixed

  • Corrected notebook discovery so the papermill test suite executes notebooks from the repository
  • Converted Python snippets in the S-Bend MMI tutorial from Markdown to executable code cells

1.2.0 — 2026-07-08

Added

  • TraceRoute.port1_index / port2_index map each trace back to the caller's ports1 / ports2 lists; traces are ordered by lateral bundle slot, not input order, so use these indices to correlate results
  • doroutes.util.segments_length_um / doroutes.util.cell_length_um — route lengths are the sum of placed cells' info["length"]; cells lacking it raise ValueError
  • Composite bundle pcells (pcells.straights / pcells.bends) record info["wire_lengths"] (per-wire sums of their inner cells' info["length"]) and info["length"] (exact total over all wires)
  • Route objects: routing functions return a doroutes.Route (pydantic model, field-compatible with kfactory's ManhattanRoute for future backend integration, generalized for sbends and coordinate endpoints). It carries the wire's placed instances port-to-port (start→end), start_port/end_port, dbu backbone, n_bend90/bend90_radius/length_straights, and length (µm) via a pluggable length_function defaulting to the exact cell-info sum. corners, path_length, iteration and len() remain as backward-compatible properties; TraceRoute is a deprecated alias
  • FanLeg.instances / FanLeg.n_bend90 — each fan leg carries its placed cells in start→end order

Changed

  • Breaking: add_fan_in now returns (stops, legs) instead of just the stops array — legs is the per-wire FanLeg detail (polyline, exact length, original input index, placed instances). Existing callers should unpack: stops, _ = add_fan_in(...)
  • GDS hierarchy is unchanged from 1.1.0: bundle bodies stay composite straights_*/bends_* segment cells and fan legs stay flat. Per-wire identity lives in the returned Route objects (instances lists the leg cells plus the shared composite segments); bundle traces use a sliced length_function that reads the wire's own wire_lengths entry per composite segment — still exact sums of cells, no geometry
  • Old-style TraceRoute(corners=..., path_length=...) construction now raises a pydantic.ValidationError (the fields became read-only properties of Route)
  • add_route_astar and add_route_manual now return TraceRoute instead of a bare list of corner points; iteration (for pt in result) and len() keep working, but isinstance(result, list) checks and list concatenation do not — use result.corners for those
  • TraceRoute.path_length, bundle per-trace lengths, and FanLeg.length_um are now the exact sum of the placed cells' info["length"] (correct for euler bends; previously approximated geometrically from the corner polyline)
  • Bundle traces (BundleResult.traces) now span port-to-port including the fan-in/fan-out legs, with exact lengths for the manhattan, sbend, and lbend fan strategies

1.1.0 — 2026-06-04

Added

  • Public add_route_from_corners_dbu API for routing in database units
  • Backwards-compatible support for passing lengths in both microns and dbu

1.0.0 — 2026-05-26

Changed

  • Breaking: standardized public API — routing and bundle functions use micron parameters, always return corners, and follow consistent naming
  • FanStrategy TypedDict replaces loose keyword arguments for fan-in/fan-out configuration
  • Deprecation wrappers added for all renamed/removed parameters — old call sites emit warnings instead of breaking

0.6.1 — 2026-05-21

Fixed

  • Use round() instead of int() for um-to-dbu corner conversion to avoid float truncation

0.6.0 — 2026-05-08

Added

  • return_corners kwarg on routing and bundle functions
  • A* clearance parameter for obstacle margin control
  • Separate fan-in / fan-out strategy support
  • Steps routing in microns
  • Bundle fan-in anchor control with validation
  • Fan-in strategy on add_bundle_from_corners
  • Generic PDK in notebooks, replacing cspdk
  • Configurable leading-straight on manhattan fan-in
  • Switch tree pad routing example
  • lbend and sbend fan-in demos
  • Python 3.11+ support

Fixed

  • L-bend wire clearance
  • Collapse collinear corners so consecutive same-axis steps don't insert fake bends
  • Sbend fan-in radius calculation rewritten as per-wire angle euler s-bend
  • Remove PDK.activate() calls and cspdk dependency

Changed

  • Corners routing parameter switched from dbu to microns
  • Split bundle_from_corners + manual dispatchers, unified component param name
  • Upgraded gdsfactory to 9.40.2

0.5.0 — 2026-03-27

Added

  • 3D multilayer routing subpackage
  • 1x16 optical switch with electrical routing example
  • Interactive KLayout GDS viewer for stress test results

Fixed

  • Reduced routing runtime with coarser grid and tighter margin

0.4.0 — 2026-02-22

Added

  • add_bundle_from_corners for explicit corner-based bundle routing
  • Array indexing support for instance port references
  • Array routing example notebook

0.3.1 — 2026-01-07

Added

  • Python 3.14 support

Fixed

  • Fix tests and notebooks compatibility

0.3.0 — 2025-11-25

Fixed

  • kfactory 2.0 compatibility

0.2.6 — 2025-11-25

Fixed

  • Pin kfactory dependency version

0.2.4 — 2025-09-01

Fixed

  • Increase bounding box search area for route finding

0.2.3 — 2025-05-13

Added

  • Ubuntu ARM release builds

0.2.2 — 2025-05-13

Added

  • Native ARM builds without emulation

0.2.1 — 2025-05-13

Added

  • ARM64 Linux release builds

0.2.0 — 2025-03-09

Fixed

  • Graceful error handling instead of panicking when no route found
  • API key verification error handling

0.1.0 — 2025-03-04

Added

  • Documentation site
  • kfactory-only routing backend
  • Bundle routing support
  • A* routing function

0.0.1 — 2025-02-14

Added

  • Initial release
  • Corner-based and step-based routing
  • A* pathfinding with obstacle avoidance
  • Bundle routing with fan-in/fan-out
  • Circuit from YAML netlist
  • Discretization for field-based routing