Example #1
0
def text_rectangular_multi_layer(
    text: str = "abcd",
    layers: Layers = (LAYER.WG, LAYER.M1, LAYER.M2, LAYER.M3),
    text_factory: ComponentFactory = text_rectangular,
    **kwargs,
) -> Component:
    """Returns rectangular text in different layers

    Args:
        text: string of text
        layers: list of layers to replicate the text
        text_factory: function to create the text Components

    Keyword Args:
        size: pixel size
        position: coordinate
        justify: left, right or center
        font: function that returns dictionary of characters
    """
    func = gf.partial(
        copy_layers,
        factory=gf.partial(text_factory, text=text, **kwargs),
        layers=layers,
    )
    return func()
def test_partial_function():
    mmi400 = gf.partial(gf.components.mmi1x2, width=0.4)
    mmi600 = gf.partial(gf.components.mmi1x2, width=0.6)
    mzi400 = gf.partial(gf.components.mzi, splitter=mmi400)
    mzi600 = gf.partial(gf.components.mzi, splitter=mmi600)
    c400 = mzi400()
    c600 = mzi600()
    assert c600.name != c400.name, print(c400.name, c600.name)
def test_compose1():
    """Ensures the first level of composed function gets a unique name"""
    mzi500 = gf.partial(gf.components.mzi, straight=straigth_extended1)
    mzi900 = gf.partial(gf.components.mzi, straight=straigth_extended2)

    c500 = mzi500()
    c900 = mzi900()

    assert c900.name != c500.name, f"{c500.name} must be different from {c900.name}"
def test_partial_function_without_kwargs():
    r1 = gf.partial(gf.c.rectangle, size=(4, 2))
    r2 = gf.partial(gf.c.rectangle, size=(4, 2))
    r3 = gf.partial(gf.c.rectangle, (4, 2))

    c1 = r1()
    c2 = r2()
    c3 = r3()

    assert c1.name == c2.name == c3.name, f"{c1.name} == {c2.name} == {c3.name}"
Example #5
0
def test_compose2():
    """Ensures the second level of composed function gets a unique name.

    FIXME! this one does not work

    """
    mzi500 = gf.partial(gf.components.mzi, straight=straigth_extended3)
    mzi900 = gf.partial(gf.components.mzi, straight=straigth_extended2)

    c500 = mzi500()
    c900 = mzi900()

    assert c900.name != c500.name, f"{c500.name} must be different from {c900.name}"
def _demo():
    c = gf.Component("get_route_from_steps_sample")

    w = gf.components.array(
        gf.partial(gf.c.straight, layer=(2, 0)),
        rows=3,
        columns=1,
        spacing=(0, 50),
    )

    left = c << w
    right = c << w
    right.move((200, 100))
    p1 = left.get_ports_list(orientation=0)
    p2 = right.get_ports_list(orientation=180)

    routes = get_bundle_from_steps_electrical(
        p1,
        p2,
        steps=[{
            "x": 150
        }],
    )

    for route in routes:
        c.add(route.references)

    c.show()
def test_get_bundle_udirect(
    data_regression: DataRegressionFixture, check: bool = True
) -> Component:

    c = gf.Component("test_get_bundle_udirect")

    pad = gf.partial(gf.c.pad, size=(10, 10))
    pad_south = gf.components.pad_array(orientation=270, spacing=(15.0, 0), pad=pad)
    pt = c << pad_south
    pb = c << pad_south
    pb.rotate(90)
    pt.rotate(90)
    pb.move((0, -100))

    pbports = pb.get_ports_list()
    ptports = pt.get_ports_list()

    pbports.reverse()

    routes = gf.routing.get_bundle(pbports, ptports, radius=5)

    lengths = {}
    for i, route in enumerate(routes):
        c.add(route.references)
        lengths[i] = route.length

    if check:
        data_regression.check(lengths)
    return c
