Exemple #1
0
def pad(
    size: Tuple[float, float] = (100.0, 100.0),
    layer: Layer = LAYER.M3,
    layers_cladding: Optional[Tuple[Layer, ...]] = None,
    cladding_offsets: Optional[Tuple[float, ...]] = None,
) -> Component:
    """Rectangular pad with 4 ports (1, 2, 3, 4)

    Args:
        width: pad width
        height: pad height
        layer: pad layer
        layers_cladding:
        cladding_offsets:
    """
    c = Component()
    rect = compass(size=size, layer=layer)
    c_ref = c.add_ref(rect)
    c.add_ports(c_ref.ports)
    c.info.size = (float(size[0]), float(size[1]))
    c.info.layer = layer

    if layers_cladding and cladding_offsets:
        for layer, cladding_offset in zip(layers_cladding, cladding_offsets):
            c.add_ref(
                compass(
                    size=(size[0] + 2 * cladding_offset,
                          size[1] + 2 * cladding_offset),
                    layer=layer,
                ))

    return c
Exemple #2
0
def fiber_array(
    n: int = 8,
    pitch: float = 127.0,
    core_diameter: float = 10,
    cladding_diameter: float = 125,
    layer_core: Tuple[int, int] = gf.LAYER.WG,
    layer_cladding: Tuple[int, int] = gf.LAYER.WGCLAD,
) -> Component:
    """Returns a fiber array

    .. code::

        pitch
         <->
        _________
       |         | lid
       | o o o o |
       |         | base
       |_________|
          length

    """
    c = Component()

    for i in range(n):
        core = c.add_ref(circle(radius=core_diameter / 2, layer=layer_core))
        cladding = c.add_ref(
            circle(radius=cladding_diameter / 2, layer=layer_cladding))
        core.movex(i * pitch)
        cladding.movex(i * pitch)
        c.add_port(name=f"F{i}", width=core_diameter, orientation=0)

    return c
Exemple #3
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
Exemple #4
0
def invert(
        elements,
        border: float = 10.0,
        precision: float = 1e-4,
        num_divisions: Union[int, Int2] = (1, 1),
        max_points: int = 4000,
        layer: Layer = (1, 0),
):
    """Creates an inverted version of the input shapes with an additional
    border around the edges. adapted from phidl.geometry.invert

    Args:
        elements : Component(/Reference), list of Component(/Reference), or Polygon
            A Component containing the polygons to invert.
        border : int or float
            Size of the border around the inverted shape (border value is the
            distance from the edges of the boundary box defining the inverted
            shape to the border, and is applied to all 4 sides of the shape).
        precision : float
            Desired precision for rounding vertex coordinates.
        num_divisions : array-like[2] of int
            The number of divisions with which the geometry is divided into
            multiple rectangular regions. This allows for each region to be
            processed sequentially, which is more computationally efficient.
        max_points : int
            The maximum number of vertices within the resulting polygon.
        layer : int, array-like[2], or set
            Specific layer(s) to put polygon geometry on.

    Returns
        D: A Component containing the inverted version of the input shape(s) and the
        corresponding border(s).
    """
    Temp = Component()
    if type(elements) is not list:
        elements = [elements]
    for e in elements:
        if isinstance(e, Component):
            Temp.add_ref(e)
        else:
            Temp.add(e)
    gds_layer, gds_datatype = pg._parse_layer(layer)

    # Build the rectangle around the Component D
    R = gf.c.rectangle(size=(Temp.xsize + 2 * border, Temp.ysize + 2 * border),
                       centered=True)
    R.center = Temp.center
    D = boolean(
        A=R,
        B=Temp,
        operation="A-B",
        precision=precision,
        num_divisions=num_divisions,
        max_points=max_points,
        layer=layer,
    )
    return D
Exemple #5
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
Exemple #6
0
def fiber(
    core_diameter: float = 10,
    cladding_diameter: float = 125,
    layer_core: Tuple[int, int] = gf.LAYER.WG,
    layer_cladding: Tuple[int, int] = gf.LAYER.WGCLAD,
) -> Component:
    """Returns a fiber."""
    c = Component()
    c.add_ref(circle(radius=core_diameter / 2, layer=layer_core))
    c.add_ref(circle(radius=cladding_diameter / 2, layer=layer_cladding))
    c.add_port(name="F0", width=core_diameter, orientation=0)
    return c
