Esempio n. 1
0
class Spirals(PlaceAndAutoRoute):

    _name_prefix = 'LSpiral'

    tipo = i3.PositiveNumberProperty(doc="Number loops", default=1)

    waveguide_template = i3.DefinitionProperty(doc="Trace template used")
    R = i3.PositiveNumberProperty(default=200, doc="Radius of curvature")
    spacing = i3.PositiveNumberProperty(default=100, doc="Radius of curvature")
    n_loops = i3.IntProperty(doc="Number loops", default=2)
    n_loops_vec = i3.ListProperty(default=[4, 8])
    s_length_vec = i3.ListProperty(default=[0.0])
    Spiral_list = i3.ChildCellListProperty(
        doc="List containing the 90 degree angle child cells")
    #chip_length = i3.PositiveNumberProperty(default=2500.0, doc="Radius of curvature")
    chip_length = i3.PositiveNumberProperty(default=3000.0,
                                            doc="Radius of curvature")
    Port = i3.ChildCellProperty(doc="Used for ports")
    Port2 = i3.ChildCellProperty(doc="Used for ports")
    tlport = i3.PositiveNumberProperty(default=1000.0,
                                       doc="Transition legth to ports")
    couplingWG = i3.ChildCellProperty(doc="", locked=True)
    couplingWG_l = i3.PositiveNumberProperty(default=5000.0,
                                             doc="Length of the coupling WG ")
    tt_port = i3.TraceTemplateProperty(
        doc="Wide trace template used for the contacts")
    tt_port2 = i3.TraceTemplateProperty(
        doc="Wide trace template used for the contacts")

    #width_vec = i3.ListProperty(default=[1])
    n = i3.PositiveNumberProperty(default=1, doc="")
    width = i3.PositiveNumberProperty(default=1, doc="")
    lengths = i3.PositiveNumberProperty(default=1, doc="")

    def _default_lengths(self):
        for counter, cell in enumerate(self.s_length_vec):
            numero = counter + 1
        return numero

    #template for Autorute
    def _default_trace_template(self):
        return self.waveguide_template

    def _default_tt(self):
        return self.waveguide_template

    def _default_tt_port(self):
        tt_port = WireWaveguideTemplate()
        tt_port_layout = tt_port.Layout(core_width=10.0, cladding_width=10.0)
        return tt_port

    def _default_tt_port2(self):
        tt_port = WireWaveguideTemplate()
        tt_port_layout = tt_port.Layout(core_width=10.0, cladding_width=10.0)
        return tt_port

    def _default_Spiral_list(self):
        Spiral_list = []  # empty list
        print ' I am in _Spiral_list'
        for l, length in enumerate(self.s_length_vec):
            loops = 1
            print length

            cell = FixedLengthSpiralRounded(
                trace_template=self.waveguide_template,
                #total_length=length-self.chip_length,
                total_length=length,
                n_o_loops=loops,
                name=self.name + '_Spiral_' + str(l))

            cell.Layout(
                incoupling_length=0,
                bend_radius=self.R,
                spacing=self.spacing,
                stub_direction="H",
                growth_direction="H",
            )  #.visualize(annotate=True)
            print 'The legth of the spiral is: ', cell.total_length
            print 'Cell: ', cell.name

            Spiral_list.append(cell)

        return Spiral_list

    def _default_couplingWG(self):
        rect = i3.Waveguide(trace_template=self.tt_port)
        layout_rect = rect.Layout(shape=[(0.0, 0.0), (self.couplingWG_l, 0.0)])
        return rect

    def _default_Port(self):
        Port = AutoTransitionPorts(contents=self.couplingWG,
                                   port_labels=["in"],
                                   trace_template=self.waveguide_template)
        layout_Port = Port.Layout(
            transition_length=self.tlport)  #.visualize(annotate=True)
        return Port

    def _default_Port2(self):
        Port = AutoTransitionPorts(contents=self.couplingWG,
                                   port_labels=["in"],
                                   trace_template=self.waveguide_template)
        layout_Port = Port.Layout(
            transition_length=self.tlport)  #.visualize(annotate=True)
        return Port

    def _default_child_cells(self):
        child_cells = {
        }  # First we define the property "child_cells" as  an empty dictionary

        for counter, spiral in enumerate(
                self.Spiral_list
        ):  # the iteration starts in the first element of the list and follows element by element to the last element.

            child_cells['Spiral{}'.format(counter)] = spiral
            print spiral
            print 'name of spiral:', spiral.name
            child_cells['InPort' + str(counter)] = self.Port
            child_cells['OutPort' + str(counter)] = self.Port

            print 'child_cells:', child_cells
        return child_cells

    def _default_links(self):
        links = []
        for counter, spiral in enumerate(self.Spiral_list):
            print counter
            in_port = "Spiral{}:in".format(counter)
            out_port = "InPort{}:in".format(counter)
            links.append((in_port, out_port))
            in_port = "Spiral{}:out".format(counter)
            out_port = "OutPort{}:in".format(counter)
            links.append((in_port, out_port))

        return links

    class Layout(PlaceAndAutoRoute.Layout):
        #tipo=1

        def _default_bend_radius(self):
            return self.R

        def _default_child_transformations(self):
            d = {}
            for counter, child in enumerate(self.Spiral_list):
                ip = child.ports["in"].position
                #print self.child_cells['InPort' + str(counter)].ports["out"].position
                #print self.child_cells['OutPort' + str(counter)].ports.position
                print '----------------'
                print 'spiral length:', child.total_length
                print 'counter: ', counter
                #print ip
                op = child.ports["out"].position
                #print op

                print 'The lateral size of the spiral is', op[0] - ip[0]
                print 'The type of mask is: ', self.tipo
                print 'The number of widths is: ', self.n
                print 'The number of lengths is: ', self.lengths
                print 'The width number is: ', self.width
                print '----------------'
                iz = child.inner_size
                sx = iz[1] + 200
                #sx=1200
                if self.tipo == 1:

                    d['Spiral' + str(counter)] = i3.Translation(
                        translation=(-(op[0] - ip[0]) / 2,
                                     self.n * counter * sx))
                    d['InPort' + str(counter)] = i3.HMirror() + i3.Translation(
                        translation=(-self.chip_length / 2.0 -
                                     self.couplingWG_l, self.n * counter * sx))
                    d['OutPort' + str(counter)] = i3.Translation(
                        translation=(self.chip_length / 2.0 +
                                     self.couplingWG_l, self.n * counter * sx))
                if self.tipo == 2:
                    d['Spiral' + str(counter)] = i3.Translation(
                        translation=(-(op[0] - ip[0]) / 2,
                                     -(self.n + 0.5) * counter * sx))
                    #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4)-self.couplingWG_l, -(self.n+0.5)*counter*sx))
                    #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R+(((self.n+0.5)*counter+self.width)*sx/4), self.chip_length*(3/4)+(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx))
                    d['InPort' + str(counter)] = i3.HMirror() + i3.Translation(
                        translation=(-self.chip_length * (1 / 2) - 2000,
                                     -(self.n + 0.5) * counter * sx))
                    d['OutPort' + str(counter)] = i3.Rotation(
                        rotation=90) + i3.Translation(translation=(
                            (op[0] - ip[0]) / 2 + 2 * self.R +
                            (((self.n + 0.5) * counter + self.width) * sx / 4),
                            3000 + self.chip_length * (3 / 4) +
                            (self.width + counter -
                             (((counter + 1) - 1.0) % self.lengths)) * sx))
                #For awg's
                #if self.tipo==2:
                #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+0.5)*counter*sx))
                #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4.0), -(self.n+0.5)*counter*sx))
                #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R
                #+(((self.n+0.5)*counter+self.width)*sx/100.0)
                #, self.chip_length*(2/4.0)+
                #(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx))
            return d

        # Fabio's addition
        def _generate_elements(self, elems):
            # We calculate the lengths of the 2 spirals in this pcell.
            # Note that we assume that there are exactly 2 spirals in this list.
            #assert len(self.Spiral_list) == 2
            lengths = get_lengths(self)
            iz = self.Spiral_list[0].inner_size
            sx = iz[1] + 200
            for counter, (child,
                          length) in enumerate(zip(self.Spiral_list, lengths)):
                ip = child.ports["in"].position
                op = child.ports["out"].position
                width = child.ports["in"].trace_template.core_width
                #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width

                #i3.TECH.PPLAYER.NONE.LOGOTXT   when using isipp50g
                if self.tipo == 2:
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}_Length={}_R={}'.format(
                            width, length, self.R),
                        coordinate=((op[0] - ip[0]) / 2 - 1000.0,
                                    (self.n + 0.5) * counter * sx - 50.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)
                if self.tipo == 1:
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}_Length={}_R={}'.format(
                            width, length, self.R),
                        coordinate=(-(op[0] - ip[0]) / 2 - 1000.0,
                                    -(self.n + 0.5) * counter * sx - 50.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)
            return elems
    class Layout(i3.LayoutView):
        # specified parameters used for layout, lengths of various waveguides
        # using some default values if standard ring shape is used
        bend_radius_ring = i3.PositiveNumberProperty(default=10.,
                                                     doc="bend radius of ring")
        ring_x_straight = i3.PositiveNumberProperty(
            default=15., doc="straight between bends in x ring")
        ring_y_straight = i3.PositiveNumberProperty(
            default=25., doc="straight between bends in y ring")
        external_straights = i3.PositiveNumberProperty(
            default=10., doc="extra straight for outside structure")
        external_gap = i3.PositiveNumberProperty(
            default=0.5, doc="gap between outside waveguides and resonator")
        # external_radius = i3.PositiveNumberProperty(default=bend_radius_ring, doc="radius of outside coupler")
        use_rounding = i3.BoolProperty(default=False,
                                       doc="use non default bending algorithm")
        rounding_algorithm = i3.DefinitionProperty(
            default=SplineRoundingAlgorithm(),
            doc="secondary rounding algorithm")

        # define the layout of the internal coupler which we SRef below
        def _default_resonator(self):
            res_layout = self.cell.resonator.get_default_view(
                i3.LayoutView)  # Retrieve layout view following example

            # make the shape of the layout from the previous values. Assume (0, 0) is bottom middle!)
            # will do each corner for clarity
            # bottom_left = (-self.bend_radius_ring - self.ring_x_straight/2., 0.)
            # top_left = (-self.bend_radius_ring - self.ring_x_straight/2.,
            #             self.bend_radius_ring*2. + self.ring_y_straight)
            # top_right = (self.bend_radius_ring + self.ring_x_straight/2.,
            #              self.bend_radius_ring*2. + self.ring_y_straight)
            # bottom_right = (self.bend_radius_ring + self.ring_x_straight/2., 0.)
            # ring_shape = [bottom_left, top_left, top_right, bottom_right, bottom_left]
            # print ring_shape

            # tried to use generic round ring, but failed :P. Using ring rect instead
            # set the layout of the resonator. Stuck a bool for non default rounding algorithm
            if self.use_rounding is True:
                res_layout.set(bend_radius=self.bend_radius_ring,
                               straights=(self.ring_x_straight,
                                          self.ring_y_straight),
                               rounding_algorithm=self.rounding_algorithm)
            else:
                res_layout.set(
                    bend_radius=self.bend_radius_ring,
                    straights=(self.ring_x_straight,
                               self.ring_y_straight))  # , shape=ring_shape
            return res_layout

        # now we take the resonator which was just defined and stick it in the main *get components thing
        def _get_components(self):
            resonator = i3.SRef(name="another_res", reference=self.resonator)
            return resonator

        # setting the output shape of the access waveguides using a shape defined by ports from MMI (hopefully..)
        def _default_wgs(self):
            # bring in parts from rest of PCell Layout, used to grab positions
            resonator = self._get_components()
            wg_in_cell, wg_pass_cell = self.cell.wgs
            wg_template = self.wg_coupler_template
            wg_ring_template = self.wg_ring_template

            # using the ring radius for the external radius
            external_rad = self.bend_radius_ring
            external_str = self.external_straights

            # grabbing the position of the resonator to layout the rest of the coupler properly
            resonator_west_side = resonator.size_info().west
            resonator_south_side = resonator.size_info().south

            resonator_core_width = wg_ring_template.core_width
            resonator_clad_width = wg_ring_template.cladding_width
            coupler_core_width = wg_template.core_width

            # calculate the x position for center of input coupling waveguide when coupling, and make shape
            x_coup_spot = resonator_west_side + resonator_clad_width/2. - resonator_core_width/2. - self.external_gap \
                - coupler_core_width/2.

            # get bottom using the south and cladding information again
            bottom_left = (x_coup_spot - external_str - external_rad,
                           resonator_south_side + resonator_clad_width / 2.)
            bottom_right = (x_coup_spot,
                            resonator_south_side + resonator_clad_width / 2.)
            top_right = (x_coup_spot, bottom_right[1] + 2. * external_rad +
                         self.ring_y_straight)
            top_left = (bottom_left[0], top_right[1])

            wg_shape = [bottom_left, bottom_right, top_right, top_left]

            # now make the instance using this shape info
            wg_in_layout = wg_in_cell.get_default_view(i3.LayoutView)
            if self.use_rounding is True:
                wg_in_layout.set(trace_template=wg_template,
                                 shape=wg_shape,
                                 bend_radius=external_rad,
                                 rounding_algorithm=self.rounding_algorithm)
            else:
                wg_in_layout.set(trace_template=wg_template,
                                 shape=wg_shape,
                                 bend_radius=external_rad)

            wg_pass_layout = wg_pass_cell.get_default_view(i3.LayoutView)
            # wg_in_layout.set()
            return wg_in_layout, wg_pass_layout  # wg_ring_layout

        # A few functions for grabbing waveguide parameters to determine lengths for FSR checking
        # def wg_lengths(self):
        #     # grab the lengths of internal waveguides to use for calculations later
        #     wg_in_layout, wg_pass_layout, wg_ring_layout = self.wgs
        #
        #     straights_and_bends = wg_ring_layout.trace_length()
        #     return straights_and_bends

        def _generate_instances(self, insts):
            # includes the get components and the new waveguides
            insts += self._get_components()
            wg_in_layout, wg_pass_layout = self.wgs  #  wg_pass_layout, wg_ring_layout

            insts += i3.SRef(reference=wg_in_layout, name="wg_in")
            # insts += i3.SRef(reference=wg_pass_layout, name="wg_pass")
            # insts += i3.SRef(reference=wg_ring_layout, name="wg_ring")
            return insts

        def _generate_ports(self, prts):
            # try to reuse the output waveguides following the example and change the names, looks good
            instances = self.instances
            prts += instances["wg_in"].ports["in"].modified_copy(name="in")
            prts += instances["wg_in"].ports["out"].modified_copy(name="pass")
            return prts
