예제 #1
0
def staircase(
    bend90: ComponentOrFactory = bend_euler,
    length_v: float = 5.0,
    length_h: float = 5.0,
    rows: int = 4,
    straight: ComponentFactory = straight,
) -> Component:
    bend90 = gf.call_if_func(bend90)

    wgh = straight(length=length_h, width=bend90.ports["o1"].width)
    wgv = straight(length=length_v, width=bend90.ports["o1"].width)

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (bend90, "o1", "o2"),
        "B": (bend90, "o2", "o1"),
        "-": (wgh, "o1", "o2"),
        "|": (wgv, "o1", "o2"),
    }

    # Generate the sequence of staircases
    s = "-A|B" * rows + "-"

    c = component_sequence(sequence=s,
                           symbol_to_component=symbol_to_component,
                           start_orientation=0)
    c.info.n_bends = 2 * rows
    return c
예제 #2
0
def test_cutback_phase(straight_length: float = 100.0,
                       bend_radius: float = 12.0,
                       n: int = 2) -> Component:
    """Modulator sections connected by bends"""
    # Define sub components
    bend180 = gf.components.bend_circular180(radius=bend_radius)
    pm_wg = gf.c.straight_pin(length=straight_length, taper=None)
    wg_short = straight(length=1.0)
    wg_short2 = straight(length=2.0)
    wg_heater = gf.c.straight_pin(length=10.0, taper=None)
    taper = taper_strip_to_ridge()

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "I": (taper, "o1", "o2"),
        "O": (taper, "o2", "o1"),
        "S": (wg_short, "o1", "o2"),
        "P": (pm_wg, "o1", "o2"),
        "A": (bend180, "o1", "o2"),
        "B": (bend180, "o2", "o1"),
        "H": (wg_heater, "o1", "o2"),
        "-": (wg_short2, "o1", "o2"),
    }

    # Generate a sequence
    # This is simply a chain of characters. Each of them represents a component
    # with a given input and and a given output

    repeated_sequence = "SIPOSASIPOSB"
    heater_seq = "-H-H-H-H-"
    sequence = repeated_sequence * n + "SIPO" + heater_seq
    component = component_sequence(sequence=sequence,
                                   symbol_to_component=symbol_to_component)
    return component
예제 #3
0
def cutback_bend180(
    bend180: ComponentOrFactory = bend_euler180,
    straight_length: float = 5.0,
    rows: int = 6,
    columns: int = 6,
    spacing: int = 3,
    straight: ComponentFactory = straight,
) -> Component:
    """

    .. code::

          _
        _| |_  this is a row

        _ this is a column

    """
    bend180 = gf.call_if_func(bend180)

    straightx = straight(length=straight_length,
                         width=bend180.ports["o1"].width)
    wg_vertical = straight(
        length=2 * bend180.size_info.width + straight_length + spacing,
        width=bend180.ports["o1"].width,
    )

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "D": (bend180, "o1", "o2"),
        "C": (bend180, "o2", "o1"),
        "-": (straightx, "o1", "o2"),
        "|": (wg_vertical, "o1", "o2"),
    }

    # Generate the sequence of staircases
    s = ""
    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
예제 #4
0
def cutback_bend90(
    bend90: ComponentOrFactory = bend_euler,
    straight_length: float = 5.0,
    rows: int = 6,
    columns: int = 6,
    spacing: int = 5,
    straight: ComponentFactory = straight,
) -> Component:
    """

    .. code::

           _
        |_| |

    """
    bend90 = gf.call_if_func(bend90)
    straightx = straight(length=straight_length,
                         width=bend90.ports["o1"].width)

    straight_length = 2 * _get_bend_size(bend90) + spacing + straight_length
    straighty = straight(
        length=straight_length,
        width=bend90.ports["o1"].width,
    )
    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (bend90, "o1", "o2"),
        "B": (bend90, "o2", "o1"),
        "-": (straightx, "o1", "o2"),
        "|": (straighty, "o1", "o2"),
    }

    # Generate the sequence of staircases
    s = ""
    for i in range(columns):
        if i % 2 == 0:  # even row
            s += "A-A-B-B-" * rows + "|"
        else:
            s += "B-B-A-A-" * 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 * 4
    return c