Exemple #7
0
def cdsem_bend180(
    width: float = 0.5,
    radius: float = 10.0,
    wg_length: float = LINE_LENGTH,
    straight: ComponentFactory = straight_function,
    bend90: ComponentFactory = bend_circular,
    cross_section: CrossSectionFactory = strip,
    text: ComponentFactory = text_rectangular_mini,
) -> Component:
    """

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

    """
    c = Component()
    r = radius

    cross_section = partial(cross_section, width=width)
    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 << text(text=str(int(width * 1e3)))
    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
Exemple #8
0
def awg(
    arms: int = 10,
    outputs: int = 3,
    free_propagation_region_input_function=free_propagation_region_input,
    free_propagation_region_output_function=free_propagation_region_output,
    fpr_spacing: float = 50.0,
) -> Component:
    """Returns a basic Arrayed Waveguide grating.

    Args:
        arms: number of arms
        outputs: number of outputs
        free_propagation_region_input_function: for input
        free_propagation_region_output_function: for output
        fpr_spacing: x separation between input/output FPR

    """
    c = Component()
    fpr_in = free_propagation_region_input_function(
        inputs=1,
        outputs=arms,
    )
    fpr_out = free_propagation_region_output_function(
        inputs=outputs,
        outputs=arms,
    )

    fpr_in_ref = c.add_ref(fpr_in)
    fpr_out_ref = c.add_ref(fpr_out)

    fpr_in_ref.rotate(90)
    fpr_out_ref.rotate(90)

    fpr_out_ref.x += fpr_spacing
    routes = gf.routing.get_bundle(
        fpr_in_ref.get_ports_list(prefix="E"), fpr_out_ref.get_ports_list(prefix="E")
    )

    c.lengths = []
    for route in routes:
        c.add(route.references)
        c.lengths.append(route.length)

    c.add_port("o1", port=fpr_in_ref.ports["o1"])

    for i, port in enumerate(fpr_out_ref.get_ports_list(prefix="W")):
        c.add_port(f"E{i}", port=port)

    c.delta_length = np.mean(np.diff(c.lengths))
    return c
def add_grating_couplers(
    component: Component,
    grating_coupler: ComponentFactory = grating_coupler_te,
    layer_label: Tuple[int, int] = (200, 0),
    gc_port_name: str = "o1",
    get_input_labels_function: Callable[..., List[Label]] = get_input_labels,
    select_ports: Callable = select_ports_optical,
    component_name: Optional[str] = None,
) -> Component:
    """Returns new component with grating couplers and labels.

    Args:
        component: to add grating_couplers
        grating_coupler: grating_coupler function
        layer_label: for label
        gc_port_name: where to add label
        get_input_labels_function: function to get label
        select_ports: for selecting optical_ports

    """

    c = Component()
    c.component = component
    component_name = component_name or component.info_child.name
    c.add_ref(component)
    grating_coupler = (
        grating_coupler() if callable(grating_coupler) else grating_coupler
    )

    io_gratings = []
    optical_ports = select_ports(component.ports)
    optical_ports = list(optical_ports.values())
    for port in optical_ports:
        gc_ref = grating_coupler.ref()
        gc_port = gc_ref.ports[gc_port_name]
        gc_ref.connect(gc_port, port)
        io_gratings.append(gc_ref)
        c.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,
    )
    c.add(labels)
    c.copy_child_info(component)
    return c
Exemple #10
0
def add_text(
    component: ComponentOrFactory,
    text: str = "",
    text_offset: Float2 = (0, 0),
    text_anchor: Anchor = "cc",
    text_factory: ComponentFactory = text_rectangular_multi_layer,
) -> Component:
    """Returns component inside a new component with text geometry.

    Args:
        component:
        text: text string.
        text_offset: relative to component anchor. Defaults to center (cc).
        text_anchor: relative to component (ce cw nc ne nw sc se sw center cc).
        text_factory: function to add text labels.
    """
    component = component() if callable(component) else component
    component_new = Component()
    component_new.component = component
    ref = component_new.add_ref(component)

    t = component_new << text_factory(text)
    t.move((np.array(text_offset) + getattr(ref.size_info, text_anchor)))

    component_new.add_ports(ref.ports)
    component_new.copy_child_info(component)
    return component_new
