route_auto

photonforge.parametric.route_auto(*, port1=None, port2=None, radius=None, obstacles=None, include_port_references_as_obstacles=None, collision_layers=None, collision_offset=None, straight_kwargs=None, s_bend_kwargs=None, bend=None, bend90=None, bend45=None, cross=None, propagation_cost=None, bend_cost=None, bend90_cost=None, bend45_cost=None, cross_cost=None, cross_space_cost=None, congestion_cost=None, congestion_radius=None, allow_diagonals=None, allow_s_bend=None, collapse_s_bends=None, max_crossings=None, grid_size=None, search_margin=None, net_reorder=None, allow_partial=None, max_iterations=None, max_reroute_rounds=None, reroute_history_cost=None, matching=None, show_progress=None, diagnostics=None, technology=None, name=None, route_model=None, bundle_model=None)[source]

Automatic optical routing between reference ports.

The automatic router performs grid-based multi-net routing. Ports must be specified as reference-port tuples so device-aware access preprocessing can use the surrounding component geometry.

Parameters:
  • port1 (tuple[Reference, str] | tuple[Reference, str, int] | Sequence[tuple[Reference, str] | tuple[Reference, str, int]] | None) – First port for single-net routing. The port must be specified as a tuple including a photonforge.Reference, the port name, and the repetition index (optional, only for array references). For bundle routing, a sequence of ports can be used.

  • port2 (tuple[Reference, str] | tuple[Reference, str, int] | Sequence[tuple[Reference, str] | tuple[Reference, str, int]] | None) – Second port for single-net routing, or sequence of ports for bundle routing (with the same length as port1).

  • radius (Annotated[float, exclusiveMinimum=0, units='μm'] | None) – Radius used to generate default bends and S-bend sections.

  • obstacles (Sequence[Rectangle | Circle | Polygon | Path | Component | Reference] | Component | Reference | None) – Additional routing obstacles. Use a sequence of 2D structures, or a Component or Reference.

  • include_port_references_as_obstacles (bool | None) – If True, add the references used by routed ports to obstacles. If None, defaults to True.

  • collision_layers (Sequence[Annotated[str | tuple[int, int], _]] | None) – Layers used for route-section collision stamps and for collecting obstacle polygons from a component or reference. An empty sequence uses all layers. Defaults to routing waveguide layers only.

  • collision_offset (Annotated[float, minimum=0, units='μm'] | None) – Offset applied to route collision layers.

  • straight_kwargs (Annotated[dict[str, Any], _] | None) – Keyword arguments for straight().

  • s_bend_kwargs (Annotated[dict[str, Any], _] | None) – Keyword arguments for s_bend().

  • bend (Component | None) – 90° bend to be used for routing.

  • bend45 (Component | None) – Optional 45° bend to be used for routing. If unset and allow_diagonals is enabled, it is derived from bend when bend is parametric and takes an angle, so the section recipe is shared; otherwise a default 45° bend is built.

  • cross (Component | None) – Optional crossing to be used for routing.

  • propagation_cost (Annotated[float, minimum=0, units='dB/μm'] | None) – Straight section cost (per μm). Defaults to 1e-5.

  • bend_cost (Annotated[float, minimum=0, units='dB'] | None) – Cost of a 90° bend. Defaults to 2.1 * radius * propagation_cost (5% penalty on the Manhattan distance).

  • bend45_cost (Annotated[float, minimum=0, units='dB'] | None) – Cost of a 45° bend. Defaults to 0.51 * bend_cost.

  • cross_cost (Annotated[float, minimum=0, units='dB'] | None) – Cost of a crossing. Defaults to twice the propagation_cost applied to the crossing length.

  • cross_space_cost (Annotated[float, minimum=0, units='dB/μm'] | None) – Cost multiplier for nearby crossing spacing. Defaults to propagation_cost.

  • congestion_cost (Annotated[float, minimum=0, units='dB/μm'] | None) – Cost multiplier for nearby routed occupancy. Defaults to propagation_cost.

  • congestion_radius (Annotated[int, minimum=0] | None) – Congestion search radius in grid cells. Defaults to 1.

  • allow_diagonals (bool | None) – Controls whether 45° bends are allowed. If None, defaults to True when bend45 is provided, and False otherwise.

  • allow_s_bend (bool | None) – Controls whether the router may use S bends to reach an aligned goal directly. Port access for grid alignment use S bends regardless of this flag. If None, defaults to False.

  • collapse_s_bends (bool | None) – Controls post-routing removal of unnecessary access S bends. If None, defaults to True.

  • max_crossings (int | None) – Maximum crossings per net. Use a negative value for no explicit limit. Defaults to -1.

  • grid_size (Annotated[float, exclusiveMinimum=0, units='μm'] | None) – Router grid size. If None, defaults to half the resolved routing radius, snapped to 100 layout grid units. See the important notes below.

  • search_margin (Annotated[float, minimum=0, units='μm'] | None) – Extra search margin around the routing bounds. If None, uses an automatic margin based on endpoint separation and bend size.

  • net_reorder (bool | None) – Allow net reordering before routing. If None, defaults to True.

  • allow_partial (bool | None) – If False, raise when any net fails. If None, defaults to False.

  • max_iterations (int | None) – Maximum search iterations per route. If None, defaults to 500000.

  • max_reroute_rounds (Annotated[int, minimum=0] | None) – Maximum route conflict-recovery rounds. If None, defaults to the number of nets clipped to [3; 16].

  • reroute_history_cost (Annotated[float, minimum=0] | None) – History cost scale used in bundle rerouting. If None, defaults to 5.

  • matching (Sequence[PathLengthMatching] | None) – Path-length matching groups. See notes below.

  • show_progress (bool | None) – If True, show routing progress for long-running routes. If None, defaults to True.

  • diagnostics (bool | None) – If True, JSON-encoded diagnostic information from the routing algorithm is stored in component.properties.route_auto. If None, defaults to False.

  • technology (Technology | None) – Component technology. If None, the default technology is used.

  • name (str | None) – Component name.

  • route_model (Model | None) – Model to be used with each route sub-component. If None a photonforge.CircuitModel is used.

  • bundle_model (Model | None) – Model to be used with the top-level route component. If None a photonforge.CircuitModel is used.

  • bend90 (Annotated[Component | None, _])

  • bend90_cost (Annotated[Annotated[float, minimum=0, units='dB'] | None, _])

