Exemple #1
0
class Funnel(i3.PCell):
    """A generic Funnel to connect elements. It is defined by a boundary which are defined by points
    """
    # 1. First we define our 2 Channel Templates with different Width's.
    channel_1_template = microfluidics.ShortChannelTemplate()
    channel_2_template = microfluidics.ShortChannelTemplate()

    # 2. Then we use the LinearWindowChannelTransition class to create a transition between Channels.

    #####################3
    ###################

    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "Funnel"  # a prefix added to the unique
    funnel_length = i3.NumberProperty(default=100.0, doc="length of funnel")
    initial_width = i3.NumberProperty(default=200.0,
                                      doc="initial with of funnel")
    final_width = i3.NumberProperty(default=100.0, doc="final width of funnel")

    class Layout(i3.LayoutView):
        def _generate_instances(self, insts):
            channel_1_template = self.cell.channel_1_template.Layout(
                channel_width=self.cell.initial_width)
            channel_2_template = self.cell.channel_2_template.Layout(
                channel_width=self.cell.final_width)

            funnel = microfluidics.LinearWindowChannelTransition(
                start_trace_template=self.cell.channel_1_template,
                end_trace_template=self.cell.channel_2_template)

            funnel_layout = funnel.Layout(
                start_position=(0.0, 0.0),
                end_position=(self.cell.funnel_length, 0.0))
            insts += i3.SRef(reference=funnel_layout,
                             name='funnel',
                             position=(0, 0))
            return insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in',
                position=(0, 0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='out',
                position=(self.funnel_length, 0),
                direction=i3.PORT_DIRECTION.OUT,
                angle_deg=0,
                trace_template=self.cell.channel_template)

            return ports
class accessHoleFlat(i3.PCell):
    """A generic inlet/outlet hole class.
    It is defined by a circular
    """
    _name_prefix = "ACCESSHOLE_FLAT"  # a prefix aded to the unique identifier

    reduction_ratio = i3.NumberProperty(
        default=1.0)  #transition from BigRes to Trap
    diameter = i3.NumberProperty(default=300.)

    class Layout(i3.LayoutView):
        channel_template = microfluidics.ShortChannelTemplate()
        cInp = i3.Coord2Property(default=(0.0, 0.0))

        def _generate_elements(self, elems):
            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                   center=(0.0, 0.0),
                                   radius=self.diameter * 0.5,
                                   line_width=50)

            point_list = []

            point_list.append((0, -self.diameter * 0.5))
            point_list.insert(0, (0, self.diameter * 0.5))
            point_list.append(
                (self.diameter * self.cell.reduction_ratio,
                 -self.diameter * 0.5 * self.cell.reduction_ratio))
            point_list.insert(
                0, (self.diameter * self.cell.reduction_ratio,
                    self.diameter * 0.5 * self.cell.reduction_ratio))

            funnel = i3.Shape(point_list, closed=True)
            bo = i3.Boundary(i3.TECH.PPLAYER.CH2.TRENCH, funnel)
            elems += bo

            return elems

        def _generate_ports(self, ports):
            '''ports += microfluidics.FluidicPort(name='in', position=(0.0, 0.0),
                                               direction=i3.PORT_DIRECTION.IN,
                                               trace_template=self.channel_template,
                                               angle_deg=0
                                               )'''

            ports += microfluidics.FluidicPort(
                name='out',
                position=(self.diameter * self.cell.reduction_ratio, 0.0),
                direction=i3.PORT_DIRECTION.OUT,
                trace_template=self.channel_template,
                angle_deg=180)

            return ports
    class Layout(i3.LayoutView):
        channel_template = microfluidics.ShortChannelTemplate()
        length = i3.NumberProperty(default=60e3)
        width = i3.NumberProperty(default=20e3)
        cInp = i3.Coord2Property(default=(0.0, 0.0))

        def _generate_elements(self, elems):
            elems += i3.RoundedRectanglePath(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                             center=(0.0, 0.0),
                                             box_size=(self.length,
                                                       self.width),
                                             radius=200.,
                                             line_width=2.0)
            return elems
Exemple #4
0
    class CircuitModel(i3.CircuitModelView):
        R = i3.NumberProperty(doc="Responsivity (A/W)", default=0.8)
        BW = i3.NumberProperty(doc="3 dB bandwidth of the photodetector (GHz)",
                               default=60)
        # Optical parameters
        reflection_dB = i3.NonNegativeNumberProperty(doc="Reflection (dB)",
                                                     default=100.0)
        # Dark current parameters
        dark_current = i3.NumberProperty(doc='Dark current (nA)', default=50)

        def _generate_model(self):
            from aeponyx.compactmodels import PhotoDetectorCompactModel
            return PhotoDetectorCompactModel(R=self.R,
                                             BW=self.BW,
                                             reflection_dB=self.reflection_dB,
                                             dark_current=self.dark_current)
    class Layout(i3.LayoutView):
        channel_template = microfluidics.ShortChannelTemplate()
        size = i3.NumberProperty(default=10e4)
        cInp = i3.Coord2Property(default=(0.0, 0.0))

        def _generate_elements(self, elems):
            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                   center=(0.0, 0.0),
                                   radius=self.size * 0.5,
                                   line_width=200)
            return elems
Exemple #6
0
    class Layout(i3.LayoutView):
        tee_length = i3.NumberProperty(default=10.0,
                                       doc="length of each tee branch")

        def _generate_instances(self, elems):  # insts):
            rectangle = i3.RoundedRectangle(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                            center=(0.0, 0.0),
                                            box_size=(self.tee_length,
                                                      2 * self.tee_length),
                                            radius=1.0)
            rectangle2 = i3.RoundedRectangle(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                             center=(0.5 * self.tee_length,
                                                     0.0),
                                             box_size=(self.tee_length,
                                                       self.tee_length),
                                             radius=1.0)
            #boolean operation add main trap and 1st rectangle
            b_add = rectangle | rectangle2
            s = i3.Structure(elements=b_add)
            elems += i3.SRef(s)

            return elems  #insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(0, -self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=270,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='in2',
                position=(0, self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=90,
                trace_template=self.cell.channel_template)
            #port3
            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.tee_length, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.cell.channel_template)
            return ports
Exemple #7
0
    class Layout(i3.LayoutView):

        tee_length = i3.NumberProperty(default=300.0,
                                       doc="length of each tee branch")

        def _generate_instances(self, insts):
            channel1 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel1_lo = channel1.Layout(
                shape=[(0, -self.tee_length), (0, self.tee_length)])
            insts += i3.SRef(channel1_lo, position=(0, 0))

            channel2 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel2_lo = channel2.Layout(shape=[(0, 0), (-self.tee_length,
                                                          0)])
            insts += i3.SRef(channel2_lo, position=(self.tee_length, 0))

            return insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(0, -self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=270,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='in2',
                position=(0, self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=90,
                trace_template=self.cell.channel_template)
            #port3
            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.tee_length, 0.0),
                direction=i3.PORT_DIRECTION.OUT,
                angle_deg=0,
                trace_template=self.cell.channel_template)
            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 accessHole(i3.PCell):
    """A generic inlet/outlet hole class.
    It is defined by a circular
    """
    _name_prefix = "ACCESSHOLE"  # a prefix aded to the unique identifier
    diameter = i3.NumberProperty(default=300.)

    class Layout(i3.LayoutView):
        channel_template = microfluidics.ShortChannelTemplate()
        #inlet_diameter = i3.NumberProperty(default =300.)
        cInp = i3.Coord2Property(default=(0.0, 0.0))

        def _generate_elements(self, elems):
            #solid
            #circle = i3.ShapeCircle(center=(0.0,0.0), radius=self.inlet_diameter*0.5)
            #elems += i3.Boundary(layer=i3.TECH.PPLAYER.CH2.TRENCH, shape=circle)
            #line (faster on MLA)
            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                   center=(0.0, 0.0),
                                   radius=self.diameter * 0.5,
                                   line_width=200)

            return elems

        def _generate_ports(self, ports):
            ports += microfluidics.FluidicPort(
                name='in',
                position=(0.0, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                trace_template=self.channel_template,
                angle_deg=90)

            ports += microfluidics.FluidicPort(
                name='out',
                position=(0.0, 0.0),
                direction=i3.PORT_DIRECTION.OUT,
                trace_template=self.channel_template,
                angle_deg=90)

            return ports
Exemple #10
0
    class CircuitModel(i3.CircuitModelView):
        n_eff = i3.PositiveNumberProperty(locked=True)
        VpiLpi = i3.PositiveNumberProperty(
            default=1.5,
            doc="Voltage to get pi-shift for 1 cm of phase modulator [V.cm]")
        delay = i3.NumberProperty(locked=True)
        insertion_loss_dB = i3.NonNegativeNumberProperty(
            default=0., doc='Insertion loss [dB]')

        def _default_n_eff(self):
            tt_cm = self.trace_template
            return tt_cm.n_eff

        def _default_delay(self):
            return self.layout_view.delay

        def _generate_model(self):
            from aeponyx.compactmodels import MZMLumpedCompactModel
            return MZMLumpedCompactModel(
                n_eff=self.n_eff,
                delay=self.delay,
                insertion_loss_dB=self.insertion_loss_dB,
                VpiLpi=self.VpiLpi,
                length=self.modulator_length)
class pinsRectangleFour(i3.PCell):
    """A generic inlet/outlet hole class.
    It is defined by a circular
    """
    _name_prefix = "PINS"  # a prefix aded to the unique identifier
    diameter = i3.NumberProperty(default=1000.)

    class Layout(i3.LayoutView):
        channel_template = microfluidics.ShortChannelTemplate()
        #inlet_diameter = i3.NumberProperty(default =300.)
        cInp = i3.Coord2Property(default=(0.0, 0.0))

        def _generate_elements(self, elems):
            #solid
            #circle = i3.ShapeCircle(center=(0.0,0.0), radius=self.inlet_diameter*0.5)
            #elems += i3.Boundary(layer=i3.TECH.PPLAYER.CH2.TRENCH, shape=circle)
            #line (faster on MLA)
            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH1.TRENCH,
                                   center=(26e3, 9e3),
                                   radius=self.diameter * 0.5,
                                   line_width=200)
            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH1.TRENCH,
                                   center=(-26e3, 9e3),
                                   radius=self.diameter * 0.5,
                                   line_width=200)

            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH1.TRENCH,
                                   center=(-26e3, -9e3),
                                   radius=self.diameter * 0.5,
                                   line_width=200)

            elems += i3.CirclePath(layer=i3.TECH.PPLAYER.CH1.TRENCH,
                                   center=(26e3, -9e3),
                                   radius=self.diameter * 0.5,
                                   line_width=200)
            return elems
