Ejemplo n.º 1
0
def connect_strip_way_points(way_points=[],
                             bend_factory=bend_circular,
                             straight_factory=waveguide,
                             taper_factory=taper_factory,
                             bend_radius=10.0,
                             wg_width=0.5,
                             layer=LAYER.WG,
                             **kwargs):
    """
    Returns a deep-etched route formed by the given way_points with
    bends instead of corners and optionally tapers in straight sections.
    
    taper_factory: can be either a taper component or a factory
    """

    bend90 = bend_factory(radius=bend_radius, width=wg_width)

    if taper_factory:
        if callable(taper_factory):
            taper = taper_factory(
                length=TAPER_LENGTH,
                width1=wg_width,
                width2=WG_EXPANDED_WIDTH,
                layer=layer,
            )
        else:
            # In this case the taper is a fixed cell
            taper = taper_factory
    else:
        taper = None

    connector = round_corners(way_points, bend90, straight_factory, taper)
    return connector
Ejemplo n.º 2
0
def connect_strip_way_points(way_points: List[Tuple[float, float]],
                             bend_factory: Callable = bend_circular,
                             straight_factory: Callable = waveguide,
                             taper_factory: Callable = taper_factory,
                             bend_radius: float = 10.0,
                             wg_width: float = 0.5,
                             layer=LAYER.WG,
                             **kwargs):
    """Returns a deep-etched route formed by the given way_points with
    bends instead of corners and optionally tapers in straight sections.

    taper_factory: can be either a taper Component or a factory
    """
    way_points = np.array(way_points)
    bend90 = bend_factory(radius=bend_radius, width=wg_width)

    taper = (taper_factory(
        length=TAPER_LENGTH,
        width1=wg_width,
        width2=WG_EXPANDED_WIDTH,
        layer=layer,
    ) if callable(taper_factory) else taper_factory)

    connector = round_corners(way_points, bend90, straight_factory, taper)
    return connector
Ejemplo n.º 3
0
def gen_loopback(
    start_port,
    end_port,
    gc,
    grating_separation=127.0,
    gc_rotation=-90,
    gc_port_name="W0",
    bend_radius_align_ports=10.0,
    bend_factory=bend_circular,
    waveguide_factory=waveguide,
    y_bot_align_route=None,
):
    """
    Add a loopback w.r.t a start port and and end port
    Input grating generated on the left of start_port
    Output grating generated on the right of end_port
    """

    if hasattr(start_port, "y"):
        y0 = start_port.y
    else:
        y0 = start_port[1]

    if hasattr(start_port, "x"):
        x0 = start_port.x - grating_separation
    else:
        x0 = start_port[0] - grating_separation

    if hasattr(end_port, "x"):
        x1 = end_port.x + grating_separation
    else:
        x1 = end_port[0] + grating_separation

    gca1, gca2 = [
        gc.ref(position=(x, y0), rotation=gc_rotation, port_id=gc_port_name)
        for x in [x0, x1]
    ]

    gsi = gc.size_info
    p0 = gca1.ports[gc_port_name].position
    p1 = gca2.ports[gc_port_name].position
    a = bend_radius_align_ports + 0.5
    b = max(2 * a, grating_separation / 2)
    if y_bot_align_route == None:
        y_bot_align_route = -gsi.width - 5.0

    route = [
        p0,
        p0 + (0, a),
        p0 + (b, a),
        p0 + (b, y_bot_align_route),
        p1 + (-b, y_bot_align_route),
        p1 + (-b, a),
        p1 + (0, a),
        p1,
    ]
    bend90 = bend_factory(radius=bend_radius_align_ports)
    loop_back = round_corners(route, bend90, waveguide_factory)
    elements = [gca1, gca2, loop_back]
    return elements
Ejemplo n.º 4
0
Archivo: add_gc.py Proyecto: tvt173/ubc
def connect_strip(
    way_points=[],
    bend_factory=bend_circular,
    straight_factory=waveguide,
    bend_radius=10.0,
    wg_width=0.5,
    **kwargs,
):
    """
    Returns a deep-etched route formed by the given way_points with
    bends instead of corners and optionally tapers in straight sections.
    """
    bend90 = bend_factory(radius=bend_radius, width=wg_width)
    connector = round_corners(way_points, bend90, straight_factory)
    return connector
