def litho_calipers( notch_size: List[int] = [2, 5], notch_spacing: int = 2, num_notches: int = 11, offset_per_notch: float = 0.1, row_spacing: int = 0, layer_top: int = 1, layer_bottom: int = 2, ) -> Component: """ vernier caliper structure to test lithography alignment Only the middle finger is aligned and the rest are offset. Args: notch_size: [xwidth, yheight] notch_spacing: 2 num_notches: 11 offset_per_notch: 0.1 row_spacing: 0 layer_top: 1 layer_bottom:2 .. plot:: :include-source: import pp c = pp.c.litho_calipers() pp.plotgds(c) """ D = pp.Component() num_notches_total = num_notches * 2 + 1 centre_notch = num_notches R1 = pc.rectangle(size=(notch_size), layer=layer_top) R2 = pc.rectangle(size=(notch_size), layer=layer_bottom) for i in range(num_notches_total): if i == centre_notch: D.add_ref(R1).movex(i * (notch_size[0] + notch_spacing)).movey( notch_size[1]) D.add_ref(R2).movex(i * (notch_size[0] + notch_spacing) + offset_per_notch * (centre_notch - i)).movey(-2 * notch_size[1] - row_spacing) D.add_ref(R1).movex(i * (notch_size[0] + notch_spacing)) D.add_ref(R2).movex(i * (notch_size[0] + notch_spacing) + offset_per_notch * (centre_notch - i)).movey(-notch_size[1] - row_spacing) return D
def litho_steps( line_widths: List[float] = (1.0, 2.0, 4.0, 8.0, 16.0), line_spacing: float = 10.0, height: float = 100.0, layer: Tuple[int, int] = pp.LAYER.WG, ) -> Component: """ Produces a positive + negative tone linewidth test, used for lithography resolution test patterning Args: line_widths: line_spacing: height: layer: .. plot:: :include-source: import pp c = pp.c.litho_steps() pp.plotgds(c) """ D = pp.Component() height = height / 2 T1 = pc.text(text="%s" % str(line_widths[-1]), size=height, justify="center", layer=layer) D.add_ref(T1).rotate(90).movex(-height / 10) R1 = pc.rectangle(size=(line_spacing, height), layer=layer) D.add_ref(R1).movey(-height) count = 0 for i in reversed(line_widths): count += line_spacing + i R2 = pc.rectangle(size=(i, height), layer=layer) D.add_ref(R1).movex(count).movey(-height) D.add_ref(R2).movex(count - i) return D
def litho_star(num_lines=20, line_width=2, diameter=200, layer=0): """ Creates a circular-star shape from lines, used as a lithographic resolution test pattern .. plot:: :include-source: import pp c = pp.c.litho_star() pp.plotgds(c) """ D = pp.Component() degree = 180 / num_lines R1 = rectangle(size=(line_width, diameter), layer=layer) for i in range(num_lines): r1 = D.add_ref(R1).rotate(degree * i) r1.center = (0, 0) return D
def test_resistance( pad_size=[50, 50], num_squares=1000, width=1, res_layer=0, pad_layer=None, gnd_layer=None, ): """ meander to test resistance from phidl.geometry Args: pad_size: Size of the two matched impedance pads (microns) num_squares: Number of squares comprising the resonator wire width: The width of the squares (microns) res_layer: pad_layer: gnd_layer: .. plot:: :include-source: import pp c = pp.c.test_resistance() pp.plotgds(c) """ x = pad_size[0] z = pad_size[1] # Checking validity of input if x <= 0 or z <= 0: raise ValueError("Pad must have positive, real dimensions") elif width > z: raise ValueError("Width of cell cannot be greater than height of pad") elif num_squares <= 0: raise ValueError("Number of squares must be a positive real number") elif width <= 0: raise ValueError("Width of cell must be a positive real number") # Performing preliminary calculations num_rows = int(np.floor(z / (2 * width))) if num_rows % 2 == 0: num_rows -= 1 num_columns = num_rows - 1 squares_in_row = (num_squares - num_columns - 2) / num_rows # Compensating for weird edge cases if squares_in_row < 1: num_rows = round(num_rows / 2) - 2 squares_in_row = 1 if width * 2 > z: num_rows = 1 squares_in_row = num_squares - 2 length_row = squares_in_row * width # Creating row/column corner combination structure T = pp.Component() Row = pc.rectangle(size=(length_row, width), layer=res_layer) Col = pc.rectangle(size=(width, width), layer=res_layer) T.add_ref(Row) col = T.add_ref(Col) col.move([length_row - width, -width]) # Creating entire waveguide net N = pp.Component("net") n = 1 for i in range(num_rows): if i != num_rows - 1: d = N.add_ref(T) else: d = N.add_ref(Row) if n % 2 == 0: d.reflect(p1=(d.x, d.ymax), p2=(d.x, d.ymin)) d.movey(-(n - 1) * T.ysize) n += 1 d = N.add_ref(Col).movex(-width) d = N.add_ref(Col).move([length_row, -(n - 2) * T.ysize]) # Creating pads P = pp.Component() Pad1 = pc.rectangle(size=(x, z), layer=pad_layer) Pad2 = pc.rectangle(size=(x + 5, z), layer=pad_layer) Gnd1 = offset(Pad1, distance=-5, layer=gnd_layer) Gnd2 = offset(Pad2, distance=-5, layer=gnd_layer) pad1 = P.add_ref(Pad1).movex(-x - width) pad2 = P.add_ref(Pad1).movex(length_row + width) P.add_ref(Gnd1).center = pad1.center gnd2 = P.add_ref(Gnd2) P.add_ref(N).y = pad1.y gnd2.center = pad2.center gnd2.movex(2.5) return P
def test_comb( pad_size=(200, 200), wire_width=1, wire_gap=3, comb_layer=0, overlap_zigzag_layer=1, comb_pad_layer=None, comb_gnd_layer=None, overlap_pad_layer=None, ): """ Superconducting heater device from phidl.geometry Args: pad_size=(200, 200) wire_width=1 wire_gap=3 comb_layer=0 overlap_zigzag_layer=1 comb_pad_layer=None comb_gnd_layer=None overlap_pad_layer=None """ CI = pp.Component() if comb_pad_layer is None: comb_pad_layer = comb_layer if comb_gnd_layer is None: comb_gnd_layer = comb_layer if overlap_pad_layer is None: overlap_pad_layer = overlap_zigzag_layer wire_spacing = wire_width + wire_gap * 2 # %% pad overlays overlay_padb = CI.add_ref( pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10), layer=overlap_pad_layer)) overlay_padl = CI.add_ref( pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10), layer=comb_pad_layer)) overlay_padt = CI.add_ref( pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10), layer=comb_pad_layer)) overlay_padr = CI.add_ref( pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10), layer=comb_gnd_layer)) overlay_padl.xmin = 0 overlay_padl.ymin = 0 overlay_padb.ymax = 0 overlay_padb.xmin = overlay_padl.xmax + pad_size[1] / 5 overlay_padr.ymin = overlay_padl.ymin overlay_padr.xmin = overlay_padb.xmax + pad_size[1] / 5 overlay_padt.xmin = overlay_padl.xmax + pad_size[1] / 5 overlay_padt.ymin = overlay_padl.ymax # %% pads padl = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer)) padt = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer)) padr = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer)) padb = CI.add_ref(pc.rectangle(size=pad_size, layer=overlap_zigzag_layer)) padl_nub = CI.add_ref( pc.rectangle(size=(pad_size[0] / 4, pad_size[1] / 2), layer=comb_layer)) padr_nub = CI.add_ref( pc.rectangle(size=(pad_size[0] / 4, pad_size[1] / 2), layer=comb_layer)) padl.xmin = overlay_padl.xmin padl.center = [padl.center[0], overlay_padl.center[1]] padt.ymax = overlay_padt.ymax padt.center = [overlay_padt.center[0], padt.center[1]] padr.xmax = overlay_padr.xmax padr.center = [padr.center[0], overlay_padr.center[1]] padb.ymin = overlay_padb.ymin padb.center = [overlay_padb.center[0], padb.center[1]] padl_nub.xmin = padl.xmax padl_nub.center = [padl_nub.center[0], padl.center[1]] padr_nub.xmax = padr.xmin padr_nub.center = [padr_nub.center[0], padr.center[1]] # %% connected zig head = CI.add_ref( pc.compass(size=(pad_size[0] / 12, wire_width), layer=comb_layer)) head.xmin = padl_nub.xmax head.ymax = padl_nub.ymax connector = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=comb_layer)) connector.connect(port="W", destination=head.ports["E"]) old_port = connector.ports["S"] top = True obj = connector while obj.xmax + pad_size[0] / 12 < padr_nub.xmin: # long zig zag rectangle obj = CI.add_ref( pc.compass(size=(pad_size[1] / 2 - 2 * wire_width, wire_width), layer=comb_layer)) obj.connect(port="W", destination=old_port) old_port = obj.ports["E"] if top: # zig zag edge rectangle obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=comb_layer)) obj.connect(port="N", destination=old_port) top = False else: # zig zag edge rectangle obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=comb_layer)) obj.connect(port="S", destination=old_port) top = True # comb rectange comb = CI.add_ref( pc.rectangle( size=( (padt.ymin - head.ymax) + pad_size[1] / 2 - (wire_spacing + wire_width) / 2, wire_width, ), layer=comb_layer, )) comb.rotate(90) comb.ymax = padt.ymin comb.xmax = obj.xmax - (wire_spacing + wire_width) / 2 old_port = obj.ports["E"] obj = CI.add_ref( pc.compass(size=(wire_spacing, wire_width), layer=comb_layer)) obj.connect(port="W", destination=old_port) old_port = obj.ports["E"] obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=comb_layer)) obj.connect(port="W", destination=old_port) if top: old_port = obj.ports["S"] else: old_port = obj.ports["N"] old_port = obj.ports["E"] if padr_nub.xmin - obj.xmax > 0: tail = CI.add_ref( pc.compass(size=(padr_nub.xmin - obj.xmax, wire_width), layer=comb_layer)) else: tail = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=comb_layer)) tail.connect(port="W", destination=old_port) # %% disconnected zig dhead = CI.add_ref( pc.compass( size=(padr_nub.ymin - padb.ymax - wire_width, wire_width), layer=overlap_zigzag_layer, )) dhead.rotate(90) dhead.ymin = padb.ymax dhead.xmax = tail.xmin - (wire_spacing + wire_width) / 2 connector = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=overlap_zigzag_layer)) connector.connect(port="S", destination=dhead.ports["E"]) old_port = connector.ports["N"] right = True obj = connector while obj.ymax + wire_spacing + wire_width < head.ymax: obj = CI.add_ref( pc.compass(size=(wire_spacing, wire_width), layer=overlap_zigzag_layer)) obj.connect(port="W", destination=old_port) old_port = obj.ports["E"] if right: obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=overlap_zigzag_layer)) obj.connect(port="W", destination=old_port) right = False else: obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=overlap_zigzag_layer)) obj.connect(port="E", destination=old_port) right = True old_port = obj.ports["N"] obj = CI.add_ref( pc.compass( size=( dhead.xmin - (head.xmax + head.xmin + wire_width) / 2, wire_width, ), layer=overlap_zigzag_layer, )) obj.connect(port="E", destination=old_port) old_port = obj.ports["W"] obj = CI.add_ref( pc.compass(size=(wire_width, wire_width), layer=overlap_zigzag_layer)) obj.connect(port="S", destination=old_port) if right: old_port = obj.ports["W"] else: old_port = obj.ports["E"] return CI
def test_via( num_vias=100, wire_width=10, via_width=15, via_spacing=40, pad_size=(300, 300), min_pad_spacing=0, pad_layer=0, wiring1_layer=1, wiring2_layer=2, via_layer=3, ): """ Via cutback to extract via resistance from phidl.geometry Args: num_vias=100 wire_width=10 via_width=15 via_spacing=40 pad_size=(300, 300) min_pad_spacing=0 pad_layer=0 wiring1_layer=1 wiring2_layer=2 via_layer=3 Usage: Call via_route_test_structure() by indicating the number of vias you want drawn. You can also change the other parameters however if you do not specifiy a value for a parameter it will just use the default value Ex:: via_route_test_structure(num_vias=54) - or -:: via_route_test_structure(num_vias=12, pad_size=(100,100),wire_width=8) total requested vias (num_vias) -> this needs to be even pad size (pad_size) -> given in a pair (width, height) wire_width -> how wide each wire should be pad_layer -> GDS layer number of the pads wiring1_layer -> GDS layer number of the top wiring wiring2_layer -> GDS layer number of the bottom wiring via_layer -> GDS layer number of the vias ex: via_route(54, min_pad_spacing=300) .. plot:: :include-source: import pp c = pp.c.test_via() pp.plotgds(c) """ VR = pp.Component() pad1 = VR.add_ref(pc.rectangle(size=pad_size, layer=pad_layer)) pad1_overlay = VR.add_ref(pc.rectangle(size=pad_size, layer=wiring1_layer)) pad2 = VR.add_ref(pc.rectangle(size=pad_size, layer=pad_layer)) pad2_overlay = VR.add_ref(pc.rectangle(size=pad_size, layer=wiring1_layer)) nub = VR.add_ref( pc.compass(size=(3 * wire_width, wire_width), layer=pad_layer)) nub_overlay = VR.add_ref( pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer)) head = VR.add_ref( pc.compass(size=(wire_width, wire_width), layer=pad_layer)) head_overlay = VR.add_ref( pc.compass(size=(wire_width, wire_width), layer=wiring1_layer)) nub.ymax = pad1.ymax - 5 nub.xmin = pad1.xmax nub_overlay.ymax = pad1.ymax - 5 nub_overlay.xmin = pad1.xmax head.connect(port="W", destination=nub.ports["E"]) head_overlay.connect(port="W", destination=nub_overlay.ports["E"]) pad1_overlay.xmin = pad1.xmin pad1_overlay.ymin = pad1.ymin old_port = head.ports["S"] count = 0 width_via_iter = 2 * via_spacing - 2 * wire_width pad2.xmin = pad1.xmax + min_pad_spacing up = False down = True edge = True current_width = 3 * wire_width + wire_width # width of nub and 1 overlap obj_old = head obj = head via_iterable = _via_iterable( via_spacing=via_spacing, wire_width=wire_width, wiring1_layer=wiring1_layer, wiring2_layer=wiring2_layer, via_layer=via_layer, via_width=via_width, ) while (count + 2) <= num_vias: obj = VR.add_ref(via_iterable) obj.connect(port="W", destination=old_port, overlap=wire_width) old_port = obj.ports["E"] edge = False if obj.ymax > pad1.ymax: obj.connect(port="W", destination=obj_old.ports["S"], overlap=wire_width) old_port = obj.ports["S"] current_width += width_via_iter down = True up = False edge = True elif obj.ymin < pad1.ymin: obj.connect(port="W", destination=obj_old.ports["N"], overlap=wire_width) old_port = obj.ports["N"] current_width += width_via_iter up = True down = False edge = True count = count + 2 obj_old = obj if (current_width < min_pad_spacing and (min_pad_spacing - current_width) > 3 * wire_width): tail = VR.add_ref( pc.compass( size=(min_pad_spacing - current_width + wire_width, wire_width), layer=wiring1_layer, )) tail_overlay = VR.add_ref( pc.compass( size=(min_pad_spacing - current_width + wire_width, wire_width), layer=pad_layer, )) else: tail = VR.add_ref( pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer)) tail_overlay = VR.add_ref( pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer)) if up == True and edge != True: tail.connect(port="W", destination=obj.ports["S"], overlap=wire_width) tail_overlay.connect(port="W", destination=obj.ports["S"], overlap=wire_width) elif down == True and edge != True: tail.connect(port="W", destination=obj.ports["N"], overlap=wire_width) tail_overlay.connect(port="W", destination=obj.ports["N"], overlap=wire_width) else: tail.connect(port="W", destination=obj.ports["E"], overlap=wire_width) tail_overlay.connect(port="W", destination=obj.ports["E"], overlap=wire_width) pad2.xmin = tail.xmax pad2_overlay.xmin = pad2.xmin pad2_overlay.ymin = pad2.ymin return VR