def test_partial_function_with_kwargs():
    mmi400 = gf.partial(gf.components.mmi1x2, width=0.4)
    mmi400_args = gf.partial(gf.components.mmi1x2, 0.4)
    mmi600 = gf.partial(gf.components.mmi1x2, width=0.6)
    mzi400 = gf.partial(gf.components.mzi, splitter=mmi400)
    mzi600 = gf.partial(gf.components.mzi, splitter=mmi600)

    c400 = mzi400()
    c600 = mzi600()

    assert c600.name != c400.name, f"{c600.name} must be different from {c400.name}"

    cmmi400 = mmi400()
    cmmi400_args = mmi400_args()
    assert (cmmi400_args.name == cmmi400.name
            ), f"{cmmi400_args.name} must be equal to {cmmi400.name}"
Example #9
0
def test_route_error_bundle():
    """Ensures that an impossible route raises value Error"""
    c = gf.Component("get_route_from_steps_sample")

    w = gf.components.array(
        gf.partial(gf.c.straight, layer=(2, 0)),
        rows=3,
        columns=1,
        spacing=(0, 50),
    )

    left = c << w
    right = c << w
    right.move((200, 100))
    p1 = left.get_ports_list(orientation=0)
    p2 = right.get_ports_list(orientation=180)

    with pytest.warns(RouteWarning):
        routes = gf.routing.get_bundle_from_steps(
            p1,
            p2,
            steps=[{
                "x": 300
            }, {
                "x": 301
            }],
        )

    for route in routes:
        c.add(route.references)
    return c
def test_get_bundle_west_to_north(
    data_regression: DataRegressionFixture, check: bool = True
) -> Component:

    lengths = {}

    c = gf.Component("test_get_bundle_west_to_north")
    pad = gf.partial(gf.c.pad, size=(10, 10))
    c = gf.Component()
    pad_south = gf.components.pad_array(orientation=270, spacing=(15.0, 0.0), pad=pad)
    pad_north = gf.components.pad_array(orientation=90, spacing=(15.0, 0.0), pad=pad)
    pl = c << pad_south
    pb = c << pad_north
    pl.rotate(90)
    pb.move((100, -100))

    pbports = pb.get_ports_list()
    ptports = pl.get_ports_list()

    c.add_ports(pbports, prefix="N")
    c.add_ports(ptports, prefix="S")

    routes = gf.routing.get_bundle(
        pbports,
        ptports,
        bend=gf.components.wire_corner,
    )
    for i, route in enumerate(routes):
        c.add(route.references)
        lengths[i] = route.length

    if check:
        data_regression.check(lengths)
    return c
Example #11
0
def find_coupling(gap: float = 0.2,
                  mode_solver: ModeSolverFactory = get_mode_solver_coupler,
                  find_modes: Callable = find_modes_function,
                  power_ratio: float = 1.0,
                  wavelength: float = 1.55,
                  **kwargs) -> float:
    """
    Returns the coupling length (um) of the directional coupler
    to achieve power_ratio

    Args:
        gap: in um
        mode_solver: function to get the mode solver
        find_modes: function to find the modes
        power_ratio: p2/p1, where 1 means 100% power transfer
        wavelength: in um

    keyword Args:
        nmodes: number of modes
        parity: for symmetries
    """
    modes = find_modes(mode_solver=gf.partial(mode_solver, gaps=(gap, )),
                       wavelength=wavelength,
                       **kwargs)
    ne = modes[1].neff
    no = modes[2].neff

    return coupling_length(neff1=ne,
                           neff2=no,
                           power_ratio=power_ratio,
                           wavelength=wavelength)
Example #12
0
def test_extend_ports() -> Component:
    import gdsfactory as gf
    import gdsfactory.components as pc

    width = 0.5
    xs_strip = gf.partial(gf.cross_section.strip, width=width)

    c = pc.cross(width=width, port_type="optical")

    c1 = extend_ports(component=c, cross_section=xs_strip)
    assert len(c.ports) == len(c1.ports)
    p = len(c1.polygons)
    assert p == 4, p

    c2 = extend_ports(component=c, cross_section=xs_strip, port_names=("o1", "o2"))
    p = len(c2.polygons)
    assert p == 2, p

    c3 = extend_ports(component=c, cross_section=xs_strip)
    p = len(c3.polygons)
    assert p == 4, p

    c4 = extend_ports(gf.c.cross(port_type="optical"))
    p = len(c4.polygons)
    assert p == 4, p

    return c4