class CombinedCircuit(PlaceAndAutoRoute):
	L1=i3.PositiveNumberProperty(default=100,doc="radius or curvature of circuit")

	incoupler = i3.ChildCellProperty(doc="coupler used", locked=True)
	outcoupler = i3.ChildCellProperty(doc="coupler used", locked=True)

	aligningmark=i3.ChildCellProperty(doc="aligning mark")
	lens=i3.ChildCellProperty(doc="flowcellbox")
	flowcellbox=i3.ChildCellProperty(doc="lens")
	aligningmark_h=i3.ChildCellProperty(doc="aligning mark for heater")
	coupling_l=i3.PositiveNumberProperty(default=5+2*270, doc="length of coupling WG")	
	coupling_win = i3.PositiveNumberProperty(default=15, doc="width of the coupling WG")
	coupling_wout = i3.PositiveNumberProperty(default=15, doc="width of the coupling WG")	
	chip_length=i3.PositiveNumberProperty(default=20000,doc="length of the chip")
	
	radius=i3.PositiveNumberProperty(default=100,doc="radius or curvature of circuit")

	core=i3.PositiveNumberProperty(default=3.3, doc="core width")	        
	width=i3.PositiveNumberProperty(default=3.3, doc="narrow width of heaters")
	tipo =i3.NumberProperty(default=2, doc="1=spiral, 2=wide waveguide")
	
	
	wide_wg_l = i3.NumberProperty(default=20, doc="Wide Waveguide")
	coupler_p=i3.NumberProperty(default=20, doc="position of the grating coupler with respect to the edge")
	ctipoin=i3.PositiveNumberProperty(default=2, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper")
	ctipoout=i3.PositiveNumberProperty(default=1, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper")
	transition_length_couplerin=i3.PositiveNumberProperty(default=500, doc="transition length of the coupler")
	transition_length_couplerout=i3.PositiveNumberProperty(default=500, doc="transition length of the coupler")
	aligningmark=i3.ChildCellProperty(doc="aligning mark for circuit used")
	
	increment=i3.NumberProperty(default=0, doc="core width")
	
	periodin=i3.PositiveNumberProperty(default=1.73, doc="core width")
	dutyin=i3.PositiveNumberProperty(default=0.5, doc="core width")
	nperiodsin=i3.PositiveNumberProperty(default=8, doc="core width")
	
	periodout=i3.PositiveNumberProperty(default=2.566, doc="core width")
	dutyout=i3.PositiveNumberProperty(default=0.403, doc="core width")
	nperiodsout=i3.PositiveNumberProperty(default=20, doc="core width")	
	
	Loc = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam
	Lec = i3.ListProperty(default=[]) #Etched part	
	
	
	layName_h = i3.StringProperty(default = 'standard', doc = 'options: standard, new')
	layName_h2 = i3.StringProperty(default = 'standard', doc = 'options: standard, new')
	layName_c = i3.StringProperty(default = 'standard', doc = 'options: standard, new')
	layName_f = i3.StringProperty(default = 'standard', doc = 'options: standard, new')
	separation=i3.NumberProperty(default=100.0, doc="separation between cross and gratings")
	size=i3.NumberProperty(default=250.0, doc="Size of the cross of aligning marks")
	
	print 'core width',core
	print 'heater width', width

	def _default_trace_template(self):
		return self.incoupler.inPort.trace_template
	
	
	def _default_Lec(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] #version A
		Loc=[2.043,1.643] #1um etch for 2um GOS
		#Loc=[1,1,1,1,1,1,1]
		Loc.reverse()
		return Loc
		
	def _default_Loc(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] #version A
		Lec=[0.511,0.949] #1um etch for 2um GOS
		#Lec=[0.4,0.5,0.6,0.7,0.8,0.9,1]
		Lec.reverse()
		return Lec	

	def _default_child_cells(self):

		child_cells={
                             "incoupling1" : self.incoupler,
                             "outcoupling1" : self.outcoupler,
		             
		             
		             
                           #  "am1"     : self.aligningmark,
		           #  "am2"     : self.aligningmark,
		           #  "am3"     : self.aligningmark,
		           #  "am4"     : self.aligningmark,
		             
		           #  "inlens1" : self.lens,
		            # "outlens1" : self.lens,
		            	             
		            # "chip" : self.flowcellbox
		             	            
                     }
		return child_cells

	def _default_links(self):
		links = [( "incoupling1:InPort_in","outcoupling1:InPort_in"),
		        
                         
                         ]
	
		return links
	
	

	def _default_aligningmark(self):
		am=AligningMarks(layName='metal2', separation=self.separation, size=self.size)
		return am
	
	def _default_aligningmark_h(self):
		am=AligningMarks(layName=self.layName_h, separation=self.separation, size=self.size)
		return am	
	
	def _default_aligningmark_h2(self):
		am=AligningMarks(layName=self.layName_h2, separation=self.separation, size=self.size)
		return am


	def _default_outcoupler(self):
		print 'I am in the coupler'
		coupler = GratingCoupler1Band(coupling_l=self.coupling_l+self.increment, chirp=self.ctipoout, coupling_w=self.coupling_wout,core=self.core, 
		                              layName = self.layName_c, period=self.periodout, duty=self.dutyout, nperiods=self.nperiodsout,
						Loc=self.Loc,
		                                Lec=self.Lec,
		                                transition_length_coupler=self.transition_length_couplerout,
		                                )		
		#layout_coupler=coupler.Layout(transition_length_coupler=self.transition_length_couplerout,
		                              #)#.visualize(annotate=True)
		
		return coupler
	
	def _default_incoupler(self):
		print 'I am in the coupler'
		coupler = GratingCoupler1Band(coupling_l=self.coupling_l, chirp=self.ctipoin, coupling_w=self.coupling_win,core=self.core, 
	                                      layName = self.layName_c, period=self.periodin, duty=self.dutyin, nperiods=self.nperiodsin,
	                                        Loc=self.Loc,
	                                        Lec=self.Lec,
		                                transition_length_coupler=self.transition_length_couplerin,
	                                        )		
		##layout_coupler=coupler.Layout(transition_length_coupler=self.transition_length_couplerin,
	                                      #)#.visualize(annotate=True)
		
		return coupler	

	def _default_lens(self):
		lens=Lens()
		return lens	
	def _default_flowcellbox(self):
		fl=flowcellbox()
		return fl	


	class Layout(PlaceAndAutoRoute.Layout):
		def _default_child_transformations(self):
			
			incoupler_t =fc_t1 = i3.Rotation(rotation=00.0) #+ i3.Translation(translation=(-(self.chip_length*0.5-self.coupler_p),0.0))
			outcoupler_t = i3.Rotation(rotation=180.0) #+ i3.Translation(translation=(self.chip_length*0.5-self.coupler_p,0.0))
			
			L1=self.L1
			
			#s=270
			s=0
			#z=2500
			z=0
			#socket_length=2*self.period*int(self.nperiods)+2*10
			socket_lengthout=2*(sum(self.Lec)+sum(self.Loc))+2*self.periodout*int(self.nperiodsout)+1*10
			socket_lengthin=2*self.periodin*int(self.nperiodsin)+0*10
			xin=0.75*self.periodin*int(self.nperiodsin)
			xout=0.75*(self.periodout*int(self.nperiodsout)+sum(self.Lec)+sum(self.Loc))
			print "socket_lengthout: ", socket_lengthout
			print "socket_lengthin: ", socket_lengthin
			#print self.child_cells['incoupling1'].FGC.Layout.socket_length
			child_transformations={                                   
                                               
			                        
			                        #"incoupling1"     :   i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z-socket_lengthin#-50.0#-self.transition_length_couplerin
			                                                                                                      #,-s)),
			                        #"outcoupling1"     :   i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1#+50.0#+self.transition_length_couplerout+self.increment-z
			                                                                                                        #,-s)),
			                        "incoupling1"     :   i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z#-socket_lengthin#-50.0#-self.transition_length_couplerin
			                                                                                                                                                              ,-s)),
			                        "outcoupling1"     :   i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1+socket_lengthout-100#+50.0#+self.transition_length_couplerout+self.increment-z
			                                                                                                                                                                ,-s)),

 
			                        # "inlens1"     :   i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z-self.transition_length_couplerin-socket_lengthin+xin,-s)),
			                         #"outlens1"     :   i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1+self.transition_length_couplerin+self.increment-z-xin,-s)),
			                         
			                       #  "am1"     :   i3.Translation(translation=(self.chip_length*0.5-1000,0.0)),
			                       #  "am2"     :   i3.Translation(translation=(-self.chip_length*0.5+1000,0.0)),
			                       #  "am3"     :   i3.Translation(translation=(-self.chip_length*0.5+5000,0.0)),
			                       #  "am4"     :   i3.Translation(translation=(self.chip_length*0.5-5000,0.0)) ,			                       

                                    }                        


			return child_transformations
		def _generate_elements(self, elems):
		
			elems += i3.PolygonText(layer= i3.TECH.PPLAYER.WG.TEXT, text='period={}_duty={}_n={}_width={}'.format(self.periodin,
		                                                                                                      self.dutyin,
			                                                                                              self.nperiodsin,
		                                                                                                      self.core),
		                                #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)


		                                coordinate=(0.0, -20),
		                                alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
		                                font = 2,
		                                height=20.0)                
			return elems



		def _default_bend_radius(self):
			return self.radius+self.core*0.5
    class Layout(i3.LayoutView):

        from ipkiss.technology import get_technology
        TECH = get_technology()

        period = i3.PositiveNumberProperty(default=.3,
                                           doc="Period of sidewall grating")
        duty_cycle = i3.PositiveNumberProperty(
            default=.1,
            doc="Length of grating teeth (along periodic direction)")
        grating_amp = i3.NumberProperty(
            default=.01,
            doc=
            "Width/amplitude of grating teeth (normal to periodic direction)")
        wg_width = i3.PositiveNumberProperty(
            default=TECH.WG.CORE_WIDTH,
            doc="Width of waveguide core (if grating_amp=0 width of waveguide)"
        )
        length = i3.PositiveNumberProperty(default=100.0,
                                           doc="Length of waveguide")

        # Flag, set to True to draw grating on both sides of wg.
        both_sides = i3.BoolProperty(
            default=False, doc='set to true to draw grating on both sides')

        def validate_properties(self):
            """Check whether the combination of properties is valid."""
            if self.duty_cycle >= self.period:
                raise i3.PropertyValidationError(
                    self,
                    "Duty cycle is larger than/equal to the grating period",
                    {"duty_cyle": self.duty_cycle})

            return True

        def _generate_elements(self, elems):
            # Waveguide path
            wg_path = [(0.0, 0.0), (self.length, 0.0)]

            # Grating tooth path
            gt_path = [(0.0, 0.0), (self.duty_cycle, 0.0)]

            gap_cycle = self.period - self.duty_cycle
            numperiod = int(np.floor(self.length / self.period))

            # Add waveguide core
            elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR,
                             shape=wg_path,
                             line_width=self.wg_width)

            # Add grating teeth
            if self.grating_amp > 0.0:
                # grating amplitude has to be non-zero

                ytrans = i3.Translation(
                    (0.0, self.wg_width / 2 + self.grating_amp / 2))
                for ii in range(numperiod):
                    #Start with gap rather than tooth
                    xtrans = i3.Translation(
                        ((gap_cycle + ii * self.period), 0.0))
                    elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR,
                                     shape=gt_path,
                                     line_width=self.grating_amp,
                                     transformation=(xtrans + ytrans))

                    # draw bottom grating if desired
                    if self.both_sides == True:
                        elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR,
                                         shape=gt_path,
                                         line_width=self.grating_amp,
                                         transformation=(xtrans - ytrans))

            # Add block layers
            import block_layers as bl
            block_layers = bl.layers
            block_widths = bl.widths
            for ii in range(len(block_layers)):
                elems += i3.Path(layer=block_layers[ii],
                                 shape=wg_path,
                                 line_width=self.wg_width +
                                 2 * self.grating_amp + 2 * block_widths[ii])

            return elems

        def _generate_ports(self, ports):
            # ports += i3.OpticalPort(name="in", position=(0.0, 0.0), angle=180.0,
            #                         trace_template=StripWgTemplate().Layout(core_width=self.wg_width))
            # ports += i3.OpticalPort(name="out", position=(self.length, 0.0), angle=0.0,
            #                         trace_template=StripWgTemplate().Layout(core_width=self.wg_width))

            ports += i3.OpticalPort(name="in",
                                    position=(0.0, 0.0),
                                    angle=180.0)
            ports += i3.OpticalPort(name="out",
                                    position=(self.length, 0.0),
                                    angle=0.0)

            return ports
Exemple #14
0
    class Layout(i3.LayoutView):

        # Properties -------

        # taper to draw
        # taper_layout = i3.ViewProperty( default='', doc='taper cell to draw and stuff' )

        # connecting length between tapers
        connect_length = i3.NumberProperty(default=0.0,
                                           doc='distance between tapers')

        # taper cell
        # taper_cell      = i3.PCellProperty( default=i3.PCell(), doc='taper cell to draw')
        taper_prop_dict = i3.DictProperty( default = {}, doc = 'Dictionary of taper cell properties.' + \
                                           'Properties = "length", "width1", "width2", "width_etch" ' )

        # this is terrible...
        # actually f**k it hard code in the taper

        # Methods -------

        def _generate_instances(self, insts):
            # generates taper pair

            # generate left taper cell
            taper_layout_left = ParabolicTaper(
                name=self.name + '_TAPER_L').get_default_view(i3.LayoutView)
            taper_layout_left.set(
                length=self.taper_prop_dict['length'],
                width1=self.taper_prop_dict['width1'],
                width2=self.taper_prop_dict['width2'],
                width_etch=self.taper_prop_dict['width_etch'])

            # generate right taper cell
            taper_layout_right = ParabolicTaper(
                name=self.name + '_TAPER_R').get_default_view(i3.LayoutView)
            taper_layout_right.set(
                length=self.taper_prop_dict['length'],
                width1=self.taper_prop_dict['width1'],
                width2=self.taper_prop_dict['width2'],
                width_etch=self.taper_prop_dict['width_etch'])

            # draw taper pairs
            insts += i3.SRef(name=self.name + '_taper1',
                             reference=taper_layout_left)
            t = i3.vector_match_transform(taper_layout_left.ports['right'],
                                          taper_layout_right.ports['right'],
                                          mirrored=True) + i3.Translation(
                                              (self.connect_length, 0.0))
            insts += i3.SRef(name=self.name + '_taper2',
                             reference=taper_layout_right,
                             transformation=t)

            # route between tapers
            if self.connect_length > 0.0:
                route_tapers = i3.RouteManhattan(
                    input_port=insts[self.name + '_taper1'].ports['right'],
                    output_port=insts[self.name + '_taper2'].ports['right'])

                # # make my OWN custom waveguide trace template
                # wg_trace = f_MyIMECWaveguideTemplate( core_width = taper_layout_left.width2,
                #                                       cladding_width = taper_layout_right.width2 + 2.0*taper_layout_right.width_etch )
                # wg_lay = i3.Waveguide(trace_template=StripWgTemplate(), name=wg_name).get_default_view(i3.LayoutView)

                # make waveguide
                wg = i3.Waveguide(trace_template=StripWgTemplate(),
                                  name=self.name + '_WG')

                # add wg
                insts += i3.SRef(name=self.name + 'connect_wg',
                                 reference=wg.Layout(shape=route_tapers))
            # end if self.connect_length > 0.0

            return insts

        # end _generate_instances()

        def _generate_ports(self, ports):
            # add ports 'left' and 'right'

            # left port
            ports += i3.OpticalPort(
                name='left',
                position=self.instances[self.name +
                                        '_taper1'].ports['left'].position,
                angle=180.0)

            # right port
            ports += i3.OpticalPort(
                name='right',
                position=self.instances[self.name +
                                        '_taper2'].ports['left'].position,
                angle=0.0)

            return ports
