예제 #1
0
def add_grating_couplers(
    component: Component,
    grating_coupler=grating_coupler_te,
    layer_label=pp.LAYER.LABEL,
    gc_port_name: str = "W0",
    get_input_labels_function=get_input_labels,
):
    """Return component with grating couplers and labels."""

    cnew = Component(name=component.name + "_c")
    cnew.add_ref(component)
    grating_coupler = pp.call_if_func(grating_coupler)

    io_gratings = []
    for port in component.ports.values():
        gc_ref = grating_coupler.ref()
        gc_ref.connect(list(gc_ref.ports.values())[0], port)
        io_gratings.append(gc_ref)
        cnew.add(gc_ref)

    labels = get_input_labels_function(
        io_gratings,
        list(component.ports.values()),
        component_name=component.name,
        layer_label=layer_label,
        gc_port_name=gc_port_name,
    )
    cnew.add(labels)
    return cnew
예제 #2
0
def pads_shorted(width=100, n_pads=8, pad_spacing=150, layer=LAYER.M1):
    c = Component(name="shorted_pads")
    pad = rectangle_centered(x=width, y=width, layer=layer)
    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_centered(x=pad_spacing * (n_pads - 1), y=10, layer=layer)
    c.add_ref(short)
    return c
예제 #3
0
def pads_shorted(width=100, n_pads=8, pad_spacing=150, layer=LAYER.M1):
    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
예제 #4
0
def rotate(component: Component, angle: int = 90) -> Component:
    """ returns rotated component
    """
    c = Component(f"{component.name}_r")
    cr = c.add_ref(component)
    cr.rotate(angle)
    c.ports = cr.ports
    return c
예제 #5
0
def rotate(component, angle=90):
    """ returns rotated component
    """
    c = Component(
        settings=component.get_settings(),
        test_protocol=component.test_protocol,
        data_analysis_protocol=component.data_analysis_protocol,
    )
    cr = c.add_ref(component)
    cr.rotate(angle)
    c.ports = cr.ports
    c.name = component.name + "_r"
    return c
예제 #6
0
def wg_heater_connected(waveguide_heater: Callable = waveguide_heater,
                        wg_heater_connector: Callable = wg_heater_connector,
                        tlm_layers: List[Tuple[int, int]] = [
                            LAYER.VIA1,
                            LAYER.M1,
                            LAYER.VIA2,
                            LAYER.M2,
                            LAYER.VIA3,
                            LAYER.M3,
                        ],
                        **kwargs) -> Component:
    """
    .. plot::
      :include-source:

      import pp

      c = pp.c.wg_heater_connected()
      pp.plotgds(c)

    """
    wg_heater = waveguide_heater(**kwargs)
    # print(wg_heater.ports.keys())
    conn1 = wg_heater_connector(
        heater_ports=[wg_heater.ports["HBE0"], wg_heater.ports["HTE0"]],
        tlm_layers=tlm_layers,
    )

    conn2 = wg_heater_connector(
        heater_ports=[wg_heater.ports["HBW0"], wg_heater.ports["HTW0"]],
        tlm_layers=tlm_layers,
    )

    cmp = Component()
    for c in [wg_heater, conn1, conn2]:
        _c = cmp.add_ref(c)
        cmp.absorb(_c)

    for port_name, p in wg_heater.ports.items():
        cmp.add_port(name=port_name, port=p)

    cmp.add_port(name=1, port=conn1.ports["0"])
    cmp.add_port(name=2, port=conn2.ports["0"])
    cmp.ports[1].orientation = 90
    cmp.ports[2].orientation = 90

    return cmp
예제 #7
0
def litho_star(num_lines: int = 20,
               line_width: int = 2,
               diameter: int = 200,
               layer: int = 0) -> Component:
    """ Creates a circular-star shape from lines, used as a lithographic
    resolution test pattern

    .. plot::
      :include-source:

      import pp

      c = pp.c.litho_star()
      pp.plotgds(c)
    """
    D = Component()

    degree = 180 / num_lines
    R1 = rectangle(size=(line_width, diameter), layer=layer)
    for i in range(num_lines):
        r1 = D.add_ref(R1).rotate(degree * i)
        r1.center = (0, 0)

    return D