Esempio n. 3
0
class Spirals(PlaceAndAutoRoute):

    _name_prefix = 'LSpiral'

    tipo = i3.PositiveNumberProperty(doc="Number loops", default=1)

    waveguide_template = i3.DefinitionProperty(doc="Trace template used")
    R = i3.PositiveNumberProperty(default=500, doc="Radius of curvature")
    spacing = i3.PositiveNumberProperty(default=100, doc="Radius of curvature")
    n_loops = i3.IntProperty(doc="Number loops", default=2)
    n_loops_vec = i3.ListProperty(default=[4, 8])
    s_length_vec = i3.ListProperty(default=[0.0])
    #Spiral_list = i3.ChildCellListProperty(doc="List containing the 90 degree angle child cells")
    #chip_length = i3.PositiveNumberProperty(default=12000.0, doc="")
    chip_length = i3.PositiveNumberProperty(default=13000.0, doc="")
    Port = i3.ChildCellProperty(doc="Used for ports")
    tlport = i3.PositiveNumberProperty(default=2000.0,
                                       doc="Transition legth to ports")
    couplingWG = i3.ChildCellProperty(doc="", locked=True)
    couplingWG_l = i3.PositiveNumberProperty(default=5000.0,
                                             doc="Length of the coupling WG ")
    tt_port = i3.TraceTemplateProperty(
        doc="Wide trace template used for the contacts")

    #width_vec = i3.ListProperty(default=[1])
    n = i3.PositiveNumberProperty(default=1, doc="")
    width = i3.PositiveNumberProperty(default=1, doc="")
    lengths = i3.PositiveNumberProperty(default=1, doc="")

    def _default_lengths(self):
        for counter, cell in enumerate(self.s_length_vec):
            numero = counter + 1
        return numero

    #template for Autorute
    def _default_trace_template(self):
        return self.waveguide_template

    def _default_tt(self):
        return self.waveguide_template

    def _default_tt_port(self):
        tt_port = WireWaveguideTemplate()
        tt_port_layout = tt_port.Layout(core_width=15.0,
                                        cladding_width=15.0 + 2 * 8.0)
        return tt_port

    def _default_couplingWG(self):
        rect = i3.Waveguide(trace_template=self.tt_port)
        layout_rect = rect.Layout(shape=[(0.0, 0.0), (self.couplingWG_l, 0.0)])
        return rect

    def _default_Port(self):
        Port = AutoTransitionPorts(contents=self.couplingWG,
                                   port_labels=["in"],
                                   trace_template=self.waveguide_template)
        layout_Port = Port.Layout(
            transition_length=self.tlport)  #.visualize(annotate=True)
        return Port

    def _default_child_cells(self):
        child_cells = {
        }  # First we define the property "child_cells" as  an empty dictionary

        for counter, length in enumerate(
                self.s_length_vec
        ):  # the iteration starts in the first element of the list and follows element by element to the last element.

            #child_cells['Spiral{}'.format(counter)] = spiral
            #print spiral
            #print 'name of spiral:', spiral.name
            child_cells['InPort' + str(counter)] = self.Port
            child_cells['OutPort' + str(counter)] = self.Port

            print 'child_cells:', child_cells
        return child_cells

    def _default_links(self):
        links = []
        for counter, spiral in enumerate(self.s_length_vec):
            print counter
            #in_port = "Spiral{}:in".format(counter)
            in_port = "InPort{}:in".format(counter)
            #links.append((in_port, out_port))
            #in_port = "Spiral{}:out".format(counter)
            out_port = "OutPort{}:in".format(counter)
            links.append((in_port, out_port))

        return links

    class Layout(PlaceAndAutoRoute.Layout):
        #tipo=1

        def _default_bend_radius(self):
            return self.R

        def _default_child_transformations(self):
            d = {}
            for counter, child in enumerate(self.s_length_vec):
                #ip= child.ports["in"].position
                #print self.child_cells['InPort' + str(counter)].ports["out"].position
                #print self.child_cells['OutPort' + str(counter)].ports.position
                print '----------------'

                #print 'spiral length:', child.total_length
                print 'counter: ', counter
                print 'self.n = ', self.n
                print 'self.width: ', self.width
                #print 'sx: ', sx

                if self.tipo == 1:
                    sx = 70
                    a = 0.5
                    print 2 * (22362 * 0.5 - self.couplingWG_l)
                    print 'tipo = ', self.tipo

                    #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, self.n*counter*sx))
                    #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*0.5, (self.n+a)*counter*sx))
                    #d['OutPort' + str(counter)] = i3.Translation(translation=(self.chip_length*0.5, (self.n+a)*counter*sx))

                    d['InPort' + str(counter)] = i3.HMirror() + i3.Translation(
                        translation=(-22362 * 0.5 + self.couplingWG_l,
                                     (self.n + a) * counter * sx))
                    d['OutPort' + str(counter)] = i3.Translation(
                        translation=(22362 * 0.5 - self.couplingWG_l,
                                     (self.n + a) * counter * sx))

                #if self.tipo==2:
                #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+0.5)*counter*sx))
                #d['InPort' + str(counter)] = i3.HMirror()+ i3.Translation(translation=(-self.chip_length*(3/4)-self.couplingWG_l, -(self.n+0.5)*counter*sx))
                #d['OutPort' + str(counter)] = i3.Rotation(rotation=90) + i3.Translation(translation=((op[0]-ip[0])/2+2*self.R+(((self.n+0.5)*counter+self.width)*sx/4), self.chip_length*(3/4)+(self.width+counter-(((counter+1)-1.0)%self.lengths))*sx))
                if self.tipo == 2:
                    sx = 100
                    #d['Spiral' + str(counter)] = i3.Translation(translation=(-(op[0]-ip[0])/2, -(self.n+1)*counter*sx))
                    a = 7.0
                    print 'increment of length between waveguides of same width: ', (
                        self.n + a) * 1 * sx + ((self.n + a) * 1 + 0) * sx
                    print 'increment of length between waveguides of same length group: ', (
                        self.n + a) * 0 * sx + (
                            (self.n + a) * 0 + self.width) * sx

                    d['InPort' + str(counter)] = i3.HMirror() + i3.Translation(
                        translation=(0.0 - self.chip_length * 0.5,
                                     -(self.n + a) * counter * sx))
                    d['OutPort' + str(counter)] = i3.Rotation(
                        rotation=90) + i3.Translation(translation=(
                            (((self.n + a) * counter + self.width) * sx),
                            self.chip_length * 0.5 +
                            (self.width + counter -
                             (((counter + 1) - 1.0) % self.lengths)) * sx))

            return d

        # Fabio's addition
        def _generate_elements(self, elems):
            # We calculate the lengths of the 2 spirals in this pcell.
            # Note that we assume that there are exactly 2 spirals in this list.
            #assert len(self.Spiral_list) == 2
            lengths = get_lengths(self)[0]
            print lengths
            Link = get_lengths(self)[1]
            print Link
            if self.tipo == 1:

                sx = 70
                for counter, (child, length) in enumerate(
                        zip(self.s_length_vec, lengths)):
                    #ip= child.ports["in"].position
                    #op= child.ports["out"].position

                    width = Link.trace_template.core_width
                    #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width
                    a = 0.5
                    #i3.TECH.PPLAYER.NONE.LOGOTXT   when using isipp50g
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}'.format(width, ),
                        coordinate=(-self.chip_length * 0.5 + 2 * self.tlport,
                                    (self.n + a) * counter * sx - 15.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)

                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}'.format(width, ),
                        coordinate=(0.0, (self.n + a) * counter * sx - 15.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)

                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}'.format(width, ),
                        coordinate=(self.chip_length * 0.5 - 2 * self.tlport,
                                    (self.n + a) * counter * sx - 15.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)

            if self.tipo == 2:
                sx = 100
                for counter, (child, length) in enumerate(
                        zip(self.s_length_vec, lengths)):
                    #ip= child.ports["in"].position
                    #op= child.ports["out"].position

                    width = Link.trace_template.core_width
                    #print 'child.ports["in"].trace_template.core_width: ', child.ports["in"].trace_template.core_width
                    a = 7.0
                    #i3.TECH.PPLAYER.NONE.LOGOTXT   when using isipp50g
                    elems += i3.PolygonText(
                        layer=i3.TECH.PPLAYER.WG.TEXT,
                        text='Width={}_Length={}_R={}'.format(
                            width, length, self.R),
                        coordinate=(-1500,
                                    -(self.n + a) * counter * sx - 55.0),
                        alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT),
                        font=2,
                        height=20.0)
            return elems
    class Layout(i3.LayoutView):
        # specified parameters used for layout, lengths of various waveguides
        # using some default values if standard ring shape is used
        bend_radius_ring = i3.PositiveNumberProperty(default=10.,
                                                     doc="bend radius of ring")
        ring_x_straight = i3.PositiveNumberProperty(
            default=15., doc="straight between bends in x ring")
        ring_y_straight = i3.PositiveNumberProperty(
            default=25., doc="straight between bends in y ring")
        external_straights = i3.PositiveNumberProperty(
            default=10., doc="extra straight for outside structure")
        external_gap = i3.PositiveNumberProperty(
            default=1., doc="gap between outside waveguides and resonator")
        # external_radius = i3.PositiveNumberProperty(default=bend_radius_ring, doc="radius of outside coupler")
        rounding_algorithm = i3.DefinitionProperty(
            default=SplineRoundingAlgorithm(),
            doc="secondary rounding algorithm")

        # extra layouting for the CROW
        num_rings = i3.IntProperty(default=3, doc="number of rings")
        ring_gap = i3.PositiveNumberProperty(default=0.5,
                                             doc="gap between internal rings")

        use_gap_list = i3.BoolProperty(default=False,
                                       doc="use non default bending algorithm")
        ring_gap_list = i3.ListProperty(
            default=[], doc="list of gaps for manual swapping, default empty!")

        # define the layout of the internal coupler which we SRef below
        def _default_resonator(self):
            res_layout = self.cell.resonator.get_default_view(
                i3.LayoutView)  # Retrieve layout view following example

            # make the shape of the layout from the previous values. Assume (0, 0) is bottom middle!)
            # will do each corner for clarity
            # bottom_left = (-self.bend_radius_ring - self.ring_x_straight/2., 0.)
            # top_left = (-self.bend_radius_ring - self.ring_x_straight/2.,
            #             self.bend_radius_ring*2. + self.ring_y_straight)
            # top_right = (self.bend_radius_ring + self.ring_x_straight/2.,
            #              self.bend_radius_ring*2. + self.ring_y_straight)
            # bottom_right = (self.bend_radius_ring + self.ring_x_straight/2., 0.)
            # ring_shape = [bottom_left, top_left, top_right, bottom_right, bottom_left]
            # print ring_shape

            # tried to use generic round ring, but failed :P. Using ring rect instead
            # set the layout of the resonator. Stuck a bool for non default rounding algorithm

            res_layout.set(bend_radius=self.bend_radius_ring,
                           straights=(self.ring_x_straight,
                                      self.ring_y_straight),
                           rounding_algorithm=self.rounding_algorithm)

            return res_layout

        def _dummy_resonator(self):
            dummy_res = i3.SRef(name="just_a_dummy", reference=self.resonator)
            return dummy_res

        # make a function for determining the distance between core size and

        def _resonator_size_core_to_core(self):
            # calls the get components function and then does math on the pulled in layout
            resonator = self._dummy_resonator()
            wg_ring_template = self.wg_ring_template

            # grabbing the position of the resonator to layout the rest of the coupler properly
            resonator_west_side = resonator.size_info().west
            resonator_east_side = resonator.size_info().east

            resonator_core_width = wg_ring_template.core_width
            resonator_clad_width = wg_ring_template.cladding_width

            resonator_x_dim = (resonator_east_side -
                               resonator_west_side) - resonator_clad_width
            return resonator_x_dim

        # setting the output shape of the access waveguides using a shape defined by ports from MMI (hopefully..)
        def _default_wgs(self):
            # bring in parts from rest of PCell Layout, used dummy resonator to grab positions
            resonator = self._dummy_resonator()
            wg_in_cell, wg_pass_cell = self.cell.wgs
            wg_template = self.wg_coupler_template
            wg_ring_template = self.wg_ring_template

            # using the ring radius for the external radius
            external_rad = self.bend_radius_ring
            external_str = self.external_straights

            # grabbing the position of the resonator to layout the rest of the coupler properly
            resonator_west_side = resonator.size_info().west
            resonator_south_side = resonator.size_info().south

            resonator_core_width = wg_ring_template.core_width
            resonator_clad_width = wg_ring_template.cladding_width
            coupler_core_width = wg_template.core_width

            # calculate the x position for center of input coupling waveguide when coupling, and make shape
            x_coup_spot = resonator_west_side + resonator_clad_width/2. - resonator_core_width/2. - self.external_gap \
                - coupler_core_width/2.

            # get bottom using the south and cladding information again
            bottom_left = (x_coup_spot - external_str - external_rad,
                           resonator_south_side + resonator_clad_width / 2.)
            bottom_right = (x_coup_spot,
                            resonator_south_side + resonator_clad_width / 2.)
            top_right = (x_coup_spot, bottom_right[1] + 2. * external_rad +
                         self.ring_y_straight)
            top_left = (bottom_left[0], top_right[1])

            wg_shape = [bottom_left, bottom_right, top_right, top_left]

            # now make the instance using this shape info
            wg_in_layout = wg_in_cell.get_default_view(i3.LayoutView)

            wg_in_layout.set(trace_template=wg_template,
                             shape=wg_shape,
                             bend_radius=external_rad,
                             rounding_algorithm=self.rounding_algorithm)

            # other waveguide for reference, can put in shape or mirror later
            wg_pass_layout = wg_pass_cell.get_default_view(i3.LayoutView)
            # wg_in_layout.set()
            return wg_in_layout, wg_pass_layout  # wg_ring_layout

        # A few functions for grabbing waveguide parameters to determine lengths for FSR checking
        # def wg_lengths(self):
        #     # grab the lengths of internal waveguides to use for calculations later
        #     wg_in_layout, wg_pass_layout, wg_ring_layout = self.wgs
        #
        #     straights_and_bends = wg_ring_layout.trace_length()
        #     return straights_and_bends

        # now we take the resonator and perform multiple translations for the CROW
        def _get_components(self):
            res_x_dim = self._resonator_size_core_to_core()
            ring_gap = self.ring_gap
            ring_core_width = self.wg_ring_template.core_width
            ring_gap_list = self.ring_gap_list

            shifting_list = [0.] + ring_gap_list
            all_components = []
            # and now crank an SRef for each Ring in a loop
            for ring in range(self.num_rings):
                # will translate the original ring over to the correct position, and iterate for number of rings
                # use an if statement for external gap list or not. Need an error
                if self.use_gap_list is False:
                    this_transform = i3.Translation(
                        ((res_x_dim + ring_gap + ring_core_width) * ring, 0.))
                    this_resonator = i3.SRef(name="R_" + str(ring),
                                             reference=self.resonator,
                                             transformation=this_transform)
                    all_components.append(this_resonator)
                else:
                    # sum previous elements of the shifting list for correct relative translation
                    total_shift = sum(shifting_list[:(ring + 1)])

                    this_transform = i3.Translation(
                        ((res_x_dim + ring_core_width) * ring + total_shift,
                         0.))
                    this_resonator = i3.SRef(name="R_" + str(ring),
                                             reference=self.resonator,
                                             transformation=this_transform)
                    all_components.append(this_resonator)

            return all_components

        def _generate_instances(self, insts):
            # includes the get components and the waveguides
            the_rings = self._get_components()
            insts += the_rings
            wg_in_layout, wg_pass_layout = self.wgs  #  wg_pass_layout, wg_ring_layout
            insts += i3.SRef(reference=wg_in_layout, name="wg_in")

            # ok so now I grab the last ring from the rings and use it to determine its position
            last_ring = the_rings[-1]
            east_side_ring = last_ring.size_info().east

            # and I get the waveguide properties for ring and coupler, to give correct outside gap
            ring_core_width = self.wg_ring_template.core_width
            ring_clad_width = self.wg_ring_template.cladding_width

            bus_wg_core_width = self.wg_coupler_template.core_width
            bus_wg_clad_width = self.wg_coupler_template.cladding_width

            final_x_spot = (east_side_ring - ring_clad_width/2.) + ring_core_width/2. \
                           + self.external_gap + bus_wg_core_width/2.

            # rather than making a new waveguide we can mirror the previous structure into the final position
            # thus we need to determine the difference in the core position of the original structure
            # with the *negative* position of the final x position, and then the mirror will flip it around
            bus_core_pos = wg_in_layout.size_info(
            ).east - bus_wg_clad_width / 2.

            # now we translate the original structure to the desired negative position, and horizontally mirror around 0
            output_transformation = i3.HMirror() + i3.Translation(
                (-1. * (-final_x_spot - bus_core_pos), 0.))

            # finally we perform the SRef on the previous layout and transform it with a new name
            insts += i3.SRef(reference=wg_in_layout,
                             name="wg_out",
                             transformation=output_transformation)

            return insts

        def _generate_ports(self, prts):
            # try to reuse the output waveguides following the example and change the names, looks good
            instances = self.instances
            prts += instances["wg_in"].ports["in"].modified_copy(name="in1")
            prts += instances["wg_in"].ports["out"].modified_copy(name="in2")
            prts += instances["wg_out"].ports["in"].modified_copy(name="out1")
            prts += instances["wg_out"].ports["out"].modified_copy(name="out2")
            return prts
