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_chip_labels(self): wafer_lbl = PATTERN + "\n" + WAFER_ID text = Label(wafer_lbl, 40., 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) center_x, center_y = (5000, 5000) for block in self.blocks: block.add(chip_lbl_cell, origin=(center_x, center_y - 300)) block.add(chip_lbl_cell, origin=(center_x, center_y - 4500)) block.add(chip_lbl_cell, origin=(center_x + 4500, center_y), rotation=90) block.add(chip_lbl_cell, origin=(center_x, center_y + 4500), rotation=180) block.add(chip_lbl_cell, origin=(center_x - 4500, center_y), rotation=270)
def add_theory_cells(self): theory_cells = Cell('TheoryCells') theory_cells.add(make_theory_cell(wafer_orient='100'), origin=(-400, 0)) theory_cells.add(make_theory_cell_3br(), origin=(0, 0)) theory_cells.add(make_theory_cell_4br(), origin=(400, 0)) theory_cells.add(make_theory_cell(wafer_orient='100'), origin=(-500, -400), rotation=45) theory_cells.add(make_theory_cell_3br(), origin=(-50, -400), rotation=45) theory_cells.add(make_theory_cell_4br(), origin=(370, -400), rotation=45) center_x, center_y = (5000, 5000) for block in self.blocks: block.add(theory_cells, origin=(center_x, center_y - 1700))
def makeAlignMarkers(self, t, w, position, layers, cross=False): if not (type(layers) == list): layers = [layers] self.aMarkers = Cell("AlignMarkers") for l in layers: if not (cross): am1 = Rectangle((-w / 2., -w / 2.), (w / 2., w / 2.), layer=l) elif cross: h = w 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.)] am1 = Boundary(crosspts, layer=l) # Create gdsCAD shape # am1 = Polygon(crosspts) #Create shapely polygon for later calculation am1 = am1.translate(tuple(position)) # 850,850 am2 = am1.copy().scale((-1, 1)) # Reflect in x-axis am3 = am1.copy().scale((1, -1)) # Reflect in y-axis am4 = am1.copy().scale((-1, -1)) # Reflect in both x and y-axis self.aMarkers.add([am1, am2, am3, am4]) self.add(self.aMarkers)
def add_subdicing_marks(self, length, width, layers): if type(layers) is not list: layers = [layers] for l in layers: mark_cell = Cell("SubdicingMark") line = Path([[0, 0], [0, length]], width=width, layer=l) mark_cell.add(line) for block in self.blocks: block.add(mark_cell, origin=(self.block_size[0] / 2., 0), rotation=0) block.add(mark_cell, origin=(0, self.block_size[1] / 2.), rotation=-90) block.add(mark_cell, origin=(self.block_size[0], self.block_size[1] / 2.), rotation=90) block.add(mark_cell, origin=(self.block_size[0] / 2., self.block_size[1]), rotation=180)
def make_many_shapes(self, array_size, shape_areas, pitches, shape, skew, layer): """ :param array_size: :param shape_areas: :param pitches: :param shape: :param skew: :param layer: :return: """ if (type(shape) == list): shape = shape[0] 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 pitch in pitches: 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(pitches) - 1) / 2., offset_y * (len(shape_areas) - 1) / 2.))
# Standard values (used when these params are not varying) width_std = 0.05 pitch_std = 1. length_std = 10. # Definition of the parameters widths_1x1 = widths_1x2 = [0.02, 0.04, 0.08, 0.1, 0.12, 0.14, 0.16, 0.2] # 8 widths lengths_1x1 = lengths_1x2 = lengths_2x2 = [ 0.25, 0.5, 1., 2., 5., 8., 10., 12. ] # 8 lenghts pitches_2x1 = [0.5, 1., 2.] # 3 pitches num_slits_2x1 = [2, 6, 10, 14, 18, 22, 26] # 8 multiple slits # 28 slits is the maximum for the chosen geometry topCell = Cell("TopCell") sm_writer = False lg_label = "" # Crate large field array following the geometry set at the beginning. for lg_row in range(0, lgField_num): for lg_col in range(0, lgField_num): # Array of Middle Fields and Parameters of the Small Fields if (lg_row + 1 == 1 and lg_col + 1 == 1): # In LF 1x1, an MF array of: 1x1 md_num_row, md_num_col = 1, 1 sm_writer = True lg_label = "Single Slit - 0deg\nPitch = " + str(pitch_std) + "um" rot_angle = 0
def make_theory_cell_3br(): ''' 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, 9) * 4.0) # Logarithmic widths = [0.060, 0.040, 0.020] 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.040 N = 13 # number of shapes in the 120 degree arc N_rows = 2 angle_sweep = 180 wheel_rad = 45. 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_branch_devices(shape_len, shape_wid, _N, wheel_rad + i * shape_len * 3., 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.040, 91, 6. * 2, l_smBeam, angle_ref='100', angle_sweep=angle_sweep)) for i in range(10): # number of concentric rings to make wheel2.add( make_rotating_slits(2, 0.040, 91, (7.2 + i * 1.2) * 2, l_smBeam, angle_sweep=angle_sweep)) # Pitch Dependence PitchDep = Cell('PitchDependence') # pitches = list(np.round(np.logspace(-1, 1, 10), 1)) # Logarithmic pitches = [0.500, 1.000, 2.000, 4.000] widths = [0.020, 0.040, 0.080, 0.140, 0.220, 0.320] length = [2.] arrayHeight = 20. arrayWidth = arrayHeight arraySpacing = 30. spacing = 0.5 for j, width in enumerate(widths): for i, pitch in enumerate(reversed(pitches)): PitchDep.add(make_branch_array(pitch, width, length, ['pitch', 'width', 'length'], spacing, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(j * 30, i * 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=(-100., -60.)) TopCell.add(wheel2, origin=(-100., -65.)) TopCell.add(PitchDep, origin=(-200., -280.)) # TopCell.add3(TheorySlitElong, origin=(-250., -50)) TopCell.add(LenWidDep, origin=(-200., -50.)) # TopCell.add(hexagon_array, origin=(-100., -50)) # TopCell.add(circles_array, origin=(-75., -50.)) # TopCell.add(triangle_down_array, origin=(-50., -50)) # TopCell.add(triangle_up_array, origin=(-25., -50)) TopCell.add(xmax_cell, origin=(0, 50)) return TopCell
def add_contacts(self, layers): corner_pos = pad_size / 2 finger_width = 20. finger_length = 80. n_cont = smField_num + 1 contact_pads = Cell('Contact_Pads') pad = Rectangle((-corner_pos, -corner_pos), (corner_pos, corner_pos), layer=layers) pad_cell = Cell('Pad_Cell') pad_cell.add(pad) finger = Rectangle((-finger_width / 2, -finger_length / 2), (finger_width / 2, finger_length / 2), layer=layers) finger_cell = Cell('Finger Cell') finger_cell.add(finger) n_finger = n_cont - 1 pad_array = CellArray(pad_cell, n_cont, n_cont, (sm_spacing, sm_spacing), origin=(0, 0)) finger_array1 = CellArray(finger_cell, n_finger, n_finger, (sm_spacing, sm_spacing), origin=(corner_pos - finger_width, +corner_pos + finger_length / 2)) finger_array2 = CellArray( finger_cell, n_finger, n_finger, (sm_spacing, sm_spacing), origin=(sm_spacing - corner_pos + finger_width, sm_spacing - corner_pos - finger_length / 2)) finger_array3 = CellArray( finger_cell, n_finger, n_finger, (sm_spacing, sm_spacing), rotation=90, origin=((n_cont - 1) * sm_spacing - corner_pos - finger_length / 2, corner_pos - finger_width)) finger_array4 = CellArray( finger_cell, n_finger, n_finger, (sm_spacing, sm_spacing), rotation=90, origin=((n_cont - 2) * sm_spacing + corner_pos + finger_length / 2, sm_spacing - corner_pos + finger_width)) contact_pads.add(pad_array) contact_pads.add(finger_array1) contact_pads.add(finger_array2) contact_pads.add(finger_array3) contact_pads.add(finger_array4) center = -0.5 * ((n_cont - 1) * smField_size + (n_cont - 1) * pad_size) for block in self.blocks: for n in range(0, lgField_num): for i in range(0, lgField_num): block.add(contact_pads, origin=(center + (n + 1) * lgField_spacing, center + (i + 1) * lgField_spacing))
def make_qp(): ''' Makes the theory cell and returns it as a cell''' widths = [0.028, 0.044] qp_spacing = 60 TopCell = Cell('QuantumPlayground_TopCell') for i, nm_width in enumerate(widths): cell_XShape = makeShape_X(1.0, 10, nm_width, 3, l_smBeam) cell_XShapeNoBuffer = makeShape_X(1.0, 10, nm_width, 0, l_smBeam) cell_StarShape = makeShape_Star(1.0, 10, nm_width, 3, l_smBeam) cell_StarShapeNoBuffer = makeShape_Star(1.0, 10, nm_width, 0, l_smBeam) cell_HashTag = makeShape_HashTag(3.0, 1.0, 5, nm_width, l_smBeam) cell_HashTagNoBuffer = makeShape_HashTag(3.0, 10.0, 5, nm_width, l_smBeam) cell_Window = makeShape_Window(3.0, 1.0, 12, nm_width, l_smBeam) cell_WindowNoBuffer = makeShape_Window(3.0, 100.0, 12, nm_width, l_smBeam) cell_Triangle = makeShape_Triangle(1.0, 5, nm_width, 1.0, 3, l_smBeam) cell_TriangleNoBuffer = makeShape_Triangle(10.0, 5, nm_width, 1.0, 0, l_smBeam) cell_AB_Diamond = makeShape_ABDiamond(1.0, 3, nm_width, 1.0, 3, l_smBeam) cell_AB_DiamondNoBuffer = makeShape_ABDiamond(10.0, 3, nm_width, 1.0, 0, l_smBeam) cell_AB_Hexagon = makeShape_ABHexagon(1.0, 2, nm_width, 2.0, 3, l_smBeam) cell_AB_HexagonNoBuffer = makeShape_ABHexagon(10.0, 2, nm_width, 2.0, 0, l_smBeam) QP = Cell('QuantumPlayground_W{:.0f}'.format(nm_width * 1000)) QP.add(cell_AB_Diamond, origin=(-30, 30)) QP.add(cell_AB_DiamondNoBuffer, origin=(-10, 30)) QP.add(cell_XShape, origin=(-30, 10)) QP.add(cell_XShapeNoBuffer, origin=(-10, 10)) QP.add(cell_HashTag, origin=(-30, -10)) QP.add(cell_HashTagNoBuffer, origin=(-10, -10)) QP.add(cell_Triangle, origin=(-30, -30)) QP.add(cell_TriangleNoBuffer, origin=(-10, -30)) QP.add(cell_AB_Hexagon, origin=(10, 30)) QP.add(cell_AB_HexagonNoBuffer, origin=(30, 30)) QP.add(cell_StarShape, origin=(10, 10)) QP.add(cell_StarShapeNoBuffer, origin=(30, 10)) QP.add(cell_Window, origin=(10, -10)) QP.add(cell_WindowNoBuffer, origin=(30, -10)) TopCell.add(QP, origin=(-qp_spacing + 2 * i * qp_spacing, qp_spacing)) # SMALL Aharonov Bohm devices cell_Triangle_sm = makeShape_Triangle(1.0, 1, nm_width, 1.0, 5, l_smBeam) cell_TriangleNoBuffer_sm = makeShape_Triangle(10.0, 1, nm_width, 1.0, 0, l_smBeam) cell_AB_Diamond_sm = makeShape_ABDiamond(1.0, 1, nm_width, 1.0, 5, l_smBeam) cell_AB_DiamondNoBuffer_sm = makeShape_ABDiamond( 10.0, 1, nm_width, 1.0, 0, l_smBeam) cell_AB_Hexagon_sm = makeShape_ABHexagon(1.0, 1, nm_width, 1.0, 5, l_smBeam) cell_AB_HexagonNoBuffer_sm = makeShape_ABHexagon( 10.0, 1, nm_width, 1.0, 0, l_smBeam) QP_sm = Cell('QuantumPlayground_W{:.0f}'.format(nm_width * 1000)) QP_sm.add(cell_AB_Diamond_sm, origin=(-30, 30)) QP_sm.add(cell_AB_DiamondNoBuffer_sm, origin=(-10, 30)) QP_sm.add(cell_XShape, origin=(-30, 10)) QP_sm.add(cell_XShapeNoBuffer, origin=(-10, 10)) QP_sm.add(cell_HashTag, origin=(-30, -10)) QP_sm.add(cell_HashTagNoBuffer, origin=(-10, -10)) QP_sm.add(cell_Triangle_sm, origin=(-30, -30)) QP_sm.add(cell_TriangleNoBuffer_sm, origin=(-10, -30)) QP_sm.add(cell_AB_Hexagon_sm, origin=(10, 30)) QP_sm.add(cell_AB_HexagonNoBuffer_sm, origin=(30, 30)) QP_sm.add(cell_StarShape, origin=(10, 10)) QP_sm.add(cell_StarShapeNoBuffer, origin=(30, 10)) QP_sm.add(cell_Window, origin=(10, -10)) QP_sm.add(cell_WindowNoBuffer, origin=(30, -10)) TopCell.add(QP_sm, origin=(-qp_spacing + 2 * i * qp_spacing, -qp_spacing)) return TopCell
def make_branch_array(x_vars, y_vars, stat_vars, var_names, spacing, rot_angle, array_height, array_width, array_spacing, layers): array_angle = 25 # 60 for 111 if len(var_names) != 3: raise Exception('Error! Need to have three variable names.') if not (type(layers) == list): layers = [layers] if not (type(x_vars) == list): x_vars = [x_vars] if not (type(y_vars) == list): y_vars = [y_vars] if not (type(stat_vars) == list): stat_vars = [stat_vars] x_var_name = var_names[0] y_var_name = var_names[1] stat_var_name = var_names[2] for l in layers: j = -1 manybranches = Cell("ManyBranches") for x_var in x_vars: j += 1 i = -1 for y_var in y_vars: i += 1 if i % 3 == 0: j += 1 # Move to array to next line i = 0 # Restart at left var_dict = { x_var_name: x_var, y_var_name: y_var, stat_var_name: stat_vars[0] } pitch = var_dict['pitch'] width = var_dict['width'] length = var_dict['length'] branch = make_branch(length, width, layers, rot_angle=rot_angle) # x_spacing = (length + pitch) * np.cos(np.deg2rad(array_angle)) # y_spacing = (length + pitch) * np.sin(np.deg2rad(array_angle)) # n_x = int(array_width / x_spacing) # n_y = int(array_width / y_spacing) # shape_array = CellArray(branch, n_x, n_y, (x_spacing, y_spacing), origin=( # -(n_x * x_spacing - pitch * np.cos(np.deg2rad(array_angle))) / 2., # -(n_y * y_spacing - pitch * np.sin(np.deg2rad(array_angle))) / 2.)) branch_array = Cell( 'BranchArray-{:.0f}/{:.0f}/{:.2f}-wpl'.format( width, spacing, length)) # branch_array.add(shape_array) dir1 = pitch dir2 = length + 2 * pitch pts = generate_lattice([array_height, array_width], [[dir1, dir2], [dir2, dir1]]) for pt in pts: pt += np.array([-array_width / 2., -array_height / 2.]) branch_array.add(branch, origin=pt) if length * 1000 % 1000 == 0: text = Label('w/p/l\n{:.0f}/{:.0f}/{:.0f}'.format( width * 1000, pitch * 1000, length), 2, layer=l_smBeam) elif length * 1000 % 100 == 0: text = Label('w/p/l\n{:.0f}/{:.0f}/{:.1f}'.format( width * 1000, pitch * 1000, length), 2, layer=l_smBeam) else: text = Label('w/p/l\n{:.0f}/{:.0f}/{:.2f}'.format( width * 1000, pitch * 1000, length), 2, layer=l_smBeam) lbl_vert_offset = 1.35 if j % 2 == 0: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, -array_height / lbl_vert_offset))) ) # Center justify label else: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, array_height / lbl_vert_offset))) ) # Center justify label branch_array.add(text) manybranches.add( branch_array, origin=((array_width + array_spacing) * i, (array_height + 2. * array_spacing) * j - array_spacing / 2.)) return manybranches
def make_finger_contacts(self, slit_length, length, nslit, pitch, rot_angle, layers): global margin margin = 2.5 cont_to_cent = 60. global fing_width fing_width = 1. global rad_angle rad_angle = rot_angle / 180 * np.pi fing_ext_length = cont_to_cent - (slit_length / 2 - margin) * np.cos(rad_angle) fing_ext_hook = 30. + nslit / 2 * pitch + np.sin( rad_angle) * slit_length / 2 fing_int_length = cont_to_cent + nslit / 2 * pitch + np.sin( rot_angle) * length + margin cont_conn_length = 2 * margin global fake_slit_length fake_slit_length = cont_to_cent - fing_ext_length - length - margin - fing_width / 2 contact = Cell(" FingerContact") triangle = RegPolygon((0, 0), cont_conn_length, 3, layer=layers) conn_triangle = Cell("ConnTriangle") conn_triangle.add(triangle) finger_rect = Rectangle((-fing_ext_length / 2., -fing_width / 2), (fing_ext_length / 2., fing_width / 2), layer=layers) finger_ext = Cell("Finger") finger_ext.add(finger_rect) hook = Rectangle((-fing_ext_hook / 2., -fing_width / 2), (fing_ext_hook / 2., fing_width / 2), layer=layers) hook_finger = Cell("ContactFinger") hook_finger.add(hook) finger_middle = Rectangle((-fing_int_length / 2., -fing_width / 2), (fing_int_length / 2., fing_width / 2), layer=layers) finger_int = Cell("Middle Finger") finger_int.add(finger_middle) # Relative coordinates for horizontal elements (origin = center of the triangle) h_finger_to_triangle_x = fing_ext_length / 2 h_hook_to_triangle_x = fing_ext_length - fing_width / 2 h_hook_to_triangle_y = -fing_ext_hook / 2 + fing_width / 2 # Relative coordinates for vertical elements (origin = center of the triangle) v_finger_to_triangle_x = fing_int_length / 2 cont_ext = Cell("ExternalContact") cont_ext.add(conn_triangle) cont_ext.add(finger_ext, origin=(h_finger_to_triangle_x, 0)) cont_ext.add(hook_finger, origin=(h_hook_to_triangle_x, h_hook_to_triangle_y), rotation=90) cont_int = Cell("InternalContact") cont_int.add(conn_triangle) cont_int.add(finger_int, origin=(v_finger_to_triangle_x, 0)) # Coordinates Horizontal and Vertical Contacts into the small field hor_x = -cont_to_cent hor_y = cont_to_cent / 2 - margin vert_x = (-length - fing_width / 2) * np.cos(rad_angle) - ( 1 - np.cos(rad_angle)) * (fing_width / 2) vert_y = cont_to_cent contact.add(cont_ext, origin=(hor_x, hor_y)) contact.add(cont_int, origin=(vert_x, vert_y), rotation=-90) self.add(contact) self.add(contact, rotation=180) return
centerLeftAlignField.make_align_markers(2., 20., (180., 180.), l_lgBeam, joy_markers=True) centerLeftAlignField.add(quantum_playground) centerRightAlignField = Frame("CenterRightAlignField", (smFrameSize, smFrameSize), []) centerRightAlignField.make_align_markers(2., 20., (180., 180.), l_lgBeam, joy_markers=True) centerRightAlignField.add(quantum_playground, rotation=45) # 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(centerLeftAlignField, origin=(-dx / 2, 0.)) topCell.add(centerRightAlignField, origin=(dx / 2, 0.)) topCell.add(centerAlignField, origin=(0., 0.)) topCell.spacing = np.array([4000., 4000.]) # %%Create the layout and output GDS file layout = Layout('LIBRARY')
def make_branch_array(self, _widths, _lengths, nx, ny, spacing_structs, spacing_arrays, rot_angle, layers): if not (type(layers) == list): layers = [layers] if not (type(_lengths) == list): _lengths = [_lengths] if not (type(_widths) == list): _widths = [_widths] l = layers[0] _length = _lengths[0] manyslits = i = j = None slits = [] for width in _widths: slit = Cell("Slit_{:.0f}".format(width * 1000)) line = Path([[-_length / 2., 0], [_length / 2., 0]], width=width, layer=l) slit.add(line) slits.append(slit) buffers = self.make_branch_device(0.08, 1.0, _lengths[0] / 2., _lengths[0] / 2., 4, layers[0], buffers_only=True) many_crosses = Cell("CrossArray") x_pos = 0 y_pos = 0 array_pitch = (ny - 1) * ( length + spacing_structs) - spacing_structs + spacing_arrays for j, width_vert in enumerate(_widths[::-1]): for i, width_horiz in enumerate(_widths): # Define a single cross cross = Cell("Cross_{:.0f}_{:.0f}".format( width_horiz * 1000, width_vert * 1000)) cross.add(slits[i]) # Horizontal slit cross.add(slits[j], rotation=90) # Vertical slit cross.add(buffers) # Define the cross array cross_array = Cell("CrossArray_{:.0f}_{:.0f}".format( width_horiz * 1000, width_vert * 1000)) slit_array = CellArray( cross, nx, ny, (_length + spacing_structs, _length + spacing_structs)) slit_array.translate( (-(nx - 1) * (_length + spacing_structs) / 2., (-(ny - 1) * (_length + spacing_structs) / 2.))) cross_array.add(slit_array) many_crosses.add(cross_array, origin=(x_pos, y_pos)) x_pos += array_pitch y_pos += array_pitch x_pos = 0 # Make the labels lbl_cell = Cell("Lbl_Cell") for i, width in enumerate(_widths): text_string = 'W{:.0f}'.format(width * 1000) text = Label(text_string, 5, layer=l) text.translate(tuple(np.array(-text.bounding_box.mean(0)))) x_offset = -1.5 * array_pitch + i * array_pitch text.translate(np.array((x_offset, 0))) # Center justify label lbl_cell.add(text) centered_cell = Cell('Centered_Cell') bbox = np.mean(many_crosses.bounding_box, 0) # Get center of cell centered_cell.add(many_crosses, origin=tuple(-bbox)) lbl_vertical_offset = 1.5 centered_cell.add(lbl_cell, origin=(0, -bbox[1] * lbl_vertical_offset)) centered_cell.add(lbl_cell, origin=(-bbox[1] * lbl_vertical_offset, 0), rotation=90) self.add(centered_cell, rotation=rot_angle)
def makeShape_ABDiamond(pitch, length, width, contactlength, n_outer_buf, layer): """ Makes Aharonov Bohm diamond shape :param pitch: pitch of nanomembranes :param length: quadrilateral side length :param width: width of the membranes :param contactlength: length of membrane coming from triangle to contact :param n_outer_buf: number of outer buffers to add :param layer: layer to write the structures in :return: cell with triangle shape in it """ diamondshape = Cell("DiamondShape") line = Cell('DiamondLine') height = length * np.sqrt(3.) / 2. pt1 = (-length / 2., 0) pt2 = (length / 2., 0) shape_half = Cell('DiamondShapeHalf') # Make the main quadrilateral with contact area line_cell = Cell('LineCell') contactline_cell = Cell('ContactLineCell') line = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) contactline = Path([(-length / 2., 0), (length / 2. + contactlength, 0)], width=width, layer=layer) line_cell.add(line) contactline_cell.add(contactline) shape_half.add(line_cell, origin=(-length / 2., 0), rotation=60) shape_half.add(contactline_cell, origin=(length / 4., height / 2.)) n_inner_buf = int(height / 2. / pitch) + 1 # Make the inner buffer triangles for i in range(1, n_inner_buf): line_cell = Cell('LineCell') slit_len = length - 2 * pitch * 2. / np.sqrt(3) * i line = Path([(-slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) line_cell.add(line) shape_half.add(line_cell, origin=(length / 4. - pitch / np.sqrt(3) * i, height / 2 - i * pitch)) shape_half.add(line_cell, origin=(-length / 2. + pitch * 2. / np.sqrt(3) * i, 0), rotation=60) # Make the outer buffer membranes for i in range(1, n_outer_buf + 1): line_cell = Cell('LineCell') contactline_cell = Cell('ContactBufferCell') slit_len = length + 2 * pitch * 2. / np.sqrt(3) * i line = Path([(-slit_len / 2. + 2 * pitch / np.sqrt(3) * (i + 1), 0), (slit_len / 2., 0)], width=width, layer=layer) contactline = Path([(-slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) line_cell.add(line) contactline_cell.add(contactline) shape_half.add(line_cell, origin=(-length / 2. - pitch * 2. / np.sqrt(3) * i, 0), rotation=60) shape_half.add(contactline_cell, origin=(length / 4. + pitch / np.sqrt(3) * i, height / 2 + i * pitch)) diamondshape.add(shape_half, rotation=0) diamondshape.add(shape_half, rotation=180) return diamondshape
def make_slit_patterns(self, sflabels, _pitches, spacing, _widths, _lengths, rot_angle, array_height, array_width, 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] manyslits = i = j = None for l in layers: i = -1 j = -1 manyslits = Cell("SlitArray") pitch = _pitches[0] for length in _lengths: 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 nx = int(array_width / (length + spacing)) ny = int(array_height / pitch) # Define the slits slit = Cell("Slit_w{:.0f}".format(width * 1000)) slit_path = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) slit.add(slit_path) slits = CellArray(slit, nx, ny, (length + spacing, pitch)) slits.translate((-(nx - 1) * (length + spacing) / 2., -(ny - 1) * pitch / 2.)) slit_array = Cell("SlitArray_w{:.0f}".format(width * 1000)) slit_array.add(slits) text = Label('w/p/l\n%i/%i/%i' % (width * 1000, pitch, length), 5, layer=l) lbl_vertical_offset = 1.35 if j % 2 == 0: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, -array_height / lbl_vertical_offset)) )) # Center justify label else: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, array_height / lbl_vertical_offset )))) # Center justify label slit_array.add(text) manyslits.add( slit_array, origin=((array_width + array_spacing) * i, (array_height + 2. * array_spacing) * j - array_spacing / 2.)) specific_label = Label(sflabels, 20, layer=l) specific_label.translate( (-lbl_vertical_offset * smMarkerPosition, -lbl_vertical_offset * smMarkerPosition)) # Center Small Field slit_array.add(specific_label) # This is an ugly hack to center rotated slits, should fix this properly... if rot_angle == 45: # TODO: fix this ugly thing hacky_offset_x = 200 hacky_offset_y = -25 elif rot_angle == 90: hacky_offset_x = 356 hacky_offset_y = 96.5 elif rot_angle == 180: hacky_offset_x = 260 hacky_offset_y = 452 elif rot_angle == 270 or rot_angle == -90: hacky_offset_x = -96.5 hacky_offset_y = 356 else: hacky_offset_x = 0 hacky_offset_y = 0 self.add(manyslits, origin=(-(i * (array_width + array_spacing)) / 2 + hacky_offset_x, -(j + 1.5) * (array_height + array_spacing) / 2 + hacky_offset_y), rotation=rot_angle)
def make_arm(self, width, length, layer, cell_name='branch'): cell = Cell(cell_name) line = Path([[0, 0], [length, 0]], width=width, layer=layer) cell.add(line) return cell
def add_contacts(self, pad_size, finger_width, finger_length, layers): contact_frames = [2, 4, 6, 8] spacing = pad_size / 2 for frame in contact_frames: frame_length = (10 - frame) * 1000 n_cont = int((frame_length) / (pad_size + spacing)) - 1 corner_pos = pad_size / 2 contact_pads = Cell('Contact_Pads') pad = Rectangle((-corner_pos, -corner_pos), (corner_pos, corner_pos), layer=layers) pad_cell = Cell('Pad_Cell') pad_cell.add(pad) finger = Rectangle((-finger_width / 2, -finger_length / 2), (finger_width / 2, finger_length / 2), layer=layers) finger_cell = Cell('Finger Cell') finger_cell.add(finger) curr_x = (10000 - ((n_cont - 1) * (pad_size + spacing))) / 2 curr_y = (10000 - frame_length) / 2 pad_array = CellArray(pad_cell, n_cont, 1, (pad_size + spacing, pad_size + spacing), origin=(curr_x, curr_y)) finger_array_tr = CellArray( finger_cell, n_cont, 1, (pad_size + spacing, pad_size + spacing), origin=(curr_x - pad_size / 2 + finger_width, curr_y + corner_pos + finger_length / 2)) finger_array_tl = CellArray( finger_cell, n_cont, 1, (pad_size + spacing, pad_size + spacing), origin=(curr_x + pad_size / 2 - finger_width, curr_y + corner_pos + finger_length / 2)) finger_array_br = CellArray( finger_cell, n_cont, 1, (pad_size + spacing, pad_size + spacing), origin=(curr_x - pad_size / 2 + finger_width, curr_y - corner_pos - finger_length / 2)) finger_array_bl = CellArray( finger_cell, n_cont, 1, (pad_size + spacing, pad_size + spacing), origin=(curr_x + pad_size / 2 - finger_width, curr_y - corner_pos - finger_length / 2)) contact_pads.add(pad_array) if frame < 8: contact_pads.add(finger_array_tr) contact_pads.add(finger_array_tl) if frame > 2: contact_pads.add(finger_array_br) contact_pads.add(finger_array_bl) for block in self.blocks: block.add(contact_pads) block.add(contact_pads, origin=(10000, 0), rotation=90) block.add(contact_pads, origin=(10000, 10000), rotation=180) block.add(contact_pads, origin=(0, 10000), rotation=270)
def make_theory_cell(wafer_orient='111'): ''' Makes the theory cell and returns ir as a cell''' # Growth Theory Slit Elongation pitch = [1.0] lengths = list(np.logspace(-3, 0, 20) * 8.0) # Logarithmic widths = [0.020, 0.040, 0.080, 0.140, 0.220] TheorySlitElong = Cell('LenWidthDependence') arrayHeight = 20. arraySpacing = 30. spacing = 10. TheorySlitElong.add( makeSlitArray(pitch, spacing, widths[0], lengths, 0., arrayHeight, arraySpacing, l_smBeam)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[1], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -30)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[2], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -60)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[3], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -90)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[4], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -120)) # Length Dependence LenWidDep = Cell('LenWidDependence') pitch = [1.0] lengths = list(np.logspace(-3, 0, 10) * 8.0) # Logarithmic widths = [0.040, 0.080, 0.140] arrayHeight = 20. arrayWidth = arrayHeight arraySpacing = 30. spacing = 0.5 for i, length in enumerate(lengths): for j, width in enumerate(widths): LenWidDep.add(makeSlitArray3(pitch, spacing, width, length, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(i * 30, j * 30)) # Make rotating slits wheel1 = Cell('RotDependence_LongSlits') wheel1.add( make_rotating_slits(5, 0.040, 361, 6. * 5, l_smBeam, angle_ref=wafer_orient)) wheel1.add(make_rotating_slits(5, 0.040, 433, 7.2 * 5, l_smBeam)) wheel1.add(make_rotating_slits(5, 0.040, 505, 8.4 * 5, l_smBeam)) wheel2 = Cell('RotDependence_ShortSlits') wheel2.add( make_rotating_slits(2, 0.040, 201, 6. * 2, l_smBeam, angle_ref=wafer_orient)) for i in range(10): # number of concentric rings to make wheel2.add( make_rotating_slits(2, 0.040, 201, (7.2 + i * 1.2) * 2, l_smBeam)) # Pitch Dependence PitchDep = Cell('PitchDependence') # pitches = list(np.round(np.logspace(-1, 1, 10), 1)) # Logarithmic pitches = [0.500, 1.000, 2.000, 4.000] widths = [0.020, 0.040, 0.080, 0.140, 0.220, 0.320] length = [20.] arrayHeight = 20. arrayWidth = arrayHeight arraySpacing = 30. spacing = 0.5 for j, width in enumerate(widths): for i, pitch in enumerate(reversed(pitches)): PitchDep.add(makeSlitArray2(pitch, spacing, width, length, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(j * 30, i * 30)) # Make arrays of various shapes manyshapes = make_many_shapes( 20, [0.005, 0.01, 0.015, 0.02], 0.75, ['Hexagons', 'Circles', 'Tris_left', 'Tris_right'], l_smBeam) TopCell = Cell('GrowthTheoryTopCell') TopCell.add(wheel1, origin=(-170., -50.)) TopCell.add(wheel2, origin=(-70., -50.)) TopCell.add(PitchDep, origin=(-200., -280.)) TopCell.add(TheorySlitElong, origin=(-250., 75.)) TopCell.add(LenWidDep, origin=(-200., -50.)) TopCell.add(manyshapes, origin=(0, -30)) # TODO: Add the branched growth shapes return TopCell
def makeSlitArray2(pitches, spacing, widths, lengths, rotAngle, arrayHeight, arrayWidth, arraySpacing, layers): ''' Give it a single pitch and lengths/widths and it will generate an array for all the combinations Makes seperate frame for each length value ''' 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") pitch = pitches[0] for length in lengths: 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 membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}_l{:.0f}'.format( width * 1000, length * 1000)) membrane_cell.add(membrane) slit = Cell("Slits") slit.add(membrane_cell, rotation=rotAngle) if Nx <= 1: slits = CellArray(slit, Nx, Ny, (length, pitchV)) slits.translate((0, -(Ny - 1) * (pitchV) / 2.)) else: 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), 2, layer=l_smBeam) 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 makeShape_Window(frame_pitch, buffer_pitch, length, width, layer): """ Makes window-shaped branched structures for quantum transport experiments :param frame_pitch: Center-to-center distance between slits in the window :param buffer_pitch: Center-to-center distance between the buffer membranes :param length: Length of the crossing slits :param width: Width of the slits :param n_buffers: Number of slits to put around (buffer) the crossing slits :param layer: GDS layer to put the pattern on :return: Cell with the desired pattern on it """ dx_big = frame_pitch / 2. / np.tan(np.deg2rad(60)) dy_big = frame_pitch / 2. dx_small = buffer_pitch / np.tan(np.deg2rad(60)) dy_small = buffer_pitch longline = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) x_dist = frame_pitch / np.sin(np.deg2rad(60)) long_slit = Cell('LongSlit') long_slit.add(longline) windowShape = Cell('WindowShape') windowShape.add(long_slit, origin=(-dx_big, -dy_big)) windowShape.add(long_slit, origin=(dx_big, dy_big)) windowShape.add(long_slit, origin=(-3 * dx_big, -3 * dy_big)) windowShape.add(long_slit, origin=(3 * dx_big, 3 * dy_big)) windowShape.add(long_slit, origin=(-x_dist / 2., 0), rotation=60) windowShape.add(long_slit, origin=(x_dist / 2., 0), rotation=60) windowShape.add(long_slit, origin=(-3 * x_dist / 2., 0), rotation=60) windowShape.add(long_slit, origin=(3 * x_dist / 2., 0), rotation=60) n_buffers = int(frame_pitch / buffer_pitch) - 1 buffers = Cell("WindowBuffers") if n_buffers <= 0: return windowShape shortline = Path([(-x_dist / 2. + buffer_pitch, 0), (x_dist / 2. - buffer_pitch, 0)], width=width, layer=layer) short_slit = Cell('ShortSlit') short_slit.add(shortline) if n_buffers % 2 == 1: # odd number of buffer slits buffers.add(shortline) n_buffers -= 1 for i in range(n_buffers // 2): buffers.add(short_slit, origin=(dx_big - (i + 1) * dx_small, dy_big - (i + 1) * dy_small)) buffers.add(short_slit, origin=(-dx_big + (i + 1) * dx_small, -dy_big + (i + 1) * dy_small)) bufferRow = Cell("BufferRow") len_buffer = x_dist - 2 * buffer_pitch v1 = (x_dist / 2. + buffer_pitch + len_buffer / 2., 0) bufferRow.add(buffers) bufferRow.add(buffers, origin=(v1[0], v1[1])) bufferRow.add(buffers, origin=(-v1[0], -v1[1])) v2 = (2 * dx_big, 2 * dy_big) windowShape.add(bufferRow) windowShape.add(bufferRow, origin=(v2[0], v2[1])) windowShape.add(bufferRow, origin=(-v2[0], -v2[1])) windowShape.add(bufferRow, origin=(2 * v2[0], 2 * v2[1])) windowShape.add(bufferRow, origin=(-2 * v2[0], -2 * v2[1])) bufferCol = Cell("BufferCol") bufferCol.add(buffers) bufferCol.add(buffers, origin=(v2[0], v2[1])) bufferCol.add(buffers, origin=(-v2[0], -v2[1])) bufferCol.add(buffers, origin=(2 * v2[0], 2 * v2[1])) bufferCol.add(buffers, origin=(-2 * v2[0], -2 * v2[1])) windowShape.add(bufferCol, origin=(2 * v1[0], 2 * v1[1])) windowShape.add(bufferCol, origin=(-2 * v1[0], -2 * v1[1])) return windowShape
def makeShape_Triangle(pitch, length, width, contactlength, n_outer_buf, layer): """ Makes triangle shape :param pitch: pitch of nanomembranes :param length: length of triangle side :param width: width of the membranes :param contactlength: length of membrane coming from triangle to contact :param n_outer_buf: number of outer buffers to add :param layer: layer to write the structures in :return: cell with triangle shape in it """ triangleshape = Cell("TriangleShape") line = Cell('TriLine') height = length * np.sqrt(3.) / 2. pt1 = (-length / 2., 0) pt2 = (length / 2., 0) pt3 = (0, height) centroid = (np.mean([pt1[0], pt2[0], pt3[0]]), np.mean([pt1[1], pt2[1], pt3[1]])) tri_arm = Cell('TriangleArms') # Make the main triangle with contact area line_cell = Cell('LineCell') line = Path([(-length / 2. - contactlength, 0), (length / 2., 0)], width=width, layer=layer) line_cell.add(line) tri_arm.add(line_cell, origin=(0, 0)) n_inner_buf = int(centroid[1] / pitch) + 1 # Make the inner buffer triangles for i in range(1, n_inner_buf): line_cell = Cell('LineCell') slit_len = length - 2 * pitch / np.tan(np.deg2rad(30)) * i line = Path([(-slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) line_cell.add(line) tri_arm.add(line_cell, origin=(0, -i * pitch)) # Make the outer buffer membranes for i in range(1, n_outer_buf + 1): line_cell = Cell('LineCell') line = Path([(-length / 2. - contactlength - pitch / np.tan(np.deg2rad(30)) * i, 0), (length / 2. + pitch / np.tan(np.deg2rad(30)) * i - pitch / np.cos(np.deg2rad(30)) * (i + 1), 0)], width=width, layer=layer) line_cell.add(line) tri_arm.add(line_cell, origin=(0, i * pitch)) tri_arm_offcenter = Cell('TriArmOffCenter') tri_arm_offcenter.add(tri_arm, origin=centroid) triangleshape.add(tri_arm_offcenter, rotation=0) triangleshape.add(tri_arm_offcenter, rotation=120) triangleshape.add(tri_arm_offcenter, rotation=240) return triangleshape
def add_contacts(self, md_size_x, md_size_y, layers): smField_num_x = int((md_size_x) / sm_spacing - 1) smField_num_y = int((md_size_y) / sm_spacing - 1) corner_pos = pad_size / 2 finger_width = 20. finger_length = 80. n_cont_x = smField_num_x + 1 n_cont_y = smField_num_y + 1 contact_pads = Cell('Contact_Pads') pad = Rectangle((-corner_pos, -corner_pos), (corner_pos, corner_pos), layer=layers) pad_cell = Cell('Pad_Cell') pad_cell.add(pad) finger = Rectangle((-finger_width / 2, -finger_length / 2), (finger_width / 2, finger_length / 2), layer=layers) finger_cell = Cell('Finger Cell') finger_cell.add(finger) n_finger_x = n_cont_x - 1 n_finger_y = n_cont_y - 1 pad_array = CellArray(pad_cell, n_cont_x, n_cont_y, (sm_spacing, sm_spacing), origin=(0, 0)) finger_array1 = CellArray(finger_cell, n_finger_x, n_finger_y, (sm_spacing, sm_spacing), origin=(corner_pos - finger_width, corner_pos + finger_length / 2)) finger_array2 = CellArray( finger_cell, n_finger_x, n_finger_y, (sm_spacing, sm_spacing), origin=(sm_spacing - corner_pos + finger_width, sm_spacing - corner_pos - finger_length / 2)) finger_array3 = CellArray(finger_cell, n_finger_y, n_finger_x, (sm_spacing, sm_spacing), rotation=90, origin=((n_cont_x - 1) * sm_spacing - corner_pos - finger_length / 2, corner_pos - finger_width)) finger_array4 = CellArray( finger_cell, n_finger_y, n_finger_x, (sm_spacing, sm_spacing), rotation=90, origin=((n_cont_x - 2) * sm_spacing + corner_pos + finger_length / 2, sm_spacing - corner_pos + finger_width)) contact_pads.add(pad_array) contact_pads.add(finger_array1) contact_pads.add(finger_array2) contact_pads.add(finger_array3) contact_pads.add(finger_array4) center_x = -0.5 * ((n_cont_x - 1) * smField_size + (n_cont_x - 1) * pad_size) center_y = -0.5 * ((n_cont_y - 1) * smField_size + (n_cont_y - 1) * pad_size) self.add(contact_pads, origin=(center_x, center_y)) return smField_num_x, smField_num_y
def make_theory_cell(wafer_orient='111'): ''' Makes the theory cell and returns ir 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( makeSlitArray(pitch, spacing, widths[0], lengths, 0., arrayHeight, arraySpacing, l_smBeam)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[1], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -30)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[2], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -60)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[3], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -90)) TheorySlitElong.add(makeSlitArray(pitch, spacing, widths[4], lengths, 0., arrayHeight, arraySpacing, l_smBeam), origin=(0, -120)) # Length Dependence LenWidDep = Cell('LenWidDependence') pitch = [1.0] # lengths = list(np.logspace(-3, 0, 10) * 8.0) # Logarithmic lengths = [ 0.008, 0.037, 0.170, 0.370, 0.800, 1.300, 1.700, 2.700, 3.700, 8.000 ] 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(makeSlitArray3(pitch, spacing, width, length, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(i * 30, j * 30)) # Second length dependence with pitch 500nm pitch = [0.5] LenWidDep2 = Cell('LenWidDependence2') for i, length in enumerate(lengths): for j, width in enumerate(widths): LenWidDep2.add(makeSlitArray3(pitch, spacing, width, length, 0, arrayHeight, arrayWidth, arraySpacing, l_smBeam), origin=(i * 30, j * 30)) # Make rotating slits wheel1 = Cell('RotDependence_LongSlits') wheel1.add( make_rotating_slits(5, 0.044, 361, 6. * 5, l_smBeam, angle_ref=True)) wheel1.add(make_rotating_slits(5, 0.044, 433, 7.2 * 5, l_smBeam)) wheel1.add(make_rotating_slits(5, 0.044, 505, 8.4 * 5, l_smBeam)) wheel2 = Cell('RotDependence_ShortSlits') wheel2.add( make_rotating_slits(2, 0.044, 200, 6. * 2, l_smBeam, angle_ref=True)) for i in range(10): # number of concentric rings to make wheel2.add( make_rotating_slits(2, 0.044, 200, (7.2 + i * 1.2) * 2, l_smBeam)) # Pitch Dependence PitchDep = Cell('PitchDependence') pitches = list(np.round(np.logspace(-1, 1, 10), 1)) # Logarithmic length = [3.] widths = [0.054, 0.044, 0.028, 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(makeSlitArray2(pitch, spacing, width, length, 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) TopCell = Cell('GrowthTheoryTopCell') TopCell.add(wheel1, origin=(-100., -100.)) TopCell.add(wheel2, origin=(0., -100.)) TopCell.add(PitchDep, origin=(-200., -350.)) TopCell.add(TheorySlitElong, origin=(-250., -50)) TopCell.add(LenWidDep, origin=(-200., -50.)) TopCell.add(LenWidDep2, origin=(-200., 50.)) TopCell.add(hexagon_array, origin=(-100., -40)) TopCell.add(circles_array, origin=(-75., -40.)) TopCell.add(triangle_down_array, origin=(-50., -40)) TopCell.add(triangle_up_array, origin=(-25., -40)) # TODO: Add the branched growth shapes return TopCell
def add_block_labels(self, layers, unique_ids=False, save_ids=True, load_ids=True): if type(layers) is not list: layers = [layers] txtSize = 1000 blockids = [] if not unique_ids: for (i, pt) in enumerate(self.block_pts): blockids.append(self.blockcols[pt[0]] + self.blockrows[pt[1]]) else: existing_ids = {} existing_id_set = set() # Load the previously-used IDs from a JSON file if load_ids: master_db = '../../../ChipIDs_DB.json' if os.path.isfile(master_db): with open(master_db, 'r') as f: try: existing_ids = json.load(f) existing_id_set = set([ item for sublist in list(existing_ids.values()) for item in sublist ]) # Check if wafer is in the loaded database if load_ids and WAFER_ID in existing_ids: blockids = existing_ids[WAFER_ID] # If there is a reading error then proceed with a warning except json.decoder.JSONDecodeError: print( "Json Error: Couldn't load chip IDs from database!" ) existing_id_set = set() # If the IDs haven't already been set by loading them from the database if not blockids: # Generate some new IDs, but only use the ones that haven't previously been used unique_label_string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' possible_label_set = set([ "".join(x) for x in itertools.product(unique_label_string, repeat=2) ]) possible_label_set = possible_label_set - existing_id_set # Remove chip lbls from the set of possible lbls blockids_set = set() while len(blockids_set) < len(self.blocks): blockids_set.add(random_choice(list(possible_label_set))) blockids = list(blockids_set) # Save the labels to a file if save_ids: existing_ids.update({WAFER_ID: blockids}) json_string = json.dumps(existing_ids) json_string = json_string.replace( "], ", "],\n") # Make the file a bit easier to read in notepad with open(master_db, 'w') as f: f.write(json_string) # Write the labels to the cells for i, block in enumerate(self.blocks): blocklabel = Cell('LBL_B_' + blockids[i]) for l in layers: txt = Label(blockids[i], txtSize, layer=l) bbox = txt.bounding_box offset = (0, 0) txt.translate(-np.mean(bbox, 0)) # Center text around origin txt.translate(offset) # Translate it to bottom of wafer blocklabel.add(txt) block.add(blocklabel, origin=(self.block_size[0] / 2., self.block_size[1] / 2. - 400))
def make_slit_array(x_vars, y_vars, stat_vars, var_names, spacing, rot_angle, array_height, array_width, array_spacing, layers): if len(var_names) != 3: raise Exception('Error! Need to have three variable names.') if not (type(layers) == list): layers = [layers] if not (type(x_vars) == list): x_vars = [x_vars] if not (type(y_vars) == list): y_vars = [y_vars] if not (type(stat_vars) == list): stat_vars = [stat_vars] x_var_name = var_names[0] y_var_name = var_names[1] stat_var_name = var_names[2] for l in layers: j = -1 manyslits = Cell("SlitArray") for x_var in x_vars: j += 1 i = -1 for y_var in y_vars: i += 1 if i % 3 == 0: j += 1 # Move to array to next line i = 0 # Restart at left var_dict = { x_var_name: x_var, y_var_name: y_var, stat_var_name: stat_vars[0] } pitch = var_dict['pitch'] width = var_dict['width'] length = var_dict['length'] pitch_v = pitch / np.cos(np.deg2rad(rot_angle)) # widthV = width / np.cos(np.deg2rad(rotAngle)) n_x = int(array_width / (length + spacing)) n_y = int(array_height / pitch_v) # Define the slits slit = Cell("Slits") rect = Rectangle((-length / 2., -width / 2.), (length / 2., width / 2.), layer=l) rect = rect.copy().rotate(rot_angle) slit.add(rect) slits = CellArray(slit, n_x, n_y, (length + spacing, pitch_v)) slits.translate((-(n_x - 1) * (length + spacing) / 2., -(n_y - 1) * pitch_v / 2.)) slit_array = Cell("SlitArray") slit_array.add(slits) text = Label('w/p/l\n%i/%i/%i' % (width * 1000, pitch * 1000, length * 1000), 2, layer=l_smBeam) lbl_vert_offset = 1.35 if j % 2 == 0: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, -array_height / lbl_vert_offset))) ) # Center justify label else: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, array_height / lbl_vert_offset))) ) # Center justify label slit_array.add(text) manyslits.add(slit_array, origin=((array_width + array_spacing) * i, (array_height + 2. * array_spacing) * j - array_spacing / 2.)) return manyslits
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, layer=l_smBeam) 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 makeShape_ABHexagon(pitch, length, width, contactlength, n_outer_buf, layer): """ Makes Aharonov Bohm hexagon shape :param pitch: pitch of nanomembranes :param length: hexagon side length :param width: width of the membranes :param contactlength: length of membrane coming from triangle to contact :param n_outer_buf: number of outer buffers to add :param layer: layer to write the structures in :return: cell with triangle shape in it """ hexagonshape = Cell("HexagonShape") line = Cell('HexagonLine') height = length * np.sqrt(3.) / 2. pt1 = (-length / 2., 0) pt2 = (length / 2., 0) shape_half = Cell('HexagonShapeHalf') # Make the main quadrilateral with contact area line_cell = Cell('LineCell') contactline_cell = Cell('ContactLineCell') line = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) contactline = Path([(-length / 2., 0), (length / 2. + contactlength, 0)], width=width, layer=layer) line_cell.add(line) contactline_cell.add(contactline) shape_half.add(line_cell, origin=(-3 * length / 4., height / 2.), rotation=60) shape_half.add(line_cell, origin=(3 * length / 4., height / 2.), rotation=-60) shape_half.add(contactline_cell, origin=(0, height)) n_inner_buf = int(height / pitch) + 1 # Make the inner buffer hexagons for i in range(1, n_inner_buf): line_cell = Cell('LineCell') slit_len = length - 2 * pitch / np.sqrt(3) * i line = Path([(-slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) line_cell.add(line) shape_half.add(line_cell, origin=(-3 * slit_len / 4., (height - (i * pitch)) / 2.), rotation=60) shape_half.add(line_cell, origin=(3 * slit_len / 4., (height - (i * pitch)) / 2.), rotation=-60) shape_half.add(line_cell, origin=(0, height - (i * pitch))) # Make the outer buffer membranes for i in range(1, n_outer_buf + 1): line_cell = Cell('LineCell') contactline_cell = Cell('ContactLineBuffer') shortline_cell = Cell('ShortLineBuffer') slit_len = length + 2 * pitch / np.sqrt(3) * i line = Path([(-slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) shortline = Path([(2 * pitch / np.sqrt(3) * (i + 1) - slit_len / 2., 0), (slit_len / 2., 0)], width=width, layer=layer) contactline = Path([(-slit_len / 2., 0), (slit_len / 2. + contactlength, 0)], width=width, layer=layer) line_cell.add(line) contactline_cell.add(contactline) shortline_cell.add(shortline) shape_half.add(line_cell, origin=(-3 * slit_len / 4., (height + (i * pitch)) / 2.), rotation=60) shape_half.add(shortline_cell, origin=(3 * slit_len / 4., (height + (i * pitch)) / 2.), rotation=-60) shape_half.add(contactline_cell, origin=(0, height + (i * pitch))) hexagonshape.add(shape_half, rotation=0) hexagonshape.add(shape_half, rotation=180) return hexagonshape
def make_slit_array(self, _pitches, spacing, _widths, _lengths, rot_angle, array_height, array_width, 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] manyslits = i = j = None for l in layers: i = -1 j = -1 manyslits = Cell("SlitArray") pitch = _pitches[0] for length in _lengths: 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 nx = int(array_width / (length + spacing)) ny = int(array_height / pitch) # Define the slits slit = Cell("Slits") rect = Rectangle((-length / 2., -width / 2.), (length / 2., width / 2.), layer=l) slit.add(rect) slits = CellArray(slit, nx, ny, (length + spacing, pitch)) slits.translate((-(nx - 1) * (length + spacing) / 2., -(ny - 1) * pitch / 2.)) slit_array = Cell("SlitArray") slit_array.add(slits) text = Label('w/p/l\n%i/%i/%i' % (width * 1000, pitch, length), 5, layer=l) lbl_vertical_offset = 1.35 if j % 2 == 0: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, -array_height / lbl_vertical_offset)) )) # Center justify label else: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((0, array_height / lbl_vertical_offset )))) # Center justify label slit_array.add(text) manyslits.add( slit_array, origin=((array_width + array_spacing) * i, (array_height + 2. * array_spacing) * j - array_spacing / 2.)) # This is an ugly hack to center rotated slits, should fix this properly... hacky_offset_x = 200 if rot_angle == 45 else 0 # TODO: fix this ugly thing hacky_offset_y = -25 if rot_angle == 45 else 0 self.add(manyslits, origin=(-i * (array_width + array_spacing) / 2 + hacky_offset_x, -(j + 1.5) * (array_height + array_spacing) / 2 + hacky_offset_y), rotation=rot_angle)
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, layer=l_smBeam) 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