def grating_coupler_uniform_optimized(
    widths=(0.5, 0.2, 0.3),
    width_grating=11,
    length_taper=150,
    width=0.5,
    partial_etch=False,
    layer=pp.LAYER.WG,
    layer_partial_etch=pp.LAYER.SLAB150,
    taper=None,
    polarization="te",
    wavelength=1500,
):
    """ Grating coupler uniform (not focusing)

    Args:
        widths: of each teeth
        width_grating: 11
        length_taper: 150
        width: 0.5
        partial_etch: False

    .. plot::
      :include-source:

      import pp

      c = pp.c.grating_coupler_uniform_optimized()
      pp.plotgds(c)

    """
    # returns a fiber grating
    c = Component()
    x = 0

    if partial_etch:
        partetch_overhang = 5

        # make the etched areas (opposite to teeth)
        for i, wt in enumerate(widths):
            if i % 2 == 1:
                _compass = pp.c.compass(
                    size=[wt, width_grating + partetch_overhang * 2],
                    layer=layer_partial_etch,
                )
                cgrating = c.add_ref(_compass)
                cgrating.x += x + wt / 2
            x += wt

        # draw the deep etched square around the grating
        xgrating = np.sum(widths)
        deepbox = c.add_ref(pp.c.compass(size=[xgrating, width_grating], layer=layer))
        deepbox.movex(xgrating / 2)
    else:
        for i, wt in enumerate(widths):
            if i % 2 == 0:
                cgrating = c.add_ref(
                    pp.c.compass(size=[wt, width_grating], layer=layer)
                )
                cgrating.x += x + wt / 2
            x += wt

    # make the taper
    if taper is None:
        taper = pp.c.taper(
            length=length_taper,
            width1=width,
            width2=width_grating,
            port=None,
            layer=layer,
        )
    taper_ref = c.add_ref(taper)
    taper_ref.xmax = 0
    port = taper_ref.ports.get("W0") or taper_ref.ports.get("1")
    c.polarization = polarization
    c.wavelength = wavelength
    c.add_port(port=taper_ref.ports[port.name], name="W0")
    pp.assert_grating_coupler_properties(c)
    return c
예제 #9
0
def component_sequence(
    sequence: List[str],
    string_to_device_in_out_ports: Dict[str, Union[Tuple[Component, str, str],
                                                   Tuple[None, str, str]]],
    ports_map: Dict[str, Tuple[str, str]] = {},
    input_port_name: str = "in",
    output_port_name: str = "out",
    start_orientation: float = 0.0,
    name_prefix: None = None,
) -> Component:
    """
    This generates a component from a sequence and a dictionnary to interprete each
    symbol in the sequence.

    Args:
        sequence: a string or a list of symbols
        string_to_device_in_out_ports: maps symbols to (device, input, output)
        ports_map: (optional) extra port mapping using the convention
            {port_name: (alias_name, port_name)}

    Returns:
        component containing the sequence of sub-components
    instantiated and connected together in the sequence order

    """
    # Remove all None devices from the sequence
    sequence = sequence[:]
    to_rm = []
    for i, d in enumerate(sequence):
        _name_device, _ = _parse_component_name(d)
        _device, _, _ = string_to_device_in_out_ports[_name_device]
        if _device is None:
            to_rm += [i]

    while to_rm:
        sequence.pop(to_rm.pop())

    # To generate unique aliases for each instance
    counters = {
        k: count(start=1)
        for k in string_to_device_in_out_ports.keys()
    }

    def _next_id(name):
        return "{}{}".format(name, next(counters[name]))

    component = Component()

    # Add first device and input port
    name_start_device, do_flip = _parse_component_name(sequence[0])
    _input_device, input_port, prev_port = string_to_device_in_out_ports[
        name_start_device]

    prev_device = component.add_ref(_input_device,
                                    alias=_next_id(name_start_device))

    if do_flip:
        prev_device = _flip_ref(prev_device, input_port)

    prev_device.rotate(angle=start_orientation)

    component.add_port(name=input_port_name,
                       port=prev_device.ports[input_port])

    # Generate and connect all elements from the sequence
    for s in sequence[1:]:
        s, do_flip = _parse_component_name(s)

        _device, input_port, next_port = string_to_device_in_out_ports[s]

        device = component.add_ref(_device, alias=_next_id(s))

        if do_flip:
            device = _flip_ref(device, input_port)

        device.connect(input_port, prev_device.ports[prev_port])
        prev_device = device
        prev_port = next_port

    # Deal with edge case where the sequence contains only one component
    if len(sequence) == 1:
        device = prev_device
        next_port = prev_port

    # Add output port
    try:
        component.add_port(name=output_port_name, port=device.ports[next_port])
    except BaseException:
        print(sequence)
        raise

    # Add any extra port specified in ports_map
    for name, (alias, alias_port_name) in ports_map.items():
        component.add_port(name=name,
                           port=component[alias].ports[alias_port_name])

    if name_prefix is not None:
        _md5 = hashlib.md5()
        _md5.update(str(string_to_device_in_out_ports).encode())
        _md5.update(str(sequence).encode())
        component.name = "{}_{}".format(name_prefix, _md5.hexdigest())
    return component
