def watch(self,dark = False): #Gerhards color scheme here :D, dark and smooth colours bkg = '#2C2A4A' colour = {} c_list = ['#DABFFF','#D5A021','#95B2B0','#7FDEFF','#D3BDB0','#89937C','#EAE2B7','#EDA4BD','#A0ACAD','#C8D6AF','#95B2B0','#BA274A','#2191FB','#FCB0B3','#CE7DA5','#CFFFB0','#907AD6','#A44200'] for i in range(18): colour[(i,0)] = c_list[i] if dark: gdspy.LayoutViewer(depth=0, pattern={'default': 8}, background=bkg,color=colour) # this opens a viewer else: gdspy.LayoutViewer(depth=0, pattern={'default': 8}, background='#FFFFFF')
def makeFile(filename, parts): lib = gdspy.GdsLibrary() cell = lib.new_cell('cell') cell.add(parts) cell.add(gdspy.Label('origin', [0, 0])) lib.write_gds(filename) gdspy.LayoutViewer()
def _example(): file_path = './layout/Combinenation_SiO2.gds' origin = (100, 100) loadedcell = new_import.import_gds(file_path, origin, 'GC_a230_0_0') lib = gdspy.GdsLibrary(name='GC', precision=1e-10) device = lib.new_cell('loadedCell') device.add(loadedcell) gdspy.LayoutViewer(lib)
def generate_gds_file(layout_path, cellname): print(os.popen("mkdir -p " + layout_path + "/gds").read()) print( os.popen("magic -Tscmos.tech -dnull -noconsole << EOF" + get_gds_magic_script(layout_path, cellname) + "EOF").read()) gdsii = gdspy.GdsLibrary() gdsii.read_gds(layout_path + "/gds/" + cellname + ".gds") cell = gdsii.extract(cellname) cell = cell.flatten() bb = cell.get_bounding_box() if '-st' in sys.argv: gdspy.LayoutViewer(cells=cellname) try: p11 = bb[0] - [orig_box_width, orig_box_width ] - [orig_box_spacing, orig_box_spacing] p12 = bb[0] - [orig_box_spacing, orig_box_spacing] p21 = bb[1] + [orig_box_spacing, orig_box_spacing] p22 = bb[1] + [orig_box_spacing, orig_box_spacing ] + [orig_box_width, orig_box_width] cell = cell.add(gdspy.Rectangle(p11, p12, 1)) cell = cell.add(gdspy.Rectangle(p21, p22, 1)) cell = cell.flatten() for layername in layer_mapping: ncell = cell.copy(layername, deep_copy=True) for idx in ncell.get_layers(): if not idx in layer_mapping[layername]: ncell = ncell.remove_polygons( lambda pts, layer, datatype: layer == idx) ncell = ncell.add(gdspy.Rectangle(p11, p12, 1)) ncell = ncell.add(gdspy.Rectangle(p21, p22, 1)) ncell = ncell.flatten(single_layer=1, single_datatype=1) newgdsii = gdspy.GdsLibrary("mask_" + layername) newgdsii.add(ncell) newgdsii.write_gds(layout_path + "/gds/mask_" + layername + ".gds") except Exception as e: print("Can't do this:" + e) if '-s' in sys.argv: gdspy.LayoutViewer()
def generate_hall_bar_array(title, width_list, length_xx_list, dx, dy, orientation=0, leg_type='default'): """ Generates a gdspy cell populated with single nanowires with the specified parameters :param title: str. Also filename :param width_list: list of floats. In um :param length_xx_list: list of floats. In um :param dx: float. Distance in um between neighboring structures :param dy: float. Distance in um between neighboring structures :param orientation: float in degrees. 0deg is horizontal. :param leg_type: {'fishbone', 'default'} :return: gdspy viewer """ cell = gdspy.Cell(title) tools.make_title(title, cell, y=2 * dy, text_size=20) for i, w in enumerate(width_list): for j, L in enumerate(length_xx_list): wire_list = [] # will contain a wire and eventually labels, SmartWalls... x = j * dx y = - i * dy # labels if y == 0: x_label = 'L_xx=' + str(L) tools.make_x_label(x_label, wire_list, y=dy) if x == 0: y_label = 'w=' + str(int(w * 1000)) + 'nm\n' tools.make_y_label(y_label, wire_list, x=-dx) length_S_to_junction = 1.5 length_total = L + 2 * length_S_to_junction length_leg = 1 if j % 2 == 0: reservoir_enable = True else: reservoir_enable = False struct = tools.modified_hall_bar(w, length_total=length_total, length_leg=length_leg, length_xx=L, leg_offset=0, orientation=orientation, leg_type=leg_type, reservoir_enable=reservoir_enable) wire_list.append(struct) tools.add_label('X{}Y{}'.format(str(j), str(i)), wire_list, text_size=2, layer=20) # adds a number label to the wire_cell # tools.add_label('W{}L{}X{}Y{}'.format(str(int(w*1000)), str(L), str(j), str(i)), wire_list, text_size=2) # adds a number label to the wire_cell tools.move_list(wire_list, x, y) # translates the entire wire_cell cell.add(wire_list) gdspy.write_gds(os.path.join(pattern_directory, title + '.gds'), cells=[cell], unit=1.0e-6, precision=1e-11) # 1um unit, 1e-11 precision allows total cell area up to ~20mm*20mm return gdspy.LayoutViewer(cells=[cell])
def output(self, name=None, path='current'): """ Plot the cell or library using gdspy viewer. """ glib = gdspy.GdsLibrary(name=self.name) if isinstance(self, spira.Library): glib = settings.get_library() glib += self glib.to_gdspy elif isinstance(self, spira.Cell): self.construct_gdspy_tree(glib) gdspy.LayoutViewer(library=glib)
def generate_2d_array(title, x_labels, y_labels, unit_function, arg_2d_list, dx=40, dy=40, preview=False): """ Generates a 2D array of patterns with unique identifiers, a title, a column of labels on the left and a row of labels on top :param title: string, also filename :param x_labels: list of strings, each is the label for a column :param y_labels: list of strings, each is the label for a row :param unit_function: a function that takes each args tuple as parameters and returns a gdspy shape :param dx: float, x distance in um :param dy: float, y distance in um :return: writes a .gds file and launches the gdspy layout viewer """ if len(x_labels) != len(arg_2d_list[0]) or len(y_labels) != len(arg_2d_list): print('Check dimensions of arg_2d_list and x/y_labels!') raise ValueError cell = gdspy.Cell(title) tools.make_title(title, cell, y=2 * dy, text_size=20) for y_count, arg_1d_list in enumerate(arg_2d_list): for x_count, args in enumerate(arg_1d_list): x = x_count * dx y = -y_count * dy wire_cell = [] # will contain a wire and eventually labels, SmartWalls... # labels if y == 0: x_label = x_labels[x_count] tools.make_x_label(x_label, wire_cell, y=dy, text_size=5) if x == 0: y_label = y_labels[y_count] tools.make_y_label(y_label, wire_cell, x=-dx/2, y=dy/2, text_size=4) wire_shape = unit_function(**args) if type(wire_shape) == tuple: for single_shape in wire_shape: wire_cell.append(single_shape) else: wire_cell.append(wire_shape) if x_count != 0: # left most row can be labeled by the big X labels tools.add_label('X{}Y{}'.format(str(x_count), str(y_count)), wire_cell, x=-dx/2, y=dy/2, text_size=2, layer=11) # adds a number label to the wire_cell tools.move_list(wire_cell, x, y) # translates the entire wire_cell cell.add(wire_cell) gdspy.write_gds(os.path.join(pattern_directory, title + '.gds'), cells=[cell], unit=1.0e-6, precision=1e-11) # 1um unit, 1e-11 precision allows total cell area up to ~20mm*20mm if preview: return gdspy.LayoutViewer(cells=[cell])
def gds(self, filename=None, view=False, extra=0, units='nms'): #check to make sure the geometry isn't an array if len(self.clean_args(None)[0]) != 1: raise ValueError( "You have changing geometries, making gds doesn't make sense") if units == 'nms': scale = 1 elif units == 'microns': scale = 10**-3 else: raise ValueError('Invalid units') #scale to proper units sc_radius = self.radius * scale sc_gap = self.gap * scale sc_width = self.width * scale sc_length = self.length * scale #write to GDS pathTop = gdspy.Path(sc_width, (sc_radius + sc_length / 2, sc_radius + sc_width / 2 + sc_gap / 2 + extra)) pathTop.segment(extra, '-y') pathTop.arc(sc_radius, 0, -np.pi / 2) pathTop.segment(sc_length, '-x') pathTop.arc(sc_radius, -np.pi / 2, -np.pi) pathTop.segment(extra, '+y') pathBottom = gdspy.Path(sc_width, (-sc_radius - sc_width / 2 - sc_length / 2 - extra, -sc_gap / 2 - sc_width / 2)) pathBottom.segment( 2 * (sc_radius + sc_width / 2) + sc_length + 2 * extra, '+x') gdspy.current_library = gdspy.GdsLibrary() path_cell = gdspy.Cell('C0') path_cell.add(pathTop) path_cell.add(pathBottom) if view: gdspy.LayoutViewer(cells='C0') if filename is not None: writer = gdspy.GdsWriter(filename, unit=1.0e-6, precision=1.0e-9) writer.write_cell(path_cell) writer.close()
def bitmarker_2inch(): dx = 20 dy = 20 # text_size = 100 nrows = 32 ncols = 32 output_dir = r'/Users/wgz/Downloads' title = 'BitmarkerArray' cell = gp.Cell(title) for x in range(ncols): for y in range(nrows): # x_label = string.ascii_uppercase[x] # y_label = str(y) # shape = gp.Text(x_label+y_label, text_size, position=(x*dx, -y*dy), layer=10) shape = tools.bitmarker(x, y) shape.translate(x*dx, -y*dy) cell.add(shape) gp.LayoutViewer(cells=[cell]) gp.write_gds(os.path.join(output_dir, title + '.gds'), cells=[cell], unit=1.0e-6, precision=1e-10)
def gds(self, filename=None, extra=0, units='microns', view=False): """Writes the geometry to the gds file Args: filename (str): location to save file to, or if you don't want to defaults to None extra (int): extra straight portion to add to ends of waveguides to make room in simulation (input with units same as units input) units (str): either 'microns' or 'nms'. Units to save gds file in """ #check to make sure the geometry isn't an array if len(self.clean_args(None)[0]) != 1: raise ValueError( "You have changing geometries, making gds doesn't make sense") if units == 'nms': scale = 1 elif units == 'microns': scale = 10**-3 else: raise ValueError('Invalid units') #scale to proper units sc_width = self.width * scale sc_length = self.length * scale #write to GDS path = gdspy.Path(sc_width, (-sc_length / 2 - extra, 0)) path.segment(2 * extra + sc_length, '+x') gdspy.current_library = gdspy.GdsLibrary() path_cell = gdspy.Cell('C0') path_cell.add(path) if view: gdspy.LayoutViewer(cells='C0') if filename is not None: writer = gdspy.GdsWriter(filename, unit=1.0e-6, precision=1.0e-9) writer.write_cell(path_cell) writer.close()
def check(device: Device, joined=False, blocking=True, gds=False): ''' Shows the device layout. If run by terminal, blocks script until window is closed. Parameters ---------- device : phidl.Device joined : boolean (optional, default False) if true, returns a flattened/joined version of device gds : boolean if true, view in gdspy viewer ''' set_quickplot_options(blocking=blocking) if joined: cell = join(device) else: cell = device if gds: lib = gdspy.GdsLibrary() gcell = lib.new_cell("Output") gcell.add(cell) gdspy.LayoutViewer(lib) else: qp(cell)
def gdsii_output(self, name=None, view_type='hierarchical', disabled_ports=None, view=True): _default = {'cells': True, 'polygons': True, 'arrows': True, 'labels': True} # _default = {'cells': True, 'polygons': False, 'arrows': False, 'labels': False} if disabled_ports is not None: _default.update(disabled_ports) G = OutputGdsii(cell=self, view_type=view_type, disabled_ports=_default) gdspy_library = gdspy.GdsLibrary(name=self.name) G.gdspy_gdsii_output(gdspy_library) if name is not None: writer = gdspy.GdsWriter('{}.gds'.format(name), unit=1.0e-6, precision=1.0e-12) for name, cell in gdspy_library.cell_dict.items(): writer.write_cell(cell) del cell writer.close() if view is True: gdspy.LayoutViewer(library=gdspy_library)
def start_viewer(self): import gdspy gdspy.LayoutViewer(library=self.get_gdspy_lib(), depth=10)
if __name__ == "__main__": from . import * top = gdspy.Cell("top") wgt_strip = WaveguideTemplate(bend_radius=50, wg_type="strip", wg_width=0.7) wgt_slot = WaveguideTemplate(bend_radius=50, wg_type="slot", wg_width=0.7, slot=0.2) wg1 = Waveguide([(0, 0), (100, 100)], wgt_strip) tk.add(top, wg1) ycoup = StripSlotYConverter(wgt_strip, wgt_slot, 10.0, 0.2, end_slot_width=0.1, **wg1.portlist["output"]) tk.add(top, ycoup) (x1, y1) = ycoup.portlist["output"]["port"] wg2 = Waveguide([(x1, y1), (x1 + 100, y1 + 100)], wgt_slot) tk.add(top, wg2) gdspy.LayoutViewer(cells=top) # gdspy.write_gds('stripslotyconverter.gds', unit=1.0e-6, precision=1.0e-9)
"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 if __name__ == "__main__": fp = FontProperties(family="serif", style="italic") text = gdspy.PolygonSet(render_text("Text rendering", 10, font_prop=fp), layer=1) lib = gdspy.GdsLibrary() cell = lib.new_cell("TXT") cell.add(text) lib.write_gds("fonts.gds") gdspy.LayoutViewer(lib)
def gds(self, filename=None, view=False, extra=0, units='nms', sbend_h=0, sbend_v=0): #check to make sure the geometry isn't an array if len(self.clean_args(None)[0]) != 1: raise ValueError( "You have changing geometries, making gds doesn't make sense") if units == 'nms': scale = 1 elif units == 'microns': scale = 10**-3 else: raise ValueError('Invalid units') #scale to proper units sc_width = self.width * scale sc_gap = self.gap * scale sc_length = self.length * scale sc_H = self.H * scale sc_V = self.V * scale #make parametric functions sbendDown = lambda x: (sc_H * x, -sc_V / 2 * (1 - np.cos(np.pi * x))) sbendUp = lambda x: (sc_H * x, sc_V / 2 * (1 - np.cos(np.pi * x))) dsbendDown = lambda x: (sc_H, -np.pi * sc_V / 2 * np.sin(np.pi * x)) dsbendUp = lambda x: (sc_H, np.pi * sc_V / 2 * np.sin(np.pi * x)) sbend = False if sbend_h != 0 and sbend_v != 0: sbend = True sbendDownExtra = lambda x: (sbend_h * x, -sbend_v / 2 * (1 - np.cos(np.pi * x))) sbendUpExtra = lambda x: (sbend_h * x, sbend_v / 2 * (1 - np.cos(np.pi * x))) dsbendDownExtra = lambda x: (sbend_h, -np.pi * sbend_v / 2 * np.sin( np.pi * x)) dsbendUpExtra = lambda x: (sbend_h, np.pi * sbend_v / 2 * np.sin(np.pi * x)) #write to GDS pathTop = gdspy.Path(sc_width, (-sc_length / 2 - sc_H - sbend_h - extra, sc_V + sbend_v + sc_width / 2 + sc_gap / 2)) pathTop.segment(extra, '+x') if sbend: pathTop.parametric(sbendDownExtra, dsbendDownExtra) pathTop.parametric(sbendDown, dsbendDown) pathTop.segment(sc_length, '+x') pathTop.parametric(sbendUp, dsbendUp) if sbend: pathTop.parametric(sbendUpExtra, dsbendUpExtra) pathTop.segment(extra, '+x') pathBottom = gdspy.Path(sc_width, (-sc_length / 2 - sc_H - sbend_h - extra, -sc_V - sbend_v - sc_width / 2 - sc_gap / 2)) pathBottom.segment(extra, '+x') if sbend: pathBottom.parametric(sbendUpExtra, dsbendUpExtra) pathBottom.parametric(sbendUp, dsbendUp) pathBottom.segment(sc_length, '+x') pathBottom.parametric(sbendDown, dsbendDown) if sbend: pathBottom.parametric(sbendDownExtra, dsbendDownExtra) pathBottom.segment(extra, '+x') gdspy.current_library = gdspy.GdsLibrary() path_cell = gdspy.Cell('C0') path_cell.add(pathTop) path_cell.add(pathBottom) if view: gdspy.LayoutViewer(cells='C0') if filename is not None: writer = gdspy.GdsWriter(filename, unit=1.0e-6, precision=1.0e-9) writer.write_cell(path_cell) writer.close()
max_points=199, **cur_spec ) self.add(clad) def __build_ports(self): # Portlist format: # example: example: {'port':(x_position, y_position), 'direction': 'NORTH'} self.portlist["input"] = {"port": self.input_port, "direction": "WEST"} self.portlist["output"] = {"port": self.output_port, "direction": "EAST"} if __name__ == "__main__": from . import * top = gdspy.Cell("top") wgt = WaveguideTemplate(bend_radius=50, resist="+") wg1 = Waveguide([(0, 0), (100, 0)], wgt) tk.add(top, wg1) sb1 = SBend(wgt, 200.0, 100.0, **wg1.portlist["output"]) tk.add(top, sb1) x, y = sb1.portlist["output"]["port"] wg2 = Waveguide([(x, y), (x + 100, y)], wgt) tk.add(top, wg2) gdspy.LayoutViewer(cells=top, depth=3) # gdspy.write_gds('sbend.gds', unit=1.0e-6, precision=1.0e-9)
self.portlist["input"] = {"port": self.portlist_input, "direction": "WEST"} self.portlist["output"] = {"port": self.portlist_output, "direction": "EAST"} if __name__ == "__main__": from picwriter.components.waveguide import WaveguideTemplate gdspy.current_library = gdspy.GdsLibrary() top = gdspy.Cell("top") wgt = WaveguideTemplate( bend_radius=50, wg_width=1.0, clad_width=10.0, euler_bend=True ) sp1 = Spiral( wgt, width=2700.0, length=2900.0, spacing=20.0, parity=1, port=(0, 0), direction="EAST", ) tk.add(top, sp1) print("length is " + str(sp1.get_spiral_length())) print("portlist = " + str(sp1.portlist)) gdspy.LayoutViewer(cells="top") # gdspy.write_gds('spiral.gds', unit=1.0e-6, precision=1.0e-9)
chip1.set_current_coor(['0.9mm', con1], [1,0]) chip1.draw_capa_inline('capa_readout', PM.track, PM.gap, '100um', PM.gap_capa_readout, n_pad=2) PM.set_variable('tune_ro', '3mm') chip1.double_port('constrain_readout1', [PM.x_T-PM.tune_ro, PM.y_T], [1,0], PM.track, PM.gap) chip1.double_port('constrain_readout2', [PM.x_T-0.3574*PM.tune_ro, 0.5*(PM.y_T+con1)], [0,-1] ,PM.track, PM.gap) chip1.draw_cable('readout', 'trm_portOut2','constrain_readout1_front', 'constrain_readout1_back','constrain_readout2_front', 'constrain_readout2_back', 'capa_readout_outPort1', is_bond=is_bond, fillet=PM.fillet) chip1.draw_cable('bef_capa', 'capa_readout_outPort2', chip1.name+'in_readoutiOut', is_bond=is_bond, fillet=PM.fillet) # gdspy.write_gds('test.gds', unit=1.0, precision=1e-9) t2 = time.time() print("execution time: ", t2-t1) #%% gdspy.LayoutViewer(library=gdspy.current_library, pattern={'default': 8},background='#FFFFFF') #### Test junctions # #if litho and 1: # PM.set_variable('x_D', '4.6mm') # PM.set_variable('y_D', '3.6mm') # PM.set_variable('dose_pad', '100um') # PM.set_variable('dose_sep', '100um') # PM.set_variable('dose_cor', '10um') # PM.key_elt('dose_test', [PM.x_D, PM.y_D], [1,0]) # dose_mat = [2,6] # # PM.key_elt('align_dose_test', PM.dose_test.pos + 0.5*Vector([2*PM.dose_pad*dose_mat[0] + 3*PM.dose_sep*dose_mat[0] - PM.dose_cor*(2*dose_mat[0]-1), PM.dose_pad*dose_mat[1] + PM.dose_sep*(dose_mat[1]+1)]), PM.dose_test.ori) # PM.align_dose_test.draw_alignement_marks('20um', ['0.3mm', '0.7mm']) # PM.key_elt('align_chip', [0.5*PM.chip_width, 0.5*PM.chip_length], PM.dose_test.ori) # PM.align_chip.draw_alignement_marks('80um', ['3.5mm', '3.2mm'])
def viewer(self, item): self.collect(item) library = gdspy.GdsLibrary(name=self.file_name) for c in self.collector.values(): library.add(c) gdspy.LayoutViewer(library=library)
gp.write_gds(os.path.join(output_dir, title + '.gds'), cells=[cell], unit=1.0e-6, precision=1e-10) def bitmarker_2inch(): dx = 20 dy = 20 # text_size = 100 nrows = 32 ncols = 32 output_dir = r'/Users/wgz/Downloads' title = 'BitmarkerArray' cell = gp.Cell(title) for x in range(ncols): for y in range(nrows): # x_label = string.ascii_uppercase[x] # y_label = str(y) # shape = gp.Text(x_label+y_label, text_size, position=(x*dx, -y*dy), layer=10) shape = tools.bitmarker(x, y) shape.translate(x*dx, -y*dy) cell.add(shape) gp.LayoutViewer(cells=[cell]) gp.write_gds(os.path.join(output_dir, title + '.gds'), cells=[cell], unit=1.0e-6, precision=1e-10) bitmarker_array(cell) gp.LayoutViewer(cells=[cell]) bitmarker_array()
def gds(self, filename=None, view=False, extra=0, units="nms"): """Writes the geometry to the gds file. Parameters ---------- filename : str, optional Location to save file to. Defaults to None. extra : int, optional Extra straight portion to add to ends of waveguides to make room in simulation (units same as units parameter). Defaults to 0. units : {'microns' or 'nms'}, optional Units to save gds file in. Defaults to microns. view : bool, optional Whether to visually show gds file. Defaults to False. """ # check to make sure the geometry isn't an array if len(self._clean_args(None)[0]) != 1: raise ValueError( "You have changing geometries, making gds doesn't make sense") if units == "nms": scale = 1e-3 elif units == "microns": scale = 1 else: raise ValueError("Invalid units") # scale to proper units sc_radius = self.radius * scale sc_gap = self.gap * scale sc_width = self.width * scale sc_length = self.length * scale # write to GDS pathTop = gdspy.Path( sc_width, (-sc_length / 2, 2 * sc_radius + sc_width / 2 + sc_gap / 2)) pathTop.segment(sc_length, "+x") pathTop.turn(sc_radius, "rr") pathTop.segment(sc_length, "-x") pathTop.turn(sc_radius, "rr") pathBottom = gdspy.Path( sc_width, (-sc_radius - sc_width / 2 - sc_length / 2, -sc_gap / 2 - sc_width / 2), ) pathBottom.segment(2 * (sc_radius + sc_width / 2) + sc_length, "+x") gdspy.current_library = gdspy.GdsLibrary() path_cell = gdspy.Cell("C0") path_cell.add(pathTop) path_cell.add(pathBottom) if view: gdspy.LayoutViewer(cells="C0") if filename is not None: writer = gdspy.GdsWriter(filename, unit=1.0e-6, precision=1.0e-9) writer.write_cell(path_cell) writer.close()
(40, 251), #M4 lbl (45, 0), #V4 (50, 0), #M5 (50, 251), #M5 lbl (55, 0), #V5 (60, 0), #M6 (60, 251), #M6 lbl (65, 0), #V6 (70, 0), #M7 (70, 251), #M7 lbl (75, 0), #V7 (80, 0), #M8 (80, 251), #M8 lbl (85, 0), #V8 (88, 0), #SDT (90, 0), #M9 (90, 251), #M9 lbl (95, 0), #V9 (96, 0), #Pad (97, 0), #SLVT (98, 0), #LVT (99, 0), #SRAMDRC (100, 0), #BOUNDARY (101, 0), #TEXT (110, 0), #SRAMVT (235, 5) #DIEAREA ] print('Opening layout in gdspy...') gdspy.LayoutViewer(gds_lib, hidden_types=hidden, depth=1)
def watch(self): gdspy.LayoutViewer(depth=0, pattern={'default': 8}, background='#FFFFFF') # this opens a viewer
def watch_cells(self, num): gdspy.LayoutViewer(cells=self.cells[num])
def create_sim_space( gds_fg_name: str, gds_bg_name: str, grating_len: float = 12000, etch_frac: float = 0.5, box_thickness: float = 2000, wg_width: float = 12000, wg_thickness: float = 220, buffer_len: float = 1500, dx: int = 40, num_pmls: int = 10, visualize: bool = False, ) -> optplan.SimulationSpace: """Creates the simulation space. The simulation space contains information about the boundary conditions, gridding, and design region of the simulation. Args: gds_fg_name: Location to save foreground GDS. gds_bg_name: Location to save background GDS. grating_len: Length of the grating coupler and design region. etch_frac: Etch fraction of the grating. 1.0 indicates a fully-etched grating. box_thickness: Thickness of BOX layer in nm. wg_thickness: Thickness of the waveguide. wg_width: Width of the waveguide. buffer_len: Buffer distance to put between grating and the end of the simulation region. This excludes PMLs. dx: Grid spacing to use. num_pmls: Number of PML layers to use on each side. visualize: If `True`, draws the polygons of the GDS file. Returns: A `SimulationSpace` description. """ # Calculate the simulation size, including PMLs sim_size = [ grating_len + 2 * buffer_len + dx * num_pmls, wg_width + 2 * buffer_len + dx * num_pmls ] # First, we use `gdspy` to draw the waveguides and shapes that we would # like to use. Instead of programmatically generating a GDS file using # `gdspy`, we could also simply provide a GDS file (e.g. drawn using # KLayout). # Declare some constants to represent the different layers. LAYER_SILICON_ETCHED = 100 LAYER_SILICON_NONETCHED = 101 # Create rectangles corresponding to the waveguide, the BOX layer, and the # design region. We extend the rectangles outside the simulation region # by multiplying locations by a factor of 1.1. # We distinguish between the top part of the waveguide (which is etched) # and the bottom part of the waveguide (which is not etched). waveguide_top = gdspy.Rectangle((-1.1 * sim_size[0] / 2, -wg_width / 2), (-grating_len / 2, wg_width / 2), LAYER_SILICON_ETCHED) waveguide_bottom = gdspy.Rectangle((-1.1 * sim_size[0] / 2, -wg_width / 2), (grating_len / 2, wg_width / 2), LAYER_SILICON_NONETCHED) design_region = gdspy.Rectangle((-grating_len / 2, -wg_width / 2), (grating_len / 2, wg_width / 2), LAYER_SILICON_ETCHED) # Generate the foreground and background GDS files. gds_fg = gdspy.Cell("FOREGROUND", exclude_from_current=True) gds_fg.add(waveguide_top) gds_fg.add(waveguide_bottom) gds_fg.add(design_region) gds_bg = gdspy.Cell("BACKGROUND", exclude_from_current=True) gds_bg.add(waveguide_top) gds_bg.add(waveguide_bottom) gdspy.write_gds(gds_fg_name, [gds_fg], unit=1e-9, precision=1e-9) gdspy.write_gds(gds_bg_name, [gds_bg], unit=1e-9, precision=1e-9) if visualize: gdspy.LayoutViewer(cells=[gds_fg]) gdspy.LayoutViewer(cells=[gds_bg]) # The BOX layer/silicon device interface is set at `z = 0`. # # Describe materials in each layer. # We actually have four material layers: # 1) Silicon substrate # 2) Silicon oxide BOX layer # 3) Bottom part of grating that is not etched # 4) Top part of grating that can be etched. # # The last two layers put together properly describe a partial etch. # # Note that the layer numbering in the GDS file is arbitrary. In our case, # layer 100 and 101 correspond to actual structure. Layer 300 is a dummy # layer; it is used for layers that only have one material (i.e. the # background and foreground indices are identical) so the actual structure # used does not matter. stack = [ optplan.GdsMaterialStackLayer( foreground=optplan.Material(mat_name="Si"), background=optplan.Material(mat_name="Si"), # Note that layer number here does not actually matter because # the foreground and background are the same material. gds_layer=[300, 0], extents=[-10000, -box_thickness], ), optplan.GdsMaterialStackLayer( foreground=optplan.Material(mat_name="SiO2"), background=optplan.Material(mat_name="SiO2"), gds_layer=[300, 0], extents=[-box_thickness, 0], ), ] # If `etch-frac` is 1, then we do not need two separate layers. if etch_frac != 1: stack.append( optplan.GdsMaterialStackLayer( foreground=optplan.Material(mat_name="Si"), background=optplan.Material(mat_name="SiO2"), gds_layer=[LAYER_SILICON_NONETCHED, 0], extents=[0, wg_thickness * (1 - etch_frac)], )) stack.append( optplan.GdsMaterialStackLayer( foreground=optplan.Material(mat_name="Si"), background=optplan.Material(mat_name="SiO2"), gds_layer=[LAYER_SILICON_ETCHED, 0], extents=[wg_thickness * (1 - etch_frac), wg_thickness], )) mat_stack = optplan.GdsMaterialStack( # Any region of the simulation that is not specified is filled with # oxide. background=optplan.Material(mat_name="SiO2"), stack=stack, ) sim_z_start = -box_thickness - 1000 sim_z_end = wg_thickness + 1500 # Create a simulation space for both continuous and discrete optimization. simspace = optplan.SimulationSpace( name="simspace", mesh=optplan.UniformMesh(dx=dx), eps_fg=optplan.GdsEps(gds=gds_fg_name, mat_stack=mat_stack), eps_bg=optplan.GdsEps(gds=gds_bg_name, mat_stack=mat_stack), # Note that we explicitly set the simulation region. Anything # in the GDS file outside of the simulation extents will not be drawn. sim_region=optplan.Box3d( center=[0, 0, (sim_z_start + sim_z_end) / 2], extents=[sim_size[0], dx, sim_z_end - sim_z_start], ), selection_matrix_type="uniform", # PMLs are applied on x- and z-axes. No PMLs are applied along y-axis # because it is the axis of translational symmetry. pml_thickness=[num_pmls, num_pmls, 0, 0, num_pmls, num_pmls], ) if visualize: # To visualize permittivity distribution, we actually have to # construct the simulation space object. import matplotlib.pyplot as plt from spins.invdes.problem_graph.simspace import get_fg_and_bg context = workspace.Workspace() eps_fg, eps_bg = get_fg_and_bg(context.get_object(simspace), wlen=1550) def plot(x): plt.imshow(np.abs(x)[:, 0, :].T.squeeze(), origin="lower") plt.figure() plt.subplot(3, 1, 1) plot(eps_fg[2]) plt.title("eps_fg") plt.subplot(3, 1, 2) plot(eps_bg[2]) plt.title("eps_bg") plt.subplot(3, 1, 3) plot(eps_fg[2] - eps_bg[2]) plt.title("design region") plt.show() return simspace
import gdspy # Create the geometry: a single rectangle. rect = gdspy.Rectangle((0, 0), (2, 1)) cell = gdspy.Cell("FIRST") cell.add(rect) # Save all created cells in file 'first.gds'. gdspy.write_gds("first.gds") # Optionally, display all cells using the internal viewer. gdspy.LayoutViewer(gdspy.current_library)
def gds(self, filename=None, extra=0, units='microns', view=False, sbend_h=0, sbend_v=0): #check to make sure the geometry isn't an array if len(self.clean_args(None)[0]) != 1: raise ValueError( "You have changing geometries, making gds doesn't make sense") if units == 'nms': scale = 1 elif units == 'microns': scale = 10**-3 else: raise ValueError('Invalid units') #scale to proper units sc_zmin = self.zmin * scale sc_zmax = self.zmax * scale sc_width = self.width * scale cL = (sc_zmax - sc_zmin) cH = self.gap(self.zmin) * scale / 2 #make parametric functions paraTop = lambda x: (x * (sc_zmax - sc_zmin) + sc_zmin, scale * self. gap(x * (self.zmax - self.zmin) + self.zmin ) / 2 + sc_width / 2) paraBottom = lambda x: (x * (sc_zmax - sc_zmin) + sc_zmin, -scale * self.gap(x * (self.zmax - self.zmin) + self. zmin) / 2 - sc_width / 2) #dparaTop = lambda x: (sc_zmax-sc_zmin, scale*(self.zmax-self.zmin)*self.dgap(x*(self.zmax-self.zmin)+self.zmin)/2) #dparaBottom = lambda x: (sc_zmax-sc_zmin, -scale*(self.zmax-self.zmin)*self.dgap(x*(self.zmax-self.zmin)+self.zmin)/2) sbend = False if sbend_h != 0 and sbend_v != 0: sbend = True sbendDown = lambda x: (sbend_h * x, -sbend_v / 2 * (1 - np.cos(np.pi * x))) sbendUp = lambda x: (sbend_h * x, sbend_v / 2 * (1 - np.cos(np.pi * x))) dsbendDown = lambda x: (sbend_h, -np.pi * sbend_v / 2 * np.sin(np.pi * x)) dsbendUp = lambda x: (sbend_h, np.pi * sbend_v / 2 * np.sin(np.pi * x)) #write to GDS pathTop = gdspy.Path( sc_width, (sc_zmin - extra - sbend_h, cH + sc_width / 2 + sbend_v)) pathTop.segment(extra, '+x') if sbend: pathTop.parametric(sbendDown, dsbendDown) pathTop.parametric(paraTop, relative=False) if sbend: pathTop.parametric(sbendUp, dsbendUp) pathTop.segment(extra, '+x') pathBottom = gdspy.Path( sc_width, (sc_zmin - extra - sbend_h, -cH - sc_width / 2 - sbend_v)) pathBottom.segment(extra, '+x') if sbend: pathBottom.parametric(sbendUp, dsbendUp) pathBottom.parametric(paraBottom, relative=False) if sbend: pathBottom.parametric(sbendDown, dsbendDown) pathBottom.segment(extra, '+x') gdspy.current_library = gdspy.GdsLibrary() path_cell = gdspy.Cell('C0') path_cell.add(pathTop) path_cell.add(pathBottom) if view: gdspy.LayoutViewer(cells='C0') if filename is not None: writer = gdspy.GdsWriter(filename, unit=1.0e-6, precision=1.0e-9) writer.write_cell(path_cell) writer.close()
# give the disks an alignment mark since they will be written with a different dose alignment_cross_disc = alignment_mark(10, 100, ld_disc) align_cell = gdspy.Cell('alignment marks') align_cell.add([alignment_cross, alignment_cross_ebeam, alignment_cross_disc]) alignment_cell = gdspy.CellArray(align_cell, 2, 2, (18000, 16000), (-9000, -8000)) main.add(alignment_cell) # now add alignment marks for the dicing street for each chip DSE_alignment_cross = alignment_mark(20, 200, ld_opt) DSE_cell = gdspy.Cell('DSE alignment marks') DSE_cell.add(DSE_alignment_cross) DSE1 = gdspy.CellArray(DSE_cell, 2, 2, (7000, 4000), (X_MIN - 500, Y_MAX - 2000)) DSE2 = gdspy.CellArray(DSE_cell, 2, 2, (7000, 4000), (X_RIGHT - 500, Y_MAX - 2000)) DSE3 = gdspy.CellArray(DSE_cell, 2, 2, (7000, 4000), (X_MIN - 500, Y_MIN - 2000)) main.add([DSE1, DSE2, DSE3]) main_ref = gdspy.CellReference(main) final = gdspy.Cell('Final') final.add(main_ref) #gdspy.top_level() gdspy.write_gds('07-19-20_disks_rings.gds') gdspy.LayoutViewer()
elbow_point=(0, 0), joint_point=(0, 100), trace=coupled_cpw_trace, gap=coupled_cpw_gap), cpw.CPW(outline=[(0, 0), (0, 500), (300, 500), (300, 700)], trace=coupled_cpw_trace, gap=coupled_cpw_gap), cpw.CPWRoundedOpen(joint_point=(0, 0), open_point=(0, 100), trace=coupled_cpw_trace, gap=coupled_cpw_gap, # Use default ground=None because this CPW will be drawn negative # Use default open_at_start=False because this is the last Segment ) ]) halfwave_cpw.draw(cell=main_cell, origin=(-1500, coupled_cpw_distance), layer=2) # Save the gds file and return the library object gds_filename = 'cpw.gds' if not os.path.exists(output_directory): os.mkdir(output_directory) full_filename = os.path.join(output_directory, gds_filename) library.write_gds(outfile=full_filename) # This will overwrite an existing file! print("gdspy saved {}".format(full_filename)) return library if __name__ == '__main__': library = main(output_directory='.') gdspy.LayoutViewer(library) print("The gdspy.GdsLibrary object is called 'library'")