Source code for gdsfactory.components.taper

from __future__ import annotations

from functools import partial

import gdsfactory as gf
from gdsfactory.cell import cell
from gdsfactory.component import Component
from gdsfactory.port import Port
from gdsfactory.snap import snap_to_grid
from gdsfactory.typings import CrossSectionSpec, LayerSpec


[docs] @cell def taper( length: float = 10.0, width1: float = 0.5, width2: float | None = None, port: Port | None = None, with_two_ports: bool = True, cross_section: CrossSectionSpec = "xs_sc", port_names: tuple | None = ("o1", "o2"), port_types: tuple | None = ("optical", "optical"), **kwargs, ) -> Component: """Linear taper, which tapers only the main cross section section. Deprecated, use gf.components.taper_cross_section instead Args: length: taper length. width1: width of the west/left port. width2: width of the east/right port. Defaults to width1. port: can taper from a port instead of defining width1. with_two_ports: includes a second port. False for terminator and edge coupler fiber interface. cross_section: specification (CrossSection, string, CrossSectionFactory dict). port_names(tuple): Ordered tuple of port names. First port is default \ taper port, second name only if with_two_ports flags used. port_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. """ c = gf.Component() width1 = gf.snap.snap_to_grid2x(width1) x1 = gf.get_cross_section(cross_section, width=width1) if width2: width2 = gf.snap.snap_to_grid2x(width2) x2 = gf.get_cross_section(cross_section, width=width2) else: x2 = x1 width1 = x1.width width2 = x2.width width_max = max([width1, width2]) x = gf.get_cross_section(cross_section, width=width_max, **kwargs) layer = x.layer if isinstance(port, gf.Port) and width1 is None: width1 = port.width delta_width = width2 - width1 length = float(snap_to_grid(length)) y1 = width1 / 2 y2 = width2 / 2 if length: xpts = [0, length, length, 0] ypts = [y1, y2, -y2, -y1] c.add_polygon((xpts, ypts), layer=layer) xpts = [0, length, length, 0] for section in x.sections[1:]: layer = section.layer y1 = section.width / 2 if not section.offset: y2 = section.width / 2 + delta_width / 2 ypts = [y1, y2, -y2, -y1] else: y2 = section.width / 2 y2 = section.width / 2 + delta_width / 2 ypts = [y1, y2, -y2, -y1] ypts = [y - section.offset for y in ypts] c.add_polygon((xpts, ypts), layer=layer) c.add_port( name=port_names[0], center=(0, 0), width=width1, orientation=180, layer=x.layer, cross_section=x1, port_type=port_types[0], ) if with_two_ports: c.add_port( name=port_names[1], center=(length, 0), width=width2, orientation=0, layer=x.layer, cross_section=x2, port_type=port_types[1], ) c.info["length"] = length c.info["width1"] = float(width1) c.info["width2"] = float(width2) x.add_bbox(c) return c
[docs] @gf.cell def taper_strip_to_ridge( length: float = 10.0, width1: float = 0.5, width2: float = 0.5, w_slab1: float = 0.15, w_slab2: float = 6.0, layer_wg: LayerSpec = "WG", layer_slab: LayerSpec = "SLAB90", cross_section: CrossSectionSpec = "xs_sc", use_slab_port: bool = False, **kwargs, ) -> Component: r"""Linear taper from strip to rib. Deprecated, use gf.components.taper_cross_section instead. Args: length: taper length (um). width1: in um. width2: in um. w_slab1: slab width in um. w_slab2: slab width in um. layer_wg: for input waveguide. layer_slab: for output waveguide with slab. cross_section: for input waveguide. use_slab_port: if True, uses the port associated with the slab layer (layer_slab) for the second output port of the component. If False, the second port uses the same layer as the first port (layer_wg). kwargs: cross_section settings. .. code:: __________________________ / | _______/____________|______________ / | width1 |w_slab1 | w_slab2 width2 ______\_____________|______________ \ | \__________________________ """ width1 = gf.snap.snap_to_grid2x(width1) width2 = gf.snap.snap_to_grid2x(width2) w_slab1 = gf.snap.snap_to_grid2x(w_slab1) w_slab2 = gf.snap.snap_to_grid2x(w_slab2) xs = gf.get_cross_section(cross_section, **kwargs) xs_wg = gf.get_cross_section(cross_section, layer=layer_wg) xs_slab = gf.get_cross_section(cross_section, layer=layer_slab) taper_wg = taper( length=length, width1=width1, width2=width2, cross_section=xs_wg, ) taper_slab = taper( length=length, width1=w_slab1, width2=w_slab2, cross_section=xs_slab, ) c = gf.Component() taper_ref_wg = c << taper_wg taper_ref_slab = c << taper_slab c.info["length"] = float(length) c.add_port(name="o1", port=taper_ref_wg.ports["o1"]) if use_slab_port: c.add_port(name="o2", port=taper_ref_slab.ports["o2"]) else: c.add_port(name="o2", port=taper_ref_wg.ports["o2"]) if length: xs.add_bbox(c) c.absorb(taper_ref_wg) c.absorb(taper_ref_slab) return c
[docs] @gf.cell def taper_strip_to_ridge_trenches( length: float = 10.0, width: float = 0.5, slab_offset: float = 3.0, trench_width: float = 2.0, trench_layer: LayerSpec = "DEEP_ETCH", layer_wg: LayerSpec = "WG", trench_offset: float = 0.1, ) -> gf.Component: """Defines taper using trenches to define the etch. Args: length: in um. width: in um. slab_offset: in um. trench_width: in um. trench_layer: trench layer. layer_wg: waveguide layer. trench_offset: after waveguide in um. """ c = gf.Component() y0 = width / 2 + trench_width - trench_offset yL = width / 2 + trench_width - trench_offset + slab_offset # straight x = [0, length, length, 0] yw = [y0, yL, -yL, -y0] if length: c.add_polygon((x, yw), layer=layer_wg) # top trench ymin0 = width / 2 yminL = width / 2 ymax0 = width / 2 + trench_width ymaxL = width / 2 + trench_width + slab_offset x = [0, length, length, 0] ytt = [ymin0, yminL, ymaxL, ymax0] ytb = [-ymin0, -yminL, -ymaxL, -ymax0] c.add_polygon((x, ytt), layer=trench_layer) c.add_polygon((x, ytb), layer=trench_layer) c.add_port(name="o1", center=(0, 0), width=width, orientation=180, layer=layer_wg) c.add_port( name="o2", center=(length, 0), width=width, orientation=0, layer=layer_wg ) return c
taper_strip_to_slab150 = partial(taper_strip_to_ridge, layer_slab="SLAB150") # taper StripCband to NitrideCband taper_sc_nc = partial( taper_strip_to_ridge, layer_wg="WG", layer_slab="WGN", length=20.0, width1=0.5, width2=0.15, w_slab1=0.15, w_slab2=1.0, use_slab_port=True, ) if __name__ == "__main__": c = taper_sc_nc() c.pprint_ports() # c = taper(cross_section="xs_rc_bbox", width2=1, length=1) # xs_pin_m1 = partial( # gf.cross_section.strip_auto_widen, # width=0.5, # width_wide=2, # sections=( # gf.Section(width=1, offset=2, layer=(24, 0), name="n+"), # gf.Section(width=1, offset=3, layer=(41, 0), name="m1"), # ), # ) # # c = taper(width2=10, length=10) # # c = taper_strip_to_ridge_trenches() # # c = taper_strip_to_ridge() # # c = taper(width1=1.5, width2=1, cross_section="xs_rc") # # c = taper_sc_nc() # c = gf.Component("taper_with_offset") # route = gf.routing.get_route_from_waypoints( # [(0, 0), (300, 0), (300, 300), (300, 600), (600, 600)], # # cross_section="xs_sc_auto_widen", # cross_section=xs_pin_m1, # radius=30, # ) # c.add(route.references) c.show(show_ports=False)