예제 #5
0
def cutback_component(
    component: ComponentFactory = taper_0p5_to_3_l36,
    cols: int = 4,
    rows: int = 5,
    radius: float = 5.0,
    port1: str = "o1",
    port2: str = "o2",
    bend180: ComponentFactory = bend_euler180,
    straight: ComponentFactory = straight,
) -> Component:
    """Returns a daisy chain of components for measuring their loss.

    Args:
        component: for cutback
        cols
        rows
        radius: for bend
        port1: name of first optical port
        port2: name of second optical port
        bend180: ubend
        straight: waveguide function to connect both sides

    """
    component = component() if callable(component) else component
    bendu = bend180(radius=radius)
    straight_component = straight()

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (component, port1, port2),
        "B": (component, port2, port1),
        "D": (bendu, "o1", "o2"),
        "C": (bendu, "o2", "o1"),
        "-": (straight_component, "o1", "o2"),
        "_": (straight_component, "o2", "o1"),
    }

    # Generate the sequence of staircases

    s = ""
    for i in range(rows):
        s += "AB" * cols
        s += "D" if i % 2 == 0 else "C"

    s = s[:-1]
    s += "-_"

    for i in range(rows):
        s += "AB" * cols
        s += "D" if (i + rows) % 2 == 0 else "C"

    s = s[:-1]

    # Create the component from the sequence
    c = component_sequence(sequence=s, symbol_to_component=symbol_to_component)
    n = len(s) - 2
    c.copy_child_info(component)
    c.info["components"] = n
    c.info["parent_name"] = f"loopback_{component.get_parent_name()}_{n}"
    return c
예제 #6
0
def cutback_component_mirror(
    component: ComponentFactory = component_flipped,
    cols: int = 4,
    rows: int = 5,
    radius: int = 10,
    port1: str = "o2",
    port2: str = "o1",
    bend180: ComponentFactory = bend_euler180,
    straight: ComponentFactory = straight_long,
) -> Component:
    """Returns a daisy chain of components for measuring their loss.

    Flips component. Useful when 'o2' is the port that you want to route to

    Args:
        component: for cutback
        cols
        rows
        radius: for bend
        port1: name of first optical port
        port2: name of second optical port
        bend180: ubend
        straight: waveguide function to connect both sides

    """
    component = component() if callable(component) else component
    bendu = bend180(radius=radius)
    straight_component = straight()

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (component, port1, port2),
        "B": (component, port2, port1),
        "D": (bendu, "o1", "o2"),
        "C": (bendu, "o2", "o1"),
        "-": (straight_component, "o1", "o2"),
        "_": (straight_component, "o2", "o1"),
    }

    s = ""
    for i in range(rows):
        s += "AB" * cols
        s += "C" if i % 2 == 0 else "D"

    s = s[:-1]
    s += "-_"

    for i in range(rows):
        s += "AB" * cols
        s += "D" if (i + rows + 1) % 2 == 0 else "C"

    s = s[:-1]

    c = component_sequence(sequence=s, symbol_to_component=symbol_to_component)
    n = len(s) - 2
    c.copy_child_info(component)
    c.info["components"] = n
    c.info["parent_name"] = f"loopback_{component.get_parent_name()}_{n}"
    return c
예제 #7
0
def cdsem_uturn(
    width: float = 0.5,
    radius: float = 10.0,
    wg_length: float = LINE_LENGTH,
    straight: ComponentFactory = straight,
    bend90: ComponentFactory = bend_circular,
    layer: Tuple[int, int] = LAYER.WG,
    layers_cladding: List[Tuple[int, int]] = None,
    cross_section: CrossSectionFactory = strip,
    pixel_size: float = 1.0,
) -> Component:
    """

    Args:
        width: of the line
        cladding_offset:
        radius: bend radius
        wg_length

    """
    c = Component()
    r = radius

    cross_section = partial(cross_section, width=width, layer=layer)
    if wg_length is None:
        wg_length = 2 * r

    bend90 = bend90(cross_section=cross_section, radius=r)
    wg = straight(
        cross_section=cross_section,
        length=wg_length,
    )

    # Add the U-turn on straight layer
    b1 = c.add_ref(bend90)
    b2 = c.add_ref(bend90)
    b2.connect("o2", b1.ports["o1"])

    wg1 = c.add_ref(wg)
    wg1.connect("o1", b1.ports["o2"])

    wg2 = c.add_ref(wg)
    wg2.connect("o1", b2.ports["o1"])

    label = c << manhattan_text(
        text=str(int(width * 1e3)), size=pixel_size, layer=layer)
    label.ymax = b2.ymin - 5
    label.x = 0
    b1.rotate(90)
    b2.rotate(90)
    wg1.rotate(90)
    wg2.rotate(90)
    label.rotate(90)
    return c