Example #13
0
def find_coupling_vs_gap(
        gap1: float = 0.2,
        gap2: float = 0.4,
        steps: int = 12,
        mode_solver: ModeSolverFactory = get_mode_solver_coupler,
        find_modes: Callable = find_modes_function,
        nmodes: int = 4,
        wavelength: float = 1.55,
        parity=mp.NO_PARITY,
        filepath: Optional[PathType] = None,
        overwrite: bool = False,
        **kwargs) -> pd.DataFrame:
    """
    Returns coupling vs gap

    Args:
        gap1:
        gap2:
        steps:
        mode_solver:
        find_modes:
        nmodes:
        wavelength:
        parity:
        filepath:
        overwrite:
    """
    if filepath and not overwrite and pathlib.Path(filepath).exists():
        return pd.read_csv(filepath)

    gaps = np.linspace(gap1, gap2, steps)
    ne = []
    no = []
    gap_to_modes = {}

    for gap in gaps:
        modes = find_modes(mode_solver=gf.partial(mode_solver, gaps=(gap, )))
        ne.append(modes[1].neff)
        no.append(modes[2].neff)
        gap_to_modes[gap] = modes

    lc = [
        coupling_length(neff1=neff1, neff2=neff2)
        for gap, neff1, neff2 in zip(gaps, ne, no)
    ]

    df = pd.DataFrame(dict(gap=gaps, ne=ne, no=no, lc=lc))
    if filepath:
        filepath = pathlib.Path(filepath)
        dirpath = filepath.parent
        dirpath.mkdir(exist_ok=True, parents=True)
        df.to_csv(filepath, index=False)
    return df
def test_get_route_auto_widen() -> gf.Component:
    c = gf.Component("test_get_route_auto_widen")
    route = gf.routing.get_route_from_waypoints(
        [(0, 0), (300, 0), (300, 300), (-600, 300), (-600, -300)],
        cross_section=xs_pin_m1,
        bend=gf.partial(gf.c.bend_euler, cross_section=xs_pin),
        taper=taper_pin,
        radius=30,
    )
    c.add(route.references)
    difftest(c)
    return c
Example #15
0
def test_name_partial_functions():
    s1 = gf.partial(gf.c.straight)
    s2 = gf.partial(gf.c.straight, length=5)
    s3 = gf.partial(gf.c.straight, 5)

    m1 = gf.partial(gf.c.mzi, straight=s1)()
    m2 = gf.partial(gf.c.mzi, straight=s2)()
    m3 = gf.partial(gf.c.mzi, straight=s3)()

    # print(m1.name)
    # print(m2.name)
    # print(m3.name)

    assert (
        m2.name == m3.name
    ), f"{m2.name} different from {m2.name} while they are the same function"
    assert (
        m1.name != m2.name
    ), f"{m1.name} is the same {m2.name} while they are different functions"
    assert (
        m1.name != m3.name
    ), f"{m1.name} is the same {m3.name} while they are different functions"
Example #16
0
"""Lets add pins to each cell from the fab a PDK.

"""

import gdsfactory as gf
from gdsfactory.add_pins import add_outline, add_pins
from gdsfactory.cross_section import strip
from gdsfactory.difftest import difftest
from gdsfactory.tech import Library

WIDTH = 2
LAYER = (30, 0)

fab_a_metal = gf.partial(strip, width=WIDTH, layer=LAYER)
fab_a_metal.__name__ = "fab_a_metal"


def test_waveguide():
    c = gf.components.straight(cross_section=fab_a_metal)
    difftest(c)


def decorator(component) -> None:
    """Fab specific functions over a component."""
    add_pins(component)
    add_outline(component)


mmi2x2 = gf.partial(gf.components.mmi2x2, decorator=decorator)
mmi1x2 = gf.partial(gf.components.mmi1x2, decorator=decorator)
bend_euler = gf.partial(gf.components.bend_euler, decorator=decorator)
Example #17
0
"""Straight Doped PIN waveguide."""

import gdsfactory as gf
from gdsfactory.components.extension import extend_ports
from gdsfactory.components.straight import straight
from gdsfactory.components.taper import taper_strip_to_ridge
from gdsfactory.cross_section import rib

straight_rib = gf.partial(straight, cross_section=rib)