예제 #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,
    partial_etch: bool = False,
    layer: Tuple[int, int] = pp.LAYER.WG,
    layer_partial_etch: Tuple[int, int] = pp.LAYER.SLAB150,
    polarization="te",
    wavelength=1500,
) -> Component:
    """Grating coupler uniform

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

    .. plot::
      :include-source:

      import pp

      c = pp.c.grating_coupler_uniform()
      pp.plotgds(c)

    """
    # returns a fiber grating
    G = Component()

    if partial_etch:
        partetch_overhang = 5
        _compass = compass(
            size=[period * (1 - fill_factor), width_grating + partetch_overhang * 2],
            layer=layer_partial_etch,
        )

        # make the etched areas (opposite to teeth)
        for i in range(num_teeth):
            cgrating = G.add_ref(_compass)
            cgrating.x += i * period

        # draw the deep etched square around the grating
        deepbox = G.add_ref(
            compass(size=[num_teeth * period, width_grating], layer=layer)
        )
        deepbox.movex(num_teeth * period / 2)
    else:
        for i in range(num_teeth):
            cgrating = G.add_ref(
                compass(size=[period * fill_factor, width_grating], layer=layer)
            )
            cgrating.x += i * period
    # make the taper
    tgrating = G.add_ref(
        taper(
            length=length_taper,
            width1=width_grating,
            width2=width,
            port=None,
            layer=layer,
        )
    )
    tgrating.xmin = cgrating.xmax
    G.add_port(port=tgrating.ports["2"], name="W0")
    G.polarization = polarization
    G.wavelength = wavelength
    G.rotate(180)
    return G
예제 #11
0
def pack(
    D_list: List[Component],
    spacing: int = 10,
    aspect_ratio: Tuple[int, int] = (1, 1),
    max_size: Tuple[None, None] = (None, None),
    sort_by_area: bool = True,
    density: float = 1.1,
    precision: float = 1e-2,
    verbose: bool = False,
) -> List[Component]:
    """ takes a list of components and returns

    Args:
        D_list: Must be a list or tuple of Components
        spacing: Minimum distance between adjacent shapes
        aspect_ratio: (width, height) ratio of the rectangular bin
        max_size: Limits the size into which the shapes will be packed
        density:  Values closer to 1 pack tighter but require more computation
        sort_by_area (Boolean): Pre-sorts the shapes by area
        verbose: False
    """

    if density < 1.01:
        raise ValueError("pack() was given a `density` argument that is" +
                         " too small.  The density argument must be >= 1.01")

    # Santize max_size variable
    max_size = [np.inf if v is None else v for v in max_size]
    max_size = np.asarray(max_size, dtype=np.float64)  # In case it's integers
    max_size = max_size / precision

    # Convert Components to rectangles
    rect_dict = {}
    for n, D in enumerate(D_list):
        w, h = (D.size + spacing) / precision
        w, h = int(w), int(h)
        if (w > max_size[0]) or (h > max_size[1]):
            raise ValueError(
                "pack() failed because one of the objects " +
                "in `D_list` is has an x or y dimension larger than `max_size` and "
                + "so cannot be packed")
        rect_dict[n] = (w, h)

    packed_list = []
    while len(rect_dict) > 0:
        (packed_rect_dict, rect_dict) = _pack_single_bin(
            rect_dict,
            aspect_ratio=aspect_ratio,
            max_size=max_size,
            sort_by_area=sort_by_area,
            density=density,
            precision=precision,
            verbose=verbose,
        )
        packed_list.append(packed_rect_dict)

    D_packed_list = []
    for rect_dict in packed_list:
        D_packed = Component()
        for n, rect in rect_dict.items():
            x, y, w, h = rect
            xcenter = x + w / 2 + spacing / 2
            ycenter = y + h / 2 + spacing / 2
            d = D_packed.add_ref(D_list[n])
            d.center = (xcenter * precision, ycenter * precision)
        D_packed_list.append(D_packed)

    return D_packed_list