예제 #8
0
def coupler90(gap: float = 0.2,
              radius: float = 10.0,
              bend: ComponentFactory = bend_euler,
              cross_section: CrossSectionFactory = strip,
              **kwargs) -> Component:
    r"""straight coupled to a bend.

    Args:
        gap: um
        radius: um
        straight: for straight
        bend: for bend
        cross_section:
        kwargs: cross_section settings

    .. code::

             3
             |
            /
           /
        2_/
        1____4

    """
    c = Component()
    x = cross_section(radius=radius, **kwargs)

    bend90 = (bend(cross_section=cross_section, radius=radius, **kwargs)
              if callable(bend) else bend)
    bend_ref = c << bend90
    straight_component = (straight(
        cross_section=cross_section,
        length=bend90.ports["o2"].midpoint[0] - bend90.ports["o1"].midpoint[0],
        **kwargs) if callable(straight) else straight)

    wg_ref = c << straight_component
    width = x.info["width"]

    pbw = bend_ref.ports["o1"]
    bend_ref.movey(pbw.midpoint[1] + gap + width)

    c.absorb(wg_ref)
    c.absorb(bend_ref)

    c.add_port("o1", port=wg_ref.ports["o1"])
    c.add_port("o4", port=wg_ref.ports["o2"])
    c.add_port("o2", port=bend_ref.ports["o1"])
    c.add_port("o3", port=bend_ref.ports["o2"])
    return c
예제 #9
0
def test_add_keepout() -> None:
    from gdsfactory.components.straight import straight

    c = straight()
    polygons = len(c.get_polygons())
    target_layers = [LAYER.WG]
    keepout_layers = [LAYER.NO_TILE_SI]
    print(len(c.get_polygons()))

    assert len(c.get_polygons()) == polygons
    c = add_keepout(component=c,
                    target_layers=target_layers,
                    keepout_layers=keepout_layers)
    # print(len(c.get_polygons()))
    assert len(c.get_polygons()) == polygons + 1
예제 #10
0
def cdsem_straight_all(
    straight: ComponentFactory = straight,
    cross_section: CrossSectionFactory = strip,
    layer: Tuple[int, int] = LAYER.WG,
    layers_cladding: List[Tuple[int, int]] = None,
    widths: Tuple[float, ...] = (0.4, 0.45, 0.5, 0.6, 0.8, 1.0),
    pixel_size: float = 1.0,
    length: float = LINE_LENGTH,
    spacing: float = 4.5,
) -> Component:
    c = Component()
    for width in widths:
        cross_section = partial(cross_section, width=width, layer=layer)
        c.add_ref(straight(length=length, cross_section=cross_section))

    c.distribute(direction="y", spacing=spacing)
    return c
예제 #11
0
def bend_straight_bend(straight_length: float = 10.0,
                       angle: int = 90,
                       p: float = 0.5,
                       with_arc_floorplan: bool = True,
                       npoints: int = 720,
                       direction: str = "ccw",
                       with_cladding_box: bool = True,
                       cross_section: CrossSectionOrFactory = strip,
                       **kwargs) -> Component:
    """Sbend made of 2 euler bends and straight section in between.

    Args:
        straight_length:
        angle: total angle of the curve
        p: Proportion of the curve that is an Euler curve
        with_arc_floorplan: If False: `radius` is the minimum radius of curvature
          If True: The curve scales such that the endpoints match a bend_circular
          with parameters `radius` and `angle`
        npoints: Number of points used per 360 degrees
        direction: cw (clock-wise) or ccw (counter clock-wise)
        with_cladding_box: to avoid DRC acute angle errors in cladding
        cross_section:
        kwargs: cross_section settings


    """
    c = Component()
    b = bend_euler(angle=angle,
                   p=p,
                   with_arc_floorplan=with_arc_floorplan,
                   npoints=npoints,
                   direction=direction,
                   with_cladding_box=with_cladding_box,
                   cross_section=cross_section,
                   **kwargs)
    b1 = c.add_ref(b)
    b2 = c.add_ref(b)
    s = c << straight(
        length=straight_length, cross_section=cross_section, **kwargs)
    s.connect("o1", b1.ports["o2"])
    b2.mirror()
    b2.connect("o1", s.ports["o2"])
    c.add_port("o1", port=b1.ports["o1"])
    c.add_port("o2", port=b2.ports["o2"])
    return c