Ejemplo n.º 5
0
def connect_loop_back(port0, port1, a, b, R, y_bot_align_route):
    p0 = port0.position
    p1 = port1.position
    route = [
        p0,
        p0 + (0, a),
        p0 + (b, a),
        p0 + (b, y_bot_align_route),
        p1 + (-b, y_bot_align_route),
        p1 + (-b, a),
        p1 + (0, a),
        p1,
    ]

    bend90 = pp.c.bend_circular(radius=R)
    loop_back = round_corners(route, bend90, pp.c.waveguide)
    return loop_back
def connect_loop_back(port0: Port, port1: Port, a, b, R,
                      y_bot_align_route) -> ComponentReference:
    p0 = port0.position
    p1 = port1.position
    route = [
        p0,
        p0 + (0, a),
        p0 + (b, a),
        p0 + (b, y_bot_align_route),
        p1 + (-b, y_bot_align_route),
        p1 + (-b, a),
        p1 + (0, a),
        p1,
    ]

    bend90 = pp.c.bend_circular(radius=R)
    return round_corners(route, bend90, pp.c.waveguide)["references"]
Ejemplo n.º 7
0
def connect_elec_waypoints(way_points,
                           bend_factory=corner,
                           straight_factory=wire,
                           taper_factory=taper_factory,
                           wg_width=10.0,
                           layer=LAYER.M3,
                           **kwargs):
    """returns a route with electrical traces"""

    bend90 = bend_factory(width=wg_width, layer=layer)

    def _straight_factory(length=10.0, width=wg_width):
        return straight_factory(length=length, width=width, layer=layer)

    connector = round_corners(way_points,
                              bend90,
                              _straight_factory,
                              taper=None)
    return connector
Ejemplo n.º 8
0
def connect_elec_waypoints(way_points=[],
                           bend_factory=bend_circular,
                           straight_factory=waveguide,
                           taper_factory=taper_factory,
                           bend_radius=10.0,
                           wg_width=0.5,
                           layer=LAYER.WG,
                           **kwargs):

    bend90 = bend_factory(width=wg_width, radius=bend_radius, layer=layer)

    def _straight_factory(length=10.0, width=wg_width):
        return straight_factory(length=length, width=width, layer=layer)

    if "bend_radius" in kwargs:
        bend_radius = kwargs.pop("bend_radius")
    else:
        bend_radius = 10

    connector = round_corners(way_points,
                              bend90,
                              _straight_factory,
                              taper=None)
    return connector
def connect_bundle_waypoints(start_ports,
                             end_ports,
                             way_points,
                             straight_factory=waveguide,
                             taper_factory=taper_factory,
                             bend_factory=bend_circular,
                             bend_radius=10.0,
                             auto_sort=True,
                             **kwargs):
    """
    start_ports: a list of ports
    end_ports: a list of ports
    way_points: a list of points defining a route
        with way_points[0] = start_ports[0] 
        way_points[-1] = end_ports[0]
    
    """
    if len(end_ports) != len(start_ports):
        raise ValueError(
            "Number of start ports should match number of end ports.\
        Got {} {}".format(len(start_ports), len(end_ports)))

    for p in start_ports:
        p.angle = int(p.angle) % 360

    for p in end_ports:
        p.angle = int(p.angle) % 360

    start_angle = start_ports[0].orientation
    end_angle = end_ports[0].orientation
    """
    Sort the ports such that the bundle connect the correct 
    corresponding ports.
    """

    angles_to_sorttypes = {
        (0, 180): ("Y", "Y"),
        (0, 90): ("Y", "X"),
        (0, 0): ("Y", "-Y"),
        (0, 270): ("Y", "-X"),
        (90, 0): ("X", "Y"),
        (90, 90): ("X", "-X"),
        (90, 180): ("X", "-Y"),
        (90, 270): ("X", "X"),
        (180, 90): ("Y", "-X"),
        (180, 0): ("Y", "Y"),
        (180, 270): ("Y", "X"),
        (180, 180): ("Y", "-Y"),
        (270, 90): ("X", "X"),
        (270, 270): ("X", "-X"),
        (270, 0): ("X", "-Y"),
        (270, 180): ("X", "Y"),
    }

    dict_sorts = {
        "X": lambda p: p.x,
        "Y": lambda p: p.y,
        "-X": lambda p: -p.x,
        "-Y": lambda p: -p.y,
    }
    key = (start_angle, end_angle)
    sp_st, ep_st = angles_to_sorttypes[key]
    start_port_sort = dict_sorts[sp_st]
    end_port_sort = dict_sorts[ep_st]

    if auto_sort:
        start_ports.sort(key=start_port_sort)
        end_ports.sort(key=end_port_sort)

    routes = _generate_manhattan_bundle_waypoints(start_ports, end_ports,
                                                  way_points, **kwargs)

    bends90 = [
        bend_factory(radius=bend_radius, width=p.width) for p in start_ports
    ]

    if taper_factory != None:
        if type(taper_factory) == type(lambda a: a):
            taper = taper_factory(
                length=TAPER_LENGTH,
                width1=start_ports[0].width,
                width2=WG_EXPANDED_WIDTH,
                layer=start_ports[0].layer,
            )
        else:
            # In this case the taper is a fixed cell
            taper = taper_factory
    else:
        taper = None
    connections = [
        round_corners(pts, bend90, straight_factory, taper=taper)
        for pts, bend90 in zip(routes, bends90)
    ]
    return connections