Return type:

Component

Important

The grid_size controls the search-space discretization. A smaller size allows routing in tighter spaces but increases execution time. A larger size is faster but may miss routes that a finer grid can find.

For correct collision avoidance, grid_size should be at least the routed waveguide core width. The collision_offset adds separation in whole grid-cell increments, so the center-to-center pitch can be larger than grid_size + collision_offset.

Note

The costs of S bends are based on the computed length multiplied by the propagation cost.

Path-length matching groups are each a PathLengthMatching instance. Net indices follow the port order (an empty nets means every net) and must not repeat across groups. After routing, the (effective) path lengths in each group are equalized by splicing displacement-neutral meanders into the routed nets, or, for ordered dense fans under bends="equal", by rebuilding the group with a uniform 4-bend ride-bus construction. Access regions, endpoints, and nets outside the groups are never modified, and no colliding geometry is ever emitted. One report per group is stored as JSON in component.properties.path_length_matching.

Returns:

Component with emitted route geometry.

Parameters:
  • port1 (tuple[Reference, str] | tuple[Reference, str, int] | Sequence[tuple[Reference, str] | tuple[Reference, str, int]] | None)

  • port2 (tuple[Reference, str] | tuple[Reference, str, int] | Sequence[tuple[Reference, str] | tuple[Reference, str, int]] | None)

  • radius (Annotated[float, exclusiveMinimum=0, units='μm'] | None)

  • obstacles (Sequence[Rectangle | Circle | Polygon | Path | Component | Reference] | Component | Reference | None)

  • include_port_references_as_obstacles (bool | None)

  • collision_layers (Sequence[Annotated[str | tuple[int, int], _]] | None)

  • collision_offset (Annotated[float, minimum=0, units='μm'] | None)

  • straight_kwargs (Annotated[dict[str, Any], _] | None)

  • s_bend_kwargs (Annotated[dict[str, Any], _] | None)

  • bend (Component | None)

  • bend90 (Annotated[Component | None, _])

  • bend45 (Component | None)

  • cross (Component | None)

  • propagation_cost (Annotated[float, minimum=0, units='dB/μm'] | None)

  • bend_cost (Annotated[float, minimum=0, units='dB'] | None)

  • bend90_cost (Annotated[Annotated[float, minimum=0, units='dB'] | None, _])

  • bend45_cost (Annotated[float, minimum=0, units='dB'] | None)

  • cross_cost (Annotated[float, minimum=0, units='dB'] | None)

  • cross_space_cost (Annotated[float, minimum=0, units='dB/μm'] | None)

  • congestion_cost (Annotated[float, minimum=0, units='dB/μm'] | None)

  • congestion_radius (Annotated[int, minimum=0] | None)

  • allow_diagonals (bool | None)

  • allow_s_bend (bool | None)

  • collapse_s_bends (bool | None)

  • max_crossings (int | None)

  • grid_size (Annotated[float, exclusiveMinimum=0, units='μm'] | None)

  • search_margin (Annotated[float, minimum=0, units='μm'] | None)

  • net_reorder (bool | None)

  • allow_partial (bool | None)

  • max_iterations (int | None)

  • max_reroute_rounds (Annotated[int, minimum=0] | None)

  • reroute_history_cost (Annotated[float, minimum=0] | None)

  • matching (Sequence[PathLengthMatching] | None)

  • show_progress (bool | None)

  • diagnostics (bool | None)

  • technology (Technology | None)

  • name (str | None)

  • route_model (Model | None)

  • bundle_model (Model | None)