예제 #12
0
def cutback_bend(
    bend90: ComponentOrFactory = bend_euler,
    straight_length: float = 5.0,
    rows: int = 6,
    columns: int = 5,
):
    """Deprecated! use cutback_bend90 instead!


    .. code::

        this is a column
            _
          _|
        _|

        _ this is a row

    """

    bend90 = gf.call_if_func(bend90)
    straightx = straight(length=straight_length,
                         width=bend90.ports["o1"].width)

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (bend90, "o1", "o2"),
        "B": (bend90, "o2", "o1"),
        "S": (straightx, "o1", "o2"),
    }

    # Generate the sequence of staircases
    s = ""
    for i in range(columns):
        s += "ASBS" * rows
        s += "ASAS" if i % 2 == 0 else "BSBS"
    s = s[:-4]

    c = component_sequence(sequence=s,
                           symbol_to_component=symbol_to_component,
                           start_orientation=90)
    c.info.n_bends = rows * columns * 2 + columns * 2 - 2
    return c
예제 #13
0
def cdsem_straight_density(
    width: float = 0.372,
    trench_width: float = 0.304,
    x: float = LINE_LENGTH,
    y: float = 50.0,
    margin: float = 2.0,
    label: str = "",
    straight: ComponentFactory = straight,
    layer: Tuple[int, int] = LAYER.WG,
    layers_cladding: Optional[Tuple[Layer, ...]] = None,
    cross_section: CrossSectionFactory = strip,
    pixel_size: float = 1.0,
) -> Component:
    """Horizontal grating etch lines

    Args:
        width: width
        trench_width: trench_width
    """
    c = Component()
    period = width + trench_width
    n_o_lines = int((y - 2 * margin) / period)
    length = x - 2 * margin

    cross_section = partial(cross_section, width=width, layer=layer)
    tooth = straight(length=length, cross_section=cross_section)

    for i in range(n_o_lines):
        tooth_ref = c.add_ref(tooth)
        tooth_ref.movey((-n_o_lines / 2 + 0.5 + i) * period)
        c.absorb(tooth_ref)

    marker_label = manhattan_text(
        text=f"{label}",
        size=pixel_size,
        layer=layer,
    )
    _marker_label = c.add_ref(marker_label)
    _marker_label.move((length + 3, 10.0))
    c.absorb(_marker_label)
    return c
예제 #14
0
def get_routes_straight(
    ports: Union[List[Port], Dict[str, Port]],
    straight: ComponentOrFactory = straight,
    **kwargs,
) -> Routes:
    """Returns routes made by 180 degree straights.

    Args:
        ports: List or dict of ports
        straight: function for straight
        **kwargs: waveguide settings
    """
    ports = list(ports.values()) if isinstance(ports, dict) else ports
    straight = straight(**kwargs)
    references = [straight.ref() for port in ports]
    references = [
        ref.connect("o1", port) for port, ref in zip(ports, references)
    ]
    ports = [ref.ports["o2"] for i, ref in enumerate(references)]
    lengths = [straight.info.length] * len(ports)
    return Routes(references=references, ports=ports, lengths=lengths)
예제 #15
0
def test_cutback_pn() -> Component:
    # Define subcomponents
    bend_radius = 10.0
    bend180 = bend_circular(radius=bend_radius, angle=180)
    wg = straight(length=5.0)
    wg_heater = straight_pn(length=50.0)

    # Define a map between symbols and (component, input port, output port)
    symbol_to_component = {
        "A": (bend180, "o1", "o2"),
        "B": (bend180, "o2", "o1"),
        "H": (wg_heater, "o1", "o2"),
        "-": (wg, "o1", "o2"),
    }

    # Generate a sequence
    # This is simply a chain of characters. Each of them represents a component
    # with a given input and a given output

    sequence = "AB-H-H-H-H-BA"
    component = component_sequence(sequence=sequence,
                                   symbol_to_component=symbol_to_component)
    return component
