Exemplo n.º 1
0
def bend_s(width=0.5, height=2, length=10, layer=pp.LAYER.WG, nb_points=99):
    """ S bend
    Based on bezier curve

    Args:
        width
        height: in y direction
        length: in x direction
        layer: gds number
        nb_points: number of points

    .. plot::
      :include-source:

      import pp

      c = pp.c.bend_s(width=0.5, height=20)
      pp.plotgds(c)

    """
    l, h = length, height
    c = bezier(
        width=width,
        control_points=[(0, 0), (l / 2, 0), (l / 2, h), (l, h)],
        t=np.linspace(0, 1, nb_points),
        layer=layer,
    )
    c.add_port(name="W0", port=c.ports.pop("0"))
    c.add_port(name="E0", port=c.ports.pop("1"))

    # c.ports["W0"] = c.ports.pop("0")
    # c.ports["E0"] = c.ports.pop("1")
    return c
Exemplo n.º 2
0
def bend_s_biased(width=0.5, height=2, length=10, layer=pp.LAYER.WG, nb_points=99):
    l, h = length, height
    return bezier(
        width=pp.bias.width(width),
        control_points=[(0, 0), (l / 2, 0), (l / 2, h), (l, h)],
        t=np.linspace(0, 1, nb_points),
        layer=layer,
    )
Exemplo n.º 3
0
def bend_s(
    width: float = 0.5,
    height: float = 2.0,
    length: float = 10.0,
    layer: Tuple[int, int] = pp.LAYER.WG,
    nb_points: int = 99,
    layers_cladding: List[Tuple[int, int]] = [pp.LAYER.WGCLAD],
    cladding_offset: float = 3.0,
) -> Component:
    """ S bend
    Based on bezier curve

    Args:
        width
        height: in y direction
        length: in x direction
        layer: gds number
        nb_points: number of points

    .. plot::
      :include-source:

      import pp

      c = pp.c.bend_s(width=0.5, height=20)
      pp.plotgds(c)

    """
    l, h = length, height
    c = bezier(
        width=width,
        control_points=[(0, 0), (l / 2, 0), (l / 2, h), (l, h)],
        t=np.linspace(0, 1, nb_points),
        layer=layer,
    )
    c.add_port(name="W0", port=c.ports.pop("0"))
    c.add_port(name="E0", port=c.ports.pop("1"))

    y = cladding_offset
    points = [
        [c.xmin, c.ymin - y],
        [c.xmax, c.ymin - y],
        [c.xmax, c.ymax + y],
        [c.xmin, c.ymax + y],
    ]
    for layer in layers_cladding:
        c.add_polygon(points, layer=layer)

    # c.ports["W0"] = c.ports.pop("0")
    # c.ports["E0"] = c.ports.pop("1")
    return c
Exemplo n.º 4
0
def package_optical2x2(
    component: Component,
    port_spacing: float = 20.0,
    bend_length: Optional[float] = None,
):
    """returns component with port_spacing"""

    comp = component() if callable(component) else component

    if bend_length is None:
        bend_length = port_spacing
    dx = bend_length
    dy = port_spacing / 2.0

    p_w0 = comp.ports["W0"].midpoint
    p_e0 = comp.ports["E0"].midpoint
    p_w1 = comp.ports["W1"].midpoint
    p_e1 = comp.ports["E1"].midpoint

    c = pp.Component(f"{comp.name}_{int(port_spacing)}")
    c << comp

    t = np.linspace(0, 1, 101)

    y0 = p_e1[1]
    control_points = [(0, 0), (dx / 2, 0), (dx / 2, dy - y0), (dx, dy - y0)]

    bezier_bend_t = bezier(control_points=control_points,
                           t=t,
                           start_angle=0,
                           end_angle=0)

    b_tr = bezier_bend_t.ref(port_id="0", position=p_e1)
    b_br = bezier_bend_t.ref(port_id="0", position=p_e0, v_mirror=True)
    b_tl = bezier_bend_t.ref(port_id="0", position=p_w1, h_mirror=True)
    b_bl = bezier_bend_t.ref(port_id="0", position=p_w0, rotation=180)

    c.add([b_tr, b_br, b_tl, b_bl])

    c.add_port("W0", port=b_bl.ports["1"])
    c.add_port("W1", port=b_tl.ports["1"])
    c.add_port("E0", port=b_br.ports["1"])
    c.add_port("E1", port=b_tr.ports["1"])

    c.info["min_bend_radius"] = bezier_bend_t.info["min_bend_radius"]

    for pname, p in c.ports.items():
        if p.port_type != "optical":
            c.add_port(pname, port=p)

    return c
