def makeCells(self, cellsize=2000, startpt=(0, 0)): gap = self.cell_gap # Define the parameters of our shapes if self.cellsAtEdges: sl_tri = self.trisize * 1.5 # Only needed if you want to put cells very close the edge of triangle chip else: sl_tri = self.trisize h_tri = np.sqrt(3.) / 2. * sl_tri # Create the triangular block block = Polygon([ [-sl_tri / 2., -h_tri / 3.], [sl_tri / 2., -h_tri / 3.], [0, 2. * h_tri / 3.], [-sl_tri / 2., -h_tri / 3.] ]) # Make a square cell cell = box(-cellsize / 2., -cellsize / 2., cellsize / 2., cellsize / 2.) # Make a lattice for the cells # lattice = self.createPtLattice(sl_tri, cellsize / 2. + gap / 2.,cellsize/2. + gap) lattice = self.createPtLattice(sl_tri, (cellsize + gap) / 2., (cellsize + gap) * np.sqrt(3.) / 2.) lattice = lattice + np.array(startpt) lattice = [ pt for pt in lattice if Point(pt).within(block) ] # Keep only points within triangular block # Use the lattice of points to translate the cell all over the block cells = [translateshape(cell, xoff=x, yoff=y) for x, y in lattice] # Keep only the cells that are fully within the block cells = [f for f in cells if f.within(block)] return cells
def add_aligment_marks(self, layers): """ Create alignment marks on all active layers """ if not (type(layers) == list): layers = [layers] d_layers = self.cell_layers # styles=['B' if i%2 else 'B' for i in range(len(d_layers))] # am = AlignmentMarks(styles, d_layers) am = Cell('CONT_ALGN') # Define dimensions of the alignment cross t = 200. # Thickness t /= 2. h = 2000. # Height w = 2000. # Width crosspts = [ (-t, t), (-t, h), (t, h), (t, t), (w, t), (w, -t), (t, -t), (t, -h), (-t, -h), (-t, -t), (-w, -t), (-w, t)] # Create shapely polygon for later calculation crossPolygon = Polygon(crosspts) crossPolygons = [] for pt in self.align_pts: crossPolygons.extend([ translateshape(crossPolygon, xoff=pt[0], yoff=pt[1])]) # TODO: Replace these two loops with a single loop, looping over an array of block objects # TODO: Make the deleting more efficient by using del for multiple indexes? i_del = [] # Loop over all triangular blocks for i, tri in enumerate(self.upTris): for poly in crossPolygons: # Loop over all alignment crosses if poly.intersects(tri) or poly.within(tri) or poly.contains( tri): # If conflict is detected, remove that triangular block i_del.append(i) print(('up:' + str(self.upTris[i].centroid.xy))) self.upTris = [tri for i, tri in enumerate(self.upTris) if i not in i_del] # Repeat for down-facing triangles i_del = [] for i, tri in enumerate(self.downTris): for poly in crossPolygons: if poly.intersects(tri) or poly.within(tri) or poly.contains( tri): # If conflict is detected, remove that triangular block i_del.append(i) print(('down:' + str(self.downTris[i].centroid.xy))) self.downTris = [tri for i, tri in enumerate(self.downTris) if i not in i_del] # Refresh the centers of the remaining triangles self.upCenters = [list(zip(*tri.centroid.xy)[0]) for tri in self.upTris] self.downCenters = [list(zip(*tri.centroid.xy)[0]) for tri in self.downTris] for l in layers: # Add marker to all layers cross = Boundary(crosspts, layer=l) # Create gdsCAD shape am.add(cross) mblock = Cell('WAF_ALGN_BLKS') mblock.add(am) for pt in self.align_pts: self.add(mblock, origin=pt)
def getCellLattice(self, cellsize=2000): iterations = self.MCIterations ycelloffset = self.cell_gap / 3.5 # Arbitrary, change by trial and error if self.doMCSearch: best = [0, 0, 0, 0] # Iterates many times to find the best fit for i in range(iterations): # Random seed point rndpt = (0, np.random.randint(-cellsize, cellsize)) # Make cells around this point cells = self.makeCells(startpt=rndpt, cellsize=cellsize) if not cells: continue centroidDist = np.array([cell.centroid.xy for cell in cells]).squeeze() if len(centroidDist.shape) == 2: centroidDist = centroidDist.mean(0) if len(cells) > best[1]: best = [rndpt, len(cells), cells, centroidDist] elif len(cells) == best[1]: # Choose the one that is closer to the center of the wafer if np.sqrt(rndpt[0] ** 2 + rndpt[1] ** 2) < np.sqrt(best[0][0] ** 2 + best[0][1] ** 2): # if centroidDist < best[3]: best = [rndpt, len(cells), cells, centroidDist] # print("Current: {:f}, Best {:f}").format(len(cells),best[1]) # centroidDist = np.array([tri.centroid.xy for tri in cells]).squeeze().mean(0) # centroidDist = np.sqrt(centroidDist[0]**2+centroidDist[1]**2) # centroidDist = np.array([cell.centroid.xy for cell in cells]).squeeze() # Choose the best configuration (fits the most cells and is closest to centroid) cells = best[2] else: cells = self.makeCells(cellsize=2000) sl_tri = self.trisize h_tri = np.sqrt(3.) / 2. * sl_tri gap = self.block_gap from matplotlib import pyplot fig = pyplot.figure(1, dpi=90) ax = fig.add_subplot(111) ax.grid() ax.axis('equal') block = Polygon([ [-sl_tri / 2., -h_tri / 3.], [sl_tri / 2., -h_tri / 3.], [0, 2. * h_tri / 3.], [-sl_tri / 2., -h_tri / 3.] ]) block = translateshape(block, yoff=h_tri / 3. + gap / 2.) block = translateshape(block, xoff=self.blockOffset[0], yoff=self.blockOffset[1]) # TODO: plot output not working properly because of this? patch = PolygonPatch(block, facecolor="#{0:0{1}X}".format(np.random.randint(0, 16777215), 6), # facecolor=RED, edgecolor=BLACK, alpha=0.3, zorder=2) ax.add_patch(patch) ax.plot(block.exterior.coords.xy[0], block.exterior.coords.xy[1], 'k-') for cell in cells: cell = translateshape(cell, yoff=h_tri / 3. + gap / 2. + ycelloffset) cell = translateshape(cell, xoff=self.blockOffset[0], yoff=self.blockOffset[1]) # TODO: plot output not working properly because of this? patch = PolygonPatch(cell, facecolor="#{0:0{1}X}".format(np.random.randint(0, 16777215), 6), edgecolor='k', alpha=0.3, zorder=2) ax.add_patch(patch) # Convert cells to lattice of points cellLattice = np.array([list(zip(*cell.centroid.xy))[0] for cell in cells]) cellLattice = cellLattice + np.array([0, ycelloffset]) return cellLattice
def _place_blocks(self): """ Create the list of valid block sites based on block size and wafer diam. """ sl_tri = self.trisize # Sidelength of the triangular blocks h_tri = np.sqrt(3.) / 2. * sl_tri # Height of triangular blocks if self.doMCBlockSearch: best = [0, 0, 0, 0] # Iterates many times to find the best fit for i in range(self.MCBlockIterations): # Random seed point rndpt = (0, np.random.randint(int(-h_tri), 0)) # Make cells around this point upTris, downTris = self.makeBlocks(sl_tri, startpt=rndpt) NTris = (len(upTris) + len(downTris)) if NTris > best[1]: centroidDist = np.array([ tri.centroid.xy for tri in upTris + downTris ]).squeeze().mean(0) centroidDist = np.sqrt(centroidDist[0]**2 + centroidDist[1]**2) # centroidDist = abs(rndpt[1]) best = [rndpt, NTris, (upTris, downTris), centroidDist] elif NTris == best[1]: # Choose the pattern that is most centered on the wafer centroidDist = np.array([ tri.centroid.xy for tri in upTris + downTris ]).squeeze().mean(0) centroidDist = np.sqrt(centroidDist[0]**2 + centroidDist[1]**2) # centroidDist = abs(rndpt[1]) # print centroidDist if centroidDist < best[3]: best = [rndpt, NTris, (upTris, downTris), centroidDist] # print("Current: {:f}, Best {:f}").format(NTris,best[1]) # Choose the best configuration (fits the most cells) self.upTris, self.downTris = best[2] self.blockOffset = best[0] else: self.upTris, self.downTris = self.makeBlocks(sl_tri) self.blockOffset = (0, 0) # Find the centers of the triangles self.upCenters = [next(zip(*tri.centroid.xy)) for tri in self.upTris] self.downCenters = [ next(zip(*tri.centroid.xy)) for tri in self.downTris ] # Shift triangles to be centered around (0,0) offset = np.mean(np.vstack([self.upCenters, self.downCenters]), 0) self.upTris = [ translateshape(tri, xoff=-offset[0], yoff=-offset[1]) for tri in self.upTris ] self.downTris = [ translateshape(tri, xoff=-offset[0], yoff=-offset[1]) for tri in self.downTris ] # Debugging self.plotTriangles(self.downTris + self.upTris) # Find the centers of the triangles self.upCenters = [next(zip(*tri.centroid.xy)) for tri in self.upTris] self.downCenters = [ next(zip(*tri.centroid.xy)) for tri in self.downTris ] # %% sl_lattice = self.trisize + self.block_gap / np.tan(np.deg2rad(30)) h_lattice = np.sqrt(3.) / 2. * sl_lattice base = h_lattice # Create label for each block (taken from templates._placeblocks) # String prefixes to associate with each row/column index x1s, y1s = set(), set() for tri in self.upTris: # In x use centroid as reference, in y use lower bound so up and down triangles give almost the same value x1s.add(np.round(tri.centroid.x, 8)) y1s.add(base * round(float(tri.bounds[1]) / base)) # Create dictionary of up and down triangles self.orientrows = dict( list(zip(y1s, ["up" for i, y in enumerate(y1s)]))) # Create dictionary of up and down triangles x2s, y2s = set(), set() for tri in self.downTris: x2s.add(np.round(tri.centroid.x, 8)) y2s.add(base * round(float(tri.bounds[1]) / base)) self.orientrows.update( dict(list(zip(y2s, ["down" for i, y in enumerate(y2s)])))) x1s.update(x2s) xs = sorted(list(x1s)) self.blockcols = dict( list(zip(xs, [string.ascii_uppercase[i] for i, x in enumerate(xs)]))) y1s.update(y2s) ys = sorted(list(y1s)) self.blockrows = dict(list(zip(ys, [str(i) for i, y in enumerate(ys)])))