def make_slits_reservoir(self, nslit, pitch, width, contact_distance, layers): # 5 additional slits as material reservoir res_slit = 5 gap = contact_distance + 2. + 2. res_length = (length - gap - 2.5*margin)/2 res_width = width res_pitch = pitch resField = Cell("resField") reservoir = Cell("Single Reservoir") res_path = Path([(-res_length / 2., 0), (res_length / 2., 0)], width = res_width, layer = layers) reservoir.add(res_path) reservoirs= CellArray(reservoir, 2, res_slit, spacing = (res_length + gap, res_pitch)) reservoirs.translate((-(res_length + gap)/2,0)) res_array = Cell("Multiple Slit") res_array.add(reservoirs) resField.add(res_array, origin=(0,0), rotation=rot_angle) if contact_distance > margin: add_slit = Cell("Additional Reservoir") add_res_path = Path([(-(contact_distance - 0.8*margin) / 2., 0), ((contact_distance - 0.8*margin) / 2., 0)], width = res_width, layer = layers) add_slit.add(add_res_path) add_reservoir = CellArray(add_slit, 1, res_slit, spacing = (0, res_pitch)) add_reservoir.translate((0,0)) add_res_array = Cell("Additional Multiple Slit") add_res_array.add(add_reservoir) resField.add(add_res_array, origin=(0,0), rotation=rot_angle) self.add(resField, origin= (0,(nslit+1) * pitch/2 )) self.add(resField, origin= (0, -((nslit+1+(2*(res_slit-1))) * pitch/2 )))
def make_rotating_slits(length, width, N, radius, layers, angle_ref=None, angle_sweep=360): """ :param length: Length of the slits in the circle :param width: Width of the slits in the circle :param N: Number of slits going around the circle :param radius: Radius of the circle :param layers: Layers to write the slits in :param angle_ref: if None, no angle reference lines are added. If '111' then add reference lines at 30/60 degrees. If '100' then add reference lines at 45/90 degrees. :return: """ cell = Cell('RotatingSlits') if not (type(layers) == list): layers = [layers] allslits = Cell('All Slits') angles = np.linspace(0, angle_sweep, N) # radius = length*12. translation = (radius, 0) for l in layers: # rect = Rectangle(pt1, pt2, layer=l) membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) slit = Cell("Slit") slit.add(membrane_cell, origin=translation) for angle in angles: allslits.add(slit, rotation=angle) cell.add(allslits) if angle_ref: labelCell = Cell('AngleLabels') lineCell = Cell('Line') pt1 = (-radius * 0.9, 0) pt2 = (radius * 0.9, 0) line = Path([pt1, pt2], width=width, layer=l) dLine = dashed_line(pt1, pt2, 2, width, l) lineCell.add(line) labelCell.add(lineCell, rotation=0) if angle_ref == '111': labelCell.add(lineCell, rotation=60) labelCell.add(lineCell, rotation=-60) labelCell.add(dLine, rotation=30) labelCell.add(dLine, rotation=90) labelCell.add(dLine, rotation=-30) elif angle_ref == '100': labelCell.add(lineCell, rotation=0) labelCell.add(lineCell, rotation=90) labelCell.add(dLine, rotation=45) labelCell.add(dLine, rotation=135) cell.add(labelCell) return cell
def makeShape_Star(pitch, length, width, n_buffers, layer): """ Makes star shaped branched structures for quantum transport experiments :param pitch: Center-to-center distance between slits :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 """ longline = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) shortline = Path([(0, 0), (length / 2., 0)], width=width, layer=layer) long_slit = Cell('LongSlit') long_slit.add(longline) short_slit = Cell('ShortSlit') short_slit.add(shortline) starShape = Cell('StarShape') starShape.add(long_slit, rotation=0) starShape.add(long_slit, rotation=-45) starShape.add(long_slit, rotation=45) if n_buffers <= 0: return starShape sideBufferNM = Cell('X_Buffer') sideBufferNM.add(short_slit, rotation=0) sideBufferNM.add(short_slit, rotation=90) allBuffers = Cell('X_AllBufferNMs') for i in range(n_buffers): allBuffers.add(sideBufferNM, origin=((i + 1) * pitch, (i + 1) * pitch)) starShape.add(allBuffers, rotation=45) starShape.add(allBuffers, rotation=225) smallBuffer = Cell('SmX_Buffer') for i in range(n_buffers): smallBuffer.add( short_slit, rotation=0, origin=((i + 1) * pitch * (1 + 2 * np.cos(np.deg2rad(45))), (i + 1) * pitch)) smallBuffer.add( short_slit, rotation=45, origin=((i + 1) * pitch * (1 + 2 * np.cos(np.deg2rad(45))), (i + 1) * pitch)) starShape.add(smallBuffer) starShape.add(smallBuffer, rotation=-45) starShape.add(smallBuffer, rotation=180) starShape.add(smallBuffer, rotation=135) return starShape
def processCheck_CleavingMark(self, yPosition, layers): if not (type(layers) == list): layers = [layers] for l in layers: pt1 = (100, yPosition) pt2 = (2000, yPosition) pt3 = (-1100, yPosition) pt4 = (-2800, yPosition) line1 = Path([pt1, pt2], width=10, layer=l) line2 = Path([pt3, pt4], width=10, layer=l) cMarkCell = Cell('Cleaving Mark') cMarkCell.add(line1) cMarkCell.add(line2) self.add(cMarkCell)
def add_cleave_xsection_nws(self): pitches = [0.5, 1., 2., 4.] widths = [10., 20., 40., 60., 100., 160., 240.] n_membranes = 10 length = 50 spacing = 10 cleave_xsection_cell = Cell("CleaveCrossSection") y_offset = 0 for pitch in pitches: for width in widths: nm_cell = Cell("P{:.0f}W{:.0f}".format(pitch, width)) slit = Path([(-length / 2., 0), (length / 2., 0)], width=width / 1000., layer=l_smBeam) nm_cell.add(slit) nm_cell_array = Cell("P{:.0f}W{:.0f}_Array".format(pitch, width)) tmp = CellArray(nm_cell, 1.0, n_membranes, [0, pitch]) nm_cell_array.add(tmp) cleave_xsection_cell.add(nm_cell_array, origin=(0, y_offset + pitch * n_membranes)) y_offset += pitch * n_membranes + spacing text = Label("P{:.1f}W{:.0f}".format(pitch, width), 1.0, layer=l_smBeam) text.translate(tuple(np.array(-text.bounding_box.mean(0)))) # Center justify label txt_cell = Cell("lbl_P{:.1f}W{:.0f}".format(pitch, width)) txt_cell.add(text) cleave_xsection_cell.add(txt_cell, origin=(length * 0.75, y_offset - 8.0)) cleave_xsection_cell.add(txt_cell, origin=(-length * 0.75, y_offset - 8.0)) y_offset += spacing * 3 center_x, center_y = (5000, 5000) for block in self.blocks: block.add(cleave_xsection_cell, origin=(center_x + 1150, center_y - 463)) # block.add(cleave_xsection_cell, origin=(center_x - 350, center_y + 350), rotation=45.) # >> VP_mod: disabled << block.add(cleave_xsection_cell, origin=(center_x + 463, center_y - 1150), rotation=90.) # >> VP_mod: disabled<<
def add_tem_membranes(self, widths, length, pitch, layer): tem_membranes = Cell('TEM_Membranes') n = 3 curr_y = 0 for width in widths: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) membrane_array = CellArray(membrane_cell, 1, n, (0, pitch)) membrane_array_cell = Cell('MembraneArray_w{:.0f}'.format(width * 1000)) membrane_array_cell.add(membrane_array) tem_membranes.add(membrane_array_cell, origin=(0, curr_y)) curr_y += n * pitch n2 = 5 tem_membranes2 = Cell('Many_TEM_Membranes') tem_membranes2.add( CellArray(tem_membranes, 1, n2, (0, n * len(widths) * pitch))) self.block_up.add(tem_membranes2, origin=(0, -2000)) # self.block_up.add(tem_membranes2, origin=(0, -1400), rotation=90) self.block_down.add(tem_membranes2, origin=(0, 2000))
def add_tem_membranes(self, widths, length, pitch, layer): tem_membranes = Cell('TEM_Membranes') n = 4 curr_y = 0 for width in widths: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) membrane_array = CellArray(membrane_cell, 1, n, (0, pitch)) membrane_array_cell = Cell('MembraneArray_w{:.0f}'.format(width * 1000)) membrane_array_cell.add(membrane_array) tem_membranes.add(membrane_array_cell, origin=(0, curr_y)) curr_y += n * pitch n2 = 3 tem_membranes2 = Cell('Many_TEM_Membranes') tem_membranes2.add( CellArray(tem_membranes, 1, n2, (0, n * len(widths) * pitch))) center_x, center_y = (5000, 5000) for block in self.blocks: block.add(tem_membranes2, origin=(center_x, center_y + 2000)) block.add(tem_membranes2, origin=(center_x, center_y + 1500), rotation=45)
def makeXShape(self, length, width, rotAngle, spacing, Nx, Ny, layers): if not (type(layers) == list): layers = [layers] slit = Cell("Slit") for l in layers: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) slit.add(membrane_cell) shape = Cell('Shapes') shape.add(slit, rotation=60) shape.add(slit, rotation=120) xspacing = (length + spacing) * np.cos(np.deg2rad(60)) yspacing = (length + spacing) * np.sin(np.deg2rad(60)) shapearray = CellArray(shape, Nx, Ny, (xspacing, yspacing), origin=(-(Nx * xspacing - spacing) / 2., -(Ny * yspacing - spacing) / 2.)) # shapearray2 = CellArray(shape, Nx, Ny/2,(xspacing,yspacing*2.),origin=(xspacing/2.-(Nx*xspacing-spacing)/2.,yspacing-(Ny*yspacing-spacing*np.tan(np.deg2rad(60)))/2.)) # shapearray = CellArray(shape, Nx, Ny,(xspacing,yspacing)) # shapearray.rotate(rotAngle) # shapearray.translate((-shapearray.bounding_box.mean(0)[0]/2.,-shapearray.bounding_box.mean(0)[1]/2.)) allshapes = Cell('All Shapes') allshapes.add(shapearray) # allshapes.add(shapearray2) # allshapes.add(shape) self.add(allshapes)
def add_tem_membranes(self, widths, length, pitch, layer): tem_membranes = Cell('TEM_Membranes') n = 5 curr_y = 0 for width in widths: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) membrane_array = CellArray(membrane_cell, 1, n, (0, pitch)) membrane_array_cell = Cell('MembraneArray_w{:.0f}'.format(width * 1000)) membrane_array_cell.add(membrane_array) tem_membranes.add(membrane_array_cell, origin=(0, curr_y)) curr_y += n * pitch n2 = 3 tem_membranes2 = Cell('Many_TEM_Membranes') tem_membranes2.add( CellArray(tem_membranes, 1, n2, (0, n * len(widths) * pitch))) # Add it in all the cells for (i, pt) in enumerate(self.block_pts): origin = (pt + np.array([0.5, 0.5])) * self.block_size self.add(tem_membranes2, origin=origin)
def make_arm(width, length, layer, cell_name='branch'): membrane = Path([(0, 0), (length, 0)], width=width, layer=layer) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) cell = Cell(cell_name) cell.add(membrane_cell) return cell
def add_cleave_xsection_nws(self): pitches = [1., 2., 4.] widths = [10., 15., 20., 30., 40., 50.] n_membranes = 10 length = 50 spacing = 10 cleave_xsection_cell = Cell("CleaveCrossSection") y_offset = 0 for pitch in pitches: for width in widths: nm_cell = Cell("P{:.0f}W{:.0f}".format(pitch, width)) slit = Path([(-length / 2., 0), (length / 2., 0)], width=width / 1000., layer=l_smBeam) nm_cell.add(slit) nm_cell_array = Cell("P{:.0f}W{:.0f}_Array".format(pitch, width)) tmp = CellArray(nm_cell, 1.0, n_membranes, [0, pitch]) nm_cell_array.add(tmp) cleave_xsection_cell.add(nm_cell_array, origin=(0, y_offset + pitch * n_membranes)) y_offset += pitch * n_membranes + spacing y_offset += spacing * 3 center_x, center_y = (5000, 5000) for block in self.blocks: block.add(cleave_xsection_cell, origin=(center_x + 1150, center_y - 340)) block.add(cleave_xsection_cell, origin=(center_x - 500, center_y + 500), rotation=45.) block.add(cleave_xsection_cell, origin=(center_x + 340, center_y - 1150), rotation=90.)
def makeYShapes(self, length, width, rotAngle, spacing, Nx, Ny, layers): if not (type(layers) == list): layers = [layers] slit = Cell("Slit") for l in layers: membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) slit.add(membrane_cell) shape = Cell('Shapes') shape.add(slit, rotation=0 + rotAngle) shape.add(slit, rotation=120 + rotAngle) shape.add(slit, rotation=240 + rotAngle) # CellArray(slit, Nx, Ny,(length + spacing, pitchV)) xspacing = length + spacing yspacing = (length + spacing) * np.sin(np.deg2rad(60)) shapearray = CellArray( shape, Nx, Ny / 2, (xspacing, yspacing * 2.), origin=(-(Nx * xspacing - spacing) / 2., -(Ny * yspacing - spacing * np.sin(np.deg2rad(60))) / 2.)) shapearray2 = CellArray( shape, Nx, Ny / 2, (xspacing, yspacing * 2.), origin=(xspacing / 2. - (Nx * xspacing - spacing) / 2., yspacing - (Ny * yspacing - spacing * np.sin(np.deg2rad(60))) / 2.)) allshapes = Cell('All Shapes') allshapes.add(shapearray) allshapes.add(shapearray2) self.add(allshapes)
def makeShape_X(pitch, length, width, n_buffers, layer): """ Makes X shaped branched structures for quantum transport experiments :param pitch: Center-to-center distance between slits :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 """ longline = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=layer) shortline = Path([(0, 0), (length / 2., 0)], width=width, layer=layer) long_slit = Cell('LongSlit') long_slit.add(longline) short_slit = Cell('ShortSlit') short_slit.add(shortline) xShape = Cell('XShape') xShape.add(long_slit, rotation=60) xShape.add(long_slit, rotation=120) if n_buffers <= 0: return xShape sideBufferNM = Cell('X_SideBufferNM') sideBufferNM.add(short_slit, rotation=60) sideBufferNM.add(short_slit, rotation=-60) topBufferNM = Cell('X_TopBufferNM') topBufferNM.add(short_slit, rotation=60) topBufferNM.add(short_slit, rotation=120) for i in range(n_buffers): xShape.add(sideBufferNM, origin=((i + 1) * pitch / np.sin(np.deg2rad(60)), 0)) xShape.add(sideBufferNM, origin=(-(i + 1) * pitch / np.sin(np.deg2rad(60)), 0), rotation=180) xShape.add(topBufferNM, origin=(0, (i + 1) * pitch / np.cos(np.deg2rad(60)))) xShape.add(topBufferNM, origin=(0, -(i + 1) * pitch / np.cos(np.deg2rad(60))), rotation=180) return xShape
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_branch(length, width, layers, rot_angle=0): slit = Cell("Slit") for l in layers: membrane = Path([(0, 0), (length, 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) slit.add(membrane_cell) branch = Cell('Branch-{:.0f}/{:.2f}-wl'.format(width, length)) branch.add(slit, rotation=0 + rot_angle) # branch.add(slit, rotation=90 + rot_angle) branch.add(slit, rotation=180 + rot_angle) branch.add(slit, rotation=270 + rot_angle) return branch
def make_rotating_branches(length, width, N, radius, layers, angle_sweep=360, angle_ref=False, angle_offset=0): cell = Cell('RotatingBranches') if not (type(layers) == list): layers = [layers] allslits = Cell('All Slits') angles = np.linspace(0, angle_sweep, N) translation = (radius, 0) pt1 = np.array((-length / 2., -width / 2.)) + translation pt2 = np.array((length / 2., width / 2.)) + translation branch = make_branch(length, width, layers) for element in branch.elements: element.origin = [radius, 0] for angle in angles: allslits.add(branch.copy(), rotation=angle_offset + angle) cell.add(allslits) for l in layers: if angle_ref: labelCell = Cell('AngleLabels') lineCell = Cell('Line') pt1 = (0, 0) pt2 = (radius * 0.9, 0) line = Path([pt1, pt2], width=width, layer=l) dLine = dashed_line(pt1, pt2, 2, width, l) lineCell.add(line) rot_angle = 0 while True: if abs(rot_angle) > abs(angle_sweep): break if abs(rot_angle) % 60 == 0: labelCell.add(lineCell, rotation=rot_angle) if (abs(rot_angle) - 30) % 60 == 0: labelCell.add(dLine, rotation=rot_angle) rot_angle += np.sign(angle_sweep) * 15 cell.add(labelCell) return cell
def make_rotating_slits(length, width, N, radius, layers, angle_sweep=360, angle_ref=False): cell = Cell('RotatingSlits') if not (type(layers) == list): layers = [layers] allslits = Cell('All Slits') angles = np.linspace(0, angle_sweep, N) # radius = length*12. translation = (radius, 0) pt1 = np.array((-length / 2., -width / 2.)) + translation pt2 = np.array((length / 2., width / 2.)) + translation slit = Cell("Slit") for l in layers: rect = Rectangle(pt1, pt2, layer=l) slit.add(rect) for angle in angles: allslits.add(slit.copy(), rotation=angle) cell.add(allslits) for l in layers: if angle_ref: label_cell = Cell('AngleLabels') line_cell = Cell('Line') pt1 = (0, 0) pt2 = (radius * 0.9, 0) line = Path([pt1, pt2], width=width, layer=l) d_line = dashed_line(pt1, pt2, 2, width, l) line_cell.add(line) rot_angle = 0 while True: if abs(rot_angle) > abs(angle_sweep): break if abs(rot_angle) % 60 == 0: label_cell.add(line_cell, rotation=rot_angle) if (abs(rot_angle) - 30) % 60 == 0: label_cell.add(d_line, rotation=rot_angle) rot_angle += np.sign(angle_sweep) * 15 cell.add(label_cell) return cell
def make_slits(self, length, width, nslit, pitch, rot_angle, layers): """ Define a single slit or a slit array with a given length, width and pitch """ slitField = Cell("slitField") slit = Cell("Single Slit") slit_path = Path([(-length / 2., 0), (length / 2., 0)], width = width, layer = layers) slit.add(slit_path) if nslit == 1: slitField.add(slit, origin=(0,0), rotation=rot_angle) elif nslit > 1: slits = CellArray(slit, 1, nslit, (0,pitch)) slits.translate((0, -(nslit-1) * pitch / 2.)) slit_array = Cell("Multiple Slit") slit_array.add(slits) slitField.add(slit_array, origin=(0,0), rotation=rot_angle) else: print("Error in the number of slits. Check the internal code"*50) quit() self.add(slitField)
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 makeShape_HashTag(hashtag_pitch, buffer_pitch, length, width, layer): """ Makes hashtag-shaped branched structures for quantum transport experiments :param hashtag_pitch: Center-to-center distance between slits in the hashtag :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 = hashtag_pitch / 2. / np.tan(np.deg2rad(60)) dy_big = hashtag_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 = hashtag_pitch / np.sin(np.deg2rad(60)) long_slit = Cell('LongSlit') long_slit.add(longline) hashtagShape = Cell('HashtagShape') hashtagShape.add(long_slit, origin=(-dx_big, -dy_big)) hashtagShape.add(long_slit, origin=(dx_big, dy_big)) hashtagShape.add(long_slit, origin=(-x_dist / 2., 0), rotation=60) hashtagShape.add(long_slit, origin=(x_dist / 2., 0), rotation=60) n_buffers = int(hashtag_pitch / buffer_pitch) - 1 if n_buffers <= 0: return hashtagShape 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) buffers = Cell("HashtagBuffers") 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)) # There is definitely a sexier way of implementing the buffers on the outside of the hashtag... # This is a bit of a hacky quick fix, not so elegant as the buffers extend out too much usually... bufferRow = Cell("BufferRow") len_buffer = x_dist - 2 * buffer_pitch bufferRow.add(buffers) bufferRow.add(buffers, origin=(x_dist / 2. + buffer_pitch + len_buffer / 2., 0)) bufferRow.add(buffers, origin=(-x_dist / 2. - buffer_pitch - len_buffer / 2., 0)) hashtagShape.add(bufferRow) hashtagShape.add(bufferRow, origin=(2 * dx_big, 2 * dy_big)) hashtagShape.add(bufferRow, origin=(-2 * dx_big, -2 * dy_big)) return hashtagShape
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 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 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 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 nm_cell = Cell("P{:.0f}W{:.0f}".format(pitch, width)) slit = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l_smBeam) nm_cell.add(slit) slits = CellArray(nm_cell, 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... 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 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 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 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('Slit_w{:.0f}_l{:.0f}_r{:.0f}'.format( width * 1000, length * 1000, rotAngle)) slit.add(membrane_cell, rotation=rotAngle) slits = CellArray(membrane_cell, 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
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 # widthV = width / np.cos(np.deg2rad(rotAngle)) Nx = int(arrayWidth / (length + spacing)) Ny = int(arrayHeight / (pitchV)) # Define the slits slit = Cell("Slits") line = Path([[-length / 2., 0], [length / 2., 0]], width=width, layer=l) slit.add(line) 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), 1, layer=l_smBeam) lblVertOffset = 1.5 if j % 2 == 0: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((arrayWidth / 2., -arrayHeight / lblVertOffset)))) # Center justify label else: text.translate( tuple( np.array(-text.bounding_box.mean(0)) + np.array((arrayWidth / 2., arrayHeight / lblVertOffset)))) # Center justify label slitarray.add(text) manyslits.add( slitarray, origin=((arrayWidth + arraySpacing) * i, (arrayHeight + arraySpacing) * j - arraySpacing)) 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 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 membrane = Path([(-length / 2., 0), (length / 2., 0)], width=width, layer=l) membrane_cell = Cell('Membrane_w{:.0f}'.format(width * 1000)) membrane_cell.add(membrane) slit.add(membrane_cell, origin=translation, rotation=rotAngle) 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_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 make_slits_reservoir( self, length, width, nslit, pitch, contact_distance, layers): # 5 additional slits as material reservoir res_slit = 5 slit_margin = 0.5 res_width = width res_pitch = pitch resField = Cell("resField") # Outer reservoir outer_res = Cell("Outer Reservoir") out_res_length = (margin - fing_width - slit_margin) outer_res_path = Path([(-out_res_length / 2, 0), (out_res_length / 2, 0)], width=res_width, layer=layers) outer_res.add(outer_res_path) out_gap = length - margin + slit_margin out_x_spac = (out_res_length + out_gap) / np.cos(rad_angle) out_y_spac = res_pitch out_reservoirs = CellArray(outer_res, 2, res_slit, spacing=(out_x_spac, out_y_spac)) out_x_transl = -(out_res_length + out_gap) / ( 2 * np.cos(rad_angle)) + (slit_margin) * np.sin(rad_angle) out_reservoirs.translate((out_x_transl, 0)) out_res_array = Cell("Multiple Slit") out_res_array.add(out_reservoirs) resField.add(out_res_array, origin=(0, 0), rotation=rot_angle) # Main reservoir reservoir = Cell("Single Reservoir") res_length = fake_slit_length res_path = Path([(-res_length / 2., 0), (res_length / 2., 0)], width=res_width, layer=layers) reservoir.add(res_path) gap = contact_distance + 2 * (slit_margin + fing_width) x_spac = (res_length + gap) / np.cos(rad_angle) y_spac = res_pitch reservoirs = CellArray(reservoir, 2, res_slit, spacing=(x_spac, y_spac)) x_transl = -(res_length + gap) / (2 * np.cos(rad_angle)) + ( slit_margin) * np.sin(rad_angle) reservoirs.translate((x_transl, 0)) res_array = Cell("Multiple Slit") res_array.add(reservoirs) resField.add(res_array, origin=(0, 0), rotation=rot_angle) # Inner reservoir if contact_distance > slit_margin: add_slit = Cell("Additional Reservoir") add_res_path = Path([(-(contact_distance - 0.5) / 2., 0), ((contact_distance - 0.5) / 2., 0)], width=res_width, layer=layers) add_slit.add(add_res_path) add_reservoir = CellArray(add_slit, 1, res_slit, spacing=(0, res_pitch)) add_reservoir.translate((0, 0)) add_res_array = Cell("Additional Multiple Slit") add_res_array.add(add_reservoir) resField.add(add_res_array, origin=(0, 0), rotation=rot_angle) self.add(resField, origin=(0, (nslit + 1) * pitch / 2) / np.cos(rad_angle)) self.add(resField, origin=(0, -((nslit + 1 + (2 * (res_slit - 1))) * pitch / 2) / np.cos(rad_angle)))