Exemple #11
0
def straight_array(n: int = 4,
                   spacing: float = 4.0,
                   straigth: ComponentOrFactory = straight_function,
                   **kwargs) -> Component:
    """Array of straights connected with grating couplers.

    useful to align the 4 corners of the chip

    Args:
        n: number of straights
        spacing: edge to edge straight spacing
        straigth: straigth straight Component or library
        **kwargs
    """

    c = Component()
    wg = straigth(**kwargs) if callable(straigth) else straigth

    for i in range(n):
        wref = c.add_ref(wg)
        wref.y += i * (spacing + wg.info.width)
        c.add_ports(wref.ports, prefix=str(i))

    c.auto_rename_ports()
    return c
Exemple #12
0
def gdsdiff(
    component1: Union[Path, Component, str],
    component2: Union[Path, Component, str],
    name: str = "TOP",
    xor: bool = True,
) -> Component:
    """Compare two Components.

    Args:
        component1: Component or path to gds file
        component2: Component or path to gds file
        name: name of the top cell
        xor: makes boolean operation

    Returns:
        Component with both cells (xor, common and diffs)
    """
    if isinstance(component1, pathlib.Path):
        component1 = str(component1)
    if isinstance(component2, pathlib.Path):
        component2 = str(component2)
    if isinstance(component1, str):
        component1 = import_gds(component1, flatten=True)
    if isinstance(component2, str):
        component2 = import_gds(component2, flatten=True)

    top = Component(name=f"{name}_diffs")

    if component1.name.startswith("Unnamed"):
        component1.name = f"{name}_old"
    if component2.name.startswith("Unnamed"):
        component2.name = f"{name}_new"

    ref1 = top << component1
    ref2 = top << component2

    ref1.xmin = 0
    ref1.ymin = 0
    ref2.xmin = 0
    ref2.ymin = 0

    if xor:
        diff = xor_polygons(ref1, ref2, hash_geometry=False)
        diff.name = f"{name}_xor"
        top.add_ref(diff)

    return top
Exemple #13
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
Exemple #14
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
Exemple #15
0
def bend_euler_s(**kwargs) -> Component:
    """Sbend made of euler bends."""
    c = Component()
    b = bend_euler(**kwargs)
    b1 = c.add_ref(b)
    b2 = c.add_ref(b)
    b2.mirror()
    b2.connect("o1", b1.ports["o2"])
    c.add_port("o1", port=b1.ports["o1"])
    c.add_port("o2", port=b2.ports["o2"])
    return c
Exemple #16
0
def add_pins_to_references(
    component: Component,
    function: Callable = add_pins_triangle,
) -> Component:
    """Add pins to Component references.

    Args:
        component: component to add pins to
        references:
        function: function to add pins
    """
    c = Component()
    c.add_ref(component)

    references = component.references

    for reference in references:
        function(component=c, reference=reference)

    return c
Exemple #17
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
Exemple #18
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
Exemple #19
0
def fanout_component(
    component: ComponentOrFactory,
    port_names: Tuple[str, ...],
    pitch: Tuple[float, float] = (0.0, 20.0),
    dx: float = 20.0,
    sort_ports: bool = True,
    **kwargs,
) -> Component:
    """Returns component with Sbend fanout routes.

    Args:
        component: to fanout ports
        port_names: list of port names
        pitch: target port spacing for new component
        dx: how far the fanout in x direction
        kwargs: for get_route_sbend
    """

    c = Component()
    comp = component() if callable(component) else component
    ref = c.add_ref(comp)
    ref.movey(-comp.y)

    for port_name in port_names:
        if port_name not in ref.ports:
            raise ValueError(f"{port_name} not in {list(ref.ports.keys())}")

    ports1 = [p for p in ref.ports.values() if p.name in port_names]
    port = ports1[0]
    port_extended_x = port.get_extended_midpoint(dx)[0]
    port_settings = port.settings.copy()

    port_settings.pop("name")
    port_settings.update(midpoint=(port_extended_x, 0))
    port_settings.update(orientation=(port.angle + 180) % 360)

    ports2 = port_array(n=len(ports1), pitch=pitch, **port_settings)

    if sort_ports:
        ports1, ports2 = sort_ports_function(ports1, ports2)

    for i, (p1, p2) in enumerate(zip(ports1, ports2)):
        route = get_route_sbend(port1=p1, port2=p2, **kwargs)
        c.add(route.references)
        c.add_port(f"new_{i}", port=flip(p2))

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

    return c