Return type:

Component

component1 = pf.Component("1")
component1.add("WG_CORE", pf.Rectangle(size=(8, 12)))
component1.add_port(
    [
        pf.Port((4, 0), 180, "Strip"),
        pf.Port((4, 4), 180, "Strip"),
        pf.Port((4, -4), 180, "Strip"),
    ]
)

component2 = pf.Component("2")
component2.add("WG_CORE", pf.Rectangle(size=(12, 4)))
component2.add_port(
    [
        pf.Port((-4, -2), 90, "Strip"),
        pf.Port((4, 2), -90, "Strip"),
        pf.Port((4, -2), 90, "Strip"),
    ]
)

# Example of bundle routing with collision avoidance
routed = pf.Component("ROUTED")
routed.add("METAL", pf.Rectangle((0, -40), (15, 10)))

ref0 = routed.add_reference(component1).translate((-50, -10))
ref1 = routed.add_reference(component2).translate((50, 10))

route = pf.parametric.route_auto(
    port1=[(ref0, "P0"), (ref0, "P1"), (ref0, "P2")],
    port2=[(ref1, "P0"), (ref1, "P1"), (ref1, "P2")],
    obstacles=routed,
    collision_layers=["METAL", "WG_CORE"],
    radius=10,
)
routed.add(route)

# Example using a crossing component
routed_x = pf.Component("ROUTED_CROSSING")
routed_x.add("METAL", pf.Rectangle((0, -40), (15, 10)))

ref0 = routed_x.add_reference(component1).translate((-50, -10))
ref1 = routed_x.add_reference(component2).translate((50, 10))
crossing = pf.parametric.crossing(port_spec="Strip", arm_length=2, added_width=0.5)

route_with_crossing = pf.parametric.route_auto(
    port1=[(ref0, "P0"), (ref0, "P1"), (ref0, "P2")],
    port2=[(ref1, "P0"), (ref1, "P2"), (ref1, "P1")],
    cross=crossing,
    obstacles=routed_x,
    collision_layers=["METAL", "WG_CORE"],
    radius=10,
)
routed_x.add(route_with_crossing)
route_auto