Ejemplo n.º 10
0
def add_gratings_and_loop_back(
    component,
    grating_coupler=grating_coupler_te,
    excluded_ports=[],
    grating_separation=127.0,
    bend_radius_align_ports=10.0,
    gc_port_name=None,
    gc_rotation=-90,
    waveguide_separation=5.0,
    bend_factory=bend_circular,
    waveguide_factory=waveguide,
    layer_label=pp.layer("TEXT"),
    # input_port_indexes=[0],
    name=None,
    component_name=None,
):
    """ returns a component with grating_couplers and loopback
    """

    direction = "S"
    component_name = component.name
    name = name or component_name or f"{component_name}_c"
    c = pp.Component(name=name)
    c.add_ref(component)
    gc = pp.call_if_func(grating_coupler)

    # Find grating port name if not specified
    if gc_port_name is None:
        gc_port_name = list(gc.ports.values())[0].name

    # List the optical ports to connect
    optical_ports = component.get_optical_ports()
    optical_ports = [p for p in optical_ports if p.name not in excluded_ports]
    optical_ports = direction_ports_from_list_ports(optical_ports)[direction]

    # Check if the ports are equally spaced
    grating_separation_extracted = check_ports_have_equal_spacing(
        optical_ports)
    if grating_separation_extracted != grating_separation:
        raise ValueError("Grating separation must be {}. Got {}".format(
            grating_separation, grating_separation_extracted))

    # Add grating couplers
    couplers = []
    for port in optical_ports:
        coupler_ref = c.add_ref(gc)
        coupler_ref.connect(list(coupler_ref.ports.values())[0].name, port)
        couplers += [coupler_ref]

    # add labels
    for i, optical_port in enumerate(optical_ports):
        label = get_input_label(
            optical_port,
            couplers[i],
            i,
            component_name=component_name,
            layer_label=layer_label,
        )
        c.add(label)

    # Add loopback
    y0 = couplers[0].ports[gc_port_name].y
    xs = [p.x for p in optical_ports]
    x0 = min(xs) - grating_separation
    x1 = max(xs) + grating_separation

    gca1, gca2 = [
        gc.ref(position=(x, y0), rotation=gc_rotation, port_id=gc_port_name)
        for x in [x0, x1]
    ]

    gsi = gc.size_info
    p0 = gca1.ports[gc_port_name].position
    p1 = gca2.ports[gc_port_name].position
    a = bend_radius_align_ports + 0.5
    b = max(2 * a, grating_separation / 2)
    y_bot_align_route = -gsi.width - waveguide_separation

    route = [
        p0,
        p0 + (0, a),
        p0 + (b, a),
        p0 + (b, y_bot_align_route),
        p1 + (-b, y_bot_align_route),
        p1 + (-b, a),
        p1 + (0, a),
        p1,
    ]
    bend90 = bend_factory(radius=bend_radius_align_ports)
    loop_back = round_corners(route, bend90, waveguide_factory)
    elements = [gca1, gca2, loop_back]
    c.add(elements)
    return c