Esempio n. 5
0
    class Layout(i3.LayoutView):

        # Properties -------

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

        # grating types
        # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom',
        # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom',
        grating_type = i3.StringProperty(default='',
                                         doc='flag for grating type')

        # inputs
        period = i3.DefinitionProperty(default=0.0, doc='period')
        duty_cycle = i3.DefinitionProperty(default=0.0, doc='duty cycle')
        grating_amp = i3.DefinitionProperty(default=0.0, doc='grating amp')
        grat_wg_width = i3.DefinitionProperty(default=0.0,
                                              doc='waveguide width')
        length = i3.DefinitionProperty(default=0.0, doc='length')

        # Methods -------

        def _generate_instances(self, insts):
            # Generates a long ass row of gratings

            # serp_grating_layout = SerpGratingArray().get_default_view(i3.LayoutView)
            # serp_grating_layout.set( pitch              = 0.5,
            #                          grat_wg_width      = 6.5,
            #                          flyback_wg_width   = 6.5,
            #                          grating_amp        = grating_amps[i_row][i_col],
            #                          duty_cycle         = duty_cycle,
            #                          period             = period,
            #                          numrows            = numrows_tx,
            #                          grating_type       = grating_types[i_row][i_col],
            #                          length             = 100.0 )

            # load the aim gds just to get its positions and stuff
            # main chip GDS
            fname = '../PDK_Library_Layout_GDS/ap_suny_v20a_chipframe.gds'
            main_chip_gds_cell = i3.GDSCell(filename=fname)

            # grab layout size info
            main_chip_gds_lay = main_chip_gds_cell.Layout()
            main_chip_gds_lay_size_info = main_chip_gds_lay.size_info()

            # grab relevant positions
            chip_edge_east = main_chip_gds_lay_size_info.east
            chip_edge_west = main_chip_gds_lay_size_info.west

            # make edge coupler
            edge_coupler_gds_lay = EdgeCoupler(
                name=self.name + 'edge_coupler_mmmmffff').Layout()

            # add and route input/west edgecoupler
            # position edge coupler on west side of chip
            chip_port_west = i3.OpticalPort(position=(chip_edge_west, 0.0),
                                            angle_deg=0.0)
            edge_coupler_west_port = edge_coupler_gds_lay.ports['out']
            t = i3.vector_match_transform(edge_coupler_west_port,
                                          chip_port_west)
            edge_coupler_west_name = self.name + '_EDGE_COUPLER_WEST'
            west_edge_coupler = i3.SRef(name=edge_coupler_west_name,
                                        reference=edge_coupler_gds_lay,
                                        transformation=t,
                                        flatten=False)

            # add a small linear taper to go from 0.4 to 0.5um wg
            lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView)
            lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0)
            t = i3.vector_match_transform(lin_taper_lay.ports['in'],
                                          west_edge_coupler.ports['in'])
            lin_taper_lay_name = self.name + '_EDGETAPER_WEST'
            insts += i3.SRef(name=lin_taper_lay_name,
                             reference=lin_taper_lay,
                             transformation=t,
                             flatten=True)

            # 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_lay_1 = ParabolicTaper(
                name=self.name + '_TAPER_1').get_default_view(i3.LayoutView)
            taper_swg_lay_1.set(length=taper_length,
                                width1=wg_width,
                                width2=self.grat_wg_width,
                                width_etch=width_etch)
            taper_swg_name_1 = self.name + '_TAPER_1'
            t = i3.vector_match_transform(
                taper_swg_lay_1.ports['left'],
                insts[lin_taper_lay_name].ports['out'])
            insts += i3.SRef(name=taper_swg_name_1,
                             reference=taper_swg_lay_1,
                             transformation=t,
                             flatten=True)

            # add grating array
            # make grating layout
            swg_l_name = self.name + '_SWG'
            if self.grating_type == 'one_sidewall':
                # single sidewall grating
                swg_l = SidewallGratingWg(name=swg_l_name).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 = SidewallGratingWg(name=swg_l_name).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(name=swg_l_name).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(name=swg_l_name).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(name=swg_l_name).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(name=swg_l_name).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 getting grating layout

            # add waveguide instance

            t = i3.vector_match_transform(
                swg_l.ports['in'], insts[taper_swg_name_1].ports['right'])
            insts += i3.SRef(name=swg_l_name,
                             reference=swg_l,
                             transformation=t,
                             flatten=True)

            # add east coupler
            chip_port_east = i3.OpticalPort(position=(chip_edge_east, 0.0),
                                            angle_deg=180.0)
            edge_coupler_east_port = edge_coupler_gds_lay.ports['out']
            t = i3.vector_match_transform(edge_coupler_east_port,
                                          chip_port_east,
                                          mirrored=True)
            edge_coupler_east_name = self.name + '_EDGE_COUPLER_EAST'
            east_edge_coupler = i3.SRef(name=edge_coupler_east_name,
                                        reference=edge_coupler_gds_lay,
                                        transformation=t,
                                        flatten=False)

            # add a small linear taper to go from 0.4 to 0.5um wg
            lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView)
            lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0)
            t = i3.vector_match_transform(lin_taper_lay.ports['in'],
                                          east_edge_coupler.ports['in'],
                                          mirrored=True)
            lin_taper_lay_name_east = self.name + '_EDGETAPER_EAST'
            insts += i3.SRef(name=lin_taper_lay_name_east,
                             reference=lin_taper_lay,
                             transformation=t,
                             flatten=True)

            # east taper
            taper_swg_lay_2 = ParabolicTaper(
                name=self.name + '_TAPER_2').get_default_view(i3.LayoutView)
            taper_swg_lay_2.set(length=taper_length,
                                width1=wg_width,
                                width2=self.grat_wg_width,
                                width_etch=width_etch)
            taper_swg_name_2 = self.name + '_TAPER_2'
            t = i3.vector_match_transform(
                taper_swg_lay_2.ports['left'],
                insts[lin_taper_lay_name_east].ports['out'],
                mirrored=True)
            insts += i3.SRef(name=taper_swg_name_2,
                             reference=taper_swg_lay_2,
                             transformation=t,
                             flatten=True)

            # connect with fat waveguide, which is just a sidewall grating with no amp
            connect_len = insts[taper_swg_name_2].ports['right'].position[
                0] - insts[swg_l_name].ports['out'].position[0]
            fat_wg_l = SidewallGratingWg().get_default_view(i3.LayoutView)
            fat_wg_l_name = self.name + '_FAT_WG_CON'
            fat_wg_l.set(period=self.period,
                         duty_cycle=self.duty_cycle,
                         grating_amp=0.0,
                         wg_width=self.grat_wg_width,
                         length=connect_len,
                         both_sides=False)
            t = i3.vector_match_transform(fat_wg_l.ports['in'],
                                          insts[swg_l_name].ports['out'])
            insts += i3.SRef(name=fat_wg_l_name,
                             reference=fat_wg_l,
                             transformation=t,
                             flatten=True)

            return insts

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

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

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

            return ports