def coupler90( bend_radius=10.0, width=0.5, gap=0.2, waveguide_factory=waveguide, bend90_factory=bend_circular, ): """ Waveguide coupled to a bend with gap Args: bend_radius: um width: waveguide width (um) gap: um .. plot:: :include-source: import pp c = pp.c.coupler90() pp.plotgds(c) """ y = width + gap _bend = bend90_factory(radius=bend_radius, width=width).ref((0, y)) c = Component() _wg = c.add_ref(waveguide_factory(length=bend_radius, width=width)) c.add(_bend) # This component is a leaf cell => using absorb c.absorb(_wg) c.absorb(_bend) port_width = 2 * width + gap c.add_port(port=_wg.ports["E0"], name="E0") c.add_port(port=_bend.ports["N0"], name="N0") c.add_port(name="W0", midpoint=[0, y / 2], width=port_width, orientation=180) c.y = y return c
def coupler_straight( length=10, width=0.5, gap=0.27, layer=pp.LAYER.WG, layer_cladding=pp.layer("wgclad"), cladding_offset=3, ): """ straight coupled waveguides. Two multimode ports .. plot:: :include-source: import pp c = pp.c.coupler_straight() pp.plotgds(c) """ c = Component() # Top path c.add_polygon([(0, 0), (length, 0), (length, width), (0, width)], layer=layer) y = width + gap # Bottom path c.add_polygon([(0, y), (length, y), (length, width + y), (0, width + y)], layer=layer) # One multimode port on each side port_w = width * 2 + gap c.add_port(name="W0", midpoint=[0, port_w / 2], width=port_w, orientation=180) c.add_port(name="E0", midpoint=[length, port_w / 2], width=port_w, orientation=0) c.width = width c.length = length # cladding ymax = 2 * width + gap + cladding_offset c.add_polygon( [(0, -cladding_offset), (length, -cladding_offset), (length, ymax), (0, ymax)], layer=layer_cladding, ) return c
def waveguide_heater( length=10.0, width=0.5, heater_width=0.5, heater_spacing=1.2, metal_connection=True, sstw=2.0, trench_width=0.5, trench_keep_out=2.0, trenches=[ { "nb_segments": 2, "lane": 1, "x_start_offset": 0 }, { "nb_segments": 2, "lane": -1, "x_start_offset": 0 }, ], layers_heater=[LAYER.HEATER], waveguide_factory=waveguide, layer_trench=LAYER.DEEPTRENCH, ): """ waveguide with heater .. code:: TTTTTTTTTTTTT TTTTTTTTTTTTT <-- trench HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH <-- heater ------------------------------ <-- waveguide HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH <-- heater TTTTTTTTTTTTT TTTTTTTTTTTTT <-- trench .. plot:: :include-source: import pp c = pp.c.waveguide_heater() pp.plotgds(c) """ c = Component() _heater = heater(length=length, width=heater_width, layers_heater=layers_heater) y_heater = heater_spacing + (width + heater_width) / 2 heater_top = c << _heater heater_bot = c << _heater heater_top.movey(+y_heater) heater_bot.movey(-y_heater) wg = c << waveguide_factory(length=length, width=width) for i in [heater_top, heater_bot, wg]: c.absorb(i) # Add wg ports for p in wg.ports.values(): c.add_port(name=p.name, port=p) # Add heater ports for p in heater_top.ports.values(): c.add_port(name="HT" + p.name, port=p) for p in heater_bot.ports.values(): c.add_port(name="HB" + p.name, port=p) c.settings["width"] = width c.settings["heater_width"] = heater_width c.settings["heater_spacing"] = heater_spacing c.settings["length"] = length add_trenches(c, sstw, trench_width, trench_keep_out, trenches, layer_trench=layer_trench) return c
def wg_heater_connected( waveguide_heater=waveguide_heater, wg_heater_connector=wg_heater_connector, tlm_layers=[ LAYER.VIA1, LAYER.M1, LAYER.VIA2, LAYER.M2, LAYER.VIA3, LAYER.M3 ], **kwargs, ): """ .. plot:: :include-source: import pp c = pp.c.wg_heater_connected() pp.plotgds(c) """ wg_heater = waveguide_heater(**kwargs) conn1 = wg_heater_connector( heater_ports=[wg_heater.ports["E0"], wg_heater.ports["E2"]], tlm_layers=tlm_layers, ) conn2 = wg_heater_connector( heater_ports=[wg_heater.ports["W0"], wg_heater.ports["W2"]], tlm_layers=tlm_layers, ) cmp = Component() for c in [wg_heater, conn1, conn2]: _c = cmp.add_ref(c) cmp.absorb(_c) for i, p in enumerate(wg_heater.get_optical_ports()): cmp.add_port(name=i, port=p) i += 1 cmp.add_port(name=i, port=conn1.ports["0"]) i += 1 cmp.add_port(name=i, port=conn2.ports["0"]) return cmp
def wg_heater_connector( heater_ports, metal_width=10.0, tlm_layers=[ LAYER.VIA1, LAYER.M1, LAYER.VIA2, LAYER.M2, LAYER.VIA3, LAYER.M3 ], ): """ Connects together a pair of wg heaters and connect to a M3 port """ cmp = Component() assert len(heater_ports) == 2 assert (heater_ports[0].orientation == heater_ports[1].orientation ), "both ports should be facing in the same direction" angle = heater_ports[0].orientation angle = angle % 360 assert angle in [0, 180], "angle should be 0 or 180, got {}".format(angle) dx = 0.0 dy = 0.0 angle_to_dps = {0: [(-dx, -dy), (-dx, dy)], 180: [(dx, -dy), (dx, dy)]} ports = heater_ports hw = heater_ports[0].width if angle in [0, 180]: ports.sort(key=lambda p: p.y) else: ports.sort(key=lambda p: p.x) _heater_to_metal = tlm(width=0.5, height=0.5, layers=tlm_layers, vias=[]) tlm_positions = [] for port, dp in zip(ports, angle_to_dps[angle]): # Extend heater p = port.midpoint # Add via/metal transitions tlm_pos = p + dp hm = _heater_to_metal.ref(position=tlm_pos) tlm_positions += [tlm_pos] cmp.add(hm) ss = 1 if angle == 0 else -1 # Connect both sides with top metal edge_metal_piece_width = 7.0 x = ss * edge_metal_piece_width / 2 top_metal_layer = tlm_layers[-1] cmp.add_polygon( line( tlm_positions[0] + (x, -hw / 2), tlm_positions[1] + (x, hw / 2), edge_metal_piece_width, ), layer=top_metal_layer, ) # Add metal port cmp.add_port( name="0", midpoint=0.5 * sum(tlm_positions) + (ss * edge_metal_piece_width / 2, 0), orientation=angle, width=metal_width, layer=top_metal_layer, port_type="dc", ) return cmp
def coupler90( bend_radius=10.0, width=0.5, gap=0.2, waveguide_factory=waveguide, bend90_factory=bend_circular, ): """ Waveguide coupled to a bend with gap Args: bend_radius: um width: waveguide width (um) gap: um .. plot:: :include-source: import pp c = pp.c.coupler90() pp.plotgds(c) """ # pp.drc.assert_on_1nm_grid((width + gap) / 2) y = pp.drc.snap_to_1nm_grid((width + gap) / 2) c = Component() wg = c << waveguide_factory(length=bend_radius, width=width) bend = c << bend90_factory(radius=bend_radius, width=width) pbw = bend.ports["W0"] bend.movey(pbw.midpoint[1] + gap + width) # This component is a leaf cell => using absorb c.absorb(wg) c.absorb(bend) port_width = 2 * width + gap c.add_port(port=wg.ports["E0"], name="E0") c.add_port(port=bend.ports["N0"], name="N0") c.add_port(name="W0", midpoint=[0, y], width=port_width, orientation=180) return c
def _bend_circular_heater( radius=10, wg_width=0.5, theta=-90, start_angle=0, angle_resolution=2.5, heater_to_wg_distance=1.2, heater_width=0.5, ): """ Creates an arc of arclength ``theta`` starting at angle ``start_angle`` Args: radius width: of the waveguide theta: arc length start_angle: angle_resolution """ component = Component() wg_bend = bend_circular( radius=radius, width=wg_width, theta=theta, start_angle=start_angle, angle_resolution=angle_resolution, layer=LAYER.WG, ).ref((0, 0)) a = heater_to_wg_distance + wg_width / 2 + heater_width / 2 heater_outer = bend_circular( radius=radius + a, width=heater_width, theta=theta, start_angle=start_angle, angle_resolution=angle_resolution, layer=LAYER.HEATER, ).ref((0, -a)) heater_inner = bend_circular( radius=radius - a, width=heater_width, theta=theta, start_angle=start_angle, angle_resolution=angle_resolution, layer=LAYER.HEATER, ).ref((0, a)) component.add(wg_bend) component.add(heater_outer) component.add(heater_inner) component.absorb(wg_bend) component.absorb(heater_outer) component.absorb(heater_inner) i = 0 for device in [wg_bend, heater_outer, heater_inner]: for port in device.ports.values(): component.ports["{}".format(i)] = port i += 1 component.info["length"] = wg_bend.info["length"] component.radius = radius component.width = wg_width return component