def _get_splitting_elem(self): pos_in = self.instances["in"].ports["out"].position pos_out_1 = self.instances["out1"].ports["in"].position pos_out_2 = self.instances["out2"].ports["in"].position wg_width = self.wg_template.core_width waypoint_shape_top = i3.Shape(points=[ pos_in + i3.Coord2(0, wg_width / 2), pos_in + i3.Coord2(self.small_straights, wg_width / 2), self.waypoint, pos_out_2 + i3.Coord2(-self.small_straights, +wg_width / 2), pos_out_2 + i3.Coord2(0, +wg_width / 2) ]) shape_top = SplinedShape(waypoint_shape=waypoint_shape_top, resolution=0.05) shape_top_m = shape_top.v_mirror_copy() start_parabole = i3.Coord2(self.split_base_pos, self.split_base_width / 2) end_parabole = pos_out_2 - i3.Coord2(self.small_straights, wg_width / 2) x_parabole = np.linspace(start_parabole[0], end_parabole[0], 50) y_parabole = (end_parabole[1] - start_parabole[1]) * 1 / ( end_parabole[0] - x_parabole[0])**0.5 * ( x_parabole - x_parabole[0])**0.5 + start_parabole[1] points_parabole = [ i3.Coord2(x, y) for x, y in zip(x_parabole, y_parabole) ] points_parabole = [ i3.Coord2(start_parabole[0], 0) ] + points_parabole + [pos_out_2 - i3.Coord2(0, wg_width / 2)] shape_parabole = i3.Shape(points=points_parabole) shape_parabole_m = shape_parabole.v_mirror_copy() shape_parabole_final = shape_parabole.reversed() + shape_parabole_m shape_parabole_final.remove_identicals() shape_bot = SplinedShape( waypoint_shape=i3.Shape(points=shape_parabole_final), resolution=0.05) shape_elem = shape_top + shape_bot + shape_top_m.reversed() shape_elem.remove_identicals() elem = i3.Boundary(layer=self.wg_template.core_layer, shape=shape_elem) return elem
def _generate_instances(self, insts): # First create shapes # Break the channel that contain two obstacles into three segments # Obstacles need to intersect these three segments # Obs 1. Segment 1:2, Obs 2 Segment 2:3 #define points will be helpful to make schematic p1 = (self.cInp.x + 0.0, self.cInp.y + 0.0) p2 = ((self.gap_btw_barriers * 0.5 + self.obstacle_trap_radius), 0.0) p3 = ((self.gap_btw_barriers * 0.5 + self.obstacle_trap_radius), self.gap_btw_barriers + self.obstacle_trap_radius * 2) p4 = (0.0, self.gap_btw_barriers + self.obstacle_trap_radius * 2) sr1 = i3.Shape(points=[p1, p2, p3, p4], closed=True) #Internal holes as Circles #to do: define position of SC2 as a function of perpendicular GAP sc1 = i3.ShapeCircle(center=(self.cInp.x + 0.0, self.gap_btw_barriers * 0.5 + self.obstacle_trap_radius), radius=(self.obstacle_trap_radius)) #Define the boundaries for shapes br1 = i3.Boundary(layer=self.layer, shape=sr1) bc1 = i3.Boundary(layer=self.layer, shape=sc1) #Substruct boundaries and add to the element list b_sub = br1 - bc1 s = i3.Structure(elements=b_sub) insts += i3.SRef(s) return insts
def _generate_instances(self, insts): delta = self.trace_template.core_width + self.spacing bend_radius = self.bend_radius coupler_length = self.cell.get_default_view( i3.CircuitModelView).coupler_length shape = i3.Shape([ (-coupler_length / 2.0 - bend_radius, bend_radius), (-coupler_length / 2.0 - bend_radius, 0.0), (-coupler_length / 2.0, 0.0), (coupler_length / 2.0, 0.0), (coupler_length / 2.0 + bend_radius, 0.0), (coupler_length / 2.0 + bend_radius, bend_radius) ]) wg = i3.RoundedWaveguide(name=self.name + "_wg", trace_template=self.trace_template) wg_layout = wg.Layout(shape=shape) insts += i3.SRef(reference=wg_layout, name="wav_top", position=(0, delta / 2.0)) insts += i3.SRef(reference=wg_layout, name="wav_bot", transformation=i3.VMirror() + i3.Translation(translation=(0, -delta / 2.0))) return insts
def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(x0 + 7500, y0 + 4500), box_size=(15000, 1000)) # elems += i3.Rectangle(layer=i3.TECH.PPLAYER.NONE.DOC, center=(x0 + 7500, y0 + 4500), # box_size=(15000, 1000)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 7500, y0 + 500), box_size=(15000, 1000)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 12500+1000, y0 + 2500), #change box_size=(self.length, self.width)) if self.pocket: PO = i3.Rectangle(layer=self.layer_bool, center=(10001+2000, 2500), box_size=(2, 160)) #change elems += PO generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) if self.tilt: # TI = i3.Rectangle(layer=self.layer_bool, center=(10001, 2500), box_size=(2, 160)) # elems += TI TI_shape = i3.Shape(points=[(10000.0+2000, 2470.0), (10010.58+2000, 2530.0), (10000.0+2000, 2530.0)], closed=True) #change TI = i3.Boundary(layer=self.layer_bool, shape=TI_shape) elems += TI generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) return elems
def _get_cladding_elem(self): shape_cladding = i3.Shape( points=[(self.length_straights, self.wg_template.width / 2), (self.length_straights + self.length_splitting_shape, self.spacing / 2 + self.wg_template.width / 2)]) shape_cladding_m = i3.Shape( points=[(self.length_straights, -self.wg_template.width / 2), (self.length_straights + self.length_splitting_shape, -self.spacing / 2 - self.wg_template.width / 2)]) shape_elem = shape_cladding + shape_cladding_m.reversed() elem = i3.Boundary(layer=self.wg_template.windows[1].layer, shape=shape_elem) return elem
def _default_wgs_straights(self): wgs_cells = self.cell.wgs_straights wgs_layout = [] for wgc in wgs_cells: wg_layout = wgc.get_default_view(i3.LayoutView) wg_layout.set(shape=i3.Shape( points=[(0, 0), (self.length_straights, 0)])) wgs_layout.append(wg_layout) return wgs_layout
def route_sbend(start_port, end_port, bend_radius=20.0): """ Calculates an sbend between ports, returns the route and the used bend radius """ ports = start_port, end_port points = [] points.append(start_port.position) points.append(start_port.position.move_polar_copy(bend_radius, start_port.angle)) points.append(end_port.position.move_polar_copy(bend_radius, end_port.angle)) points.append(end_port.position) return i3.Shape(points)
def __example(self): for i, y in enumerate(yvalues): x = dist / len(yvalues) * (i + 1) points.append((x, y)) waypoint_shape = i3.Shape(points=points) splined_shape = SplinedShape(waypoint_shape=waypoint_shape) plt.figure() plt.plot(waypoint_shape.x_coords(), waypoint_shape.y_coords(), 'x', splined_shape.x_coords(), splined_shape.y_coords()) plt.legend(['Orig', 'Interp']) plt.title('Spline of parametrically-defined curve') plt.show()
def _generate_instances(self, elems): # insts): channel1 = microfluidics.Channel( trace_template=self.cell.channel_template) channel1_lo = channel1.Layout( shape=i3.Shape([(0, -self.tee_length), (0, self.tee_length)])) elems += i3.SRef(channel1, position=(0, 0)) channel2 = microfluidics.Channel( trace_template=self.cell.channel_template) channel2_lo = channel2.Layout(shape=[(0, 0), (-self.tee_length, 0)]) elems += i3.SRef(channel2, position=(self.tee_length, 0)) return elems #insts
def _generate_elements(self, insts): block_width = self.channel_template.channel_width point_list = [] point_list.append((-self.block_length * 0.5, -block_width * 0.5)) point_list.insert(0, (-self.block_length * 0.5, block_width * 0.5)) point_list.append((self.block_length * 0.5, -block_width * 0.5)) point_list.insert(0, (self.block_length * 0.5, block_width * 0.5)) t = i3.Shape(point_list, closed=True) bo = i3.Boundary(i3.TECH.PPLAYER.CH2.TRENCH, t) insts += bo #comm/uncomm for debugging round stl return insts
def get_waveguide_shape(start_port, end_port, way_points=[], distance_straight=10.0): original_points = [ start_port.position, start_port.move_polar_copy(distance_straight, start_port.angle).position ] original_points.extend(way_points) original_points.extend([ end_port.move_polar_copy(distance_straight, end_port.angle).position, end_port.position ]) original_shape = i3.Shape(points=original_points, start_face_angle=start_port.angle, end_face_angle=end_port.angle + 180.0) s2 = i3.ShapeFitClampedCubicSpline(original_shape=original_shape, discretisation=1) return s2
def _generate_elements(self, elems): elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH2.TRENCH, center=(0.0, 0.0), radius=self.diameter * 0.5, line_width=50) point_list = [] point_list.append((0, -self.diameter * 0.5)) point_list.insert(0, (0, self.diameter * 0.5)) point_list.append( (self.diameter * self.cell.reduction_ratio, -self.diameter * 0.5 * self.cell.reduction_ratio)) point_list.insert( 0, (self.diameter * self.cell.reduction_ratio, self.diameter * 0.5 * self.cell.reduction_ratio)) funnel = i3.Shape(point_list, closed=True) bo = i3.Boundary(i3.TECH.PPLAYER.CH2.TRENCH, funnel) elems += bo return elems
def _generate_instances(self, insts): # Generates taper pairs tp_name_list = [] # temporary? pick taper properties taper_prop_dict = { 'length': 79.0, 'width1': 0.50, 'width2': 6.50, 'width_etch': 2.0 } # generate a huge taper row tp_rows_layout = TaperPairRow().Layout( taper_prop_dict=taper_prop_dict, connect_length=0.0, pair_connect_length=10.0, n_pairs=self.n_pairs) # load the aim gds just to get its positions and stuff # main chip GDS fname = os.path.dirname( os.path.realpath(__file__)) + '/gds/ap_suny_v20a_chipframe.gds' main_chip_gds_cell = i3.GDSCell(filename=fname) # grab layout size info main_chip_gds_lay = main_chip_gds_cell.Layout() main_chip_gds_lay_size_info = main_chip_gds_lay.size_info() # grab relevant positions chip_edge_east = main_chip_gds_lay_size_info.east chip_edge_west = main_chip_gds_lay_size_info.west # make edge coupler and add to layout # edge coupler edge_coupler_gds_lay = EdgeCoupler(name=self.name + 'edge_coupler_si').Layout() # add and route input/west edgecoupler # position edge coupler on west side of chip chip_port_west = i3.OpticalPort(position=(chip_edge_west, 0.0), angle_deg=0.0) edge_coupler_west_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_west_port, chip_port_west) edge_coupler_west_name = self.name + '_EDGE_COUPLER_WEST' west_edge_coupler = i3.SRef(name=edge_coupler_west_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], west_edge_coupler.ports['in']) lin_taper_lay_name = self.name + '_EDGETAPER_WEST' insts += i3.SRef(name=lin_taper_lay_name, reference=lin_taper_lay, transformation=t, flatten=True) # add taper rows taper_row_name = self.name + '_TAPERSSSSSSSS' t = i3.vector_match_transform( tp_rows_layout.ports['left'], insts[lin_taper_lay_name].ports['out']) insts += i3.SRef(name=taper_row_name, reference=tp_rows_layout, transformation=t, flatten=True) # add east coupler chip_port_east = i3.OpticalPort(position=(chip_edge_east, 0.0), angle_deg=180.0) edge_coupler_east_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_east_port, chip_port_east, mirrored=True) edge_coupler_east_name = self.name + '_EDGE_COUPLER_EAST' east_edge_coupler = i3.SRef(name=edge_coupler_east_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], east_edge_coupler.ports['in'], mirrored=True) lin_taper_lay_name = self.name + '_EDGETAPER_EAST' insts += i3.SRef(name=lin_taper_lay_name, reference=lin_taper_lay, transformation=t, flatten=True) # route the east coupler to the east edge of the taper pairs route_wg_row_taper = i3.Shape([ insts[taper_row_name].ports['right'].position, insts[lin_taper_lay_name].ports['out'].position ]) wg_name = self.name + '_WG' wg_lay = i3.Waveguide(trace_template=StripWgTemplate(), name=wg_name).get_default_view(i3.LayoutView) wg_lay.set(shape=route_wg_row_taper) insts += i3.SRef(name=wg_name, reference=wg_lay, flatten=True) return insts
def _generate_instances(self, insts): # Generates taper pairs w edge couplers # load the aim gds just to get its positions and stuff # main chip GDS fname = '../PDK_Library_Layout_GDS/ap_suny_v20a_chipframe.gds' main_chip_gds_cell = i3.GDSCell(filename=fname) # grab layout size info main_chip_gds_lay = main_chip_gds_cell.Layout() main_chip_gds_lay_size_info = main_chip_gds_lay.size_info() # grab relevant positions chip_edge_east = main_chip_gds_lay_size_info.east chip_edge_west = main_chip_gds_lay_size_info.west # make edge coupler edge_coupler_gds_lay = EdgeCoupler(name=self.name + 'edge_coupler_sffdfi').Layout() # add and route input/west edgecoupler # position edge coupler on west side of chip chip_port_west = i3.OpticalPort(position=(chip_edge_west, 0.0), angle_deg=0.0) edge_coupler_west_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_west_port, chip_port_west) edge_coupler_west_name = self.name + '_EDGE_COUPLER_WEST' west_edge_coupler = i3.SRef(name=edge_coupler_west_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], west_edge_coupler.ports['in']) lin_taper_lay_name = self.name + '_EDGETAPER_WEST' insts += i3.SRef(name=lin_taper_lay_name, reference=lin_taper_lay, transformation=t, flatten=True) # route wg to wg with arc bend_radius = 10.0 arc_center_1 = ( insts[lin_taper_lay_name].ports['out'].position[0], insts[lin_taper_lay_name].ports['out'].position[1] + bend_radius) route_wg_shape_arc1 = i3.ShapeArc(radius=bend_radius, angle_step=1.0, center=arc_center_1, start_angle=269.5, end_angle=0.5, closed=False, clockwise=False) wg_name_arc1 = self.name + '_ARC1' wg_lay_arc1 = i3.Waveguide(trace_template=StripWgTemplate(), name=wg_name_arc1).get_default_view( i3.LayoutView) wg_lay_arc1.set(shape=route_wg_shape_arc1) insts += i3.SRef(name=wg_name_arc1, reference=wg_lay_arc1, flatten=True) # add the bends bend_clip_lay = BendClip( name=self.name + '_BEND_CLIP').get_default_view(i3.LayoutView) bend_clip_lay.set(n_pairs=self.n_pairs) # add to insts bend_clip_lay_name = self.name + '_BEND_CLIP' t = i3.vector_match_transform(bend_clip_lay.ports['in'], insts[wg_name_arc1].ports['out']) insts += i3.SRef(name=bend_clip_lay_name, reference=bend_clip_lay, transformation=t, flatten=True) # add output bend arc_center_2 = ( insts[bend_clip_lay_name].ports['out'].position[0] + bend_radius, insts[bend_clip_lay_name].ports['out'].position[1]) route_wg_shape_arc2 = i3.ShapeArc(radius=bend_radius, angle_step=1.0, center=arc_center_2, start_angle=180.5, end_angle=89.5, closed=False, clockwise=True) wg_name_arc2 = self.name + '_ARC2' wg_lay_arc2 = i3.Waveguide(trace_template=StripWgTemplate(), name=wg_name_arc2).get_default_view( i3.LayoutView) wg_lay_arc2.set(shape=route_wg_shape_arc2) insts += i3.SRef(name=wg_name_arc2, reference=wg_lay_arc2, flatten=True) # add east coupler chip_port_east = i3.OpticalPort( position=(chip_edge_east, insts[wg_name_arc2].ports['out'].position[1]), angle_deg=180.0) edge_coupler_east_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_east_port, chip_port_east, mirrored=True) edge_coupler_east_name = self.name + '_EDGE_COUPLER_EAST' east_edge_coupler = i3.SRef(name=edge_coupler_east_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], east_edge_coupler.ports['in'], mirrored=True) lin_taper_lay_name = self.name + '_EDGETAPER_EAST' insts += i3.SRef(name=lin_taper_lay_name, reference=lin_taper_lay, transformation=t, flatten=True) # route arc to arc with straight section route_wg_shape_out = i3.Shape([ insts[wg_name_arc2].ports['out'].position, insts[lin_taper_lay_name].ports['out'].position ]) wg_name_out = self.name + '_WG_CON_OUT' wg_lay_out = i3.Waveguide(trace_template=StripWgTemplate(), name=wg_name_out).get_default_view( i3.LayoutView) wg_lay_out.set(shape=route_wg_shape_out) insts += i3.SRef(name=wg_name_out, reference=wg_lay_out, flatten=True) return insts
def _generate_instances(self, insts): # First create shapes # Break the block containig the feature into two segments # Block need to intersect these two segments # Feature 1. Segment 1:2 #define points will be helpful to make schematic p1 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (-0.5), 0.0) p2 = (self.cInp.x + 0.0, self.cInp.y + 0.0) p3 = (self.cInp.x, self.feature_height * 0.5 + self.vacuum_width) p4 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (-0.5), self.feature_height * 0.5 + self.vacuum_width) p5 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (0.5), 0.0) p6 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (0.5), self.feature_height * 0.5 + self.vacuum_width) p7 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (-0.5), -(self.feature_height * 0.5 + self.vacuum_width)) p8 = (self.cInp.x, -(self.feature_height * 0.5 + self.vacuum_width)) p9 = ((self.feature_width + self.gap_horiz + self.vacuum_width) * (0.5), -(self.feature_height * 0.5 + self.vacuum_width)) sr1 = i3.Shape(points=[p1, p2, p3, p4], closed=True) sr2 = i3.Shape(points=[p2, p5, p6, p3], closed=True) sr3 = i3.Shape(points=[p7, p8, p2, p1], closed=True) sr4 = i3.Shape(points=[p8, p9, p5, p2], closed=True) #Internal holes as Circles #It is needed to define position of SC2 as a function of perpendicular GAP #sc1 = i3.ShapeCircle(center = (self.cInp.x+(self.gap_btw_barriers+self.obstacle_trap_length)*0.65, 0.0), radius = (self.obstacle_trap_width)) #sc2 = i3.ShapeCircle(center = (self.cInp.x+(self.gap_btw_barriers+self.obstacle_trap_length)*1.35,self.cInp.y+self.channel_trap_width), radius = (self.obstacle_trap_width)) #Internal holes as Rectangles sc1 = i3.ShapeRectangle( center=(self.cInp.x, self.cInp.y), box_size=(self.feature_width + self.gap_horiz, self.feature_height + self.gap_vertical)) #Define the boundaries for shapes br1 = i3.Boundary(layer=self.layer, shape=sr1) br2 = i3.Boundary(layer=self.layer, shape=sr2) br3 = i3.Boundary(layer=self.layer, shape=sr3) br4 = i3.Boundary(layer=self.layer, shape=sr4) bc1 = i3.Boundary(layer=self.layer, shape=sc1) #Substruct boundaries and add to the element list b_sub = br1 - bc1 s = i3.Structure(elements=b_sub) insts += i3.SRef(s) b_sub = br2 - bc1 b_sub = b_sub[0] - bc1 s = i3.Structure(elements=b_sub) insts += i3.SRef(s) b_sub = br3 - bc1 s = i3.Structure(elements=b_sub) insts += i3.SRef(s) b_sub = br4 - bc1 s = i3.Structure(elements=b_sub) insts += i3.SRef(s) return insts
def _generate_instances(self, insts): # Generates taper clip # make my OWN custom waveguide trace template # wg_trace = f_MyIMECWaveguideTemplate(core_width=self.taper_prop_dict['width1'], # cladding_width=self.taper_prop_dict['width1'] + 2.0 * self.taper_prop_dict['width_etch']) # make waveguide wg = i3.Waveguide(trace_template=StripWgTemplate(), name=self.name + '_WG') wg_round = i3.RoundedWaveguide(trace_template=StripWgTemplate(), name=self.name + '_WG_ROUND') # how much to translate bends left/right # t_left = i3.Translation((self.bend_radius + (float(self.n_rows)/2.0) )) t_left = i3.Translation((-2.5 * self.bend_radius, 0.0)) t_right = i3.Translation((2.5 * self.bend_radius, 0.0)) # draw taper pair rows for ii in range(self.n_rows): # add rows tp_rows_layout = TaperPairRow(name=self.name + '_TProw' + str(ii)).get_default_view( i3.LayoutView) tp_rows_layout.set( taper_prop_dict=self.taper_prop_dict, connect_length=self.connect_length, pair_connect_length=self.pair_connect_length, n_pairs=self.n_taper_pairs_per_row) # set translation t = i3.Translation((0.0, float(ii) * self.row_spacing)) # place taper pair row tp_row_name = self.name + '_TP_ROW' + str(ii) insts += i3.SRef(name=tp_row_name, reference=tp_rows_layout, transformation=t) # draw connecting arcs if ii > 0: if (ii % 2) == 1: # bend on the right # make shape bend row_name = self.name + '_TP_ROW' + str(ii - 1) shape_bend = i3.ShapeBend(start_point=insts[row_name]. ports['right'].position, radius=self.bend_radius, start_angle=-90.05, end_angle=90.05, angle_step=0.1) # add 180 deg bend wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_arc_r' + str(ii)) arc_name = self.name + '_arc' + str(ii) insts += i3.SRef( name=arc_name, reference=wg_copy.Layout(shape=shape_bend), transformation=t_right) # connect bottom wgs # get coords in_port_coords = insts[arc_name].ports['in'].position out_port_coords = insts[row_name].ports[ 'right'].position # draw bezier curve bez = BezierCurve( N=100, P0=(in_port_coords[0] + 0.01, in_port_coords[1]), P1=(in_port_coords[0] - self.bend_radius / 2.0, in_port_coords[1]), P2=(out_port_coords[0] + self.bend_radius / 2.0, out_port_coords[1]), P3=(out_port_coords[0] - 0.01, out_port_coords[1]), R=(-self.bend_radius, +self.bend_radius), dy_dx=(0.0, -0.0)) bez_coords = bez.bezier_coords() # make ipkiss shape s = i3.Shape(bez_coords) # add bottom wg connector wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_arc_r_con' + str(ii)) insts += i3.SRef(name=self.name + '_con_wg_r_b_' + str(ii), reference=wg_copy.Layout(shape=s)) # connect top wgs next_row_name = self.name + '_TP_ROW' + str(ii) in_port_coords = insts[arc_name].ports['out'].position out_port_coords = insts[next_row_name].ports[ 'right'].position # draw bezier curve bez = BezierCurve( N=500, P0=(in_port_coords[0] + 0.01, in_port_coords[1]), P1=(in_port_coords[0] - self.bend_radius / 2.0, in_port_coords[1]), P2=(out_port_coords[0] + self.bend_radius / 2.0, out_port_coords[1]), P3=(out_port_coords[0] - 0.01, out_port_coords[1]), R=(self.bend_radius, -self.bend_radius), dy_dx=(0.0, -0.0)) bez_coords = bez.bezier_coords() # make ipkiss shape s = i3.Shape(bez_coords) # add wg bend wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_bez_r' + str(ii)) insts += i3.SRef(name=self.name + '_con_wg_r_t_' + str(ii), reference=wg_copy.Layout(shape=s)) else: # bend on the left # make shape bend row_name = self.name + '_TP_ROW' + str(ii - 1) shape_bend = i3.ShapeBend(start_point=( insts[row_name].ports['left'].position), radius=self.bend_radius, start_angle=90.05, end_angle=-90.05, angle_step=0.1, clockwise=False) # add 180 deg bend wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_arc_l' + str(ii)) arc_name = self.name + '_arc' + str(ii) insts += i3.SRef( name=arc_name, reference=wg_copy.Layout(shape=shape_bend), transformation=t_left) # connect bottom wgs # get coords in_port_coords = insts[arc_name].ports['out'].position out_port_coords = insts[row_name].ports[ 'left'].position # draw bezier curve bez = BezierCurve( N=100, P0=(in_port_coords[0] - 0.01, in_port_coords[1]), P1=(in_port_coords[0] + self.bend_radius / 2.0, in_port_coords[1]), P2=(out_port_coords[0] - self.bend_radius / 2.0, out_port_coords[1]), P3=(out_port_coords[0] + 0.01, out_port_coords[1]), R=(-self.bend_radius, +self.bend_radius), dy_dx=(0.0, -0.0)) bez_coords = bez.bezier_coords() # make ipkiss shape s = i3.Shape(bez_coords) # add bottom wg connector wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_arc_l_con' + str(ii)) insts += i3.SRef(name=self.name + '_con_wg_l_b_' + str(ii), reference=wg_copy.Layout(shape=s)) # connect top wgs next_row_name = self.name + '_TP_ROW' + str(ii) in_port_coords = insts[arc_name].ports['in'].position out_port_coords = insts[next_row_name].ports[ 'left'].position # draw bezier curve bez = BezierCurve( N=500, P0=(in_port_coords[0] - 0.01, in_port_coords[1]), P1=(in_port_coords[0] + self.bend_radius / 2.0, in_port_coords[1]), P2=(out_port_coords[0] - self.bend_radius / 2.0, out_port_coords[1]), P3=(out_port_coords[0] + 0.01, out_port_coords[1]), R=(-self.bend_radius, +self.bend_radius), dy_dx=(0.0, -0.0)) bez_coords = bez.bezier_coords() # make ipkiss shape s = i3.Shape(bez_coords) # add wg bend wg_copy = i3.Waveguide( trace_template=StripWgTemplate(), name=self.name + '_bez_l' + str(ii)) insts += i3.SRef(name=self.name + '_con_wg_l_t_' + str(ii), reference=wg_copy.Layout(shape=s)) # end if bend # end drawing connecting arcs # end for ii in range(self.rows) # # connect the input grating # # pick grating layout to return # grating_layout = { # 'FGCCTE_FC1DC_625_313': FGCCTE_FC1DC_625_313().Layout(), # 'FGCCTE_FCWFC1DC_630_378': FGCCTE_FCWFC1DC_630_378().Layout(), # 'FGCCTM_FC1DC_984_492': FGCCTM_FC1DC_984_492().Layout(), # }[self.grating_name] # # # # # place bottom grating # # always assuming bottom grating starts on the left # bot_grating_name = self.name+'_bot_grating' # t = i3.vector_match_transform( grating_layout.ports['waveguide'], # insts[self.name + '_TP_ROW0'].ports['left'] ) + \ # i3.Translation( ( -self.bot_gc_connect_length, 0.0 ) ) # # insts += i3.SRef( name = bot_grating_name, # reference = grating_layout, # transformation = t ) # # # connect bottom grating to taper # route_wg_bot = i3.RouteManhattan( input_port = insts[bot_grating_name].ports['waveguide'], # output_port = insts[self.name + '_TP_ROW0'].ports['left'] ) # # # add wg # wg_bot = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_BOT') # insts += i3.SRef(name=self.name + '_connect_wg_bot', reference=wg_bot.Layout(shape=route_wg_bot)) # # # # # place top grating # top_grating_name = self.name + '_top_grating' # if (self.n_rows % 2) == 1: # # even # of rows, output is to the right # t = i3.vector_match_transform( grating_layout.ports['waveguide'], # insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['right'], # mirrored = True ) + \ # i3.Translation((self.top_gc_connect_length, 0.0)) # # insts += i3.SRef( name = top_grating_name, # reference = grating_layout, # transformation = t) # # # connect top grating to taper # route_wg_top = i3.RouteManhattan( input_port = insts[top_grating_name].ports['waveguide'], # output_port = insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['right']) # # # add wg # wg_top = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_TOP') # insts += i3.SRef(name=self.name + '_connect_wg_top', reference=wg_top.Layout(shape=route_wg_top)) # # else: # # odd # of rows, output is to the left # t = i3.vector_match_transform( grating_layout.ports['waveguide'], # insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['left'], # mirrored = False ) + \ # i3.Translation((-self.top_gc_connect_length, 0.0)) # # insts += i3.SRef( name = top_grating_name, # reference = grating_layout, # transformation = t) # # # connect top grating to taper # route_wg_top = i3.RouteManhattan( input_port = insts[top_grating_name].ports['waveguide'], # output_port = insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['left']) # # # add wg # wg_top = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_TOP') # insts += i3.SRef(name=self.name + '_connect_wg_top', reference=wg_top.Layout(shape=route_wg_top)) return insts
d_phi = np.pi / 2. delay_length = d_phi * wavelength / (2 * np.pi * n_eff) mzm = demo.TW_MZM() lay = mzm.Layout(delta=50., additional_length=150., delay=delay_length) fig = lay.visualize(annotate=True, show=False) fig.canvas.set_window_title('Modulator layout') fig = lay.visualize_2d(show=False) fig.canvas.set_window_title('Virtual fabrication of the modulator') ax = fig.get_axes()[0] ax.vlines(0, -75, 75) ax.annotate('Cross-section', xy=(0, 0), xytext=(100, 100), arrowprops=dict(facecolor='black', shrink=0.05)) xs = lay.cross_section(cross_section_path=i3.Shape([(0., -75.), (0., 75.)]), path_origin=-75.) fig = xs.visualize(show=False) fig.canvas.set_window_title('Cross-section from y=-75 --> y=75 um.') xs = lay.cross_section(cross_section_path=i3.Shape([(0., 36.), (0., 60.)]), path_origin=36.) fig = xs.visualize(show=False) fig.canvas.set_window_title('Cross-section from y=36 --> y=60 um.') from pylab import plt plt.show()
def _default_wg1b_shape(self): return i3.Shape(points=[(0, -self.coupler_spacing / 2), (+1 * self.bend_radius + self.coupler_length / 2, -self.coupler_spacing / 2)])
# generated_layout = i3.LayoutCell("generated_mask").Layout(elements=generated_elements) # generated_layout.visualize() # generated_layout.write_gdsii("boolean_ops_photonics.gds") # use as a generated mask layer generated_elements = get_elements_for_generated_layers( ring_lo.layout, {wg_mask: TECH.PPLAYER.NONE.DOC}) generated_layout = i3.LayoutCell("generated_mask").Layout( elements=generated_elements) generated_layout.visualize() generated_layout.write_gdsii("boolean_ops_photonics.gds") # define a virtual fabrication flow, using the material stacks in the silicon_photonics technology vfab_process = VFabricationProcessFlow( active_processes=[wg_process], process_layer_map={wg_process: wg_mask}, is_lf_fabrication={wg_process: False}, process_to_material_stack_map=[ ((0, ), TECH.MATERIAL_STACKS.MSTACK_SOI_SI_220nm), ((1, ), TECH.MATERIAL_STACKS.MSTACK_SOI_SI_100nm), ]) # visualize the result of the virtual fabrication # top-down ring_lo.visualize_2d(vfabrication_process_flow=vfab_process) ring_xs = ring_lo.cross_section(process_flow=vfab_process, cross_section_path=i3.Shape([(0.0, 4.0), (0.0, 7.0)])) ring_xs.visualize() # generated_layout.visualize(vfabrication_process_flow=vfab_process) # generated_layout.write_gdsii("boolean_ops_photonics.gds")
def _generate_elements(self, elems): cell_trap_width = self.channel_template.channel_width entry_Lfd = self.cell_trap_length * 0.5 # 1000.0 exit_Lfd = self.cell_trap_length * 0.5 # 500.0 beta = math.radians(self.out_angle) lf = self.funnel_length wi = cell_trap_width wf = self.cell_trap_gap #lfd = 0 taper_samples = 200 a = lf / (wi / wf - 1.0) dx = lf / taper_samples x = 0.0 xl = [] wl = [] point_list = [] x_offset = self.funnel_length + self.cell_trap_gap_length # all expansion will be at 0.0x a = 0.5 b = .35 point_list.append( self.cInp + (-(self.cell_trap_length * b), wi * 0.5)) # end of array point_list.insert(0, self.cInp + (-(self.cell_trap_length * b), -wi * 0.5)) # begging of array, position 0 for i in reversed(range(1, taper_samples + 1)): #xa = lf * math.exp(10.0 * (i / taper_samples - 1.0)) #discretization radius = 0.5 * wi ### this needs to be improved xa = (radius) * math.cos(0.5 * math.pi * i / taper_samples) #w = wi / (1.0 + xa / a) #function value w = (radius) * math.sin(0.5 * math.pi * i / taper_samples) p = (xa - radius - self.cell_trap_gap_length * 0.5, 0.5 * (w + 0.5 * wi)) point_list.append(self.cInp + p) p = (xa - radius - self.cell_trap_gap_length * 0.5, -0.5 * (w + 0.5 * wi)) point_list.insert(0, self.cInp + p) # GAP LENGTH p = ( point_list[-1][0], wf * 0.5 ) #wGet last point, coordX use it for next point with wf as coordY point_list.append(self.cInp + p) # Insert it at the bottom of point_list p = point_list[-1] + (0.0, (-wf)) # Get last point, add -wf point_list.insert(0, self.cInp + p) # Insert it at the bottom of point_list p = point_list[-1] + (self.cell_trap_gap_length, 0.0 ) # Get last point and add length point_list.append(self.cInp + p) # Insert it at [0] in the point_list p = point_list[-1] + (0.0, -wf) # Get last point and add length point_list.insert(0, self.cInp + p) # Insert it at [0] in the point_list # EXIT ANGLE p = point_list[-1] + ( 0.5 * (cell_trap_width - self.cell_trap_gap) / math.tan(beta), -cell_trap_width * 0.5 - wf * .50 ) # Get last point and add length of angle point_list.insert(0, self.cInp + p) # Insert it at [0] in the point_list p = point_list[0] + (0, wi) point_list.append(self.cInp + p) # Insert it at the bottom of point_list # EXIT LENGTH p = (self.cell_trap_length * b, point_list[-1][1] ) # get first point (last point added) and add length point_list.append(self.cInp + p) p = point_list[-1] + (0, -wi) ##get last point and add length point_list.insert(0, self.cInp + p) t = i3.Shape(point_list, closed=True) rectang = i3.ShapeRound(original_shape=t, start_face_angle=0, end_face_angle=0, radius=self.radius_fillet) bo = i3.Boundary(self.channel_template.layer, rectang) #creating an inlet rectangle boundary to avoid round corners point_list = [] point_list.append( (-self.cell_trap_length * a, -cell_trap_width * 0.5)) point_list.insert( 0, (-self.cell_trap_length * a, cell_trap_width * 0.5)) point_list.append((-self.cell_trap_length * b + self.radius_fillet, -cell_trap_width * 0.5)) point_list.insert(0, (-self.cell_trap_length * b + self.radius_fillet, cell_trap_width * 0.5)) t = i3.Shape(point_list, closed=True) bo1 = i3.Boundary(self.channel_template.layer, t) #creating an outlet rectangle boundary to avoid round corners point_list = [] point_list.append((self.cell_trap_length * b - self.radius_fillet, -cell_trap_width * 0.5)) point_list.insert(0, (self.cell_trap_length * b - self.radius_fillet, cell_trap_width * 0.5)) point_list.append( (self.cell_trap_length * a, -cell_trap_width * 0.5)) point_list.insert( 0, (self.cell_trap_length * a, cell_trap_width * 0.5)) t = i3.Shape(point_list, closed=True) bo2 = i3.Boundary(self.channel_template.layer, t) #boolean operation adding main geometry and inlet rectangle b_add = bo | bo1 #boolean operation adding main geometry and outlet rectangle b_add2 = b_add[0] | bo2 #s2 = i3.Structure(elements=b_add2) elems += b_add2 #insts += bo return elems
def _generate_elements(self, elems): cell_trap_width = self.channel_template.channel_width alpha = math.radians(self.in_angle) beta = math.radians(self.out_angle) point_list = [] point_list.append( (-self.cell_trap_length * 0.25, -cell_trap_width * 0.5)) point_list.insert( 0, (-self.cell_trap_length * 0.25, cell_trap_width * 0.5)) point_list.append( (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) - self.cell_trap_gap_length * 0.5, -(cell_trap_width * 0.5))) point_list.insert( 0, (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) - self.cell_trap_gap_length * 0.5, (cell_trap_width * 0.5))) point_list.append((-self.cell_trap_gap_length * 0.25, -self.cell_trap_gap * 0.5)) # end of array point_list.insert( 0, (-self.cell_trap_gap_length * 0.25, self.cell_trap_gap * 0.5)) # begging of array, position 0 point_list.append( (self.cell_trap_gap_length * 0.25, -self.cell_trap_gap * 0.5)) point_list.insert( 0, (self.cell_trap_gap_length * 0.25, self.cell_trap_gap * 0.5)) point_list.append( ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) + self.cell_trap_gap_length * 0.25, -(cell_trap_width * 0.5))) point_list.insert( 0, ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) + self.cell_trap_gap_length * 0.25, (cell_trap_width * 0.5))) point_list.append( (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5, -cell_trap_width * 0.5)) point_list.insert( 0, (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5, cell_trap_width * 0.5)) t = i3.Shape(point_list, closed=True) rectang = i3.ShapeRound(original_shape=t, start_face_angle=0, end_face_angle=0, radius=self.radius_fillet) bo = i3.Boundary(self.channel_template.layer, rectang) #insts += bo #comm/uncomm for debugging round stl #creating an inlet rectangle boundary to avoid round corners point_list = [] #w = 3 point_list.append( (-self.cell_trap_length * 0.5, -cell_trap_width * 0.5)) point_list.insert( 0, (-self.cell_trap_length * 0.5, cell_trap_width * 0.5)) point_list.append( (-self.cell_trap_length * 0.25 + self.radius_fillet, -cell_trap_width * 0.5)) point_list.insert(0, (-self.cell_trap_length * 0.25 + self.radius_fillet, cell_trap_width * 0.5)) t = i3.Shape(point_list, closed=True) bo1 = i3.Boundary(self.channel_template.layer, t) #creating an outlet rectangle boundary to avoid round corners point_list = [] point_list.append( (self.cell_trap_length * 0.25 - self.radius_fillet, -cell_trap_width * 0.5)) point_list.insert(0, (self.cell_trap_length * 0.25 - self.radius_fillet, cell_trap_width * 0.5)) point_list.append( (self.cell_trap_length * 0.5, -cell_trap_width * 0.5)) point_list.insert(0, (-self.cell_trap_length * 0.5 + self.cell_trap_length, cell_trap_width * 0.5)) t = i3.Shape(point_list, closed=True) bo2 = i3.Boundary(self.channel_template.layer, t) #boolean operation adding main geometry and inlet rectangle b_add = bo1 | bo #boolean operation adding main geometry and outlet rectangle b_add2 = bo2 | b_add[0] elems += b_add2 return elems
def _generate_instances(self, insts): # First create shapes # Break the channel that contain two obstacles into three segments # Obstacles need to intersect these three segments # Obs 1. Segment 1:2, Obs 2 Segment 2:3 #define points will be helpful to make schematic p1 = (self.cInp.x+0.0,self.cInp.y+0.0) p2 = ((self.gap_btw_barriers+self.obstacle_trap_length)*0.5,0.0) p3 = ((self.gap_btw_barriers+self.obstacle_trap_length)*0.5,self.channel_trap_width) p4 = (0.0,self.channel_trap_width) p5 = ((self.gap_btw_barriers+self.obstacle_trap_length)*1.5, 0.0) p6 = ((self.gap_btw_barriers+self.obstacle_trap_length)*2, 0.0) p7 = ((self.gap_btw_barriers+self.obstacle_trap_length)*2, self.channel_trap_width) p8 = ((self.gap_btw_barriers+self.obstacle_trap_length)*1.5,self.channel_trap_width) sr1 = i3.Shape(points = [p1,p2,p3,p4], closed =True) sr2 = i3.Shape(points = [p2,p5,p8,p3], closed =True) sr3 = i3.Shape(points = [p5,p6,p7,p8], closed =True) #Internal holes as Circles #to do: define position of SC2 as a function of perpendicular GAP sc1 = i3.ShapeCircle(center = (self.cInp.x+(self.gap_btw_barriers+self.obstacle_trap_length)*0.65, 0.0), radius = (self.obstacle_trap_width)) sc2 = i3.ShapeCircle(center = (self.cInp.x+(self.gap_btw_barriers+self.obstacle_trap_length)*1.35,self.cInp.y+self.channel_trap_width), radius = (self.obstacle_trap_width)) #Internal holes as Rectangles ''' sc1 = i3.ShapeRectangle(center = (self.cInp.x+(self.gap_btw_barriers +self.obstacle_trap_length)*0.5, self.cInp.y+self.obstacle_trap_width*0.5), box_size = (self.obstacle_trap_length, self.obstacle_trap_width)) sc2 = i3.ShapeRectangle(center = (self.cInp.x+(self.gap_btw_barriers +self.obstacle_trap_length)*1.5, self.cInp.y+self.channel_trap_width-self.obstacle_trap_width*0.5), box_size = (self.obstacle_trap_length, self.obstacle_trap_width)) ''' #Define the boundaries for shapes br1 = i3.Boundary(layer = self.layer, shape = sr1) br2 = i3.Boundary(layer = self.layer, shape = sr2) br3 = i3.Boundary(layer = self.layer, shape = sr3) bc1 = i3.Boundary(layer = self.layer, shape = sc1) bc2 = i3.Boundary(layer = self.layer, shape = sc2) #Substruct boundaries and add to the element list b_sub = br1-bc1 s= i3.Structure(elements = b_sub) insts += i3.SRef(s) b_sub = br2-bc1 b_sub = b_sub[0] - bc2 s= i3.Structure(elements = b_sub) insts += i3.SRef(s) b_sub = br3-bc2 s= i3.Structure(elements = b_sub) insts += i3.SRef(s) return insts
from siepicfab import all as pdk from ipkiss3 import all as i3 import numpy as np import pylab as plt splitter = pdk.EbeamY1550() # 1. Layout splitter_layout = splitter.Layout() splitter_layout.visualize(annotate=True) splitter_layout.visualize_2d() splitter_layout.cross_section( cross_section_path=i3.Shape([(-0.5, -1.5), (-0.5, 1.5)])).visualize() # 2. Circuit splitter_circuit = splitter.CircuitModel() # 3. Plotting wavelengths = np.linspace(1.5, 1.58, 51) S = splitter_circuit.get_smatrix(wavelengths=wavelengths) plt.plot(wavelengths, 10 * np.log10(np.abs(S["opt2", "opt1"])**2), '-', linewidth=2.2, label="T(opt2)") plt.plot(wavelengths, 10 * np.log10(np.abs(S["opt3", "opt1"])**2), '-', linewidth=2.2, label="T(opt1)") plt.ylim(-5., 0.)