Beispiel #1
0
def align_wafer(
    width: float = 10.0,
    spacing: float = 10.0,
    cross_length: float = 80.0,
    layer: Tuple[int, int] = (1, 0),
    layer_cladding: Optional[Tuple[int, int]] = None,
    square_corner: str = "bottom_left",
) -> Component:
    """Returns cross inside a frame to align wafer."""
    c = Component()
    cross = gf.components.cross(length=cross_length, width=width, layer=layer)
    c.add_ref(cross)

    b = cross_length / 2 + spacing + width / 2
    w = width

    rh = rectangle(size=(2 * b + w, w), layer=layer, centered=True)
    rtop = c.add_ref(rh)
    rbot = c.add_ref(rh)
    rtop.movey(+b)
    rbot.movey(-b)

    rv = rectangle(size=(w, 2 * b), layer=layer, centered=True)
    rl = c.add_ref(rv)
    rr = c.add_ref(rv)
    rl.movex(-b)
    rr.movex(+b)

    wsq = (cross_length + 2 * spacing) / 4
    square_mark = c << rectangle(size=(wsq, wsq), layer=layer, centered=True)
    a = width / 2 + wsq / 2 + spacing

    corner_to_position = {
        "bottom_left": (-a, -a),
        "bottom_right": (a, -a),
        "top_right": (a, a),
        "top_left": (-a, a),
    }

    square_mark.move(corner_to_position[square_corner])

    if layer_cladding:
        rc_tile_excl = rectangle(
            size=(2 * (b + spacing), 2 * (b + spacing)),
            layer=layer_cladding,
            centered=True,
        )
        c.add_ref(rc_tile_excl)

    return c
Beispiel #2
0
def pads_shorted(
    pad: ComponentFactory = pad_function,
    columns: int = 8,
    pad_spacing: float = 150.0,
    layer_metal: Tuple[int, int] = LAYER.M3,
    metal_width: float = 10,
) -> Component:
    """Returns a 1D array of shorted_pads

    Args:
        pad: pad function
        columns: number of columns
        pad_spacing:
        layer_metal: for the short
        metal_width: for the short

    """
    c = Component(name="shorted_pads")
    pad = pad()
    for i in range(columns):
        pad_ref = c.add_ref(pad)
        pad_ref.movex(i * pad_spacing - columns / 2 * pad_spacing +
                      pad_spacing / 2)

    short = rectangle(
        size=(pad_spacing * (columns - 1), metal_width),
        layer=layer_metal,
        centered=True,
    )
    c.add_ref(short)
    return c
Beispiel #3
0
def pads_shorted(
    width: int = 100,
    n_pads: int = 8,
    pad_spacing: int = 150,
    layer: Tuple[int, int] = LAYER.M1,
) -> Component:
    c = Component(name="shorted_pads")
    pad = rectangle(size=(width, width), layer=layer, centered=True)
    for i in range(n_pads):
        pad_ref = c.add_ref(pad)
        pad_ref.movex(i * pad_spacing - n_pads / 2 * pad_spacing +
                      pad_spacing / 2)

    short = rectangle(size=(pad_spacing * (n_pads - 1), 10),
                      layer=layer,
                      centered=True)
    c.add_ref(short)
    return c
Beispiel #4
0
def add_frame(
    component: Component = rectangle,
    width: float = 10.0,
    spacing: float = 10.0,
    layer: Layer = (1, 0),
) -> Component:
    """Returns component with a frame around it.

    Args:
        component: Component to frame
        width: of the frame
        spacing: of component to frame

    """
    c = Component()
    component = component() if callable(component) else component
    cref = c.add_ref(component)
    cref.move(-c.size_info.center)
    y = (
        max([component.size_info.height, component.size_info.width]) / 2
        + spacing
        + width / 2
    )
    x = y
    w = width

    rh = rectangle(size=(2 * y + w, w), layer=layer, centered=True)
    rtop = c.add_ref(rh)
    rbot = c.add_ref(rh)
    rtop.movey(+y)
    rbot.movey(-y)

    rv = rectangle(size=(w, 2 * y), layer=layer, centered=True)
    rl = c.add_ref(rv)
    rr = c.add_ref(rv)
    rl.movex(-x)
    rr.movex(+x)
    c.absorb(cref)
    return c
Beispiel #5
0
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

    mbl = c << m
    mbl.mirror()
    mbl.xmax = r.xmin

    mtr = c << m
    mtr.mirror()
    mtr.rotate(180)
    mtr.xmin = r.xmax
    mtr.ymax = r.ymax

    mtl = c << m
    mtl.rotate(180)
    mtl.xmax = r.xmin
    mtl.ymax = r.ymax
    return c
