class Layout(i3.LayoutView): """ This section is to draw a Vernier scale """ # Basic properties of the scale spacing = i3.PositiveNumberProperty(default=4, doc="spacing between bars") number_of_bars = i3.IntProperty(default=13, doc="the number of bars") # Detailed properties of the scale bar_length = i3.PositiveNumberProperty( default=10, doc="length of the shortest bars on the scale") bar_extra_length = i3.PositiveNumberProperty( default=10, doc="extra length of the central bar") bar_width = i3.PositiveNumberProperty(default=2, doc="width of a single bar") process = i3.ProcessProperty( default=i3.TECH.PPLAYER.CH2.TRENCH ) #i3.TECH.PROCESS.WG, doc="Process Layer on which the cross is drawn") # Purpose property cannot be set from outside purpose = i3.PurposeProperty( locked=True, default=i3.TECH.PPLAYER.CH2.TRENCH ) #i3.TECH.PURPOSE.DF.LINE, doc="Process Purpose of the cross") def validate_properties(self): # The scale is symmetric with respect to its central bar so the number of bars is an odd number if self.number_of_bars % 2 == 0: raise i3.PropertyValidationError( self, "The number of bars should be an odd number", {"number_of_bars": self.number_of_bars}) return True def _generate_elements(self, elems): # Draw the central bar, which is longer than the others elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH1. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(0, (self.bar_length + self.bar_extra_length) * 0.5), box_size=(self.bar_width, self.bar_length + self.bar_extra_length)) # Draw the other bars for i in range((self.number_of_bars - 1) / 2): elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH1. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(-(i + 1) * self.spacing, self.bar_length * 0.5), box_size=(self.bar_width, self.bar_length)) for j in range((self.number_of_bars - 1) / 2): elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH1. TRENCH, #i3.PPLayer(self.process, self.purpose), center=((j + 1) * self.spacing, self.bar_length * 0.5), box_size=(self.bar_width, self.bar_length)) return elems
class PI(i3.PCell): _name_prefix = "PI" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.HFW) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) # Mesa parameters length = i3.PositiveNumberProperty(default=7000.0) width = i3.PositiveNumberProperty(default=630.0) pocket = i3.BoolProperty(default=False) tilt = i3.BoolProperty(default=False) # Recess label label = i3.StringProperty(default="PI_") class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500, y0 + 1000 + (3000 - self.width) / 4), box_size=(self.length, (3000 - self.width) / 2)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500, y0 + 1000 + self.width + (3000 - self.width) * 3 / 4), box_size=(self.length, (3000 - self.width) / 2)) elems += i3.SRef(reference=Interface(pocket=self.pocket, tilt=self.tilt)) for i in range(7): elems += i3.Rectangle(layer=self.layer, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + 185), box_size=(50, 50)) elems += i3.Rectangle(layer=self.layer, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + self.width - 185), box_size=(50, 50)) if self.pocket: self.label += "WP" if self.tilt: self.label += "WT" elems += i3.PolygonText(layer=self.layer_bool, text=self.label, coordinate=(6000, 4000), # alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=700.0) generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) return elems
class Layout(i3.LayoutView): # properties width = i3.PositiveNumberProperty(default=4.0, doc="Width of the MMI section.") length = i3.PositiveNumberProperty(default=20.0, doc="Length of the MMI secion.") taper_width = i3.PositiveNumberProperty(default=1.0, doc="Width of the taper.") taper_length = i3.PositiveNumberProperty(default=2.0, doc="Length of the taper") waveguide_spacing = i3.PositiveNumberProperty(default=2.0, doc="Spacing between the waveguides.") # methods def _generate_elements(self, elems): elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.CORE, center=(0.5 * self.length, 0.0), box_size=(self.length, self.width)) elems += i3.Wedge(layer=i3.TECH.PPLAYER.WG.CORE, begin_coord=(0.0, 0.5 * self.waveguide_spacing), end_coord=(-self.taper_length, 0.5 * self.waveguide_spacing), begin_width=self.taper_width, end_width=self.trace_template.core_width ) elems += i3.Wedge(layer=i3.TECH.PPLAYER.WG.CORE, begin_coord=(0.0, -0.5 * self.waveguide_spacing), end_coord=(-self.taper_length, -0.5 * self.waveguide_spacing), begin_width=self.taper_width, end_width=self.trace_template.core_width ) elems += i3.Wedge(layer=i3.TECH.PPLAYER.WG.CORE, begin_coord=(self.length, 0.5 * self.waveguide_spacing), end_coord=(self.length + self.taper_length, 0.5 * self.waveguide_spacing), begin_width=self.taper_width, end_width=self.trace_template.core_width ) elems += i3.Wedge(layer=i3.TECH.PPLAYER.WG.CORE, begin_coord=(self.length, -0.5 * self.waveguide_spacing), end_coord=(self.length + self.taper_length, -0.5 * self.waveguide_spacing), begin_width=self.taper_width, end_width=self.trace_template.core_width ) elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.CLADDING, center=(0.5 * self.length, 0.0), box_size=(self.length + 2 * self.taper_length, self.width + 2.0) ) return elems def _generate_ports(self, ports): ports += i3.OpticalPort(name="in1", position=(-self.taper_length, -0.5 * self.waveguide_spacing), angle=180.0, trace_template=self.trace_template) ports += i3.OpticalPort(name="in2", position=(-self.taper_length, 0.5 * self.waveguide_spacing), angle=180.0, trace_template=self.trace_template) ports += i3.OpticalPort(name="out1", position=(self.length + self.taper_length, -0.5 * self.waveguide_spacing), angle=0.0, trace_template=self.trace_template) ports += i3.OpticalPort(name="out2", position=(self.length + self.taper_length, +0.5 * self.waveguide_spacing), angle=0.0, trace_template=self.trace_template) return ports
class Interface_mmi12(i3.PCell): _name_prefix = "INTERFACE_" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.HFW) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) # Mesa parameters length = i3.PositiveNumberProperty(default=2500) # shrink width = i3.PositiveNumberProperty(default=3000.0 * 0.6) pocket = i3.BoolProperty(default=False) tilt = i3.BoolProperty(default=False) class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(x0 + 7500 + 2000+1500, y0 + 4500 - 1800+500), box_size=(10000, 1600)) # change # 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 + 2000+1500, y0 + 500 - 200-500), box_size=(10000, 1600)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 12500 + 1000 - 250, y0 + 2500 - 1000), # change box_size=(self.length, self.width)) elems +=i3.Rectangle(layer=self.layer, center=(x0+ 15250, y0+1500),box_size=(1500,1800)) #add if self.pocket: PO = i3.Rectangle(layer=self.layer_bool, center=(10001 + 2000, 2500 - 1000), 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 - 1000), (10010.58 + 2000, 2530.0 - 1000), (10000.0 + 2000, 2530.0 - 1000)], 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
class Layout(i3.LayoutView): length = i3.PositiveNumberProperty(default=25.0, doc="Length of the mmi.") width = i3.PositiveNumberProperty(default=5.0, doc="Width of core layer at center of the mmi.") transistion_length = i3.PositiveNumberProperty(default=5.0, doc="Length of the tapers.") wg_spacing_in = i3.NonNegativeNumberProperty(default=2.0, doc="Center to center distance between the waveguides at the input.") wg_spacing_out = i3.NonNegativeNumberProperty(default=2.0, doc="Center to center distance between the waveguides at the output.") taper_width = i3.PositiveNumberProperty(default=1.0, doc="Width of the core of the taper of the access waveguides of the mmi.") @i3.cache() def _get_input_taper_coords(self): # coordinates of the input tapers [(taper1_begin, taper1_end), (taper2_begin, taper2_end), ...] base_y = - (self.n_inputs - 1) * self.wg_spacing_in / 2.0 taper_coords = [ [(0, base_y + cnt * self.wg_spacing_in), (-self.transistion_length, base_y + cnt * self.wg_spacing_in)] for cnt in range(self.n_inputs)] return taper_coords @i3.cache() def _get_output_taper_coords(self): # coordinates of the output tapers [(taper1_begin, taper1_end), (taper2_begin, taper2_end), ...] base_y = - (self.n_outputs - 1) * self.wg_spacing_out / 2.0 taper_coords = [[(self.length, base_y + cnt * self.wg_spacing_out), (self.length + self.transistion_length, base_y + cnt * self.wg_spacing_out)] for cnt in range(self.n_outputs)] return taper_coords def _generate_elements(self, elems): layer_core = self.trace_template.core_layer # mmi core elems += i3.Rectangle(layer=layer_core, center=(+self.length / 2.0, 0.0), box_size=(self.length, self.width)) # input wedges for bc, ec in self._get_input_taper_coords(): elems += i3.Wedge(layer_core, begin_coord=bc, end_coord=ec, begin_width=self.taper_width, end_width=self.trace_template.core_width) for bc, ec in self._get_output_taper_coords(): elems += i3.Wedge(layer_core, begin_coord=bc, end_coord=ec, begin_width=self.taper_width, end_width=self.trace_template.core_width) return elems def _generate_ports(self, ports): for cnt, coords in enumerate(self._get_input_taper_coords(), 1): ports += i3.OpticalPort(name="in{}".format(cnt), position=coords[1], angle=180.0, trace_template=self.trace_template) for cnt, coords in enumerate(self._get_output_taper_coords(), 1): ports += i3.OpticalPort(name="out{}".format(cnt), position=coords[1], angle=0.0, trace_template=self.trace_template) return ports
class Layout(APAC.Layout): grating_coupler_spacing = i3.PositiveNumberProperty(default=800, doc="Spacing between the grating couplers") center_grating_coupler_y = i3.PositiveNumberProperty(doc="Start position of the first grating coupler") def _default_metal1_width(self): return 20.0 def _default_center_bp(self): return 2500 / 2.0 def _default_center_grating_coupler_y(self): return 5150.0 / 2.0 def _default_child_transformations(self): trans = dict() nw = len(self.m_spacing) for cnt, mod in enumerate(self.modulators): t = (100.0, self.center_grating_coupler_y + (-nw / 2.0 + 0.5 + cnt) * self.grating_coupler_spacing) trans["grating_in_{}".format(cnt)] = i3.Translation(translation=t) t = (2500/2.0 , self.center_grating_coupler_y + (-nw / 2.0 + 0.5 + cnt) * self.grating_coupler_spacing) trans["mod_{}".format(cnt)] = i3.Translation(translation=t) trans["grating_out_{}".format(cnt)] = i3.Rotation(rotation=180.0) + i3.Translation(translation=(2500, self.center_grating_coupler_y + (-nw / 2.0 + 0.5 + cnt) * self.grating_coupler_spacing)) return trans @i3.cache() def _default_electrical_routes(self): routes = [] for c in self.electrical_links: inst1, port1 = self._resolve_inst_port(c[0]) inst2, port2 = self._resolve_inst_port(c[1]) if "left" in port1.name: r = i3.RouteManhattan(input_port=port1, output_port=port2, min_straight=100.0, angle_out=0.0, angle_in=180.0, rounding_algorithm=None) else: r = i3.RouteManhattan(input_port=port1, output_port=port2, min_straight=100.0, angle_out=180.0, angle_in=0.0, rounding_algorithm=None) routes.append(r) return routes
class SiN_NP(i3.PCell): _name_prefix = "SiN_NP" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.SIL.LINE) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) # Mesa parameters length = i3.PositiveNumberProperty(default=7000.0) width = i3.PositiveNumberProperty(default=330.0) pillar = i3.BoolProperty(default=False) tilt_0 = i3.BoolProperty(default=False) class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(1500 - 20, 2500), box_size=(3000 - 40, 3000 - 40 * 2)) if self.tilt_0: elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500 - 40 + 20 + 7.5, 2500), box_size=(self.length + 40 + 15, self.width - 40 * 2)) else: elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500 - 40 + 20 + 5, 2500), box_size=(self.length + 40 + 10, self.width - 40 * 2)) if self.pillar: for i in range(7): elems += i3.Rectangle( layer=self.layer_bool, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + 30), box_size=(130, 140)) elems += i3.Rectangle( layer=self.layer_bool, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + self.width - 30), box_size=(130, 140)) generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) return elems
class Layout(i3.LayoutView): """ Cross marker Layout view """ inversion = i3.BoolProperty( default=False, doc="if True: open cross - white cross on black background") cross_bar_width = i3.PositiveNumberProperty(default=8, doc="width of the cross") cross_boundary_width = i3.PositiveNumberProperty( default=50, doc="width the boundary box") #process = i3.ProcessProperty(default=i3.TECH.PPLAYER.CH2.TRENCH)#i3.TECH.PROCESS.WG, doc="Process Layer on which the cross is drawn") # Purpose Property cannot be set from outside #purpose = i3.PurposeProperty(locked=True, default=i3.TECH.PPLAYER.CH2.TRENCH)#i3.TECH.PURPOSE.DF.LINE, doc="Process Purpose of the cross") def _generate_elements(self, elems): rect_size = (self.cross_boundary_width - self.cross_bar_width) / 2 rect_center = self.cross_bar_width / 2 + rect_size / 2 if not self.inversion: # Dark cross elems += i3.Cross( layer=i3.TECH.PPLAYER.CH1. TRENCH, #i3.PPLayer(self.process,self.purpose), center=(0, 0), box_size=self.cross_boundary_width, thickness=self.cross_bar_width) else: # Open cross: formed by 4 dark squares at corners elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH2. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(rect_center, rect_center), box_size=(rect_size, rect_size)) elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH2. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(rect_center, -rect_center), box_size=(rect_size, rect_size)) elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH2. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(-rect_center, rect_center), box_size=(rect_size, rect_size)) elems += i3.Rectangle( layer=i3.TECH.PPLAYER.CH2. TRENCH, #i3.PPLayer(self.process, self.purpose), center=(-rect_center, -rect_center), box_size=(rect_size, rect_size)) return elems
class JoinedObstacles(i3.PCell): #(Structure): channel_template = microfluidics.ChannelTemplateProperty( default=microfluidics.ShortChannelTemplate(), doc="Channel template for ports") mysingleObstacle = i3.ChildCellProperty( doc='the single Obstacle child cell, which will be clonned many times', default=Obstacle_BooleanBoundary()) wholeTrapX = i3.PositiveNumberProperty( default=500.0, doc="total X distance length of traps") wholeTrapY = i3.PositiveNumberProperty( default=500.0, doc="total Y distance length of traps") cInp = i3.Coord2Property(default=0.0, doc="") class Layout(i3.LayoutView): def _generate_instances(self, insts): x_inc = (self.mysingleObstacle.gap_btw_barriers + self.mysingleObstacle.obstacle_trap_length) * 2 y_inc = self.mysingleObstacle.channel_trap_width * 1.5 cycles_x = int(self.wholeTrapX / ((self.mysingleObstacle.gap_btw_barriers + self.mysingleObstacle.obstacle_trap_length) * 2)) cycles_y = int(self.wholeTrapY / (y_inc)) insts += i3.ARef(reference=self.mysingleObstacle, origin=(0, 0.0 * self.cell.wholeTrapY), period=(x_inc, y_inc), n_o_periods=(cycles_x, cycles_y)) print 'insts', insts return insts def _generate_ports(self, ports): #port1 ports += microfluidics.FluidicPort( name='in', position=(0, self.wholeTrapY * 0.5), #position = (0, 'insts_0'.size_info().north*0.5), direction=i3.PORT_DIRECTION.IN, angle_deg=180, trace_template=self.cell.channel_template) #port2 ports += microfluidics.FluidicPort( name='out', position=(self.wholeTrapX, self.wholeTrapY * 0.5), direction=i3.PORT_DIRECTION.OUT, angle_deg=0, trace_template=self.cell.channel_template) return ports
class Layout(i3.LayoutView): # Properties ------- length = i3.PositiveNumberProperty(default=0.0, doc='length of taper') width1 = i3.PositiveNumberProperty(default=0.0, doc='width of left edge of taper') width2 = i3.PositiveNumberProperty(default=0.0, doc='width of right edge of taper') width_etch = i3.PositiveNumberProperty( default=0.0, doc='width of taper sidewall etch') # Methods ------- def _generate_elements(self, elems): """ This method generates layout by adding elements to 'elems' """ # draw wg elems += i3.ParabolicWedge(layer=i3.TECH.PPLAYER.WG.COR, begin_coord=(-self.length, 0.0), end_coord=(0.0, 0.0), begin_width=self.width1, end_width=self.width2) # draw clad etch for block_lay in block_layers: elems += i3.ParabolicWedge( layer=block_lay, begin_coord=(-self.length, 0.0), end_coord=(0.0, 0.0), begin_width=self.width1 + 2 * self.width_etch, end_width=self.width2 + 2 * self.width_etch) # return elems return elems # end _generate_elements() def _generate_ports(self, ports): # generate ports # the ports are 'right', and 'left' ports += i3.OpticalPort(name='right', position=(0.0, 0.0), angle=0.0) ports += i3.OpticalPort(name='left', position=(-self.length, 0.0), angle=180.0) return ports
class Layout(i3.LayoutView): length = i3.PositiveNumberProperty(default=5.0, doc="length") width = i3.PositiveNumberProperty(doc="width") def _default_width(self): return self.length def _generate_elements(self, elems): shape_rect = i3.ShapeRectangle(box_size=(self.length, self.width)) elems += i3.Boundary(layer=i3.TECH.PPLAYER.WG.CORE, shape=shape_rect) return elems
class Layout(PlaceAndAutoRoute.Layout): radius = i3.PositiveNumberProperty(doc="radius", default=200.0) gap = i3.PositiveNumberProperty(doc="gap", default=1.0) length = i3.PositiveNumberProperty(doc="coupler_length", default=60.0) # def _default_mmi1_12(self): # layout_mmi1_12 = self.cell.mmi1_12.get_default_view(i3.LayoutView) # layout_mmi1_12.set(transition_length=200.0, length=self.length, trace_spacing=11.0) # return layout_mmi1_12 def _default_ring1(self): layout_ring1 = self.cell.ring1.get_default_view(i3.LayoutView) layout_ring1.set( bend_radius=self.radius, coupler_lengths=[self.length, self.length], coupler_radii=[300.0, 300.0], coupler_angles=[90.0, 90.0], coupler_spacings=[3.8 + self.gap, 3.8 + self.gap], straights=(self.length, 0.0), # manhattan=True, ) return layout_ring1 def _default_ring2(self): layout_ring1 = self.cell.ring2.get_default_view(i3.LayoutView) layout_ring1.set( bend_radius=self.radius + 20, coupler_lengths=[self.length, self.length], coupler_radii=[300.0, 300.0], coupler_angles=[90.0, 90.0], coupler_spacings=[3.8 + self.gap, 3.8 + self.gap], straights=(self.length, 0.0), # manhattan=True, ) return layout_ring1 def _default_child_transformations(self): # print self.cell.mmi1_12.get_default_view(i3.LayoutView).length # print self.cell.mmi1_21.get_default_view(i3.LayoutView).ports['in1'].x # print self.cell.mmi1_21.get_default_view(i3.LayoutView).ports['out'].x # a = self.cell.mmi1_21.get_default_view(i3.LayoutView).ports['out'].x - \ # self.cell.mmi1_21.get_default_view(i3.LayoutView).ports['in1'].x child_transformations = {"MMI1a": (0, -2000), "MMI1b": (0, 2500)} return child_transformations def _default_bend_radius(self): bend_radius = 300 return bend_radius
class Layout(PlaceAndAutoRoute.Layout): length2 = i3.PositiveNumberProperty(doc="MMI2 length", default=97) def _default_WG1(self): layout_WG1 = self.cell.WG1.get_default_view(i3.LayoutView) layout_WG1.set(shape=[(0.0, 0.0), (150.0, 0.0)]) return layout_WG1 def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(start_position=(150.0, 0.0), end_position=(450.0, 0.0)) return layout_WG2 def _default_mmi22(self): # layout_mmi22 = self.cell.mmi22.get_default_view(i3.LayoutView) self.cell.mmi22.length = self.length2 layout_mmi22 = self.cell.mmi22.get_default_view(i3.LayoutView) layout_mmi22.set(length=self.length2) return layout_mmi22 def _default_child_transformations(self): child_transformations = {"MMI1b": (1300, 0), "WGup": (0, 4000), "WGuptaper": (0, 4000), "WGdown": (0, -4000), "WGdowntaper": (0, -4000), "WGuptaper2": i3.HMirror() + i3.Translation((3300, 2000)), "WGdowntaper2": i3.HMirror() + i3.Translation((3300, -6000)), "WGup2": (3150, 2000), "WGdown2": (3150, -6000)} return child_transformations def _default_bend_radius(self): bend_radius = 300 return bend_radius
class Layout(PlaceAndAutoRoute.Layout): length = i3.PositiveNumberProperty(doc="MMI length", default=97) def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(shape=[(0.0, 0.0), (300.0, 0.0)]) return layout_WG2 def _default_narro(self): layout = self.cell.narro.get_default_view(i3.LayoutView) layout.set(shape=[(0.0, 0.0), (300.0, 0.0)]) return layout def _default_child_transformations(self): trans = dict() for counter in range(0, 24, 1): trans['edge1' + str(counter)] = i3.Translation( translation=(-300, counter * 150)) trans['edge2' + str(counter)] = i3.Translation( translation=(-300, counter * 150 + 7500)) for counter in range(24, 48, 1): trans['edge1' + str(counter)] = i3.Translation( translation=(18600, counter * 150 - 2600)) trans['edge2' + str(counter)] = i3.Translation( translation=(18600, counter * 150 + 7500 - 2600)) return trans
class CircuitModel(i3.CircuitModelView): center_wavelength = i3.PositiveNumberProperty( default=1.55, doc="center wavelength [um]") bandwidth_3dB = i3.PositiveNumberProperty(default=0.060, doc="3dB bandwidth [um]") peak_transmission = i3.NonNegativeNumberProperty( default=1.0, doc="peak transmission (0 to 1)") reflection = i3.ComplexFractionProperty( default=0.0, doc="Complex reflection back into the waveguide") def _generate_model(self): return GratingModel(center_wavelength=self.center_wavelength, bandwidth_3dB=self.bandwidth_3dB, peak_transmission=self.peak_transmission, reflection=self.reflection)
class AlignmentMarkerSet(i3.PCell): _name_prefix = "ALIGNMENT MARKER SET" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Spacing v_spacing = i3.PositiveNumberProperty(default=5000.0) class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position # ADD RELEASE elems += i3.SRef(reference=Interface(pocket=False, tilt=False), transformation=i3.Translation( (x0, 0.0 * self.v_spacing + y0))) elems += i3.SRef(reference=Interface(pocket=True, tilt=False), transformation=i3.Translation( (x0, 1.0 * self.v_spacing + y0))) elems += i3.SRef(reference=Interface(pocket=False, tilt=True), transformation=i3.Translation( (x0, 2.0 * self.v_spacing + y0))) elems += i3.SRef(reference=Interface(pocket=True, tilt=True), transformation=i3.Translation( (x0, 3.0 * self.v_spacing + y0))) return elems
class Layout(PlaceAndAutoRoute.Layout): length = i3.PositiveNumberProperty(doc="MMI length", default=97) def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(start_position=(0.0, 0.0), end_position=(200.0, 0.0)) return layout_WG2 def _default_mmi1_12(self): layout_mmi1_12 = self.cell.mmi1_12.get_default_view(i3.LayoutView) layout_mmi1_12.set(transition_length=200.0, length=self.length, trace_spacing=11.0) return layout_mmi1_12 def _default_mmi1_21(self): layout_mmi1_21 = self.cell.mmi1_21.get_default_view(i3.LayoutView) layout_mmi1_21.set(name="MMI2112_l_{}".format(str(self.length)), transition_length=200.0, length=self.length, trace_spacing=11.0) # print layout_mmi1_21.ports['in1'].x return layout_mmi1_21 def _default_child_transformations(self): a = self.cell.mmi1_21.get_default_view(i3.LayoutView).ports['out'].x child_transformations = {"MMI1a": (a + 490, 0), "taper": (a, 0), "taper2": i3.HMirror(0.0) + i3.Translation((a + 490, 0)) } return child_transformations
class Layout(i3.LayoutView): spacing = i3.PositiveNumberProperty( default=0.2, doc="Spacing between the waveguides", locked=True) bend_radius = i3.PositiveNumberProperty( default=10.0, doc="Bend radius of the directional coupler", locked=True) 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_ports(self, ports): ports += self.instances["wav_top"].ports["in"].modified_copy( name="in2") ports += self.instances["wav_top"].ports["out"].modified_copy( name="out2") ports += self.instances["wav_bot"].ports["in"].modified_copy( name="in1") ports += self.instances["wav_bot"].ports["out"].modified_copy( name="out1") return ports
class Layout(PlaceAndAutoRoute.Layout): length = i3.PositiveNumberProperty(doc="MMI length", default=398) # width = i3.PositiveNumberProperty(doc="width of ports", default=15) # def _default_wg_t1(self): # layout_wg_t1 = self.cell.wg_t1.get_default_view(i3.LayoutView) # layout_wg_t1.set(core_width=self.width, # cladding_width=self.width + 16.0, # core_process=i3.TECH.PROCESS.WG) # return layout_wg_t1 def _default_WG1(self): layout_WG1 = self.cell.WG1.get_default_view(i3.LayoutView) layout_WG1.set(shape=[(0.0, 0.0), (150.0, 0.0)]) return layout_WG1 def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(start_position=(150.0, 0.0), end_position=(450.0, 0.0)) return layout_WG2 def _default_WGSM(self): layout_WGSM = self.cell.WGSM.get_default_view(i3.LayoutView) layout_WGSM.set(shape=[(0.0, 0.0), (400.0, 0.0)]) return layout_WGSM def _default_mmi22(self): layout_mmi22 = self.cell.mmi22.get_default_view(i3.LayoutView) layout_mmi22.set(name="MMI22_l_{}".format(str(self.length)), transition_length=200.0, length=self.length, trace_spacing=11.0) return layout_mmi22 def _default_child_transformations(self): child_transformations = { # "MMI1b": (1300, 0), # "WGup": (0, 4000), # "WGuptaper": (0, 4000), # "WGdown": (0, -4000), # "WGdowntaper": (0, -4000), # "WGuptaper2": i3.HMirror() + i3.Translation((3000, 2000)), # "WGdowntaper2": i3.HMirror() + i3.Translation((3000, -6000)), # "WGup2": (2850, 2000), # "WGdown2": (2850, -6000), "dummy1": (1300, -300), "DWGup": (0, 20900), "DWGuptaper": (0, 20900), "DWGdown": (0, -4300), "DWGdowntaper": (0, -4300), "DWGuptaper2": i3.HMirror() + i3.Translation((3000, 20900)), "DWGdowntaper2": i3.HMirror() + i3.Translation((3000, -6300)), "DWGup2": (2850, 20900), "DWGdown2": (2850, -6300) } return child_transformations def _default_bend_radius(self): bend_radius = 300 return bend_radius
class Square(PlaceComponents): size=i3.PositiveNumberProperty(default=20.0, doc="simension of the square of aligning mark") separation=i3.PositiveNumberProperty(default=2.0, doc="simension of the square of aligning mark") square = i3.ChildCellProperty(doc="grating with pitch 1", locked=True) tt_square = i3.TraceTemplateProperty(doc="Wide trace template used ") layName = i3.StringProperty(default = 'new') props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) def _default_tt_square(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=(self.size), cladding_width=(self.size), **self.props ) print 'ttw in Square is ', tt_w return tt_w def _default_square(self): rect=i3.Waveguide(trace_template=self.tt_square) layout_rect = rect.Layout(shape=[(0.0, self.size/2.0),(self.size,self.size/2.0)]) print 'The trace template of the hline of the cross ', rect.trace_template return rect def _default_child_cells(self): child_cells={"S1" : self.square, } return child_cells class Layout(PlaceComponents.Layout): def _default_child_transformations(self): child_transformations={ "S1" : i3.Translation(translation=(-(self.size*0.5),(-self.size*0.5))), } return child_transformations
class Layout(PlaceAndAutoRoute.Layout): length = i3.PositiveNumberProperty(doc="MMI length", default=97) def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(start_position=(0.0, 0.0), end_position=(200.0, 0.0)) return layout_WG2 def _default_mmi1_12(self): layout_mmi1_12 = self.cell.mmi1_12.get_default_view(i3.LayoutView) layout_mmi1_12.set(transition_length=200.0, length=self.length, trace_spacing=11.0) return layout_mmi1_12 def _default_mmi1_21(self): layout_mmi1_21 = self.cell.mmi1_21.get_default_view(i3.LayoutView) layout_mmi1_21.set(name="MMI2112_l_{}".format(str(self.length)), transition_length=200.0, length=self.length, trace_spacing=11.0) # print layout_mmi1_21.ports['in1'].x return layout_mmi1_21 def _default_child_transformations(self): a = self.cell.mmi1_21.get_default_view( i3.LayoutView).ports['out'].x child_transformations = { "MMI1a": (a + 490, 0), "taper": (a, 0), "taper2": i3.HMirror(0.0) + i3.Translation((a + 490, 0)) } return child_transformations def _generate_elements(self, elems): elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Name={}_port_15'.format( self.cell.mmi1_21.get_default_view(i3.LayoutView).name), coordinate=(200.0, 100.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Name={}_port_15'.format( self.cell.mmi1_21.get_default_view(i3.LayoutView).name), # coordinate=(-4000.0, -1650.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=200.0, transformation=i3.Rotation((0.0, 0.0), 90.0) + i3.Translation( (-2050, -2000))) return elems
class Release(i3.PCell): _name_prefix = "RELEASE" # Layer lay_release = i3.Layer(number=1, name="release") layer = i3.LayerProperty(default=lay_release) # Mesa parameters length = i3.PositiveNumberProperty(default=40.0) width = i3.PositiveNumberProperty(default=8.0) class Layout(i3.LayoutView): def _generate_elements(self, elems): elems += i3.Rectangle(layer=self.layer, center=(0, 0), box_size=(self.length, self.width)) return elems
class CircuitModel(i3.CircuitModelView): length = i3.PositiveNumberProperty( doc="Lengths of the crossing waveguides used for simulation") neff = i3.PositiveNumberProperty( doc='Effective index (by default, the same as SWG450)') crosstalk_dB = i3.NonNegativeNumberProperty( doc='Crosstalk in amplitude (dB)') insertion_loss_dB = i3.NonNegativeNumberProperty( doc="Insertion Loss (dB)") reflection_dB = i3.NonNegativeNumberProperty(doc='Reflection (dB)') def _generate_model(self): from aeponyx.compactmodels import CrossingCompactModel return CrossingCompactModel( length=self.length, neff=self.neff, crosstalk_dB=self.crosstalk_dB, insertion_loss_dB=self.insertion_loss_dB, reflection_dB=self.reflection_dB)
class CircuitModel(i3.CircuitModelView): coupler_length = i3.PositiveNumberProperty( doc= "Length of the straight section of the directional coupler, calculated from the power coupling", locked=True) power_coupling_factor = i3.FractionProperty( default=0.5, doc="Fraction of the field coupling") delta_n_eff = i3.NumberProperty( doc="Difference between even and odd mode of the dc") coupling_at_zero_length = i3.NonNegativeNumberProperty( default=0.03, doc="Field coupling for a zero length coupling", locked=True) center_wavelength = i3.PositiveNumberProperty( doc="Reference wavelength for all parameters", locked=True) def _default_center_wavelength(self): return self.trace_template.center_wavelength def _default_delta_n_eff(self): return 0.04 def _default_coupler_length(self): L = (self.center_wavelength * np.arcsin(self.power_coupling_factor**0.5) / (np.pi * self.delta_n_eff) - self.center_wavelength * np.arcsin(self.coupling_at_zero_length) / (np.pi * self.delta_n_eff)) return L def _generate_model(self): trace_length = self.layout_view.instances[ 'wav_top'].reference.trace_length() non_coupling_length = (trace_length - self.coupler_length) return DirCoupModel( delta_n=self.delta_n_eff, n_avg=self.trace_template.n_eff, coupler_length=self.coupler_length, non_coupling_length=non_coupling_length, coupling_at_zero_length=self.coupling_at_zero_length, center_wavelength=self.center_wavelength)
class AL_PI(i3.PCell): _name_prefix = "AL_PI" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.CONTACT.PILLAR) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) # Mesa parameters length = i3.PositiveNumberProperty(default=7000.0) width = i3.PositiveNumberProperty(default=630.0) class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(1500 - 20, 2500), box_size=(3000 - 40, 3000 - 40 * 2)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500 - 40, 2500), box_size=(self.length, self.width - 40 * 2)) for i in range(7): elems += i3.Rectangle(layer=self.layer_bool, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + 185), box_size=(130, 130)) elems += i3.Rectangle( layer=self.layer_bool, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + self.width - 185), box_size=(130, 130)) generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) return elems
class CircuitModel(i3.CircuitModelView): center_wavelength = i3.PositiveNumberProperty( doc="center wavelength (um)") bandwidth_1dB = i3.PositiveNumberProperty(doc="1dB bandwidth (um)") peak_IL_dB = i3.NonNegativeNumberProperty( doc="peak insertion loss (dB)") reflection = i3.ComplexFractionProperty( doc="Complex reflection back into the waveguide") reflection_vertical_in = i3.ComplexFractionProperty( doc="Complex reflection back into the vertical direction") def _generate_model(self): from aeponyx.compactmodels import GratingCouplerCompactModel return GratingCouplerCompactModel( center_wavelength=self.center_wavelength, bandwidth_1dB=self.bandwidth_1dB, peak_IL_dB=self.peak_IL_dB, reflection=self.reflection, reflection_vertical_in=self.reflection_vertical_in)
class Layout(PlaceAndAutoRoute.Layout): length = i3.PositiveNumberProperty(doc="MMI length", default=398) # width = i3.PositiveNumberProperty(doc="width of ports", default=15) # def _default_wg_t1(self): # layout_wg_t1 = self.cell.wg_t1.get_default_view(i3.LayoutView) # layout_wg_t1.set(core_width=self.width, # cladding_width=self.width + 16.0, # core_process=i3.TECH.PROCESS.WG) # return layout_wg_t1 def _default_WG1(self): layout_WG1 = self.cell.WG1.get_default_view(i3.LayoutView) layout_WG1.set(shape=[(0.0, 0.0), (150.0, 0.0)]) return layout_WG1 def _default_WG2(self): layout_WG2 = self.cell.WG2.get_default_view(i3.LayoutView) layout_WG2.set(start_position=(150.0, 0.0), end_position=(450.0, 0.0)) return layout_WG2 def _default_mmi22(self): layout_mmi22 = self.cell.mmi22.get_default_view(i3.LayoutView) layout_mmi22.set(name="MMI22_l_{}".format(str(self.length)), transition_length=200.0, length=self.length, trace_spacing=11.0) return layout_mmi22 def _default_child_transformations(self): child_transformations = {"MMI1b": (1300, 0), "WGup": (0, 4000), "WGuptaper": (0, 4000), "WGdown": (0, -4000), "WGdowntaper": (0, -4000), "WGuptaper2": i3.HMirror() + i3.Translation((3000, 2000)), "WGdowntaper2": i3.HMirror() + i3.Translation((3000, -6000)), "WGup2": (2850, 2000), "WGdown2": (2850, -6000)} return child_transformations def _default_bend_radius(self): bend_radius = 300 return bend_radius def _generate_elements(self, elems): elems += i3.PolygonText(layer=i3.TECH.PPLAYER.WG.TEXT, text='Name={}_{}'.format(self.cell.mmi22.get_default_view(i3.LayoutView).name, self.cell.wg_t1.name), coordinate=(1300.0, 100.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) return elems
class DropRing(PlaceAndAutoRoute): """ Drop ring with the total ring length as a property. """ directional_coupler = i3.ChildCellProperty( doc="Directional couplers used for the ring resonator") total_ring_length = i3.PositiveNumberProperty(doc="Total ring length") def _default_trace_template(self): return SiWireWaveguideTemplate(name=self.name + "tt") def _default_total_ring_length(self): return 200.0 def _default_directional_coupler(self): dc = DirectionalCoupler(name=self.name + 'dc') return dc def _default_child_cells(self): return { 'dc1': self.directional_coupler, 'dc2': self.directional_coupler } def _default_links(self): return [('dc1:in2', 'dc2:in2'), ('dc1:out2', 'dc2:out2')] def _default_external_port_names(self): return { "dc1:in1": "in1", "dc1:out1": "out1", "dc2:out1": "in2", "dc2:in1": "out2", } class Layout(PlaceAndAutoRoute.Layout): def _get_distance_between_dc(self): # Get length of the curved section of the directional coupler. dc = self.directional_coupler waveguide_length = (self.total_ring_length - 2 * dc.get_length_ring_section()) / 2.0 height_out_port = dc.ports["out2"].y return 2 * height_out_port + waveguide_length def _default_child_transformations(self): return { "dc1": (0, 0), "dc2": i3.VMirror(0.0) + i3.Translation( (0, self._get_distance_between_dc())) }
class SimpleRing(RingRect180DropFilter): resonance_wavelength = i3.PositiveNumberProperty(default=1.55) length = i3.PositiveNumberProperty() order = i3.PositiveIntProperty(default=200) def _get_neff_at_res(self): tt = self.coupler_trace_templates[0] cm = tt.get_default_view(i3.CircuitModelView) # Get the n_eff and n_g from the circuit model n_eff = cm.n_eff n_g = cm.n_g cw = cm.center_wavelength dneff = -(n_g - n_eff) / cw dl = self.resonance_wavelength - cw n_res = n_eff + dneff * (dl) return n_res def _default_length(self): length = self.order * self.resonance_wavelength / self._get_neff_at_res( ) return length class Layout(RingRect180DropFilter.Layout): def _default_straights(self): return [0.0, 0.0] def _default_bend_radius(self): return self.length / np.pi / 2 class CircuitModel(RingRect180DropFilter.CircuitModel): def _default_coupler_parameters(self): tau = 0.9**0.5 kappa = 1j * (1 - tau**2)**0.5 cp = dict(cross_coupling1=kappa, straight_coupling1=tau) return [cp, cp] def _default_ring_length(self): return self.length
class flowcellbox(i3.PCell): #widthchip = i3.PositiveNumberProperty(default=15000) #heightchip = i3.PositiveNumberProperty(default=20000) widthchip = i3.PositiveNumberProperty(default=15000) heightchip = i3.PositiveNumberProperty(default=20000) class Layout(i3.LayoutView): layer = i3.LayerProperty(default=i3.TECH.TRACE.DEFAULT_LAYER) #layer_c = i3.LayerProperty(default=i3.TECH.TRACE.DEFAULT_LAYER) def _default_layer(self): layer=PPLayer(process=i3.TECH.PROCESS.WG,purpose=i3.TECH.PURPOSE.LF.LINE) return layer def _generate_elements(self, elems): elems += i3.Rectangle(layer=self.layer, box_size=(self.heightchip,self.widthchip)) return elems