class SimpleMMI(Coupler1x2): trace_template = i3.TraceTemplateProperty(doc="Trace template of the access waveguide") def _default_trace_template(self): return i3.TECH.PCELLS.WG.DEFAULT 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=(-self.taper_length, 0.0), end_coord=(0.0, 0.0), begin_width=self.trace_template.core_width, end_width=self.taper_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="in", position=(-self.taper_length, 0.0), 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 CircuitModel(Coupler1x2.CircuitModel): pass
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 SimpleMMI(i3.PCell): trace_template = i3.TraceTemplateProperty( doc="Trace template of the access waveguide") def _default_trace_template(self): return WireWaveguideTemplate() 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=(-self.taper_length, 0.0), end_coord=(0.0, 0.0), begin_width=self.trace_template.core_width, end_width=self.taper_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="in", position=(-self.taper_length, 0.0), 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 Netlist(i3.NetlistFromLayout): pass class CapheModelCST(CapheModelCST): """ This model encapsulates all the properties of the simulation. This way we consolidate simulation settings. """ def _default_start_wavelength(self): return 1.45e-6 def _default_stop_wavelength(self): return 1.55e-6 def _default_cells_per_wave(self): return 6 # 10 for more precise results def _default_additional_commands_path(self): import os return r"{}\additional_commands.mod".format( os.path.dirname(__file__)) # Extra settings set in the CST GUI def _default_bounding_box(self): si = self.extended_layout.size_info() w = self.layout.width bounding_box = [ [si.west, si.east], # [startx, stopx], propagation direction [-w / 2.0 - 0.7, +w / 2.0 + 0.7], # [starty,stopy] [0.15, 0.5 + 0.22 + 0.6] ] # [startz, stopz], layer direction return bounding_box
class MZI_12_21(PlaceAndAutoRoute): _name_prefix = 'MZIs' #delay_length = i3.PositiveNumberProperty(default=132.0, doc="Delay length used in the mzi") delay_length = i3.PositiveNumberProperty(default=0.00001, doc="Delay length used in the mzi") R = i3.PositiveNumberProperty(default=200, doc="Radius of curvature") #MMI12_list = i3.ChildCellListProperty(default=[]) MMI12 = i3.ChildCellProperty(default=[]) MMI21_list = i3.ChildCellListProperty(default=[]) MMI22_list = i3.ChildCellListProperty(default=[]) #MZI_12_21_list = i3.ChildCellListProperty(default=[]) MZI_12_22_list = i3.ChildCellListProperty(default=[]) MZI_22_22_list = i3.ChildCellListProperty(default=[]) #MMI22_list = i3.ChildCellListProperty() wg_t = i3.TraceTemplateProperty(doc="trace template used") wg_t_MM = i3.TraceTemplateProperty(doc="Trace template used in the MM part") wg_t_port = i3.TraceTemplateProperty(doc="Trace template used in the ports") width_inc_vec = i3.ListProperty(default=[]) length_inc_vec = i3.ListProperty(default=[]) l_taper =i3.PositiveNumberProperty(default=200.0, doc="Length of the tapers") width=i3.PositiveNumberProperty(default=20.0, doc="width of MM") length_12 =i3.PositiveNumberProperty(default=110.0, doc="Length of MMI 1x2") length_22 =i3.PositiveNumberProperty(default=435.0, doc="Length of MMI 2x2") ts_12=i3.PositiveNumberProperty(default=11.25, doc="trace spacing") #ts for 12 is 7.0 --> MM=5 () L12=39.0 L22=158.0 #ts for 20 is 11 -->MM=9 (ts=11.25, MM=8.75) L12=110.0, L22=435.0 #ts for 30 is 16 -->MM=14 (ts=16.25, MM=13.75) L12=245.0, L22=980.0 chip_length = i3.PositiveNumberProperty(default=10000.0, doc="Radius of curvature") #chip_length = i3.PositiveNumberProperty(default=7100.0, doc="Radius of curvature") Port = i3.ChildCellProperty( doc="Used for ports") tlport = i3.PositiveNumberProperty(default=200.0, doc="Transition legth to ports") couplingWG = i3.ChildCellProperty(doc="", locked=True) couplingWG_l=i3.PositiveNumberProperty(default=3000.0, doc="Length of the coupling WG ") tt_port = i3.TraceTemplateProperty(doc="Wide trace template used for the contacts") tipo = i3.PositiveNumberProperty(default=1, doc="type of out-couplers tipo==1, straight, tipo==2, 90 degree bend") #template for Autorute def _default_trace_template(self): return self.wg_t def _default_wg_t_MM(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=self.width, cladding_width=self.width+2*8, ) return tt_w def _default_wg_t_port(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=8.75, cladding_width=8.75+2*8, ) return tt_w def _default_wg_t(self): tt_n = WireWaveguideTemplate() tt_n.Layout(core_width=3.3, cladding_width=3.3+2*8, ) return tt_n def _default_tt_port(self): tt_port = WireWaveguideTemplate() tt_port_layout=tt_port.Layout(core_width=15.0, cladding_width=15.0+2*8) return tt_port def _default_couplingWG(self): rect=i3.Waveguide(trace_template=self.tt_port) layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.couplingWG_l,0.0)] ) return rect def _default_Port(self): Port=AutoTransitionPorts(contents=self.couplingWG, port_labels=["in"], trace_template=self.wg_t) layout_Port = Port.Layout(transition_length=self.tlport)#.visualize(annotate=True) return Port def _default_MMI12(self): mmi12 = MMI1x2Tapered(mmi_trace_template=self.wg_t_MM, input_trace_template=self.wg_t_port, output_trace_template=self.wg_t_port, trace_template=self.wg_t, name = 'MMI12_w_{}_L_{}'.format(self.width,self.length_12 ),) mmi12.Layout(transition_length=self.l_taper, length=self.length_12, trace_spacing=self.ts_12)#.visualize(annotate=True) return mmi12 ################################################################################# def _default_MMI22_list(self): print '____________ MMI 2x2 ______________' MMI22_list = [] for l, dl in enumerate(self.length_inc_vec): print 'length number ' +str(l) print 'dl ' + str(dl) print 'MM length ' + str(self.length_22+dl) cell = MMI2x2Tapered(mmi_trace_template=self.wg_t_MM, input_trace_template=self.wg_t_port, output_trace_template=self.wg_t_port, trace_template=self.wg_t , name = 'MMI22_w_'+str(self.width) +'_l_'+str(self.length_22+dl)) cell.Layout(transition_length=self.l_taper, length=self.length_22+dl, trace_spacing=self.ts_12) MMI22_list.append(cell) print 'cell name '+str(cell.name) print '__________________________' for w, dw in enumerate(self.width_inc_vec): MM_w=self.width+dw print 'width number ' +str(w) print 'dw ' + str(dw) print 'MM width ' + str(MM_w) wg_t_MM_w = WireWaveguideTemplate() wg_t_MM_w.Layout(core_width=MM_w, cladding_width=MM_w+2*8, ) cell = MMI2x2Tapered(mmi_trace_template=wg_t_MM_w, input_trace_template=self.wg_t_port, output_trace_template=self.wg_t_port, trace_template=self.wg_t, name = 'MMI22_w_'+str(self.width+dw) +'_l_'+str(self.length_22)) cell.Layout(transition_length=self.l_taper, length=self.length_22, trace_spacing=self.ts_12+dw)#.visualize(annotate=True) print cell MMI22_list.append(cell) print 'cell name '+str(cell.name) print '__________________________' print 'last MMI22 done' print '_ _ _ _ _ _ _ _ _ _ _ _ _ ' return MMI22_list def _default_MZI_12_22_list(self): print '____________ MZI_1x2_2x2 ______________' MZI_12_22_list = [] counter=1 print '____________ MZI_1x2_2x2 list ______________' for i, m in enumerate(self.MMI22_list): print 'MZI number ' + str(counter) cell = MZIWaveguides(name='MZI_12_22:'+str(self.MMI12.name)+str(m.name), trace_template=self.wg_t, splitter=self.MMI12, combiner=m, splitter_port_names=['out1','out2'], combiner_port_names=['in1','in2']) cell.Layout(bend_radius=self.R, delay_length=self.delay_length)#.visualize(annotate=True) MZI_12_22_list.append(cell) counter=counter+1 print 'splitter '+ cell.splitter.name print 'combiner '+ cell.combiner.name print cell.name print '__________________________' print "Last MMI_12_22 done" print '_ _ _ _ _ _ _ _ _ _ _ _ _ ' return MZI_12_22_list def _default_MZI_22_22_list(self): print '____________ MZI_2x2_2x2 ______________' MZI_22_22_list = [] counter=1 print '____________ MZI_2x2_2x2 list ______________' for i, m in enumerate(self.MMI22_list): print 'MZI number ' + str(counter) cell = MZIWaveguides(name='MZI_22_22:'+str(m.name), trace_template=self.wg_t, splitter=m, combiner=m, splitter_port_names=['out1','out2'], combiner_port_names=['in1','in2']) cell.Layout(bend_radius=self.R,delay_length=self.delay_length)#.visualize(annotate=True) MZI_22_22_list.append(cell) counter=counter+1 print 'splitter '+ cell.splitter.name print 'combiner '+ cell.combiner.name print cell.name print '__________________________' print "Last MMI_22_22 done" print '_ _ _ _ _ _ _ _ _ _ _ _ _ ' return MZI_22_22_list ################################################################################# def _default_child_cells(self): print '____________ Child cells ______________' child_cells = {} for counter, child in enumerate(self.MZI_22_22_list): print 'child number'+str(counter) child_cells['mzi_22_22_' + str(counter)] = child child_cells['InPort1_' + str(counter)] = self.Port child_cells['OutPort1_' + str(counter)]= self.Port child_cells['InPort2_' + str(counter)] = self.Port child_cells['OutPort2_' + str(counter)]= self.Port print 'child name ' +str(child.name) print child ################# for counter2, child in enumerate(self.MZI_12_22_list): print 'child number'+str(counter+1+counter2) child_cells['mzi_12_22_' + str(counter+1+counter2)] = child child_cells['InPort_' + str(counter+1+counter2)] = self.Port child_cells['OutPort1_' + str(counter+1+counter2)]= self.Port child_cells['OutPort2_' + str(counter+1+counter2)]= self.Port print 'child name ' +str(child.name) print child ################### print '__________________________' child_cells['InPortWG1'] = self.Port child_cells['OutPortWG1'] = self.Port child_cells['InPortWG2'] = self.Port child_cells['OutPortWG2'] = self.Port child_cells['InPortWG3'] = self.Port child_cells['OutPortWG3'] = self.Port print "Last child cell done" print '_ _ _ _ _ _ _ _ _ _ _ _ _ ' return child_cells def _default_links(self): links = [] for counter, child in enumerate(self.MZI_22_22_list): print counter in_port = "InPort1_{}:in".format(counter) print 'in_port', in_port out_port = 'mzi_22_22_{}:splitter_in1'.format(counter) print 'out_port', in_port links.append((in_port, out_port)) in_port = "InPort2_{}:in".format(counter) print 'in_port', in_port out_port = 'mzi_22_22_{}:splitter_in2'.format(counter) links.append((in_port, out_port)) out_port = "OutPort1_{}:in".format(counter) in_port = 'mzi_22_22_{}:combiner_out1'.format(counter) print 'in_port', in_port links.append((in_port, out_port)) out_port = "OutPort2_{}:in".format(counter) in_port = 'mzi_22_22_{}:combiner_out2'.format(counter) print 'in_port', in_port links.append((in_port, out_port)) for counter2, child in enumerate(self.MZI_12_22_list): out_port = "InPort_{}:in".format(counter+1+counter2) in_port = 'mzi_12_22_{}:splitter_in'.format(counter+1+counter2) links.append((in_port, out_port)) in_port = "OutPort1_{}:in".format(counter+1+counter2) out_port = 'mzi_12_22_{}:combiner_out1'.format(counter+1+counter2) links.append((in_port, out_port)) in_port = "OutPort2_{}:in".format(counter+1+counter2) out_port = 'mzi_12_22_{}:combiner_out2'.format(counter+1+counter2) links.append((in_port, out_port)) links.append(("InPortWG1:in", "OutPortWG1:in")) links.append(("InPortWG2:in", "OutPortWG2:in")) links.append(("InPortWG3:in", "OutPortWG3:in")) return links class Layout(PlaceAndAutoRoute.Layout): def _default_bend_radius(self): return self.R def _default_start_straight(self): return 1.0 print '____________ Layout mask ______________' def _default_child_transformations(self): d={} a=2.2 for counter, child in enumerate(self.MZI_22_22_list): if self.tipo==1: d['mzi_22_22_' + str(counter)] = i3.Translation(translation=((-1)**counter*2*self.R,counter*5*self.R)) d['InPort1_' + str(counter)] = i3.HMirror()+i3.Translation(translation=(-self.chip_length*0.5, counter*5*self.R-2.2*self.R)) d['OutPort1_' + str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5, counter*5*self.R-2.2*self.R)) d['InPort2_' + str(counter)] = i3.HMirror()+i3.Translation(translation=(-self.chip_length*0.5, counter*5*self.R+2.2*self.R)) d['OutPort2_' + str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5, counter*5*self.R+2.2*self.R)) print 'transformation ' +str(counter) + ' is ' +str(d) if self.tipo==2: #l_coupling=self.child_cells['Coupler'].l_coupling #radius=self.child_cells['Coupler'].local_bend_radius print 'R= ',self.R #print 'translation port: ' ##For w=20 d['mzi_22_22_' + str(counter)] = i3.Translation(translation=(counter*850+1200+1000+200,-counter*5*self.R)) d['InPort1_'+ str(counter)] = i3.HMirror()+i3.Translation(translation=(1500, -5*self.R*counter-a*self.R)) d['OutPort1_'+ str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+counter*50+counter*4*self.R+a*self.R-100, self.R*a)) d['InPort2_'+ str(counter)] = i3.HMirror()+i3.Translation(translation=(1500, -5*self.R*counter+a*self.R)) d['OutPort2_'+ str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+counter*50+counter*4*self.R-100, self.R*a)) d['InPortWG1'] = i3.HMirror()+i3.Translation(translation=(1500, 1000.0)) d['OutPortWG1']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5-500, self.R*a)) d['InPortWG2'] = i3.HMirror()+i3.Translation(translation=(1500, -3400+670)) d['OutPortWG2']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+2500, self.R*a)) d['InPortWG3'] = i3.HMirror()+i3.Translation(translation=(1500, -6500)) d['OutPortWG3']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+5600, self.R*a)) #d['mzi_22_22_' + str(counter)] = i3.Translation(translation=(counter*850+1200+1000+200,-counter*5*self.R)) #d['InPort1_'+ str(counter)] = i3.HMirror()+i3.Translation(translation=(1500, -5*self.R*counter-a*self.R)) #d['OutPort1_'+ str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+1100+counter*50+counter*4*self.R+a*self.R-100, self.R*a)) #d['InPort2_'+ str(counter)] = i3.HMirror()+i3.Translation(translation=(1500, -5*self.R*counter+a*self.R)) #d['OutPort2_'+ str(counter)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+1100+counter*50+counter*4*self.R-100, self.R*a)) #d['InPortWG1'] = i3.HMirror()+i3.Translation(translation=(1500, 1000.0)) #d['OutPortWG1']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5-500+1200, self.R*a)) #d['InPortWG2'] = i3.HMirror()+i3.Translation(translation=(1500, -3400+670)) #d['OutPortWG2']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+2500+1100, self.R*a)) #d['InPortWG3'] = i3.HMirror()+i3.Translation(translation=(1500, -6500)) #d['OutPortWG3']= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+5600+1400, self.R*a)) ################ for counter2, child in enumerate(self.MZI_12_22_list): if self.tipo==1: d['mzi_12_22_' + str(counter+1+counter2)] = i3.Translation(translation=((-1)**counter2*2*self.R-self.length_22+counter*50+counter*4*self.R,(counter+1+counter2)*5*self.R)) d['InPort_' + str(counter+1+counter2)] = i3.HMirror()+i3.Translation(translation=(-self.chip_length*0.5, (counter+1+counter2)*5*self.R)) d['OutPort1_' + str(counter+1+counter2)]= i3.Translation(translation=(self.chip_length*0.5-self.bend_radius*counter*0.2-a*self.R-550, (counter+1+counter2)*5*self.R-2.2*self.R)) d['OutPort2_' + str(counter+1+counter2)]= i3.Translation(translation=(self.chip_length*0.5-self.bend_radius*counter*0.2-550, (counter+1+counter2)*5*self.R+2.2*self.R)) if self.tipo==2: #l_coupling=self.child_cells['Coupler'].l_coupling #radius=self.child_cells['Coupler'].local_bend_radius print 'R= ',self.R a=2.2 b=500 d['mzi_12_22_'+ str(counter+1+counter2)] = i3.Translation(translation=((counter+2+counter2)*850+1200+200+580,-(counter+1+counter2)*5*self.R-b)) d['InPort_'+ str(counter+1+counter2)] = i3.HMirror()+i3.Translation(translation=(1500, -(5*self.R)*(counter+1+counter2)-b)) d['OutPort1_'+ str(counter+1+counter2)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+(counter+1+counter2)*50+a*self.R+(counter+1+counter2)*4*self.R+b, self.R*a)) d['OutPort2_'+ str(counter+1+counter2)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+(counter+1+counter2)*50+(counter+1+counter2)*4*self.R+b,self.R*a)) #d['mzi_12_22_'+ str(counter+1+counter2)] = i3.Translation(translation=((counter+2+counter2)*850+1200+200+580+1000,-(counter+1+counter2)*5*self.R-b)) #d['InPort_'+ str(counter+1+counter2)] = i3.HMirror()+i3.Translation(translation=(1500, -(5*self.R)*(counter+1+counter2)-b)) #d['OutPort1_'+ str(counter+1+counter2)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+1200+(counter+1+counter2)*50+a*self.R+(counter+1+counter2)*4*self.R+b, self.R*a)) #d['OutPort2_'+ str(counter+1+counter2)]= i3.Rotation(rotation=90.0)+i3.Translation(translation=(self.chip_length*0.5+1200+(counter+1+counter2)*50+(counter+1+counter2)*4*self.R+b,self.R*a)) ################ print '__________________________' print "Last layout child cell done" print d print '_ _ _ _ _ _ _ _ _ _ _ _ _ ' return d def _generate_elements(self, elems): for counter, child in enumerate(self.MZI_22_22_list): name=child.name print name elems += i3.PolygonText(layer= i3.TECH.PPLAYER.WG.TEXT, text='Name={}_R={}_delay={}'.format(name, self.R, self.delay_length), coordinate=(0.0, -counter*5*self.R+2*self.R-50.0#-100 ), 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={}_R={}_delay={}'.format(name, self.R, self.delay_length), coordinate=(0.0, -counter*5*self.R-2*self.R+50.0#-100 ), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font = 2, height=20.0) for counter2, child in enumerate(self.MZI_12_22_list): name=child.name print name elems += i3.PolygonText(layer= i3.TECH.PPLAYER.WG.TEXT, text='Name={}'.format(name), coordinate=(0.0, -(counter+1+counter2)*5*self.R-90.0-500#-100 ), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font = 2, height=20.0) return elems
class Spirals(PlaceAndAutoRoute): _name_prefix = 'LSpiral' tipo = i3.PositiveNumberProperty(doc="Number loops", default=1) waveguide_template = i3.DefinitionProperty(doc="Trace template used") R = i3.PositiveNumberProperty(default=200, doc="Radius of curvature") spacing = i3.PositiveNumberProperty(default=100, doc="Radius of curvature") n_loops = i3.IntProperty(doc="Number loops", default=2) n_loops_vec = i3.ListProperty(default=[4, 8]) s_length_vec = i3.ListProperty(default=[0.0]) Spiral_list = i3.ChildCellListProperty( doc="List containing the 90 degree angle child cells") #chip_length = i3.PositiveNumberProperty(default=2500.0, doc="Radius of curvature") chip_length = i3.PositiveNumberProperty(default=3000.0, doc="Radius of curvature") Port = i3.ChildCellProperty(doc="Used for ports") Port2 = i3.ChildCellProperty(doc="Used for ports") tlport = i3.PositiveNumberProperty(default=1000.0, doc="Transition legth to ports") couplingWG = i3.ChildCellProperty(doc="", locked=True) couplingWG_l = i3.PositiveNumberProperty(default=5000.0, doc="Length of the coupling WG ") tt_port = i3.TraceTemplateProperty( doc="Wide trace template used for the contacts") tt_port2 = i3.TraceTemplateProperty( doc="Wide trace template used for the contacts") #width_vec = i3.ListProperty(default=[1]) n = i3.PositiveNumberProperty(default=1, doc="") width = i3.PositiveNumberProperty(default=1, doc="") lengths = i3.PositiveNumberProperty(default=1, doc="") def _default_lengths(self): for counter, cell in enumerate(self.s_length_vec): numero = counter + 1 return numero #template for Autorute def _default_trace_template(self): return self.waveguide_template def _default_tt(self): return self.waveguide_template def _default_tt_port(self): tt_port = WireWaveguideTemplate() tt_port_layout = tt_port.Layout(core_width=10.0, cladding_width=10.0) return tt_port def _default_tt_port2(self): tt_port = WireWaveguideTemplate() tt_port_layout = tt_port.Layout(core_width=10.0, cladding_width=10.0) return tt_port def _default_Spiral_list(self): Spiral_list = [] # empty list print ' I am in _Spiral_list' for l, length in enumerate(self.s_length_vec): loops = 1 print length cell = FixedLengthSpiralRounded( trace_template=self.waveguide_template, #total_length=length-self.chip_length, total_length=length, n_o_loops=loops, name=self.name + '_Spiral_' + str(l)) cell.Layout( incoupling_length=0, bend_radius=self.R, spacing=self.spacing, stub_direction="H", growth_direction="H", ) #.visualize(annotate=True) print 'The legth of the spiral is: ', cell.total_length print 'Cell: ', cell.name Spiral_list.append(cell) return Spiral_list def _default_couplingWG(self): rect = i3.Waveguide(trace_template=self.tt_port) layout_rect = rect.Layout(shape=[(0.0, 0.0), (self.couplingWG_l, 0.0)]) return rect def _default_Port(self): Port = AutoTransitionPorts(contents=self.couplingWG, port_labels=["in"], trace_template=self.waveguide_template) layout_Port = Port.Layout( transition_length=self.tlport) #.visualize(annotate=True) return Port def _default_Port2(self): Port = AutoTransitionPorts(contents=self.couplingWG, port_labels=["in"], trace_template=self.waveguide_template) layout_Port = Port.Layout( transition_length=self.tlport) #.visualize(annotate=True) return Port def _default_child_cells(self): child_cells = { } # First we define the property "child_cells" as an empty dictionary for counter, spiral in enumerate( self.Spiral_list ): # the iteration starts in the first element of the list and follows element by element to the last element. child_cells['Spiral{}'.format(counter)] = spiral print spiral print 'name of spiral:', spiral.name child_cells['InPort' + str(counter)] = self.Port child_cells['OutPort' + str(counter)] = self.Port print 'child_cells:', child_cells return child_cells def _default_links(self): links = [] for counter, spiral in enumerate(self.Spiral_list): print counter in_port = "Spiral{}:in".format(counter) out_port = "InPort{}:in".format(counter) links.append((in_port, out_port)) in_port = "Spiral{}:out".format(counter) out_port = "OutPort{}:in".format(counter) links.append((in_port, out_port)) return links class Layout(PlaceAndAutoRoute.Layout): #tipo=1 def _default_bend_radius(self): return self.R def _default_child_transformations(self): d = {} for counter, child in enumerate(self.Spiral_list): ip = child.ports["in"].position #print self.child_cells['InPort' + str(counter)].ports["out"].position #print self.child_cells['OutPort' + str(counter)].ports.position print '----------------' print 'spiral length:', child.total_length print 'counter: ', counter #print ip op = child.ports["out"].position #print op print 'The lateral size of the spiral is', op[0] - ip[0] print 'The type of mask is: ', self.tipo print 'The number of widths is: ', self.n print 'The number of lengths is: ', self.lengths print 'The width number is: ', self.width print '----------------' iz = child.inner_size sx = iz[1] + 200 #sx=1200 if self.tipo == 1: d['Spiral' + str(counter)] = i3.Translation( translation=(-(op[0] - ip[0]) / 2, self.n * counter * sx)) d['InPort' + str(counter)] = i3.HMirror() + i3.Translation( translation=(-self.chip_length / 2.0 - self.couplingWG_l, self.n * counter * sx)) d['OutPort' + str(counter)] = i3.Translation( translation=(self.chip_length / 2.0 + self.couplingWG_l, self.n * counter * sx)) if self.tipo == 2: d['Spiral' + str(counter)] = i3.Translation( translation=(-(op[0] - ip[0]) / 2, -(self.n + 0.5) * counter * sx)) #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4)-self.couplingWG_l, -(self.n+0.5)*counter*sx)) #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R+(((self.n+0.5)*counter+self.width)*sx/4), self.chip_length*(3/4)+(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx)) d['InPort' + str(counter)] = i3.HMirror() + i3.Translation( translation=(-self.chip_length * (1 / 2) - 2000, -(self.n + 0.5) * counter * sx)) d['OutPort' + str(counter)] = i3.Rotation( rotation=90) + i3.Translation(translation=( (op[0] - ip[0]) / 2 + 2 * self.R + (((self.n + 0.5) * counter + self.width) * sx / 4), 3000 + self.chip_length * (3 / 4) + (self.width + counter - (((counter + 1) - 1.0) % self.lengths)) * sx)) #For awg's #if self.tipo==2: #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+0.5)*counter*sx)) #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4.0), -(self.n+0.5)*counter*sx)) #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R #+(((self.n+0.5)*counter+self.width)*sx/100.0) #, self.chip_length*(2/4.0)+ #(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx)) return d # Fabio's addition def _generate_elements(self, elems): # We calculate the lengths of the 2 spirals in this pcell. # Note that we assume that there are exactly 2 spirals in this list. #assert len(self.Spiral_list) == 2 lengths = get_lengths(self) iz = self.Spiral_list[0].inner_size sx = iz[1] + 200 for counter, (child, length) in enumerate(zip(self.Spiral_list, lengths)): ip = child.ports["in"].position op = child.ports["out"].position width = child.ports["in"].trace_template.core_width #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width #i3.TECH.PPLAYER.NONE.LOGOTXT when using isipp50g if self.tipo == 2: elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Width={}_Length={}_R={}'.format( width, length, self.R), coordinate=((op[0] - ip[0]) / 2 - 1000.0, (self.n + 0.5) * counter * sx - 50.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) if self.tipo == 1: elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Width={}_Length={}_R={}'.format( width, length, self.R), coordinate=(-(op[0] - ip[0]) / 2 - 1000.0, -(self.n + 0.5) * counter * sx - 50.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) return elems
class Spirals(PlaceAndAutoRoute): _name_prefix = 'LSpiral' tipo = i3.PositiveNumberProperty(doc="Number loops", default=1) waveguide_template = i3.DefinitionProperty(doc="Trace template used") R = i3.PositiveNumberProperty(default=500, doc="Radius of curvature") spacing = i3.PositiveNumberProperty(default=100, doc="Radius of curvature") n_loops = i3.IntProperty(doc="Number loops", default=2) n_loops_vec = i3.ListProperty(default=[4, 8]) s_length_vec = i3.ListProperty(default=[0.0]) #Spiral_list = i3.ChildCellListProperty(doc="List containing the 90 degree angle child cells") #chip_length = i3.PositiveNumberProperty(default=12000.0, doc="") chip_length = i3.PositiveNumberProperty(default=13000.0, doc="") Port = i3.ChildCellProperty(doc="Used for ports") tlport = i3.PositiveNumberProperty(default=2000.0, doc="Transition legth to ports") couplingWG = i3.ChildCellProperty(doc="", locked=True) couplingWG_l = i3.PositiveNumberProperty(default=5000.0, doc="Length of the coupling WG ") tt_port = i3.TraceTemplateProperty( doc="Wide trace template used for the contacts") #width_vec = i3.ListProperty(default=[1]) n = i3.PositiveNumberProperty(default=1, doc="") width = i3.PositiveNumberProperty(default=1, doc="") lengths = i3.PositiveNumberProperty(default=1, doc="") def _default_lengths(self): for counter, cell in enumerate(self.s_length_vec): numero = counter + 1 return numero #template for Autorute def _default_trace_template(self): return self.waveguide_template def _default_tt(self): return self.waveguide_template def _default_tt_port(self): tt_port = WireWaveguideTemplate() tt_port_layout = tt_port.Layout(core_width=15.0, cladding_width=15.0 + 2 * 8.0) return tt_port def _default_couplingWG(self): rect = i3.Waveguide(trace_template=self.tt_port) layout_rect = rect.Layout(shape=[(0.0, 0.0), (self.couplingWG_l, 0.0)]) return rect def _default_Port(self): Port = AutoTransitionPorts(contents=self.couplingWG, port_labels=["in"], trace_template=self.waveguide_template) layout_Port = Port.Layout( transition_length=self.tlport) #.visualize(annotate=True) return Port def _default_child_cells(self): child_cells = { } # First we define the property "child_cells" as an empty dictionary for counter, length in enumerate( self.s_length_vec ): # the iteration starts in the first element of the list and follows element by element to the last element. #child_cells['Spiral{}'.format(counter)] = spiral #print spiral #print 'name of spiral:', spiral.name child_cells['InPort' + str(counter)] = self.Port child_cells['OutPort' + str(counter)] = self.Port print 'child_cells:', child_cells return child_cells def _default_links(self): links = [] for counter, spiral in enumerate(self.s_length_vec): print counter #in_port = "Spiral{}:in".format(counter) in_port = "InPort{}:in".format(counter) #links.append((in_port, out_port)) #in_port = "Spiral{}:out".format(counter) out_port = "OutPort{}:in".format(counter) links.append((in_port, out_port)) return links class Layout(PlaceAndAutoRoute.Layout): #tipo=1 def _default_bend_radius(self): return self.R def _default_child_transformations(self): d = {} for counter, child in enumerate(self.s_length_vec): #ip= child.ports["in"].position #print self.child_cells['InPort' + str(counter)].ports["out"].position #print self.child_cells['OutPort' + str(counter)].ports.position print '----------------' #print 'spiral length:', child.total_length print 'counter: ', counter print 'self.n = ', self.n print 'self.width: ', self.width #print 'sx: ', sx if self.tipo == 1: sx = 70 a = 0.5 print 2 * (22362 * 0.5 - self.couplingWG_l) print 'tipo = ', self.tipo #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, self.n*counter*sx)) #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*0.5, (self.n+a)*counter*sx)) #d['OutPort' + str(counter)] = i3.Translation(translation=(self.chip_length*0.5, (self.n+a)*counter*sx)) d['InPort' + str(counter)] = i3.HMirror() + i3.Translation( translation=(-22362 * 0.5 + self.couplingWG_l, (self.n + a) * counter * sx)) d['OutPort' + str(counter)] = i3.Translation( translation=(22362 * 0.5 - self.couplingWG_l, (self.n + a) * counter * sx)) #if self.tipo==2: #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+0.5)*counter*sx)) #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4)-self.couplingWG_l, -(self.n+0.5)*counter*sx)) #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R+(((self.n+0.5)*counter+self.width)*sx/4), self.chip_length*(3/4)+(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx)) if self.tipo == 2: sx = 100 #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+1)*counter*sx)) a = 7.0 print 'increment of length between waveguides of same width: ', ( self.n + a) * 1 * sx + ((self.n + a) * 1 + 0) * sx print 'increment of length between waveguides of same length group: ', ( self.n + a) * 0 * sx + ( (self.n + a) * 0 + self.width) * sx d['InPort' + str(counter)] = i3.HMirror() + i3.Translation( translation=(0.0 - self.chip_length * 0.5, -(self.n + a) * counter * sx)) d['OutPort' + str(counter)] = i3.Rotation( rotation=90) + i3.Translation(translation=( (((self.n + a) * counter + self.width) * sx), self.chip_length * 0.5 + (self.width + counter - (((counter + 1) - 1.0) % self.lengths)) * sx)) return d # Fabio's addition def _generate_elements(self, elems): # We calculate the lengths of the 2 spirals in this pcell. # Note that we assume that there are exactly 2 spirals in this list. #assert len(self.Spiral_list) == 2 lengths = get_lengths(self)[0] print lengths Link = get_lengths(self)[1] print Link if self.tipo == 1: sx = 70 for counter, (child, length) in enumerate( zip(self.s_length_vec, lengths)): #ip= child.ports["in"].position #op= child.ports["out"].position width = Link.trace_template.core_width #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width a = 0.5 #i3.TECH.PPLAYER.NONE.LOGOTXT when using isipp50g elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Width={}'.format(width, ), coordinate=(-self.chip_length * 0.5 + 2 * self.tlport, (self.n + a) * counter * sx - 15.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='Width={}'.format(width, ), coordinate=(0.0, (self.n + a) * counter * sx - 15.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='Width={}'.format(width, ), coordinate=(self.chip_length * 0.5 - 2 * self.tlport, (self.n + a) * counter * sx - 15.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) if self.tipo == 2: sx = 100 for counter, (child, length) in enumerate( zip(self.s_length_vec, lengths)): #ip= child.ports["in"].position #op= child.ports["out"].position width = Link.trace_template.core_width #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width a = 7.0 #i3.TECH.PPLAYER.NONE.LOGOTXT when using isipp50g elems += i3.PolygonText( layer=i3.TECH.PPLAYER.WG.TEXT, text='Width={}_Length={}_R={}'.format( width, length, self.R), coordinate=(-1500, -(self.n + a) * counter * sx - 55.0), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=20.0) return elems
class MMI(i3.PCell): """ MMI with a variable number of inputs and outputs with variable width and length of the taper. """ n_inputs = i3.PositiveIntProperty(default=1, doc="Number of inputs") n_outputs = i3.PositiveIntProperty(default=2, doc="Number of outputs") trace_template = i3.TraceTemplateProperty(doc="Trace template at the ports") def _default_trace_template(self): return SiWireWaveguideTemplate(name=self.name + "tt") 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 Netlist(i3.NetlistFromLayout): pass
class GratingCoupler1Band(PlaceComponents): core=i3.PositiveNumberProperty(default=3.3, doc="core width") period=i3.PositiveNumberProperty(default=2.566, doc="core width") duty=i3.PositiveNumberProperty(default=0.403, doc="core width") nperiods=i3.PositiveNumberProperty(default=7, doc="core width") wg_coupler= i3.TraceTemplateProperty(doc="Wide trace template used") #FGC= i3.ChildCellProperty(doc="grating used") ctipo=i3.PositiveNumberProperty(default=1, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper") coupling_l=i3.PositiveNumberProperty(default=5000, doc="length of coupling WG") coupler_template= i3.TraceTemplateProperty(doc="Wide trace template used for coupler tipo2") waveguide_template= i3.TraceTemplateProperty(doc="Wide trace template used on routing") coupling_w = i3.PositiveNumberProperty(default=20, doc="width of the coupling WG") transition_length_coupler=i3.PositiveNumberProperty(default=300, doc="transition length of the coupler") Grating_list = i3.ChildCellListProperty(doc="List containing the non etched parts of gratings") inPort = i3.ChildCellProperty( doc="Used for ports") outPort = i3.ChildCellProperty( doc="Used for ports") incouplingWG = i3.ChildCellProperty( doc="Used for ports") outcouplingWG = i3.ChildCellProperty( doc="Used for ports") chirp=i3.NumberProperty(default=1, doc="1=chirped") socket_length=i3.PositiveNumberProperty(default=2.2, doc="length of coupling WG") layName = i3.StringProperty(default = 'waveguide') layNameg = i3.StringProperty(default = 'metal') print 'the name of the layer is', layName props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) propsg = i3.DictProperty() def _default_propsg(self): return AssignProcess(self.layNameg) Lo = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam Le = i3.ListProperty(default=[]) #Etched part Loc = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam Lec = i3.ListProperty(default=[]) #Etched part #def _default_transition_length(self): #return self.transition_length_coupler def _default_socket_length(self): a=sum(self.Lo)+sum(self.Le) #if self.chirp==1: #A=a=self.period * int(self.nperiods)+sum(self.Loc)) return a def _default_Loc(self): #Loc=[2.175,2.122,2.07,2.016,1.963,1.908,1.854,1.798,1.743,1.687,1.63,1.573, #1.515,1.457,1.398,1.339,1.279,1.219,1.158,1.096] Loc=self.Loc Loc.reverse() return Loc def _default_Lec(self): #Lec=[0.242,0.301,0.361,0.421,0.482,0.543,0.605,0.667,0.73,0.794,0.858,0.922, #0.988,1.054,1.12,1.187,1.255,1.323,1.392,1.462] Lec=self.Lec Lec.reverse() return Lec def _default_Lo(self): A=[None] * int(self.nperiods) if self.chirp==1: A=[None] * int(self.nperiods+len(self.Loc)) for x in range(0,int(self.nperiods)): A[x]=self.period*self.duty if self.chirp==1: for x in range(0,int(len(self.Loc))): print x print len(self.Loc) A[int(self.nperiods)+x]=self.Loc[x] print 'Lo: ',A return A def _default_Le(self): Le=[None] * int(self.nperiods) if self.chirp==1: Le=[None] * int(self.nperiods+len(self.Loc)) for x in range(0,int(self.nperiods)): Le[x]=self.period*(1-self.duty) if self.chirp==1: for x in range(0,int(len(self.Loc))): Le[int(self.nperiods)+x]=self.Lec[x] print 'Le: ',Le return Le def _default_Grating_list(self): Grating_list = [] for x in range(0,int(len(self.Lo))): #rect=i3.Waveguide(trace_template=self.wg_coupler) rect=i3.Waveguide(trace_template=self.coupler_template) #layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.Lo[x],0.0)])#.visualize(annotate=True) layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.Lo[x],0.0)])#.visualize(annotate=True) Grating_list.append(rect) return Grating_list def _default_incouplingWG(self): rect=i3.Waveguide(trace_template=self.wg_coupler) layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.coupling_l,0.0)] ) return rect def _default_outcouplingWG(self): rect=i3.Waveguide(trace_template=self.wg_coupler) layout_rect = rect.Layout(shape=[(0.0, 0.0),(50+self.socket_length,0.0)] ) return rect def _default_inPort(self): Port=AutoTransitionPorts(contents=self.incouplingWG, port_labels=["in"], trace_template=self.waveguide_template) layout_Port = Port.Layout(transition_length=self.transition_length_coupler)#.visualize(annotate=True) return Port def _default_outPort(self): Port=AutoTransitionPorts(contents=self.outcouplingWG, port_labels=["in"], trace_template=self.wg_coupler) layout_Port = Port.Layout(transition_length=10)#.visualize(annotate=True) return Port def _default_child_cells(self): child_cells = {} # First we define the property "child_cells" as an empty dictionary for counter, pillar in enumerate(self.Grating_list): child_cells['pillar{}'.format(counter)] = pillar print pillar print 'name of pillar:', pillar.name child_cells['InPort'] = self.inPort child_cells['OutPort']= self.outPort print 'child_cells:', child_cells return child_cells def _default_props(self): return AssignProcess(self.layName) def _default_wg_coupler(self): wg_coupler = WireWaveguideTemplate() wg_coupler.Layout(core_width=self.coupling_w, cladding_width=self.coupling_w+2*8, **self.props) return wg_coupler def _default_waveguide_template(self): wg_t = WireWaveguideTemplate() wg_t_layout=wg_t.Layout(core_width=self.core, cladding_width=self.core+2*8, **self.props) return wg_t def _default_coupler_template(self): wg_t = WireWaveguideTemplate() wg_t_layout=wg_t.Layout(core_width=self.coupling_w, cladding_width=self.coupling_w, **self.propsg) return wg_t def _default_trace_template(self): return self.waveguide_template def _default_contents(self): return self.FGC def _default_port_labels(self): return ["out"] class Layout(PlaceComponents.Layout): #def _default_transition_length(self): #return self.transition_length_coupler def _default_child_transformations(self): d={} position=0 for counter, child in enumerate(self.Grating_list): d['pillar{}'.format(counter)] = i3.Translation(translation=(position, 0.0)) position=position+self.Lo[counter]+self.Le[counter] print 'pillar position: ', position print 'counter= ', counter print 'Lo: ', self.Lo[counter] print 'Le: ', self.Le[counter] #d['InPort'] = i3.HMirror()+ i3.Translation(translation=(position+10,0)) d['InPort'] = i3.HMirror()+ i3.Translation(translation=(self.coupling_l+self.socket_length,0)) d['OutPort'] = i3.Translation(translation=(-50,0.0)) return d
class AligningMarks(PlaceComponents): tt_cross = i3.TraceTemplateProperty(doc="Wide trace template used for the contact pads") hline = i3.ChildCellProperty(doc="Horizontal line", locked=True) vline = i3.ChildCellProperty(doc="Vertical", locked=True) square = i3.ChildCellProperty(doc="Vertical", locked=True) size=i3.PositiveNumberProperty(default=250.0, doc="bigger dimension of aligning mark") width=i3.PositiveNumberProperty(default=20.0, doc="smaller dimension of aligning mark") #Pitch1=i3.PositiveNumberProperty(default=2.0, doc="pitch grating 1") separation=i3.NumberProperty(default=100.0, doc="separation between cross and gratings") #dc=i3.PositiveNumberProperty(default=0.47, doc="duty cycle") layName = i3.StringProperty(default = 'metal2') props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) def _default_tt_cross(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=(self.width), cladding_width=(self.width), **self.props ) return tt_w def _default_hline(self): rect=i3.Waveguide(trace_template=self.tt_cross) 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_vline(self): rect=i3.Waveguide(trace_template=self.tt_cross) layout_rect = rect.Layout(shape=[(self.size/2.0, 0.0),(self.size/2.0,self.size)]) print 'The trace template of the vline of the cross ', rect.trace_template return rect def _default_square(self): #square=Square(size=self.width, layName=self.layName) square=Square(size=self.width, layName='metal') #square.Layout().visualize() return square def _default_child_cells(self): child_cells={"S1" : self.square, "S2" : self.square, "S3" : self.square, "S4" : self.square, "V" : self.vline, "H" : self.hline } return child_cells class Layout(PlaceComponents.Layout): def _default_child_transformations(self): child_transformations={"S1" : i3.Translation(translation=(-(self.width+5.0),(self.width+5.0))), "S2" : i3.Translation(translation=((self.width+5.0),(self.width+5.0))), "S3" : i3.Translation(translation=(-(self.width+5.0),-(self.width+5.0))), "S4" : i3.Translation(translation=((self.width+5.0),-(self.width+5.0))), "V" : i3.Translation(translation=(0.0, 0.0))+ i3.Translation(translation=(-(self.size)/2.0,-(self.size)/2.0)), "H" : i3.Translation(translation=(0.0, 0.0))+ i3.Translation(translation=(-(self.size)/2.0,-(self.size)/2.0)) } return child_transformations
class DirectionalCoupler(i3.PCell): trace_template = i3.TraceTemplateProperty( doc="Trace template used for directional coupler") def _default_trace_template(self): return SiWireWaveguideTemplate() 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 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 Netlist(i3.NetlistFromLayout): pass