Beispiel #6
0
def grating_coupler_rectangular_arbitrary(
    gaps: Floats = _gaps,
    widths: Floats = _widths,
    wg_width: float = 0.5,
    width_grating: float = 11.0,
    length_taper: float = 150.0,
    layer: Tuple[int, int] = gf.LAYER.WG,
    polarization: str = "te",
    wavelength: float = 1.55,
    taper: Optional[ComponentFactory] = taper_function,
    layer_grating: Optional[Layer] = None,
    layer_slab: Optional[Tuple[int, int]] = LAYER.SLAB150,
    slab_xmin: float = -1.0,
    slab_offset: float = 1.0,
) -> Component:
    r"""Grating coupler uniform (grating with rectangular shape not elliptical).
    Therefore it needs a longer taper.
    Grating teeth are straight instead of elliptical.

    Args:
        gaps: list of gaps
        widths: list of widths
        wg_width: input waveguide width
        width_grating:
        length_taper:
        layer: for grating teeth
        polarization: 'te' or 'tm'
        wavelength: in um
        taper: function
        layer_grating:
        layer_slab: layer that protects the slab under the grating
        slab_xmin: where 0 is at the start of the taper
        slab_offset: from edge of grating to edge of the slab

    .. code::

                      fiber

                   /  /  /  /
                  /  /  /  /

                _|-|_|-|_|-|___ layer
                   layer_slab |
            o1  ______________|



        top view     _________
                    /| | | | |
                   / | | | | |
                  /taper_angle
                 /_ _| | | | |
        wg_width |   | | | | |
                 \   | | | | |
                  \  | | | | |
                   \ | | | | |
                    \|_|_|_|_|
                 <-->
                taper_length

    """
    c = Component()

    if taper:
        taper_ref = c << taper(
            length=length_taper,
            width2=width_grating,
            width1=wg_width,
            layer=layer,
        )

        c.add_port(port=taper_ref.ports["o1"], name="o1")
        xi = taper_ref.xmax
    else:
        length_taper = 0
        xi = 0

    widths = gf.snap.snap_to_grid(widths)
    gaps = gf.snap.snap_to_grid(gaps)

    for width, gap in zip(widths, gaps):
        xi += gap + width / 2
        cgrating = c.add_ref(
            rectangle(
                size=[width, width_grating],
                layer=layer,
                port_type=None,
                centered=True,
            ))
        cgrating.x = gf.snap.snap_to_grid(xi)
        cgrating.y = 0
        xi += width / 2

    if layer_slab:
        slab_xmin += length_taper
        slab_xsize = xi + slab_offset
        slab_ysize = c.ysize + 2 * slab_offset
        yslab = slab_ysize / 2
        c.add_polygon(
            [
                (slab_xmin, yslab),
                (slab_xsize, yslab),
                (slab_xsize, -yslab),
                (slab_xmin, -yslab),
            ],
            layer_slab,
        )
    xport = np.round((xi + length_taper) / 2, 3)
    port_type = f"vertical_{polarization.lower()}"
    c.add_port(name=port_type,
               port_type=port_type,
               midpoint=(xport, 0),
               orientation=0)
    c.info.polarization = polarization
    c.info.wavelength = wavelength
    gf.asserts.grating_coupler(c)
    return c
