def nwell_square(dope='NP', ext=[], topmet=1): # square cell to fill corners # ext: extend M1 0:North, 1:East, 2:South, 3:West nwell_square = gdspy.Cell('NWELL_SQUARE', True) od_shape = gdspy.Rectangle((0,0), (basic.OD_W, basic.OD_W), basic.layer['OD']) nwell_square.add(od_shape) # Legalization changes delta = 0.5*(basic.OD_W-basic.min_w['M1']) for i in range(topmet): m_layer = 'M' + str(i+1) if len(ext) > 0: m1_shape = gdspy.Rectangle((0.5*(basic.OD_W-basic.min_w['M1']),0.5*(basic.OD_W-basic.min_w['M1'])), (0.5*(basic.OD_W+basic.min_w['M1']),0.5*(basic.OD_W+basic.min_w['M1'])), basic.layer[m_layer], basic.datatype[m_layer]) nwell_square.add(m1_shape) m1_ext_ns = gdspy.Rectangle((0,0), (basic.min_w['M1'], delta), basic.layer[m_layer], basic.datatype[m_layer]) m1_ext_ew = gdspy.Rectangle((0,0), (delta, basic.min_w['M1']), basic.layer[m_layer], basic.datatype[m_layer]) if 0 in ext: m1_ext_1 = gdspy.copy(m1_ext_ns, delta, delta+basic.min_w['M1']) nwell_square.add(m1_ext_1) if 1 in ext: m1_ext_2 = gdspy.copy(m1_ext_ew, delta+basic.min_w['M1'], delta) nwell_square.add(m1_ext_2) if 2 in ext: m1_ext_3 = gdspy.copy(m1_ext_ns, delta, 0) nwell_square.add(m1_ext_3) if 3 in ext: m1_ext_4 = gdspy.copy(m1_ext_ew, 0, delta) nwell_square.add(m1_ext_4) # Removed co for DRC #co_en = 0.5 * (basic.OD_W - basic.min_w['CO']) #co_shape = gdspy.Rectangle((co_en, co_en), (co_en+basic.min_w['CO'], co_en+basic.min_w['CO']), layer['CO']) #nwell_square.add(co_shape) np_shape = gdspy.Rectangle((-basic.NP_OD, -basic.NP_OD), (basic.OD_W+basic.NP_OD, basic.OD_W+basic.NP_OD), basic.layer[dope]) nwell_square.add(np_shape) nwell_square.flatten() return nwell_square
def test_copy(): p = gdspy.Rectangle((0, 0), (1, 1)) q = gdspy.copy(p, 1, -1) assert set(p.polygons[0][:, 0]) == {0, 1} assert set(p.polygons[0][:, 1]) == {0, 1} assert set(q.polygons[0][:, 0]) == {1, 2} assert set(q.polygons[0][:, 1]) == {-1, 0} p = gdspy.PolygonSet([[(0, 0), (1, 0), (0, 1)], [(2, 2), (3, 2), (2, 3)]]) q = gdspy.copy(p, 1, -1) assert set(p.polygons[0][:, 0]) == {0, 1} assert set(p.polygons[0][:, 1]) == {0, 1} assert set(q.polygons[0][:, 0]) == {1, 2} assert set(q.polygons[0][:, 1]) == {-1, 0} assert set(p.polygons[1][:, 0]) == {2, 3} assert set(p.polygons[1][:, 1]) == {2, 3} assert set(q.polygons[1][:, 0]) == {3, 4} assert set(q.polygons[1][:, 1]) == {1, 2} l = gdspy.Label('text', (0, 1)) m = gdspy.copy(l, -1, 1) assert l.position[0] == 0 and l.position[1] == 1 assert m.position[0] == -1 and m.position[1] == 2 c = gdspy.CellReference('empty', (0, 1), ignore_missing=True) d = gdspy.copy(c, -1, 1) assert c.origin == (0, 1) assert d.origin == (-1, 2) c = gdspy.CellArray('empty', 2, 3, (1, 0), (0, 1), ignore_missing=True) d = gdspy.copy(c, -1, 1) assert c.origin == (0, 1) assert d.origin == (-1, 2)
def test_copy(): p = gdspy.Rectangle((0, 0), (1, 1)) q = gdspy.copy(p, 1, -1) assert set(p.polygons[0][:, 0]) == {0, 1} assert set(p.polygons[0][:, 1]) == {0, 1} assert set(q.polygons[0][:, 0]) == {1, 2} assert set(q.polygons[0][:, 1]) == {-1, 0} p = gdspy.PolygonSet([[(0, 0), (1, 0), (0, 1)], [(2, 2), (3, 2), (2, 3)]]) q = gdspy.copy(p, 1, -1) assert set(p.polygons[0][:, 0]) == {0, 1} assert set(p.polygons[0][:, 1]) == {0, 1} assert set(q.polygons[0][:, 0]) == {1, 2} assert set(q.polygons[0][:, 1]) == {-1, 0} assert set(p.polygons[1][:, 0]) == {2, 3} assert set(p.polygons[1][:, 1]) == {2, 3} assert set(q.polygons[1][:, 0]) == {3, 4} assert set(q.polygons[1][:, 1]) == {1, 2} l = gdspy.Label("text", (0, 1)) m = gdspy.copy(l, -1, 1) assert l.position[0] == 0 and l.position[1] == 1 assert m.position[0] == -1 and m.position[1] == 2 c = gdspy.CellReference("empty", (0, 1), ignore_missing=True) d = gdspy.copy(c, -1, 1) assert c.origin == (0, 1) assert d.origin == (-1, 2) c = gdspy.CellArray("empty", 2, 3, (1, 0), (0, 1), ignore_missing=True) d = gdspy.copy(c, -1, 1) assert c.origin == (0, 1) assert d.origin == (-1, 2)
def generate_JJ(): root_width = 5 root_height = 15 tip_width = 2 tip_height = 4 taper_height=15 cross_dist = 5 cross_len = 8 cross_width = 0.2 uc_shift = 1 uc_tip_height = 2.5 base_layer = 30 uc_layer = 40 # base pattern base_path = gdspy.Path(root_width, (0, 0)) base_path.segment(root_height, '+y', layer=base_layer) base_path.segment(taper_height, '+y', final_width=tip_width, layer=base_layer) base_path.segment(tip_height, '+y', layer=base_layer) tip_cir = gdspy.Round((0, root_height+taper_height+tip_height), tip_width/2, initial_angle=0, final_angle=np.pi, layer=base_layer) JJ_base1 = gdspy.boolean(base_path, tip_cir, 'or', max_points=0, layer=base_layer) JJ_base2 = gdspy.copy(JJ_base1).rotate(np.pi, (0, root_height+taper_height+tip_height)).translate(cross_dist, cross_dist) JJ_base = gdspy.boolean(JJ_base1, JJ_base2, 'or', max_points=0, layer=base_layer) JJ_cross1 = gdspy.Path(cross_width, (0, root_height+taper_height+tip_height)) JJ_cross1.segment(cross_len, '+x', layer=base_layer) JJ_cross2 = gdspy.Path(cross_width, initial_point=(cross_dist, root_height+taper_height+tip_height+cross_dist)) JJ_cross2.segment(cross_len, '-y', layer=base_layer) JJ_cross = gdspy.boolean(JJ_cross1, JJ_cross2, 'or', max_points=0, layer=base_layer) JJ_total = gdspy.boolean(JJ_base, JJ_cross, 'or', max_points=0, layer=base_layer) # under cut uc_path = gdspy.Path(root_width+2*uc_shift, (0, -uc_shift)) uc_path.segment(root_height+uc_shift, '+y', layer=uc_layer) uc_path.segment(taper_height, '+y', final_width=tip_width+2*uc_shift, layer=uc_layer) uc_path.segment(tip_height+tip_width/2+uc_shift, '+y', layer=uc_layer) uc_base1 = uc_path uc_base2 = gdspy.copy(uc_base1).rotate(np.pi, (0, root_height+taper_height+tip_height)).translate(cross_dist, cross_dist) uc_base = gdspy.boolean(uc_base1, uc_base2, 'or', max_points=0, layer=uc_layer) uc_tip1 = gdspy.Path(uc_shift, (cross_len - uc_tip_height/2, root_height+taper_height+tip_height)) uc_tip1.segment(uc_tip_height, '+x', layer=uc_layer) uc_tip2 = gdspy.Path(uc_shift, (cross_dist, root_height+taper_height+tip_height+cross_dist-cross_len+uc_tip_height/2)) uc_tip2.segment(uc_tip_height, '-y', layer=uc_layer) uc_tip = gdspy.boolean(uc_tip1, uc_tip2, 'or', max_points=0, layer=uc_layer) uc = gdspy.boolean(uc_base, uc_tip, 'or', max_points=0, layer=uc_layer) dx = -cross_dist/2 dy = -(root_height+taper_height+tip_height+cross_dist/2) return [JJ_total.translate(dx, dy), uc.translate(dx, dy)]
def test_fillet(target): cell = gdspy.Cell("test") orig = gdspy.PolygonSet([ [ (0, 0), (-1, 0), (0, -1), (0.5, -0.5), (1, 0), (1, 1), (4, -1), (1, 3), (1, 2), (0, 1), ], [(2, -1), (3, -1), (2.5, -2)], ]) orig.datatypes = [0, 1] p = gdspy.copy(orig, 0, 5) p.layers = [1, 1] p.fillet(0.3, max_points=0) cell.add(p) p = gdspy.copy(orig, 5, 5) p.layers = [2, 2] p.fillet([0.3, 0.2, 0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.1, 0.2, 0], max_points=0) cell.add(p) p = gdspy.copy(orig, 5, 0) p.layers = [3, 3] p.fillet( [[0.1, 0.1, 0.4, 0, 0.4, 0.1, 0.1, 0.4, 0.4, 0.1], [0.2, 0.2, 0.5]], max_points=0, ) cell.add(p) p = gdspy.PolygonSet( [ [ (0, 0), (0, 0), (-1, 0), (0, -1), (0.5, -0.5), (1, 0), (1, 0), (1, 1), (4, -1), (1, 3), (1, 2), (0, 1), ], [(2, -1), (3, -1), (2.5, -2), (2, -1)], ], layer=4, ) p.datatypes = [0, 1] p.fillet([0.8, [10.0, 10.0, 20.0, 20.0]], max_points=199, precision=1e-6) cell.add(p) assertsame(cell, target["PolygonSet_fillet"], tolerance=1e-3)
def contour2gds(contour0, args): """transform contour list to gds """ contour = [[ele[0] for ele in arr] for arr in contour0] if args.sharpen: contour = sharpenCorner(contour, args) flat_list = [item for sublist in contour for item in sublist] x = [arr[0] for arr in flat_list] y = [arr[1] for arr in flat_list] xlength = max(x) - min(x) ylength = max(y) - min(y) maxY = max(y) contour = [[[ele[0], maxY - ele[1]] for ele in arr] for arr in contour] poly_cell = gdspy.Cell('tmp') poly = gdspy.PolygonSet(contour, 1) nX = args.nX nY = args.nY xsep = max(xlength, ylength) * args.sep ysep = xsep for i in range(nX): for j in range(nY): xpos = (xlength + xsep) * (i + 1) ypos = (ylength + ysep) * (j + 1) trans = gdspy.copy(poly, xpos, ypos) poly_cell.add(trans) if args.out_file is not None: gdspy.write_gds(args.out_file, unit=args.scale * 1.0e-9, precision=1.0e-9)
def corners2gds(corners, args): polyidx = [] with open(args.corner_seq, 'r') as f: for line in f: line = line.strip().split(',') tmp = [int(x) for x in line] polyidx.append(tmp) poly_cell = gdspy.Cell('tmp') polyvertice = [] for i, idx in enumerate(polyidx): polyvertice.append(idx2xy(corners, idx)) # poly=gdspy.Polygon(polyvertice,1) # poly_cell.add(poly) poly = gdspy.PolygonSet(polyvertice, 1) # poly_cell.add(poly) xlength = max(corners[:, 0]) - min(corners[:, 0]) ylength = max(corners[:, 1]) - min(corners[:, 1]) nX = args.nX nY = args.nY xsep = max(xlength, ylength) * args.sep ysep = xsep for i in range(nX): for j in range(nY): xpos = (xlength + xsep) * (i + 1) ypos = (ylength + ysep) * (j + 1) trans = gdspy.copy(poly, xpos, ypos) poly_cell.add(trans) if args.out_file is not None: gdspy.write_gds(args.out_file, unit=args.scale * 1.0e-9, precision=1.0e-9)
def layer_expansion(self, shift, old_layer, new_layer, N_shifts=8): total = None polygonset = gdspy.PolygonSet(self.total_cell.get_polygons( (old_layer, 0)), layer=new_layer) for i in np.linspace(-np.pi, np.pi, N_shifts, endpoint=False): dx, dy = shift * np.cos(i), shift * np.sin(i) new_polygonset = gdspy.copy(polygonset, dx, dy) #total = gdspy.boolean(total, new_polygonset, 'or', layer=new_layer) self.total_cell.add(new_polygonset)
def bridgeFreeJJ(conf: DefaultConfig): sizes = conf.bridgeFreeJJSizes layers = conf.bridgeFreeJJLayers rectangles = [myRectangle(size, layers[i]) for i, size in enumerate(sizes)] dy0 = (sizes[0][1] + sizes[3][1]) / 2 dx1 = (sizes[0][0] - sizes[1][0]) / 2 dx2 = (sizes[0][0] - sizes[2][0]) / 2 rectangles[0].translate(0, dy0) rectangles[1].translate(dx1, dy0) rectangles[2].translate(dx2, dy0) rectangles[0] = cut(rectangles[0], rectangles[1]) rectangles[1] = cut(rectangles[1], rectangles[2]) for i in range(3): rectangles.append(copy(rectangles[i]).rotate(pi)) return rectangles
def contour2gds(contour0, args): # print 'contour0',contour0 contour = [[ele[0] for ele in arr] for arr in contour0] # print 'contour1',contour if args.sharpen: contour = sharpenCorner(contour, args) # print 'contour2',contour flat_list = [item for sublist in contour for item in sublist] # print 'flat_list',flat_list x = [arr[0] for arr in flat_list] y = [arr[1] for arr in flat_list] # print 'x', x # print 'y', y xlength = max(x) - min(x) ylength = max(y) - min(y) maxY = max(y) # contour=[[[ele[0][0],maxY-ele[0][1]] for ele in arr] for arr in contour0] contour = [[[ele[0], maxY - ele[1]] for ele in arr] for arr in contour] # for sublist in contour: # for ele in sublist: # ele[1]=maxY-ele[1] poly_cell = gdspy.Cell('tmp') poly = gdspy.PolygonSet(contour, 1) # poly_cell.add(poly) # print 'max/min x',max(x),min(x) # print 'max/min y',max(y),min(y) # print 'length',xlength,ylength nX = args.nX nY = args.nY xsep = max(xlength, ylength) * args.sep ysep = xsep for i in range(nX): for j in range(nY): xpos = (xlength + xsep) * (i + 1) ypos = (ylength + ysep) * (j + 1) trans = gdspy.copy(poly, xpos, ypos) poly_cell.add(trans) if args.out_file is not None: gdspy.write_gds(args.out_file, unit=args.scale * 1.0e-9, precision=1.0e-9)
def qubitLead(conf: DefaultConfig, test=False): sizes = conf.qubitLeadSizes if test: sizes[2][1] = conf.qubitTestSize gaps = conf.qubitLeadGaps layers = conf.qubitLeadLayers curve = gdspy.Curve(0) for i, size in enumerate(sizes): w1, h1 = size if i == 0: dx = dy = w1 / 2 curve.c(dx, 0, dx, 0, dx, dy).v(h1 - dy) else: dx, dy = (w1 - sizes[i - 1][0]) / 2, gaps[i - 1] curve.c(0, dy / 2, dx, dy / 2, dx, dy).v(h1) curve.h(-sizes[-1][0] / 2) halfLead = gdspy.Polygon(curve.get_points()) lead = join([halfLead, copy(halfLead).mirror([0, 1])]) slice1 = sizes[0][1] + gaps[0] slice2 = slice1 + conf.qubitLeadOverlap coarseLead = gdspy.slice(lead, slice1, 1, layer=layers)[1] fineLead = gdspy.slice(lead, slice2, 1, layer=layers)[0] return coarseLead, fineLead
def poly2gds(polyvertice, corners, args): f = open('auto.seq', 'w') epsilon = 4 for vset in polyvertice: # print('vset',vset) seqList = [] for v in vset: for i, corner in enumerate(corners): dist = distance(v, corner) if dist <= epsilon: # print('dist',dist) seqList.append(i) continue f.write(','.join(str(x) for x in seqList) + '\n') # print('seqList',seqList) f.close() poly_cell = gdspy.Cell('tmp') poly = gdspy.PolygonSet(polyvertice, 1) # poly_cell.add(poly) xlength = max(corners[:, 0]) - min(corners[:, 0]) ylength = max(corners[:, 1]) - min(corners[:, 1]) nX = args.nX nY = args.nY xsep = max(xlength, ylength) * args.sep ysep = xsep for i in range(nX): for j in range(nY): xpos = (xlength + xsep) * (i + 1) ypos = (ylength + ysep) * (j + 1) trans = gdspy.copy(poly, xpos, ypos) # print poly poly_cell.add(trans) if args.out_file is not None: gdspy.write_gds(args.out_file, unit=args.scale * 1.0e-9, precision=1.0e-9)
[ (0, 0), (-1, 0), (0, -1), (0.5, -0.5), (1, 0), (1, 1), (4, -1), (1, 3), (1, 2), (0, 1), ], [(2, -1), (3, -1), (2.5, -2)], ]) orig.datatypes = [0, 1] p = gdspy.copy(orig, 0, 5) p.layers = [1, 1] p.fillet(0.3, max_points=0) cell.add(p) p = gdspy.copy(orig, 5, 5) p.layers = [2, 2] p.fillet([0.3, 0.2, 0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.1, 0.2, 0], max_points=0) cell.add(p) p = gdspy.copy(orig, 5, 0) p.layers = [3, 3] p.fillet([[0.1, 0.1, 0.4, 0, 0.4, 0.1, 0.1, 0.4, 0.4, 0.1], [0.2, 0.2, 0.5]], max_points=0) cell.add(p) p = gdspy.copy(orig, 0, 0) p.layers = [4, 4]
def copy(self, entity): new_polygon = gdspy.copy(self.gds_object_instances[entity.name], 0, 0) new_name = gen_name(entity.name) self.gds_object_instances[new_name] = new_polygon self.cell.add(new_polygon)
# ------------------------------------------------------------------ # # Translation # ------------------------------------------------------------------ # trans_cell = gdspy.Cell('TRANS') # Any geometric object can be translated by providing the distance to # translate in the x-direction and y-direction: translate(dx, dy) rect1 = gdspy.Rectangle((80, 0), (81, 1), 1) rect1.translate(2, 0) trans_cell.add(rect1) # Translatable objects can also be copied & translated in the same way. rect2 = gdspy.Rectangle((80, 0), (81, 1), 2) rect3 = gdspy.copy(rect2, 0, 3) trans_cell.add(rect2) trans_cell.add(rect3) # Reference Cells are also translatable, and thus copyable. ref1 = gdspy.CellReference(poly_cell, (25, 0), rotation=180) ref2 = gdspy.copy(ref1, 30, 30) trans_cell.add(ref1) trans_cell.add(ref2) # Same goes for Labels & Text text1 = gdspy.Text('Created with gdspy ' + gdspy.__version__, 7, (-7, -35), layer=6) text2 = gdspy.copy(text1, 0, -20) label1 = gdspy.Label('Created with gdspy ' + gdspy.__version__, (-7, -36),
def markers_ebeam_litho(center_coords, chip_side_x, chip_side_y, factor, layer_align): """ Generates "crosshair" markers at the corners of each chip for alignment of the dicing saw and dots following that fo alignment of ebeam INPUT: array with center position of the chips, chip dimensions OUTPUT: dicing markers elements """ elements = [] w = 5 * factor # width of the cross hair on the corner of a chip l_x = 100 * factor # length of the cross hair l_y = 100 * factor w_d = 20 * factor # width of ebeam alignment dots # w_g = 10 # width of grid d_x = 300 * factor # period of ebeam alignment dots in x and y direction d_y = 300 * factor for c in center_coords: # print(c) # print(type(c)) rv = gdspy.Rectangle( (c[0] - chip_side_x / 2 - w / 2, c[1] + chip_side_y / 2 - l_y / 2), (c[0] - chip_side_x / 2 + w / 2, c[1] + chip_side_y / 2 + l_y / 2), layer=layer_align) rh = gdspy.Rectangle( (c[0] - chip_side_x / 2 - l_x / 2, c[1] + chip_side_y / 2 - w / 2), (c[0] - chip_side_x / 2 + l_x / 2, c[1] + chip_side_y / 2 + w / 2), layer=layer_align) crosshair = gdspy.boolean( rv, rh, 'or', layer=layer_align) #making a cross hair on the edge of a chip # rectangle for ebeam in vertical and horizontal direction reh = gdspy.Rectangle((c[0] - chip_side_x / 2 - w_d / 2 - (d_x + 50), c[1] + chip_side_y / 2 - w_d / 2), (c[0] - chip_side_x / 2 + w_d / 2 - (d_x + 50), c[1] + chip_side_y / 2 + w_d / 2), layer=layer_align) rev = gdspy.Rectangle( (c[0] - chip_side_x / 2 - w_d / 2, c[1] + chip_side_y / 2 + (d_y + 50) - w_d / 2), (c[0] - chip_side_x / 2 + w_d / 2, c[1] + chip_side_y / 2 + (d_y + 50) + w_d / 2), layer=layer_align) # offsetting the horizontal dot to left and right offs_x = [0, -d_x, -2 * d_x] for j in offs_x: elements.append(gdspy.copy(reh, j, 0)) offs_x = [2 * d_x + 100, 3 * d_x + 100, 4 * d_x + 100] for j in offs_x: elements.append(gdspy.copy(reh, j, 0)) # offsetting the vertical dot to top and bottom offs_y = [0, -2 * d_y - 100, -3 * d_y - 100, -4 * d_y - 100] for j in offs_y: elements.append(gdspy.copy(rev, 0, j)) offs_y = [d_y, 2 * d_y] for j in offs_y: elements.append(gdspy.copy(rev, 0, j)) offs_x = [0, chip_side_x] offs_y = [0, -chip_side_y] for j in offs_x: for k in offs_y: elements.append(gdspy.copy(crosshair, j, k)) # array of 27 x 27 square dots of 10um side # square ebeam marker for chips number [0,6,last-6,last] last = len(center_coords) # positions = [3,9] # for j in positions: # se = gdspy.Rectangle((center_coords[j][0]+2500-w_g/2,center_coords[j][1]+6000-w_g/2),(center_coords[j][0]+2500+w_g/2,center_coords[j][1]+6000+w_g/2),layer=layer_align) # offs_x = [-1053,-966,-880,-795,-711,-628,-546,-465,-385,-306,-228,-151,-75,0,75,151,228,306,385,465,546,628,711,795,880,966,1053] # offs_y = [-1053,-966,-880,-795,-711,-628,-546,-465,-385,-306,-228,-151,-75,0,75,151,228,306,385,465,546,628,711,795,880,966,1053] # for i in offs_x: # for k in offs_y: # elements.append(gdspy.copy(se,i,k)) # positions = [len(center_coords)-11,len(center_coords)-5] # for j in positions: # se = gdspy.Rectangle((center_coords[j][0]+2500-w_g/2,center_coords[j][1]-6000-w_g/2),(center_coords[j][0]+2500+w_g/2,center_coords[j][1]-6000+w_g/2),layer=layer_align) # offs_x = [-1053,-966,-880,-795,-711,-628,-546,-465,-385,-306,-228,-151,-75,0,75,151,228,306,385,465,546,628,711,795,880,966,1053] # offs_y = [-1053,-966,-880,-795,-711,-628,-546,-465,-385,-306,-228,-151,-75,0,75,151,228,306,385,465,546,628,711,795,880,966,1053] # for i in offs_x: # for k in offs_y: # elements.append(gdspy.copy(se,i,k)) markers = gdspy.boolean(elements, None, 'or', precision=0.001, max_points=199, layer=layer_align) return markers
[(input_gap * i, taper_len + bus_len)], width=[small_margin, small_margin], offset=small_margin + width, gdsii_path=True, ) path.segment((0, 600 - bus_len - bend_radius - wg_gap * i), relative=True) path.turn(bend_radius, "r") path.segment((io_gap - 2 * bend_radius, 0), relative=True) path.turn(bend_radius, "l") path.segment((0, 300 - bend_radius + wg_gap * i), relative=True) c.add(path) dx = width / 2 + gap c.add( gdspy.boolean( gdspy.boolean( ring_bus, gdspy.copy(ring_margin, dx, 300), "or", precision=1e-4 ), gdspy.copy(ring_hole, dx, 300), "not", precision=1e-4, ).translate(input_gap * i, 0) ) c.add(gdspy.CellArray(taper, len(ring_gaps), 1, (input_gap, 0), (0, 0))) c.add( gdspy.CellArray( grat, len(ring_gaps), 1, (input_gap, 0), (io_gap, 900 + taper_len) ) ) # Save to a gds file and check out the output lib.write_gds("photonics.gds")
def teleportation_loop(width, l1, l2, la=1, orientation=0, loop_type='mirror-symmetric', reservoir_enable=False, layer=10, sw_enable=False, sw_layer=20, sw_distance=1, twin_enable=True): """ :param width: nanowire width :param l1: length of shorter (bottom) side :param l2: length of slanted side :param la: length of protruding arms for contacts :param orientation: degrees. 0deg = horizontal :param loop_type: {'mirror-symmetric', 'center-symmetric', 'asymmetric'} :param reservoir_enable: not used for now :param layer: shapes on 1 by default :return: gdspy object """ allowed_types = {'mirror-symmetric', 'center-symmetric', 'asymmetric'} if loop_type not in allowed_types: print('loop_type must be in ' + allowed_types) raise ValueError l2_proj_x = l2 * math.cos(math.pi / 3) l2_proj_y = l2 * math.sin(math.pi / 3) if loop_type == 'asymmetric': p1 = [(-l2_proj_x - la * math.cos(math.pi / 3), l2_proj_y + la * math.sin(math.pi / 3)), (0, 0), (l1, 0), (l1 + l2_proj_x, l2_proj_y)] p2 = [(-l2_proj_x, l2_proj_y), (l1 + l2_proj_x + la, l2_proj_y)] elif loop_type == 'center-symmetric': p1 = [(-la, 0), (l1, 0), (l1 + l2_proj_x, l2_proj_y)] p2 = [(0, 0), (l2_proj_x, l2_proj_y), (l2_proj_x + l1 + la, l2_proj_y)] else: p1 = [(-l2_proj_x, l2_proj_y), (0, 0), (l1, 0), (l1 + l2_proj_x, l2_proj_y)] p2 = [(-l2_proj_x - la, l2_proj_y), (l1 + l2_proj_x + la, l2_proj_y)] path1 = gp.FlexPath(p1, width) path2 = gp.FlexPath(p2, width) loop = gp.fast_boolean(path1, path2, 'or', layer=layer) if twin_enable: # only works on mirro-symmetric types loop2 = gp.copy(loop) loop2.mirror((l1 + l2_proj_x + 1.5 * la, 0), (l1 + l2_proj_x + 1.5 * la, 1)) loop = gp.fast_boolean(loop, loop2, 'or', layer=layer) loop = gp.fast_boolean( loop, gp.FlexPath([(l1 + l2_proj_x + la, l2_proj_y), (l1 + l2_proj_x + 3 * la, l2_proj_y)], width), 'or', layer=layer) if reservoir_enable: reservoir_width = 2 reservoir_height = 0.5 if loop_type == 'asymmetric': left_coordinates = ( -l2_proj_x - (la + reservoir_width / 2) * math.cos(math.pi / 3), l2_proj_y + (la + reservoir_width / 2) * math.sin(math.pi / 3)) right_coordinates = (l1 + l2_proj_x + la + reservoir_width / 2, l2_proj_y) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=left_coordinates, rotation=-60, layer=layer) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=right_coordinates, layer=layer) elif loop_type == 'center-symmetric': left_coordinates = (-la - reservoir_width / 2, 0) right_coordinates = (l2_proj_x + l1 + la + reservoir_width / 2, l2_proj_y) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=left_coordinates, layer=layer) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=right_coordinates, layer=layer) else: left_coordinates = (-l2_proj_x - la - reservoir_width / 2, l2_proj_y) right_coordinates = (l1 + l2_proj_x + la + reservoir_width / 2, l2_proj_y) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=left_coordinates, layer=layer) loop = add_reservoir_to_shape(loop, reservoir_width, reservoir_height, position=right_coordinates, layer=layer) wall_polygon = [(0, -sw_distance), (0, -sw_distance - 1), (l1, -sw_distance - 1), (l1, -sw_distance), (l1 + l2_proj_x + la + 2, -sw_distance)] wall_polygon += straight_to_zigzag_line( [(l1 + l2_proj_x + la + 2, -sw_distance), (l1 + l2_proj_x + la + 2, -sw_distance - 2), (-l2_proj_x - la - 2, -sw_distance - 2), (-l2_proj_x - la - 2, -sw_distance)], 0.3, 30) symmetric_wall = gp.Polygon(wall_polygon, layer=sw_layer) if twin_enable: wall2 = gp.copy(symmetric_wall) wall2.mirror((l1 + l2_proj_x + 1.5 * la, 0), (l1 + l2_proj_x + 1.5 * la, 1)) symmetric_wall = gp.fast_boolean(symmetric_wall, wall2, 'or', layer=sw_layer) if sw_enable: return loop, symmetric_wall # no 30deg option with SWs else: return loop.rotate(orientation * math.pi / 180)
landing_strip_4.translate(-markOffset + mark_size, 0) landing_strip_5.rotate(-np.pi / 4) landing_strip_6.rotate(np.pi / 4) landing_strip_7.rotate(-np.pi / 4) landing_strip_8.rotate(np.pi / 4) landing_strip_5.translate(-markOffset + mark_size, mark_size) landing_strip_6.translate(-markOffset - mark_size, mark_size) landing_strip_7.translate(-markOffset - mark_size, -mark_size) landing_strip_8.translate(-markOffset + mark_size, -mark_size) landing_strips = [ landing_strip_1, landing_strip_2, landing_strip_3, landing_strip_4, landing_strip_5, landing_strip_6, landing_strip_7, landing_strip_8 ] for l in landing_strips: l_right = gdspy.copy(l, dx=markOffset * 2) l_bottom = gdspy.copy(l) l_bottom.layers = [2] l_bottom_right = gdspy.copy(l_bottom, dx=markOffset * 2) cell.add(l) cell.add(l_right) cell.add(l_bottom) cell.add(l_bottom_right) radii = np.arange(0.5 * mm, 10 * mm, 0.1 * mm) landing_circles = [gdspy.Round((0, 0), r, inner_radius=r - 25) for r in radii] for l in landing_circles: l_right = gdspy.copy(l, dx=markOffset) l_left = gdspy.copy(l, dx=-markOffset) l_bottom_left = gdspy.copy(l_left) l_bottom_left.layers = [2 for x in l_bottom_left.layers]
## ------------------------------------------------------------------ ## ## Translation ## ------------------------------------------------------------------ ## trans_cell = gdspy.Cell('TRANS') ## Any geometric object can be translated by providing the distance to ## translate in the x-direction and y-direction: translate(dx, dy) rect1 = gdspy.Rectangle( (80,0), (81,1), 1 ) rect1.translate(2, 0) trans_cell.add(rect1) ## Translatable objects can also be copied & translated in the same way. rect2 = gdspy.Rectangle( (80,0), (81,1), 2 ) rect3 = gdspy.copy(rect2, 0,3) trans_cell.add(rect2) trans_cell.add(rect3) ## Reference Cells are also translatable, and thus copyable. ref1 = gdspy.CellReference(poly_cell, (25, 0), rotation=180) ref2 = gdspy.copy(ref1, 30,30) trans_cell.add(ref1) trans_cell.add(ref2) ## Same goes for Labels & Text text1 = gdspy.Text('Created with gsdpy ' + gdspy.__version__, 7, (-7, -35), layer=6)
# DO NOT Invert layer 2 mask layer2Mask = gdspy.Rectangle( [-fieldSpacing / 2, -fieldSpacing / 2], [-fieldSpacing / 2 - fieldSize, -fieldSpacing / 2 - fieldSize]) layer2Cell = gdspy.boolean(layer2Mask, layer2Cell, 'and', layer=4) # Create copy of layer 0 mask and invert it layer3Mask = gdspy.Rectangle( [fieldSpacing / 2, -fieldSpacing / 2], [fieldSpacing / 2 + fieldSize, -fieldSpacing / 2 - fieldSize], layer=0) layer3Reference = gdspy.CellReference( layer0Cell, (fieldSize + fieldSpacing, -fieldSize - fieldSpacing)) layer3Cell = gdspy.copy(layer0Cell, dx=fieldSpacing + fieldSize, dy=-fieldSpacing - fieldSize) layer3Cell = gdspy.boolean(layer3Mask, layer3Cell, 'not', layer=4) reticle_cell.add(layer0Cell) reticle_cell.add(layer1Cell) reticle_cell.add(layer2Cell) # BARCODE AND BARCODE TEXT barcodeCell, textCell = ASMLBarcodeGenerator.generateBarcodeAndText( 'JEPCKMOD2') reticle_cell.add(barcodeCell) reticle_cell.add(textCell) # Attempt to flip entire mask left-right (required by mla150) flipped_library = gdspy.GdsLibrary()
def render(self): self.jj_params['x'] = self.cpw_port.position[0] + np.cos( self.orientation) * self.length / 2 self.jj_params['y'] = self.cpw_port.position[1] + np.abs(np.cos(self.orientation))*self.jj_params['indent']/2 +\ np.abs(np.sin(self.orientation))*(np.sin(self.orientation)*self.length+self.jj_params['indent'])/2 JJ = JJ4q.JJ_1(self.jj_params['x'], self.jj_params['y'], self.jj_params['a1'], self.jj_params['a2']) jj = JJ.generate_jj() jj = gdspy.boolean(jj, jj, 'or', layer=self.layer_configuration.jj_layer) angle = self.jj_params['angle'] jj.rotate(angle, (self.jj_params['x'], self.jj_params['y'])) indent = 1 # overlap between the JJ's layer and the ground layer pad_up = gdspy.Rectangle( (self.jj_params['x'] - JJ.contact_pad_a / 2, self.jj_params['y'] + indent), (self.jj_params['x'] + JJ.contact_pad_a / 2, self.jj_params['y'] - JJ.contact_pad_b + indent), layer=self.layer_configuration.total_layer) pad_down = gdspy.Rectangle( (JJ.x_end - JJ.contact_pad_a / 2, JJ.y_end - 1), (JJ.x_end + JJ.contact_pad_a / 2, JJ.y_end - JJ.contact_pad_b - indent), layer=self.layer_configuration.total_layer) if np.round(np.sin(self.orientation), 3) == 0: # for horizontal based couplers poly1 = gdspy.Polygon( [(self.jj_params['x'] - JJ.contact_pad_a / 2, self.jj_params['y'] + indent), (self.jj_params['x'] - JJ.contact_pad_a / 2, self.jj_params['y'] + indent - JJ.contact_pad_b), (self.jj_params['x'] - 3 * JJ.contact_pad_a / 2, self.cpw_port.position[1] - self.w / 2), (self.jj_params['x'] - self.length / 2, self.cpw_port.position[1] - self.w / 2), (self.jj_params['x'] - self.length / 2, self.cpw_port.position[1] + self.w / 2), (self.jj_params['x'] - 3 * JJ.contact_pad_a / 2, self.cpw_port.position[1] + self.w / 2)], layer=self.layer_configuration.total_layer) poly2 = gdspy.Polygon( [(JJ.x_end + JJ.contact_pad_a / 2, JJ.y_end - indent - JJ.contact_pad_b), (JJ.x_end + JJ.contact_pad_a / 2, JJ.y_end - indent), (JJ.x_end + 3 * JJ.contact_pad_a / 2, self.cpw_port.position[1] + self.w / 2), (JJ.x_end + self.length / 2, self.cpw_port.position[1] + self.w / 2), (JJ.x_end + self.length / 2, self.cpw_port.position[1] - self.w / 2), (JJ.x_end + 3 * JJ.contact_pad_a / 2, self.cpw_port.position[1] - self.w / 2)], layer=self.layer_configuration.total_layer) elif np.round(np.cos(self.orientation), 3) == 0: poly1 = gdspy.Rectangle( (self.jj_params['x'] - self.w / 2, self.jj_params['y']), (self.jj_params['x'] + self.w / 2, self.jj_params['y'] + (self.length - self.jj_params['indent']) / 2), layer=self.layer_configuration.total_layer) poly2 = gdspy.Rectangle( (JJ.x_end + self.w / 2, JJ.y_end - JJ.contact_pad_b), (JJ.x_end - self.w / 2, JJ.y_end - JJ.contact_pad_b - (self.length - self.jj_params['indent']) / 2 - indent), layer=self.layer_configuration.total_layer) ground_x1 = self.cpw_port.position[0] + np.sin( self.orientation) * (self.w / 2 + self.g + self.s) ground_y1 = self.cpw_port.position[1] + np.cos( self.orientation) * (self.w / 2 + self.g + self.s) ground_x2 = self.cpw_port.position[0]+np.sin(self.orientation)*(self.w/2+self.s) +\ np.cos(self.orientation)*self.length ground_y2 = self.cpw_port.position[1] + np.cos(self.orientation) * (self.w /2 + self.s) + \ np.sin(self.orientation) * self.length ground1 = gdspy.Rectangle((ground_x1, ground_y1), (ground_x2, ground_y2), layer=self.layer_configuration.total_layer) ground2 = gdspy.copy(ground1) ground2 = ground2.mirror( (self.cpw_port.position[0], self.cpw_port.position[1]), (self.cpw_port.position[0] + np.cos(self.orientation) * self.length, self.cpw_port.position[1] + np.sin(self.orientation) * self.length)) line = gdspy.boolean(pad_up, [pad_down, poly1, poly2, ground1, ground2], 'or', layer=self.layer_configuration.total_layer) line.rotate(angle, (self.jj_params['x'], self.jj_params['y'])) return {'positive': line, 'JJ': jj}
def main(): # load file comsol_filename = "fourQ_test_pattern_cell_divide.java" parser = cp.comsol_parser() parser.load(comsol_filename) # show info #parser.ls_g_params() #parser.ls_geom() #parser.ls_objs("wp2") # change_paramter ## parser.g_params['read_D_pad'] = '0.660[mm]' # change geometric object parser.activate_geom_obj('wp2', ['c15', 'c16', 'c18', 'c17'], False) # c15-18: positioning via parser.activate_geom_obj('wp2', ['c8'], False) # c8: center via #print (parser.get_geom_obj('wp2', 'c15').__dict__) ## TiN pattern dry_etch_layer = 11 cell_qc = gdspy.Cell('Qubit_Coplanar') poly_q = parser.export('wp1', layer=11, n_points_for_circle=256) poly_c = parser.export('wp5', layer=11, n_points_for_circle=128) poly_qc = gdspy.boolean(poly_q, poly_c, 'or', max_points=0, layer=dry_etch_layer) ## disable max_points check ## JJ cell_JJ = gdspy.Cell('JJ') JJ_polys = generate_JJ() cell_JJ.add(JJ_polys) q_r_outer_hole = 300 q_r_inner = 95 q_gap = q_r_inner + (q_r_outer_hole - q_r_inner)/2 q_dist = 2400 p_JJ0 = (-q_dist/2+q_gap/np.sqrt(2), q_dist/2-q_gap/np.sqrt(2)) p_JJ1 = (q_dist/2-q_gap/np.sqrt(2), q_dist/2-q_gap/np.sqrt(2)) p_JJ2 = (-q_dist/2+q_gap/np.sqrt(2), -q_dist/2+q_gap/np.sqrt(2)) p_JJ3 = (q_dist/2-q_gap/np.sqrt(2), -q_dist/2+q_gap/np.sqrt(2)) p_JJ_list = [p_JJ0, p_JJ1, p_JJ2, p_JJ3] JJ_list = map(lambda x: gdspy.CellReference(cell_JJ, x), p_JJ_list) cell_qc.add(JJ_list) ## hook for JJ gap_for_JJ = 90/np.sqrt(2) hook_path_base = gdspy.FlexPath([(0, 0), (0, -4.5), (-3.5, -4.5)], 3, layer=dry_etch_layer) hook_path_base.translate(5, gap_for_JJ/2) hook_path_list = map(lambda x: gdspy.copy(hook_path_base).translate(*x), p_JJ_list) hook_path_union = None for path in hook_path_list: hook_path_union = gdspy.boolean(hook_path_union, path, 'or', max_points=0, layer=dry_etch_layer) #poly_qc_hook = gdspy.boolean(poly_qc, hook_path_union, 'not', max_points=0, layer=dry_etch_layer) #cell_qc.add(poly_qc_hook) cell_qc.add(hook_path_union) cell_qc.add(poly_c) cell_qc.add(poly_q) ## mask mask_layer = 100 shift = 20 cell_mask_shifted = gdspy.Cell('Shifted Pattern Mask') polyset_shifted = cp.gdspy_shift_size(poly_qc, shift ,layer=mask_layer) unit_size = 4000 rect_fill_lr = gdspy.Path(150, (-unit_size/2, 0)) rect_fill_lr.segment(unit_size, '+x', layer=mask_layer) rect_fill_bt = gdspy.Path(150, (0, -unit_size/2)) rect_fill_bt.segment(unit_size, '+y', layer=mask_layer) rect_list = [gdspy.copy(rect_fill_lr).translate(0, -q_dist/2), gdspy.copy(rect_fill_lr).translate(0, q_dist/2), gdspy.copy(rect_fill_bt).translate(-q_dist/2, 0), gdspy.copy(rect_fill_bt).translate(q_dist/2, 0)] rect_union = None for rect in rect_list: rect_union = gdspy.boolean(rect_union, rect, 'or', max_points=0, layer=mask_layer) mask_shifted = gdspy.boolean(polyset_shifted, rect_union, 'or', max_points=0, layer=mask_layer) cell_mask_shifted.add(mask_shifted) ## Via via_layer = 13 top_Al_layer = 8 bottom_Al_layer = 9 cell_via = gdspy.Cell('Via') via_poly = parser.export('wp2', layer=via_layer) via_poly_Al_t = cp.gdspy_shift_size(via_poly, 35, layer=top_Al_layer) via_poly_Al_b = cp.gdspy_shift_size(via_poly, 20, layer=bottom_Al_layer) via_poly_Al_t = gdspy.boolean(via_poly_Al_t, mask_shifted, 'not', layer=top_Al_layer) ## mask the top pattern cell_via.add([via_poly, via_poly_Al_t, via_poly_Al_b]) ### center via center_via = gdspy.Round((0, 0), 75, layer=via_layer) center_via_Al_t = gdspy.Round((0, 0), 95, layer=top_Al_layer) center_via_Al_b = gdspy.Round((0, 0), 95, layer=bottom_Al_layer) cell_via.add([center_via, center_via_Al_t, center_via_Al_b]) ### positioning via pos_via_dist = 7400 pos_via_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 520, layer=via_layer) pos_via_lt_Al_t = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 620, layer=top_Al_layer) pos_via_lt_Al_b = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 600, layer=bottom_Al_layer) pos_via_rb = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 520, layer=via_layer) pos_via_rb_Al_t = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 620, layer=top_Al_layer) pos_via_rb_Al_b = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 600, layer=bottom_Al_layer) cell_via.add([pos_via_lt, pos_via_lt_Al_t, pos_via_lt_Al_b, pos_via_rb, pos_via_rb_Al_t, pos_via_rb_Al_b]) ### tiling Via cell_single_via = gdspy.Cell('single_via') via_s = gdspy.Round((0, 0), 75, layer=via_layer) via_s_Al_t = gdspy.Round((0, 0), 110, layer=top_Al_layer) via_s_Al_b = gdspy.Round((0, 0), 95, layer=bottom_Al_layer) cell_single_via.add([via_s, via_s_Al_t, via_s_Al_b]) tiled_via_list = tile_cell(cell_single_via, (-4500, -4500), (4500, 4500), 500) cell_mask_via = gdspy.Cell('Via Mask') rect_mask_lr = gdspy.Rectangle((-2300, -400), (2300, 400), layer=mask_layer) rect_mask_bt = gdspy.Rectangle((-400, -2300), (400, 2300), layer=mask_layer) rect_mask_c = gdspy.Rectangle((-1200, -1200), (1200, 1200), layer=mask_layer) rect_mask_lr1 = gdspy.copy(rect_mask_lr).translate(0, -1200) rect_mask_lr2 = gdspy.copy(rect_mask_lr).translate(0, 1200) rect_mask_bt1 = gdspy.copy(rect_mask_bt).translate(-1200, 0) rect_mask_bt2 = gdspy.copy(rect_mask_bt).translate(1200, 0) pos_via_mask_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 600, layer=mask_layer) pos_via_mask_br = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 600, layer=mask_layer) cell_mask_via.add([rect_mask_lr1, rect_mask_lr2, rect_mask_bt1, rect_mask_bt2, rect_mask_c, pos_via_mask_lt, pos_via_mask_br]) for via_ref in tiled_via_list: if np.any(gdspy.inside([via_ref.origin], cell_mask_via.polygons)): pass else: cell_via.add(via_ref) generate_flux_trap = False if generate_flux_trap: # Flux trap cell_single_flux_trap = gdspy.Cell('single_flux_trap') trap_size = np.array([5, 5]) cell_single_flux_trap.add(gdspy.Rectangle(-trap_size/2, trap_size/2, layer=dry_etch_layer)) cell_flux_trap = gdspy.Cell('Flux trap') flux_trap_list = tile_cell(cell_single_flux_trap, (-2500, -2500), (2500, 2500), 20) cell_mask_flux_trap = gdspy.Cell("Mask for flux trap") mask_flux_trap_on_via = cp.gdspy_shift_size(via_poly, 40, layer=mask_layer) mask_pos_via_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 630, layer=mask_layer) mask_pos_via_rb = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 630, layer=mask_layer) cell_mask_flux_trap.add([mask_shifted, mask_flux_trap_on_via, mask_pos_via_lt, mask_pos_via_rb]) ### for flux_trap_ref in flux_trap_list: if np.any(gdspy.inside([flux_trap_ref.origin], cell_mask_flux_trap.polygons)): pass else: cell_flux_trap.add(flux_trap_ref) # Top total_cell = gdspy.Cell('4Q total pattern') total_cell.add(gdspy.CellReference(cell_qc)) total_cell.add(gdspy.CellReference(cell_via)) if generate_flux_trap: total_cell.add(gdspy.CellReference(cell_flux_trap)) #gdspy.LayoutViewer() gdspy.write_gds("4Q_pattern.gds", unit=1.0e-6, precision=1.0e-9) return 0
def gdsgen_part(self, part_id, layer=1, dbu=0.001, n_points_for_circle=128, input_params={}): ## if isinstance(n_points_for_circle, float): n_points_for_circle = int(n_points_for_circle / dbu) ## export_obj_ids = [] export_kl_obj_ids = [] gds_objs = {} kl_objs = {} skipped_obj_ids = [] if part_id in self.two_dim_part_dict: part = self.two_dim_part_dict[part_id] is_wp = False elif part_id in self.two_dim_wp_dict: part = self.two_dim_wp_dict[part_id] is_wp = True else: raise Exception('Could not find the corresponding parts or wp.') eval_g_params = func_dict.copy() eval_g_params.update(self.g_params_evaluated) if_skip_flag = False for obj_id in part.obj_order: local_params = None obj = part.objs[obj_id] if input_params: local_params = part.get_local_params(input_params) local_params.update(input_params) else: local_params = part.get_local_params() local_params.update(part.input_params) obj.eval_params(eval_g_params, local_params) if obj.is_active == False: pass elif obj.type == 'EndIf': if_skip_flag = False elif if_skip_flag == True: skipped_obj_ids.append(obj.id) elif obj.type == 'If': if obj.params_evaluated['condition'] == False: if_skip_flag = True else: if_skip_flag = False elif obj.type == 'Circle': r = obj.params_evaluated['r'] angle_i = 0. angle_f = 2 * np.pi r_i = 0. if 'angle' in obj.params_evaluated: angle_f = obj.params_evaluated['angle'] * np.pi / 180.0 if 'layer' in obj.params_evaluated: if len(obj.params_evaluated['layer']) > 1: print( 'Warning: Circle with more than 1 layer is not supported ({}).' .format(obj.id), file=sys.stderr) r_i = r - obj.params_evaluated['layer'][0] gds_obj = gdspy.Round((0, 0), r, initial_angle=angle_i, final_angle=angle_f, inner_radius=r_i, number_of_points=n_points_for_circle, layer=layer) if 'rot' in obj.params_evaluated: gds_obj.rotate(obj.params_evaluated['rot'] * np.pi / 180.0) if 'pos' in obj.params_evaluated: gds_obj.translate(*obj.params_evaluated['pos']) gds_objs[obj_id] = gds_obj export_obj_ids.append(obj_id) elif obj.type == 'Rectangle': size = np.array(obj.params_evaluated['size']) if 'base' in obj.params_evaluated and obj.params_evaluated[ 'base'] == 'center': gds_obj = gdspy.Rectangle(-size / 2.0, size / 2.0, layer=layer) else: gds_obj = gdspy.Rectangle((0, 0), size, layer=layer) if 'rot' in obj.params_evaluated: gds_obj.rotate(obj.params_evaluated['rot'] * np.pi / 180.0) if 'pos' in obj.params_evaluated: gds_obj.translate(*obj.params_evaluated['pos']) gds_objs[obj_id] = gds_obj export_obj_ids.append(obj_id) elif obj.type == 'Polygon': if 'source' in obj.params_evaluated: if obj.params_evaluated['source'] == 'table': gds_obj = gdspy.Polygon(obj.params_evaluated['table'], layer=layer) gds_objs[obj_id] = gds_obj export_obj_ids.append(obj_id) else: print('Unsupported source ({0}) in {1}'.format( params_evaluated['source'], obj.id, file=sys.stderr)) else: print('Source not specified in {}'.format(obj.id), file=sys.stderr) elif obj.type == 'Union': sel = obj.selections['input'] union_list = [] for sel_obj_id_org in sel: if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections[ 'input'][0] else: sel_obj_id = sel_obj_id_org union_list.append(sel_obj_id) if sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) if union_list: union_obj = None for sel_obj_id in union_list: union_obj = gdspy.boolean(union_obj, gds_objs[sel_obj_id], 'or', precision=dbu, layer=layer) gds_objs[obj_id] = union_obj export_obj_ids.append(obj_id) ### from here elif obj.type == 'Difference': selA = obj.selections['input'] selB = obj.selections['input2'] objA_list = [] objB_list = [] for sel_obj_id_org in selA: if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections[ 'input'][0] else: sel_obj_id = sel_obj_id_org objA_list.append(sel_obj_id) if sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) for sel_obj_id_org in selB: if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections[ 'input'][0] else: sel_obj_id = sel_obj_id_org objB_list.append(sel_obj_id) if sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) if objA_list: objA = None for sel_obj_id in objA_list: objA = gdspy.boolean(objA, gds_objs[sel_obj_id], 'or', precision=dbu, layer=layer) if objB_list: objB = None for sel_obj_id in objB_list: objB = gdspy.boolean(objB, gds_objs[sel_obj_id], 'or', precision=dbu, layer=layer) diff_obj = gdspy.boolean(objA, objB, 'not', precision=dbu, layer=layer) gds_objs[obj_id] = diff_obj export_obj_ids.append(obj_id) elif obj.type == 'Move': if 'displx' in obj.params_evaluated: displx = obj.params_evaluated['displx'] else: displx = 0 if 'disply' in obj.params_evaluated: disply = obj.params_evaluated['disply'] else: disply = 0 sel = obj.selections['input'] # for single slection if len(sel) > 1: print( 'Warning: {} of more than 1 object is not supported.'. format(obj.type), file=sys.stderr) sel_obj_id_org = sel[0] if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections['input'][ 0] else: sel_obj_id = sel_obj_id_org sel_obj = gds_objs[sel_obj_id] move_obj = gdspy.copy(sel_obj, displx, disply) gds_objs[obj_id] = move_obj export_obj_ids.append(obj_id) if 'keep' in obj.params_evaluated and obj.params_evaluated[ 'keep'] == True: pass elif sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) elif obj.type == 'Mirror': if 'pos' in obj.params_evaluated: pos = np.array(obj.params_evaluated['pos']) else: pos = np.array([0., 0.]) if 'axis' in obj.params_evaluated: axis = np.array(obj.params_evaluated['axis']) else: axis = np.array([1., 0.]) sel = obj.selections['input'] # for single selection if len(sel) > 1: print( 'Warning: {} of more than 1 object is not supported.'. format(obj.type), file=sys.stderr) sel_obj_id_org = sel[0] if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections['input'][ 0] else: sel_obj_id = sel_obj_id_org sel_obj = gds_objs[sel_obj_id] mirror_obj = gdspy.copy(sel_obj).mirror( pos, pos + np.array([-axis[1], axis[0]])) gds_objs[obj_id] = mirror_obj export_obj_ids.append(obj_id) if 'keep' in obj.params_evaluated and obj.params_evaluated[ 'keep'] == True: pass elif sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) elif obj.type == 'Rotate': if 'rot' in obj.params_evaluated: if isinstance( obj.params_evaluated['rot'], (list, tuple, np.ndarray)): # can be ndarray when use range rot = np.array( obj.params_evaluated['rot'] ) * np.pi / 180 # rot can be the list of angle else: rot = np.array([obj.params_evaluated['rot'] ]) * np.pi / 180 else: rot = np.array([0.]) if 'pos' in obj.params_evaluated: pos = np.round(np.array(obj.params_evaluated['pos'])) else: pos = np.array([0., 0.]) sel = obj.selections['input'] if len(sel) > 1: print( 'Warning: {} of more than 1 object is not supported.'. format(obj.type), file=sys.stderr) sel_obj_id_org = sel[0] if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections['input'][ 0] else: sel_obj_id = sel_obj_id_org sel_obj = gds_objs[sel_obj_id] rot_obj = gdspy.copy(sel_obj).rotate(rot[0], center=pos) for angle in rot[1:]: rot_obj = gdspy.boolean(rot_obj, gdspy.copy(sel_obj).rotate( angle, center=pos), 'or', precision=dbu, layer=layer) gds_objs[obj_id] = rot_obj export_obj_ids.append(obj_id) if 'keep' in obj.params_evaluated and obj.params_evaluated[ 'keep'] == True: pass elif sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) elif obj.type == 'Array': if 'type' in obj.params_evaluated and obj.params_evaluated[ 'type'] == 'linear': linearsize = obj.params_evaluated['linearsize'] displ = np.array(obj.params_evaluated['displ']) sel = obj.selections['input'] if len(sel) > 1: print( 'Warning: {} of more than 1 object is not supported.' .format(obj.type), file=sys.stderr) sel_obj_id_org = sel[0] if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections[ 'input'][0] else: sel_obj_id = sel_obj_id_org sel_obj = gds_objs[sel_obj_id] arr_obj = gdspy.copy(sel_obj) for i in range(1, int(linearsize)): displ_i = displ * i arr_obj = gdspy.boolean( arr_obj, gdspy.copy(sel_obj).translate(*displ_i), 'or', precision=dbu, layer=layer) if sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) gds_objs[obj_id] = arr_obj export_obj_ids.append(obj_id) else: fullsize = obj.params_evaluated['fullsize'] displ = np.array(obj.params_evaluated['displ']) sel = obj.selections['input'] if len(sel) > 1: print( 'Warning: {} of more than 1 object is not supported.' .format(obj.type), file=sys.stderr) sel_obj_id_org = sel[0] if sel_obj_id_org in skipped_obj_ids: sel_obj_id = part.objs[sel_obj_id_org].selections[ 'input'][0] else: sel_obj_id = sel_obj_id_org sel_obj = gds_objs[sel_obj_id] arr_obj = gdspy.copy(sel_obj) for i in range(int(fullsize[0])): for j in range(int(fullsize[1])): if (i, j) is (0, 0): continue displ_ij = np.array([i, j]) * displ arr_obj = gdspy.boolean( arr_obj, gdspy.copy(sel_obj).translate(*displ_ij), 'or', precision=dbu, layer=layer) if sel_obj_id in export_obj_ids: export_obj_ids.remove(sel_obj_id) gds_objs[obj_id] = arr_obj export_obj_ids.append(obj_id) elif obj.type == 'PartInstance': if 'part' in obj.params_evaluated: pi_part_id = obj.params_evaluated['part'] else: if is_wp == True: pi_part_id = self.default_part_id_wp else: pi_part_id = self.default_part_id if isinstance(obj.params_evaluated['inputexpr'][0], list): # 3.5a pi_params = dict(obj.params_evaluated['inputexpr']) else: pi_param_keys = self.two_dim_part_dict[ pi_part_id].input_param_names pi_param_vals = obj.params_evaluated['inputexpr'] pi_params = dict(zip(pi_param_keys, pi_param_vals)) pi_objs, pi_export_obj_ids = self.gdsgen_part( pi_part_id, layer=layer, dbu=dbu, n_points_for_circle=n_points_for_circle, input_params=pi_params) if len(pi_export_obj_ids) > 1: print( 'Warning: PartInstance with more than 1 final objects is not supported ({}).' .format(pi_part_id), file=sys.stderr) print( ' Take union in the definition of Geometry Parts', file=sys.stderr) pi_obj = pi_objs[pi_export_obj_ids[0]] if 'rot' in obj.params_evaluated: angle = obj.params_evaluated['rot'] * np.pi / 180 pi_obj = pi_obj.rotate(angle) if 'displ' in obj.params_evaluated: displ = np.array(obj.params_evaluated['displ']) pi_obj = pi_obj.translate(*displ) gds_objs[obj_id] = pi_obj export_obj_ids.append(obj_id) else: print('Warning: object({}) was skipped.'.format(obj_id), file=sys.stderr) return (gds_objs, export_obj_ids)
def loop_with_sw(width, l1, l2, d1, d2, la=1, loop_type='high-angle-60deg', layer=10, sw_layer=20, twin_enable=True): """ The above function got too complicated so started a separate loop generating function for those with smart walls :param width: nanowire width :param l1: length of shorter (bottom) side :param l2: length of slanted side :param d1: distance between top arm and the two side SWs :param d2: distance between top arm and the island boundary :param la: length of protruding arms for contacts. Check the geometries again if you change this value to anything but the default 1um. :param loop_type: {'high-angle', 'grazing-angle'} :param layer: shapes on 10 by default :param sw_layer: SWs on 20 by default :param twin_enable: mirror the structure overall and connect with a 3um segment in the middle :return: two gdspy objects: first one containing the wire, the second the SWs """ allowed_types = { 'high-angle-symmetric', 'high-angle-60deg', 'high-angle-90deg', 'grazing-angle' } if loop_type not in allowed_types: print('loop_type must be in ' + allowed_types) raise ValueError # convenience variables if loop_type == 'high-angle-90deg': l2_proj_x = 0 l2_proj_y = l2 island_boundary_horizontal_offset = 0.2 # islands need to stay inside arm and some distance away from the joints. This is automatically guaranteed in 60deg configurations else: l2_proj_x = l2 * math.cos(math.pi / 3) l2_proj_y = l2 * math.sin(math.pi / 3) island_boundary_horizontal_offset = 0.1 # drawing a unit loop if loop_type == 'high-angle-60deg': # this one is special: only twinned structures for now la_proj_x = la * math.cos(math.pi / 3) la_proj_y = la * math.sin(math.pi / 3) ld = 5 # distance between two units p1 = [(l2_proj_x + la_proj_x, l2_proj_y + la_proj_y), (0, 0), (l1, 0), (l1 + l2_proj_x, l2_proj_y)] p2 = [(l1 + l2_proj_x + ld, l2_proj_y), (l1 + ld, 0), (2 * l1 + ld, 0), (2 * l1 + l2_proj_x + ld + la_proj_x, l2_proj_y + la_proj_y)] p3 = [(l2_proj_x, l2_proj_y), (2 * l1 + l2_proj_x + ld, l2_proj_y)] path1 = gp.FlexPath(p1, width) path2 = gp.FlexPath(p2, width) path3 = gp.FlexPath(p3, width) loop = gp.boolean(gp.boolean(path1, path2, 'or', layer=layer), path3, 'or', layer=layer) else: # 'high-angle-symmetric', 'high-angle-90deg', 'grazing-angle' p1 = [(-l2_proj_x, l2_proj_y), (0, 0), (l1, 0), (l1 + l2_proj_x, l2_proj_y)] p2 = [(-l2_proj_x - la, l2_proj_y), (l1 + l2_proj_x + la, l2_proj_y)] path1 = gp.FlexPath(p1, width) path2 = gp.FlexPath(p2, width) loop = gp.boolean(path1, path2, 'or', layer=layer) # attach smart walls if loop_type in {'high-angle-symmetric', 'high-angle-90deg'}: left_wall = [(-1, l2_proj_y - d2), (0, l2_proj_y - d2), (-math.cos(math.pi / 6), l2_proj_y - d2 - 0.8)] left_wall += straight_to_zigzag_line( [(-math.cos(math.pi / 6), l2_proj_y - d2 - 0.8), (-3, l2_proj_y - d2 - 0.8), (-3, l2_proj_y - d2), (-1, l2_proj_y - d2)], 0.2, 30) left_wall = gp.Polygon(left_wall, layer=sw_layer) left_wall.translate(island_boundary_horizontal_offset, 0) right_wall = [(-1, l2_proj_y - d2), (0, l2_proj_y - d2), (-math.cos(math.pi / 6), l2_proj_y - d2 - 0.8)] right_wall += straight_to_zigzag_line( [(-math.cos(math.pi / 6), l2_proj_y - d2 - 0.8), (-2, l2_proj_y - d2 - 0.8), (-2, l2_proj_y - d2), (-1, l2_proj_y - d2)], 0.2, 30) right_wall = gp.Polygon(right_wall, layer=sw_layer) right_wall.mirror((l1 / 2, 0), (l1 / 2, 1)) right_wall.translate(-island_boundary_horizontal_offset, 0) middel_wall = gp.Polygon( [(-0.2 + island_boundary_horizontal_offset, l2_proj_y - d1), (l1 + 0.2 - island_boundary_horizontal_offset, l2_proj_y - d1), (l1 + 1, l2_proj_y - d1 - 1), (-1, l2_proj_y - d1 - 1)], layer=sw_layer) symmetric_wall = gp.boolean(left_wall, right_wall, 'or', layer=sw_layer) symmetric_wall = gp.boolean(symmetric_wall, middel_wall, 'or', layer=sw_layer) elif loop_type == 'high-angle-60deg': left_wall = [(2 * l2_proj_x - 0.5, l2_proj_y - d2), (2 * l2_proj_x, l2_proj_y - d2), (2 * l2_proj_x - 0.5, l2_proj_y - d2 - 0.5)] left_wall += straight_to_zigzag_line( [(2 * l2_proj_x - 0.5, l2_proj_y - d2), (-2, l2_proj_y - d2), (-2, l2_proj_y - d2 - 1), (2 * l2_proj_x - 0.5, l2_proj_y - d2 - 0.5)], 0.2, 30) left_wall = gp.Polygon(left_wall, layer=sw_layer) right_wall = [(l1 + 0.5, l2_proj_y - d2), (l1, l2_proj_y - d2), (l1 + 0.5, l2_proj_y - d2 - 0.5)] right_wall += straight_to_zigzag_line( [(l1 + 0.5, l2_proj_y - d2), (l1 - 2 * l2_proj_x + 2.5, l2_proj_y - d2), (l1 - 2 * l2_proj_x + 2, l2_proj_y - d2 - 1), (l1 + 0.5, l2_proj_y - d2 - 0.5)], 0.2, 30) right_wall = gp.Polygon(right_wall, layer=sw_layer) middel_wall = gp.Polygon( [(2 * l2_proj_x - 0.2, l2_proj_y - d1), (l1 + 0.2, l2_proj_y - d1), (l1 + 1.5, l2_proj_y - d1 - 3**0.5), (2 * l2_proj_x - 1.5, l2_proj_y - d1 - 3**0.5)], layer=sw_layer) symmetric_wall = gp.boolean(left_wall, right_wall, 'or', layer=sw_layer) symmetric_wall = gp.boolean(symmetric_wall, middel_wall, 'or', layer=sw_layer) twin_wall = gp.copy(symmetric_wall) twin_wall.mirror((l2_proj_x + l1 + 0.5 * ld, 0), (l2_proj_x + l1 + 0.5 * ld, 1)) symmetric_wall = gp.boolean(symmetric_wall, twin_wall, 'or', layer=sw_layer) else: # loop-type: 'grazing-angle' loop.mirror((0, l2_proj_y / 2), (1, l2_proj_y / 2)) left_wall = [(0, -d1), (-1, -d1 - math.sqrt(3)), (-3, -d1 - math.sqrt(3)), (-4, -d1)] left_wall = gp.Polygon(left_wall, layer=sw_layer) right_wall = gp.copy(left_wall) right_wall.mirror((l1 / 2, 0), (l1 / 2, 1)) symmetric_wall = gp.boolean(left_wall, right_wall, 'or', layer=sw_layer) # make twin structures to facilitate growth if twin_enable and loop_type != 'high-angle-60deg': # only works on mirror-symmetric types loop2 = gp.copy(loop) loop2.mirror((l1 + l2_proj_x + 2.5 * la, 0), (l1 + l2_proj_x + 2.5 * la, 1)) loop = gp.boolean(loop, loop2, 'or', layer=layer) if loop_type in {'high-angle-symmetric', 'high-angle-90deg'}: loop = gp.boolean( loop, gp.FlexPath([(l1 + l2_proj_x + la, l2_proj_y), (l1 + l2_proj_x + 4 * la, l2_proj_y)], width), 'or', layer=layer) else: # 'grazing-angle' loop = gp.boolean(loop, gp.FlexPath([(l1 + l2_proj_x + la, 0), (l1 + l2_proj_x + 4 * la, 0)], width), 'or', layer=layer) wall2 = gp.copy(symmetric_wall) wall2.mirror((l1 + l2_proj_x + 2.5 * la, 0), (l1 + l2_proj_x + 2.5 * la, 1)) symmetric_wall = gp.boolean(symmetric_wall, wall2, 'or', layer=sw_layer) shadow = _add_shadow(symmetric_wall) return ( loop, symmetric_wall, shadow) if symmetric_wall != None else loop # no 30deg option with SWs
width=[small_margin, small_margin], offset=small_margin + width, gdsii_path=True, ) path.segment((0, 600 - bus_len - bend_radius - wg_gap * i), relative=True) path.turn(bend_radius, "r") path.segment((io_gap - 2 * bend_radius, 0), relative=True) path.turn(bend_radius, "l") path.segment((0, 300 - bend_radius + wg_gap * i), relative=True) c.add(path) dx = width / 2 + gap c.add( gdspy.boolean( gdspy.boolean(ring_bus, gdspy.copy(ring_margin, dx, 300), "or", precision=1e-4), gdspy.copy(ring_hole, dx, 300), "not", precision=1e-4, ).translate(input_gap * i, 0)) c.add(gdspy.CellArray(taper, len(ring_gaps), 1, (input_gap, 0), (0, 0))) c.add( gdspy.CellArray(grat, len(ring_gaps), 1, (input_gap, 0), (io_gap, 900 + taper_len))) # Save to a gds file and check out the output lib.write_gds("photonics.gds") gdspy.LayoutViewer(lib)