예제 #16
0
def array_with_via(
    component: ComponentOrFactory = pad,
    columns: int = 3,
    spacing: float = 150.0,
    via_spacing: float = 10.0,
    straight_length: float = 60.0,
    cross_section: Optional[CrossSectionFactory] = metal2,
    contact: ComponentFactory = contact_factory,
    contact_dy: float = 0,
    port_orientation: int = 180,
    port_offset: Optional[Float2] = None,
    **kwargs,
) -> Component:
    """Returns an array of components in X axis
    with fanout waveguides facing west

    Args:
        component: to replicate in the array
        columns: number of components
        spacing: for the array
        via_spacing: for fanout
        straight_length: lenght of the straight at the end
        waveguide: waveguide definition
        cross_section:
        contact:
        contact_dy: contact offset
        port_orientation: 180: facing west
        port_offset: Optional port movement
        kwargs: cross_section settings
    """

    c = Component()
    component = component() if callable(component) else component
    contact = contact()

    for col in range(columns):
        ref = component.ref()
        ref.x = col * spacing
        c.add(ref)

        if port_orientation == 180:
            xlength = col * spacing + straight_length
        elif port_orientation == 0:
            xlength = columns * spacing - (col * spacing) + straight_length
        elif port_orientation == 270:
            xlength = col * via_spacing + straight_length

        elif port_orientation == 90:
            xlength = columns * via_spacing - (col *
                                               via_spacing) + straight_length

        else:
            raise ValueError(
                f"Invalid port_orientation = {port_orientation}",
                "180: west, 0: east, 90: north, 270: south",
            )

        contact_ref = c << contact
        contact_ref.x = col * spacing
        contact_ref.y = col * via_spacing + contact_dy

        if cross_section:
            port_name = f"e{col}"
            straightx_ref = c << straight(
                length=xlength, cross_section=cross_section, **kwargs)
            straightx_ref.connect(
                "e2",
                contact_ref.get_ports_list(orientation=port_orientation)[0])
            c.add_port(port_name, port=straightx_ref.ports["e1"])
            if port_offset:
                c.ports[port_name].move(np.array(port_offset) * col)
    return c
