def image_to_gds(p: pathlib.Path, layer: int = LayoutDefault.layerTop, *a, **k): try: import nazca as nd except Exception: import subprocess import sys thispath = pathlib.Path(__file__).parent nazcapath = thispath / "addOns" / "nazca" / "nazca-0.5.13.zip" subprocess.check_call([ sys.executable, "-m", "pip", "install", str(nazcapath.absolute()) ]) import nazca as nd nd.image(str(p.absolute()), layer=layer, **k).put(0) nd.export_gds(filename=str(p.parent / p.stem) + '.gds', flat=True)
def _plot(self): nd.Polyline(points=self.points, width=self.width, olayer=self.olayer, layer=self.layer).put() nd.export_gds() return
def generate_gds_from_image(path, **kwargs): import nazca as nd if isinstance(path, pathlib.Path): path = str(path.absolute()) else: path = pathlib.Path(path) cell = nd.image(path, **kwargs).put() path = path.parent / (path.stem + ".gds") nd.export_gds(filename=str(path.absolute())) return path
200) rect_w = num.array([3, 5, 8, 10]) rect_l = 200 rect_a = 10 * (3.0 + num.arange(7)) rect_x = 1.25 * rect_l * (1 + num.arange(rect_a.size)) rect_y = 1.25 * rect_l * num.arange(rect_w.size) rect_structs = place_rects('rectangles', rect_l, rect_w, rect_a, rect_x, rect_y) with nd.Cell(name='resolution_test') as res_test_bb: filename_res = \ 'c:\\users\\micha\documents\\code\\nazca-mask-design\\' + \ 'ms_test_structures\\resolution_test.gds' res_test_bb = nd.load_gds(filename=filename_res, layermap={1: 3}, prefix='res_', newcellname='res_test') res_test_bb = res_test_bb.put(-325, 750) with nd.Cell(name='critical_dimsg') as crit_dims_bb: filename_crit = \ 'c:\\users\\micha\\documents\code\\nazca-mask-design' + \ '\\ms_test_structures\\critical_dimension.gds' crit_dims_bb = nd.load_gds(filename=filename_crit, layermap={1: 3}, newcellname='crit_dim_cell', prefix='dims_') dims_bb = crit_dims_bb.put((-325, 450, 0)) nd.export_gds(filename='ms_test_struct_v2')
def __createWhitePcellLib(gdsin, whitelibrary=None, black2whiteMap=None, prefixb='black_', prefixw='wb_', infolevel=0): """ Create a Pcell library based in cells <gdsin>. Args: gdsin (str): file name of input GDS. gdsout (str): optional file name of output GDS. whitelibrary (str): optional file name of generated white cell GDS library. black2whitemap (dict): mapping black cell names to white cell functions {name: function}. prefixb: blackbox prefix (default = 'black_') prefixw (str): whitebox prefix (default = 'wb_') infolevel (int): amount of debug info printed (default = 0) Returns: str, dict: gds filename of white Pcell library, {black-cellname: white-cellname} """ if whitelibrary is None: timestr = time.strftime("%Y-%m-%d") whitelibrary = "{}_white_lib_{}.gds".format(gdsin[:-4], timestr) # Using the black2whiteMap dictionary: # - create a list of all black cellnames in the map, # - extract their Pcell parameters, # - create a matching list of newly generated white cells using the params. # Note the white cell is (should be) generated with a black cell inside. # Note that the replaced white cells have the same name for the gds ref gdsinstream = nd.GDSII_stream(gdsin) allInputCellNames = gdsinstream.cells.keys() allBlackCellNames = [] allWhiteCells = [] allWhiteCellNames = [] for blackBasename, whiteFunction in black2whiteMap.items(): #print('whiteFunction', blackBasename, whiteFunction, ) if whiteFunction is None: continue cells_x_Params = __readPcellParams(blackBasename, gdsinstream, allInputCellNames, infolevel=infolevel) for cellname, parameters in cells_x_Params.items(): try: whiteCell = whiteFunction(**parameters) allWhiteCells.append(whiteCell) allBlackCellNames.append( cellname ) #inside for loop to sync order of white and black except Exception as error: print("Error in inside white box function or whitbox function call.\n"\ " - can not generate cell '{}'\n"\ " - whitebox function: {}\n"\ " - parameters: {}\n".\ format(cellname, whiteFunction, parameters)) #traceback.print_exc(file=sys.stdout) raise #TODO: add empty/error cell to keep black and white list in sync #if infolevel > 3: # print('\nblackBasename = ', blackBasename) # print('whiteCellparams:\n', allWhiteCells) if infolevel > 3: print("\n{:30}{}".format("allBlackCells", "allWhiteCells")) for base, cell in zip(allBlackCellNames, allWhiteCells): try: print("{:40}{}".format(base, cell.cell_name)) except: print("{:40}{}".format(base, cell)) #generate cell names for all black and white cells allBlackCellNamesOut = [prefixb + name for name in allBlackCellNames] allWhiteCellNames = [cell.cell_name for cell in allWhiteCells] #map input black cellname to output black cellname (for gds debugging). blackmap = { black: newblack for black, newblack in zip(allBlackCellNames, allBlackCellNamesOut) } #map white cellname to black cellname whitemap = { white: black for white, black in zip(allWhiteCellNames, allBlackCellNames) } if infolevel > 1: print('\nMapping for renaming black cells:') pprint(blackmap) print( '\nMapping to copy white cellnames to original (black) gdsin cellnames:' ) pprint(whitemap) #print('\n') #Export all white cells into the <whitelibrary> gds file nd.export_gds(allWhiteCells, filename=whitelibrary) # rename black cells: g = nd.GDSII_stream(whitelibrary, cellmap=blackmap) g.GDSII_write(whitelibrary) # rename white cells into original black cell names: #g = nd.GDSII_stream(whitelibrary, cellmap=whitemap) #g.GDSII_write(whitelibrary) #white to black cell name map: b2w = dict(zip(allBlackCellNames, allWhiteCellNames)) return whitelibrary, b2w
ic1.bend(radius=20, angle=45).put() y3 = yjunction().put() ic1.bend(angle=-45, radius=20).put(y2.pin['b0']) ic1.taper(width1=w_1, width2=w_2, length=t_len).put() o1 = ic1.strt(length=5, width=w_2).put() ic1.bend(angle=45, radius=20).put(y2.pin['b1']) ic1.taper(width1=w_1, width2=w_2, length=t_len).put() o2 = ic1.strt(length=5, width=w_2).put() ic1.bend(angle=-45, radius=20).put(y3.pin['b0']) ic1.taper(width1=w_1, width2=w_2, length=t_len).put() o3 = ic1.strt(length=5, width=w_2).put() ic1.bend(angle=45, radius=20).put(y3.pin['b1']) ic1.taper(width1=w_1, width2=w_2, length=t_len).put() o4 = ic1.strt(length=5, width=w_2).put() taperdown = dha(name='taper down', layer=1, olayer=2, owidth=w_trench) taperdown.strt(length=5) taperdown.taper(length=t_len, width1=w_2, width2=w_1) taperdown.strt(length=100) t = taperdown.getcell() t.put(o1.pin['b0'].move(-5)) t.put(o2.pin['b0'].move(-5)) t.put(o3.pin['b0'].move(-5)) t.put(o4.pin['b0'].move(-5)) nd.export_gds(filename='testchip.gds')
nd.bend(angle=da*0.5,radius=10000,width=w).put() nd.strt(length=l,width=w).put() #nd.bend(angle=da,radius=((10000-12*pitch)/2).put() #nd.bend(angle=da,radius=((10000-12*pitch-pitch)/2).put() #nd.bend(angle=ua,radius=((10000-12*pitch-pitch)/2).put() #cleave mark nd.strt(length=300,width=8000).put(0,0) nd.strt(length=300,width=8000).put(25.4*4*1000-5000,0) nd.strt(length=300,width=15000).put(15000,15000/2) nd.strt(length=300,width=15000).put(wafer-15000,15000/2) #nd.text('15000',height=500).put(wafer-15000, 0) #nd.text('wafer-15000',height=500).put(15000, 0) nd.strt(length=300,width=15000).put(15000,-15000/2-4500) nd.strt(length=300,width=15000).put(wafer-15000,-15000/2-4500) #nd.text('XL',height=5000).put(48000, 20000) #nd.text('L',height=5000).put(43000, 3000) #nd.text('M',height=4000).put(35000, -12500) #nd.text('S',height=4000).put(65500, -9000) #nd.text('XS',height=4000).put(73000, 7400) # nd.bend(angle=360,radius=25.4*1000*2,layer=2,width=w).put(25.4*1000*2,-25.4*1000*2) nd.export_gds()
yj = split1_2_4_8().put(0,y4) a.put(yj.pin['b0']) a.put(yj.pin['b1']) a.put(yj.pin['b2']) a.put(yj.pin['b3']) a.put(yj.pin['b4']) a.put(yj.pin['b5']) a.put(yj.pin['b6']) a.put(yj.pin['b7']) split1_2_4_8(taper_in=False).put(12000,y4, flop=True) y4 += 500 yj = split1_2_4_8(taper_in= False).put(0,y4) a.put(yj.pin['b0']) a.put(yj.pin['b1']) a.put(yj.pin['b2']) a.put(yj.pin['b3']) a.put(yj.pin['b4']) a.put(yj.pin['b5']) a.put(yj.pin['b6']) a.put(yj.pin['b7']) split1_2_4_8(taper_in= True).put(12000,y4, flop=True) nd.export_gds(filename='testchip2.gds', flat=True)
n * 50 - 20 * 1000) n = n + 1 nd.text('XL', height=5000).put(48000, 20000) # dose 1200mj/cm2 n = 0 while n < 10: nd.strt(length=25.4 * 2 * 1000, width=w).put(25.4 * 1000, n * 50 - 30 * 1000) n = n + 1 nd.text('XL', height=5000).put(48000, 20000) # dose 1400mj/cm2 n = 0 while n < 10: nd.strt(length=25.4 * 2 * 1000, width=w).put(25.4 * 1000, n * 50 - 40 * 1000) n = n + 1 nd.text('XL', height=5000).put(48000, 20000) # dose 1400mj/cm2 n = 0 while n < 10: nd.strt(length=25.4 * 2 * 1000, width=w).put(25.4 * 1000, n * 50 - 30 * 1000) n = n + 1 nd.text('XL', height=5000).put(48000, 20000) nd.export_gds(filename='dose_test.gds')
path_structure.strt(length=20) path_structure.arc(angle=90, radius=20) path_structure.eulerbend(p=0.2, angle=-90, radius=20) path_structure.taper(width1=0.5, width2=5, length=50) path_structure.strt(length=10) path_structure.taper(width1=5, width2=0.5, length=20) # to place the structure, get the cell with the getcell() method, then place that using the cells put() method # cells can also be place multiple places with specified position cell = path_structure.getcell() cell.put() cell.put(0, -50) #export to GDS nd.export_gds(filename='dha_elements_usage_example_1.gds') # for repeated structures with varying parameters, it is maybe better to define the cell in a function: def parametrized_cell(w1, w2, bend_radius, length1, length2, trenchwidth=5): name = 'parametrized cell with taper lenght = ' + str(length2) p = dha(name=name, layer=1, olayer=2, width=w1, owidth=trenchwidth) p.strt(length=length1) p.taper(width1=w1, width2=w2, length=length2) p.eulerbend(radius=bend_radius, angle=90) p.taper(width1=w2, width2=w1, length=length2) p.strt(length=length1) cell = p.getcell() return cell
def angle_drc(cell, rules=None, basename=None, version_layer=None): """Apply intantiation DRC rules to cell hierarchy and scan for black boxes. The format of angle DRC rules: rule_dict = { 'angle': <cell_basename>: 'noflip': # optional level if flip state has to be False 'values': <list of allowed angles> 'domain': <list allowed domains> 'flip': # optional level if flip state has to be True 'values': <list of allowed angles> 'domain': <list allowed domains>111 } Example:: somerules = { 'laser': 'angle': 'values': [0, 180] 'wild_bb': 'noflip': 'domains: [[25, 50], [140, 260]] 'flip': 'values': [0] 'domains': [[150, 210]] } instance_drc(rules=somerules, cell=<your Cell>) Args: rules (dict): drc rules for instantiation cell (Cell): cell (and subcells) to rundrc on version_layer (layer): layer containing the cell's version annotation Returns: Cell: cell with angle DRC result to overlay with the gds design. """ global cnt, drclog, items if basename is None: basename = "{}".format(cell.cell_name) if rules is None: rules = nd.cfg.drc_instance_angle if version_layer is None: nd.logger.warning( 'version layer missing. Will not create a black box overview.') else: version_layer = nd.get_layer(version_layer) cnt = 0 #drclogname = os.path.join(basename+'.'+drc_filename) #drclog = open(drclogname, 'w') #drclog.write("DRC on cell: {}\n".format(cell.cell_name)) now = datetime.datetime.now() #drclog.write('datetime: {}\n'.format(now.strftime("%Y-%m-%d %H:%M"))) # Get instance info from topcell down. positions = [] for params in nd.cell_iter(cell, flat=True, infolevel=0): if params.cell_start: # 1. detect black box (besides DRC check): version = '' for anno, pos in params.iters['annotation']: if anno.layer == version_layer: version = anno.text # TODO: what if multiple annotations exist? # 2. store position for DRC and possible version: positions.append((params.cell.cell_basename, params.cell.cell_name, params.transflip_glob, version)) # cellname order needs to be reverse-ordered match the longest possible base name first: cell_rules_angle = OrderedDict(sorted(rules['angle'].items(), reverse=True)) for cellbasename, name, (trans, flip), version in positions: x, y, a = trans.xya() if version != '': blocks.append((cellbasename, version)) for bb, rules in cell_rules_angle.items(): if name.startswith(bb): angle_rules_flip = rules.get('flip', None) angle_rules_noflip = rules.get('noflip', None) if angle_rules_flip is not None and flip: drc_angle(name, rules=angle_rules_flip, flip_state=True, xya=[x, y, a], flip=flip) elif angle_rules_noflip is not None and not flip: drc_angle(name, rules=angle_rules_noflip, flip_state=False, xya=[x, y, a], flip=flip) elif flip and angle_rules_flip is None and angle_rules_noflip is not None: cnt += 1 msg = " flip=True not allowed\n" items.append((cnt, name, [x, y, a], flip, msg)) msg = "#{} ERROR cell '{}' @ ({:.3f}, {:.3f}, {:.3f}), flip={}\n{}".\ format(str(cnt).zfill(4), name, x, y, a, flip, msg) #drclog.write(msg) nd.logger.error(msg) elif not flip and angle_rules_noflip is None and angle_rules_flip is not None: cnt += 1 msg = " flip=False not allowed\n" items.append((cnt, name, [x, y, a], flip, msg)) msg = "#{} ERROR cell '{}' @ ({:.3f}, {:.3f}, {:.3f}), flip={}\n{}".\ format(str(cnt).zfill(4), name, x, y, a, flip, msg) #drclog.write(msg) nd.logger.error(msg) elif rules != {}: drc_angle(name, rules=rules, flip_state=None, xya=[x, y, a], flip=flip) break # only the first hit (longest match of a cell in reversed ordered bb is the match nd.logger.info("angle violation items found: {}".format(cnt)) #drclog.write("items found: {}".format(cnt)) #drclog.close() #nd.logger.info("exported {}".format(drclogname)) # Save DRC results as cells to gds to load on top of the design with nd.Cell('{}_drc'.format(cell.cell_name)) as DRC: for i in items: with nd.Cell(str(i[0]).zfill(4)) as C: bbox = nd.cfg.cellnames[i[1]].bbox points = [(bbox[0], bbox[1]), (bbox[0], bbox[3]), (bbox[2], bbox[3]), (bbox[2], bbox[1])] #print(i[1], i[2], flip, points) #print(i) nd.Polygon(points=points, layer=nd.cfg.drc_layer_instance_angle).put( 0) # put(*i[2], flop=i[3]) C.put(*i[2], flip=i[3]) gdsname = os.path.join(basename + '.drc.gds') nd.export_gds(DRC, filename=gdsname, clear=False) # Save manifest if version_layer is not None: countBBs = Counter(blocks) bblistname = os.path.join(basename + '.' + blocklist_filename) F = open(bblistname, 'w') F.write('#datetime: {}\n'.format(now.strftime("%Y-%m-%d %H:%M"))) L, D, T = nd.cfg.layername2LDT[version_layer] F.write("#version_layer: ({}, {})\n".format(L, D)) F.write("{:6} block_info\n".format('#units')) for bb in sorted(countBBs.keys()): F.write("{:6} {}\n".format(countBBs[bb], bb)) F.close() nd.logger.info("exported {}".format(bblistname)) return DRC