def straight( length: float = 10.0, npoints: int = 2, with_cladding_box: bool = True, cross_section: CrossSectionFactory = strip, **kwargs ) -> Component: """Returns a Straight waveguide. Args: length: straight length npoints: number of points with_cladding_box: box in layers_cladding to avoid DRC sharp edges cross_section: **kwargs: cross_section settings """ p = gf.path.straight(length=length, npoints=npoints) x = cross_section(**kwargs) c = gf.path.extrude(p, x) c.info.length = gf.snap.snap_to_grid(length) c.info.width = float(x.info["width"]) if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] points = get_padding_points( component=c, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) return c
def bend_circular(angle: int = 90, npoints: int = 720, with_cladding_box: bool = True, cross_section: CrossSectionOrFactory = strip, **kwargs) -> Component: """Returns a radial arc. Args: angle: angle of arc (degrees) npoints: number of points with_cladding_box: square in layers_cladding to remove DRC cross_section: kwargs: cross_section settings .. code:: o2 | / / / o1_____/ """ x = cross_section(**kwargs) if callable(cross_section) else cross_section radius = x.info["radius"] p = arc(radius=radius, angle=angle, npoints=npoints) c = Component() path = extrude(p, x) ref = c << path c.add_ports(ref.ports) c.info.length = snap_to_grid(p.length()) c.info.dy = float(abs(p.points[0][0] - p.points[-1][0])) c.info.radius = float(radius) if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] top = cladding_offset if angle == 180 else 0 points = get_padding_points( component=c, default=0, bottom=cladding_offset, right=cladding_offset, top=top, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) c.absorb(ref) return c
def bend_s(size: Float2 = (10.0, 2.0), nb_points: int = 99, with_cladding_box: bool = True, cross_section: CrossSectionFactory = strip, **kwargs) -> Component: """S bend with bezier curve stores min_bend_radius property in self.info['min_bend_radius'] min_bend_radius depends on height and length Args: size: in x and y direction nb_points: number of points with_cladding_box: square bounding box to avoid DRC errors cross_section: function kwargs: cross_section settings """ dx, dy = size x = cross_section(**kwargs) width = x.info["width"] layer = x.info["layer"] c = Component() bend = bezier( width=width, control_points=[(0, 0), (dx / 2, 0), (dx / 2, dy), (dx, dy)], npoints=nb_points, layer=layer, ) bend_ref = c << bend c.add_ports(bend_ref.ports) c.copy_child_info(bend) c.info.start_angle = bend.info.start_angle c.info.end_angle = bend.info.end_angle c.info.length = bend.info.length c.info.min_bend_radius = bend.info.min_bend_radius if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] points = get_padding_points( component=c, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) auto_rename_ports(c) return c
def bend_circular(angle: int = 90, npoints: int = 720, with_cladding_box: bool = True, cross_section: CrossSectionFactory = strip, **kwargs) -> Component: """Returns a radial arc. Args: angle: angle of arc (degrees) npoints: number of points with_cladding_box: square in layers_cladding to remove DRC cross_section: **kwargs: cross_section settings .. plot:: :include-source: import gdsfactory as gf c = gf.components.bend_circular(radius=10, angle=90, npoints=720) c.plot() """ x = cross_section(**kwargs) radius = x.info["radius"] p = arc(radius=radius, angle=angle, npoints=npoints) c = extrude(p, x) c.info.length = snap_to_grid(p.length()) c.info.dy = float(abs(p.points[0][0] - p.points[-1][0])) c.info.radius_min = float(radius) if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] top = cladding_offset if angle == 180 else 0 points = get_padding_points( component=c, default=0, bottom=cladding_offset, right=cladding_offset, top=top, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) return c
def add_outline( component: Component, reference: Optional[ComponentReference] = None, layer: Tuple[int, int] = LAYER.DEVREC, **kwargs, ) -> None: """Adds devices outline bounding box in layer. Args: component: where to add the markers reference: to read outline from layer: to add padding default: default padding top: North padding bottom right left """ c = reference or component if hasattr(component, "parent"): component = component.parent points = get_padding_points(component=c, default=0, **kwargs) component.add_polygon(points, layer=layer)
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: Layer = gf.LAYER.WG, layer_slab: Layer = gf.LAYER.SLAB90, with_slab_port: bool = False, layers_cladding: Optional[Tuple[Layer, ...]] = None, cladding_offset: float = 3.0, ) -> Component: r"""Linear taper from strip to rib Args: length: width1: width2: w_slab1 w_slab2 layer_wg: layer_slab: with_slab_port: adds a wide slab port layers_cladding cladding_offset: .. code:: __________________________ / | _______/____________|______________ / | width1 |w_slab1 | w_slab2 width2 ______\_____________|______________ \ | \__________________________ """ taper_wg = taper(length=length, width1=width1, width2=width2, layer=layer_wg) taper_slab = taper(length=length, width1=w_slab1, width2=w_slab2, layer=layer_slab) c = gf.Component() for _t in [taper_wg, taper_slab]: taper_ref = _t.ref() c.add(taper_ref) c.absorb(taper_ref) c.info["length"] = length c.add_port(name="o1", port=taper_wg.ports["o1"]) if with_slab_port: c.add_port(name="o2", port=taper_slab.ports["o2"]) else: c.add_port(name="o2", port=taper_wg.ports["o2"]) if layers_cladding: points = get_padding_points( component=c, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding: c.add_polygon(points, layer=layer) return c
def taper(length: float = 10.0, width1: float = 0.5, width2: Optional[float] = None, port: Optional[Port] = None, with_cladding_box: bool = True, cross_section: CrossSectionFactory = strip, **kwargs) -> Component: """Linear taper. Args: length: width1: width of the west port width2: width of the east port port: can taper from a port instead of defining width1 with_cladding_box: to avoid DRC acute angle errors in cladding cross_section: kwargs: cross_section settings .. plot:: :include-source: import gdsfactory as gf c = gf.components.taper(width1=0.5, width2=5, length=3) c.plot() """ x = cross_section(**kwargs) layers_cladding = x.info["layers_cladding"] layer = x.info["layer"] if isinstance(port, gf.Port) and width1 is None: width1 = port.width if width2 is None: width2 = width1 y1 = width1 / 2 y2 = width2 / 2 xpts = [0, length, length, 0] ypts = [y1, y2, -y2, -y1] c = gf.Component() c.add_polygon((xpts, ypts), layer=layer) c.add_port( name="o1", midpoint=[0, 0], width=width1, orientation=180, layer=layer, cross_section=x, ) c.add_port( name="o2", midpoint=[length, 0], width=width2, orientation=0, layer=layer, cross_section=x, ) if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] points = get_padding_points( component=c, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) c.info["length"] = length c.info["width1"] = float(width1) c.info["width2"] = float(width2) return c
def fanout2x2(component: ComponentOrFactory, port_spacing: float = 20.0, bend_length: Optional[float] = None, npoints: int = 101, select_ports: Callable = select_ports_optical, cross_section: CrossSectionFactory = strip, with_cladding_box: bool = True, **kwargs) -> Component: """returns component with port_spacing. Args: component: to package port_spacing: for the returned component bend_length: length of the bend (defaults to port_spacing) npoints: for sbend select_ports: function to select optical_ports ports cross_section: with_cladding_box: square bounding box to avoid DRC errors Keyword Args: cross_section settings """ c = gf.Component() component = component() if callable(component) else component component.component = component ref = c << component ref.movey(-ref.y) if bend_length is None: bend_length = port_spacing dx = bend_length y = port_spacing / 2.0 p_w0 = ref.ports["o1"].midpoint p_w1 = ref.ports["o2"].midpoint p_e1 = ref.ports["o3"].midpoint p_e0 = ref.ports["o4"].midpoint y0 = p_e1[1] dy = y - y0 control_points = [(0, 0), (dx / 2, 0), (dx / 2, dy), (dx, dy)] x = cross_section(**kwargs) width = x.info["width"] layer = x.info["layer"] bend = bezier( control_points=control_points, npoints=npoints, start_angle=0, end_angle=0, width=width, layer=layer, ) if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] bend.unlock() points = get_padding_points( component=bend, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding or []: bend.add_polygon(points, layer=layer) b_tr = bend.ref(port_id="o1", position=p_e1) b_br = bend.ref(port_id="o1", position=p_e0, v_mirror=True) b_tl = bend.ref(port_id="o1", position=p_w1, h_mirror=True) b_bl = bend.ref(port_id="o1", position=p_w0, rotation=180) c.add([b_tr, b_br, b_tl, b_bl]) c.add_port("o1", port=b_bl.ports["o2"]) c.add_port("o2", port=b_tl.ports["o2"]) c.add_port("o3", port=b_tr.ports["o2"]) c.add_port("o4", port=b_br.ports["o2"]) c.min_bend_radius = bend.info["min_bend_radius"] optical_ports = select_ports(ref.ports) for port_name in ref.ports.keys(): if port_name not in optical_ports: c.add_port(port_name, port=ref.ports[port_name]) c.copy_child_info(component) return c
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: Layer = gf.LAYER.WG, layer_slab: Layer = gf.LAYER.SLAB90, layers_cladding: Optional[Tuple[Layer, ...]] = None, cladding_offset: float = 3.0, cross_section: CrossSectionFactory = strip, ) -> Component: r"""Linear taper from strip to rib Deprecated, use gf.c.taper_cross_section instead Args: length: width1: width2: w_slab1 w_slab2 layer_wg: layer_slab: layers_cladding cladding_offset: cross_section: for input waveguide .. code:: __________________________ / | _______/____________|______________ / | width1 |w_slab1 | w_slab2 width2 ______\_____________|______________ \ | \__________________________ """ cross_section = gf.partial(cross_section, width=width1) taper_wg = taper( length=length, width1=width1, width2=width2, layer=layer_wg, cross_section=cross_section, ) taper_slab = taper( length=length, width1=w_slab1, width2=w_slab2, layer=layer_slab, ) c = gf.Component() for _t in [taper_wg, taper_slab]: taper_ref = _t.ref() c.add(taper_ref) c.absorb(taper_ref) c.info["length"] = float(length) c.add_port(name="o1", port=taper_wg.ports["o1"]) c.add_port(name="o2", port=taper_slab.ports["o2"]) if layers_cladding: points = get_padding_points( component=c, default=0, bottom=cladding_offset, top=cladding_offset, ) for layer in layers_cladding: c.add_polygon(points, layer=layer) return c
def bend_euler(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: CrossSectionFactory = strip, **kwargs) -> Component: """Returns an euler bend that adiabatically transitions from straight to curved. By default, `radius` corresponds to the minimum radius of curvature of the bend. However, if `with_arc_floorplan` is True, `radius` corresponds to the effective radius of curvature (making the curve a drop-in replacement for an arc). If p < 1.0, will create a "partial euler" curve as described in Vogelbacher et. al. https://dx.doi.org/10.1364/oe.27.031394 default p = 0.5 based on this paper https://www.osapublishing.org/oe/fulltext.cfm?uri=oe-25-8-9150&id=362937 Args: 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: """ x = cross_section(**kwargs) radius = x.info["radius"] p = euler(radius=radius, angle=angle, p=p, use_eff=with_arc_floorplan, npoints=npoints) c = extrude(p, x) c.info.length = snap_to_grid(p.length()) c.info.dy = abs(float(p.points[0][0] - p.points[-1][0])) c.info.radius_min = float(p.info["Rmin"]) c.info.radius = radius if with_cladding_box and x.info["layers_cladding"]: layers_cladding = x.info["layers_cladding"] cladding_offset = x.info["cladding_offset"] top = cladding_offset if angle == 180 else 0 points = get_padding_points( component=c, default=0, bottom=cladding_offset, right=cladding_offset, top=top, ) for layer in layers_cladding or []: c.add_polygon(points, layer=layer) if direction == "cw": c.mirror(p1=[0, 0], p2=[1, 0]) return c