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
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
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
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
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
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
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