Ejemplo n.º 11
0
def route_fiber_array(
    component: Component,
    optical_io_spacing: float = SPACING_GC,
    grating_coupler: Callable = grating_coupler_te,
    bend_factory: Callable = bend_circular,
    straight_factory: Callable = waveguide,
    fanout_length: Optional[int] = None,
    max_y0_optical: None = None,
    with_align_ports: bool = True,
    waveguide_separation: float = 4.0,
    optical_routing_type: Optional[int] = None,
    bend_radius: float = BEND_RADIUS,
    connected_port_list_ids: None = None,
    nb_optical_ports_lines: int = 1,
    force_manhattan: bool = False,
    excluded_ports: List[Any] = None,
    grating_indices: None = None,
    route_filter: Callable = connect_strip_way_points,
    gc_port_name: str = "W0",
    gc_rotation: int = -90,
    layer_label: Tuple[int, int] = LAYER.LABEL,
    component_name: Optional[str] = None,
    x_grating_offset: int = 0,
    optical_port_labels: None = None,
    route_factory: Callable = route_south,
    get_input_labels_function: Callable = get_input_labels,
    select_ports: Callable = select_optical_ports,
) -> Tuple[
    List[Union[ComponentReference, Label]], List[List[ComponentReference]], float64
]:
    """
    Returns component I/O elements for adding grating couplers with a fiber array input
    Many components are fine with the default.

    Args:
        component: The component to connect.
        optical_io_spacing: the wanted spacing between the optical I/O
        grating_coupler: grating coupler instance, function or list of functions
        bend_factory: bend_circular
        straight_factory: waveguide
        fanout_length: Wanted distance between the gratings and the southest component port. If None, automatically calculated.
        max_y0_optical: Maximum y coordinate at which the intermediate optical ports can be set. Usually fine to leave at None.
        with_align_ports: If True, add compact loopback alignment ports
        waveguide_separation: min separation between the waveguides used to route grating couplers to the component I/O.
        optical_routing_type: There are three options for optical routing
           * ``0`` is very basic but can be more compact.  Can also be used in combination with ``connected_port_list_ids`` or to route some components which otherwise fail with type ``1``.
           * ``1`` is the standard routing.
           * ``2`` uses the optical ports as a guideline for the component's physical size (instead of using the actual component size).  Useful where the component is large due to metal tracks
           * ``None: leads to an automatic decision based on size and number
           of I/O of the component.
        bend_radius: bend radius
        connected_port_list_ids: only for type 0 optical routing.  Can specify which ports goes to which grating assuming the gratings are ordered from left to right.  e.g ['N0', 'W1','W0','E0','E1', 'N1' ] or [4,1,7,3]
        nb_optical_ports_lines: number of lines with I/O grating couplers.  One line by default.  WARNING: Only works properly if:
            - nb_optical_ports_lines divides the total number of ports
            - the components have an equal number of inputs and outputs
        force_manhattan: in some instances, the port linker defaults to an S-bend due to lack of space to do manhattan. Force manhattan offsets all the ports to replace the s-bend by a straight link.  This fails if multiple ports have the same issue
        excluded_ports: ports excluded from routing
        grating_indices: allows to fine skip some grating slots e.g [0,1,4,5] will put two gratings separated by the pitch. Then there will be two empty grating slots, and after that an additional two gratings.
        route_filter: waveguide and bend factories
        gc_port_name: grating_coupler port name, where to route waveguides
        gc_rotation: grating_coupler rotation (deg)
        layer_label: for TM labels
        component_name: name of component
        x_grating_offset: x offset
        optical_port_labels: port labels that need connection
        route_factory: factories for route
        get_input_labels_function: functions to add labels
        select_ports: function to select ports

    Returns:
        elements, io_grating_lines, y0_optical
    """
    component_name = component_name or component.name
    excluded_ports = excluded_ports or []
    if optical_port_labels is None:
        # for pn, p in component.ports.items():
        #     print(p.name, p.port_type, p.layer)
        # optical_ports = component.get_ports_list(port_type='optical')
        optical_ports = list(select_ports(component.ports).values())
        # print(optical_ports)
    else:
        optical_ports = [component.ports[lbl] for lbl in optical_port_labels]

    optical_ports = [p for p in optical_ports if p.name not in excluded_ports]
    N = len(optical_ports)
    if N == 0:
        return [], [], 0

    elements = []

    # grating_coupler can either be a component/function
    # or a list of components/functions

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

    assert (
        gc_port_name in grating_coupler.ports
    ), f"{gc_port_name} not in {list(grating_coupler.ports.keys())}"

    # Now:
    # - grating_coupler is a single grating coupler
    # - grating_couplers is a list of grating couplers
    # Define the route filter to apply to connection methods

    route_filter_params = {
        "bend_radius": bend_radius,
        "wg_width": grating_coupler.ports[gc_port_name].width,
    }

    def routing_method(p1, p2, **kwargs):
        way_points = get_waypoints_connect_strip(p1, p2, **kwargs)
        return route_filter(way_points, **route_filter_params)

    R = bend_radius

    # `delta_gr_min` Used to avoid crossing between waveguides in special cases
    # This could happen when abs(x_port - x_grating) <= 2 * bend_radius

    delta_gr_min = 2 * bend_radius + 1

    io_sep = optical_io_spacing
    offset = (N - 1) * io_sep / 2.0

    # Get the center along x axis
    x_c = round(sum([p.x for p in optical_ports]) / N, 1)
    y_min = component.ymin  # min([p.y for p in optical_ports])

    # Sort the list of optical ports:
    direction_ports = direction_ports_from_list_ports(optical_ports)
    sep = waveguide_separation

    K = len(optical_ports)
    K = K + 1 if K % 2 else K

    # Set routing type if not specified
    pxs = [p.x for p in optical_ports]
    is_big_component = (
        (K > 2)
        or (max(pxs) - min(pxs) > io_sep - delta_gr_min)
        or (component.xsize > io_sep)
    )
    if optical_routing_type is None:
        if not is_big_component:
            optical_routing_type = 0
        else:
            optical_routing_type = 1

    """
    Look at a bunch of conditions to choose the default length
    if the default fanout distance is not set
    """

    def has_p(side):
        return len(direction_ports[side]) > 0

    list_ew_ports_on_sides = [has_p(side) for side in ["E", "W"]]
    list_ns_ports_on_sides = [has_p(side) for side in ["N", "S"]]

    has_ew_ports = any(list_ew_ports_on_sides)
    has_ns_ports = any(list_ns_ports_on_sides)

    is_one_sided_horizontal = False
    for side1, side2 in [("E", "W"), ("W", "E")]:
        if len(direction_ports[side1]) >= 2:
            if all([len(direction_ports[side]) == 0 for side in ["N", "S", side2]]):
                is_one_sided_horizontal = True

    # Compute fanout length if not specified
    if fanout_length is None:
        fanout_length = bend_radius + 1.0
        # We need 3 bends in that case to connect the most bottom port to the
        # grating couplers
        if has_ew_ports and is_big_component:
            fanout_length = max(fanout_length, 3 * bend_radius + 1.0)

        if has_ns_ports or is_one_sided_horizontal:
            fanout_length = max(fanout_length, 2 * bend_radius + 1.0)

        if has_ew_ports and not is_big_component:
            fanout_length = max(fanout_length, bend_radius + 1.0)

    fanout_length += 5
    # use x for grating coupler since we rotate it
    y0_optical = y_min - fanout_length - grating_coupler.ports[gc_port_name].x
    y0_optical += -K / 2 * sep
    y0_optical = round(y0_optical, 1)

    if max_y0_optical is not None:
        y0_optical = round(min(max_y0_optical, y0_optical), 1)
    """
     - First connect half of the north ports going from middle of list
    down to first elements
     - then connect west ports (top to bottom)
     - then connect south ports (left to right)
     - then east ports (bottom to top)
     - then second half of the north ports (right to left)

    """
    north_ports = direction_ports["N"]
    north_start = north_ports[0 : len(north_ports) // 2]
    north_finish = north_ports[len(north_ports) // 2 :]

    west_ports = direction_ports["W"]
    west_ports.reverse()
    east_ports = direction_ports["E"]
    south_ports = direction_ports["S"]
    north_finish.reverse()  # Sort right to left
    north_start.reverse()  # Sort right to left
    ordered_ports = north_start + west_ports + south_ports + east_ports + north_finish

    nb_ports_per_line = N // nb_optical_ports_lines
    grating_coupler_si = grating_coupler.size_info
    y_gr_gap = (K / (nb_optical_ports_lines) + 1) * sep
    gr_coupler_y_sep = grating_coupler_si.height + y_gr_gap + bend_radius

    offset = (nb_ports_per_line - 1) * io_sep / 2 - x_grating_offset
    io_gratings_lines = []  # [[gr11, gr12, gr13...], [gr21, gr22, gr23...] ...]

    if grating_indices is None:
        grating_indices = list(range(nb_ports_per_line))
    else:
        assert len(grating_indices) == nb_ports_per_line

    for j in range(nb_optical_ports_lines):
        io_gratings = [
            gc.ref(
                position=(x_c - offset + i * io_sep, y0_optical - j * gr_coupler_y_sep),
                rotation=gc_rotation,
                port_id=gc_port_name,
            )
            for i, gc in zip(grating_indices, grating_couplers)
        ]

        io_gratings_lines += [io_gratings[:]]

    # optical routing - type ``0``
    if optical_routing_type == 0:
        """
        Basic optical routing, typically fine for small components
        No heuristic to avoid collisions between connectors.

        If specified ports to connect in a specific order
        (i.e if connected_port_list_ids is not None and not empty)
        then grab these ports
        """

        if connected_port_list_ids:
            ordered_ports = [component.ports[i] for i in connected_port_list_ids]

        for io_gratings in io_gratings_lines:
            for i in range(N):
                p0 = io_gratings[i].ports[gc_port_name]
                p1 = ordered_ports[i]
                elements.extend(
                    routing_method(p0, p1, bend_radius=bend_radius)["references"]
                )

    # optical routing - type ``1 or 2``
    elif optical_routing_type in [1, 2]:
        elems, to_route = route_factory(
            component=component,
            bend_radius=bend_radius,
            optical_routing_type=optical_routing_type,
            excluded_ports=excluded_ports,
            waveguide_separation=waveguide_separation,
            io_gratings_lines=io_gratings_lines,
            gc_port_name=gc_port_name,
            route_filter=route_filter,
        )
        elements.extend(elems)

        if force_manhattan:
            """
            1) find the min x_distance between each grating port and
            each component port.
            2) If abs(min distance) < 2* bend radius
                then offset io_gratings by -min_distance
            """
            min_dist = 2 * R + 10.0
            min_dist_threshold = 2 * R + 1.0
            for io_gratings in io_gratings_lines:
                for gr in io_gratings:
                    for p in to_route:
                        dist = gr[0].x - p.x
                        if abs(dist) < abs(min_dist):
                            min_dist = dist
                if abs(min_dist) < min_dist_threshold:
                    for gr in io_gratings:
                        gr.translate((-min_dist, 0))

        # If the array of gratings is too close, adjust its location
        gc_ports_tmp = []
        for io_gratings in io_gratings_lines:
            gc_ports_tmp += [gc.ports[gc_port_name] for gc in io_gratings]
        min_y = get_min_spacing(to_route, gc_ports_tmp, sep=sep, radius=R)
        delta_y = abs(to_route[0].y - gc_ports_tmp[0].y)

        if min_y > delta_y:
            for io_gratings in io_gratings_lines:
                for gr in io_gratings:
                    gr.translate(0, delta_y - min_y)

        # If we add align ports, we need enough space for the bends
        end_straight_offset = waveguide_separation + 5 if with_align_ports else 0.01
        if len(io_gratings_lines) == 1:
            io_gratings = io_gratings_lines[0]
            gc_ports = [gc.ports[gc_port_name] for gc in io_gratings]
            routes = link_optical_ports(
                to_route,
                gc_ports,
                separation=sep,
                end_straight_offset=end_straight_offset,
                route_filter=route_filter,
                **route_filter_params,
            )
            elements.extend([route["references"] for route in routes])

        else:
            for io_gratings in io_gratings_lines:
                gc_ports = [gc.ports[gc_port_name] for gc in io_gratings]
                nb_gc_ports = len(io_gratings)
                nb_ports_to_route = len(to_route)
                n0 = nb_ports_to_route / 2
                dn = nb_gc_ports / 2
                routes = link_optical_ports(
                    to_route[n0 - dn : n0 + dn],
                    gc_ports,
                    separation=sep,
                    end_straight_offset=end_straight_offset,
                    route_filter=route_filter,
                    **route_filter_params,
                )
                elements.extend([route["references"] for route in routes])
                del to_route[n0 - dn : n0 + dn]

    if with_align_ports:
        gca1, gca2 = [
            grating_coupler.ref(
                position=(
                    x_c - offset + ii * io_sep,
                    io_gratings_lines[-1][0].ports[gc_port_name].y,
                ),
                rotation=gc_rotation,
                port_id=gc_port_name,
            )
            for ii in [grating_indices[0] - 1, grating_indices[-1] + 1]
        ]

        gsi = grating_coupler.size_info
        p0 = gca1.ports[gc_port_name].position
        p1 = gca2.ports[gc_port_name].position
        bend_radius_align_ports = R
        a = bend_radius_align_ports + 5.0  # 0.5
        b = max(2 * a, io_sep / 2)
        y_bot_align_route = -gsi.width - waveguide_separation

        route = [
            p0,
            p0 + (0, a),
            p0 + (b, a),
            p0 + (b, y_bot_align_route),
            p1 + (-b, y_bot_align_route),
            p1 + (-b, a),
            p1 + (0, a),
            p1,
        ]
        elements.extend([gca1, gca2])

        bend90 = bend_factory(radius=bend_radius)
        route = round_corners(route, bend90, straight_factory)
        elements.extend(route["references"])

    elements.extend(
        get_input_labels_function(
            io_gratings, ordered_ports, component_name, layer_label, gc_port_name
        )
    )

    return elements, io_gratings_lines, y0_optical
Ejemplo n.º 12
0
def delay_snake(
    wg_width: float = 0.5,
    total_length: float = 160000.0,
    L0: float = 2350.0,
    n: int = 5,
    taper: Callable = taper_function,
    bend_factory: Callable = bend_circular,
    bend_radius: float = 10.0,
    straight_factory: Callable = waveguide_function,
) -> Component:
    """ Snake input facing west
    Snake output facing east

    Args:
        wg_width
        total_length:
        L0: initial offset
        n: number of loops
        taper: taper factory
        bend_factory
        bend_radius
        straight_factory

    .. code::

       | L0 |    L2        |

            ->-------------|
                           | pi * radius
       |-------------------|
       |
       |------------------->

       |        DL         |

    .. plot::
      :include-source:

      import pp

      c = pp.c.delay_snake(L0=5, total_length=1600, n=2)
      pp.plotgds(c)

    """
    epsilon = 0.1
    R = bend_radius
    bend90 = bend_factory(radius=R, width=wg_width)
    DL = (total_length + L0 - n * (pi * R + epsilon)) / (2 * n + 1)
    L2 = DL - L0
    assert (
        L2 > 0
    ), "Snake is too short: either reduce L0, increase the total length,\
    or decrease n"

    y = 0
    path = [(0, y), (L2, y)]
    for i in range(n):
        y -= 2 * R + epsilon
        path += [(L2, y), (-L0, y)]
        y -= 2 * R + epsilon
        path += [(-L0, y), (L2, y)]

    path = [(round(_x, 3), round(_y, 3)) for _x, _y in path]

    component = pp.Component()
    if taper:
        _taper = taper(width1=wg_width, width2=WG_EXPANDED_WIDTH, length=TAPER_LENGTH)
    snake = round_corners(path, bend90, straight_factory, taper=_taper)
    component.add(snake)
    component.ports = snake.ports

    pp.port.auto_rename_ports(component)
    return component
Ejemplo n.º 13
0
def gen_loopback(
    start_port: Port,
    end_port: Port,
    gc: Callable,
    grating_separation: float = 127.0,
    gc_rotation: int = -90,
    gc_port_name: str = "W0",
    bend_radius_align_ports: float = 10.0,
    bend_factory: Callable = bend_circular,
    waveguide_factory: Callable = waveguide,
    y_bot_align_route=None,
) -> List[ComponentReference]:
    """
    Add a loopback (grating coupler align reference) to a start port and and end port
    Input grating generated on the left of start_port
    Output grating generated on the right of end_port

    .. code::

        __________________________________________
        | separation  |            |              |
        |             |            |              |
       GC          start_port  end_port          GC

    """

    gc = gc() if callable(gc) else gc

    if hasattr(start_port, "y"):
        y0 = start_port.y
    else:
        y0 = start_port[1]

    if hasattr(start_port, "x"):
        x0 = start_port.x - grating_separation
    else:
        x0 = start_port[0] - grating_separation

    if hasattr(end_port, "x"):
        x1 = end_port.x + grating_separation
    else:
        x1 = end_port[0] + grating_separation

    gca1, gca2 = [
        gc.ref(position=(x, y0), rotation=gc_rotation, port_id=gc_port_name)
        for x in [x0, x1]
    ]

    gsi = gc.size_info
    p0 = gca1.ports[gc_port_name].position
    p1 = gca2.ports[gc_port_name].position
    a = bend_radius_align_ports + 0.5
    b = max(2 * a, grating_separation / 2)
    y_bot_align_route = (y_bot_align_route if y_bot_align_route is not None
                         else -gsi.width - 5.0)

    route = [
        p0,
        p0 + (0, a),
        p0 + (b, a),
        p0 + (b, y_bot_align_route),
        p1 + (-b, y_bot_align_route),
        p1 + (-b, a),
        p1 + (0, a),
        p1,
    ]
    bend90 = bend_factory(radius=bend_radius_align_ports)
    route = round_corners(route, bend90, waveguide_factory)
    elements = [gca1, gca2]
    elements.extend(route["references"])
    return elements
Ejemplo n.º 14
0
def delay_snake(
    total_length=160000,
    L0=2350.0,
    n=5,
    taper=taper,
    bend_factory=bend_circular,
    bend_radius=10.0,
    straight_factory=waveguide,
    wg_width=0.5,
):
    """ Snake input facing west
    Snake output facing east

    Args:
        total_length:
        L0:
        n:
        taper:
        bend_factory
        bend_radius
        straight_factory
        wg_width

    .. code::

       | L0 |    L2        |

            ->-------------|
                           | pi * radius
       |-------------------|
       |
       |------------------->

       |        L1         |

    .. plot::
      :include-source:

      import pp

      c = pp.c.delay_snake(L0=5, total_length=1600, n=2)
      pp.plotgds(c)

    """
    epsilon = 0.1
    R = bend_radius
    bend90 = bend_factory(radius=R, width=wg_width)
    L1 = (total_length + L0 - n * (pi * R + epsilon)) / (2 * n + 1)
    L2 = L1 - L0
    assert (
        L2 >
        0), "Snake is too short: either reduce L0, increase the total length,\
    or decrease n"

    y = 0
    path = [(0, y), (L2, y)]
    for i in range(n):
        y -= 2 * R + epsilon
        path += [(L2, y), (-L0, y)]
        y -= 2 * R + epsilon
        path += [(-L0, y), (L2, y)]

    path = [(round(_x, 3), round(_y, 3)) for _x, _y in path]

    component = pp.Component()
    if taper != None:
        if callable(taper):
            _taper = taper(width1=wg_width,
                           width2=WG_EXPANDED_WIDTH,
                           length=TAPER_LENGTH)
        else:
            _taper = taper
    else:
        _taper = None
    snake = round_corners(path, bend90, straight_factory, taper=_taper)
    component.add(snake)
    component.ports = snake.ports

    pp.ports.port_naming.auto_rename_ports(component)
    return component