예제 #17
0
def add_fiber_single(
    component: ComponentOrFactory,
    grating_coupler: ComponentFactory = grating_coupler_te,
    layer_label: Tuple[int, int] = TECH.layer_label,
    fiber_spacing: float = TECH.fiber_spacing,
    bend: ComponentFactory = bend_circular,
    straight: ComponentFactory = straight,
    route_filter: Callable = get_route_from_waypoints,
    min_input_to_output_spacing: float = 200.0,
    optical_routing_type: int = 2,
    with_loopback: bool = True,
    component_name: Optional[str] = None,
    gc_port_name: str = "o1",
    get_input_label_text_loopback_function:
    Callable = get_input_label_text_loopback,
    get_input_label_text_function: Callable = get_input_label_text,
    select_ports: Callable = select_ports_optical,
    cross_section: CrossSectionFactory = strip,
    **kwargs,
) -> Component:
    r"""Returns component with grating ports and labels on each port.

    Can add loopback reference structure next to it.

    Args:
        component: to connect
        grating_coupler: grating coupler instance, function or list of functions
        layer_label: for test and measurement label
        fiber_spacing: between outputs
        bend: bend_circular
        straight: straight
        route_filter:
        max_y0_optical: None
        with_loopback: True, adds loopback structures
        straight_separation: 4.0
        list_port_labels: None, adds TM labels to port indices in this list
        connected_port_list_ids: None # only for type 0 optical routing
        nb_optical_ports_lines: 1
        force_manhattan: False
        excluded_ports:
        grating_indices: None
        routing_method: get_route
        gc_port_name: W0
        get_input_labels_function: function to get input labels for grating couplers
        optical_routing_type: None: autoselection, 0: no extension
        gc_rotation: -90
        component_name: name of component
        cross_section:
        **kwargs: cross_section settings

    .. code::

              fiber
             ______
            /| | |
           / | | |
        W0|  | | |
           \ | | |
          | \|_|_|_

          |
         xmin = 0

    .. plot::
        :include-source:

        import gdsfactory as gf

        c = gf.components.crossing()
        cc = gf.routing.add_fiber_single(
            component=c,
            optical_routing_type=0,
            grating_coupler=gf.components.grating_coupler_elliptical_te,
        )
        cc.plot()

    """
    component = component() if callable(component) else component
    optical_ports = select_ports(component.ports)
    optical_ports = list(optical_ports.values())
    optical_port_names = [p.name for p in optical_ports]

    if not optical_ports:
        raise ValueError(f"No ports for {component.name}")

    component = component() if callable(component) else component
    component_name = component_name or component.get_parent_name()

    gc = grating_coupler = (grating_coupler()
                            if callable(grating_coupler) else grating_coupler)
    if gc_port_name not in gc.ports:
        raise ValueError(f"{gc_port_name} not in {list(gc.ports.keys())}")

    gc_port_to_edge = abs(gc.xmax - gc.ports[gc_port_name].midpoint[0])

    c = Component()

    c.component = component
    cr = c << component
    cr.rotate(90)

    for port in cr.ports.values():
        if port.name not in optical_port_names:
            c.add_port(name=port.name, port=port)

    if (len(optical_ports) == 2
            and abs(optical_ports[0].x - optical_ports[1].x) >
            min_input_to_output_spacing):

        grating_coupler = call_if_func(grating_coupler)
        grating_couplers = []
        for port in cr.ports.values():
            if port.name in optical_port_names:
                gc_ref = grating_coupler.ref()
                gc_ref.connect(gc_port_name, port)
                grating_couplers.append(gc_ref)

        elements = get_input_labels(
            io_gratings=grating_couplers,
            ordered_ports=list(cr.ports.values()),
            component_name=component_name,
            layer_label=layer_label,
            gc_port_name=gc_port_name,
            get_input_label_text_function=get_input_label_text_function,
        )

    else:
        elements, grating_couplers = route_fiber_single(
            component,
            fiber_spacing=fiber_spacing,
            bend=bend,
            straight=straight,
            route_filter=route_filter,
            grating_coupler=grating_coupler,
            layer_label=layer_label,
            optical_routing_type=optical_routing_type,
            min_input_to_output_spacing=min_input_to_output_spacing,
            gc_port_name=gc_port_name,
            component_name=component_name,
            cross_section=cross_section,
            select_ports=select_ports,
            **kwargs,
        )

    for e in elements:
        c.add(e)
    for gc in grating_couplers:
        c.add(gc)

    for i, io_row in enumerate(grating_couplers):
        if isinstance(io_row, list):
            for j, io in enumerate(io_row):
                ports = io.get_ports_list(prefix="vertical")
                if ports:
                    port = ports[0]
                    c.add_port(f"{port.name}_{i}{j}", port=port)
        else:
            ports = io_row.get_ports_list(prefix="vertical")
            if ports:
                port = ports[0]
                c.add_port(f"{port.name}_{i}", port=port)

    if isinstance(grating_coupler, list):
        grating_couplers = [call_if_func(g) for g in grating_coupler]
        grating_coupler = grating_couplers[0]
    else:
        grating_coupler = call_if_func(grating_coupler)
        grating_couplers = [grating_coupler]

    if with_loopback:
        length = c.ysize - 2 * gc_port_to_edge
        wg = c << straight(
            length=length, cross_section=cross_section, **kwargs)
        wg.rotate(90)
        wg.xmax = (c.xmin - fiber_spacing if abs(c.xmin) > abs(fiber_spacing)
                   else c.xmin - fiber_spacing)
        wg.ymin = c.ymin + gc_port_to_edge

        gci = c << grating_coupler
        gco = c << grating_coupler
        gci.connect(gc_port_name, wg.ports["o1"])
        gco.connect(gc_port_name, wg.ports["o2"])

        port = wg.ports["o2"]
        text = get_input_label_text_loopback_function(
            port=port,
            gc=grating_coupler,
            gc_index=0,
            component_name=component_name)

        c.add_label(
            text=text,
            position=port.midpoint,
            anchor="o",
            layer=layer_label,
        )

        port = wg.ports["o1"]
        text = get_input_label_text_loopback_function(
            port=port,
            gc=grating_coupler,
            gc_index=1,
            component_name=component_name)
        c.add_label(
            text=text,
            position=port.midpoint,
            anchor="o",
            layer=layer_label,
        )

    c.copy_child_info(component)
    return c