Exemple #15
0
class Coupon(i3.PCell):
    _name_prefix = "Coupon"

    # Center of the structure
    position = i3.Coord2Property(default=(0.0, 0.0))

    # Coupon parameters
    length = i3.PositiveNumberProperty(default=40.0)
    width = i3.PositiveNumberProperty(default=8.0)
    shrink = i3.NumberProperty(default=0.0)
    # nb = i3.PositiveIntProperty(default=8)
    space = i3.PositiveNumberProperty(default=1000.0)

    class Layout(i3.LayoutView):
        # _name_prefix = "length{}".format(str(self.length))
        def _generate_elements(self, elems):
            # Center of the structure
            (x0, y0) = self.position
            # RELEASE
            release = Release(
                length=self.length,
                width=self.width,
            )
            # release = i3.Rectangle(layer=i3.Layer(number=1, name="release"), center=(0, 0),
            #                         box_size=(self.length, self.width))
            # elems += i3.SRef(reference=release, position=self.position)  Error

            dx = 918.125  # 800nm coupon
            for i in range(0, 3, 1):
                elems += i3.ARef(n_o_periods=(3, 7),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 468.4))
                elems += i3.ARef(n_o_periods=(3, 7),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 538.4))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(560.75 + i * dx, 511.6))

                dy = 1725
                elems += i3.ARef(n_o_periods=(3, 15),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(3, 15),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(560.75 + i * dx, 511.6 + dy))

                dy = 5060
                elems += i3.ARef(n_o_periods=(3, 15),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(3, 15),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(560.75 + i * dx, 511.6 + dy))

                dy = 8395
                elems += i3.ARef(n_o_periods=(3, 8),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(3, 7),
                                 period=(159.5, 210),
                                 reference=release,
                                 origin=(640.5 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(560.75 + i * dx, 511.6 + dy))

            dx += 200  # 1000nm coupon
            for i in range(0, 3, 1):
                elems += i3.ARef(n_o_periods=(4, 7),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 468.4))
                elems += i3.ARef(n_o_periods=(4, 7),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 538.4))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(3319.175 + i * dx, 511.6))

                dy = 1725
                elems += i3.ARef(n_o_periods=(4, 15),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(4, 15),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(3319.175 + i * dx, 511.6 + dy))

                dy = 5060
                elems += i3.ARef(n_o_periods=(4, 15),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(4, 15),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(3319.175 + i * dx, 511.6 + dy))

                dy = 8395
                elems += i3.ARef(n_o_periods=(4, 8),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(4, 7),
                                 period=(167.6, 210),
                                 reference=release,
                                 origin=(3402.975 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(3319.175 + i * dx, 511.6 + dy))

            dx += 200  # 1200nm coupon
            for i in range(0, 3, 1):
                elems += i3.ARef(n_o_periods=(5, 7),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 468.4))
                elems += i3.ARef(n_o_periods=(5, 7),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 538.4))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(6676.25 + i * dx, 511.6))

                dy = 1725
                elems += i3.ARef(n_o_periods=(5, 15),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(5, 15),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(6676.25 + i * dx, 511.6 + dy))

                dy = 5060
                elems += i3.ARef(n_o_periods=(5, 15),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(5, 15),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=15,
                                  period_1d=210,
                                  reference=release,
                                  origin=(6676.25 + i * dx, 511.6 + dy))

                dy = 8395
                elems += i3.ARef(n_o_periods=(5, 8),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 468.4 + dy))
                elems += i3.ARef(n_o_periods=(5, 7),
                                 period=(173, 210),
                                 reference=release,
                                 origin=(6762.75 + i * dx, 538.4 + dy))
                elems += i3.ARefY(n_o_periods_1d=7,
                                  period_1d=210,
                                  reference=release,
                                  origin=(6676.25 + i * dx, 511.6 + dy))

            return elems
Exemple #16
0
    class Layout(i3.LayoutView):
        """
        List of properties:
        period
        duty_cycle
            absolute length of the grating section, not percentage
        grating_amp
        grat_wg_width
        flyback_wg_width
        pitch
        spacing
        length
        numrows
        taper_length
        taper_path_flyback
        taper_width_flyback
        taper_path_swg
        taper_width_swg
        bend_width
        arc_path
        arc_width

        TO GENERATE CUSTOM BENDS:
            set pitch to either 16.0 or 16.516

        """

        from ipkiss.technology import get_technology
        TECH = get_technology()

        # -----------
        # Properties

        # Sidewall grating waveguide properties
        period = i3.PositiveNumberProperty(default=.3,
                                           doc="Period of sidewall grating")
        duty_cycle = i3.PositiveNumberProperty(
            default=.1,
            doc="Length of grating teeth (along periodic direction)")
        grating_amp = i3.NumberProperty(
            default=.01,
            doc=
            "Width/amplitude of grating teeth (normal to periodic direction)")
        grat_wg_width = i3.PositiveNumberProperty(
            default=1.0,
            doc=
            "Width of sidewall grating waveguide core (if grating_amp=0 width of waveguide)"
        )

        # Flyback waveguide properites
        flyback_wg_width = i3.PositiveNumberProperty(
            default=0.4, doc="Width of flyback waveguide core")

        # Grating array properties
        pitch = i3.PositiveNumberProperty(
            default=16.0,
            doc=
            "Sidewall grating pitch (center-to-center distance of sidewall grating waveguides)"
        )
        spacing = i3.PositiveNumberProperty(
            doc="Gap between sidewall grating waveguides and flyback waveguides"
        )

        def _default_spacing(self):
            spacing = (self.pitch - self.grat_wg_width -
                       self.flyback_wg_width) / 2
            return spacing

        length = i3.PositiveNumberProperty(
            default=800.0,
            doc="Length of straight (untapered) waveguide sections")
        numrows = i3.PositiveIntProperty(
            default=32,
            doc=
            "Number of sidewall grating/flyback waveguide pairs in the array")

        # Taper properties
        # Properties used for taper_type = "default"
        taper_length = i3.PositiveNumberProperty(default=10.0,
                                                 doc="Taper length")
        # Properties used for taper_type = "manual"
        taper_path_flyback = i3.NumpyArrayProperty(
            doc=
            "List of coordinates denoting the center path of the taper (bend to flyback waveguide)"
        )
        taper_width_flyback = i3.NumpyArrayProperty(
            doc=
            "List of taper widths normal to each point on the path (bend to flyback waveguide)"
        )
        taper_path_swg = i3.NumpyArrayProperty(
            doc=
            "List of coordinates denoting the center path of the taper (bend to sidewall grating waveguide)"
        )
        taper_width_swg = i3.NumpyArrayProperty(
            doc=
            "List of taper widths normal to each point on the path (bend to sidewall grating waveguide)"
        )

        # REDEFINING TAPER HERE
        # taper_swg       = i3.ViewProperty( default='', doc='Taper layout that connects grating waveguide to the bends')
        # taper_flyback   = i3.ViewProperty( default='', doc='Taper layout that connects flyback waveguide to the bends')

        # Pick grating type:
        # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom',
        # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom',
        grating_type = i3.StringProperty(default='',
                                         doc='Grating type to draw')

        def _default_taper_path_flyback(self):
            #Default is a straight linear taper
            path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_)
            return path

        def _default_taper_width_flyback(self):
            # Default is a straight linear taper
            widths = np.array([self.bend_width, self.flyback_wg_width],
                              np.float_)
            return widths

        def _default_taper_path_swg(self):
            #Default is a straight linear taper
            path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_)
            return path

        def _default_taper_width_swg(self):
            # Default is a straight linear taper
            widths = np.array([self.bend_width, self.grat_wg_width], np.float_)
            return widths

        # Bend properties
        # Properties used for bend_type = "default"
        bend_width = i3.PositiveNumberProperty(
            default=TECH.WG.CORE_WIDTH,
            doc="Width of waveguides in bend sections")
        # Properties used for bend_type = "manual"
        arc_path = i3.NumpyArrayProperty(
            doc=
            "List of coordinates denoting the center path of the arc connectors (going from sidewall grating waveguide to flyback waveguide"
        )
        arc_width = i3.NumpyArrayProperty(
            doc=
            "List of arc widths normal to each point on the path (going from sidewall grating waveguide to flyback waveguide"
        )

        def _default_arc_path(self):
            if self.pitch == 16.0:
                #Use pregenerated adiabatic bends (TX)
                pathwidth = np.loadtxt("../nathan/bend_data/txbend.txt",
                                       np.float_)
                arc_path = pathwidth[:, :2]
            elif self.pitch == 16.516:
                # Use pregenerated adiabatic bends (RX)
                pathwidth = np.loadtxt("../nathan/bend_data/rxbend.txt",
                                       np.float_)
                arc_path = pathwidth[:, :2]
            else:
                # Default is 180 arc
                arc_path = np.zeros([181, 2], np.float_)
                bend_rad = (self.grat_wg_width / 2 + self.spacing +
                            self.flyback_wg_width / 2) / 2
                for ii in range(181):
                    angle = np.pi / 180.0 * ii
                    arc_path[ii, :] = bend_rad * np.array(
                        [-np.sin(angle), np.cos(angle)], np.float_)

            return arc_path

        def _default_arc_width(self):
            if self.pitch == 16.0:
                #Use pregenerated adiabatic bends (TX)
                pathwidth = np.loadtxt("../nathan/bend_data/txbend.txt",
                                       np.float_)
                arc_width = pathwidth[:, 2]
            elif self.pitch == 16.516:
                #Use pregenerated adiabatic bends (RX)
                pathwidth = np.loadtxt("../nathan/bend_data/rxbend.txt",
                                       np.float_)
                arc_width = pathwidth[:, 2]
            else:
                #Default is uniform width with default core_width
                arc_width = np.ones([181], np.float_)
                arc_width = arc_width * self.bend_width
            return arc_width

        def validate_properties(self):
            """Check whether the combination of properties is valid."""
            if (self.grat_wg_width + self.flyback_wg_width +
                    2 * self.spacing) != self.pitch:
                raise i3.PropertyValidationError(
                    self,
                    "Array incorrectly overspecified (pitch=/=wg_widths+spacing",
                    {"pitch": self.pitch})
            return True

        @i3.cache()
        def _get_components(self):
            # Make waveguides

            # Pick grating type:
            # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom',
            # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom',

            if self.grating_type == 'one_sidewall':
                # single sidewall grating
                swg_l = self.cell.swg.get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          both_sides=False)

            elif self.grating_type == 'two_sidewalls':
                # double sidewall grating
                swg_l = self.cell.swg.get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          both_sides=True)

            elif self.grating_type == 'nitride_vertical_top':
                # nitride vertical grating, top layer
                swg_l = NitrideGratingWg().get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          grating_type='vertical',
                          nitride_layer='top')

            elif self.grating_type == 'nitride_vertical_bottom':
                # nitride vertical grating, top layer
                swg_l = NitrideGratingWg().get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          grating_type='vertical',
                          nitride_layer='bottom')

            elif self.grating_type == 'nitride_one_sidewall_top':
                # nitride vertical grating, top layer
                swg_l = NitrideGratingWg().get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          grating_type='one_sidewall',
                          nitride_layer='top')

            elif self.grating_type == 'nitride_one_sidewall_bottom':
                # nitride vertical grating, top layer
                swg_l = NitrideGratingWg().get_default_view(i3.LayoutView)
                swg_l.set(period=self.period,
                          duty_cycle=self.duty_cycle,
                          grating_amp=self.grating_amp,
                          wg_width=self.grat_wg_width,
                          length=self.length,
                          grating_type='one_sidewall',
                          nitride_layer='bottom')

            # end making grating if statement

            # flyback and stuff
            flyback_l = self.cell.flyback.get_default_view(i3.LayoutView)
            flyback_path = [(0.0, 0.0), (self.length, 0.0)]
            wg_temp_flyback = self.cell.wg_temp.get_default_view(i3.LayoutView)
            wg_temp_flyback.set(core_width=self.flyback_wg_width)
            flyback_l.set(trace_template=wg_temp_flyback, shape=flyback_path)

            # Center-to-center distance between sidewall grating waveguide and flyback waveguide
            flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2

            # Make bends
            bend_l = self.cell.bend.get_default_view(i3.LayoutView)
            if self.cell.bend_type is "default":
                # Default waveguide 180 arc
                bend_rad = flyback_offset / 2
                arc = i3.ShapeArc(center=(0.0, 0.0),
                                  radius=bend_rad,
                                  start_angle=89.0,
                                  end_angle=270.0)
                wg_temp_bend = self.cell.wg_temp.get_default_view(
                    i3.LayoutView)
                wg_temp_bend.set(core_width=self.bend_width)
                bend_l.set(trace_template=wg_temp_bend, shape=arc)
            else:
                # Custom bend pcell
                bend_l.set(wg_path=self.arc_path,
                           wg_width=self.arc_width,
                           start_angle=180.0,
                           end_angle=0.0)

            # Make tapers
            taper_flyback_l = self.cell.taper_flyback.get_default_view(
                i3.LayoutView)
            taper_swg_l = self.cell.taper_swg.get_default_view(i3.LayoutView)

            if self.cell.taper_type is "default":
                # Linear taper pcell
                if self.cell.bend_type is "default":
                    flyback_bend_width = self.bend_width
                    swg_bend_width = self.bend_width
                else:
                    arcsize = self.arc_width.shape
                    arclength = arcsize[0]
                    flyback_bend_width = self.arc_width[arclength - 1]
                    swg_bend_width = self.arc_width[0]

                taper_flyback_l.set(length=self.taper_length,
                                    wg_width_in=flyback_bend_width,
                                    wg_width_out=self.flyback_wg_width)
                taper_swg_l.set(length=self.taper_length,
                                wg_width_in=swg_bend_width,
                                wg_width_out=self.grat_wg_width)
            else:
                # Custom taper pcell
                taper_flyback_l.set(wg_path=self.taper_path_flyback,
                                    wg_width=self.taper_width_flyback,
                                    start_angle=0.0,
                                    end_angle=0.0)
                taper_swg_l.set(wg_path=self.taper_path_swg,
                                wg_width=self.taper_width_swg,
                                start_angle=0.0,
                                end_angle=0.0)

            return swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l

        def _generate_instances(self, insts):
            swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l = self._get_components(
            )

            # Hard code the tapers into here: (I hate hardcoding stuff, but no choice here)
            taper_length = 79.0  # 79 is the best according to deniz' sims
            width_etch = 4.0
            wg_width = 0.5
            taper_swg = ParabolicTaper(
                name=self.name + '_TAPER').get_default_view(i3.LayoutView)
            taper_swg.set(length=taper_length,
                          width1=wg_width,
                          width2=self.grat_wg_width,
                          width_etch=width_etch)

            taper_flyback = ParabolicTaper(
                name=self.name + '_OTHERTAPER').get_default_view(i3.LayoutView)
            taper_flyback.set(length=taper_length,
                              width1=wg_width,
                              width2=self.flyback_wg_width,
                              width_etch=width_etch)

            for ii in range(self.numrows):

                # Find component translations (for all numrows)
                t_swg = i3.Translation((0.0, ii * self.pitch))
                # t_taper_swg_w   = vector_match_transform(taper_swg_l.ports["out"], swg_l.ports['in']) + t_swg
                # t_taper_swg_e   = vector_match_transform(taper_swg_l.ports["out"], swg_l.ports['out'], mirrored=True) + t_swg
                t_taper_swg_w = vector_match_transform(
                    taper_swg.ports["right"], swg_l.ports['in']) + t_swg
                t_taper_swg_e = vector_match_transform(
                    taper_swg.ports["right"],
                    swg_l.ports['out'],
                    mirrored=True) + t_swg

                # Add grating rows + grating row tapers
                insts += i3.SRef(reference=swg_l,
                                 name="SidewallGratWg" + str(ii),
                                 transformation=t_swg)
                # insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_West" + str(ii), transformation=t_taper_swg_w)
                # insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_East" + str(ii), transformation=t_taper_swg_e)
                insts += i3.SRef(reference=taper_swg,
                                 name="SwgTaper_West" + str(ii),
                                 transformation=t_taper_swg_w)
                insts += i3.SRef(reference=taper_swg,
                                 name="SwgTaper_East" + str(ii),
                                 transformation=t_taper_swg_e)

                if ii < (self.numrows - 1):

                    # Find component translations (for numrows-1)
                    flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2
                    t_flyback = i3.Translation(
                        (0.0, ii * self.pitch + flyback_offset))
                    # t_taper_flyback_w   = vector_match_transform(taper_flyback_l.ports["out"], flyback_l.ports['in']) + t_flyback
                    # t_taper_flyback_e   = vector_match_transform(taper_flyback_l.ports["out"], flyback_l.ports['out'],
                    #                                        mirrored=True) + t_flyback
                    t_taper_flyback_w   = vector_match_transform( taper_flyback.ports["right"],
                                                                  flyback_l.ports['in'] ) \
                                          + t_flyback
                    t_taper_flyback_e   = vector_match_transform( taper_flyback.ports["right"],
                                                                  flyback_l.ports['out'],
                                                                  mirrored = True ) \
                                          + t_flyback

                    # t_bend_e = i3.VMirror() + vector_match_transform(bend_l.ports['in'], taper_swg_l.ports["in"],mirrored=True) + t_taper_swg_e
                    t_bend_e = i3.VMirror() \
                               + vector_match_transform( bend_l.ports['in'],
                                                       taper_swg.ports["left"],
                                                       mirrored = True ) \
                               + t_taper_swg_e
                    t_bend_w = i3.VMirror() \
                               + vector_match_transform( bend_l.ports['out'],
                                                         taper_flyback.ports["left"] ) \
                               + t_taper_flyback_w \
                               + i3.Translation( (0.0, self.pitch) )

                    # Add instances (for numrows-1)

                    # flyback waveguide
                    insts += i3.SRef(reference=flyback_l,
                                     name="FlybackWg" + str(ii),
                                     transformation=t_flyback)

                    # flyback tapers
                    # insts += i3.SRef(   reference       = taper_flyback_l,
                    #                     name            = "FlybackTaper_West" + str(ii),
                    #                     transformation  = t_taper_flyback_w )
                    # insts += i3.SRef(   reference       = taper_flyback_l,
                    #                     name            = "FlybackTaper_East" + str(ii),
                    #                     transformation  = t_taper_flyback_e )
                    insts += i3.SRef(reference=taper_flyback,
                                     name="FlybackTaper_West" + str(ii),
                                     transformation=t_taper_flyback_w)
                    insts += i3.SRef(reference=taper_flyback,
                                     name="FlybackTaper_East" + str(ii),
                                     transformation=t_taper_flyback_e)

                    # bends
                    insts += i3.SRef(reference=bend_l,
                                     name="Bend_West" + str(ii),
                                     transformation=t_bend_w)
                    insts += i3.SRef(reference=bend_l,
                                     name="Bend_East" + str(ii),
                                     transformation=t_bend_e)

                # end if
            # end for loop

            return insts

        def _generate_ports(self, ports):
            """
            THIS NEEDS TO BE UPDATED TO REFLECT INPUT OUTPUT TAPERS
            """
            # ports += self.instances["SidewallGratWg0"].ports["in"]
            # ports += self.instances["SidewallGratWg"+str(self.numrows-1)].ports["out"]

            ports += i3.OpticalPort(name='in',
                                    position=self.instances["SwgTaper_West0"].
                                    ports["left"].position,
                                    angle=180.0)
            ports += i3.OpticalPort(
                name='out',
                position=self.instances["SwgTaper_East" +
                                        str(self.numrows -
                                            1)].ports["left"].position,
                angle=0.0)

            return ports