Exemplo n.º 5
0
def package_optical2x2(component, port_spacing=20.0, bend_length=None):
    """ returns component with port_spacing
    """

    component = pp.call_if_func(component)

    if bend_length is None:
        bend_length = port_spacing
    dx = bend_length
    dy = port_spacing / 2

    p_w0 = component.ports["W0"].midpoint
    p_e0 = component.ports["E0"].midpoint
    p_w1 = component.ports["W1"].midpoint
    p_e1 = component.ports["E1"].midpoint

    c = pp.Component()
    c.add_ref(component)

    t = np.linspace(0, 1, 101)

    y0 = p_e1[1]
    control_points = [(0, 0), (dx / 2, 0), (dx / 2, dy - y0), (dx, dy - y0)]

    bezier_bend_t = bezier(control_points=control_points,
                           t=t,
                           start_angle=0,
                           end_angle=0)

    b_tr = bezier_bend_t.ref(port_id="0", position=p_e1)
    b_br = bezier_bend_t.ref(port_id="0", position=p_e0, v_mirror=True)
    b_tl = bezier_bend_t.ref(port_id="0", position=p_w1, h_mirror=True)
    b_bl = bezier_bend_t.ref(port_id="0", position=p_w0, rotation=180)

    c.add([b_tr, b_br, b_tl, b_bl])

    c.add_port("W0", port=b_bl.ports["1"])
    c.add_port("W1", port=b_tl.ports["1"])
    c.add_port("E0", port=b_br.ports["1"])
    c.add_port("E1", port=b_tr.ports["1"])

    c.info["min_bend_radius"] = bezier_bend_t.info["min_bend_radius"]

    return c
Exemplo n.º 6
0
def compensation_path(crossing45=crossing45, direction="top"):
    r""" Path with same path length as crossing45 but with input and output ports having same y coordinates

    Args:
        name: component name
        crossing45: the crossing45 component that we want to match in path length
            This component needs to have .info["components"] with bends and crossing
        direction: the direction in which the bend should go "top" / "bottom"

    Returns:
        <pp.Component> a compensation path



    crossing45:

    .. code::

          ----       ----
              \     /
               \   /
                \ /
                 X
                / \
               /   \
              /     \
          ----       ----

    Compensation path:

    .. code::

             --+--
           _/     \_
        --/         \--


    """
    # Get total path length taken by the bends
    crossing45 = pp.call_if_func(crossing45)
    X45_cmps = crossing45.info["components"]
    length = 2 * X45_cmps["bezier_bend"].info["length"]

    # Find a bezier S-bend with half this length, but with a fixed length
    # governed by the crossing45 X-distance (west to east ports) and
    # the crossing x_distance

    target_bend_length = length / 2

    def get_x_span(cmp):
        return cmp.ports["E0"].x - cmp.ports["W0"].x

    x_span_crossing45 = get_x_span(crossing45)
    x_span_crossing = get_x_span(X45_cmps["crossing"])

    # x span allowed for the bend
    x0 = (x_span_crossing45 - x_span_crossing) / 2

    def get_control_pts(x, y):
        return [(0, 0), (x0 / 2, 0), (x0 / 2, y), (x0, y)]

    def f(y):
        control_points = get_control_pts(x0, y)
        t = np.linspace(0, 1, 51)
        path_points = bezier_curve(t, control_points)
        return path_length(path_points) - target_bend_length

    # the path length of the s-bend between two ports p0 and p1 is :
    # - larger than the euclidian distance L2(p0, p1)
    # - smaller than the manhattan distance DL(p0, p1)
    #
    # This gives the bounds for the brentq root finding

    ya = target_bend_length - x0
    yb = np.sqrt(target_bend_length**2 - x0**2)

    solution = so.root_scalar(f, bracket=[ya, yb], method="brentq")

    y_bend = solution.root
    y_bend = rnd(y_bend)

    if direction == "top":
        v_mirror = False
    else:
        v_mirror = True

    sbend = bezier(control_points=get_control_pts(x0, y_bend))

    component = pp.Component()
    crossing0 = X45_cmps["crossing"].ref()
    component.add(crossing0)

    sbend_left = sbend.ref(position=crossing0.ports["W0"],
                           port_id="1",
                           v_mirror=v_mirror)
    sbend_right = sbend.ref(position=crossing0.ports["E0"],
                            port_id="1",
                            h_mirror=True,
                            v_mirror=v_mirror)

    component.add(sbend_left)
    component.add(sbend_right)

    # Add ports
    component.add_port("W0", port=sbend_left.ports["0"])
    component.add_port("E0", port=sbend_right.ports["0"])

    component.info["min_bend_radius"] = sbend.info["min_bend_radius"]
    component.info["components"] = {"sbend": sbend}

    return component
