def makeYShapes(self, length, width, rotAngle, spacing, Nx, Ny, layers): if not (type(layers) == list): layers = [layers] pt1 = np.array((0, -width / 2.)) pt2 = np.array((length, width / 2.)) slit = Cell("Slit") for l in layers: rect = Rectangle(pt1, pt2, layer=l) slit.add(rect) shape = Cell('Shapes') shape.add(slit, rotation=0 + rotAngle) shape.add(slit, rotation=120 + rotAngle) shape.add(slit, rotation=240 + rotAngle) # CellArray(slit, Nx, Ny,(length + spacing, pitchV)) xspacing = length + spacing yspacing = (length + spacing) * np.sin(np.deg2rad(60)) shapearray = CellArray( shape, Nx, Ny / 2, (xspacing, yspacing * 2.), origin=(-(Nx * xspacing - spacing) / 2., -(Ny * yspacing - spacing * np.sin(np.deg2rad(60))) / 2.)) shapearray2 = CellArray( shape, Nx, Ny / 2, (xspacing, yspacing * 2.), origin=( xspacing / 2. - (Nx * xspacing - spacing) / 2., yspacing - (Ny * yspacing - spacing * np.sin(np.deg2rad(60))) / 2.)) allshapes = Cell('All Shapes') allshapes.add(shapearray) allshapes.add(shapearray2) self.add(allshapes)
def build_and_add_blocks(self): """ Create blocks and add them to the wafer Cell """ self.upCellLattice = self.getCellLattice(cellsize=2000) # Create a cell for the triangular blocks block_up = Cell('upblock') for x, y in self.upCellLattice: block_up.add(self.cells, origin=(x, y)) # Take each point in block lattice and make a copy of the block in that location for x, y in self.upCenters: self.add(block_up, origin=(x, y)) if self.symmetric_chips: for x, y in self.downCenters: self.add(block_up, origin=(x, y), rotation=180) else: self.downCellLattice = np.array(self.upCellLattice) * np.array( [1, -1]) block_down = Cell('downblock') for x, y in self.downCellLattice: block_down.add(self.cells, origin=(x, y)) for x, y in self.downCenters: self.add(block_down, origin=(x, y))
def add_tem_nanowires(self): size = 500 y_offset = 1300 shapes_big = make_shape_array(size, 0.02, 0.5, 'Tris_right', l_smBeam, labels=False) shapes_small = make_shape_array(size, 0.005, 0.5, 'Tris_right', l_smBeam, labels=False) tem_shapes = Cell('TEMShapes') # tem_shapes.add(shapes_big, origin=(2200 - size / 2., y_offset - size / 2.)) tem_shapes.add(shapes_small, origin=(-2200 - size / 2., y_offset - size / 2.)) for x, y in self.upCenters: self.add(tem_shapes, origin=(x, y)) for x, y in self.downCenters: self.add(tem_shapes, origin=( x, y - 2 * y_offset)) # Don't rotate because of directionality
def make_many_shapes(self, array_size, shape_areas, pitch, shapes, skew, layer): offset_x = array_size * 1.25 offset_y = array_size * 1.25 cur_y = 0 many_shape_cell = Cell('ManyShapes') for area in shape_areas: cur_x = 0 for shape in shapes: write_top_labels = cur_y == 0 write_side_labels = cur_x == 0 s_array = self.make_shape_array(array_size, area, pitch, shape, layer, skew, toplabels=write_top_labels, sidelabels=write_side_labels) many_shape_cell.add(s_array, origin=(cur_x - array_size / 2., cur_y - array_size / 2.)) cur_x += offset_x cur_y -= offset_y self.add(many_shape_cell, origin=(-offset_x * (len(shapes) - 1) / 2., offset_y * (len(skews) - 1) / 2.))
def add_theory_cell(self): theory_cells = Cell('TheoryCells') theory_cells.add(make_theory_cell(), origin=(-200, 0)) theory_cells.add(make_theory_cell_br(), origin=(200, 0)) self.block_up.add(theory_cells, origin=(0, 1300)) self.block_down.add(theory_cells, origin=(0, -1300))
def frame_label(self, label_txt, size, beam): text = Label(label_txt, size, layer=beam) lblVertOffset = 0.4 text.translate(tuple( np.array(-text.bounding_box.mean(0)))) # Center justify label lbl_cell = Cell('frame_label') lbl_cell.add(text) self.add(lbl_cell, origin=(0, self.size_y * lblVertOffset / 2.))
def add_chip_labels(self): wafer_lbl = PATTERN + '\n' + WAFER_ID text = Label(wafer_lbl, 20., layer=l_lgBeam) text.translate(tuple( np.array(-text.bounding_box.mean(0)))) # Center justify label chip_lbl_cell = Cell('chip_label') chip_lbl_cell.add(text) self.block_up.add(chip_lbl_cell, origin=(0, -3000)) self.block_down.add(chip_lbl_cell, origin=(0, 3000))
def add_wafer_outline(self, layers): """ Create Wafer Outline """ if not (type(layers) == list): layers = [layers] outline = Cell('WAF_OLINE') for l in layers: circ = Circle((0, 0), self.wafer_r, 100, layer=l) outline.add(circ) self.add(outline)
def add_theory_cell(self): theory_cells = Cell('TheoryCells') theory_cells.add(make_theory_cell(), origin=(-200, 0)) theory_cells.add(make_theory_cell_br(), origin=(200, 0)) for x, y in self.upCenters: self.add(theory_cells, origin=(x, y + 1300)) for x, y in self.downCenters: self.add(theory_cells, origin=( x, y - 1300 )) # Don't rotate because of directionality of branched membranes
def add_chip_labels(self): wafer_lbl = "AN1.3\n" + WAFER_ID text = Label(wafer_lbl, 20., layer=l_lgBeam) text.translate(tuple( np.array(-text.bounding_box.mean(0)))) # Center justify label chip_lbl_cell = Cell('chip_label') chip_lbl_cell.add(text) for x, y in self.upCenters: self.add(chip_lbl_cell, origin=(x, y - 3000)) for x, y in self.downCenters: self.add(chip_lbl_cell, origin=(x, y + 3000))
def processCheck_CleavingMark(self, yPosition, layers): if not (type(layers) == list): layers = [layers] for l in layers: pt1 = (100, yPosition) pt2 = (2000, yPosition) pt3 = (-1100, yPosition) pt4 = (-2800, yPosition) line1 = Path([pt1, pt2], width=10, layer=l) line2 = Path([pt3, pt4], width=10, layer=l) cMarkCell = Cell('Cleaving Mark') cMarkCell.add(line1) cMarkCell.add(line2) self.add(cMarkCell)
def makeArrowShape(self, length, width, rotAngle, spacing, Nx, Ny, layers): if not (type(layers) == list): layers = [layers] pt1 = np.array((-width * 0.3, -width / 2.)) pt2 = np.array((length, width / 2.)) slit = Cell("Slit") for l in layers: rect = Rectangle(pt1, pt2, layer=l) slit.add(rect) shape = Cell('Shapes') shape.add(slit, rotation=-120) shape.add(slit, rotation=120) xspacing = (width + spacing) / np.cos(np.deg2rad(30)) yspacing = (length + spacing / 2.) * np.sin(np.deg2rad(60)) shapearray = CellArray(shape, Nx, Ny, (xspacing, yspacing * 2.), origin=(-(Nx * xspacing - spacing) / 2., -(Ny * yspacing - spacing) / 2.)) allshapes = Cell('All Shapes') allshapes.add(shapearray) # allshapes.add(shapearray2) # allshapes.add(shape) self.add(allshapes)
def makeXShape(self, length, width, rotAngle, spacing, Nx, Ny, layers): if not (type(layers) == list): layers = [layers] pt1 = np.array((-length / 2., -width / 2.)) pt2 = np.array((length / 2., width / 2.)) slit = Cell("Slit") for l in layers: rect = Rectangle(pt1, pt2, layer=l) slit.add(rect) shape = Cell('Shapes') shape.add(slit, rotation=60) shape.add(slit, rotation=120) xspacing = (length + spacing) * np.cos(np.deg2rad(60)) yspacing = (length + spacing) * np.sin(np.deg2rad(60)) shapearray = CellArray(shape, Nx, Ny, (xspacing, yspacing), origin=(-(Nx * xspacing - spacing) / 2., -(Ny * yspacing - spacing) / 2.)) # shapearray2 = CellArray(shape, Nx, Ny/2,(xspacing,yspacing*2.),origin=(xspacing/2.-(Nx*xspacing-spacing)/2.,yspacing-(Ny*yspacing-spacing*np.tan(np.deg2rad(60)))/2.)) # shapearray = CellArray(shape, Nx, Ny,(xspacing,yspacing)) # shapearray.rotate(rotAngle) # shapearray.translate((-shapearray.bounding_box.mean(0)[0]/2.,-shapearray.bounding_box.mean(0)[1]/2.)) allshapes = Cell('All Shapes') allshapes.add(shapearray) # allshapes.add(shapearray2) # allshapes.add(shape) self.add(allshapes)
def add_orientation_text(self, layers): """ Create Orientation Label """ if not (type(layers) == list): layers = [layers] tblock = Cell('WAF_ORI_TEXT') for l in layers: for (t, pt) in list(self.o_text.items()): txt = Label(t, 1000, layer=l) bbox = txt.bounding_box txt.translate(-np.mean(bbox, 0)) # Center text around origin txt.translate(np.array(pt)) tblock.add(txt) self.add(tblock)
def make_many_shapes(array_size, shape_areas, pitch, shapes, layer): offset_x = array_size * 1.25 offset_y = array_size * 1.25 cur_y = 0 many_shape_cell = Cell('ManyShapes') for area in shape_areas: cur_x = 0 for shape in shapes: write_labels = cur_y == 0 s_array = make_shape_array(array_size, area, pitch, shape, layer, labels=write_labels) many_shape_cell.add(s_array, origin=(cur_x, cur_y)) cur_x += offset_x cur_y -= offset_y return many_shape_cell
def makeSlitArray(pitches, spacing, widths, lengths, rotAngle, arrayHeight, arraySpacing, layers): ''' Give it a single pitch and width and it will generate an array for all the lengths ''' if not (type(layers) == list): layers = [layers] if not (type(pitches) == list): pitches = [pitches] if not (type(lengths) == list): lengths = [lengths] if not (type(widths) == list): widths = [widths] for l in layers: i = -1 j = -1 manyslits = Cell("SlitArray") slitarray = Cell("SlitArray") pitch = pitches[0] width = widths[0] j += 1 i = -1 xlength = 0 slit = Cell("Slits") for length in lengths: spacing = length / 5. + 0.1 i += 1 pitchV = pitch / np.cos(np.deg2rad(rotAngle)) # widthV = width / np.cos(np.deg2rad(rotAngle)) # Nx = int(arrayWidth / (length + spacing)) Ny = int(arrayHeight / (pitchV)) # Define the slits if xlength == 0: translation = (length / 2., 0) xlength += length else: translation = (xlength + spacing + length / 2., 0) xlength += length + spacing pt1 = np.array((-length / 2., -width / 2.)) + translation pt2 = np.array((length / 2., width / 2.)) + translation rect = Rectangle(pt1, pt2, layer=l) rect = rect.copy().rotate(rotAngle) slit.add(rect) slits = CellArray(slit, 1, Ny, (0, pitchV)) # slits.translate((-(Nx - 1) * (length + spacing) / 2., -(Ny - 1)* (pitchV) / 2.)) slits.translate( (-slits.bounding_box[1, 0] / 2., -slits.bounding_box[1, 1] / 2.)) slitarray.add(slits) text = Label('w/p\n%i/%i' % (width * 1000, pitch * 1000), 2) lblVertOffset = 1.4 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, arrayHeight / lblVertOffset)))) # Center justify label slitarray.add(text) # manyslits.add(slitarray,origin=((arrayWidth + arraySpacing) * i, (arrayHeight + 2.*arraySpacing) * j-arraySpacing/2.)) manyslits.add(slitarray) # self.add(manyslits, origin=(-i * (arrayWidth + arraySpacing) / 2, -j * (arrayHeight + arraySpacing) / 2)) # self.add(manyslits) return manyslits
def add_tem_membranes(self, widths, length, pitch, layer): tem_membranes = Cell('TEM_Membranes') n = 3 curr_y = 0 for width in widths: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) membrane_array = CellArray(membrane_cell, 1, n, (0, pitch)) membrane_array_cell = Cell('MembraneArray_w{:.0f}'.format(width * 1000)) membrane_array_cell.add(membrane_array) tem_membranes.add(membrane_array_cell, origin=(0, curr_y)) curr_y += n * pitch n2 = 5 tem_membranes2 = Cell('Many_TEM_Membranes') tem_membranes2.add( CellArray(tem_membranes, 1, n2, (0, n * len(widths) * pitch))) self.block_up.add(tem_membranes2, origin=(0, -2000)) # self.block_up.add(tem_membranes2, origin=(0, -1400), rotation=90) self.block_down.add(tem_membranes2, origin=(0, 2000))
def make_align_markers(self, t, w, position, layers, cross=False, auto_marks=False): if not (type(layers) == list): layers = [layers] self.align_markers = Cell("AlignMarkers") self.align_marker = Cell("AlignMarker") for l in layers: if not cross: am0 = Rectangle((-w / 2., -w / 2.), (w / 2., w / 2.), layer=l) self.align_marker.add(am0) elif cross: crosspts = [(0, 0), (w / 2., 0), (w / 2., t), (t, t), (t, w / 2), (0, w / 2), (0, 0)] crosspts.extend( tuple(map(tuple, (-np.array(crosspts)).tolist()))) # crosspts = [(-t / 2., t / 2.), (-t / 2., h / 2.), (t / 2., h / 2.), # (t / 2., t / 2.), (w / 2., t / 2.), (w / 2., -t / 2.), # (t / 2., -t / 2.), (t / 2., -h / 2.), # (-t / 2., -h / 2.), (-t / 2., -t / 2.), # (-w / 2., -t / 2.), (-w / 2., t / 2.)] am0 = Boundary(crosspts, layer=l) # Create gdsCAD shape self.align_marker.add(am0) # am1 = Polygon(crosspts) #Create shapely polygon for later calculation if auto_marks: # automatic alignment marks for the e-beam tool auto_mark_rect = Rectangle((-10., -10.), (10., 10.), layer=l) auto_mark = Cell("AutoMark") auto_mark.add(auto_mark_rect) self.align_marker.add(auto_mark, origin=(100, 100)) self.align_marker.add(auto_mark, origin=(-100, 100)) self.align_marker.add(auto_mark, origin=(100, -100)) self.align_marker.add(auto_mark, origin=(-100, -100)) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [1, 1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [-1, 1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [1, -1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [-1, -1])) self.add(self.align_markers)
def makeSlitArray3(pitches, spacing, widths, lengths, rotAngle, arrayHeight, arrayWidth, arraySpacing, layers): ''' Give it a single pitch and arrays for spacings/widths and it will generate an array for all the combinations Makes seperate frame for each pitch ''' if not (type(layers) == list): layers = [layers] if not (type(pitches) == list): pitches = [pitches] if not (type(lengths) == list): lengths = [lengths] if not (type(widths) == list): widths = [widths] for l in layers: i = -1 j = -1 manyslits = Cell("SlitArray") length = lengths[0] spacing = length / 5. + 0.1 # Set the spacing between arrays for pitch in pitches: j += 1 i = -1 for width in widths: # for pitch in pitches: i += 1 if i % 3 == 0: j += 1 # Move to array to next line i = 0 # Restart at left pitchV = pitch / np.cos(np.deg2rad(rotAngle)) # widthV = width / np.cos(np.deg2rad(rotAngle)) Nx = int(arrayWidth / (length + spacing)) Ny = int(arrayHeight / (pitchV)) # Define the slits slit = Cell("Slits") rect = Rectangle( (-length / 2., -width / 2.), (length / 2., width / 2.), layer=l) rect = rect.copy().rotate(rotAngle) slit.add(rect) slits = CellArray(slit, Nx, Ny, (length + spacing, pitchV)) slits.translate((-(Nx - 1) * (length + spacing) / 2., -(Ny - 1) * (pitchV) / 2.)) slitarray = Cell("SlitArray") slitarray.add(slits) text = Label('w/p/l\n%i/%i/%i' % (width * 1000, pitch * 1000, length * 1000), 2) lblVertOffset = 1.35 if j % 2 == 0: text.translate( tuple(np.array(-text.bounding_box.mean(0)) + np.array(( 0, -arrayHeight / lblVertOffset)))) # Center justify label else: text.translate( tuple(np.array(-text.bounding_box.mean(0)) + np.array(( 0, arrayHeight / lblVertOffset)))) # Center justify label slitarray.add(text) manyslits.add(slitarray, origin=((arrayWidth + arraySpacing) * i, ( arrayHeight + 2. * arraySpacing) * j - arraySpacing / 2.)) return manyslits
def dashed_line(pt1, pt2, dashlength, width, layer): line = LineString((pt1, pt2)) dash_pts = np.arange(0, line.length, dashlength).tolist() if len(dash_pts) % 2 == 1: # Odd number dash_pts.append(line.length) # Add last point on line dash_pts = list( map(line.interpolate, dash_pts)) # Interpolate points along this line to make dashes dash_pts = [pt.xy for pt in dash_pts] dash_pts = np.reshape(dash_pts, (-1, 2, 2)) lines = [ Path(list(linepts), width=width, layer=layer) for linepts in dash_pts ] dline = Cell('DASHLINE') dline.add(lines) return dline
def processCheck_Slits(self, position, arrayWidth, slitWidth, pitch, length, rotation, layers): if not (type(layers) == list): layers = [layers] Nx = int(arrayWidth / pitch) Ny = 1 for l in layers: # Define the slits slit = Cell("Slits") rect = Rectangle((-slitWidth / 2., -length / 2.), (slitWidth / 2., length / 2.), layer=l) slit.add(rect) slits = CellArray(slit, Nx, Ny, (pitch, 0)) slits.translate((-(Nx) * (pitch) / 2., 0.)) slits.translate(position) slitarray = Cell("ProcessCheckingSlits") slitarray.add(slits) self.add(slitarray)
def slit_elongation_array(pitches, spacing, widths, lengths, rot_angle, array_height, array_spacing, layers): if not (type(layers) == list): layers = [layers] if not (type(pitches) == list): pitches = [pitches] if not (type(lengths) == list): lengths = [lengths] if not (type(widths) == list): widths = [widths] for l in layers: j = -1 manyslits = Cell("SlitArray") slitarray = Cell("SlitArray") pitch = pitches[0] width = widths[0] j += 1 i = -1 x_length = 0 slit = Cell("Slits") for length in lengths: spacing = length / 5. + 0.1 i += 1 pitch_v = pitch / np.cos(np.deg2rad(rot_angle)) n_y = int(array_height / pitch_v) # Define the slits if x_length == 0: translation = (length / 2., 0) x_length += length else: translation = (x_length + spacing + length / 2., 0) x_length += length + spacing pt1 = np.array((-length / 2., -width / 2.)) + translation pt2 = np.array((length / 2., width / 2.)) + translation rect = Rectangle(pt1, pt2, layer=l) rect = rect.copy().rotate(rot_angle) slit.add(rect) slits = CellArray(slit, 1, n_y, (0, pitch_v)) slits.translate( (-slits.bounding_box[1, 0] / 2., -slits.bounding_box[1, 1] / 2.)) slitarray.add(slits) text = Label('w/p\n%i/%i' % (width * 1000, pitch * 1000), 2) lbl_vert_offset = 1.4 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, array_height / lbl_vert_offset)))) # Center justify label slitarray.add(text) manyslits.add(slitarray) return manyslits
def add_tem_nanowires(self): size = 500 y_offset = 1000 shapes_big = make_shape_array(size, 0.02, 0.5, 'Tris_right', l_smBeam, labels=False) shapes_small = make_shape_array(size, 0.005, 0.5, 'Tris_right', l_smBeam, labels=False) tem_shapes = Cell('TEMShapes') # tem_shapes.add(shapes_big, origin=(2200 - size / 2., y_offset - size / 2.)) tem_shapes.add(shapes_small, origin=(-size / 2., -size / 2.)) self.block_up.add(tem_shapes, origin=(-2200, y_offset)) self.block_down.add(tem_shapes, origin=(2200, -y_offset))
def add_blockLabels(self, layers, center=False): if not (type(layers) == list): layers = [layers] vOffsetFactor = 1. blocklabelsUp = Cell('BlockLabelsUp') h = self.upTris[0].bounds[3] - self.upTris[0].bounds[1] sl_lattice = self.trisize + self.block_gap / np.tan(np.deg2rad(30)) h_lattice = np.sqrt(3.) / 2. * sl_lattice base = h_lattice for tri in self.upTris: lbl_col = self.blockcols[np.round(tri.centroid.x, 8)] lbl_row = self.blockrows[base * round(float(tri.bounds[1]) / base)] blockid = str(lbl_col) + str(lbl_row) blocklabel = Cell('LBL_B_' + blockid) for l in layers: txt = Label(blockid, 1000, layer=l) bbox = txt.bounding_box offset = np.array(tri.centroid) txt.translate(-np.mean(bbox, 0)) # Center text around origin txt.translate(offset) # Translate it to bottom of wafer blocklabel.add(txt) blocklabelsUp.add(blocklabel) if center: self.add(blocklabelsUp) else: self.add(blocklabelsUp, origin=(0, h / 2. * vOffsetFactor)) blocklabelsDown = Cell('BlockLabelsDown') for tri in self.downTris: lbl_col = self.blockcols[np.round(tri.centroid.x, 8)] lbl_row = self.blockrows[base * round(float(tri.bounds[1]) / base)] blockid = str(lbl_col) + str(lbl_row) blocklabel = Cell('LBL_' + blockid) for l in layers: txt = Label(blockid, 1000, layer=l) bbox = txt.bounding_box offset = np.array(tri.centroid) txt.translate(-np.mean(bbox, 0)) # Center text around origin if self.symmetric_chips: txt.rotate(180) txt.translate(offset) # Translate it to bottom of wafer blocklabel.add(txt) blocklabelsDown.add(blocklabel) if center: self.add(blocklabelsDown) else: self.add(blocklabelsDown, origin=(0, -h / 2. * vOffsetFactor))
def make_branch(length, width, layers, rot_angle=0): pt1 = np.array((0, -width / 2.)) pt2 = np.array((length, width / 2.)) slit = Cell("Slit") for l in layers: rect = Rectangle(pt1, pt2, layer=l) slit.add(rect) branch = Cell('Branch-{}/{}-lw'.format(length, width)) branch.add(slit, rotation=0 + rot_angle) branch.add(slit, rotation=120 + rot_angle) branch.add(slit, rotation=240 + rot_angle) return branch
def make_shape_array(self, array_size, shape_area, shape_pitch, type, layer, skew, toplabels=False, sidelabels=False): num_of_shapes = int(np.ceil(array_size / shape_pitch)) base_cell = Cell('Base') if 'tris' in type.lower(): triangle_side = np.sqrt(shape_area / np.sqrt(3) * 4) tri_shape = scale( RegPolygon([0, 0], triangle_side, 3, layer=layer), [skew, 1.0]) tri_cell = Cell('Tri') tri_cell.add(tri_shape) if 'right' in type.lower(): base_cell.add(tri_cell, rotation=0) elif 'left' in type.lower(): base_cell.add(tri_cell, rotation=-180) elif 'down' in type.lower(): base_cell.add(tri_cell, rotation=30) # not working for skew yet elif 'up' in type.lower(): base_cell.add(tri_cell, rotation=-30) # not working for skew yet elif type.lower() == "circles": circ_radius = np.sqrt(shape_area / np.pi) circ = scale(Disk([0, 0], circ_radius, layer=layer), [skew, 1.0]) base_cell.add(circ) elif type.lower() == 'hexagons': hex_side = np.sqrt(shape_area / 6. / np.sqrt(3) * 4) hex_shape = scale(RegPolygon([0, 0], hex_side, 6, layer=layer), [skew, 1.0]) hex_cell = Cell('Hex') hex_cell.add(hex_shape) base_cell.add(hex_cell, rotation=0) shape_array = CellArray(base_cell, num_of_shapes, num_of_shapes, [shape_pitch, shape_pitch]) shape_array_cell = Cell('Shape Array') shape_array_cell.add(shape_array) lbl_dict = { 'hexagons': 'hex', 'circles': 'circ', 'tris_right': 'triR', 'tris_left': 'triL' } if toplabels: text = Label('{}'.format(lbl_dict[type.lower()]), 2, layer=layer) lblVertOffset = 0.8 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((array_size / 2., array_size / lblVertOffset)))) # Center justify label shape_array_cell.add(text) if sidelabels: text = Label('a={:.0f}knm2'.format(shape_area * 1000), 2, layer=layer) lblHorizOffset = 1.5 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((-array_size / lblHorizOffset, array_size / 2.)))) # Center justify label shape_array_cell.add(text) return shape_array_cell
class Frame(Cell): """ Make a frame for writing to with ebeam lithography Params: -name of the frame, just like when naming a cell -size: the size of the frame as an array [xsize,ysize] """ def __init__(self, name, size, border_layers): if not (type(border_layers) == list): border_layers = [border_layers] Cell.__init__(self, name) self.size_x, self.size_y = size # Create the border of the cell for l in border_layers: self.border = Box((-self.size_x / 2., -self.size_y / 2.), (self.size_x / 2., self.size_y / 2.), 1, layer=l) self.add(self.border) # Add border to the frame self.align_markers = None def frame_label(self, label_txt, size, beam): text = Label(label_txt, size, layer=beam) lblVertOffset = 0.4 text.translate(tuple( np.array(-text.bounding_box.mean(0)))) # Center justify label lbl_cell = Cell('frame_label') lbl_cell.add(text) self.add(lbl_cell, origin=(0, self.size_y * lblVertOffset / 2.)) def make_align_markers(self, t, w, position, layers, cross=False, auto_marks=False): if not (type(layers) == list): layers = [layers] self.align_markers = Cell("AlignMarkers") self.align_marker = Cell("AlignMarker") for l in layers: if not cross: am0 = Rectangle((-w / 2., -w / 2.), (w / 2., w / 2.), layer=l) self.align_marker.add(am0) elif cross: crosspts = [(0, 0), (w / 2., 0), (w / 2., t), (t, t), (t, w / 2), (0, w / 2), (0, 0)] crosspts.extend( tuple(map(tuple, (-np.array(crosspts)).tolist()))) # crosspts = [(-t / 2., t / 2.), (-t / 2., h / 2.), (t / 2., h / 2.), # (t / 2., t / 2.), (w / 2., t / 2.), (w / 2., -t / 2.), # (t / 2., -t / 2.), (t / 2., -h / 2.), # (-t / 2., -h / 2.), (-t / 2., -t / 2.), # (-w / 2., -t / 2.), (-w / 2., t / 2.)] am0 = Boundary(crosspts, layer=l) # Create gdsCAD shape self.align_marker.add(am0) # am1 = Polygon(crosspts) #Create shapely polygon for later calculation if auto_marks: # automatic alignment marks for the e-beam tool auto_mark_rect = Rectangle((-10., -10.), (10., 10.), layer=l) auto_mark = Cell("AutoMark") auto_mark.add(auto_mark_rect) self.align_marker.add(auto_mark, origin=(100, 100)) self.align_marker.add(auto_mark, origin=(-100, 100)) self.align_marker.add(auto_mark, origin=(100, -100)) self.align_marker.add(auto_mark, origin=(-100, -100)) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [1, 1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [-1, 1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [1, -1])) self.align_markers.add(self.align_marker, origin=tuple(np.array(position) * [-1, -1])) self.add(self.align_markers) # TODO: Center array around the origin def make_shape_array(self, array_size, shape_area, shape_pitch, type, layer, skew, toplabels=False, sidelabels=False): num_of_shapes = int(np.ceil(array_size / shape_pitch)) base_cell = Cell('Base') if 'tris' in type.lower(): triangle_side = np.sqrt(shape_area / np.sqrt(3) * 4) tri_shape = scale( RegPolygon([0, 0], triangle_side, 3, layer=layer), [skew, 1.0]) tri_cell = Cell('Tri') tri_cell.add(tri_shape) if 'right' in type.lower(): base_cell.add(tri_cell, rotation=0) elif 'left' in type.lower(): base_cell.add(tri_cell, rotation=-180) elif 'down' in type.lower(): base_cell.add(tri_cell, rotation=30) # not working for skew yet elif 'up' in type.lower(): base_cell.add(tri_cell, rotation=-30) # not working for skew yet elif type.lower() == "circles": circ_radius = np.sqrt(shape_area / np.pi) circ = scale(Disk([0, 0], circ_radius, layer=layer), [skew, 1.0]) base_cell.add(circ) elif type.lower() == 'hexagons': hex_side = np.sqrt(shape_area / 6. / np.sqrt(3) * 4) hex_shape = scale(RegPolygon([0, 0], hex_side, 6, layer=layer), [skew, 1.0]) hex_cell = Cell('Hex') hex_cell.add(hex_shape) base_cell.add(hex_cell, rotation=0) shape_array = CellArray(base_cell, num_of_shapes, num_of_shapes, [shape_pitch, shape_pitch]) shape_array_cell = Cell('Shape Array') shape_array_cell.add(shape_array) lbl_dict = { 'hexagons': 'hex', 'circles': 'circ', 'tris_right': 'triR', 'tris_left': 'triL' } if toplabels: text = Label('{}'.format(lbl_dict[type.lower()]), 2, layer=layer) lblVertOffset = 0.8 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((array_size / 2., array_size / lblVertOffset)))) # Center justify label shape_array_cell.add(text) if sidelabels: text = Label('a={:.0f}knm2'.format(shape_area * 1000), 2, layer=layer) lblHorizOffset = 1.5 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((-array_size / lblHorizOffset, array_size / 2.)))) # Center justify label shape_array_cell.add(text) return shape_array_cell def make_many_shapes(self, array_size, shape_areas, pitch, shapes, skew, layer): offset_x = array_size * 1.25 offset_y = array_size * 1.25 cur_y = 0 many_shape_cell = Cell('ManyShapes') for area in shape_areas: cur_x = 0 for shape in shapes: write_top_labels = cur_y == 0 write_side_labels = cur_x == 0 s_array = self.make_shape_array(array_size, area, pitch, shape, layer, skew, toplabels=write_top_labels, sidelabels=write_side_labels) many_shape_cell.add(s_array, origin=(cur_x - array_size / 2., cur_y - array_size / 2.)) cur_x += offset_x cur_y -= offset_y self.add(many_shape_cell, origin=(-offset_x * (len(shapes) - 1) / 2., offset_y * (len(skews) - 1) / 2.))
smField3.frame_label(lbl, 3, l_smBeam) smField3.make_align_markers(2., 20., (180., 180.), l_lgBeam, cross=True) smField3.make_many_shapes(25, areas, pitch, shapes, skew, l_smBeam) skew = skews[3] lbl = "Sk={:.1f}x".format(skew) smField4 = Frame(lbl, (smFrameSize, smFrameSize), []) smField4.frame_label(lbl, 3, l_smBeam) smField4.make_align_markers(2., 20., (180., 180.), l_lgBeam, cross=True) smField4.make_many_shapes(25, areas, pitch, shapes, skew, l_smBeam) centerAlignField = Frame("CenterAlignField", (smFrameSize, smFrameSize), []) # Add everything together to a top cell topCell = Cell("TopCell") topCell.add(lgField) smFrameSpacing = 400 # Spacing between the three small frames dx = smFrameSpacing + smFrameSize dy = smFrameSpacing + smFrameSize topCell.add(smField1, origin=(-dx / 2., dy / 2.)) topCell.add(smField2, origin=(dx / 2., dy / 2.)) topCell.add(smField3, origin=(-dx / 2., -dy / 2.)) topCell.add(smField4, origin=(dx / 2., -dy / 2.)) # topCell.add(centerAlignField, origin=(0., 0.)) # %%Create the layout and output GDS file layout = Layout('LIBRARY', precision=1e-10) wafer = MBEWafer('MembranesWafer', wafer_r=wafer_r, cells=[topCell],
def make_theory_cell_br(): ''' Makes the theory cell and returns it as a cell''' # Growth Theory Slit Elongation pitch = [0.500] lengths = list(np.logspace(-3, 0, 20) * 8.0) # Logarithmic widths = [0.044, 0.028, 0.016, 0.012, 0.008] TheorySlitElong = Cell('LenWidthDependence') arrayHeight = 20. arraySpacing = 30. spacing = 10. TheorySlitElong.add( slit_elongation_array(pitch, spacing, widths[0], lengths, 0., arrayHeight, arraySpacing, l_smBeam)) TheorySlitElong.add(slit_elongation_array(pitch, spacing, widths[1], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -30)) TheorySlitElong.add(slit_elongation_array(pitch, spacing, widths[2], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -60)) TheorySlitElong.add(slit_elongation_array(pitch, spacing, widths[3], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -90)) TheorySlitElong.add(slit_elongation_array(pitch, spacing, widths[4], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -120)) # Length Dependence LenWidDep = Cell('LenWidDependence') pitch = [0.5] lengths = list(np.logspace(-2, 0, 10) * 8.0) # Logarithmic widths = [0.044, 0.016, 0.008] arrayHeight = 20. arrayWidth = arrayHeight arraySpacing = 30. spacing = 0.5 for i, length in enumerate(lengths): for j, width in enumerate(widths): LenWidDep.add(make_branch_array(pitch, width, length, ['pitch', 'width', 'length'], spacing, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(i * 30, j * 30)) # Make rotating slits shape_len = 3. shape_wid = 0.044 N = 13 # number of shapes in the 120 degree arc N_rows = 8 angle_sweep = 180 wheel_rad = 25. wheel1 = Cell('RotDependence_LongSlits') for i in range(N_rows): angle_offset = (i % 2) * 7.5 _angle_sweep = 180. - (i % 2) * 15. _N = int(N * _angle_sweep / angle_sweep) + (i % 2) angle_ref = False if i == 0: angle_ref = True wheel1.add( make_rotating_branches(shape_len, shape_wid, _N, wheel_rad + i * shape_len, l_smBeam, angle_sweep=_angle_sweep, angle_ref=angle_ref, angle_offset=angle_offset)) wheel2 = Cell('RotDependence_ShortSlits') angle_sweep = -180 wheel2.add( make_rotating_slits(2, 0.044, 91, 6. * 2, l_smBeam, angle_ref=True, angle_sweep=angle_sweep)) for i in range(10): # number of concentric rings to make wheel2.add( make_rotating_slits(2, 0.044, 91, (7.2 + i * 1.2) * 2, l_smBeam, angle_sweep=angle_sweep)) # Make branch devices shape_len = 3. shape_wid = 0.044 N = 13 # number of shapes in the 120 degree arc N_rows = 2 angle_sweep = 180 wheel_rad = 50. wheel3 = Cell('RotDependence_BranchDev') for i in range(N_rows): angle_offset = (i % 2) * 7.5 _angle_sweep = 180. - (i % 2) * 15. _N = int(N * _angle_sweep / angle_sweep) + (i % 2) angle_ref = False if i == 0: angle_ref = True wheel3.add( make_rotating_branch_devices(shape_len, shape_wid, _N, wheel_rad + i * shape_len * 2., l_smBeam, angle_sweep=_angle_sweep, angle_ref=angle_ref, angle_offset=angle_offset)) # Pitch Dependence PitchDep = Cell('PitchDependence') pitches = list(np.round(np.logspace(-1, 1, 10), 1)) # Logarithmic length = [2.] widths = [0.044, 0.016, 0.008] arrayHeight = 20. arrayWidth = arrayHeight arraySpacing = 30. spacing = 0.5 for j, width in enumerate(widths): for i, pitch in enumerate(pitches): PitchDep.add(make_branch_array(pitch, width, length, ['pitch', 'width', 'length'], spacing, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(i * 30, j * 30)) # Make arrays of various shapes hexagon_array = make_shape_array(20, 0.02, 0.75, 'Hexagons', l_smBeam) circles_array = make_shape_array(20, 0.02, 0.75, 'Circles', l_smBeam) triangle_down_array = make_shape_array(20, 0.02, 0.75, 'Tris_down', l_smBeam) triangle_up_array = make_shape_array(20, 0.02, 0.75, 'Tris_up', l_smBeam) # Merry Christmas! xmas_texts = [ LineLabel('Merry Christmas!', 2, style='gothgbt', line_width=0.044, layer=l_smBeam), LineLabel('Merry Christmas!', 2, style='italict', line_width=0.044, layer=l_smBeam), LineLabel('Merry Christmas!', 2, style='scriptc', line_width=0.044, layer=l_smBeam), LineLabel('Merry Christmas!', 2, style='scripts', line_width=0.044, layer=l_smBeam), LineLabel('Merry Christmas!', 2, style='romanc', line_width=0.044, layer=l_smBeam), LineLabel('Merry Christmas!', 2, style='romand', line_width=0.044, layer=l_smBeam) ] xmax_cell = Cell('MerryChristmas') for i, xmas_text in enumerate(xmas_texts): xmas_text.translate( tuple( np.array(-xmas_text.bounding_box.mean(0)) + np.array([20, -80 - i * 10.]))) # Center justify label xmax_cell.add(xmas_text) TopCell = Cell('GrowthTheoryTopCell') TopCell.add(wheel1, origin=(-170., -50.), rotation=-90.) TopCell.add(wheel2, origin=(-175., -50.), rotation=-90.) TopCell.add(wheel3, origin=(0, -80)) TopCell.add(PitchDep, origin=(-200., -250.)) TopCell.add(LenWidDep, origin=(-200., -50.)) TopCell.add(xmax_cell, origin=(-110., 60.)) return TopCell
def make_shape_array(array_size, shape_area, shape_pitch, type, layer): num_of_shapes = int(np.ceil(array_size / shape_pitch)) base_cell = Cell('Base') if type.lower() == "circles": circ_radius = np.sqrt(shape_area / np.pi) circ = Disk([0, 0], circ_radius, layer=layer) base_cell.add(circ) elif type.lower() == 'tris_down': triangle_side = np.sqrt(shape_area / np.sqrt(3) * 4) tri_shape = RegPolygon([0, 0], triangle_side, 3, layer=layer) tri_cell = Cell('Tri') tri_cell.add(tri_shape) base_cell.add(tri_cell, rotation=30) elif type.lower() == 'tris_up': triangle_side = np.sqrt(shape_area / np.sqrt(3) * 4) tri_shape = RegPolygon([0, 0], triangle_side, 3, layer=layer) tri_cell = Cell('Tri') tri_cell.add(tri_shape) base_cell.add(tri_cell, rotation=-30) elif type.lower() == 'hexagons': hex_side = np.sqrt(shape_area / 6. / np.sqrt(3) * 4) hex_shape = RegPolygon([0, 0], hex_side, 6, layer=layer) hex_cell = Cell('Hex') hex_cell.add(hex_shape) base_cell.add(hex_cell, rotation=0) shape_array = CellArray(base_cell, num_of_shapes, num_of_shapes, [shape_pitch, shape_pitch]) shape_array_cell = Cell('Shape Array') shape_array_cell.add(shape_array) text = Label('{}'.format(type), 2) lblVertOffset = 0.8 text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((array_size / 2., array_size / lblVertOffset)))) # Center justify label shape_array_cell.add(text) return shape_array_cell