"""Routes bundles of ports (river routing)."""
from __future__ import annotations
from collections.abc import Callable
import gdsfactory as gf
from gdsfactory.components.bend_euler import bend_euler
from gdsfactory.components.straight import straight as _straight
from gdsfactory.components.taper import taper as taper_function
from gdsfactory.cross_section import strip
from gdsfactory.port import Port
from gdsfactory.routing.get_bundle import (
_get_bundle_waypoints,
compute_ports_max_displacement,
)
from gdsfactory.routing.get_route import get_route_from_waypoints
from gdsfactory.routing.path_length_matching import path_length_matched_points
from gdsfactory.routing.sort_ports import sort_ports as sort_ports_function
from gdsfactory.typings import (
ComponentSpec,
CrossSectionSpec,
MultiCrossSectionAngleSpec,
Route,
)
[docs]
def get_bundle_path_length_match(
ports1: list[Port],
ports2: list[Port],
separation: float = 30.0,
end_straight_length: float | None = None,
extra_length: float = 0.0,
nb_loops: int = 1,
modify_segment_i: int = -2,
bend: ComponentSpec = bend_euler,
straight: ComponentSpec = _straight,
taper: ComponentSpec | None = taper_function,
start_straight_length: float = 0.0,
route_filter: Callable = get_route_from_waypoints,
sort_ports: bool = True,
cross_section: CrossSectionSpec | MultiCrossSectionAngleSpec = strip,
enforce_port_ordering: bool = True,
**kwargs,
) -> list[Route]:
"""Returns list of routes that are path length matched.
Args:
ports1: list of ports.
ports2: list of ports.
separation: between the loops.
end_straight_length: if None tries to determine it.
extra_length: distance added to all path length compensation. Useful is we want to add space for extra taper on all branches.
nb_loops: number of extra loops added in the path.
modify_segment_i: index of the segment that accommodates the new turns default is next to last segment.
bend: for bends.
straight: for straights.
taper: spec.
start_straight_length: in um.
route_filter: get_route_from_waypoints.
sort_ports: sorts ports before routing.
cross_section: factory.
kwargs: cross_section settings.
Tips:
- If path length matches the wrong segments, change `modify_segment_i` arguments.
- Adjust `nb_loops` to avoid too short or too long segments
- Adjust `separation` and `end_straight_offset` to avoid compensation collisions
.. plot::
:include-source:
import gdsfactory as gf
c = gf.Component("path_length_match_sample")
dy = 2000.0
xs1 = [-500, -300, -100, -90, -80, -55, -35, 200, 210, 240, 500, 650]
pitch = 100.0
N = len(xs1)
xs2 = [-20 + i * pitch for i in range(N)]
a1 = 90
a2 = a1 + 180
ports1 = [gf.Port(name=f"top_{i}", center=(xs1[i], +0), width=0.5, orientation=a1, layer="WG") for i in range(N)]
ports2 = [gf.Port(name=f"bot_{i}", center=(xs2[i], dy), width=0.5, orientation=a2, layer="WG") for i in range(N)]
routes = gf.routing.get_bundle_path_length_match(ports1, ports2, extra_length=44)
for route in routes:
c.add(route.references)
gf.config.set_plot_options(show_subports=False)
c.plot()
"""
extra_length /= 2
cross_section = gf.get_cross_section(cross_section)
cross_section = cross_section.copy(**kwargs)
# Heuristic to get a correct default end_straight_offset to leave
# enough space for path-length compensation
if sort_ports:
ports1, ports2 = sort_ports_function(
ports1, ports2, enforce_port_ordering=enforce_port_ordering
)
if end_straight_length is None:
if modify_segment_i == -2:
end_straight_length = (
compute_ports_max_displacement(ports1, ports2) / (2 * nb_loops)
+ separation
+ extra_length
)
else:
end_straight_length = 0
list_of_waypoints = _get_bundle_waypoints(
ports1=ports1,
ports2=ports2,
separation=separation,
end_straight_length=end_straight_length,
start_straight_length=start_straight_length,
cross_section=cross_section,
)
list_of_waypoints = path_length_matched_points(
list_of_waypoints,
extra_length=extra_length,
bend=bend,
nb_loops=nb_loops,
modify_segment_i=modify_segment_i,
cross_section=cross_section,
)
return [
route_filter(
waypoints,
bend=bend,
straight=straight,
taper=taper,
cross_section=cross_section,
)
for waypoints in list_of_waypoints
]
if __name__ == "__main__":
c = gf.Component()
c1 = c << gf.components.straight_array(spacing=50)
c2 = c << gf.components.straight_array(spacing=5)
c2.movex(200)
c1.y = 0
c2.y = 0
routes = gf.routing.get_bundle_path_length_match(
c1.get_ports_list(orientation=0),
c2.get_ports_list(orientation=180),
end_straight_length=0,
start_straight_length=0,
separation=50,
# layer=(2, 0),
)
for route in routes:
c.add(route.references)
c.show(show_ports=True)