from __future__ import annotations
import gdsfactory as gf
from gdsfactory.cell import cell
from gdsfactory.component import Component
from gdsfactory.port import port_array
from gdsfactory.routing.get_route_sbend import get_route_sbend
from gdsfactory.routing.sort_ports import sort_ports as sort_ports_function
from gdsfactory.routing.utils import direction_ports_from_list_ports, flip
from gdsfactory.typings import ComponentSpec
[docs]
@cell
def fanout_component(
component: ComponentSpec,
port_names: tuple[str, ...],
pitch: tuple[float, float] = (0.0, 20.0),
dx: float = 20.0,
sort_ports: bool = True,
auto_rename_ports: bool = True,
enforce_port_ordering: bool = False,
**kwargs,
) -> Component:
"""Returns component with Sbend fanout routes.
Args:
component: to fanout ports.
port_names: list of port names.
pitch: target port spacing for new component.
dx: how far the fanout in x direction.
sort_ports: sort ports.
auto_rename_ports: auto_rename_ports.
enforce_port_ordering: enforce_port_ordering. False by default.
kwargs: for get_route_sbend.
.. plot::
:include-source:
import gdsfactory as gf
c = gf.components.mmi2x2()
cc = gf.routing.fanout_component(
component=c, port_names=tuple(c.get_ports_dict(orientation=0).keys())
)
cc.plot()
"""
c = Component()
comp = gf.get_component(component)
ref = c.add_ref(comp)
ref.movey(-comp.y)
for port_name in port_names:
if port_name not in ref.ports:
raise ValueError(f"{port_name} not in {list(ref.ports.keys())}")
ports1 = [p for p in ref.ports.values() if p.name in port_names]
port = ports1[0]
port_extended_x = port.get_extended_center(dx)[0]
port_settings = port.to_dict().copy()
port_settings.pop("name")
port_settings.update(center=(port_extended_x, 0))
port_settings.update(orientation=(port.orientation + 180) % 360)
ports2 = port_array(n=len(ports1), pitch=pitch, **port_settings)
if sort_ports:
ports1, ports2 = sort_ports_function(
ports1, ports2, enforce_port_ordering=enforce_port_ordering
)
for i, (p1, p2) in enumerate(zip(ports1, ports2)):
route = get_route_sbend(port1=p1, port2=p2, **kwargs)
c.add(route.references)
c.add_port(f"new_{i}", port=flip(p2))
for port in ref.ports.values():
if port.name not in port_names:
c.add_port(port.name, port=port)
if auto_rename_ports:
c.auto_rename_ports()
return c
[docs]
def fanout_ports(
ports: list[gf.Port],
pitch: tuple[float, float] = (0.0, 20.0),
dx: float = 20.0,
**kwargs,
) -> list[gf.typings.Route]:
"""Returns fanout Sbend routes.
Args:
ports: list of ports.
pitch: target port spacing for new component.
dx: how far the fanout.
kwargs: for route_basic.
"""
routes = []
ports1 = ports
port = ports1[0]
port_extended_x = port.get_extended_center(dx)[0]
port_settings = port.to_dict().copy()
port_settings.pop("name")
port_settings.update(center=(port_extended_x, 0))
port_settings.update(orientation=(port.orientation + 180) % 360)
ports2 = port_array(n=len(ports1), pitch=pitch, **port_settings)
for p1, p2 in zip(ports1, ports2):
route = gf.routing.get_route_sbend(p1, p2)
routes.append(route)
return routes
def test_fanout_ports() -> None:
c = gf.components.mmi2x2()
ports = c.get_ports_dict(orientation=0)
port_names = list(ports.keys())
c2 = fanout_component(component=c, port_names=port_names)
d = direction_ports_from_list_ports(c2.get_ports_list())
assert len(d["E"]) == 2, len(d["E"]) == 2
assert len(d["W"]) == 2, len(d["W"]) == 2
if __name__ == "__main__":
# test_fanout_ports()
# c =gf.components.coupler(gap=1.0)
# c = gf.components.nxn(west=4)
# c = gf.components.nxn(west=4, layer=(3, 0))
c = gf.components.mmi2x2()
cc = fanout_component(
component=c, port_names=tuple(c.get_ports_dict(orientation=0).keys())
)
print(len(cc.ports))
cc.show(show_ports=True)
# c = gf.components.nxn(west=4, layer=(3, 0))
# routes = fanout_ports(ports=c.get_ports_list(orientation=180))
# for route in routes:
# c.add(route.references)
# c.show(show_ports=True)
# print(cc.ports.keys())