Source code for piel.tools.gdsfactory.patch

from __future__ import annotations


import gdsfactory as gf
from gdsfactory.add_padding import get_padding_points
from gdsfactory.cell import cell
from gdsfactory.component import Component
from gdsfactory.port import Port
from gdsfactory.typings import ComponentSpec, CrossSectionSpec

__all__ = ["straight_heater_metal_simple"]


@cell
def simple_taper(
    length: float = 10.0,
    width1: float = 0.5,
    width2: float | None = None,
    port: Port | None = None,
    with_bbox: bool = True,
    with_two_ports: bool = True,
    cross_section: CrossSectionSpec = "strip",
    port_order_name: tuple | None = ("o1", "o2"),
    port_order_types: tuple | None = ("optical", "optical"),
    **kwargs,
) -> Component:
    """Linear taper.

    Deprecated, use gf.components.taper_cross_section instead

    Args:
        length: taper length.
        width1: width of the west port.
        width2: width of the east port.
        port: can taper from a port instead of defining width1.
        with_bbox: box in bbox_layers and bbox_offsets to avoid DRC sharp edges.
        with_two_ports: includes a second port.
            False for terminator and edge coupler fiber interface.
        cross_section: specification (CrossSection, string, CrossSectionFactory dict).
         port_order_name(tuple): Ordered tuple of port names. First port is default taper port, second name only if with_two_ports flags used.
        port_order_types(tuple): Ordered tuple of port types. First port is default taper port, second name only if with_two_ports flags used.
        kwargs: cross_section settings.
    """
    x = gf.get_cross_section(cross_section, **kwargs)
    layer = x.layer

    if isinstance(port, gf.Port) and width1 is None:
        width1 = port.width
    if width2 is None:
        width2 = width1

    c = gf.Component()

    y1 = width1 / 2
    y2 = width2 / 2
    x1 = x.copy(width=width1)
    x2 = x.copy(width=width2)
    xpts = [0, length, length, 0]
    ypts = [y1, y2, -y2, -y1]
    c.add_polygon((xpts, ypts), layer=layer)

    for section in x.sections:
        layer = section.layer
        y1 = section.width / 2
        y2 = y1 + (width2 - width1)
        ypts = [y1, y2, -y2, -y1]
        c.add_polygon((xpts, ypts), layer=layer)

    if x.cladding_layers and x.cladding_offsets:
        for layer, offset in zip(x.cladding_layers, x.cladding_offsets, strict=True):
            y1 = width1 / 2 + offset
            y2 = width2 / 2 + offset
            ypts = [y1, y2, -y2, -y1]
            c.add_polygon((xpts, ypts), layer=gf.get_layer(layer))

    c.add_port(
        name=port_order_name[0],
        center=(0, 0),
        width=width1,
        orientation=180,
        layer=x.layer,
        cross_section=x1,
        port_type=port_order_types[0],
    )
    if with_two_ports:
        c.add_port(
            name=port_order_name[1],
            center=(length, 0),
            width=width2,
            orientation=0,
            layer=x.layer,
            cross_section=x2,
            port_type=port_order_types[1],
        )

    if with_bbox and length:
        padding = []
        for offset in x.bbox_offsets:
            points = get_padding_points(
                component=c,
                default=0,
                bottom=offset,
                top=offset,
            )
            padding.append(points)

        for layer, points in zip(x.bbox_layers, padding, strict=True):
            c.add_polygon(points, layer=layer)

    c.info["length"] = length
    c.info["width1"] = float(width1)
    c.info["width2"] = float(width2)

    if x.add_bbox:
        c = x.add_bbox(c)
    if x.add_pins:
        c = x.add_pins(c)
    return c


[docs]@cell def straight_heater_metal_simple( length: float = 320.0, length_straight_input: float = 15.0, heater_width: float = 2.5, cross_section_heater: CrossSectionSpec = "heater_metal", cross_section_waveguide_heater: CrossSectionSpec = "strip_heater_metal", via_stack: ComponentSpec | None = "via_stack_heater_mtop", port_orientation1: int | None = None, port_orientation2: int | None = None, heater_taper_length: float | None = 5.0, ohms_per_square: float | None = None, **kwargs, ) -> Component: """Returns a thermal phase shifter that has properly fixed electrical connectivity to extract a suitable electrical netlist and models. dimensions from https://doi.org/10.1364/OE.27.010456 Args: length: of the waveguide. length_undercut_spacing: from undercut regions. length_undercut: length of each undercut section. length_straight_input: from input port to where trenches start. heater_width: in um. cross_section_heater: for heated sections. heater metal only. cross_section_waveguide_heater: for heated sections. cross_section_heater_undercut: for heated sections with undercut. with_undercut: isolation trenches for higher efficiency. via_stack: via stack. port_orientation1: left via stack port orientation. port_orientation2: right via stack port orientation. heater_taper_length: minimizes current concentrations from heater to via_stack. ohms_per_square: to calculate resistance. cross_section: for waveguide ports. kwargs: cross_section common settings. """ c = Component() straight_heater_section = gf.components.straight( cross_section=cross_section_waveguide_heater, length=length, heater_width=heater_width, # **kwargs # Note cross section is set from the provided, no more settings should be set ) c.add_ref(straight_heater_section) c.add_ports(straight_heater_section.ports) if via_stack: via = via_stackw = via_stacke = gf.get_component(via_stack) via_stack_west_center = straight_heater_section.size_info.cw via_stack_east_center = straight_heater_section.size_info.ce dx = via_stackw.get_ports_xsize() / 2 + heater_taper_length or 0 via_stack_west = c << via_stackw via_stack_east = c << via_stacke via_stack_west.move(via_stack_west_center - (dx, 0)) via_stack_east.move(via_stack_east_center + (dx, 0)) valid_orientations = {p.orientation for p in via.ports.values()} p1 = via_stack_west.get_ports_list(orientation=port_orientation1) p2 = via_stack_east.get_ports_list(orientation=port_orientation2) if not p1: raise ValueError( f"No ports for port_orientation1 {port_orientation1} in {valid_orientations}" ) if not p2: raise ValueError( f"No ports for port_orientation2 {port_orientation2} in {valid_orientations}" ) # c.add_ports(p1, prefix="l_") # c.add_ports(p2, prefix="r_") if heater_taper_length: x = gf.get_cross_section(cross_section_heater, width=heater_width) taper = simple_taper( width1=via_stackw.ports["e1"].width, width2=heater_width, length=heater_taper_length, cross_section=x, port_order_name=("e1", "e2"), port_order_types=("electrical", "electrical"), ) taper1 = c << taper taper2 = c << taper taper1.connect("e1", via_stack_west.ports["e3"]) taper2.connect("e1", via_stack_east.ports["e1"]) c.info["resistance"] = ( ohms_per_square * heater_width * length if ohms_per_square else None ) return c