Exemplo n.º 7
0
def crossing45(crossing=crossing, port_spacing=40.0, dx=None, alpha=0.08):
    r""" 45Deg crossing with bends

    Args:
        crossing: 90D crossing
        port_spacing: target I/O port spacing
        dx: target length
        alpha: optimization parameter. Try with 0.1 to start with.
            - If the structure has too tight bends, diminish it.
            - If raise assertion angle errors, increase it


    Implementation note: The 45 Degree crossing CANNOT be kept as an SRef since
    we only allow for multiples of 90Deg rotations in SRef

    .. code::

        ----   ----
            \ /
             X
            / \
        ---    ----

    """

    crossing = crossing() if callable(crossing) else crossing

    c = pp.Component()
    _crossing = crossing.ref(rotation=45)
    c.add(_crossing)

    # Add bends
    p_e = _crossing.ports["E0"].midpoint
    p_w = _crossing.ports["W0"].midpoint
    p_n = _crossing.ports["N0"].midpoint
    p_s = _crossing.ports["S0"].midpoint

    # Flatten the crossing - not an SRef anymore
    c.absorb(_crossing)
    if dx is None:
        dx = port_spacing
    dy = port_spacing / 2

    t = np.linspace(0, 1, 101)

    start_angle = 45
    end_angle = 0
    cpts = find_min_curv_bezier_control_points(
        start_point=p_e,
        end_point=(dx, dy),
        start_angle=start_angle,
        end_angle=end_angle,
        t=t,
        alpha=alpha,
    )

    _bez_bend = bezier(
        control_points=cpts,
        t=t,
        start_angle=start_angle,
        end_angle=end_angle,
    )

    tol = 1e-2
    assert abs(_bez_bend.info["start_angle"] -
               start_angle) < tol, _bez_bend.info["start_angle"]
    assert abs(_bez_bend.info["end_angle"] -
               end_angle) < tol, _bez_bend.info["end_angle"]

    # print(abs(_bez_bend.info["start_angle"] - start_angle))
    # print(abs(_bez_bend.info["end_angle"] - end_angle))

    b_tr = _bez_bend.ref(position=p_e, port_id="0")
    b_tl = _bez_bend.ref(position=p_n, port_id="0", h_mirror=True)
    b_bl = _bez_bend.ref(position=p_w, port_id="0", rotation=180)
    b_br = _bez_bend.ref(position=p_s, port_id="0", v_mirror=True)

    for cmp_ref in [b_tr, b_br, b_tl, b_bl]:
        # cmp_ref = _cmp.ref()
        c.add(cmp_ref)
        c.absorb(cmp_ref)

    c.info["components"] = {"bezier_bend": _bez_bend, "crossing": crossing}

    c.info["min_bend_radius"] = b_br.info["min_bend_radius"]
    # print (b_tr.info["min_bend_radius"])
    c.add_port("E0", port=b_br.ports["1"])
    c.add_port("E1", port=b_tr.ports["1"])
    c.add_port("W0", port=b_bl.ports["1"])
    c.add_port("W1", port=b_tl.ports["1"])
    c.snap_ports_to_grid()
    return c