def __init__(self, name, cells, size, edge_gap=0, prefix=''): Cell.__init__(self, name) size=np.asarray(size) cell_layers=set() for c in cells: cell_layers |= set(c.get_layers()) cell_layers=list(cell_layers) d_layers=cell_layers #Create alignment marks styles=['A' if i%2 else 'C' for i in range(len(d_layers))] am = AlignmentMarks(styles, d_layers) ver = Verniers(styles, d_layers) for e in ver.elements: e.translate((310,-150)) am.add(e) am_bbox=am.bounding_box am_size=np.array([am_bbox[1,0]-am_bbox[0,0], am_bbox[1,1]-am_bbox[0,1]]) sp=size - am_size - edge_gap self.add(CellArray(am, 2, 1, sp, -am_bbox[0]+0.5*edge_gap)) #Create text for l in d_layers: text=Label(prefix+cells[0].name, 150, (am_size[0]+edge_gap, +edge_gap), layer=l) self.add(text) bbox=text.bounding_box t_width = bbox[1,0]-bbox[0,0] #Pattern reference cells spacings, corners, widths=[],[],[] for c in cells: bbox=c.bounding_box corners.append(bbox[0]) bbox = np.array([bbox[1][0]-bbox[0][0], bbox[1][1]-bbox[0][1]]) spacings.append(bbox*1.5) widths.append((bbox*1.5)[0]) self.N=0 origin = edge_gap * np.array([1,1]) n_cols=_divide_cols(size[0]-2*edge_gap, widths) for (c, w, n, s, cr) in zip(cells, widths, n_cols, spacings, corners): if ((origin[0]-cr[0])<(am_size[0]+t_width)) or ((origin[0]+n*s[0]) > (size[0]-am_size[0])): origin[1]=am_size[1]+edge_gap height=size[1]-2*edge_gap-am_size[1] else: origin[1]=edge_gap height=size[1]-2*edge_gap rows=np.floor(height/s[1]) ar=CellArray(c, n, rows, s, origin-cr) self.add(ar) self.N+=rows*n origin += s[0] * n *np.array([1,0])
def __init__(self, name, cells=None, block_gap=400): Cell.__init__(self, name) self.cells=cells self.cell_layers=self._cell_layers() self._label=None self.edge_gap=block_gap/2.
def add_wafer_outline(self): """ Create Wafer Outline """ outline=Cell('WAF_OLINE') for l in self.cell_layers: circ=Circle((0, 0), self.wafer_r, 100, layer=l) outline.add(circ) # outline.add(Disk(l, (0,0), self.wafer_r, self.wafer_r-10)) self.add(outline)
def add_orientation_text(self): """ Create Orientation Label """ tblock = Cell('WAF_ORI_TEXT') for l in self.cell_layers: for (t, pt) in self.o_text.iteritems(): txt=Label(t, 1000, layer=l) bbox=txt.bounding_box width=np.array([1,0]) * (bbox[1,0]-bbox[0,0]) offset=width * (-1 if pt[0]<0 else 0) txt.translate(np.array(pt) + offset) tblock.add(txt) self.add(tblock)
def AlignmentMarks(styles, layers=1): """ Create alignment marks. :param styles: a character, or a seq of characters indicating the style of mark(s) desired :param layers: an integer or a list of integers of layer(s) on which to place the mark of the corresponding entry in ``styles`` :returns: A cell with the requested marks Example:: # Make matching marks on layers 1 and 2 AlignmentMarks(('A', 'C'), (1,2)) The marks are stored in the file CONTACTALIGN.GDS A:(layer1): 300 x 300 um B:(layer2): C:(layer3): 600x400um """ if isinstance(styles, numbers.Number): styles=[styles] if isinstance(layers, numbers.Number): layers=[layers]*len(styles) else: if len(layers)!=len(styles): raise ValueError('Styles and layers must have same length.') styles_dict={'A':1, 'B':2, 'C':3} cell=Cell('CONT_ALGN') path,_=os.path.split(__file__) fname=os.path.join(path, 'resources', 'ALIGNMENT.GDS') imp=GdsImport(fname) for (s,l) in zip(styles, layers): style=styles_dict[s] for e in imp['CONTACTALIGN'].elements: if e.layer==style: new_e=e.copy() new_e.layer=l cell.add(new_e) return cell
def Verniers(styles, layers=1): """ Create vernier alignment tools. :param styles: a character 'A' or 'B', or a list of characters indicating the style of mark(s) desired :param layers: an integer or a list of integers of layer(s) on which to place the mark of the corresponding entry in ``styles`` :returns: A cell with the requested marks Example:: #Make a pair of matching verniers on layers 1 and 2 ver = Verniers(('A', 'B'), (1,2)) The marks are stored in the file VERNIERS.GDS 215 x 203 um """ if isinstance(styles, numbers.Number): styles=[styles] if isinstance(layers, numbers.Number): layers=[layers]*len(styles) else: if len(layers)!=len(styles): raise ValueError('Styles and layers must have same length.') styles_dict={'A':1, 'B':2, 'C':2} cell=Cell('VERNIERS') path,_=os.path.split(__file__) fname=os.path.join(path, 'resources', 'ALIGNMENT.GDS') imp=GdsImport(fname) for (s,l) in zip(styles, layers): style=styles_dict[s] for e in imp['VERNIERS'].elements: if e.layer==style: new_e=e.copy() new_e.layer=l cell.add(new_e) return cell
def add_aligment_marks(self): """ Create alignment marks on all active layers """ d_layers=self.cell_layers styles=['A' if i%2 else 'C' for i in range(len(d_layers))] am = AlignmentMarks(styles, d_layers) ver = Verniers(styles, d_layers) mag = 10. mblock = Cell('WAF_ALGN_BLKS') mblock.add(am, magnification=mag) mblock.add(am, origin=(2300, -870)) mblock.add(ver, origin=(1700, -1500), magnification=3) mblock.add(ver, origin=(2000, -1200)) mblock.add(ver, origin=(2500, -1200)) for pt in self.align_pts: offset=np.array([3000, 2000]) * np.sign(pt) self.add(mblock, origin=pt + offset)
def add_label(self, label): """ Create a label """ if self._label is None: self._label=Cell(self.name+'_LBL') self.add(self._label) else: self._label.elements=[] for l in self._cell_layers(): txt=Label(label, 1000, layer=l) bbox=txt.bounding_box offset=np.array([0,2]) * self.block_size - bbox[0] + 200 txt.translate(offset) self._label.add(txt)
def add_dicing_marks(self): """ Create dicing marks """ width=100./2 r=self.wafer_r rng=np.floor(self.wafer_r/self.block_size).astype(int) dmarks=Cell('DIC_MRKS') for l in self.cell_layers: for x in np.arange(-rng[0], rng[0]+1)*self.block_size[0]: y=np.sqrt(r**2-x**2) vm=Rectangle((x-width, y), (x+width, -y), layer=l) dmarks.add(vm) for y in np.arange(-rng[1], rng[1]+1)*self.block_size[1]: x=np.sqrt(r**2-y**2) hm=Rectangle((x, y-width), (-x, y+width), layer=l) dmarks.add(hm) self.add(dmarks)
def __init__(self, name, cell, size, spacing=None, edge_gap=0, prefix=''): Cell.__init__(self, name) size=np.asarray(size) cell_layers=cell.get_layers() d_layers=cell_layers #Create alignment marks styles=['A' if i%2 else 'C' for i in range(len(d_layers))] am = AlignmentMarks(styles, d_layers) ver = Verniers(styles, d_layers) for e in ver.elements: e.translate((310,-150)) am.add(e) am_bbox = am.bounding_box am_size = am_bbox[1]-am_bbox[0] sp = size - am_size - edge_gap self.add(CellArray(am, 2, 1, sp, -am_bbox[0]+0.5*edge_gap)) #Create text for l in d_layers: text=Label(prefix+cell.name, 150, (am_size[0]+edge_gap, +edge_gap), layer=l) bbox=text.bounding_box t_width = bbox[1,0]-bbox[0,0] self.add(text) bbox = cell.bounding_box corner=bbox[0] bbox = bbox[1]-bbox[0] #Pattern reference cell if spacing is None: spacing= bbox*(1.5) self.N=0 # upper area cols=np.floor((size[0]-2*edge_gap + spacing[0])/spacing[0]) rows=np.floor((size[1]-am_size[1]-2*edge_gap)/spacing[1]) origin = np.ceil((am_size[1])/spacing[1])\ * spacing * np.array([0,1]) + edge_gap - corner ar=CellArray(cell, cols, rows, spacing, origin) self.add(ar) self.N+=rows*cols # lower area cols=np.floor((size[0]-2*am_size[0]-t_width-2*edge_gap)/spacing[0]) rows=np.ceil(am_size[1]/spacing[1]) origin = np.ceil((am_size[0]+t_width)/spacing[0])\ * spacing * np.array([1,0]) + edge_gap - corner ar=CellArray(cell, cols, rows, spacing, origin) self.add(ar) self.N+=rows*cols
class Wafer_GridStyle(Cell): """ The base wafer style consisting of blocks of patterned features. :param name: The name of the new wafer cell :param cells: a list of cells that will be tiled to fill the blocks the cells will be cycled until all blocks are filled. :block_gap: the distance to leave between blocks :returns: A new wafer ``Cell`` Spacing between cells in a block is determined automatically based on the cell bounding box, or by using the attribute cell.spacing if it is available. """ #wafer radius (in um) wafer_r = None #the block size in um block_size = None #the placement of the wafer alignment points align_pts = None def __init__(self, name, cells=None, block_gap=400): Cell.__init__(self, name) self.cells=cells self.cell_layers=self._cell_layers() self._label=None self.edge_gap=block_gap/2. def _cell_layers(self): """ A list of all active layers in ``cells`` """ cell_layers=set() for c in self.cells: if isinstance(c, Cell): cell_layers |= set(c.get_layers()) else: for s in c: cell_layers |= set(s.get_layers()) return list(cell_layers) def add_aligment_marks(self): """ Create alignment marks on all active layers """ d_layers=self.cell_layers styles=['A' if i%2 else 'C' for i in range(len(d_layers))] am = AlignmentMarks(styles, d_layers) ver = Verniers(styles, d_layers) mag = 10. mblock = Cell('WAF_ALGN_BLKS') mblock.add(am, magnification=mag) mblock.add(am, origin=(2300, -870)) mblock.add(ver, origin=(1700, -1500), magnification=3) mblock.add(ver, origin=(2000, -1200)) mblock.add(ver, origin=(2500, -1200)) for pt in self.align_pts: offset=np.array([3000, 2000]) * np.sign(pt) self.add(mblock, origin=pt + offset) def add_orientation_text(self): """ Create Orientation Label """ tblock = Cell('WAF_ORI_TEXT') for l in self.cell_layers: for (t, pt) in self.o_text.iteritems(): txt=Label(t, 1000, layer=l) bbox=txt.bounding_box width=np.array([1,0]) * (bbox[1,0]-bbox[0,0]) offset=width * (-1 if pt[0]<0 else 0) txt.translate(np.array(pt) + offset) tblock.add(txt) self.add(tblock) def add_dicing_marks(self): """ Create dicing marks """ width=100./2 r=self.wafer_r rng=np.floor(self.wafer_r/self.block_size).astype(int) dmarks=Cell('DIC_MRKS') for l in self.cell_layers: for x in np.arange(-rng[0], rng[0]+1)*self.block_size[0]: y=np.sqrt(r**2-x**2) vm=Rectangle((x-width, y), (x+width, -y), layer=l) dmarks.add(vm) for y in np.arange(-rng[1], rng[1]+1)*self.block_size[1]: x=np.sqrt(r**2-y**2) hm=Rectangle((x, y-width), (-x, y+width), layer=l) dmarks.add(hm) self.add(dmarks) def add_wafer_outline(self): """ Create Wafer Outline """ outline=Cell('WAF_OLINE') for l in self.cell_layers: circ=Circle((0, 0), self.wafer_r, 100, layer=l) outline.add(circ) # outline.add(Disk(l, (0,0), self.wafer_r, self.wafer_r-10)) self.add(outline) def add_blocks(self): """ Create blocks and add them to he wafer Cell """ self.manifest='' for (i, pt) in enumerate(self.block_pts): cell=self.cells[i % len(self.cells)] origin = pt*self.block_size prefix=self.blockcols[pt[0]]+self.blockrows[pt[1]] if isinstance(cell, Cell): cell_name=prefix+cell.name try: spacing = cell.spacing except AttributeError: spacing = None block=Block(cell_name, cell, self.block_size, edge_gap=self.edge_gap, prefix=prefix+'_', spacing = spacing) self.manifest+='%2d\t%s\t%s\t(%.2f, %.2f)\n' % ((i, prefix, cell.name)+tuple(origin)) else: cell_name=prefix + cell[0].name block=RangeBlock_1D(cell_name, cell, self.block_size, edge_gap=self.edge_gap, prefix=prefix+'_') self.manifest+='%2d\t%s\t%s\t(%.2f, %.2f)\n' % ((i, prefix, cell[0].name)+tuple(origin)) self.add(block, origin=origin) def _place_blocks(self): """ Create the list of valid block sites based on block size and wafer diam. """ ind_max=np.floor(self.wafer_r/self.block_size).astype(int) self.block_pts=[] for x in range(-ind_max[0], ind_max[0]): for y in range(-ind_max[1], ind_max[1]): origin=np.array([x,y]) flag=True for corner in np.array([[0,0], [1,0], [1,1], [0,1]]): lsq=(((origin+corner)*self.block_size)**2).sum() if lsq > self.wafer_r**2: flag=False break if flag: self.block_pts.append([x,y]) #String prefixes to associate with each row/column index xs, ys=set(), set() for p in self.block_pts: xs.add(p[0]) ys.add(p[1]) xs=sorted(list(xs)) self.blockcols=dict(zip(xs, [string.uppercase[i] for i,x in enumerate(xs)])) ys=sorted(list(ys)) self.blockrows=dict(zip(ys, [string.digits[i] for i,y in enumerate(ys)])) def add_label(self, label): """ Create a label """ if self._label is None: self._label=Cell(self.name+'_LBL') self.add(self._label) else: self._label.elements=[] for l in self._cell_layers(): txt=Label(label, 1000, layer=l) bbox=txt.bounding_box offset=np.array([0,2]) * self.block_size - bbox[0] + 200 txt.translate(offset) self._label.add(txt)