Exemple #20
0
def gdsdiff(
    component1: Union[Path, Component, str],
    component2: Union[Path, Component, str],
    name: str = "TOP",
    xor: bool = True,
) -> Component:
    """Compare two Components.

    Args:
        component1: Component or path to gds file (reference)
        component2: Component or path to gds file (run)
        name: name of the top cell
        xor: makes boolean operation

    Returns:
        Component with both cells (xor, common and diffs)
    """
    if isinstance(component1, (str, pathlib.Path)):
        component1 = import_gds(str(component1), flatten=True, name=f"{name}_old")
    if isinstance(component2, (str, pathlib.Path)):
        component2 = import_gds(str(component2), flatten=True, name=f"{name}_new")

    component1 = component1.copy()
    component2 = component2.copy()

    component1.name = f"{name}_old"
    component2.name = f"{name}_new"

    top = Component(name=f"{name}_diffs")
    ref1 = top << component1
    ref2 = top << component2

    if xor:
        diff = xor_polygons(ref1, ref2, hash_geometry=False)
        diff.name = f"{name}_xor"
        top.add_ref(diff)

    return top
Exemple #21
0
def move(
    component: Component,
    origin=(0, 0),
    destination=None,
    axis: Optional[str] = None,
) -> Component:
    """Return container that contains a reference to the original component."""
    component_new = Component()
    component_new.component = component
    ref = component_new.add_ref(component)
    ref.move(origin=origin, destination=destination, axis=axis)
    component_new.add_ports(ref.ports)
    component_new.copy_child_info(component)
    return component_new
Exemple #22
0
def mirror(component: Component, p1: Float2 = (0, 1), p2: Float2 = (0, 0)) -> Component:
    """Returns mirrored component inside a new component.

    Args:
        p1: first point to define mirror axis
        p2: second point to define mirror axis
    """
    component_new = Component()
    component_new.component = component
    ref = component_new.add_ref(component)
    ref.mirror(p1=p1, p2=p2)
    component_new.add_ports(ref.ports)
    component_new.copy_child_info(component)
    return component_new
Exemple #23
0
def add_termination(
    component: Component,
    ports: Optional[List[Port]] = None,
    terminator: ComponentFactory = terminator_function,
    port_name: Optional[str] = None,
    port_type: str = "optical",
    **kwargs
) -> Component:
    """Returns component with all or some ports terminated

    Args:
        component:
        ports: optional list of ports to terminate (defaults to all)
        terminator: factory for the terminator
        port_name: for the terminator to connect to the component ports
        port_type: of the ports that you want to terminate
        **kwargs: for the ports you want to terminate (orientation, width)
    """
    terminator = terminator() if callable(terminator) else terminator
    port_name = port_name or terminator.get_ports_list()[0].name

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

    ports_all = component.get_ports_list()
    ports = ports or component.get_ports_list(port_type=port_type, **kwargs)

    for port in ports_all:
        if port in ports:
            t_ref = c.add_ref(terminator)
            t_ref.connect(port_name, port)
        else:
            c.add_port(port.name, port=port)

    c.copy_child_info(component)
    return c
Exemple #24
0
def loop_mirror(component: ComponentFactory = mmi1x2,
                bend90: ComponentFactory = bend_euler) -> Component:
    """Returns Sagnac loop_mirror."""
    c = Component()
    component = gf.call_if_func(component)
    bend90 = gf.call_if_func(bend90)
    cref = c.add_ref(component)
    routes = route_manhattan(
        cref.ports["o3"],
        cref.ports["o2"],
        straight=gf.components.straight,
        bend=bend90,
    )
    c.add(routes.references)
    c.add_port(name="o1", port=cref.ports["o1"])
    c.absorb(cref)
    return c
Exemple #25
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
Exemple #26
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
Exemple #27
0
def rotate(
    component: ComponentOrFactory,
    angle: int = 90,
) -> Component:
    """Returns rotated component inside a new component.

    Most times you just need to place a reference and rotate it.
    This rotate function just encapsulates the rotated reference into a new component.

    Args:
        component:
        angle: in degrees
    """
    component = component() if callable(component) else component
    component_new = Component()
    component_new.component = component
    ref = component_new.add_ref(component)
    ref.rotate(angle)
    component_new.add_ports(ref.ports)
    component_new.copy_child_info(component)
    return component_new
