Source code for gdsfactory.components.splitter_tree

from __future__ import annotations

import numpy as np

import gdsfactory as gf
from gdsfactory.components.bend_s import bend_s as bend_s_function
from gdsfactory.components.mmi1x2 import mmi1x2
from gdsfactory.components.mmi2x2 import mmi2x2
from gdsfactory.typings import ComponentSpec, CrossSectionSpec, Float2


[docs] @gf.cell def splitter_tree( coupler: ComponentSpec = mmi1x2, noutputs: int = 4, spacing: Float2 = (90.0, 50.0), bend_s: ComponentSpec | None = bend_s_function, bend_s_xsize: float | None = None, cross_section: CrossSectionSpec = "xs_sc", ) -> gf.Component: """Tree of power splitters. Args: coupler: coupler factory. noutputs: number of outputs. spacing: x, y spacing between couplers. bend_s: Sbend function for termination. bend_s_xsize: xsize for the sbend. cross_section: cross_section. .. code:: __| __| |__ _| |__ |__ dy dx """ c = gf.Component() dx, dy = spacing coupler = gf.get_component(coupler) coupler_ports_west = coupler.get_ports_list(port_type="optical", orientation=180) coupler_ports_east = coupler.get_ports_list(port_type="optical", orientation=0) e1_port_name = coupler_ports_east[0].name e0_port_name = coupler_ports_east[1].name w0_port_name = coupler_ports_west[0].name if bend_s: dy_coupler_ports = abs( coupler.ports[e0_port_name].center[1] - coupler.ports[e1_port_name].center[1] ) bend_s_ysize = dy / 4 - dy_coupler_ports / 2 bend_s_xsize = bend_s_xsize or dx bend_s = gf.get_component( bend_s, cross_section=cross_section, size=(bend_s_xsize, bend_s_ysize), ) cols = int(np.log2(noutputs)) i = 0 for col in range(cols): ncouplers = int(2**col) y0 = -0.5 * dy * 2 ** (cols - 1) for row in range(ncouplers): x = col * dx y = y0 + (row + 0.5) * dy * 2 ** (cols - col - 1) coupler_ref = c.add_ref(coupler, alias=f"coupler_{col}_{row}") coupler_ref.move((x, y)) if col == 0: for port in coupler_ref.get_ports_list(): if port.name not in [e0_port_name, e1_port_name]: c.add_port(name=f"{port.name}_{col}_{i}", port=port) i += 1 if col > 0: if row % 2 == 0: port_name = e0_port_name if row % 2 == 1: port_name = e1_port_name c.add( gf.routing.get_route( c.named_references[f"coupler_{col-1}_{row//2}"].ports[ port_name ], coupler_ref.ports["o1"], cross_section=cross_section, ).references ) if cols > col > 0: for port in coupler_ref.get_ports_list(): if port.name not in [ "o1", e0_port_name, e1_port_name, w0_port_name, ]: c.add_port(name=f"{port.name}_{col}_{i}", port=port) i += 1 if col == cols - 1 and bend_s is None: for port in coupler_ref.get_ports_list(): if port.name in [e1_port_name, e0_port_name]: c.add_port(name=f"{port.name}_{col}_{i}", port=port) i += 1 if col == cols - 1 and bend_s: btop = c << bend_s bbot = c << bend_s bbot.mirror() btop.connect("o1", coupler_ref.ports[e1_port_name]) bbot.connect("o1", coupler_ref.ports[e0_port_name]) port = btop.ports["o2"] c.add_port(name=f"{port.name}_{col}_{i}", port=port) i += 1 port = bbot.ports["o2"] c.add_port(name=f"{port.name}_{col}_{i}", port=port) i += 1 return c
def test_splitter_tree_ports() -> None: c = splitter_tree( coupler=mmi2x2, noutputs=4, ) assert len(c.ports) == 8, len(c.ports) def test_splitter_tree_ports_no_sbend() -> None: c = splitter_tree( coupler=mmi2x2, noutputs=4, bend_s=None, ) assert len(c.ports) == 8, len(c.ports) if __name__ == "__main__": test_splitter_tree_ports() test_splitter_tree_ports_no_sbend() import gdsfactory as gf # c = splitter_tree( # coupler=partial(mmi2x2, gap_mmi=2.0, width_mmi=5.0), # # noutputs=128 * 2, # # noutputs=2 ** 3, # noutputs=2**2, # # bend_s=None, # # dy=100.0, # # layer=(2, 0), # ) c = splitter_tree( noutputs=2**2, spacing=(120.0, 50.0), # bend_length=30, # bend_s=None, cross_section="xs_rc2", ) c.show(show_ports=True) # print(len(c.ports)) # for port in c.get_ports_list(): # print(port)