def crossing_from_taper(taper=lambda: taper(width2=2.5, length=3.0)): """ Crossing based on a taper. The default is a dummy taper """ taper = pp.call_if_func(taper) c = pp.Component() for i, a in enumerate([0, 90, 180, 270]): _taper = taper.ref(position=(0, 0), port_id="2", rotation=a) c.add(_taper) c.add_port(name="{}".format(i), port=_taper.ports["1"]) c.absorb(_taper) c = pp.port.rename_ports_by_orientation(c) return c
def add_io_optical(c, grating_coupler=grating_coupler_te, gc_port_name="W0", component_name=None, **kwargs): """ returns component with optical IO (tapers, south routes and grating_couplers) Args: component: to connect optical_io_spacing: SPACING_GC grating_coupler: grating coupler instance, function or list of functions bend_factory: bend_circular straight_factory: waveguide fanout_length: None, # if None, automatic calculation of fanout length max_y0_optical: None with_align_ports: True, adds loopback structures waveguide_separation=4.0 bend_radius: BEND_RADIUS list_port_labels: None, adds TM labels to port indices in this list connected_port_list_ids: None # only for type 0 optical routing nb_optical_ports_lines: 1 force_manhattan: False excluded_ports: grating_indices: None routing_waveguide: None routing_method: connect_strip gc_port_name: W0 optical_routing_type: None: autoselection, 0: no extension gc_rotation=-90 layer_label=LAYER.LABEL input_port_indexes=[0] component_name: for the label """ if not c.ports: return c cc = Component( settings=c.get_settings(), test_protocol=c.test_protocol, data_analysis_protocol=c.data_analysis_protocol, ) cc.function_name = "add_io_optical" if isinstance(grating_coupler, list): gc = grating_coupler[0] else: gc = grating_coupler gc = pp.call_if_func(gc) if "polarization" in gc.settings: gc.polarization = gc.settings["polarization"] cc.name = "{}_{}".format(c.name, gc.polarization) port_width_gc = list(gc.ports.values())[0].width port_width_component = list(c.ports.values())[0].width if port_width_component != port_width_gc: c = add_tapers( c, taper(length=10, width1=port_width_gc, width2=port_width_component)) elements, io_gratings_lines, _ = _get_optical_io_elements( component=c, grating_coupler=grating_coupler, gc_port_name=gc_port_name, component_name=component_name, **kwargs) if len(elements) == 0: return c cc.add(elements) for io_gratings in io_gratings_lines: cc.add(io_gratings) cc.add(c.ref()) cc.move(origin=io_gratings_lines[0][0].ports[gc_port_name], destination=(0, 0)) return cc
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, partial_etch: bool = False, layer: Tuple[int, int] = pp.LAYER.WG, layer_partial_etch: Tuple[int, int] = pp.LAYER.SLAB150, polarization="te", wavelength=1500, ) -> 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 .. plot:: :include-source: import pp c = pp.c.grating_coupler_uniform() pp.plotgds(c) .. code:: \ \ \ \ \ \ \ \ _|-|_|-|_|-|___ |_______________ W0 """ G = Component() if partial_etch: partetch_overhang = 5 _compass = compass( size=[period * (1 - fill_factor), width_grating + partetch_overhang * 2], layer=layer_partial_etch, ) # make the etched areas (opposite to teeth) for i in range(num_teeth): cgrating = G.add_ref(_compass) cgrating.x += i * period # draw the deep etched square around the grating deepbox = G.add_ref( compass(size=[num_teeth * period, width_grating], layer=layer) ) deepbox.movex(num_teeth * period / 2) else: for i in range(num_teeth): cgrating = G.add_ref( compass(size=[period * fill_factor, width_grating], layer=layer) ) cgrating.x += i * period # make the taper tgrating = G.add_ref( taper( length=length_taper, width1=width_grating, width2=width, port=None, layer=layer, ) ) tgrating.xmin = cgrating.xmax G.add_port(port=tgrating.ports["2"], name="W0") G.polarization = polarization G.wavelength = wavelength G.rotate(180) pp.assert_grating_coupler_properties(G) return G
width=wg_width, length=length_y + dut.xsize) waveguide_top = call_if_func(waveguide, width=wg_width, length=length_x) bend = call_if_func(bend, width=wg_width, radius=bend_radius) c = Component() cb = c << coupler wl = c << waveguide_side if with_dut: d = c << dut else: d = c << waveguide_side bl = c << bend br = c << bend wt = c << waveguide_top wl.connect(port="E0", destination=cb.ports["N0"]) bl.connect(port="N0", destination=wl.ports["W0"]) wt.connect(port="W0", destination=bl.ports["W0"]) br.connect(port="N0", destination=wt.ports["E0"]) d.connect(port="W0", destination=br.ports["W0"]) c.add_port("E0", port=cb.ports["E0"]) c.add_port("W0", port=cb.ports["W0"]) return c if __name__ == "__main__": c = ring_single_dut(component=taper(width2=3)) pp.show(c)
width=wg_width, length=length_y + dut.xsize) waveguide_top = call_if_func(waveguide, width=wg_width, length=length_x) bend = call_if_func(bend, width=wg_width, radius=bend_radius) c = Component() cb = c << coupler wl = c << waveguide_side if with_dut: d = c << dut else: d = c << waveguide_side bl = c << bend br = c << bend wt = c << waveguide_top wl.connect(port="E0", destination=cb.ports["N0"]) bl.connect(port="N0", destination=wl.ports["W0"]) wt.connect(port="W0", destination=bl.ports["W0"]) br.connect(port="N0", destination=wt.ports["E0"]) d.connect(port="W0", destination=br.ports["W0"]) c.add_port("E0", port=cb.ports["E0"]) c.add_port("W0", port=cb.ports["W0"]) return c if __name__ == "__main__": c = ring_single_dut(component=taper(width2=3), pins=True) pp.show(c)