straight_rib_tapered = gf.partial(
    extend_ports,
    component=straight_rib,
    extension_factory=taper_strip_to_ridge,
    port1="o2",
    port2="o1",
)


if __name__ == "__main__":
    c = straight_rib()
    c = straight_rib_tapered()
    c.show()
Example #18
0
import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.components.bend_euler import bend_euler
from gdsfactory.components.coupler_ring import coupler_ring
from gdsfactory.components.straight import straight as straight_function
from gdsfactory.components.taper import taper
from gdsfactory.config import call_if_func
from gdsfactory.snap import assert_on_2nm_grid

taper2 = gf.partial(taper, width2=3)


@gf.cell
def ring_single_dut(component=taper2,
                    wg_width=0.5,
                    gap=0.2,
                    length_x=4,
                    radius=5,
                    length_y=0,
                    coupler=coupler_ring,
                    straight=straight_function,
                    bend=bend_euler,
                    with_component=True,
                    **kwargs):
    """Single bus ring made of two couplers (ct: top, cb: bottom)
    connected with two vertical straights (wyl: left, wyr: right)
    (Device Under Test) in the middle to extract loss from quality factor


    Args:
        with_component: if False changes component for just a straight
Example #19
0
    for i in range(columns):
        if i % 2 == 0:  # even row
            s += "D-C-" * rows + "|"
        else:
            s += "C-D-" * rows + "|"
    s = s[:-1]

    # Create the component from the sequence
    c = component_sequence(sequence=s,
                           symbol_to_component=symbol_to_component,
                           start_orientation=0)
    c.info.n_bends = rows * columns * 2 + columns * 2 - 2
    return c


cutback_bend180circular = gf.partial(cutback_bend180, bend180=bend_circular180)
cutback_bend90circular = gf.partial(cutback_bend90, bend90=bend_circular)

if __name__ == "__main__":
    c = cutback_bend()
    # c = cutback_bend90()
    # c = cutback_bend_circular(rows=7, columns=4, radius=5) #62
    # c = cutback_bend_circular(rows=14, columns=4) #118
    # c = cutback_bend90()
    # c = cutback_bend180(rows=3, columns=1)
    # c = cutback_bend(rows=3, columns=2)
    # c = cutback_bend90(rows=3, columns=2)
    # c = cutback_bend180(rows=2, columns=2)
    # c = cutback_bend(rows=3, columns=2)
    c.show()
Example #20
0
Lets say that the waveguides are defined in layer (2, 0) and are 0.3um wide

"""

import gdsfactory as gf
from gdsfactory.cross_section import strip
from gdsfactory.difftest import difftest

WIDTH = 0.3
LAYER = (2, 0)
LAYERS_CLADDING = ((71, 0), (68, 0))

fab_b_metal = gf.partial(
    strip,
    width=WIDTH,
    layer=LAYER,
    layers_cladding=LAYERS_CLADDING,
)
fab_b_metal.__name__ = "fab_b_metal"