def grating_coupler_rectangular(
    n_periods: int = 20,
    period: float = 0.75,
    fill_factor: float = 0.5,
    width_grating: float = 11.0,
    length_taper: float = 150.0,
    wg_width: float = 0.5,
    layer: Tuple[int, int] = gf.LAYER.WG,
    polarization: str = "te",
    wavelength: float = 1.55,
    taper: ComponentFactory = taper_function,
    layer_slab: Optional[Tuple[int, int]] = LAYER.SLAB150,
    slab_xmin: float = -1.0,
    slab_offset: float = 1.0,
) -> Component:
    r"""Grating coupler uniform (grating with rectangular shape not elliptical).
    Therefore it needs a longer taper.
    Grating teeth are straight.
    For a focusing grating take a look at grating_coupler_elliptical.


    Args:
        n_periods: number of grating teeth
        period: grating pitch
        fill_factor: ratio of grating width vs gap
        width_grating: 11
        length_taper: 150
        wg_width: input waveguide width
        layer: for grating teeth
        polarization: 'te' or 'tm'
        wavelength: in um
        taper: function
        layer_slab: layer that protects the slab under the grating
        slab_xmin: where 0 is at the start of the taper
        slab_offset: from edge of grating to edge of the slab

    .. code::

        side view
                      fiber

                   /  /  /  /
                  /  /  /  /

                _|-|_|-|_|-|___ layer
                   layer_slab |
            o1  ______________|


        top view     _________
                    /| | | | |
                   / | | | | |
                  /taper_angle
                 /_ _| | | | |
        wg_width |   | | | | |
                 \   | | | | |
                  \  | | | | |
                   \ | | | | |
                    \|_|_|_|_|
                 <-->
                taper_length
    """
    c = Component()
    taper_ref = c << taper_function(
        length=length_taper,
        width2=width_grating,
        width1=wg_width,
        layer=layer,
    )

    c.add_port(port=taper_ref.ports["o1"], name="o1")
    x0 = taper_ref.xmax

    for i in range(n_periods):
        xsize = gf.snap.snap_to_grid(period * fill_factor)
        cgrating = c.add_ref(
            rectangle(size=[xsize, width_grating], layer=layer,
                      port_type=None))
        cgrating.xmin = gf.snap.snap_to_grid(x0 + i * period)
        cgrating.y = 0

    xport = np.round((x0 + cgrating.x) / 2, 3)

    port_type = f"vertical_{polarization.lower()}"
    c.add_port(name=port_type,
               port_type=port_type,
               midpoint=(xport, 0),
               orientation=0)
    c.info.polarization = polarization
    c.info.wavelength = wavelength
    gf.asserts.grating_coupler(c)

    if layer_slab:
        slab_xmin += length_taper
        slab_xsize = cgrating.xmax + slab_offset
        slab_ysize = c.ysize + 2 * slab_offset
        yslab = slab_ysize / 2
        c.add_polygon(
            [
                (slab_xmin, yslab),
                (slab_xsize, yslab),
                (slab_xsize, -yslab),
                (slab_xmin, -yslab),
            ],
            layer_slab,
        )
    return c
def rectangle_with_slits(
    size: Tuple[float, float] = (100.0, 200.0),
    layer: Layer = (1, 0),
    layer_slit: Optional[Layer] = (2, 0),
    centered: bool = False,
    port_type: Optional[str] = None,
    slit_size: Tuple[float, float] = (1.0, 1.0),
    slit_spacing: Float2 = (20, 20),
    slit_enclosure: float = 10,
) -> Component:
    """Returns a rectangle with slits. Metal slits reduce stress.

    Args:
        size: (tuple) Width and height of rectangle.
        layer: Specific layer to put polygon geometry on.
        layer_slit: does a boolan NOT when None.
        centered: True sets center to (0, 0), False sets south-west to (0, 0)
        port_type: for the rectangle
        slit_size: x, y slit size
        slit_spacing: pitch_x, pitch_y for slits
        slit_enclosure: from slit to rectangle edge


    .. code::

        slit_enclosure
        _____________________________________
        |<--->                              |
        |                                   |
        |      ______________________       |
        |     |                      |      |
        |     |                      | slit_size[1]
        |     |______________________|      |
        |  |                                |
        |  | slit_spacing                   |
        |  |                                |  size[1]
        |  |   ______________________       |
        |  |  |                      |      |
        |  |  |                      |      |
        |  |  |______________________|      |
        |     <--------------------->       |
        |            slit_size[0]           |
        |___________________________________|
                        size[0]


    """
    c = Component()
    r = rectangle(size=size,
                  layer=layer,
                  port_type=port_type,
                  centered=centered)
    c.add_ports(r.ports)
    slit = rectangle(size=slit_size, port_type=None, layer=layer_slit or layer)

    columns = np.floor((size[0] - 2 * slit_enclosure) / slit_spacing[0])
    rows = np.floor((size[1] - 2 * slit_enclosure) / slit_spacing[1])
    slits = array(slit, columns=columns, rows=rows, spacing=slit_spacing).ref()
    slits.xmin = slit_enclosure
    slits.ymin = slit_enclosure

    if layer_slit:
        c << r
        c.add(slits)
    else:
        r_with_slits = c << gf.geometry.boolean(
            r, slits, operation="not", layer=layer)
        c.absorb(r_with_slits)
    return c
