def test_path_length_matching_nb_loops(): c = pp.Component("path_length_match_sample") dy = 2000.0 xs1 = [-500, -300, -100, -90, -80, -55, -35, 200, 210, 240, 500, 650] pitch = 100.0 N = len(xs1) xs2 = [-20 + i * pitch for i in range(N)] a1 = 90 a2 = a1 + 180 ports1 = [pp.Port(f"top_{i}", (xs1[i], 0), 0.5, a1) for i in range(N)] ports2 = [pp.Port(f"bottom_{i}", (xs2[i], dy), 0.5, a2) for i in range(N)] routes = pp.routing.connect_bundle_path_length_match(ports1, ports2, nb_loops=2) for route in routes: # print(route.parent.length) assert np.isclose(route.parent.length, 2681.07963267949) c.add(routes) c.routes = routes return c
def import_gds(gdsname: str, rename_ports: bool = False) -> Component: """import gds from SIEPIC PDK""" c = pp.import_gds(gds / f"{gdsname}.gds") c.function_name = gdsname n = 0 for label in c.get_labels(): if label.text.startswith("opt"): n += 1 for label in c.get_labels(): if label.text.startswith("opt"): port = pp.Port( name=label.text, midpoint=label.position, width=port_width, orientation=guess_port_orientaton( position=label.position, name=gdsname, label=label.text, n=n, ), layer=layer, ) c.add_port(port) if rename_ports: auto_rename_ports(c) return c
def big_device(w=400.0, h=400.0, N=16, port_pitch=15.0, layer=pp.LAYER.WG, wg_width=0.5): """ big device with N ports on each side """ component = pp.Component() p0 = np.array((0, 0)) dx = w / 2 dy = h / 2 points = [[dx, dy], [dx, -dy], [-dx, -dy], [-dx, dy]] component.add_polygon(points, layer=layer) port_params = {"layer": layer, "width": wg_width} for i in range(N): port = pp.Port( name="W{}".format(i), midpoint=p0 + (-dx, (i - N / 2) * port_pitch), orientation=180, **port_params ) component.add_port(port) for i in range(N): port = pp.Port( name="E{}".format(i), midpoint=p0 + (dx, (i - N / 2) * port_pitch), orientation=0, **port_params ) component.add_port(port) for i in range(N): port = pp.Port( name="N{}".format(i), midpoint=p0 + ((i - N / 2) * port_pitch, dy), orientation=90, **port_params ) component.add_port(port) for i in range(N): port = pp.Port( name="S{}".format(i), midpoint=p0 + ((i - N / 2) * port_pitch, -dy), orientation=-90, **port_params ) component.add_port(port) return component
def import_gds(gdsname): """ import gds from SIEPIC PDK """ c = pp.import_gds(gds / f"{gdsname}.gds") for label in c.get_labels(): if label.text.startswith("opt"): port = pp.Port( name=label.text, midpoint=label.position, width=port_width, orientation=position2orientation(label.position), layer=layer, ) c.add_port(port) return c
def flip(port): """ Flip a phidl Port """ return pp.Port(port.name, port.midpoint, port.width, port.orientation + 180)
def spiral_inner_io( N: int = 6, x_straight_inner_right: float = 150.0, x_straight_inner_left: float = 150.0, y_straight_inner_top: float = 50.0, y_straight_inner_bottom: float = 10.0, grating_spacing: float = 127.0, dx: float = 3.0, dy: float = 3.0, bend90_function: Callable = bend_circular, bend180_function: Callable = bend_circular180, bend_radius: float = 50.0, wg_width: float = 0.5, wg_width_grating_coupler: float = 0.5, straight_factory: Callable = waveguide, taper: Optional[Callable] = None, length: Optional[float] = None, ) -> Component: """Spiral with ports inside the spiral circle. Args: N: number of loops x_straight_inner_right: x_straight_inner_left: y_straight_inner_top: y_straight_inner_bottom: grating_spacing: dx: center to center x-spacing dy: center to center y-spacing bend90_function bend180_function bend_radius wg_width straight_factory taper: length: cm .. plot:: :include-source: import pp from pp.components.spiral_inner_io import spiral_inner_io c = spiral_inner_io() pp.plotgds(c) """ if length: if bend180_function == bend_circular180: y_straight_inner_top = get_straight_length( length_cm=length, spiral_function=spiral_inner_io, N=N, x_straight_inner_right=x_straight_inner_right, x_straight_inner_left=x_straight_inner_left, y_straight_inner_top=y_straight_inner_top, y_straight_inner_bottom=y_straight_inner_bottom, grating_spacing=grating_spacing, dx=dx, dy=dy, straight_factory=waveguide, bend90_function=bend_euler90, bend180_function=bend_euler180, wg_width=wg_width, ) else: y_straight_inner_top = get_straight_length( length_cm=length, spiral_function=spiral_inner_io_euler, N=N, x_straight_inner_right=x_straight_inner_right, x_straight_inner_left=x_straight_inner_left, y_straight_inner_top=y_straight_inner_top, y_straight_inner_bottom=y_straight_inner_bottom, grating_spacing=grating_spacing, dx=dx, dy=dy, wg_width=wg_width, ) _bend180 = pp.call_if_func(bend180_function, radius=bend_radius, width=wg_width) _bend90 = pp.call_if_func(bend90_function, radius=bend_radius, width=wg_width) rx, ry = get_bend_port_distances(_bend90) _, rx180 = get_bend_port_distances(_bend180) # rx180, second arg since we rotate component = pp.Component() # gc_port_lbl = "W0" # gc1 = _gc.ref(port_id=gc_port_lbl, position=(0, 0), rotation=-90) # gc2 = _gc.ref(port_id=gc_port_lbl, position=(grating_spacing, 0), rotation=-90) # component.add([gc1, gc2]) p1 = pp.Port( name="S0", midpoint=(0, y_straight_inner_top), orientation=270, width=wg_width, layer=pp.LAYER.WG, ) p2 = pp.Port( name="S1", midpoint=(grating_spacing, y_straight_inner_top), orientation=270, width=wg_width, layer=pp.LAYER.WG, ) taper = pp.c.taper( width1=wg_width_grating_coupler, width2=_bend180.ports["W0"].width, length=TAPER_LENGTH + y_straight_inner_top - 15 - 35, ) taper_ref1 = component.add_ref(taper) taper_ref1.connect("2", p1) taper_ref2 = component.add_ref(taper) taper_ref2.connect("2", p2) component.absorb(taper_ref1) component.absorb(taper_ref2) component.add_port(name="S0", port=taper_ref1.ports["1"]) component.add_port(name="S1", port=taper_ref2.ports["1"]) # Create manhattan path going from west grating to westest port of bend 180 _pt = np.array(p1.position) pts_w = [_pt] for i in range(N): y1 = y_straight_inner_top + ry + (2 * i + 1) * dy x2 = grating_spacing + 2 * rx + x_straight_inner_right + (2 * i + 1) * dx y3 = -y_straight_inner_bottom - ry - (2 * i + 3) * dy x4 = -x_straight_inner_left - (2 * i + 1) * dx if i == N - 1: x4 = x4 - rx180 + dx _pt1 = np.array([_pt[0], y1]) _pt2 = np.array([x2, _pt1[1]]) _pt3 = np.array([_pt2[0], y3]) _pt4 = np.array([x4, _pt3[1]]) _pt5 = np.array([_pt4[0], 0]) _pt = _pt5 pts_w += [_pt1, _pt2, _pt3, _pt4, _pt5] route_west = round_corners( pts_w, bend90=_bend90, straight_factory=straight_factory, taper=taper ) component.add(route_west["references"]) # Add loop back bend180_ref = _bend180.ref( port_id="W1", position=route_west["ports"]["output"], rotation=90 ) component.add(bend180_ref) component.absorb(bend180_ref) # Create manhattan path going from east grating to eastest port of bend 180 _pt = np.array(p2.position) pts_e = [_pt] for i in range(N): y1 = y_straight_inner_top + ry + (2 * i) * dy x2 = grating_spacing + 2 * rx + x_straight_inner_right + 2 * i * dx y3 = -y_straight_inner_bottom - ry - (2 * i + 2) * dy x4 = -x_straight_inner_left - (2 * i) * dx _pt1 = np.array([_pt[0], y1]) _pt2 = np.array([x2, _pt1[1]]) _pt3 = np.array([_pt2[0], y3]) _pt4 = np.array([x4, _pt3[1]]) _pt5 = np.array([_pt4[0], 0]) _pt = _pt5 pts_e += [_pt1, _pt2, _pt3, _pt4, _pt5] route_east = round_corners( pts_e, bend90=_bend90, straight_factory=straight_factory, taper=taper ) component.add(route_east["references"]) length = ( route_east["settings"]["length"] + route_west["settings"]["length"] + bend180_ref.info["length"] ) component.length = pp.drc.snap_to_1nm_grid(length + 2 * y_straight_inner_top) return component