Exemple #28
0
def pcm_optical(
    widths: Tuple[float, ...] = (0.4, 0.45, 0.5, 0.6, 0.8, 1.0),
    dense_lines_width: float = 0.3,
    dense_lines_width_difference: float = 20e-3,
    dense_lines_gap: float = 0.3,
    dense_lines_labels: Tuple[str, ...] = ("DL", "DM", "DH"),
    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:
    """column with all optical PCMs

    Args:
        widths:  for straight

    """
    c = Component()
    _c1 = cdsem_straight_all(
        straight=straight,
        layer=layer,
        layers_cladding=layers_cladding,
        widths=widths,
        cross_section=cross_section,
        pixel_size=pixel_size,
    )

    all_devices = [_c1]

    all_devices += [
        cdsem_uturn(
            width=width,
            straight=straight,
            bend90=bend90,
            layer=layer,
            layers_cladding=layers_cladding,
            cross_section=cross_section,
            pixel_size=pixel_size,
        ) for width in widths
    ]

    density_params = [
        (
            dense_lines_width - dense_lines_width_difference,
            dense_lines_gap - dense_lines_width_difference,
            dense_lines_labels[0],
        ),
        (dense_lines_width, dense_lines_gap, dense_lines_labels[1]),
        (
            dense_lines_width + dense_lines_width_difference,
            dense_lines_gap + dense_lines_width_difference,
            dense_lines_labels[2],
        ),
    ]

    all_devices += [
        cdsem_straight_density(
            width=w,
            trench_width=t,
            label=lbl,
            straight=straight,
            layer=layer,
            layers_cladding=layers_cladding,
            cross_section=cross_section,
            pixel_size=pixel_size,
        ) for w, t, lbl in density_params
    ]

    [c.add_ref(d) for d in all_devices]
    c.align(elements="all", alignment="xmin")
    c.distribute(elements="all", direction="y", spacing=5, separation=True)
    return c
Exemple #29
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
def add_grating_couplers_with_loopback_fiber_single(
    component: Component,
    grating_coupler: ComponentFactory = grating_coupler_te,
    layer_label: Tuple[int, int] = (200, 0),
    gc_port_name: str = "o1",
    get_input_labels_function: Callable[..., List[Label]] = get_input_labels,
    get_input_label_text_loopback_function: Callable = get_input_label_text_loopback,
    select_ports: Callable = select_ports_optical,
    with_loopback: bool = True,
    cross_section: CrossSectionFactory = strip,
    component_name: Optional[str] = None,
    fiber_spacing: float = 50.0,
    loopback_xspacing: float = 5.0,
    straight: ComponentFactory = straight_function,
    rotation: int = 90,
) -> Component:
    """
    Returns component with all ports terminated with grating couplers

    Args:
        component:
        grating_coupler:
        layer_label:
        gc_port_name:
        get_input_label_text_loopback_function:
        with_loopback: adds a reference loopback
        rotation: 90 for North South devices, 0 for East-West

    """

    c = Component()
    c.component = component
    c.add_ref(component)
    grating_coupler = (
        grating_coupler() if callable(grating_coupler) else grating_coupler
    )

    component_name = component_name or component.info_child.name

    io_gratings = []
    optical_ports = select_ports(component.ports)
    optical_ports = list(optical_ports.values())
    for port in optical_ports:
        gc_ref = grating_coupler.ref()
        gc_port = gc_ref.ports[gc_port_name]
        gc_ref.connect(gc_port, port)
        io_gratings.append(gc_ref)
        c.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,
    )
    c.add(labels)

    p2 = optical_ports[0]
    p1 = optical_ports[-1]

    if with_loopback:

        if rotation in [0, 180]:
            length = abs(p2.x - p1.x)
            wg = c << straight(length=length, cross_section=cross_section)
            wg.rotate(rotation)
            wg.xmin = p2.x
            wg.ymin = c.ymax + grating_coupler.ysize / 2 + loopback_xspacing
        else:
            length = abs(p2.y - p1.y)
            wg = c << straight(length=length, cross_section=cross_section)
            wg.rotate(rotation)
            wg.ymin = p1.y
            wg.xmin = c.xmax + grating_coupler.ysize / 2 + loopback_xspacing

        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