def grating_coupler_rectangular_arbitrary_slab(
    gaps: Floats = _gaps,
    widths: Floats = _widths,
    wg_width: float = 0.5,
    width_grating: float = 11.0,
    length_taper: float = 150.0,
    layer: Tuple[int, int] = gf.LAYER.WG,
    polarization: str = "te",
    wavelength: float = 1.55,
    taper: ComponentFactory = taper_strip_to_slab150,
    layer_slab: Optional[Layer] = gf.LAYER.SLAB150,
    slab_offset: float = 2.0,
) -> Component:
    r"""Grating coupler uniform (grating with rectangular shape not elliptical).
    Therefore it needs a longer taper.
    Grating teeth are straight instead of elliptical.

    Args:
        gaps: list of gaps
        widths: list of widths
        wg_width: input waveguide width
        width_grating:
        length_taper:
        layer: for grating teeth
        polarization: 'te' or 'tm'
        wavelength: in um
        taper: function
        layer_slab:
        slab_offset

    .. code::

        side view
                      fiber

                   /  /  /  /
                  /  /  /  /

                _|-|_|-|_|-|___ layer
                   layer_slab |
            o1  ______________|


        top view     _________
                    /| | | | |
                   / | | | | |
                  /taper_angle
                 /_ _| | | | |
        wg_width |   | | | | |
                 \   | | | | |
                  \  | | | | |
                   \ | | | | |
                    \|_|_|_|_|
                 <-->
                taper_length

    """
    c = Component()

    taper = taper(
        length=length_taper,
        width2=width_grating,
        width1=wg_width,
        w_slab2=width_grating + 2 * slab_offset,
    )

    taper_ref = c << taper

    c.add_port(port=taper_ref.ports["o1"], name="o1")
    x0 = xi = taper_ref.xmax

    widths = gf.snap.snap_to_grid(widths)
    gaps = gf.snap.snap_to_grid(gaps)

    for width, gap in zip(widths, gaps):
        xi += gap + width / 2
        cgrating = c.add_ref(
            rectangle(
                size=[width, width_grating],
                layer=layer,
                port_type=None,
                centered=True,
            )
        )
        cgrating.x = gf.snap.snap_to_grid(xi)
        cgrating.y = 0
        xi += width / 2

    if layer_slab:
        slab = c << rectangle(
            size=(
                gf.snap.snap_to_grid(xi - x0) + slab_offset,
                width_grating + 2 * slab_offset,
            ),
            layer=layer_slab,
            port_type=None,
            centered=True,
        )
        slab.xmin = x0

    xport = np.round((xi + length_taper) / 2, 3)

    port_type = f"vertical_{polarization.lower()}"
    c.add_port(name=port_type, port_type=port_type, midpoint=(xport, 0), orientation=0)
    c.info.polarization = polarization
    c.info.wavelength = wavelength
    gf.asserts.grating_coupler(c)
    return c
Beispiel #10
0
def grating_coupler_uniform(
    num_teeth: int = 20,
    period: float = 0.75,
    fill_factor: float = 0.5,
    width_grating: float = 11.0,
    length_taper: float = 150.0,
    width: float = 0.5,
    layer: Tuple[int, int] = gf.LAYER.WG,
    polarization: str = "te",
    wavelength: float = 1.55,
) -> Component:
    r"""Grating coupler uniform (grating with rectangular shape not elliptical).
    Therefore it needs a longer taper.
    Grating teeth are straight instead of elliptical.

    Args:
        num_teeth: 20
        period: 0.75
        fill_factor: 0.5
        width_grating: 11
        length_taper: 150
        width: 0.5
        partial_etch: False

    .. code::

                 \  \  \  \
                  \  \  \  \
                _|-|_|-|_|-|___
               |_______________  W0

    """
    c = Component()
    taper_ref = c << taper(
        length=length_taper,
        width2=width_grating,
        width1=width,
        layer=layer,
    )

    c.add_port(port=taper_ref.ports["o1"], name="o1")
    x0 = taper_ref.xmax

    for i in range(num_teeth):
        xsize = gf.snap.snap_to_grid(period * fill_factor)
        cgrating = c.add_ref(
            rectangle(size=[xsize, width_grating], layer=layer))
        cgrating.x = gf.snap.snap_to_grid(x0 + i * period)
        cgrating.y = 0

    xport = (x0 + cgrating.x) / 2

    port_type = f"vertical_{polarization}"
    c.add_port(name=port_type,
               port_type=port_type,
               midpoint=(xport, 0),
               orientation=0)
    c.info.polarization = polarization
    c.info.wavelength = wavelength
    gf.asserts.grating_coupler(c)
    return c