def __init__(self, name, holecell, arrayaxes=((1, 0), (0, 1)), arrayperiods=(1, 1), excludepoly=None): self.Name = name self.Axes = arrayaxes self.Periods = arrayperiods self.holearray = gdspy.Cell(name) self.hole = holecell self.excludepoly = excludepoly if (len(numpy.array(holecell).shape) == 0): for i in range(self.Periods[0]): ax0pt = addtup((0, 0), scalartup(i, self.Axes[0])) for j in range(self.Periods[1]): ax1pt = addtup((0, 0), scalartup(j, self.Axes[1])) if (excludepoly == None) | (not gdspy.inside( [addtup(ax0pt, ax1pt)], excludepoly)[0]): refcell = gdspy.CellReference(holecell, addtup(ax0pt, ax1pt)) self.holearray.add(refcell) elif (numpy.array(holecell).shape == arrayperiods): for i in range(self.Periods[0]): ax0pt = addtup((0, 0), scalartup(i, self.Axes[0])) for j in range(self.Periods[1]): ax1pt = addtup((0, 0), scalartup(j, self.Axes[1])) if (excludepoly == None) | (not gdspy.inside( [addtup(ax0pt, ax1pt)], excludepoly)[0]): refcell = gdspy.CellReference(holecell[i, j], addtup(ax0pt, ax1pt)) self.holearray.add(refcell) else: raise ValueError( "Error in the holecell input! Not right dimention")
def _render_text(text, size=None, position=(0, 0), font_prop=None, tolerance=0.1): """This function is copied from https://gdspy.readthedocs.io/en/stable/gettingstarted.html#using-system-fonts""" path = TextPath(position, text, size=size, prop=font_prop) polys = [] xmax = position[0] for points, code in path.iter_segments(): if code == path.MOVETO: c = gdspy.Curve(*points, tolerance=tolerance) elif code == path.LINETO: c.L(*points) elif code == path.CURVE3: c.Q(*points) elif code == path.CURVE4: c.C(*points) elif code == path.CLOSEPOLY: poly = c.get_points() if poly.size > 0: if poly[:, 0].min() < xmax: i = len(polys) - 1 while i >= 0: if gdspy.inside(poly[:1], [polys[i]], precision=0.1 * tolerance)[0]: p = polys.pop(i) poly = gdspy.boolean( [p], [poly], "xor", precision=0.1 * tolerance, max_points=0, ).polygons[0] break elif gdspy.inside(polys[i][:1], [poly], precision=0.1 * tolerance)[0]: p = polys.pop(i) poly = gdspy.boolean( [p], [poly], "xor", precision=0.1 * tolerance, max_points=0, ).polygons[0] i -= 1 xmax = max(xmax, poly[:, 0].max()) polys.append(poly) return polys
def test_inside(): polygons = [ gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180), gdspy.Rectangle((20, -10), (40, 10)), gdspy.Rectangle((-10, 0), (10, 20)) ] assert gdspy.inside([(0, 0)], polygons) == (True, ) assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == \ (True, False, True, False) assert gdspy.inside([[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, 'any') == (True, False, True) assert gdspy.inside([[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, 'all') == (False, False, True)
def render_text(text, size=None, position=(0, 0), font_prop=None, tolerance=0.1): path = TextPath(position, text, size=size, prop=font_prop) polys = [] xmax = position[0] for points, code in path.iter_segments(): if code == path.MOVETO: c = gdspy.Curve(*points, tolerance=tolerance) elif code == path.LINETO: c.L(*points) elif code == path.CURVE3: c.Q(*points) elif code == path.CURVE4: c.C(*points) elif code == path.CLOSEPOLY: poly = c.get_points() if poly.size > 0: if poly[:, 0].min() < xmax: i = len(polys) - 1 while i >= 0: if gdspy.inside(poly[:1], [polys[i]], precision=0.1 * tolerance)[0]: p = polys.pop(i) poly = gdspy.boolean( [p], [poly], "xor", precision=0.1 * tolerance, max_points=0, ).polygons[0] break elif gdspy.inside(polys[i][:1], [poly], precision=0.1 * tolerance)[0]: p = polys.pop(i) poly = gdspy.boolean( [p], [poly], "xor", precision=0.1 * tolerance, max_points=0, ).polygons[0] i -= 1 xmax = max(xmax, poly[:, 0].max()) polys.append(poly) return polys
def test_inside(): polygons = [ gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180), gdspy.Rectangle((20, -10), (40, 10)).polygons[0], gdspy.CellReference( gdspy.Cell("X").add(gdspy.Rectangle((-10, 0), (10, 20)))), ] assert gdspy.inside([(0, 0)], polygons[0]) == (False, ) assert gdspy.inside([(0, 0)], polygons[2]) == (True, ) assert gdspy.inside([(0, 0)], polygons) == (True, ) assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == ( True, False, True, False, ) assert gdspy.inside( [[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, "any", ) == (True, False, True) assert gdspy.inside( [[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, "all", ) == (False, False, True)
def bench_gdspy(): r = gdspy.Rectangle((0, 0), (20, 10)) pts = [[(1, 1), (-1, -1)], [(2, 2), (-2, 2), (2, -2)], [(5, 5), (10, 5)], [(-1, -1), (-2, -2)], [(2, 3)]] assert gdspy.inside(pts[0], r) == (True, False) assert gdspy.inside(pts[1], r) == (True, False, False) assert gdspy.inside(pts[1:2], r, "any") == (True, ) assert gdspy.inside(pts[1:2], r, "all") == (False, ) assert gdspy.inside(pts[4], r) == (True, ) assert gdspy.inside(pts, r, "any") == (True, True, True, False, True) assert gdspy.inside(pts, r, "all") == (False, False, True, False, True)
def inside(points, cellref, dist, nop = 3, precision = 0.001): #===================== # Save cell to a file \\ #========================================================================= # Arguments: points : list of points to check || # cellref : gdspy cell reference object || # dist : distance from points to search || # nop : number of probe points within dist || # precision : gdspy.inside precision parameter || #========================================================================= # Force uneven if nop % 2 == 0: nop += 1 search_ps = [] for p in points: px = np.linspace(p[0] - dist/2, p[0] + dist/2, nop) py = np.linspace(p[1] - dist/2, p[1] + dist/2, nop) search_ps.append([[i, j] for i in px for j in py]) return gd.inside(search_ps, cellref, precision = precision)
def cut_out_holes(polygons, layer=0, datatype=0): top_level_polygons = [] used_polygons = set() for polygon_ext in polygons: polygons_to_cut = [polygon_ext] for polygon_int in polygons: if polygon_ext is polygon_int: continue # if g.inside([polygon_ext], g.Polygon(polygon_int))[0]: if g.inside([polygon_int], g.Polygon(polygon_ext))[0]: polygons_to_cut.append(polygon_int) used_polygons.add(make_hashable(polygon_int)) if len(polygons_to_cut) >= 2: used_polygons.add(make_hashable( polygons_to_cut[0])) # don't add an un-cut exterior top_level_polygons.append(polygons_to_cut) for polygon in polygons: if make_hashable(polygon) not in used_polygons: top_level_polygons.append([polygon]) result = [ reduce(partial(cut_out_hole, layer=layer, datatype=datatype), polygons_to_cut) for polygons_to_cut in top_level_polygons ] return g.PolygonSet(result, layer=layer, datatype=datatype)
def test_inside(): gdspy.current_library = gdspy.GdsLibrary() polygons = [ gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180), gdspy.Rectangle((20, -10), (40, 10)).polygons[0], gdspy.CellReference( gdspy.Cell('X').add(gdspy.Rectangle((-10, 0), (10, 20)))), ] assert gdspy.inside([(0, 0)], polygons[0]) == (False, ) assert gdspy.inside([(0, 0)], polygons[2]) == (True, ) assert gdspy.inside([(0, 0)], polygons) == (True, ) assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == \ (True, False, True, False) assert gdspy.inside([[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, 'any') == (True, False, True) assert gdspy.inside([[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]], polygons, 'all') == (False, False, True)
def __init__(self, cell, grid_size, buffer=None, layers=None, precision=0.001): start_time = time.time() self.grid_size = grid_size if layers is None: layers = list(cell.get_layers()) if not isinstance(layers, list): layers = [layers] if buffer is None: buffer = grid_size / 2 bounding_box = cell.get_bounding_box() x_length = int( (bounding_box[1][0] - bounding_box[0][0] + 2 * grid_size) / grid_size) + 1 y_length = int( (bounding_box[1][1] - bounding_box[0][1] + 2 * grid_size) / grid_size) + 1 out_string = '-- Constructing map with ' + str(int( x_length * y_length)) + ' (' + str(int(x_length)) + ' x ' + str( int(y_length)) + ') entries' print(out_string, end=(7 - len(out_string) // 8) * '\t', flush=True) x_linspace = np.linspace(bounding_box[0][0] - grid_size, bounding_box[1][0] + grid_size, x_length) y_linspace = np.flip( np.linspace(bounding_box[0][1] - grid_size, bounding_box[1][1] + grid_size, y_length)) x_array, y_array = np.meshgrid(x_linspace, y_linspace) xy_array = np.array(list(zip(x_array.ravel(), y_array.ravel()))).reshape( *x_array.shape, 2) self.mask = np.zeros((y_length, x_length)) self.copy_cell = cell.copy(cell.name + "_copy", deep_copy=True) self.copy_cell.remove_polygons( lambda pts, layer, datatype: layer not in layers) self.copy_polygonset = gp.offset(self.copy_cell.get_polygons(), distance=buffer) map_gdspy = np.array( gp.inside(np.array(xy_array).reshape(-1, 2), self.copy_polygonset, precision=precision)).reshape((y_length, x_length)) for i in range(y_length): for j in range(x_length): if not map_gdspy[i][j]: if self.mask[i][j] != 1: self.mask[i][j] = 0 else: try: self.mask[i][j] = self.mask[i - 1][j] = self.mask[ i + 1][j] = self.mask[i][j - 1] = self.mask[i][j + 1] = 1 except: pass elapsed_time = round(time.time() - start_time, 3) print('| Finished after ' + str(elapsed_time) + ' s --') self.x_length = x_length self.y_length = y_length self.x_linspace = x_linspace self.y_linspace = y_linspace self.x_array = x_array self.y_array = y_array self.xy_array = xy_array
def gen_gds(poly_coords: List[np.ndarray], filepath: str, extra_structures: List[np.ndarray] = None, deembed: bool = True) -> None: """Generate GDS given a list of polygon coordinates. Output GDS has units of microns and precision in nanometers. Args: poly_coords: List of polygon coordinates. Elements of list are n x 2 numpy.ndarrays. Assumes coordinates in nanometers. filepath: Name of the filepath to output gds file. extra_structures: List of polygons to be added to the gds that are not part of the levelset function. deembed: Boolean to control if polygon deembeding will occur or not. """ poly_cell = gdspy.Cell("POLYGONS", exclude_from_current=True) test_points = [] gds_polygons = [] # Convert polygon coordinates from nanometers to microns since # output is in microns. poly_coords = [np.array(poly) / NM_PER_UM for poly in poly_coords] for polygon in poly_coords: test_points.append(tuple(polygon[0])) gds_polygons.append(gdspy.Polygon(polygon, 0)) if deembed: containment_mx = [] for polygon in gds_polygons: containment_mx.append(gdspy.inside(test_points, [polygon])) # Subtract by identity matrix since polygon_i trivially contains # polygon_i. containment_mx = np.array(containment_mx) - np.eye(len(gds_polygons)) # overlap_list[i] tells how many polygons are contained in polygon i. overlap_list = np.sum(containment_mx, axis=1) overlap_num = 0 while sum(overlap_list) != 0: overlap_num = overlap_num + 1 # We loop until there are no longer any more polygons of a specific # overlap number before going to the next overlap number. # # The reasoning for this is as we begin to delete polygons, # the overlap number changes and so polygons which were of # overlap_num > 1, may become polygons of overlap_num = 1. # # np.where(overlap_list==overlap_num)[0].size is how we see if # any polygons satisfy the current overlap number. target_polys = np.where(overlap_list == overlap_num)[0] while target_polys.size != 0: # We iterate through each polygon in our polygon list until no # polygon satisfies the current overlap number. for i in target_polys[::-1]: containment_list = np.nonzero(containment_mx[i, :])[0] for j in containment_list[::-1]: # The boolean 'not' operation is performed here. # We replace polygon[i] of the two polygons with the # result of the operation and delete polygon[j]. gds_polygons[i] = gdspy.fast_boolean(gds_polygons[i], gds_polygons[j], 'not', layer=0) gds_polygons[j] = None test_points[j] = None for k in range(len(gds_polygons) - 1, -1, -1): if gds_polygons[k] is None: del gds_polygons[k] del test_points[k] containment_mx = [] for polygon in gds_polygons: containment_mx.append(gdspy.inside(test_points, [polygon])) containment_mx = np.array(containment_mx) - np.eye( len(gds_polygons)) overlap_list = np.sum(containment_mx, axis=1) target_polys = np.where(overlap_list == overlap_num)[0] for polygon in gds_polygons: poly_cell.add(polygon) if extra_structures is not None: for extra_polygon in extra_structures: poly_cell.add(gdspy.Polygon(extra_polygon, 0)) gdspy.write_gds(filepath, cells=[poly_cell], unit=1.0e-6, precision=1.0e-9)
def router(cell, fr_str, fr_ep, to_str, to_ep, width, bmul, grid_s=1, xr=False, yr=False, uniform_width=False, precision=0.001, pref='y', switch_pref=False, layer=0, debug=False, nop=21, dist_multi=2, pathmethod='poly', detect='native'): fr = fr_str.endpoints[fr_ep] to = to_str.endpoints[to_ep] border_s = bmul * grid_s box = [fr, to] # Make sure first box coord is always the top-left corner and add additional border points xs = [box[0][0], box[1][0]] ys = [box[0][1], box[1][1]] box = [[min(xs) - border_s, max(ys) + border_s], [max(xs) + border_s, min(ys) - border_s]] # Build list of gridpoints that are outside all structures in cell lxr = int((box[1][0] - box[0][0]) / grid_s) + 1 lyr = int((box[0][1] - box[1][1]) / grid_s) + 1 if type(xr) not in [list, np.ndarray]: xr = np.linspace(box[0][0], box[1][0], lxr) else: lxr = len(xr) if type(yr) not in [list, np.ndarray]: yr = np.linspace(box[0][1], box[1][1], lyr) else: lyr = len(yr) p = [] p_d_to = [] p_d_fr = [] for y in yr: for x in xr: c = (x, y) p.append(c) # Compute squared Euclidean distance from to and fr coords for each gridpoint # For optimization we don't need to sqrt() since minimal in squared is minimal in sqrt dist_fr = (x - fr[0])**2 + (y - fr[1])**2 dist_to = (x - to[0])**2 + (y - to[1])**2 p_d_fr.append(dist_fr) p_d_to.append(dist_to) p_i = np.array(p) p_d_fr = np.array(p_d_fr) p_d_to = np.array(p_d_to) # Build list of points that are inside a structure cell_ref = gd.CellReference(cell) if detect == 'native': inside = np.array(gd.inside(p, cell_ref, precision=precision)) elif detect == 'custom': inside = np.array( gtools.funcs.inside(p, cell_ref, dist=dist_multi * grid_s, nop=nop, precision=precision)) else: raise ValueError( 'Parameter \'detect\' is only allowed to have values [\'native\', \'custom\'], cannot continue' ) p_d_fr_min = np.min(p_d_fr[np.argwhere(inside == False)]) p_d_to_min = np.min(p_d_to[np.argwhere(inside == False)]) # Get p_i index of starting values start_i = np.argwhere(p_d_fr == p_d_fr_min).tolist() end_i = np.argwhere(p_d_to == p_d_to_min).tolist() start_i = [item for sublist in start_i for item in sublist] end_i = [item for sublist in end_i for item in sublist] start = p_i[start_i] end = p_i[end_i] # Now start stepping from start to end, labelling all gridpoints accordingly by the number of steps required from starting point to reach it n = [0] * 4 lp = len(p) p_g = [0] * lp path_found = False k = 0 while not path_found and start_i: k += 1 next_start_i = [] if debug: print(start_i) for i in start_i: # Look up, down, left and right, store the index n = lookaround(i, lxr, pref=pref) # Check if any of the neighbouring points are not in a structure and not in p_g for nb in n: if nb in end_i: path_found = True p_g[nb] = k final_index = nb if debug: # Visualize circ = gd.Round(p[nb], 0.1, layer=10) cell.add(circ) txt = gd.Text(str(k), 0.5, p[nb], layer=11) cell.add(txt) break # Point is out of bounds, marked as structure (< 0) or already has a step value (> 0) if nb < 0 or nb >= lp or p_g[nb] != 0 or ( i % lxr == 0 and nb % lxr == 1) or (i % lxr == 1 and nb % lxr == 0): continue # Skip this iteration if inside[nb]: p_g[nb] = -1 else: p_g[nb] = k next_start_i.append(nb) if debug: # Visualize circ = gd.Round(p[nb], 0.1, layer=1) cell.add(circ) txt = gd.Text(str(k), 0.5, p[nb], layer=2) cell.add(txt) start_i = copy.copy(next_start_i) # Routing ended, checking whether we succeeded if not path_found: print('>> ERROR: No existing route was found.') return False print('>> Found a route in ' + str(k) + ' steps.') # Backtrace path this_index = final_index backtraced = [to, p[final_index]] switched = False for this_k in range(k, -1, -1): # Change move preference after switch_pref moves if switch_pref and not switched and this_k < switch_pref * k: pref = 'x' if pref == 'y' else 'y' switched = True n = lookaround(this_index, lxr, pref=pref) for nb in n: if nb < lp and p_g[nb] == this_k: this_index = nb backtraced.append(p[nb]) break backtraced.append(fr) if debug: print('>> Points of found route:') print(backtraced) # Generate list of widths for the route if not uniform_width: to_w = to_str.endpoint_dims[to_ep] fr_w = fr_str.endpoint_dims[fr_ep] ws = [to_w if to_w != None else width] * 2 + [width] * ( len(backtraced) - 4) + [fr_w if fr_w != None else width] * 2 else: ws = width # Create backtraced path if pathmethod == 'poly': r = gd.PolyPath(backtraced, ws, layer=layer) elif pathmethod == 'flex': r = gd.FlexPath(backtraced, ws, corners='smooth', layer=layer) else: raise ValueError( 'Parameter \'pathmethod\' only has allowed values [\'poly\', \'flex\']' ) ends = {'A': backtraced[0], 'B': backtraced[-1]} epsz = { 'A': ws[0] if not uniform_width else width, 'B': ws[-1] if not uniform_width else width } structure = gtools.classes.GDStructure(r, ends, epsz) # Connect to 'to' and 'from' structures fr_str.next['AUTOROUTE_A'] = structure to_str.next['AUTOROUTE_B'] = structure structure.prev['AUTOROUTE_A'] = fr_str structure.prev['AUTOROUTE_B'] = to_str return structure
def bench_gdspy(): gdspy.inside(points, gdspy_ring) gdspy.inside([points], gdspy_ring, "any") gdspy.inside([points], gdspy_ring, "all") gdspy.inside(points, [gdspy_ring, gdspy_circle]) gdspy.inside([points], [gdspy_ring, gdspy_circle], "any") gdspy.inside([points], [gdspy_ring, gdspy_circle], "all")
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