straight = gf.partial(gf.components.straight, cross_section=fab_b_metal)
bend_euler = gf.partial(gf.components.bend_euler, cross_section=fab_b_metal)
mmi1x2 = gf.partial(
    gf.components.mmi1x2,
    cross_section=fab_b_metal,
    width=WIDTH,
    width_taper=WIDTH,
    width_mmi=3 * WIDTH,
)
mzi = gf.partial(gf.components.mzi, cross_section=fab_b_metal, splitter=mmi1x2)
gc = gf.partial(gf.components.grating_coupler_elliptical_te,
Example #21
0
            ref = c.add_array(
                via, columns=nb_vias_x, rows=nb_vias_y, spacing=(pitch_x, pitch_y)
            )

            cw = (width - (nb_vias_x - 1) * pitch_x - w) / 2
            ch = (height - (nb_vias_y - 1) * pitch_y - h) / 2
            x0 = -a + cw + w / 2
            y0 = -b + ch + h / 2
            ref.move((x0, y0))

    return c


contact_metal = gf.partial(
    contact,
    layers=(LAYER.M1, LAYER.M2, LAYER.M3),
    vias=(via1, via2),
)

contact_slab = gf.partial(
    contact,
    layers=(LAYER.SLAB90, LAYER.M1, LAYER.M2, LAYER.M3),
    vias=(viac, via1, via2),
)
contact_npp = gf.partial(
    contact,
    layers=(LAYER.WG, LAYER.NPP, LAYER.M1),
    vias=(None, None, viac),
)
contact_slab_npp = gf.partial(
    contact,
Example #22
0
                 |  |_   -
                 |__|


           |<-dx->|

"""


import gdsfactory as gf
from gdsfactory.components.mmi2x2 import mmi2x2
from gdsfactory.components.mzi import mzi1x2_2x2
from gdsfactory.components.splitter_tree import splitter_tree
from gdsfactory.components.straight_heater_metal import straight_heater_metal

mzi = gf.partial(
    mzi1x2_2x2,
    combiner=mmi2x2,
    delta_length=0,
    straight_x_top=straight_heater_metal,
    length_x=None,
)

switch_tree = gf.partial(splitter_tree, coupler=mzi, spacing=(500, 100))


if __name__ == "__main__":
    # c = mzi()
    c = switch_tree(noutputs=16)
    c.show()
Example #23
0
                    monitor_indices=monitor_indices,
                    **settings,
                ))
        df = pd.DataFrame(sp)
        df["wavelengths"] = np.linspace(wl_min, wl_max, wl_steps)
        df["freqs"] = 1 / df["wavelengths"]
        df.to_csv(filepath, index=False)

        logger.info(f"Write simulation results to {filepath!r}")
        filepath_sim_settings.write_text(OmegaConf.to_yaml(sim_settings))
        logger.info(f"Write simulation settings to {filepath_sim_settings!r}")
        return df


write_sparameters_meep_lr = gf.partial(write_sparameters_meep,
                                       ymargin_top=3,
                                       ymargin_bot=3)

write_sparameters_meep_lt = gf.partial(write_sparameters_meep,
                                       ymargin_bot=3,
                                       xmargin_right=3)

if __name__ == "__main__":
    c = gf.components.straight(length=2)
    # p = 2
    # c = gf.add_padding_container(c0, default=0, top=p, bottom=p)
    # write_sparameters_meep(c, run=False)

    write_sparameters_meep_lr(c, run=False)
    plt.show()
Example #24
0
    c = Component()
    extension = (extension_factory()
                 if callable(extension_factory) else extension_factory)

    extension_port_name = extension_port_name or list(
        extension.ports.keys())[0]

    for i, port in enumerate(ports):
        extension_ref = c << extension
        extension_ref.connect(extension_port_name, port)

        for port_name, port in extension_ref.ports.items():
            # if port_name not in extension_port_name:
            c.add_port(f"{i}_{port_name}", port=port)

    c.auto_rename_ports()
    return c


if __name__ == "__main__":
    import gdsfactory as gf

    c = gf.components.mmi1x2()
    t = gf.partial(gf.c.taper, width2=0.1)

    cr = extend_ports_list(ports=c.get_ports_list(),
                           extension_factory=t,
                           extension_port_name="o1")
    c.add_ref(cr)
    c.show()
Example #25
0
    """
    c = Component()
    c.info["spacing"] = spacing
    c.info["enclosure"] = enclosure
    c.info["size"] = size

    width, height = size
    a = width / 2
    b = height / 2
    c.add_polygon([(-a, -b), (a, -b), (a, b), (-a, b)], layer=layer)

    layers_cladding = layers_cladding or []
    a = (width + cladding_offset) / 2
    b = (height + cladding_offset) / 2
    for layer in layers_cladding:
        c.add_polygon([(-a, -b), (a, -b), (a, b), (-a, b)], layer=layer)

    return c


viac = gf.partial(via, layer=LAYER.VIAC)
via1 = gf.partial(via, layer=LAYER.VIA1, enclosure=2)
via2 = gf.partial(via, layer=LAYER.VIA2)

if __name__ == "__main__":

    c = via()
    # c.pprint
    print(c)
    c.show()
Example #26
0
cross_section

.. code::

                              |<------width------>|
      ____________             ___________________               ______________
     |            |           |     undoped Si    |             |              |
     |layer_heater|           |  intrinsic region |<----------->| layer_heater |
     |____________|           |___________________|             |______________|
                                                                 <------------>
                                                    heater_gap     heater_width

"""

import gdsfactory as gf
from gdsfactory.components.contact import contact_npp
from gdsfactory.components.straight_heater_doped_rib import straight_heater_doped_rib
from gdsfactory.cross_section import strip_heater_doped

straight_heater_doped_strip = gf.partial(
    straight_heater_doped_rib,
    cross_section_heater=strip_heater_doped,
    contact_contact=contact_npp,
)

if __name__ == "__main__":
    # c = straight_heater_doped_strip(length=100)
    # c = test_straight_heater_doped_strip_ports()
    c = straight_heater_doped_strip(contact_contact=None)
    c.show()
Example #27
0
from typing import Tuple

import numpy as np

import gdsfactory as gf
from gdsfactory.add_grating_couplers import (
    add_grating_couplers_with_loopback_fiber_array, )
from gdsfactory.component import Component
from gdsfactory.config import CONFIG
from gdsfactory.mask.write_labels import write_labels

layer_label = (200, 0)

add_te = gf.partial(
    gf.routing.add_fiber_array,
    grating_coupler=gf.components.grating_coupler_elliptical_te,
    layer_label=layer_label,
)
add_tm = gf.partial(
    gf.routing.add_fiber_array,
    grating_coupler=gf.components.grating_coupler_elliptical_tm,
    bend_radius=20,
    layer_label=layer_label,
)


@gf.cell
def coupler_te(
    gap: float,
    length: int,
) -> Component:
Example #28
0
def round_corners(
    points: Coordinates,
    straight: ComponentFactory = straight_function,
    bend: ComponentFactory = bend_euler,
    bend_s_factory: Optional[ComponentFactory] = bend_s,
    taper: Optional[ComponentFactory] = None,
    straight_fall_back_no_taper: Optional[ComponentFactory] = None,
    mirror_straight: bool = False,
    straight_ports: Optional[List[str]] = None,
    cross_section: CrossSectionFactory = strip,
    on_route_error: Callable = get_route_error,
    with_point_markers: bool = False,
    snap_to_grid_nm: Optional[int] = 1,
    **kwargs,
) -> Route:
    """Returns Route:

    - references list with rounded straight route from a list of manhattan points.
    - ports: Tuple of ports
    - length: route length (float)

    Args:
        points: manhattan route defined by waypoints
        bend90: the bend to use for 90Deg turns
        straight: the straight library to use to generate straight portions
        taper: taper for straight portions. If None, no tapering
        straight_fall_back_no_taper: in case there is no space for two tapers
        mirror_straight: mirror_straight waveguide
        straight_ports: port names for straights. If None finds them automatically.
        cross_section:
        on_route_error: function to run when route fails
        with_point_markers: add route points markers (easy for debugging)
        snap_to_grid_nm: nm to snap to grid
        kwargs: cross_section settings
    """
    x = cross_section(**kwargs)
    points = (gf.snap.snap_to_grid(points, nm=snap_to_grid_nm)
              if snap_to_grid_nm else points)

    auto_widen = x.info.get("auto_widen", False)
    auto_widen_minimum_length = x.info.get("auto_widen_minimum_length", 200.0)
    taper_length = x.info.get("taper_length", 10.0)
    width = x.info.get("width", 2.0)
    width_wide = x.info.get("width_wide", None)
    references = []
    bend90 = bend(cross_section=cross_section, **
                  kwargs) if callable(bend) else bend
    # bsx = bsy = _get_bend_size(bend90)
    taper = taper or taper_function(
        cross_section=cross_section,
        width1=width,
        width2=width_wide,
        length=taper_length,
    )
    taper = taper(cross_section=cross_section, **
                  kwargs) if callable(taper) else taper

    # If there is a taper, make sure its length is known
    if taper and isinstance(taper, Component):
        if "length" not in taper.info:
            _taper_ports = list(taper.ports.values())
            taper.info["length"] = _taper_ports[-1].x - _taper_ports[0].x

    straight_fall_back_no_taper = straight_fall_back_no_taper or straight

    # Remove any flat angle, otherwise the algorithm won't work
    points = remove_flat_angles(points)
    points = np.array(points)

    straight_sections = []  # (p0, angle, length)
    p0_straight = points[0]
    p1 = points[1]

    total_length = 0  # Keep track of the total path length

    if not hasattr(bend90.info, "length"):
        raise ValueError(
            f"bend {bend90} needs to have bend.info.length defined")

    bend_length = bend90.info.length

    dp = p1 - p0_straight
    bend_orientation = None
    if _is_vertical(p0_straight, p1):
        if dp[1] > 0:
            bend_orientation = 90
        elif dp[1] < 0:
            bend_orientation = 270
    elif _is_horizontal(p0_straight, p1):
        if dp[0] > 0:
            bend_orientation = 0
        elif dp[0] < 0:
            bend_orientation = 180

    if bend_orientation is None:
        return on_route_error(points=points, cross_section=x)

    layer = x.info["layer"]
    try:
        pname_west, pname_north = [
            p.name for p in _get_bend_ports(bend=bend90, layer=layer)
        ]
    except ValueError as exc:
        raise ValueError(
            f"Did not find 2 ports on layer {layer}. Got {list(bend90.ports.values())}"
        ) from exc
    n_o_bends = points.shape[0] - 2
    total_length += n_o_bends * bend_length

    previous_port_point = points[0]
    bend_points = [previous_port_point]

    # Add bend sections and record straight-section information
    for i in range(1, points.shape[0] - 1):
        bend_origin, rotation, x_reflection = _get_bend_reference_parameters(
            points[i - 1], points[i], points[i + 1], bend90, x.info["layer"])
        bend_ref = gen_sref(bend90, rotation, x_reflection, pname_west,
                            bend_origin)
        references.append(bend_ref)

        dx_points = points[i][0] - points[i - 1][0]
        dy_points = points[i][1] - points[i - 1][1]

        if abs(dx_points) < TOLERANCE:
            matching_ports = [
                port for port in bend_ref.ports.values()
                if np.isclose(port.x, points[i][0])
            ]

        if abs(dy_points) < TOLERANCE:
            matching_ports = [
                port for port in bend_ref.ports.values()
                if np.isclose(port.y, points[i][1])
            ]

        if matching_ports:
            next_port = matching_ports[0]
            other_port_name = set(bend_ref.ports.keys()) - {next_port.name}
            other_port = bend_ref.ports[list(other_port_name)[0]]
            bend_points.append(next_port.midpoint)
            bend_points.append(other_port.midpoint)
            previous_port_point = other_port.midpoint

        try:
            straight_sections += [(
                p0_straight,
                bend_orientation,
                get_straight_distance(p0_straight, bend_origin),
            )]
        except RouteError:
            on_route_error(
                points=(p0_straight, bend_origin),
                cross_section=x,
                references=references,
            )

        p0_straight = bend_ref.ports[pname_north].midpoint
        bend_orientation = bend_ref.ports[pname_north].orientation

    bend_points.append(points[-1])

    try:
        straight_sections += [(
            p0_straight,
            bend_orientation,
            get_straight_distance(p0_straight, points[-1]),
        )]
    except RouteError:
        on_route_error(
            points=(p0_straight, points[-1]),
            cross_section=x,
            references=references,
        )

    # with_point_markers=True
    # print()
    # for i, point in enumerate(points):
    #     print(i, point)
    # print()
    # for i, point in enumerate(bend_points):
    #     print(i, point)

    # ensure bend connectivity
    for i, point in enumerate(points[:-1]):
        sx = np.sign(points[i + 1][0] - point[0])
        sy = np.sign(points[i + 1][1] - point[1])
        bsx = np.sign(bend_points[2 * i + 1][0] - bend_points[2 * i][0])
        bsy = np.sign(bend_points[2 * i + 1][1] - bend_points[2 * i][1])
        if bsx * sx == -1 or bsy * sy == -1:
            return on_route_error(points=points,
                                  cross_section=x,
                                  references=references)

    wg_refs = []
    for straight_origin, angle, length in straight_sections:
        with_taper = False
        # wg_width = list(bend90.ports.values())[0].width
        length = snap_to_grid(length)
        total_length += length

        if auto_widen and length > auto_widen_minimum_length and width_wide:
            # Taper starts where straight would have started
            with_taper = True
            length = length - 2 * taper_length
            taper_origin = straight_origin

            pname_west, pname_east = [
                p.name
                for p in _get_straight_ports(taper, layer=x.info["layer"])
            ]
            taper_ref = taper.ref(position=taper_origin,
                                  port_id=pname_west,
                                  rotation=angle)

            references.append(taper_ref)
            wg_refs += [taper_ref]

            # Update start straight position
            straight_origin = taper_ref.ports[pname_east].midpoint

            # Straight waveguide
            kwargs_wide = kwargs.copy()
            kwargs_wide.update(width=width_wide)
            cross_section_wide = gf.partial(cross_section, **kwargs_wide)
            wg = straight(length=length, cross_section=cross_section_wide)
        else:
            wg = straight_fall_back_no_taper(length=length,
                                             cross_section=cross_section,
                                             **kwargs)

        if straight_ports is None:
            straight_ports = [
                p.name for p in _get_straight_ports(wg, layer=x.info["layer"])
            ]
        pname_west, pname_east = straight_ports

        wg_ref = wg.ref()
        wg_ref.move(wg.ports[pname_west], (0, 0))
        if mirror_straight:
            wg_ref.reflect_v(list(wg_ref.ports.values())[0].name)

        wg_ref.rotate(angle)
        wg_ref.move(straight_origin)

        if length > 0:
            references.append(wg_ref)
            wg_refs += [wg_ref]

        port_index_out = 1
        if with_taper:
            # Second taper:
            # Origin at end of straight waveguide, starting from east side of taper

            taper_origin = wg_ref.ports[pname_east]
            pname_west, pname_east = [
                p.name
                for p in _get_straight_ports(taper, layer=x.info["layer"])
            ]

            taper_ref = taper.ref(
                position=taper_origin,
                port_id=pname_east,
                rotation=angle + 180,
                v_mirror=True,
            )
            # references += [
            #     gf.Label(
            #         text=f"a{angle}",
            #         position=taper_ref.center,
            #         layer=2,
            #         texttype=0,
            #     )
            # ]
            references.append(taper_ref)
            wg_refs += [taper_ref]
            port_index_out = 0

    if with_point_markers:
        route = get_route_error(points, cross_section=x)
        references += route.references

    port_input = list(wg_refs[0].ports.values())[0]
    port_output = list(wg_refs[-1].ports.values())[port_index_out]
    length = snap_to_grid(float(total_length))
    return Route(references=references,
                 ports=(port_input, port_output),
                 length=length)
Example #29
0
"""
                  __
                _|  |_
          __   | |  |_   _
         |  |__| |__|    |
        _|  |__          |dy
         |__|  |  __     |
               |_|  |_   |
                 |  |_   -
                 |__|


           |<-dx->|

"""

import gdsfactory as gf
from gdsfactory.components.mmi2x2 import mmi2x2
from gdsfactory.components.mzi_phase_shifter import mzi_phase_shifter
from gdsfactory.components.splitter_tree import splitter_tree

mzi = gf.partial(mzi_phase_shifter, combiner=mmi2x2, delta_length=0)

switch_tree = gf.partial(splitter_tree, coupler=mzi, spacing=(500, 100))

if __name__ == "__main__":
    # c = mzi()
    c = switch_tree(noutputs=16)
    c.show()
Example #30
0
import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.components.rectangle import rectangle
from gdsfactory.components.triangle import triangle
from gdsfactory.tech import LAYER
from gdsfactory.types import ComponentFactory, Float2, Layer

triangle_metal = gf.partial(triangle, layer=LAYER.M3, xtop=2)


@gf.cell
def dicing_lane(
        size: Float2 = (50, 300),
        marker: ComponentFactory = triangle_metal,
        layer_dicing: Layer = (100, 0),
) -> Component:
    """Dicing lane with triangular markers on both sides.

    Args:
        size: (tuple) Width and height of rectangle.
        marker: function to generate the dicing lane markers
        layer_dicing: Specific layer to put polygon geometry on.

    """
    c = Component()
    r = c << rectangle(size=size, layer=layer_dicing)

    m = marker()

    mbr = c << m
    mbr.xmin = r.xmax