class Coupon(i3.PCell):
    _name_prefix = "Coupon"

    # Center of the structure
    position = i3.Coord2Property(default=(0.0, 0.0))

    # Coupon parameters
    length = i3.PositiveNumberProperty(default=2750.0)
    width = i3.PositiveNumberProperty(default=85.0)
    shrink = i3.NumberProperty(default=0.0)
    nb = i3.PositiveIntProperty(default=8)
    space = i3.PositiveNumberProperty(default=1000.0)

    class Layout(i3.LayoutView):
        # _name_prefix = "length{}".format(str(self.length))
        def _generate_elements(self, elems):
            # Center of the structure
            (x0, y0) = self.position
            # RELEASE
            release = Release(
                length=self.length,
                width=self.width,
            )
            # elems += i3.SRef(reference=release, position=self.position)
            elems += i3.ARef(n_o_periods=(3, self.nb),
                             period=(self.length + 250, 210),
                             reference=release,
                             origin=(x0, y0))
            elems += i3.ARef(n_o_periods=(3, self.nb),
                             period=(self.length + 250, 280),
                             reference=release,
                             origin=(x0, y0 + 210 * self.nb -
                                     (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(3, self.nb),
                period=(self.length + 250, 350),
                reference=release,
                origin=(x0,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(3, self.nb),
                period=(self.length + 250, 420),
                reference=release,
                origin=(x0,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 500, 210),
                             reference=release,
                             origin=(x0 + 9250 - self.shrink * 3, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 500, 280),
                reference=release,
                origin=(x0 + 9250 - self.shrink * 3,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 500, 350),
                reference=release,
                origin=(x0 + 9250 - self.shrink * 3,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 500, 420),
                reference=release,
                origin=(x0 + 9250 - self.shrink * 3,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 750, 210),
                             reference=release,
                             origin=(x0 + 8000 * 2 - self.shrink * 5, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 750, 280),
                reference=release,
                origin=(x0 + 8000 * 2 - self.shrink * 5,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 750, 350),
                reference=release,
                origin=(x0 + 8000 * 2 - self.shrink * 5,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 750, 420),
                reference=release,
                origin=(x0 + 8000 * 2 - self.shrink * 5,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 1000, 210),
                             reference=release,
                             origin=(x0 + 23250 - self.shrink * 7, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1000, 280),
                reference=release,
                origin=(x0 + 23250 - self.shrink * 7,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1000, 350),
                reference=release,
                origin=(x0 + 23250 - self.shrink * 7,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1000, 420),
                reference=release,
                origin=(x0 + 23250 - self.shrink * 7,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 1500, 210),
                             reference=release,
                             origin=(x0 + 29750 + 1500 - self.shrink * 9, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1500, 280),
                reference=release,
                origin=(x0 + 29750 + 1500 - self.shrink * 9,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1500, 350),
                reference=release,
                origin=(x0 + 29750 + 1500 - self.shrink * 9,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 1500, 420),
                reference=release,
                origin=(x0 + 29750 + 1500 - self.shrink * 9,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 2000, 210),
                             reference=release,
                             origin=(x0 + 38250 + 2000 - self.shrink * 11, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 2000, 280),
                reference=release,
                origin=(x0 + 38250 + 2000 - self.shrink * 11,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 2000, 350),
                reference=release,
                origin=(x0 + 38250 + 2000 - self.shrink * 11,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 2000, 420),
                reference=release,
                origin=(x0 + 38250 + 2000 - self.shrink * 11,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            elems += i3.ARef(n_o_periods=(2, self.nb),
                             period=(self.length + 3000, 210),
                             reference=release,
                             origin=(x0 + 47750 + 3000 - self.shrink * 13, y0))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 3000, 280),
                reference=release,
                origin=(x0 + 47750 + 3000 - self.shrink * 13,
                        y0 + 210 * self.nb - (210 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 3000, 350),
                reference=release,
                origin=(x0 + 47750 + 3000 - self.shrink * 13,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space))
            elems += i3.ARef(
                n_o_periods=(2, self.nb),
                period=(self.length + 3000, 420),
                reference=release,
                origin=(x0 + 47750 + 3000 - self.shrink * 13,
                        y0 + 210 * self.nb - (210 - self.width) + self.space +
                        280 * self.nb - (280 - self.width) + self.space +
                        350 * self.nb - (350 - self.width) + self.space))

            # elems += i3.Circle(layer=i3.Layer(number = 5, name = "tether"),radius=50000)
            return elems
Exemple #18
0
    class Layout(i3.LayoutView):

        # Properties -------

        # taper to draw
        taper_prop_dict = i3.DictProperty( default = {}, doc = 'Dictionary of taper cell properties.' + \
                                           'Properties = "length", "width1", "width2", "width_etch" ' )

        # number of rows
        n_rows = i3.IntProperty(default=3, doc='number of taper clip rows')

        # number of taper pairs per row
        n_taper_pairs_per_row = i3.IntProperty(
            default=2, doc='number of taper clip pairs per row')

        # spacing between rows
        row_spacing = i3.PositiveNumberProperty(
            default=0.0, doc='spacing between rows (midpoint to midpoint)')

        # Taper pair properties
        connect_length = i3.NumberProperty(default=0.0,
                                           doc='distance between tapers')
        pair_connect_length = i3.NumberProperty(
            default=0.0, doc='distance between taper pairs')

        # input/output connection length
        bot_gc_connect_length = i3.NumberProperty(
            default=0.0, doc='distance between grating and bottom taper')
        top_gc_connect_length = i3.NumberProperty(
            default=0.0, doc='distance between grating and top taper')

        # radius of each arc
        bend_radius = i3.PositiveNumberProperty(
            default=5.0, doc='spacing between rows (midpoint to midpoint)')

        # Methods -------

        def _generate_instances(self, insts):
            # Generates taper clip

            # make my OWN custom waveguide trace template
            # wg_trace = f_MyIMECWaveguideTemplate(core_width=self.taper_prop_dict['width1'],
            #                                      cladding_width=self.taper_prop_dict['width1'] + 2.0 * self.taper_prop_dict['width_etch'])

            # make waveguide
            wg = i3.Waveguide(trace_template=StripWgTemplate(),
                              name=self.name + '_WG')
            wg_round = i3.RoundedWaveguide(trace_template=StripWgTemplate(),
                                           name=self.name + '_WG_ROUND')

            # how much to translate bends left/right
            # t_left = i3.Translation((self.bend_radius + (float(self.n_rows)/2.0) ))
            t_left = i3.Translation((-2.5 * self.bend_radius, 0.0))
            t_right = i3.Translation((2.5 * self.bend_radius, 0.0))

            # draw taper pair rows
            for ii in range(self.n_rows):

                # add rows
                tp_rows_layout = TaperPairRow(name=self.name + '_TProw' +
                                              str(ii)).get_default_view(
                                                  i3.LayoutView)
                tp_rows_layout.set(
                    taper_prop_dict=self.taper_prop_dict,
                    connect_length=self.connect_length,
                    pair_connect_length=self.pair_connect_length,
                    n_pairs=self.n_taper_pairs_per_row)

                # set translation
                t = i3.Translation((0.0, float(ii) * self.row_spacing))

                # place taper pair row
                tp_row_name = self.name + '_TP_ROW' + str(ii)
                insts += i3.SRef(name=tp_row_name,
                                 reference=tp_rows_layout,
                                 transformation=t)

                # draw connecting arcs
                if ii > 0:

                    if (ii % 2) == 1:
                        # bend on the right
                        # make shape bend
                        row_name = self.name + '_TP_ROW' + str(ii - 1)
                        shape_bend = i3.ShapeBend(start_point=insts[row_name].
                                                  ports['right'].position,
                                                  radius=self.bend_radius,
                                                  start_angle=-90.05,
                                                  end_angle=90.05,
                                                  angle_step=0.1)

                        # add 180 deg bend
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_arc_r' + str(ii))
                        arc_name = self.name + '_arc' + str(ii)
                        insts += i3.SRef(
                            name=arc_name,
                            reference=wg_copy.Layout(shape=shape_bend),
                            transformation=t_right)

                        # connect bottom wgs

                        # get coords
                        in_port_coords = insts[arc_name].ports['in'].position
                        out_port_coords = insts[row_name].ports[
                            'right'].position

                        # draw bezier curve
                        bez = BezierCurve(
                            N=100,
                            P0=(in_port_coords[0] + 0.01, in_port_coords[1]),
                            P1=(in_port_coords[0] - self.bend_radius / 2.0,
                                in_port_coords[1]),
                            P2=(out_port_coords[0] + self.bend_radius / 2.0,
                                out_port_coords[1]),
                            P3=(out_port_coords[0] - 0.01, out_port_coords[1]),
                            R=(-self.bend_radius, +self.bend_radius),
                            dy_dx=(0.0, -0.0))
                        bez_coords = bez.bezier_coords()

                        # make ipkiss shape
                        s = i3.Shape(bez_coords)

                        # add bottom wg connector
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_arc_r_con' + str(ii))
                        insts += i3.SRef(name=self.name + '_con_wg_r_b_' +
                                         str(ii),
                                         reference=wg_copy.Layout(shape=s))

                        # connect top wgs
                        next_row_name = self.name + '_TP_ROW' + str(ii)
                        in_port_coords = insts[arc_name].ports['out'].position
                        out_port_coords = insts[next_row_name].ports[
                            'right'].position

                        # draw bezier curve
                        bez = BezierCurve(
                            N=500,
                            P0=(in_port_coords[0] + 0.01, in_port_coords[1]),
                            P1=(in_port_coords[0] - self.bend_radius / 2.0,
                                in_port_coords[1]),
                            P2=(out_port_coords[0] + self.bend_radius / 2.0,
                                out_port_coords[1]),
                            P3=(out_port_coords[0] - 0.01, out_port_coords[1]),
                            R=(self.bend_radius, -self.bend_radius),
                            dy_dx=(0.0, -0.0))
                        bez_coords = bez.bezier_coords()

                        # make ipkiss shape
                        s = i3.Shape(bez_coords)

                        # add wg bend
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_bez_r' + str(ii))
                        insts += i3.SRef(name=self.name + '_con_wg_r_t_' +
                                         str(ii),
                                         reference=wg_copy.Layout(shape=s))

                    else:
                        # bend on the left
                        # make shape bend
                        row_name = self.name + '_TP_ROW' + str(ii - 1)
                        shape_bend = i3.ShapeBend(start_point=(
                            insts[row_name].ports['left'].position),
                                                  radius=self.bend_radius,
                                                  start_angle=90.05,
                                                  end_angle=-90.05,
                                                  angle_step=0.1,
                                                  clockwise=False)

                        # add 180 deg bend
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_arc_l' + str(ii))
                        arc_name = self.name + '_arc' + str(ii)
                        insts += i3.SRef(
                            name=arc_name,
                            reference=wg_copy.Layout(shape=shape_bend),
                            transformation=t_left)

                        # connect bottom wgs

                        # get coords
                        in_port_coords = insts[arc_name].ports['out'].position
                        out_port_coords = insts[row_name].ports[
                            'left'].position

                        # draw bezier curve
                        bez = BezierCurve(
                            N=100,
                            P0=(in_port_coords[0] - 0.01, in_port_coords[1]),
                            P1=(in_port_coords[0] + self.bend_radius / 2.0,
                                in_port_coords[1]),
                            P2=(out_port_coords[0] - self.bend_radius / 2.0,
                                out_port_coords[1]),
                            P3=(out_port_coords[0] + 0.01, out_port_coords[1]),
                            R=(-self.bend_radius, +self.bend_radius),
                            dy_dx=(0.0, -0.0))
                        bez_coords = bez.bezier_coords()

                        # make ipkiss shape
                        s = i3.Shape(bez_coords)

                        # add bottom wg connector
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_arc_l_con' + str(ii))
                        insts += i3.SRef(name=self.name + '_con_wg_l_b_' +
                                         str(ii),
                                         reference=wg_copy.Layout(shape=s))

                        # connect top wgs
                        next_row_name = self.name + '_TP_ROW' + str(ii)
                        in_port_coords = insts[arc_name].ports['in'].position
                        out_port_coords = insts[next_row_name].ports[
                            'left'].position

                        # draw bezier curve
                        bez = BezierCurve(
                            N=500,
                            P0=(in_port_coords[0] - 0.01, in_port_coords[1]),
                            P1=(in_port_coords[0] + self.bend_radius / 2.0,
                                in_port_coords[1]),
                            P2=(out_port_coords[0] - self.bend_radius / 2.0,
                                out_port_coords[1]),
                            P3=(out_port_coords[0] + 0.01, out_port_coords[1]),
                            R=(-self.bend_radius, +self.bend_radius),
                            dy_dx=(0.0, -0.0))
                        bez_coords = bez.bezier_coords()

                        # make ipkiss shape
                        s = i3.Shape(bez_coords)

                        # add wg bend
                        wg_copy = i3.Waveguide(
                            trace_template=StripWgTemplate(),
                            name=self.name + '_bez_l' + str(ii))
                        insts += i3.SRef(name=self.name + '_con_wg_l_t_' +
                                         str(ii),
                                         reference=wg_copy.Layout(shape=s))

                    # end if bend

                # end drawing connecting arcs

            # end for ii in range(self.rows)

            # # connect the input grating
            # # pick grating layout to return
            # grating_layout = {
            #     'FGCCTE_FC1DC_625_313':     FGCCTE_FC1DC_625_313().Layout(),
            #     'FGCCTE_FCWFC1DC_630_378':  FGCCTE_FCWFC1DC_630_378().Layout(),
            #     'FGCCTM_FC1DC_984_492':     FGCCTM_FC1DC_984_492().Layout(),
            # }[self.grating_name]
            #
            #
            #
            # # place bottom grating
            # # always assuming bottom grating starts on the left
            # bot_grating_name = self.name+'_bot_grating'
            # t = i3.vector_match_transform( grating_layout.ports['waveguide'],
            #                                insts[self.name + '_TP_ROW0'].ports['left'] ) + \
            #     i3.Translation( ( -self.bot_gc_connect_length, 0.0 ) )
            #
            # insts += i3.SRef(   name            = bot_grating_name,
            #                     reference       = grating_layout,
            #                     transformation  = t )
            #
            # # connect bottom grating to taper
            # route_wg_bot = i3.RouteManhattan( input_port  = insts[bot_grating_name].ports['waveguide'],
            #                                   output_port = insts[self.name + '_TP_ROW0'].ports['left'] )
            #
            # # add wg
            # wg_bot = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_BOT')
            # insts += i3.SRef(name=self.name + '_connect_wg_bot', reference=wg_bot.Layout(shape=route_wg_bot))
            #
            #
            #
            # # place top grating
            # top_grating_name = self.name + '_top_grating'
            # if (self.n_rows % 2) == 1:
            #     # even # of rows, output is to the right
            #     t = i3.vector_match_transform(  grating_layout.ports['waveguide'],
            #                                     insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['right'],
            #                                     mirrored = True ) + \
            #         i3.Translation((self.top_gc_connect_length, 0.0))
            #
            #     insts += i3.SRef( name              = top_grating_name,
            #                       reference         = grating_layout,
            #                       transformation    = t)
            #
            #     # connect top grating to taper
            #     route_wg_top = i3.RouteManhattan(   input_port  = insts[top_grating_name].ports['waveguide'],
            #                                         output_port = insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['right'])
            #
            #     # add wg
            #     wg_top = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_TOP')
            #     insts += i3.SRef(name=self.name + '_connect_wg_top', reference=wg_top.Layout(shape=route_wg_top))
            #
            # else:
            #     # odd # of rows, output is to the left
            #     t = i3.vector_match_transform(  grating_layout.ports['waveguide'],
            #                                     insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['left'],
            #                                     mirrored = False ) + \
            #         i3.Translation((-self.top_gc_connect_length, 0.0))
            #
            #     insts += i3.SRef( name              = top_grating_name,
            #                       reference         = grating_layout,
            #                       transformation    = t)
            #
            #     # connect top grating to taper
            #     route_wg_top = i3.RouteManhattan(   input_port  = insts[top_grating_name].ports['waveguide'],
            #                                         output_port = insts[self.name + '_TP_ROW' + str(self.n_rows-1)].ports['left'])
            #
            #     # add wg
            #     wg_top = i3.Waveguide( trace_template = StripWgTemplate(), name = self.name + '_WG_TOP')
            #     insts += i3.SRef(name=self.name + '_connect_wg_top', reference=wg_top.Layout(shape=route_wg_top))

            return insts
Exemple #19
0
    class Layout(PhaseShifterWaveguideTemplate.Layout):
        core_width = i3.PositiveNumberProperty(doc="width of the core")
        p_width = i3.PositiveNumberProperty(doc="width of low dose P implant")
        p_offset = i3.NumberProperty(
            doc="offset from the center line of low dose P implant")
        n_width = i3.PositiveNumberProperty(doc="width of low dose N implant")
        n_offset = i3.NumberProperty(
            doc="offset from the center line of low dose N implant")
        high_dose_p_width = i3.PositiveNumberProperty(
            doc="width of high dose P implant")
        high_dose_p_offset = i3.NumberProperty(
            doc="offset from the center line of high dose P implant")
        high_dose_n_width = i3.PositiveNumberProperty(
            doc="width of high dose N implant")
        high_dose_n_offset = i3.NumberProperty(
            doc="offset from the center line of high dose N implant")
        con_width = i3.PositiveNumberProperty(
            doc="width of contacts etch (same on both side of the center line)"
        )
        con_p_offset = i3.NumberProperty(
            doc="offset from the center line of contacts etch on P implant")
        con_n_offset = i3.NumberProperty(
            doc="offset from the center line of contacts etch on N implant")

        def _default_core_width(self):
            return 0.45

        def _default_p_width(self):
            return 3.

        def _default_p_offset(self):
            return self.p_width / 2.

        def _default_n_width(self):
            return self.p_width

        def _default_n_offset(self):
            return -self.n_width / 2.

        def _default_high_dose_p_width(self):
            return 2.

        def _default_high_dose_p_offset(self):
            return self.p_width + self.high_dose_p_width / 2.

        def _default_high_dose_n_width(self):
            return self.high_dose_p_width

        def _default_high_dose_n_offset(self):
            return -self.high_dose_p_offset

        def _default_con_width(self):
            return self.high_dose_p_width / 2.

        def _default_con_p_offset(self):
            return self.high_dose_p_offset

        def _default_con_n_offset(self):
            return self.high_dose_n_offset

        def _default_trace_template(self):
            lv = self.cell.trace_template.get_default_view(self)
            lv.set(core_width=self.core_width)
            return lv

        def _default_trace_template_for_ports(self):
            port_tt = SiWireWaveguideTemplate(
                name="{}_wg_port_tt".format(self.name))
            port_tt_lv = port_tt.Layout(core_width=self.core_width)
            return port_tt_lv

        def _default_implant_windows(self):
            core_half_width = 0.5 * self.core_width
            p_half_width = 0.5 * self.p_width
            n_half_width = 0.5 * self.n_width
            high_dose_p_half_width = 0.5 * self.high_dose_p_width
            high_dose_n_half_width = 0.5 * self.high_dose_n_width

            p_offset = self.p_offset
            n_offset = self.n_offset
            high_dose_p_offset = self.high_dose_p_offset
            high_dose_n_offset = self.high_dose_n_offset

            windows = []
            # core
            windows.append(
                i3.PathTraceWindow(layer=i3.TECH.PPLAYER.SI,
                                   start_offset=-core_half_width,
                                   end_offset=+core_half_width))
            # low_dose_p
            windows.append(
                i3.PathTraceWindow(layer=i3.TECH.PPLAYER.P,
                                   start_offset=p_offset - p_half_width,
                                   end_offset=p_offset + p_half_width))
            # low_dose_n
            windows.append(
                i3.PathTraceWindow(layer=i3.TECH.PPLAYER.N,
                                   start_offset=n_offset - n_half_width,
                                   end_offset=n_offset + n_half_width))
            # high_dose_p
            windows.append(
                i3.PathTraceWindow(
                    layer=i3.TECH.PPLAYER.PPLUS,
                    start_offset=high_dose_p_offset - high_dose_p_half_width,
                    end_offset=high_dose_p_offset + high_dose_p_half_width))
            # high_dose_n
            windows.append(
                i3.PathTraceWindow(
                    layer=i3.TECH.PPLAYER.NPLUS,
                    start_offset=high_dose_n_offset - high_dose_n_half_width,
                    end_offset=high_dose_n_offset + high_dose_n_half_width))
            return windows

        def _default_contact_windows(self):
            con_half_width = 0.5 * self.con_width
            con_p_offset = self.con_p_offset
            con_n_offset = self.con_n_offset

            windows = []
            # Contact on P++
            windows.append(
                i3.ExtendedPathTraceWindow(
                    layer=i3.TECH.PPLAYER.CON,
                    start_offset=con_p_offset - con_half_width,
                    end_offset=con_p_offset + con_half_width,
                    extension=(-0.5, -0.5)))
            # Contact on N++
            windows.append(
                i3.ExtendedPathTraceWindow(
                    layer=i3.TECH.PPLAYER.CON,
                    start_offset=con_n_offset - con_half_width,
                    end_offset=con_n_offset + con_half_width,
                    extension=(-0.5, -0.5)))
            return windows

        def _default_metal_windows(self):
            windows = []
            return windows

        def _default_windows(self):
            windows = self.implant_windows + self.contact_windows + self.metal_windows
            return windows
Exemple #20
0
    class Layout(PlaceAndAutoRoute.Layout):
        delta = i3.PositiveNumberProperty(
            default=60., doc='Offset of the arm with the 0 (@ 0 delay) [um]')
        ground_width = i3.PositiveNumberProperty(
            default=80., doc="Width of exteriors grounds line [um]")
        signal_width = i3.PositiveNumberProperty(
            default=10., doc="Width of signal line [um]")
        metal_spacing = i3.PositiveNumberProperty(
            default=4., doc="Spacing between 2 metal lines [um]")
        delay = i3.NumberProperty(
            default=0.,
            doc=
            'Delay between the 2 arms (0< in bottom arm, >0 in top arm) [um]')
        additional_length = i3.NonNegativeNumberProperty(
            default=50., doc="Additional length of the metal lines [um]")
        pad_width = i3.PositiveNumberProperty(
            default=50., doc='Width of the electrical pads [um]')
        pad_length = i3.PositiveNumberProperty(
            default=70., doc='Length of the electrical pads [um]')
        taper_length = i3.PositiveNumberProperty(
            default=60.,
            doc='Length of the tapers between the pads and the lines [um]')
        period_pad = i3.PositiveNumberProperty(default=70.,
                                               doc='Period of the pads [um]')

        def _default_modulator(self):
            lv = self.cell.modulator.get_default_view(self)
            lv.set(shape=[(0., 0.), (self.modulator_length, 0.)])
            return lv

        def _generate_elements(self, elems):
            super(PlaceAndAutoRoute.Layout, self)._generate_elements(elems)

            total_length = self.modulator_length + self.additional_length
            delta = self.delta
            delay = self.delay

            signal_width = self.signal_width
            metal_spacing = self.metal_spacing
            ground_width = self.ground_width

            period_pad = self.period_pad
            taper_length = self.taper_length
            pad_length = self.pad_length
            pad_width = self.pad_width
            pad_size = (pad_length, pad_width)

            y_ground = -delta + min(
                delay / 2.,
                0.) - signal_width - 1.5 * metal_spacing - ground_width / 2.
            y_arm1_n = -delta + min(
                delay / 2., 0.) - signal_width / 2. - metal_spacing / 2.
            y_arm1_p = delay / 4. - signal_width / 2. - metal_spacing / 2.
            y_arm2_n = delta + max(delay / 2.,
                                   0.) - signal_width / 2. - metal_spacing / 2.
            y_arm2_p = delta + max(delay / 2.,
                                   0.) + ground_width / 2. + metal_spacing / 2.

            arm2_n_width = 2 * delta + abs(
                delay / 2.) - signal_width - 2 * metal_spacing

            # Metal lines
            lines = []
            ground = i3.Rectangle(layer=i3.TECH.PPLAYER.M1,
                                  center=(0., y_ground),
                                  box_size=(total_length, ground_width))
            arm1_n = i3.Rectangle(layer=i3.TECH.PPLAYER.M1,
                                  center=(0., y_arm1_n),
                                  box_size=(total_length, signal_width))
            arm1_p = i3.Rectangle(layer=i3.TECH.PPLAYER.M1,
                                  center=(0., y_arm1_p),
                                  box_size=(total_length, arm2_n_width))
            arm2_n = i3.Rectangle(layer=i3.TECH.PPLAYER.M1,
                                  center=(0., y_arm2_n),
                                  box_size=(total_length, signal_width))
            arm2_p = i3.Rectangle(layer=i3.TECH.PPLAYER.M1,
                                  center=(0., y_arm2_p),
                                  box_size=(total_length, ground_width))

            lines += [ground, arm1_n, arm1_p, arm2_n, arm2_p]

            # Metal left pads
            left_pads = []
            taper_ground = i3.Boundary(
                layer=i3.TECH.PPLAYER.M1,
                shape=[
                    (-(total_length / 2. + taper_length),
                     y_arm1_p - 2 * period_pad + pad_width / 2.),
                    (-(total_length / 2. + taper_length),
                     y_arm1_p - 2 * period_pad - pad_width / 2.),
                    (-total_length / 2., y_ground - ground_width / 2.),
                    (-total_length / 2., y_ground + ground_width / 2.),
                ])
            taper_arm1_n = i3.Boundary(
                layer=i3.TECH.PPLAYER.M1,
                shape=[
                    (-(total_length / 2. + taper_length),
                     y_arm1_p - period_pad + pad_width / 2.),
                    (-(total_length / 2. + taper_length),
                     y_arm1_p - period_pad - pad_width / 2.),
                    (-total_length / 2., y_arm1_n - signal_width / 2.),
                    (-total_length / 2., y_arm1_n + signal_width / 2.),
                ])
            taper_arm1_p = i3.Wedge(
                layer=i3.TECH.PPLAYER.M1,
                begin_coord=(-(total_length / 2. + taper_length), y_arm1_p),
                end_coord=(-total_length / 2., y_arm1_p),
                begin_width=pad_width,
                end_width=arm2_n_width,
            )
            taper_arm2_n = i3.Boundary(
                layer=i3.TECH.PPLAYER.M1,
                shape=[
                    (-(total_length / 2. + taper_length),
                     y_arm1_p + period_pad + pad_width / 2.),
                    (-(total_length / 2. + taper_length),
                     y_arm1_p + period_pad - pad_width / 2.),
                    (-total_length / 2., y_arm2_n - signal_width / 2.),
                    (-total_length / 2., y_arm2_n + signal_width / 2.),
                ])
            taper_arm2_p = i3.Boundary(
                layer=i3.TECH.PPLAYER.M1,
                shape=[
                    (-(total_length / 2. + taper_length),
                     y_arm1_p + 2 * period_pad + pad_width / 2.),
                    (-(total_length / 2. + taper_length),
                     y_arm1_p + 2 * period_pad - pad_width / 2.),
                    (-total_length / 2., y_arm2_p - ground_width / 2.),
                    (-total_length / 2., y_arm2_p + ground_width / 2.),
                ])

            for i in range(-2, 3):
                left_pads += i3.Rectangle(
                    layer=i3.TECH.PPLAYER.M1,
                    center=(
                        -(total_length / 2. + taper_length + pad_length / 2.),
                        y_arm1_p + i * period_pad),
                    box_size=pad_size)

            left_pads += [
                taper_ground, taper_arm1_n, taper_arm1_p, taper_arm2_n,
                taper_arm2_p
            ]

            # Metal right pads
            right_pads = [
                elt.transform_copy(i3.HMirror(0.)) for elt in left_pads
            ]

            elems += lines
            elems += left_pads
            elems += right_pads
            return elems

        def _generate_ports(self, ports):
            # Calling super() to inherit ports from non-connected subblocks (i.e., splitter optical input port and combiner optical output port)
            super(PlaceAndAutoRoute.Layout, self)._generate_ports(ports)

            modulator_length = self.modulator_length
            additional_length = self.additional_length
            pad_length = self.pad_length
            taper_length = self.taper_length
            period_pad = self.period_pad

            y_center_pad = self.delay / 4. - 7.

            for i in range(5):
                ports += i3.ElectricalPort(
                    name='elec_left_{}'.format(i + 1),
                    position=(
                        -((modulator_length + additional_length + pad_length) /
                          2. + taper_length),
                        y_center_pad + (i - 2) * period_pad),
                    layer=i3.TECH.PPLAYER.M1)
                ports += i3.ElectricalPort(
                    name='elec_right_{}'.format(i + 1),
                    position=(
                        (modulator_length + additional_length + pad_length) /
                        2. + taper_length,
                        y_center_pad + (i - 2) * period_pad),
                    layer=i3.TECH.PPLAYER.M1)
            return ports

        def _default_child_transformations(self):
            offset_x = self.modulator_length / 2.
            delta = self.delta
            delay = self.delay

            return {
                'splitter':
                i3.Translation((-(50. + offset_x), 0.)),
                'arm1':
                i3.Translation((-offset_x, -delta + (delay / 2. if
                                                     (delay < 0) else 0.))),
                'arm2':
                i3.Translation((-offset_x, delta + (delay / 2. if
                                                    (delay >= 0) else 0.))),
                'combiner':
                i3.HMirror(0.) + i3.Translation((50. + offset_x, 0.))
            }
Exemple #21
0
    class Layout(i3.LayoutView):

        # Properties -------

        # taper to draw
        taper_prop_dict = i3.DictProperty( default = {}, doc = 'Dictionary of taper cell properties.' + \
                                           'Properties = "length", "width1", "width2", "width_etch" ' )

        # connecting length between tapers
        connect_length = i3.NumberProperty(default=0.0,
                                           doc='distance between tapers')

        # connecting length between taper PAIRS
        pair_connect_length = i3.NumberProperty(
            default=0.0, doc='distance between taper pairs')

        # number of taper pairs
        n_pairs = i3.IntProperty(default=1, doc='number of taper pairs')

        # Methods -------

        def _generate_instances(self, insts):
            # Generates taper pairs

            tp_name_list = []

            for ii in range(self.n_pairs):
                # for each pair

                # draw taper pair layout
                tp_lay = TaperPair(name=self.name + '_tp' +
                                   str(ii)).get_default_view(i3.LayoutView)
                tp_lay.set(taper_prop_dict=self.taper_prop_dict,
                           connect_length=self.connect_length)

                # set name
                tp_name = 'tp' + str(ii)
                tp_name_list.append(tp_name)

                # set transformation
                if ii > 0:

                    # set transform
                    t = i3.vector_match_transform(  tp_lay.ports['left'],
                                                    insts[ tp_name_list[ii - 1] ].ports['right']) \
                                                    + i3.Translation( ( self.pair_connect_length, 0.0 ) )

                    # print t

                    # draw next taper pair
                    insts += i3.SRef(name=tp_name,
                                     reference=tp_lay,
                                     transformation=t)

                    # route wg
                    route_wg = i3.RouteManhattan(
                        input_port=insts[tp_name_list[ii - 1]].ports['right'],
                        output_port=insts[tp_name_list[ii]].ports['left'])

                    # # make my OWN custom waveguide trace template
                    # wg_trace = f_MyIMECWaveguideTemplate( core_width = self.taper_prop_dict['width1'],
                    #                                       cladding_width = self.taper_prop_dict['width1'] + 2.0*self.taper_prop_dict['width_etch'] )

                    # make waveguide
                    wg = i3.Waveguide(trace_template=StripWgTemplate(),
                                      name=self.name + '_WG' + str(ii))

                    # add wg
                    insts += i3.SRef(name=self.name + 'connect_wg' + str(ii),
                                     reference=wg.Layout(shape=route_wg))

                else:
                    # draw first taper pair
                    insts += i3.SRef(name=tp_name, reference=tp_lay)

                    # DEBUG
                    # print insts

                # end if else

            return insts

        # end _generate_instances()

        def _generate_ports(self, ports):
            # add ports 'left' and 'right'

            # left port
            ports += i3.OpticalPort(
                name='left',
                position=self.instances['tp0'].ports['left'].position,
                angle=180.0)

            # right port
            ports += i3.OpticalPort(
                name='right',
                position=self.instances['tp' + str(self.n_pairs -
                                                   1)].ports['right'].position,
                angle=0.0)

            return ports
    class Layout(i3.LayoutView):

        wg_path = i3.NumpyArrayProperty(
            doc="List of coordinates denoting the center path of the waveguide"
        )
        wg_width = i3.NumpyArrayProperty(
            doc=
            "List of waveguide widths normal to the path, specified for each point on the path"
        )
        wg_angles = i3.NumpyArrayProperty(
            doc=
            "Internal Property!: list of waveguide pointing angles at each path point (rads)"
        )
        start_angle = i3.NumberProperty(
            doc=
            "Beginning angle of waveguide for calculating slope (in degrees);"
            "Note this angle points *into* the waveguide so start_angle=0.0 is equivalent"
            "to the wg going east")
        end_angle = i3.NumberProperty(
            doc="End angle of waveguide for calculating slope (in degrees);"
            "Note this angle points *out of* the waveguide so end_angle=0.0 is equivalent"
            "to the waveguide going east")

        def _default_wg_path(self):
            sample_wg_path = np.array(
                [[0.0, 0.0], [5.0, 0.0], [10.0, 0.0], [15.0, 0.0]], np.float_)
            return sample_wg_path

        def _default_wg_width(self):
            width = i3.TECH.WG.CORE_WIDTH
            size = self.wg_path.shape
            length = size[0]
            sample_wg_width = width * np.ones([length], np.float_)
            return sample_wg_width

        def _default_wg_angles(self):
            length, numdim = self.wg_path.shape
            angle = np.zeros([length - 2], np.float_)
            for ii in range(length - 2):
                dy = self.wg_path[ii + 2, 1] - self.wg_path[ii, 1]
                dx = self.wg_path[ii + 2, 0] - self.wg_path[ii, 0]
                angle[ii] = np.arctan2(dy, dx)

            return angle

        def _default_start_angle(self):
            start_angle = int(np.round(self.wg_angles[0] / (np.pi / 2))) * 90.0
            return start_angle

        def _default_end_angle(self):
            size = self.wg_angles.shape
            length = size[0]
            end_angle = int(np.round(self.wg_angles[length - 1] /
                                     (np.pi / 2))) * 90.0
            return end_angle

        def validate_properties(self):
            """Check whether the combination of properties is valid."""
            return True

        def _generate_elements(self, elems):
            # Append start and end angles
            size = self.wg_width.shape
            length = size[0]
            allangles = np.zeros([length], np.float_)
            allangles[0] = self.start_angle * np.pi / 180.0
            allangles[1:(length - 1)] = self.wg_angles
            allangles[length - 1] = self.end_angle * np.pi / 180.0

            # Check block fill layer widths
            import block_layers as bl
            block_layers = bl.layers
            block_widths = bl.widths
            max_width = 0.0
            for ii in range(len(block_widths)):
                if block_widths[ii] > max_width:
                    max_width = block_widths[ii]

            # Create coord list for boundaries
            topcoords = np.zeros([length, 2], np.float_)
            botcoords = np.zeros([length, 2], np.float_)
            topbfillcoords = np.zeros([length, 2], np.float_)
            botbfillcoords = np.zeros([length, 2], np.float_)
            for ii in range(length):
                norm = np.array(
                    [-np.sin(allangles[ii]),
                     np.cos([allangles[ii]])], np.float_)
                topcoords[
                    ii, :] = self.wg_path[ii, :] + self.wg_width[ii] / 2 * norm
                botcoords[
                    ii, :] = self.wg_path[ii, :] - self.wg_width[ii] / 2 * norm
                topbfillcoords[ii, :] = self.wg_path[
                    ii, :] + (self.wg_width[ii] / 2 + max_width) * norm
                botbfillcoords[ii, :] = self.wg_path[
                    ii, :] - (self.wg_width[ii] / 2 + max_width) * norm

            allcoords = np.zeros([2 * length, 2], np.float_)
            allbfillcoords = np.zeros([2 * length, 2], np.float_)
            allcoords[0:length, :] = topcoords
            allbfillcoords[:length, :] = topbfillcoords
            for ii in range(length):
                allcoords[(length + ii), :] = botcoords[length - (ii + 1), :]
                allbfillcoords[(length + ii), :] = botbfillcoords[length -
                                                                  (ii + 1), :]

            wg_coords = []
            fill_coords = []
            for ii in range(2 * length):
                wg_coords.append((allcoords[ii, 0], allcoords[ii, 1]))
                fill_coords.append((allbfillcoords[ii, 0], allbfillcoords[ii,
                                                                          1]))

            wg_shape = i3.Boundary(shape=wg_coords,
                                   layer=i3.TECH.PPLAYER.WG.COR)

            # Add wg shape to core layer
            elems += wg_shape

            # Add block layers
            for ii in range(len(block_layers)):
                fill_shape = i3.Boundary(shape=fill_coords,
                                         layer=block_layers[ii])
                elems += fill_shape

            return elems

        def _generate_ports(self, ports):
            size = self.wg_width.shape
            length = size[0] - 1
            ports += i3.OpticalPort(name="in",
                                    position=(self.wg_path[0, 0],
                                              self.wg_path[0, 1]),
                                    angle=self.start_angle + 180.0,
                                    trace_template=StripWgTemplate().Layout(
                                        core_width=self.wg_width[0]))
            ports += i3.OpticalPort(name="out",
                                    position=(self.wg_path[length, 0],
                                              self.wg_path[length, 1]),
                                    angle=self.end_angle,
                                    trace_template=StripWgTemplate().Layout(
                                        core_width=self.wg_width[length]))
            return ports
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=600, doc="Radius of curvature")
    #spacing =i3.PositiveNumberProperty(default=100, doc="Radius of curvature")
    spacing = i3.PositiveNumberProperty(default=50, doc="Radius of curvature")
    n_loops = i3.NumberProperty(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")
    tlport = i3.PositiveNumberProperty(default=200.0,
                                       doc="Transition legth to ports")
    couplingWG = i3.ChildCellProperty(doc="", locked=True)
    couplingWG_l = i3.PositiveNumberProperty(default=10000.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)
        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 = int(self.n_loops)
            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_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
                a = 10
                b = (self.s_length_vec[-1] - self.s_length_vec[counter]) * 0.1
                #b=0
                print 'b = ', b
                #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=(
                            0.0 - (op[0] - ip[0]) / 2 - self.tlport - a -
                            b,  #-self.chip_length/2-self.couplingWG_l,
                            self.n * counter * sx))
                    d['OutPort' + str(counter)] = i3.Translation(translation=(
                        self.tlport + (op[0] - ip[0]) / 2 + a +
                        b,  #self.chip_length/2,
                        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
                total_length = length + self.R * (
                    1 +
                    3.14159) - self.spacing + 4 * self.n_loops * self.spacing
                print 'total length when inport on top is: ', total_length
                #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width

                #i3.TECH.PPLAYER.NONE.LOGOTXT   when using isipp50g

                elems += i3.PolygonText(
                    layer=i3.TECH.PPLAYER.WG.TEXT,
                    text='Width = {} - Length = {} - R = {}'.format(
                        width, total_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)
                    coordinate=(-(op[0] - ip[0]) / 2 - 1000.0,
                                counter * sx - 100.0),
                    alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                    font=2,
                    height=20.0)
            return elems
    class Layout(i3.LayoutView):
        cell_trap_length = i3.PositiveNumberProperty(default=300.0,
                                                     doc="total length")
        cell_trap_gap = i3.NumberProperty(default=10.0, doc="trap gap")
        cell_trap_gap_length = i3.NumberProperty(default=60.0,
                                                 doc="length of trap section")
        in_angle = i3.NumberProperty(default=85,
                                     doc="internal entry angle of the trap ")
        out_angle = i3.NumberProperty(default=85,
                                      doc="internal exit angle of the trap ")
        radius_fillet = i3.NumberProperty(
            default=3, doc="radius for rounding internal edges/corners")
        '''
        ----------------------------\           /--------------
                        in angle     \         /  outangle
                                      \       /
                                       |_____|        
                                       
                                        _____
                                       |     |
                                      /       \
                        in angle     /         \outangle
        ____________________________/           \------------------  
        '''
        def _generate_elements(self, elems):

            cell_trap_width = self.channel_template.channel_width

            alpha = math.radians(self.in_angle)
            beta = math.radians(self.out_angle)

            point_list = []

            point_list.append(
                (-self.cell_trap_length * 0.25, -cell_trap_width * 0.5))
            point_list.insert(
                0, (-self.cell_trap_length * 0.25, cell_trap_width * 0.5))

            point_list.append(
                (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) -
                 self.cell_trap_gap_length * 0.5, -(cell_trap_width * 0.5)))
            point_list.insert(
                0, (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) -
                    self.cell_trap_gap_length * 0.5, (cell_trap_width * 0.5)))

            point_list.append((-self.cell_trap_gap_length * 0.25,
                               -self.cell_trap_gap * 0.5))  # end of array
            point_list.insert(
                0, (-self.cell_trap_gap_length * 0.25,
                    self.cell_trap_gap * 0.5))  # begging of array, position 0

            point_list.append(
                (self.cell_trap_gap_length * 0.25, -self.cell_trap_gap * 0.5))
            point_list.insert(
                0,
                (self.cell_trap_gap_length * 0.25, self.cell_trap_gap * 0.5))

            point_list.append(
                ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) +
                 self.cell_trap_gap_length * 0.25, -(cell_trap_width * 0.5)))
            point_list.insert(
                0, ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) +
                    self.cell_trap_gap_length * 0.25, (cell_trap_width * 0.5)))

            point_list.append(
                (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5,
                 -cell_trap_width * 0.5))
            point_list.insert(
                0,
                (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5,
                 cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)

            rectang = i3.ShapeRound(original_shape=t,
                                    start_face_angle=0,
                                    end_face_angle=0,
                                    radius=self.radius_fillet)
            bo = i3.Boundary(self.channel_template.layer, rectang)
            #insts += bo  #comm/uncomm for debugging round stl

            #creating an inlet rectangle boundary to avoid round corners
            point_list = []
            #w = 3
            point_list.append(
                (-self.cell_trap_length * 0.5, -cell_trap_width * 0.5))
            point_list.insert(
                0, (-self.cell_trap_length * 0.5, cell_trap_width * 0.5))

            point_list.append(
                (-self.cell_trap_length * 0.25 + self.radius_fillet,
                 -cell_trap_width * 0.5))
            point_list.insert(0, (-self.cell_trap_length * 0.25 +
                                  self.radius_fillet, cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo1 = i3.Boundary(self.channel_template.layer, t)

            #creating an outlet rectangle boundary to avoid round corners
            point_list = []
            point_list.append(
                (self.cell_trap_length * 0.25 - self.radius_fillet,
                 -cell_trap_width * 0.5))
            point_list.insert(0, (self.cell_trap_length * 0.25 -
                                  self.radius_fillet, cell_trap_width * 0.5))

            point_list.append(
                (self.cell_trap_length * 0.5, -cell_trap_width * 0.5))
            point_list.insert(0,
                              (-self.cell_trap_length * 0.5 +
                               self.cell_trap_length, cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo2 = i3.Boundary(self.channel_template.layer, t)

            #boolean operation adding main geometry and inlet rectangle
            b_add = bo1 | bo

            #boolean operation adding main geometry and outlet rectangle
            b_add2 = bo2 | b_add[0]
            elems += b_add2
            return elems

        def _generate_ports(self, ports):

            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(-self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.channel_template)

            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.channel_template)

            return ports
    class Layout(CellTrapSimple.Layout):
        '''
        ----------------------------\           /--------------
                        in angle     \         /  outangle
                                      \       /
                                       |_____|

                         |-funnel length-| _____
                                         .     .
                                        .       .
                                      .           .
                                    .               .
                                 .                    .
        _____________________.                          .__________
                ###UNDER CONSTRUCTION

        '''

        funnel_length = i3.NumberProperty(default=100.0,
                                          doc="Francisoc: What is this?")

        def _generate_elements(self, elems):
            cell_trap_width = self.channel_template.channel_width
            entry_Lfd = self.cell_trap_length * 0.5  # 1000.0
            exit_Lfd = self.cell_trap_length * 0.5  # 500.0
            beta = math.radians(self.out_angle)

            lf = self.funnel_length
            wi = cell_trap_width
            wf = self.cell_trap_gap
            #lfd = 0

            taper_samples = 200
            a = lf / (wi / wf - 1.0)

            dx = lf / taper_samples
            x = 0.0
            xl = []
            wl = []

            point_list = []
            x_offset = self.funnel_length + self.cell_trap_gap_length  # all expansion will be at 0.0x
            a = 0.5
            b = .35
            point_list.append(
                self.cInp +
                (-(self.cell_trap_length * b), wi * 0.5))  # end of array
            point_list.insert(0, self.cInp +
                              (-(self.cell_trap_length * b),
                               -wi * 0.5))  # begging of array, position 0

            for i in reversed(range(1, taper_samples + 1)):
                #xa = lf * math.exp(10.0 * (i / taper_samples - 1.0))  #discretization
                radius = 0.5 * wi  ### this needs to be improved
                xa = (radius) * math.cos(0.5 * math.pi * i / taper_samples)
                #w = wi / (1.0 + xa / a)    #function value
                w = (radius) * math.sin(0.5 * math.pi * i / taper_samples)
                p = (xa - radius - self.cell_trap_gap_length * 0.5,
                     0.5 * (w + 0.5 * wi))
                point_list.append(self.cInp + p)
                p = (xa - radius - self.cell_trap_gap_length * 0.5,
                     -0.5 * (w + 0.5 * wi))
                point_list.insert(0, self.cInp + p)

            # GAP LENGTH
            p = (
                point_list[-1][0], wf * 0.5
            )  #wGet last point, coordX use it for next point with wf as coordY
            point_list.append(self.cInp +
                              p)  # Insert it at the bottom of point_list
            p = point_list[-1] + (0.0, (-wf))  # Get last point, add -wf
            point_list.insert(0, self.cInp +
                              p)  # Insert it at the bottom of point_list

            p = point_list[-1] + (self.cell_trap_gap_length, 0.0
                                  )  # Get last point and add length
            point_list.append(self.cInp +
                              p)  # Insert it at [0] in the point_list

            p = point_list[-1] + (0.0, -wf)  # Get last point and add length
            point_list.insert(0, self.cInp +
                              p)  # Insert it at [0] in the point_list

            # EXIT ANGLE
            p = point_list[-1] + (
                0.5 * (cell_trap_width - self.cell_trap_gap) / math.tan(beta),
                -cell_trap_width * 0.5 - wf * .50
            )  # Get last point and add length of angle
            point_list.insert(0, self.cInp +
                              p)  # Insert it at [0] in the point_list

            p = point_list[0] + (0, wi)
            point_list.append(self.cInp +
                              p)  # Insert it at the bottom of point_list

            # EXIT LENGTH
            p = (self.cell_trap_length * b, point_list[-1][1]
                 )  # get first point (last point added) and add length
            point_list.append(self.cInp + p)

            p = point_list[-1] + (0, -wi)  ##get last point and add length
            point_list.insert(0, self.cInp + p)

            t = i3.Shape(point_list, closed=True)

            rectang = i3.ShapeRound(original_shape=t,
                                    start_face_angle=0,
                                    end_face_angle=0,
                                    radius=self.radius_fillet)
            bo = i3.Boundary(self.channel_template.layer, rectang)

            #creating an inlet rectangle boundary to avoid round corners
            point_list = []
            point_list.append(
                (-self.cell_trap_length * a, -cell_trap_width * 0.5))
            point_list.insert(
                0, (-self.cell_trap_length * a, cell_trap_width * 0.5))

            point_list.append((-self.cell_trap_length * b + self.radius_fillet,
                               -cell_trap_width * 0.5))
            point_list.insert(0,
                              (-self.cell_trap_length * b + self.radius_fillet,
                               cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo1 = i3.Boundary(self.channel_template.layer, t)

            #creating an outlet rectangle boundary to avoid round corners
            point_list = []
            point_list.append((self.cell_trap_length * b - self.radius_fillet,
                               -cell_trap_width * 0.5))
            point_list.insert(0,
                              (self.cell_trap_length * b - self.radius_fillet,
                               cell_trap_width * 0.5))

            point_list.append(
                (self.cell_trap_length * a, -cell_trap_width * 0.5))
            point_list.insert(
                0, (self.cell_trap_length * a, cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo2 = i3.Boundary(self.channel_template.layer, t)

            #boolean operation adding main geometry and inlet rectangle
            b_add = bo | bo1

            #boolean operation adding main geometry and outlet rectangle
            b_add2 = b_add[0] | bo2
            #s2 = i3.Structure(elements=b_add2)
            elems += b_add2
            #insts += bo
            return elems

        def _generate_ports(self, ports):

            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(-self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                #angle_deg=0,
                trace_template=self.channel_template)

            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                #angle_deg=0,
                trace_template=self.channel_template)

            return ports
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 CircuitOfBlocks(microfluidics.PlaceAndAutoRoute):
    """Parametric cell with several traps, which are stacked vertically (Parallel) or horizontally (Series)
    """
    #_name_prefix = "circuitOfTraps"
    type = i3.NumberProperty(default=0)  #  0 Paralell 1 Series
    block_distance = i3.NumberProperty(default=400.)  #distance betwn traps
    block_with_tee = i3.ChildCellListProperty(
    )  #  Generating traps with Tee from Child Cell List Property
    trace_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate())
    n_blocks_x = i3.PositiveIntProperty(default=30)
    n_blocks_y = i3.PositiveIntProperty(default=30)
    x_footprint = i3.PositiveIntProperty(default=1000)
    y_footprint = i3.PositiveIntProperty(default=1000)

    def _default_child_cells(self):
        return {
            "blk_w_tee{}".format(cnt): self.block_with_tee[cnt]
            for cnt in range(self.n_blocks_x * self.n_blocks_y)
        }

    def _default_links(self):
        links = []
        bx = self.n_blocks_x

        ########################
        #############   PARALLEL
        if self.type == 0:
            for cntx in range(0, self.n_blocks_x):
                # self connection at the top -bypass
                top = self.n_blocks_y * self.n_blocks_x - self.n_blocks_x + cntx
                links.append(("blk_w_tee{}:in2".format(top),
                              "blk_w_tee{}:out2".format(top)))
                # connecting bottom to top
                for cnty in range(0, self.n_blocks_y - 1):
                    links.append(
                        ("blk_w_tee{}:in2".format(cnty * bx + cntx),
                         "blk_w_tee{}:in1".format((cnty + 1) * bx + cntx)))
                    links.append(
                        ("blk_w_tee{}:out2".format(cnty * bx + cntx),
                         "blk_w_tee{}:out1".format((cnty + 1) * bx + cntx)))

            #interconnecting horizontally
            if self.n_blocks_x > 1:
                for cntd in range(0, self.n_blocks_x - 1):
                    links.append(("blk_w_tee{}:out1".format(cntd),
                                  "blk_w_tee{}:in1".format(cntd + 1)))
        ########  END PARALLEL #################

        ########################
        #############   SERIES
        if self.type == 1:  # series
            #all by-pass, each object
            for cnt in range(0,
                             self.n_blocks_y * self.n_blocks_x):  #all bypass
                links.append(("blk_w_tee{}:in2".format(cnt),
                              "blk_w_tee{}:out2".format(cnt)))

            #all interconnecting horizontally
            if self.n_blocks_x > 1:
                for cnty in range(0, self.n_blocks_y):
                    for cntd in range(0, (self.n_blocks_x - 1)):
                        links.append(
                            ("blk_w_tee{}:out1".format(cnty * bx + cntd),
                             "blk_w_tee{}:in1".format(cnty * bx + cntd + 1)))

            #left connections
            for cntd in range(1, (self.n_blocks_y - 1), 2):
                #links.append(("blk_w_tee{}:in1".format(cntd * bx), "blk_w_tee{}:in1".format((cntd+1) * bx)))
                links.append(("blk_w_tee{}:in1".format(
                    (cntd + 1) * bx), "blk_w_tee{}:in1".format(cntd * bx)))

            #right connections
            for cntd in range(1, (self.n_blocks_y), 2):
                links.append(("blk_w_tee{}:out1".format(cntd * bx - 1),
                              "blk_w_tee{}:out1".format((cntd + 1) * bx - 1)))

        ########  END SERIES #################

        return links

    def _default_block_with_tee(
            self):  # Generating traps from Child Cell List Property
        tee1 = TeeSimple()
        tee1.Layout(tee_length=(200.0))
        my_block = CellTrapSimple()
        my_block.Layout(cell_trap_length=300.0)
        return [
            TrapWithTees(
                name="blk_w_tee_{}".format(cnt),
                trap=my_block,
                tee=tee1,
            ) for cnt in range(self.n_blocks_x * self.n_blocks_y)
        ]

    class Layout(microfluidics.PlaceAndAutoRoute.Layout):
        def _default_child_transformations(self):

            # generate grid
            x = np.linspace(0, self.cell.x_footprint, self.cell.n_blocks_x)
            y = np.linspace(0, self.cell.y_footprint, self.cell.n_blocks_y)

            # generate positions
            from functions.position_coordinates import generate_positions
            coords = generate_positions(x, y, self.type)

            return {
                "blk_w_tee{}".format(cnt): i3.Translation(coords[cnt])
                for cnt in range(self.n_blocks_x * self.n_blocks_y)
            }

        def _generate_ports(self, ports):
            # Add ports
            if self.type == 0:
                ports += i3.expose_ports(
                    self.instances, {
                        'blk_w_tee0:in1': 'in1',
                        'blk_w_tee{}:out1'.format(self.n_blocks_x - 1): 'out1'
                    })

            if self.type == 1:
                if self.n_blocks_y % 2 == 0:
                    ports += i3.expose_ports(
                        self.instances,
                        {
                            'blk_w_tee0:in1':
                            'in1',
                            'blk_w_tee{}:in1'.format(self.n_blocks_x * self.n_blocks_y - self.n_blocks_x):
                            'out1'  # last left
                        })
                else:
                    ports += i3.expose_ports(
                        self.instances,
                        {
                            'blk_w_tee0:in1':
                            'in1',
                            'blk_w_tee{}:out1'.format(self.n_blocks_x * self.n_blocks_y - 1):
                            'out1'  # last right
                        })

            return ports
Exemple #29
0
class Lspiral(PlaceAndAutoRoute):
    rectV_list = i3.ChildCellListProperty(default=[])
    rectH_list = i3.ChildCellListProperty(default=[])
    gap_inc_vec = i3.ListProperty(default=[], doc="Length of MMI")
    gap_inc_vec2 = i3.ListProperty(default=[], doc="length of 12mmi")
    WG1 = i3.ChildCellProperty(doc="", locked=True)
    WG2 = i3.ChildCellProperty()
    wg_t1 = i3.WaveguideTemplateProperty(doc="board WG")
    wg_t2 = i3.WaveguideTemplateProperty(doc="change WG")
    # mmi_trace_template = i3.WaveguideTemplateProperty()
    # mmi_access_template = i3.WaveguideTemplateProperty()
    width = i3.PositiveNumberProperty(doc="width of ports", default=15)
    # cleave = i3.PositiveNumberProperty(doc="tolerance", default=150)
    offset = i3.NumberProperty(doc="count", default=0)

    def _default_wg_t1(self):
        wg_t1 = WireWaveguideTemplate(name="port20")
        wg_t1.Layout(
            core_width=20,
            cladding_width=20 + 2 * 12.0,
        )
        return wg_t1

    def _default_wg_t2(self):
        wg_t2 = WireWaveguideTemplate(
            name="port_{}_{}".format(str(self.width), str(self.offset)))
        wg_t2.Layout(
            core_width=self.width,
            cladding_width=self.width + 2 * 12.0,
        )
        return wg_t2

    def _default_trace_template(self):
        wg_sm = WireWaveguideTemplate(name="sm_template")
        wg_sm.Layout(core_width=3.8, cladding_width=3.8 + 2 * 12.0)
        return wg_sm

    def _default_WG1(self):
        WG1 = i3.Waveguide(name="straight{}".format(str(self.width)),
                           trace_template=self.wg_t1)
        WG1.Layout(shape=[(-200.0, 0.0), (600.0, 0.0)])
        return WG1

    def _default_WG2(self):
        Port = AutoTransitionPorts(name="ports{}".format(str(self.width)),
                                   contents=self.WG1,
                                   port_labels=["out"],
                                   trace_template=self.wg_t2)
        Port.Layout(transition_length=300)  # .visualize(annotate=True)
        return Port

    # def _default_mmi_trace_template(self):
    #     mmi_trace_template = WireWaveguideTemplate(name="MMI_tt")
    #     mmi_trace_template.Layout(core_width=20.0, cladding_width=20.0 + 2 * 12)  # MMI_width
    #     return mmi_trace_template
    #
    # def _default_mmi_access_template(self):
    #     mmi_access_template = WireWaveguideTemplate(name="MMI_at")
    #     mmi_access_template.Layout(core_width=9.0, cladding_width=9.0 + 2 * 12)
    #     return mmi_access_template

    def _default_rectH_list(self):

        MMI22_list = []
        for l in range(0, 5, 1):

            cell = i3.Waveguide(name="rectH{}_{}".format(
                str(l), str(self.offset)),
                                trace_template=self.wg_t2)
            cell.Layout(shape=[(0.0, 0.0), (17000 - 4000 * l, 0.0)])
            # cell = i3.Waveguide(name="rectV{}".format(str(l)),
            #                     trace_template=self.wg_t2)
            # cell.Layout(shape=[(18000 - 4000 * l, 0.0), (0.0, 0.0)])

            MMI22_list.append(cell)

        return MMI22_list

    def _default_rectV_list(self):
        print '____________ MMI 2x2 ______________'
        MMI22_list2 = []
        for l in range(0, 5, 1):

            # cell = i3.Waveguide(name="rectH{}".format(str(l)),
            #                    trace_template=self.wg_t2)
            # cell.Layout(shape=[(0.0, 0.0), (18000-4000*l, 0.0)])
            cell = i3.Waveguide(name="rectV{}_{}".format(
                str(l), str(self.offset)),
                                trace_template=self.wg_t2)
            cell.Layout(shape=[(0.0, 0.0), (0.0, -1000 - 4000 * l)])

            MMI22_list2.append(cell)

        return MMI22_list2

    def _default_child_cells(self):
        child_cells = dict()
        for counter in range(0, 5, 1):
            print counter
            # child_cells['straight' + str(counter)] = self.WG1
            child_cells['taperH' + str(counter)] = self.WG2
            child_cells['taperV' + str(counter)] = self.WG2

        for counter, child in enumerate(self.rectH_list):
            print 'child number' + str(counter)
            child_cells['recH' + str(counter)] = child
            print 'child name ' + str(child.name)

        for counter, child in enumerate(self.rectV_list):
            print 'child number' + str(counter)
            child_cells['recV' + str(counter)] = child
            print 'child name ' + str(child.name)

        return child_cells

    def _default_links(self):
        links = [
            ("recH0:out", "recV4:out"),
            ("recH1:out", "recV3:out"),
            ("recH2:out", "recV2:out"),
            ("recH3:out", "recV1:out"),
            ("recH4:out", "recV0:out"),
        ]
        return links

    class Layout(PlaceAndAutoRoute.Layout):
        def _default_child_transformations(self):
            trans = dict()
            column = 4000
            # trans['ring0'] = (600, 0)
            # trans['ring1'] = (600, 1 * column)
            # trans['ring2'] = (600, 2 * column)
            # # trans['ring3'] = (1300, 8000 + 2 * column )

            for i in range(0, 5, 1):
                trans["taperH{}".format(i)] = (0,
                                               column * i + 100 * self.offset)
                trans["taperV{}".format(i)] = i3.Rotation(
                    rotation=-90) + i3.Translation(
                        (4000 + column * i - 100 * self.offset, 20000))
                trans["recH{}".format(i)] = (900,
                                             column * i + 100 * self.offset)
                trans["recV{}".format(i)] = (4000 + column * i -
                                             100 * self.offset, 20000 - 900)
            # trans["taper0"] = (0, 0)
            # trans["taper1"] = i3.HMirror(0) + i3.Translation((2500, -1500))
            # trans["taper2"] = i3.HMirror(0) + i3.Translation((2500, 1500))
            #
            # trans["taper3"] = (0, 1 * column)
            # trans["taper4"] = i3.HMirror(0) + i3.Translation((2500, -1500 + 1 * column))
            #
            # trans["taper5"] = i3.HMirror(0) + i3.Translation((2500, 1500 + 1 * column))
            #
            # trans["taper6"] = (0, 2 * column)
            # trans["taper7"] = i3.HMirror(0) + i3.Translation((2500, -1500 + 2 * column))
            # trans["taper8"] = i3.HMirror(0) + i3.Translation((2500, 1500 + 2 * column))
            #
            # trans["taper9"] = (0, 3800 + 2 * column)
            #
            # trans["taper10"] = i3.HMirror(0) + i3.Translation((2500, -1500 + 3 * column))
            # # trans["taper11"] = i3.HMirror(0) + i3.Translation((3000, 6500+ 2 * column))
            # # trans["taper12"] = i3.HMirror(0) + i3.Translation((3000, 9500+ 2 * column))

            return trans

        def _default_bend_radius(self):
            bend_radius = 500
            return bend_radius

        def _generate_elements(self, elems):

            for i in range(0, 5, 1):
                elems += i3.PolygonText(
                    layer=i3.TECH.PPLAYER.WG.TEXT,
                    text="WITDH={}_length={}*2_R=500".format(
                        str(self.width), 17000 - 4000 * i),
                    coordinate=(900, 55 + 4000 * i + 100 * self.offset),
                    font=2,
                    height=20.0,
                )
                for j in range(0, 13, 1):
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text="{}_{}".format(str(i), str(j)),
                        coordinate=(550, 63 + 4000 * i + 100 * j),
                        font=2,
                        height=30.0,
                    )
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text="{}_{}".format(str(i), str(j)),
                        # coordinate=(),
                        font=2,
                        height=30.0,
                        transformation=i3.Rotation(rotation=-90) +
                        i3.Translation(
                            (20000 - 4000 * i - 100 * j + 63, 20000 - 550)),
                    )
            for i in range(0, 6, 1):
                elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                      center=(100, 4000 * i - 1000 + 700),
                                      box_size=(100, 100))
                elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                      center=(300, 4000 * i - 1000 + 700),
                                      box_size=(100, 100))
                elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                      center=(4000 * i + 300, 19700),
                                      box_size=(100, 100))
                elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                      center=(4000 * i + 300, 19900),
                                      box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(100, 19900),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(-100, 19900),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(500, 19900),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(100, 19500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(100, 20100),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(-100, -500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(100, -500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(300, -500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(500, -500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(20500, 19500),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(20500, 19700),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(20500, 19900),
                                  box_size=(100, 100))
            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.WG.TEXT,
                                  center=(20500, 20100),
                                  box_size=(100, 100))

            return elems