예제 #18
0
def round_corners(
    points: Coordinates,
    straight: ComponentFactory = straight,
    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,
    **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)
        **kwargs: cross_section settings
    """
    x = cross_section(**kwargs)

    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_factory(
        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

        straight_sections += [(
            p0_straight,
            bend_orientation,
            get_straight_distance(p0_straight, bend_origin),
        )]

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

    bend_points.append(points[-1])
    straight_sections += [(p0_straight, bend_orientation,
                           get_straight_distance(p0_straight, points[-1]))]

    # 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:
            # print("error", bsx * sx, bsy * sy)
            # references += [gf.c.rectangle(size=(2, 2)).ref(position=point)]
            return on_route_error(points=points,
                                  cross_section=x,
                                  references=references)

    # for i, point in enumerate(bend_points[:-1]):
    #     bsx = bend_points[i + 1][0] - point[0]
    #     bsy = bend_points[i + 1][1] - point[1]
    #     if abs(bsx) > 0.001 and abs(bsy) > 0.001:
    #         print(i, point, bsx, bsy)
    #         # 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)

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

    # route = Component()
    # route.add(references)
    # netlist = route.get_netlist()
    # if len(netlist["connections"]) != len(references) - 1:
    #     return on_route_error(points=points, cross_section=x, references=references)

    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)
예제 #19
0
def array_with_fanout(
    component: ComponentOrFactory = pad,
    columns: int = 3,
    pitch: float = 150.0,
    waveguide_pitch: float = 10.0,
    start_straight_length: float = 5.0,
    end_straight_length: float = 40.0,
    radius: float = 5.0,
    component_port_name: str = "e4",
    bend: ComponentFactory = bend_euler,
    bend_port_name1: Optional[str] = None,
    bend_port_name2: Optional[str] = None,
    cross_section: CrossSectionFactory = strip,
    **kwargs,
) -> Component:
    """Returns an array of components in X axis
    with fanout waveguides facing west

    Args:
        component: to replicate.
        columns: number of components.
        pitch: for waveguides.
        waveguide_pitch: for output waveguides.
        start_straight_length: length of the start of the straight
        end_straight_length: lenght of the straight at the end
        radius: bend radius
        component_port_name:
        bend:
        bend_port_name1:
        bend_port_name2:
        cross_section: cross_section definition
        kwargs: cross_section settings
    """
    c = Component()
    component = component() if callable(component) else component
    bend = bend(radius=radius, cross_section=cross_section, **kwargs)

    bend_ports = bend.get_ports_list()
    bend_ports = sort_ports_x(bend_ports)
    bend_ports.reverse()
    bend_port_name1 = bend_port_name1 or bend_ports[0].name
    bend_port_name2 = bend_port_name2 or bend_ports[1].name

    for col in range(columns):
        ref = component.ref()
        ref.x = col * pitch
        c.add(ref)
        ylength = col * waveguide_pitch + start_straight_length
        xlength = col * pitch + end_straight_length
        straight_ref = c << straight(
            length=ylength, cross_section=cross_section, **kwargs)
        port_s1, port_s2 = straight_ref.get_ports_list()

        straight_ref.connect(port_s2.name, ref.ports[component_port_name])

        bend_ref = c.add_ref(bend)
        bend_ref.connect(bend_port_name1, straight_ref.ports[port_s1.name])
        straightx_ref = c << straight(
            length=xlength, cross_section=cross_section, **kwargs)
        straightx_ref.connect(port_s2.name, bend_ref.ports[bend_port_name2])
        c.add_port(f"W_{col}", port=straightx_ref.ports[port_s1.name])
    auto_rename_ports(c)
    return c
예제 #20
0
    from gdsfactory.components.straight import straight

    c = straight()
    polygons = len(c.get_polygons())
    target_layers = [LAYER.WG]
    keepout_layers = [LAYER.NO_TILE_SI]
    print(len(c.get_polygons()))

    assert len(c.get_polygons()) == polygons
    c = add_keepout(component=c,
                    target_layers=target_layers,
                    keepout_layers=keepout_layers)
    # print(len(c.get_polygons()))
    assert len(c.get_polygons()) == polygons + 1


if __name__ == "__main__":
    # test_add_keepout()

    # import gdsfactory as gf
    # from gdsfactory.components.crossing_waveguide import crossing_etched
    # from gdsfactory.components.crossing_waveguide import crossing45

    from gdsfactory.components.straight import straight

    c = straight()
    target_layers = [LAYER.WG]
    keepout_layers = [LAYER.SLAB150]
    c = add_keepout(c, target_layers, keepout_layers)
    c.show()