Example #1
0
    def produce_impl(self):
        from SiEPIC.utils import arc
        from SiEPIC.extend import to_itype

        dbu = self.layout.dbu

        layer = self.layout.layer(self.layer)
        radius = to_itype(self.radius, dbu)
        width = to_itype(self.width, dbu)

        poly = pya.Polygon(arc(radius + width / 2, 0, 360))
        hole = pya.Polygon(arc(radius - width / 2, 0, 360))
        poly.insert_hole(hole.get_points())
        self.cell.shapes(layer).insert(poly)
Example #2
0
    def coerce_parameters_impl(self):
        from SiEPIC.extend import to_itype
        print("GSiP.Waveguide coerce parameters")

        if 0:
            TECHNOLOGY = get_technology_by_name('GSiP')
            dbu = self.layout.dbu
            wg_width = to_itype(self.width, dbu)
            for lr in range(0, len(self.layers)):
                layer = self.layout.layer(TECHNOLOGY[self.layers[lr]])
                width = to_itype(self.widths[lr], dbu)
                # check to make sure that the waveguide with parameters are consistent in both places
                if self.layout.layer(TECHNOLOGY['Waveguide']) == layer:
                    if width != wg_width:
                        self.widths[lr] = self.width
                # check to make sure that the DevRec is bigger than the waveguide width
                if self.layout.layer(TECHNOLOGY['DevRec']) == layer:
                    if width < wg_width:
                        self.widths[lr] = self.width * 2
Example #3
0
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts,
                      radius, adiab, bezier):
    from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal
    from SiEPIC.extend import to_itype
    from pya import Path, Polygon, Trans
    dbu = layout.dbu

    width = widths[0]
    turn = 0
    waveguide_length = 0
    for lr in range(0, len(layers)):
        wg_pts = [pts[0]]
        layer = layout.layer(TECHNOLOGY[layers[lr]])
        width = to_itype(widths[lr], dbu)
        offset = to_itype(offsets[lr], dbu)
        for i in range(1, len(pts) - 1):
            turn = (
                (angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] - pts[i]) +
                 90) % 360 - 90) / 90
            dis1 = pts[i].distance(pts[i - 1])
            dis2 = pts[i].distance(pts[i + 1])
            angle = angle_vector(pts[i] - pts[i - 1]) / 90
            pt_radius = to_itype(radius, dbu)
            # determine the radius, based on how much space is available
            if len(pts) == 3:
                pt_radius = min(dis1, dis2, pt_radius)
            else:
                if i == 1:
                    if dis1 <= pt_radius:
                        pt_radius = dis1
                elif dis1 < 2 * pt_radius:
                    pt_radius = dis1 / 2
                if i == len(pts) - 2:
                    if dis2 <= pt_radius:
                        pt_radius = dis2
                elif dis2 < 2 * pt_radius:
                    pt_radius = dis2 / 2
            # waveguide bends:
            if abs(turn) == 1:
                if (adiab):
                    wg_pts += Path(
                        arc_bezier(
                            pt_radius,
                            270,
                            270 + inner_angle_b_vectors(
                                pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                            float(bezier),
                            DevRec='DevRec' in layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()
                else:
                    wg_pts += Path(
                        arc_xy(-pt_radius,
                               pt_radius,
                               pt_radius,
                               270,
                               270 + inner_angle_b_vectors(
                                   pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                               DevRec='DevRec' in layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()

        wg_pts += [pts[-1]]
        wg_pts = pya.Path(wg_pts, 0).unique_points().get_points()
        wg_polygon = Polygon(
            translate_from_normal(
                wg_pts, width / 2 + (offset if turn > 0 else -offset)) +
            translate_from_normal(
                wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1])
        cell.shapes(layer).insert(wg_polygon)

        if layout.layer(TECHNOLOGY['Waveguide']) == layer:
            waveguide_length = wg_polygon.area() / width * dbu
    return waveguide_length
Example #4
0
    def produce_impl(self):
        from SiEPIC._globals import PIN_LENGTH
        from SiEPIC.extend import to_itype
        from pya import DPolygon
        import math
        # This is the main part of the implementation: create the layout

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes
        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        #variables
        pitch = self.pitch
        w = self.w
        wc = self.wc
        ff = self.ff
        #angle = self.angle
        gap = self.gap
        #gap2 = self.gap2
        row = self.row
        Length = self.Length
        taperL = self.taperL
        phaseshifted = self.phaseshifted
        #print(doublebus)

        if Length <= 3 * pitch:
            Length = 3 * pitch
            print(
                'invalid length of MultiBox Bragg grating, set length at least 3 times larger than the period of multibox blocks'
            )

        s1 = pitch * ff  #silicon
        s2 = pitch - s1  #gap

        # Draw the first Multi-box Waveguides
        #calulate ideal length of bus
        Bragg_length = Length
        #bus_length = self.cell.bbox().height()*dbu +pitch*2
        constant = math.ceil(Bragg_length / (s1 + s2))
        if Bragg_length % (s1 + s2) != 0:
            Bragg_length = constant * (s1 + s2)

        for ii in range(0, int(row)):
            xo = [(ii * (w + gap)), (w + ii * (w + gap)), (w + ii * (w + gap)),
                  (ii * (w + gap))]
            yo = [0, 0, s1, s1]
            dpts = [pya.DPoint(xo[i], yo[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

            # draw the SWG waveguide from the center one to +/- positions
            for i in range(0, int(math.ceil((constant) / 2))):
                yu = [yo[j] + i * pitch for j in range(len(yo))]
                yd = [yo[j] - i * pitch for j in range(len(yo))]

                dpts = [pya.DPoint(xo[i], yu[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)
                dpts = [pya.DPoint(xo[i], yd[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

            # draw the tapers from waveguide to SWG
            if taperL != 0:
                xtu = [((ii * (w + gap)) + (w - 0.06) / 2),
                       ((ii * (w + gap)) + (w - 0.06) / 2 + 0.06),
                       ((ii * (w + gap)) + w + gap / 2),
                       ((ii * (w + gap)) - gap / 2)]
                ytu = [(yu[3] - taperL), (yu[3] - taperL), (yu[3]), (yu[3])]
                dpts = [pya.DPoint(xtu[i], ytu[i]) for i in range(len(xtu))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

                ytd = [(yd[1] + taperL), (yd[1] + taperL), (yd[1]), (yd[1])]
                dpts = [pya.DPoint(xtu[i], ytd[i]) for i in range(len(xtu))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

                # taper connections from multi-tapers to std WG
                xTu = [(-gap / 2), (-gap / 2 + row * (gap + w)),
                       ((row * (gap + w) - gap) / 2 + 0.25),
                       ((row * (gap + w) - gap) / 2 - 0.25)]
                yTu = [(yu[3]), (yu[3]), (yu[3] + taperL), (yu[3] + taperL)]
                dpts = [pya.DPoint(xTu[i], yTu[i]) for i in range(len(xTu))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

                yTd = [(yd[1]), (yd[1]), (yd[1] - taperL), (yd[1] - taperL)]
                dpts = [pya.DPoint(xTu[i], yTd[i]) for i in range(len(xTu))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)
                # f is the factor to define the Dev starting point
                f = 1

            if taperL == 0:
                yTd = yd
                yTu = yu
                xTu = [0, 0, 0, 0]
                f = 0

        # draw the corrugations of the Bragg gratings
        constant_c = math.ceil((Bragg_length - taperL) / (s1 + s2))

        for iii in range(0, int(math.ceil(constant_c / 4))):
            yuc = [yo[j] + 2 * iii * pitch for j in range(len(yo))]
            ydc = [yo[j] - 2 * iii * pitch for j in range(len(yo))]
            xlc = [-wc - s2, -s2, -s2, -wc - s2]
            xrc = [
                row * pitch, row * pitch + wc, row * pitch + wc, row * pitch
            ]

            dpts = [pya.DPoint(xlc[i], yuc[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

            dpts = [pya.DPoint(xrc[i], yuc[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

        if phaseshifted is False:
            for iii in range(0, int(math.ceil(constant_c / 4))):
                #yuc = [yo[j]+2*iii*pitch for j in range(len(yo))]
                ydc = [yo[j] - 2 * iii * pitch for j in range(len(yo))]
                #xlc = [-wc-s2, -s2, -s2,-wc-s2]
                #xrc = [row*pitch, row*pitch+wc, row*pitch+wc, row*pitch]

                dpts = [pya.DPoint(xlc[i], ydc[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

                dpts = [pya.DPoint(xrc[i], ydc[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

        if phaseshifted is True:
            for iii in range(0, int(math.ceil(constant_c / 4))):
                #yuc = [yo[j]+2*iii*pitch for j in range(len(yo))]
                yddc = [
                    yo[j] - pitch - 2 * iii * pitch for j in range(len(yo))
                ]

                dpts = [pya.DPoint(xlc[i], yddc[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

                dpts = [pya.DPoint(xrc[i], yddc[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

        #DEV BOX
        dev = Box(f * (-gap - wc - (2) * pitch) / dbu, yTd[-1] / dbu,
                  (wc + (row + 2) * pitch) / dbu, yTu[-1] / dbu)
        shapes(LayerDevRecN).insert(dev)
        dev_width = self.cell.bbox().width() / 2

        dev_up = yu[-1] / dbu + taperL / dbu
        dev_down = yd[-4] / dbu - taperL / dbu

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.w, dbu)
        gap = to_itype(self.gap, dbu)

        #Pin1
        t = Trans(Trans.R0, xTu[-1] / dbu + 250, dev_up)
        pin = Path([Point(0, -pin_length / 2),
                    Point(0, pin_length / 2)], 500)  #500 is width of std WG
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        t = Trans(Trans.R270, xTu[-1] / dbu + 250, dev_up)
        text = Text("pin1", t)
        text.halign = 0
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        #Pin2
        t = Trans(Trans.R0, xTu[-1] / dbu + 250, dev_down)
        pin = Path([Point(0, pin_length / 2), Point(0, -pin_length / 2)], 500)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        t = Trans(Trans.R90, xTu[-1] / dbu + 250, dev_down)
        text = Text("pin2", t)
        text.halign = 0
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        # Ref
        t = Trans(Trans.R270, xTu[-1] / dbu + 250 + 0.5 / dbu, dev_up)
        text = Text("Ref: E. Luan, doi.org/10.1364/BOE.10.004825", t)
        text.halign = 0
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
Example #5
0
    def produce_impl(self):

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        from SiEPIC.extend import to_itype

        # Draw the Bragg grating:
        box_width = self.grating_period / 2 / dbu
        grating_period = self.grating_period / dbu
        w = to_itype(self.wg_width, dbu)
        half_w = w / 2
        half_corrugation_w = self.corrugation_width / 2 / dbu
        misalignment = int(self.misalignment / dbu)
        if self.sinusoidal:
            npoints_sin = 40
            for i in range(0, self.number_of_periods):
                x = ((i * self.grating_period) / dbu)
                box1 = Box(x, 0, x + box_width, half_w + half_corrugation_w)
                pts1 = [Point(x, 0)]
                pts3 = [Point(x + misalignment, 0)]
                for i1 in range(0, npoints_sin + 1):
                    x1 = i1 * 2 * math.pi / npoints_sin
                    y1 = half_corrugation_w * math.sin(x1)
                    x1 = x1 / 2 / math.pi * grating_period
                    #          print("x: %s, y: %s" % (x1,y1))
                    pts1.append(Point(x + x1, half_w + y1))
                    pts3.append(Point(x + misalignment + x1, -half_w - y1))
                pts1.append(Point(x + grating_period, 0))
                pts3.append(Point(x + grating_period + misalignment, 0))
                shapes(LayerSiN).insert(Polygon(pts1))
                shapes(LayerSiN).insert(Polygon(pts3))
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, 0, length, half_w)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, 0, misalignment, -half_w)
                shapes(LayerSiN).insert(box3)

        else:
            for i in range(0, self.number_of_periods):
                x = (i * self.grating_period) / dbu
                box1 = Box(x, 0, x + box_width, half_w + half_corrugation_w)
                box2 = Box(x + box_width, 0, x + grating_period,
                           half_w - half_corrugation_w)
                box3 = Box(x + misalignment, 0, x + box_width + misalignment,
                           -half_w - half_corrugation_w)
                box4 = Box(x + box_width + misalignment, 0,
                           x + grating_period + misalignment,
                           -half_w + half_corrugation_w)
                shapes(LayerSiN).insert(box1)
                shapes(LayerSiN).insert(box2)
                shapes(LayerSiN).insert(box3)
                shapes(LayerSiN).insert(box4)
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, 0, length, half_w)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, 0, misalignment, -half_w)
                shapes(LayerSiN).insert(box3)

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        t = Trans(Trans.R0, 0, 0)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        t = Trans(Trans.R0, length, 0)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
        shape.text_halign = 2

        # Compact model information
        t = Trans(Trans.R0, 0, 0)
        text = Text('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, length / 10, 0)
        text = Text('Component=ebeam_bragg_te1550', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, length / 9, 0)
        text = Text \
          ('Spice_param:number_of_periods=%s grating_period=%.3g corrugation_width=%.3g misalignment=%.3g sinusoidal=%s' %\
          (self.number_of_periods, self.grating_period*1e-6, self.corrugation_width*1e-6, self.misalignment*1e-6, int(self.sinusoidal)), t )
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu

        # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
        t = Trans(Trans.R0, 0, 0)
        path = Path([Point(0, 0), Point(length, 0)], 3 * w)
        shapes(LayerDevRecN).insert(path.simple_polygon())
Example #6
0
    def produce_impl(self):
        import math

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        from SiEPIC.extend import to_itype

        # Draw the Bragg grating (bottom):
        width_period1 = to_itype(self.grating_period1 / 2, dbu)
        width_period2 = to_itype(self.grating_period2 / 2, dbu)

        grating_period1 = to_itype(self.grating_period1, dbu)
        grating_period2 = to_itype(self.grating_period2, dbu)

        w1 = to_itype(self.wg1_width, dbu)
        w2 = to_itype(self.wg2_width, dbu)

        GaussianIndex = self.index

        N1 = self.number_of_periods1

        vertical_offset1 = to_itype(self.gap / 2 + self.wg1_width / 2, dbu)
        vertical_offset2 = to_itype(-self.gap / 2 - self.wg2_width / 2, dbu)

        for i in range(0, self.number_of_periods1):
            x1 = to_itype(i * self.grating_period1, dbu)
            x2 = to_itype(i * self.grating_period2, dbu)

            profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                               (i - N1 / 2) / (N1))**2)

            profile_outer = to_itype(self.corrugation_width1outer,
                                     dbu) * profileFunction
            profile_inner = to_itype(self.corrugation_width1inner,
                                     dbu) * profileFunction

            box1outer = Box(x1, vertical_offset1 + w1 / 2 - profile_outer / 2,
                            x1 + width_period1, vertical_offset1)
            box2outer = Box(x1 + width_period1,
                            vertical_offset1 + w1 / 2 + profile_outer / 2,
                            x1 + 2 * width_period1, vertical_offset1)

            box1inner = Box(x2, vertical_offset1 - w1 / 2 - profile_inner / 2,
                            x2 + width_period2, vertical_offset1)
            box2inner = Box(x2 + width_period2,
                            vertical_offset1 - w1 / 2 + profile_inner / 2,
                            x2 + 2 * width_period2, vertical_offset1)

            shapes(LayerSiN).insert(box1outer)
            shapes(LayerSiN).insert(box2outer)

            shapes(LayerSiN).insert(box1inner)
            shapes(LayerSiN).insert(box2inner)

            length1 = x1 + grating_period1
            length2 = x2 + grating_period2

        if grating_period1 > grating_period2:
            box_inner = Box(length2, vertical_offset1, length1,
                            vertical_offset1 - w1 / 2)
            shapes(LayerSiN).insert(box_inner)
            length = x1 + grating_period1
        else:
            box_outer = Box(length1, vertical_offset1, length2,
                            vertical_offset1 + w1 / 2)
            shapes(LayerSiN).insert(box_outer)
            length = x2 + grating_period2

        # lower waveguide
        for i in range(0, self.number_of_periods1):
            x1 = to_itype(i * self.grating_period1, dbu)
            x2 = to_itype(i * self.grating_period2, dbu)

            profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                               (i - N1 / 2) / (N1))**2)

            profile_outer = to_itype(self.corrugation_width2outer,
                                     dbu) * profileFunction
            profile_inner = to_itype(self.corrugation_width2inner,
                                     dbu) * profileFunction

            box1outer = Box(x2, vertical_offset2 + w2 / 2 + profile_outer / 2,
                            x2 + width_period2, vertical_offset2)
            box2outer = Box(x2 + width_period2,
                            vertical_offset2 + w2 / 2 - profile_outer / 2,
                            x2 + 2 * width_period2, vertical_offset2)

            box1inner = Box(x1, vertical_offset2 - w2 / 2 + profile_inner / 2,
                            x1 + width_period1, vertical_offset2)
            box2inner = Box(x1 + width_period1,
                            vertical_offset2 - w2 / 2 - profile_inner / 2,
                            x1 + 2 * width_period1, vertical_offset2)

            shapes(LayerSiN).insert(box1outer)
            shapes(LayerSiN).insert(box2outer)

            shapes(LayerSiN).insert(box1inner)
            shapes(LayerSiN).insert(box2inner)

            length1 = x1 + grating_period1
            length2 = x2 + grating_period2

        if grating_period1 > grating_period2:
            box_inner = Box(length2, vertical_offset2, length1,
                            vertical_offset2 + w2 / 2)
            shapes(LayerSiN).insert(box_inner)
            length = x1 + grating_period1
        else:
            box_outer = Box(length1, vertical_offset2, length2,
                            vertical_offset2 - w2 / 2)
            shapes(LayerSiN).insert(box_outer)
            length = x2 + grating_period2

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0, 0, vertical_offset2)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0, 0, vertical_offset1)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin3", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0, length, vertical_offset1)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0, length, vertical_offset2)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin4", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        # Compact model information
        t = Trans(Trans.R0, 0, 0)
        text = Text('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, length / 10, 0)
        text = Text('Component=ebeam_contra_dc', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, length / 9, 0)
        text = Text \
          ('Spice_param:number_of_periods=%s' %\
          (self.number_of_periods1), t )
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu

        # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
        t = Trans(Trans.R0, 0, 0)
        path = Path([Point(0, 0), Point(length, 0)], 3 * w)
        shapes(LayerDevRecN).insert(path.simple_polygon())
Example #7
0
    def produce_impl(self):

        from SiEPIC.utils.layout import layout_waveguide2
        from SiEPIC.utils import angle_vector
        from math import cos, sin, pi, sqrt
        import pya
        from SiEPIC.extend import to_itype

        # print("GSiP.Waveguide")

        from SiEPIC.utils import get_technology_by_name
        TECHNOLOGY = get_technology_by_name('GSiP')

        dbu = self.layout.dbu
        wg_width = to_itype(self.width, dbu)
        path = self.path.to_itype(dbu)

        if not (len(self.layers) == len(self.widths)
                and len(self.layers) == len(self.offsets)
                and len(self.offsets) == len(self.widths)):
            raise Exception(
                "There must be an equal number of layers, widths and offsets")
        path.unique_points()
        pts = path.get_points()

        # Draw the waveguide geometry, new in SiEPIC-Tools v0.3.64
        waveguide_length = layout_waveguide2(TECHNOLOGY, self.layout,
                                             self.cell, self.layers,
                                             self.widths, self.offsets, pts,
                                             self.radius, self.adiab,
                                             self.bezier)

        pts = path.get_points()
        LayerPinRecN = self.layout.layer(TECHNOLOGY['PinRec'])

        t1 = Trans(angle_vector(pts[0] - pts[1]) / 90, False, pts[0])
        self.cell.shapes(LayerPinRecN).insert(
            Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t1))
        self.cell.shapes(LayerPinRecN).insert(Text("pin1", t1, 0.3 / dbu, -1))

        t = Trans(angle_vector(pts[-1] - pts[-2]) / 90, False, pts[-1])
        self.cell.shapes(LayerPinRecN).insert(
            Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t))
        self.cell.shapes(LayerPinRecN).insert(Text("pin2", t, 0.3 / dbu, -1))

        LayerDevRecN = self.layout.layer(TECHNOLOGY['DevRec'])

        # Compact model information
        angle_vec = angle_vector(pts[0] - pts[1]) / 90
        halign = 0  # left
        angle = 0
        if angle_vec == 0:  # horizontal
            halign = 2  # right
            angle = 0
            dpt = Point(0, 0.2 * wg_width)
        if angle_vec == 2:  # horizontal
            halign = 0  # left
            angle = 0
            dpt = Point(0, 0.2 * wg_width)
        if angle_vec == 1:  # vertical
            halign = 2  # right
            angle = 1
            dpt = Point(0.2 * wg_width, 0)
        if angle_vec == -1:  # vertical
            halign = 0  # left
            angle = 1
            dpt = Point(0.2 * wg_width, 0)
        pt2 = pts[0] + dpt
        pt3 = pts[0] - dpt
        pt4 = pts[0] - 2 * dpt
        pt5 = pts[0] + 2 * dpt

        t = Trans(angle, False, pt5)
        text = Text('cellName=%s' % self.cellName, t, 0.1 * wg_width, -1)
        text.halign = halign
        shape = self.cell.shapes(LayerDevRecN).insert(text)
        t = Trans(angle, False, pt3)
        text = Text('Lumerical_INTERCONNECT_library=Design kits/%s' % self.CML,
                    t, 0.1 * wg_width, -1)
        text.halign = halign
        shape = self.cell.shapes(LayerDevRecN).insert(text)
        t = Trans(angle, False, pt2)
        text = Text('Component=%s' % self.model, t, 0.1 * wg_width, -1)
        text.halign = halign
        shape = self.cell.shapes(LayerDevRecN).insert(text)
        t = Trans(angle, False, pts[0])
        pts_txt = str(
            [[round(p.to_dtype(dbu).x, 3),
              round(p.to_dtype(dbu).y, 3)] for p in pts]).replace(', ', ',')
        text = Text ( \
          'Spice_param:wg_length=%.3fu wg_width=%.3fu points="%s" radius=%s' %\
            (waveguide_length, self.width, pts_txt,self.radius ), t, 0.1*wg_width, -1  )
        text.halign = halign
        shape = self.cell.shapes(LayerDevRecN).insert(text)
        t = Trans(angle, False, pt4)
        text = Text ( \
          'Length=%.3fu' %(waveguide_length), t, 0.5*wg_width, -1  )
        text.halign = halign
        shape = self.cell.shapes(LayerDevRecN).insert(text)
  def produce_impl(self):
  
    # fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes


    LayerSiN = ly.layer(self.waveguide)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)
    LayerTextN = ly.layer(self.text)


    from math import pi, cos, sin, log, sqrt
    from SiEPIC.utils import arc, arc_to_waveguide, points_per_circle, arc_wg
    
    x = 0
    y = 0
    theta = self.theta
#    2*pi*r*(4*theta/360) = length + self.delta_length

    from SiEPIC.extend import to_itype
    w = to_itype(self.wg_width,dbu)
    length = to_itype(self.length,dbu)
    r = length/4/sin(theta/180.0*pi)
    waveguide_length = 2*pi*r*(4*theta/360.0)
    
    #arc_to_waveguide(pts, width):
    #arc(radius, start, stop)
    t = Trans(Trans.R0,x, round(y+r))
    self.cell.shapes(LayerSiN).insert(arc_wg(r, w, 270., 270.+theta).transformed(t))

    t = Trans(Trans.R0,round(x+length/2), round(y-r+ 2*r*(1-cos(theta/180.0*pi))))
    self.cell.shapes(LayerSiN).insert(arc_wg(r, w, 90.-theta, 90.+theta).transformed(t))

    t = Trans(Trans.R0,round(x+length), round(y+r))
    self.cell.shapes(LayerSiN).insert(arc_wg(r, w, 270.-theta, 270).transformed(t))


    # Create the pins on the waveguides, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length
    x = self.length / dbu
    t = Trans(Trans.R0, x,0)
    pin = Path([Point(-pin_length/2,0), Point(pin_length/2,0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin2", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    shape.text_halign = 2

    x = 0
    t = Trans(Trans.R0, x,0)
    pin = Path([Point(pin_length/2,0), Point(-pin_length/2,0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin1", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    # Compact model information
    t = Trans(Trans.R0, 0, 0)
    text = Text ('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, 0, w*2)
    text = Text ('Component=ebeam_wg_integral_1550', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, 0, -w*2)
    text = Text \
      ('Spice_param:wg_length=%.3fu wg_width=%.3fu' %\
      (waveguide_length*dbu, self.wg_width), t )
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu

    t = Trans(Trans.R0, self.length /6, -w*2)
    text = Text ('dL = %.4f um' % ((waveguide_length-length)*dbu), t)
    shape = shapes(LayerTextN).insert(text)
    shape.text_size = 0.6/dbu

    # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
    box1 = Box(0, -w*3, length, w*3+(2*r*(1-cos(theta/180.0*pi))))
    shapes(LayerDevRecN).insert(box1)

    print("SiEPIC EBeam: Waveguide_bump complete.")
Example #9
0
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts,
                      radius, adiab, bezier):
    from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal
    from SiEPIC.extend import to_itype
    from pya import Path, Polygon, Trans
    dbu = layout.dbu

    if 'Errors' in TECHNOLOGY:
        error_layer = layout.layer(TECHNOLOGY['Errors'])
    else:
        error_layer = None

    width = widths[0]
    turn = 0
    waveguide_length = 0
    for lr in range(0, len(layers)):
        wg_pts = [pts[0]]
        layer = layout.layer(TECHNOLOGY[layers[lr]])
        width = to_itype(widths[lr], dbu)
        offset = to_itype(offsets[lr], dbu)
        for i in range(1, len(pts) - 1):
            turn = (
                (angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] - pts[i]) +
                 90) % 360 - 90) / 90
            dis1 = pts[i].distance(pts[i - 1])
            dis2 = pts[i].distance(pts[i + 1])
            angle = angle_vector(pts[i] - pts[i - 1]) / 90
            pt_radius = to_itype(radius, dbu)
            error_seg1 = False
            error_seg2 = False
            # determine the radius, based on how much space is available
            if len(pts) == 3:
                # simple corner, limit radius by the two edges
                if dis1 < pt_radius:
                    error_seg1 = True
                if dis2 < pt_radius:
                    error_seg2 = True
                pt_radius = min(dis1, dis2, pt_radius)
            else:
                if i == 1:
                    # first corner, limit radius by first edge, or 1/2 of second one
                    if dis1 < pt_radius:
                        error_seg1 = True
                    if dis2 / 2 < pt_radius:
                        error_seg2 = True
                    pt_radius = min(dis1, dis2 / 2, pt_radius)
                elif i == len(pts) - 2:
                    # last corner, limit radius by second edge, or 1/2 of first one
                    if dis1 / 2 < pt_radius:
                        error_seg1 = True
                    if dis2 < pt_radius:
                        error_seg2 = True
                    pt_radius = min(dis1 / 2, dis2, pt_radius)
                else:
                    if dis1 / 2 < pt_radius:
                        error_seg1 = True
                    if dis2 / 2 < pt_radius:
                        error_seg2 = True
                    pt_radius = min(dis1 / 2, dis2 / 2, pt_radius)

            if error_seg1 or error_seg2:
                if not error_layer:
                    # we have an error, but no Error layer
                    print('- SiEPIC:layout_waveguide2: missing Error layer')
                # and pt_radius < to_itype(radius,dbu):
                elif layer == layout.layer(TECHNOLOGY['Waveguide']):
                    # add an error polygon to flag the incorrect bend
                    if error_seg1:
                        error_pts = pya.Path([pts[i - 1], pts[i]], width)
                        cell.shapes(error_layer).insert(error_pts)
                    if error_seg2:
                        error_pts = pya.Path([pts[i], pts[i + 1]], width)
                        cell.shapes(error_layer).insert(error_pts)
    #                error_pts = pya.Path([pts[i-1], pts[i], pts[i+1]], width)
    #                cell.shapes(error_layer).insert(error_pts)
    # waveguide bends:
            if abs(turn) == 1:
                if (adiab):
                    wg_pts += Path(
                        arc_bezier(
                            pt_radius,
                            270,
                            270 + inner_angle_b_vectors(
                                pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                            float(bezier),
                            DevRec='DevRec' in layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()
                else:
                    wg_pts += Path(
                        arc_xy(-pt_radius,
                               pt_radius,
                               pt_radius,
                               270,
                               270 + inner_angle_b_vectors(
                                   pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                               DevRec='DevRec' in layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()

        wg_pts += [pts[-1]]
        wg_pts = pya.Path(wg_pts, 0).unique_points().get_points()
        wg_polygon = Polygon(
            translate_from_normal(
                wg_pts, width / 2 + (offset if turn > 0 else -offset)) +
            translate_from_normal(
                wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1])
        cell.shapes(layer).insert(wg_polygon)

        if layout.layer(TECHNOLOGY['Waveguide']) == layer:
            waveguide_length = wg_polygon.area() / width * dbu

    return waveguide_length
Example #10
0
    def produce_impl(self):
        from SiEPIC._globals import PIN_LENGTH
        from SiEPIC.extend import to_itype
        import math
        from pya import DPolygon
        # This is the main part of the implementation: create the layout

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes
        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        #variables
        pitch = self.pitch
        w = self.w
        r = self.r
        ff = self.ff
        angle = self.angle
        gap = self.gap
        W_ratio = self.W_ratio
        doublebus = self.doublebus
        print(doublebus)

        # set the deltaL of sT-shaped silicon pillar (deltaL = (Lin-Lout)/4)
        deltaL = (2 * pitch * ff) * (W_ratio - 1) / ((1 + W_ratio) * (4))

        if (r - w / 2 <= 0):
            r = 5
            print('invalid radius, set r to default: 5')

        #Calculate number of segments
        s1 = pitch * ff  #silicon
        s2 = pitch - s1  #gap

        #calculate best radius
        pi = math.pi
        const = math.ceil(2 * pi * r / (s1 + s2))
        #if doesn't divide evenly, replace r with best possible r
        if ((2 * pi * r) % (s1 + s2) != 0):
            r = const * (s1 + s2) / (2 * pi)
            print('r adjusted to ' + str(r) + 'um to fit periods perfectly.')

        #theta1 = (s1/r)
        #theta2 = (s2/r)
        theta1 = math.atan(s1 /
                           r)  # angle of silicon compared to the origin point
        theta2 = math.atan(s2 /
                           r)  # angle of the gap compared to the origin point
        nSeg = int(
            math.floor(angle /
                       (math.degrees(theta1) +
                        math.degrees(theta2))))  #how many segments to have
        si_first = True  #for alternating between silicon and gap
        j = 0  #index of how many silicon thetas
        jj = 0  #index of how many gap thetas
        ORDER = True  #ordering of the coordinates for polygon drawing

        #xo = [(r-w/2)*math.cos(0)]
        #yo = [(r-w/2)*math.sin(0)]
        #xo.append((r+w/2)*math.cos(0))
        #yo.append((r+w/2)*math.sin(0))

        xo = [(r - w / 2) * math.cos(0) + deltaL * math.sin(0)]
        yo = [(r - w / 2) * math.sin(0) - deltaL * math.cos(0)]
        xo.append((r + w / 2) * math.cos(0) - deltaL * math.sin(0))
        yo.append((r + w / 2) * math.sin(0) + deltaL * math.cos(0))

        for i in range(0, nSeg * 2):
            if si_first:
                j = j + 1
                si_first = not (si_first)
            else:
                jj = jj + 1
                si_first = not (si_first)

            if ORDER:
                xo.append((r + w / 2) * math.cos(j * theta1 + jj * theta2) +
                          deltaL * math.sin(j * theta1 + jj * theta2))
                yo.append((r + w / 2) * math.sin(j * theta1 + jj * theta2) -
                          deltaL * math.cos(j * theta1 + jj * theta2))
                xo.append((r - w / 2) * math.cos(j * theta1 + jj * theta2) -
                          deltaL * math.sin(j * theta1 + jj * theta2))
                yo.append((r - w / 2) * math.sin(j * theta1 + jj * theta2) +
                          deltaL * math.cos(j * theta1 + jj * theta2))
                ORDER = not (ORDER)
            else:
                xo.append((r - w / 2) * math.cos(j * theta1 + jj * theta2) +
                          deltaL * math.sin(j * theta1 + jj * theta2))
                yo.append((r - w / 2) * math.sin(j * theta1 + jj * theta2) -
                          deltaL * math.cos(j * theta1 + jj * theta2))
                xo.append((r + w / 2) * math.cos(j * theta1 + jj * theta2) -
                          deltaL * math.sin(j * theta1 + jj * theta2))
                yo.append((r + w / 2) * math.sin(j * theta1 + jj * theta2) +
                          deltaL * math.cos(j * theta1 + jj * theta2))
                ORDER = not (ORDER)

            if len(xo) == 4:
                dpts = [pya.DPoint(xo[i], yo[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)
                xo = []
                yo = []

        #Draw Bus WG
        #calulate ideal length of bus
        bus_length = self.cell.bbox().height() * dbu + pitch * 2
        constant = math.ceil(bus_length / (s1 + s2))
        if bus_length % (s1 + s2) != 0:
            bus_length = constant * (s1 + s2)

        #draw first box at center
        xo = [(r + w / 2 + gap), (r + w / 2 + gap + w), (r + w / 2 + gap + w),
              (r + w / 2 + gap)]
        yo = [0, 0, s1, s1]
        dpts = [pya.DPoint(xo[i], yo[i]) for i in range(len(xo))]
        dpolygon = DPolygon(dpts)
        element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
        shapes(LayerSiN).insert(element)

        for i in range(0, int(math.ceil((constant) / 2))):
            yu = [yo[j] + i * pitch for j in range(len(yo))]
            yd = [yo[j] - i * pitch for j in range(len(yo))]

            dpts = [pya.DPoint(xo[i], yu[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)
            dpts = [pya.DPoint(xo[i], yd[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

        if doublebus:
            for i in range(0, int(math.ceil((constant) / 2))):
                x2 = [xo[j] * -1 for j in range(len(xo))]
                yu = [yo[j] + i * pitch for j in range(len(yo))]
                yd = [yo[j] - i * pitch for j in range(len(yo))]

                dpts = [pya.DPoint(x2[i], yu[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)
                dpts = [pya.DPoint(x2[i], yd[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

        #DEV BOX
        if doublebus is False:
            half_l = (self.cell.bbox().width() - w / dbu - gap / dbu) / 2
            half_r = self.cell.bbox().width() - half_l
            dev = Box(-half_l, yd[-4] / dbu, half_r, yu[-1] / dbu)
            shapes(LayerDevRecN).insert(dev)
            dev_width = self.cell.bbox().width() / 2
        else:
            half_l = (self.cell.bbox().width()) / 2
            half_r = self.cell.bbox().width() - half_l
            dev = Box(-half_l, yd[-4] / dbu, half_r, yu[-1] / dbu)
            shapes(LayerDevRecN).insert(dev)
            dev_width = self.cell.bbox().width() / 2

    # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.w, dbu)
        gap = to_itype(self.gap, dbu)
        bus_length = to_itype(bus_length / 2, dbu)

        #Pin1
        t = Trans(Trans.R0, half_r - w / 2, yu[-1] / dbu)
        pin = Path([Point(0, -pin_length / 2), Point(0, pin_length / 2)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        #Pin2
        t = Trans(Trans.R0, half_r - w / 2, yd[-4] / dbu)
        pin = Path([Point(0, pin_length / 2), Point(0, -pin_length / 2)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        if doublebus is True:
            half_l = self.cell.bbox().width() / 2
            half_r = self.cell.bbox().width() - half_l
            #pin 3
            t = Trans(Trans.R0, -half_l + w / 2, yu[-1] / dbu)
            pin = Path([Point(0, -pin_length / 2),
                        Point(0, pin_length / 2)], w)
            pin_t = pin.transformed(t)
            shapes(LayerPinRecN).insert(pin_t)
            text = Text("pin3", t)
            shape = shapes(LayerPinRecN).insert(text)
            shape.text_size = 0.4 / dbu

            #Pin4
            t = Trans(Trans.R0, -half_l + w / 2, yd[-4] / dbu)
            pin = Path([Point(0, pin_length / 2),
                        Point(0, -pin_length / 2)], w)
            pin_t = pin.transformed(t)
            shapes(LayerPinRecN).insert(pin_t)
            text = Text("pin4", t)
            shape = shapes(LayerPinRecN).insert(text)
            shape.text_size = 0.4 / dbu
Example #11
0
    def produce(self, layout, layers, parameters, cell):

        #coerce parameters (make consistent)

        self._layers = layers
        self.cell = cell
        self._param_values = parameters
        self.layout = layout

        # cell: layout cell to place the layout
        # LayerSiN: which layer to use
        # r: radius
        # w: waveguide width
        # length units in dbu

        from math import pi, cos, sin
        from SiEPIC.utils import arc_wg, arc_wg_xy
        from SiEPIC._globals import PIN_LENGTH
        from SiEPIC.utils.layout import layout_waveguide2
        from SiEPIC.extend import to_itype

        # fetch the parameters
        TECHNOLOGY = get_technology_by_name('EBeam')
        dbu = self.layout.dbu
        ly = self.layout

        LayerSiN = ly.layer(self.silayer)
        LayerSlab = ly.layer(self.slayer)
        #    LayerNN = ly.layer(self.nlayer)
        LayerNPPN = ly.layer(self.npplayer)
        LayerVCN = ly.layer(self.vclayer)
        LayerMN = ly.layer(self.mlayer)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)
        TextLayerN = ly.layer(self.textl)

        ## define parameters for phase shifter

        # mask overlay accuracy
        overlay = to_itype(self.overlay, dbu)
        overlay_ebl = to_itype(self.overlay_ebl, dbu)

        ## define waveguide related parameters
        radius, adiab, bezier = 5 / dbu, 1, 0.2
        w = to_itype(self.width, dbu)  #waveguide width, default 0.5 um
        l = to_itype(self.length, dbu)  #pahse shifter length, default 150 um
        npp_d = to_itype(self.npp_distance,
                         dbu)  #npp to edge of waveguide distance
        sw = 2 * npp_d + w  # twice of npp_d that is defined above
        in_rib = to_itype(
            self.input_rib_width, dbu
        )  #the slab width of the input/output waveguide to the phase shifter
        in_taper = to_itype(
            self.in_taper_length, dbu
        )  #the input waveguide to phase shifter dimension transfer taper length, default 15
        edge_slab_width = to_itype(
            4, dbu
        )  # width of the 90 nm slab that is outside of all the folding waveguide, default 2 * 2um
        npp_width = to_itype(self.npp_width, dbu)  #npp width, default 5 um

        ## define node related parameters
        contact_size = to_itype(self.vc_w,
                                dbu)  # square NPP size, for VC purpose
        pin_text_size = to_itype(0.4, dbu)  # pin text size

        # define metal contact parameters
        metal_routing_width = to_itype(self.m_w, dbu)  # width of metal
        ps_sl_w = sw + npp_width * 2 + 2 * overlay  # define overall phase shifter 90nm slab width
        metal_routing_distance_to_node = metal_routing_width + ps_sl_w / 2
        vc_si_distance = to_itype(self.vc_si_distance, dbu)
        vc_to_npp_exclusion = to_itype(
            0, dbu)  # VC boundary to NPP boundary distance

        ## define strip to slab transfer taper parameters
        N = 100
        # Number of points for the input/output slab taper
        order = 3
        # input/output slab taper curve

        wg1 = pya.Box(-l / 2, -w / 2, l / 2, w / 2)
        wg2 = pya.Box(-l / 2, -ps_sl_w / 2, l / 2, ps_sl_w / 2)
        wg3 = pya.Box(-l / 2, npp_d + w / 2, l / 2, npp_d + w / 2 + npp_width)
        wg4 = pya.Box(-l / 2, -npp_d - w / 2, l / 2,
                      -npp_d - w / 2 - npp_width)
        self.cell.shapes(LayerSiN).insert(wg1)

        self.cell.shapes(LayerNPPN).insert(wg3)
        self.cell.shapes(LayerNPPN).insert(wg4)

        if self.io_wg_type:
            in_slab = to_itype(self.input_slab_width, dbu)
        else:
            in_slab = in_rib

        if 1:
            self.cell.shapes(LayerSlab).insert(wg2)
            # add input strip taper
            pts = [
                Point(-l / 2 - in_taper, -in_rib / 2),
                Point(-l / 2, -w / 2),
                Point(-l / 2, w / 2),
                Point(-l / 2 - in_taper, in_rib / 2)
            ]
            #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
            self.cell.shapes(LayerSiN).insert(Polygon(pts))

            # add input slab taper
            pts = []
            for i in range(0, N + 1):
                pts.append(
                    Point(-l / 2 - in_taper + in_taper / N * i,
                          (in_slab - overlay_ebl * 2) / 2 +
                          ((sw / 2 - (in_slab - overlay_ebl * 2)) /
                           (N**order)) * (i**order)))
            for i in range(0, N + 1):
                pts.append(
                    Point(
                        -l / 2 - in_taper + in_taper / N * (N - i),
                        -(in_slab - overlay_ebl * 2) / 2 -
                        ((sw / 2 - (in_slab - overlay_ebl * 2)) /
                         (N**order)) * ((N - i)**order)))
            self.cell.shapes(LayerSlab).insert(Polygon(pts))

            # add output strip taper
            pts = [
                Point(l / 2 + in_taper, -in_rib / 2),
                Point(l / 2, -w / 2),
                Point(l / 2, w / 2),
                Point(l / 2 + in_taper, in_rib / 2)
            ]
            #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
            self.cell.shapes(LayerSiN).insert(Polygon(pts))

            # cubic taper
            pts = []
            for i in range(0, N + 1):
                pts.append(
                    Point(l / 2 + in_taper - in_taper / N * i,
                          (in_slab - overlay_ebl * 2) / 2 +
                          ((sw / 2 - (in_slab - overlay_ebl * 2)) /
                           (N**order)) * (i**order)))
            for i in range(0, N + 1):
                pts.append(
                    Point(
                        l / 2 + in_taper / N * i,
                        -(in_slab - overlay_ebl * 2) / 2 -
                        ((sw / 2 - (in_slab - overlay_ebl * 2)) /
                         (N**order)) * ((N - i)**order)))
            self.cell.shapes(LayerSlab).insert(Polygon(pts))

            from SiEPIC._globals import PIN_LENGTH as pin_length

            # Pin on the left side:
            p1 = [
                Point(-l / 2 - in_taper + pin_length / 2, 0),
                Point(-l / 2 - in_taper - pin_length / 2, 0)
            ]
            p1c = Point(-l / 2 - in_taper, 0)
            self.set_p1 = p1c
            self.p1 = p1c
            pin = Path(p1, in_rib)
            self.cell.shapes(LayerPinRecN).insert(pin)
            t = Trans(Trans.R0, -l / 2 - in_taper, 0)
            text = Text("pin1", t)
            shape = self.cell.shapes(LayerPinRecN).insert(text)
            shape.text_size = pin_text_size

            # Pin on the right side:
            p2 = [
                Point(l / 2 + in_taper - pin_length / 2, 0),
                Point(l / 2 + in_taper + pin_length / 2, 0)
            ]
            p2c = Point(l / 2 + in_taper, 0)
            self.set_p2 = p2c
            self.p2 = p2c
            pin = Path(p2, in_rib)
            self.cell.shapes(LayerPinRecN).insert(pin)
            t = Trans(Trans.R0, l / 2 + in_taper, 0)
            text = Text("pin2", t)
            shape = self.cell.shapes(LayerPinRecN).insert(text)
            shape.text_size = pin_text_size

        for i in range(0, self.segments + 1):

            vc_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 +
                vc_to_npp_exclusion, w / 2 + vc_si_distance,
                (l - contact_size) / self.segments * i - l / 2 + contact_size -
                vc_to_npp_exclusion, w / 2 + vc_si_distance + contact_size)
            self.cell.shapes(LayerVCN).insert(vc_temp_upper)
            wg_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 - overlay,
                sw / 2, (l - contact_size) / self.segments * i - l / 2 +
                contact_size + overlay,
                w / 2 + vc_si_distance + contact_size + overlay)
            self.cell.shapes(LayerNPPN).insert(wg_temp_upper)
            wg_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 - 2 * overlay,
                sw / 2, (l - contact_size) / self.segments * i - l / 2 +
                contact_size + 2 * overlay,
                w / 2 + vc_si_distance + contact_size + 2 * overlay)
            self.cell.shapes(LayerSlab).insert(wg_temp_upper)

            vc_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 +
                vc_to_npp_exclusion, -w / 2 - vc_si_distance,
                (l - contact_size) / self.segments * i - l / 2 + contact_size -
                vc_to_npp_exclusion, -w / 2 - vc_si_distance - contact_size)
            self.cell.shapes(LayerVCN).insert(vc_temp_lower)
            wg_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 - overlay,
                -sw / 2, (l - contact_size) / self.segments * i - l / 2 +
                contact_size + overlay,
                -(w / 2 + vc_si_distance + contact_size + overlay))
            self.cell.shapes(LayerNPPN).insert(wg_temp_lower)
            wg_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 - 2 * overlay,
                -sw / 2, (l - contact_size) / self.segments * i - l / 2 +
                contact_size + 2 * overlay,
                -(w / 2 + vc_si_distance + contact_size + 2 * overlay))
            self.cell.shapes(LayerSlab).insert(wg_temp_lower)

            metal_temp = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 - overlay,
                -(w / 2 + vc_si_distance + contact_size + 1 * overlay) -
                metal_routing_distance_to_node * (i % 2),
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                overlay, w / 2 + vc_si_distance + contact_size + 1 * overlay +
                metal_routing_distance_to_node * ((i + 1) % 2))
            self.cell.shapes(LayerMN).insert(metal_temp)

        metal_routing = Path([
            Point(-l / 2,
                  -sw / 2 - metal_routing_distance_to_node - contact_size),
            Point(l / 2,
                  -sw / 2 - metal_routing_distance_to_node - contact_size)
        ], metal_routing_width)
        self.cell.shapes(LayerMN).insert(metal_routing)
        metal_routing = Path([
            Point(-l / 2,
                  sw / 2 + metal_routing_distance_to_node + contact_size),
            Point(l / 2,
                  sw / 2 + metal_routing_distance_to_node + contact_size)
        ], metal_routing_width)
        self.cell.shapes(LayerMN).insert(metal_routing)

        dev = Box(
            -l / 2 - in_taper, -sw / 2 - metal_routing_distance_to_node -
            contact_size - metal_routing_width, +l / 2 + in_taper,
            sw / 2 + metal_routing_distance_to_node + contact_size +
            metal_routing_width)

        self.cell.shapes(LayerDevRecN).insert(dev)
  def produce_impl(self):

    # This is the main part of the implementation: create the layout
    from math import pi, cos, sin
    from SiEPIC.extend import to_itype
    
    # fetch the parameters
#    TECHNOLOGY = get_technology_by_name('GSiP')
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes
    
    LayerSi3N = ly.layer(self.si3layer)
    LayerSiN = ly.layer(self.silayer)
    LayernN = ly.layer(self.nlayer)
    LayerpN = ly.layer(self.player)
    LayernpN = ly.layer(self.nplayer)
    LayerppN = ly.layer(self.pplayer)
    LayernppN = ly.layer(self.npplayer)
    LayerpppN = ly.layer(self.ppplayer)
    LayervcN = ly.layer(self.vclayer)
    Layerm1N = ly.layer(self.m1layer)
    LayervlN = ly.layer(self.vllayer)
    LayermlN = ly.layer(self.mllayer)
    LayermhN = ly.layer(self.mhlayer)
    TextLayerN = ly.layer(self.textl)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)

    # Define variables for the Modulator
    # Variables for the Si waveguide
    w = to_itype(self.w,dbu)
    r = to_itype(self.r,dbu)
    g = to_itype(self.g,dbu)
    gmon = to_itype(self.gmon,dbu)
    
    #Variables for the N layer
    w_1 = 2.0/dbu  #same for N, P, N+, P+ layer
    r_n = to_itype(self.r - 1.0,dbu)
    
    #Variables for the P layer
    r_p = to_itype(self.r + 1.0, dbu)
     
    #Variables for the N+layer
    r_np = to_itype(self.r - 1.5,dbu)
    
    #Variables for the P+layer
    r_pp = to_itype(self.r + 1.5,dbu)

    #Variables for the N++ layer
    w_2 = to_itype(5.5,dbu)  #same for N++, P++ layer
    r_npp = to_itype(self.r - 3.75,dbu)

    #Variables for the P+layer
    r_ppp = to_itype(self.r + 3.75,dbu)

    #Variables for the VC layer
    w_vc = to_itype(4.0,dbu)
    r_vc1 = to_itype(self.r - 3.75,dbu)
    r_vc2 = to_itype(self.r + 3.75,dbu)
   
    #Variables for the M1 layer
    w_m1_in = r_vc1 + w_vc/2.0 + to_itype(0.5,dbu)
    r_m1_in = r_vc1 + w_vc/2.0 + to_itype(0.5,dbu) /2.0
    w_m1_out = to_itype(6.0,dbu)
    r_m1_out = to_itype(self.r + 4.25,dbu)
    
    #Variables for the VL layer
    #r_vl =  w_m1_in/2.0 -  2.1/dbu
    r_vl =  r_vc1 - w_vc/2.0 - to_itype(2.01,dbu)
    if r_vl < to_itype(1.42,dbu):
      r_vl = to_itype(1.42,dbu)
      w_vc = r - to_itype(1.75,dbu) - (r_vl + 2.01)
      r_vc1 = r - to_itype(1.75,dbu) - w_vc/2.0
      r_vc2 = r + to_itype(1.75,dbu) + w_vc/2.0
      w_2 = (r-w/2.0 - to_itype(0.75,dbu)) - (r_vc1 - w_vc/2.0 - 0.75) # same for N++, P++ layer
      r_npp = ((r-w/2.0 - to_itype(0.75,dbu)) + (r_vc1 - w_vc/2.0 - 0.75))/2.0
      r_ppp = 2*r - r_npp
    w_via = to_itype(5.0,dbu)
    h_via = to_itype(5.0,dbu)

    # Variables for the SiEtch2 layer  (Slab)
    w_Si3 = round(w_m1_out + 2*(r_m1_out)+ 0/dbu)
    h_Si3 = w_Si3
    taper_bigend =  to_itype(2,dbu)
    taper_smallend =  to_itype(0.3,dbu)
    taper_length =  to_itype(5,dbu)

    #Variables for the MH layer
    w_mh = to_itype(2.0,dbu)
    r_mh = r
    r_mh_in = r_mh - w_mh/2.0
    
    #Define Ring centre   
    x0 = r + w/2
    y0 = r + g + w 

    ######################
    # Generate the layout:
   
    # Create the ring resonator
    t = pya.Trans(pya.Trans.R0,x0, y0)
    pcell = ly.create_cell("Ring", "GSiP", { "layer": self.silayer, "radius": self.r, "width": self.w } )
    self.cell.insert(pya.CellInstArray(pcell.cell_index(), t))

    
    # Create the two waveguides
    wg1 = pya.Box(x0 - (w_Si3 / 2 + taper_length), -w/2, x0 + (w_Si3 / 2 + taper_length), w/2)
    shapes(LayerSiN).insert(wg1)
    y_offset = 2*r + g + gmon + 2*w
    wg2 = pya.Box(x0 - (w_Si3 / 2 + taper_length), y_offset-w/2, x0 + (w_Si3 / 2 + taper_length), y_offset+w/2)
    shapes(LayerSiN).insert(wg2)

    
    #Create the SiEtch2 (Slab) layer
    boxSi3 = pya.Box(x0-w_Si3/2.0, y0 - h_Si3/2.0, x0+w_Si3/2.0, y0 + h_Si3/2.0)
    shapes(LayerSi3N).insert(boxSi3)
    pin1pts = [pya.Point(x0-w_Si3/2.0, -taper_bigend/2.0),
               pya.Point(x0-w_Si3/2.0-taper_length,-taper_smallend/2.0),
               pya.Point(x0-w_Si3/2.0-taper_length,taper_smallend/2.0),
               pya.Point(x0-w_Si3/2.0, taper_bigend/2.0)]
    pin2pts = [pya.Point(x0+w_Si3/2.0,-taper_bigend/2.0),
               pya.Point(x0+w_Si3/2.0+taper_length,-taper_smallend/2.0),
               pya.Point(x0+w_Si3/2.0+taper_length,taper_smallend/2.0),
               pya.Point(x0+w_Si3/2.0,+taper_bigend/2.0)]
    pin3pts = [pya.Point(x0-w_Si3/2.0,y_offset-taper_bigend/2.0),
               pya.Point(x0-w_Si3/2.0-taper_length,y_offset-taper_smallend/2.0),
               pya.Point(x0-w_Si3/2.0-taper_length,y_offset+taper_smallend/2.0),
               pya.Point(x0-w_Si3/2.0,y_offset+ taper_bigend/2.0)]
    pin4pts = [pya.Point(x0+w_Si3/2.0,y_offset-taper_bigend/2.0),
               pya.Point(x0+w_Si3/2.0+taper_length,y_offset-taper_smallend/2.0),
               pya.Point(x0+w_Si3/2.0+taper_length,y_offset+taper_smallend/2.0),
               pya.Point(x0+w_Si3/2.0,y_offset+taper_bigend/2.0)]
    shapes(LayerSi3N).insert(pya.Polygon(pin1pts))
    shapes(LayerSi3N).insert(pya.Polygon(pin2pts))
    shapes(LayerSi3N).insert(pya.Polygon(pin3pts))
    shapes(LayerSi3N).insert(pya.Polygon(pin4pts))
    
    # arc angles
    # doping:
    angle_min_doping = -35
    angle_max_doping = 215
    # VC contact:
    angle_min_VC = angle_min_doping + 8
    angle_max_VC = angle_max_doping - 8
    # M1:
    angle_min_M1 = angle_min_VC - 4
    angle_max_M1 = angle_max_VC + 4
    # MH:
    angle_min_MH = -75.0
    angle_max_MH = 255

    from SiEPIC.utils import arc

    #Create the N Layer
    self.cell.shapes(LayernN).insert(pya.Path(arc(r_n, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon())

    #Create the P Layer
    self.cell.shapes(LayerpN).insert(pya.Path(arc(r_p, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon())
    
    #Create the N+ Layer
    self.cell.shapes(LayernpN).insert(pya.Path(arc(r_np, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon())

    #Create the P+ Layer
    self.cell.shapes(LayerppN).insert(pya.Path(arc(r_pp, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon())
    
    #Create the N++ Layer
    self.cell.shapes(LayernppN).insert(pya.Path(arc(r_npp, angle_min_doping, angle_max_doping), w_2).transformed(t).simple_polygon())

    #Create the P+ +Layer
    poly = pya.Path(arc(r_ppp, angle_min_doping, angle_max_doping), w_2).transformed(t).simple_polygon()
    self.cell.shapes(LayerpppN).insert(pya.Region(poly) - pya.Region(pya.Box(x0-r_ppp-w_2/2, y_offset-w/2 - 0.75/dbu, x0+r_ppp+w/2, y_offset+w/2 + 0.75/dbu)))
    
    #Create the VC Layer
    self.cell.shapes(LayervcN).insert(pya.Path(arc(r_vc1, angle_min_VC, angle_max_VC), w_vc).transformed(t).simple_polygon())

    poly = pya.Path(arc(r_vc2, angle_min_VC, angle_max_VC), w_vc).transformed(t).simple_polygon()
    self.cell.shapes(LayervcN).insert(pya.Region(poly) - pya.Region(pya.Box(x0-r_vc2-w_vc/2, y_offset-w/2 - 1.5/dbu, x0+r_vc2+w_vc/2, y_offset+w/2 + 1.5/dbu)))

        
    #Create the M1 Layer
    self.cell.shapes(Layerm1N).insert(pya.Polygon(arc(w_m1_in, angle_min_doping, angle_max_doping) + [pya.Point(0, 0)]).transformed(t))
    self.cell.shapes(Layerm1N).insert(pya.Polygon(arc(w_m1_in/2.0, 0, 360)).transformed(t))
    self.cell.shapes(Layerm1N).insert(pya.Path(arc(r_m1_out, angle_min_M1, angle_max_M1), w_m1_out).transformed(t).simple_polygon())
    boxM11 = pya.Box(x0-w_via, y0 + r_m1_out + w_m1_out-h_via, x0+w_via, y0 + r_m1_out + w_m1_out+h_via)
    shapes(Layerm1N).insert(boxM11)
    
    #Create the ML Layer
    self.cell.shapes(LayermlN).insert(pya.Polygon(arc(w_m1_in/2.0, 0, 360)).transformed(t))
    
    #Create the VL Layer, as well as the electrical PinRec geometries
    # centre contact (P, anode):
    self.cell.shapes(LayervlN).insert(pya.Polygon(arc(r_vl, 0, 360)).transformed(t))
    self.cell.shapes(LayerPinRecN).insert(pya.Polygon(arc(r_vl, 0, 360)).transformed(t))
    shapes(LayerPinRecN).insert(pya.Text ("elec1a", pya.Trans(pya.Trans.R0,x0,y0))).text_size = 0.5/dbu
    shapes(LayerPinRecN).insert(pya.Box(x0-w_via/2, y0-w_via/2, x0+w_via/2, y0+w_via/2))
    
    # top contact (N, cathode):
    boxVL1 = pya.Box(x0-w_via/2, y0 +  r_vc2 +  w_vc/2 + 2.0/dbu, x0+w_via/2, y0 + r_vc2 +  w_vc/2 + 2.0/dbu+ h_via)
    shapes(LayervlN).insert(boxVL1)
    shapes(LayerPinRecN).insert(boxVL1)
    shapes(LayerPinRecN).insert(pya.Text ("elec1c", pya.Trans(pya.Trans.R0,x0,y0 + r_vc2 +  w_vc/2 + 2.0/dbu+ h_via/2))).text_size = 0.5/dbu
    # heater contacts
    boxVL3 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi) + 2.5/dbu, -w/2.0 -  10/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + 7.5/dbu, -w/2.0 -  5/dbu)
    shapes(LayervlN).insert(boxVL3)
    shapes(LayerPinRecN).insert(boxVL3)
    shapes(LayerPinRecN).insert(pya.Text ("elec2h2", pya.Trans(pya.Trans.R0,x0+(r_mh_in)*cos(angle_min_MH/180*pi) + 5.0/dbu,-w/2.0 -  7.5/dbu))).text_size = 0.5/dbu
    boxVL4 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi)- 7.5/dbu, -w/2.0 -  10/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi) - 2.5/dbu, -w/2.0 -  5/dbu)
    shapes(LayervlN).insert(boxVL4)
    shapes(LayerPinRecN).insert(boxVL4)
    shapes(LayerPinRecN).insert(pya.Text ("elec2h1", pya.Trans(pya.Trans.R0,x0-(r_mh_in)*cos(angle_min_MH/180*pi) - 5.0/dbu,-w/2.0 -  7.5/dbu))).text_size = 0.5/dbu

    #Create the MH Layer
    self.cell.shapes(LayermhN).insert(pya.Path(arc(r_mh, angle_min_MH, angle_max_MH), w_mh).transformed(t).simple_polygon())
    boxMH1 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 -  2.5/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + w_mh, y0 +(r_mh_in)*sin(angle_min_MH/180*pi))
    shapes(LayermhN).insert(boxMH1)
    boxMH2 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi)  - w_mh, -w/2.0 -  2.5/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi), y0 +(r_mh_in)*sin(angle_min_MH/180*pi))
    shapes(LayermhN).insert(boxMH2)
    boxMH3 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 -  12.5/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + 10/dbu, -w/2.0 -  2.5/dbu)
    shapes(LayermhN).insert(boxMH3)
    boxMH4 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi)- 10/dbu, -w/2.0 -  12.5/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 -  2.5/dbu)
    shapes(LayermhN).insert(boxMH4)
    
    # Create the pins, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length
        
    shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 - (w_Si3 / 2. + taper_length) + pin_length/2., 0),
                                          pya.Point(x0 - (w_Si3 / 2. + taper_length) - pin_length/2., 0)], w))
    shapes(LayerPinRecN).insert(pya.Text("opt1", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2. + taper_length), 0))).text_size = 0.5/dbu

    shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 + (w_Si3 / 2. + taper_length) - pin_length/2., 0),
                                          pya.Point(x0 + (w_Si3 / 2. + taper_length)           + pin_length/2., 0)], w))
    shapes(LayerPinRecN).insert(pya.Text("opt2", pya.Trans(pya.Trans.R0,x0 + (w_Si3 / 2. + taper_length), 0))).text_size = 0.5/dbu

    shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 - (w_Si3 / 2. + taper_length) + pin_length/2., y_offset),
                                          pya.Point(x0 - (w_Si3 / 2. + taper_length) - pin_length/2., y_offset)], w))
    shapes(LayerPinRecN).insert(pya.Text("opt3", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2. + taper_length), y_offset))).text_size = 0.5/dbu

    shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 + (w_Si3 / 2. + taper_length) - pin_length/2., y_offset),
                                          pya.Point(x0 + (w_Si3 / 2. + taper_length) + pin_length/2., y_offset)], w))
    shapes(LayerPinRecN).insert(pya.Text("opt4", pya.Trans(pya.Trans.R0,x0 + (w_Si3 / 2. + taper_length), y_offset))).text_size = 0.5/dbu

    # Create the device recognition layer
    shapes(LayerDevRecN).insert(pya.Box(x0 - (w_Si3 / 2 + taper_length), -w/2.0 -  12.5/dbu, x0 + (w_Si3 / 2 + taper_length), y0 + r_m1_out + w_m1_out+h_via ))

    # Compact model information
    shape = shapes(LayerDevRecN).insert(pya.Text('Lumerical_INTERCONNECT_library=Design kits/GSiP', \
      pya.Trans(pya.Trans.R0,0, 0))).text_size = 0.3/dbu
    shapes(LayerDevRecN).insert(pya.Text('Component=Ring_Modulator_DB', \
      pya.Trans(pya.Trans.R0,0, w*2))).text_size = 0.3/dbu
    shapes(LayerDevRecN).insert(pya.Text('Component_ID=%s' % self.component_ID, \
      pya.Trans(pya.Trans.R0,0, w*4))).text_size = 0.3/dbu
    shapes(LayerDevRecN).insert(pya.Text \
      ('Spice_param:radius=%.3fu wg_width=%.3fu gap=%.3fu gap_monitor=%.3fu' %\
      (self.r, self.w, self.g, self.gmon), \
      pya.Trans(pya.Trans.R0,0, -w*2) ) ).text_size = 0.3/dbu
    
    # Add a polygon text description
    from SiEPIC.utils import layout_pgtext
    if self.textpolygon : layout_pgtext(self.cell, self.textl, self.w, self.r+self.w, "%.3f-%g" % ( self.r, self.g), 1)

    # Reference publication:
    shapes(TextLayerN).insert(pya.Text ("Ref: Raphael Dube-Demers, JLT, 2015", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2 + taper_length), -w/2.0 -  12.5/dbu+4.0/dbu))).text_size = 0.7/dbu
    shapes(TextLayerN).insert(pya.Text ("http://dx.doi.org/10.1109/JLT.2015.2462804", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2 + taper_length), -w/2.0 -  12.5/dbu+1.0/dbu))).text_size = 0.7/dbu
Example #13
0
  def produce_impl(self):
  
    import os
    from SiEPIC.extend import to_itype
    
    # fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes

    LayerSi = self.layer
    LayerSiN = ly.layer(LayerSi)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)
    TextLayerN = ly.layer(self.textl)
    LayerPinRec  = ly.layer(self.pinrec)
    
    file_path = os.path.join(self.forder, self.name + '.' + self.filetype)   
    print('Bragg_Straight_from_file: input file: ' + file_path)

    if not(os.path.isfile(file_path)):
      error = 'File not found: ' + file_path
      text = Text (error, Trans(0,0))
      shape = shapes(TextLayerN).insert(text)
      shape.text_size = 1/dbu
      box=Box(0,0, len(error)*shape.text_size, shape.text_size)
      shapes(LayerDevRecN).insert(box)
      return
    
    if 'txt' in self.filetype:
      # Format: (x1,y1;x2,y2;...), where x and y values are integers
      text_file = open(file_path, "r")
      lines = text_file.readlines()
    else:
      error = 'File type not available: ' + self.filetype
      text = Text (error, Trans(0,0))
      shape = shapes(TextLayerN).insert(text)
      shape.text_size = 1/dbu
      box=Box(0,0, len(error)*shape.text_size, shape.text_size)
      shapes(LayerDevRecN).insert(box)
      return
        
    p = SimplePolygon().from_s(lines[0])
    shapes(LayerSiN).insert(p)
    
    # Create the pins on the waveguides, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length
    
    bbox = p.bbox()
    y = (bbox.p1.y + bbox.p2.y) / 2
    leftx = bbox.left
    port_w = to_itype(self.port_w,dbu)
    pin = Path([Point(pin_length/2, 0), Point(-pin_length/2, 0)], port_w)

    t = Trans(Trans.R0, bbox.left, y)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin1", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    t = Trans(Trans.R180, bbox.right, y)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin2", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    
    # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
    box=Box(bbox.left,y-3/2*port_w,bbox.right,y+3/2*port_w)
    shapes(LayerDevRecN).insert(box)
Example #14
0
def bent_bragg_layout():

    # Configure parameter sweep
    pol = 'te'
    if pol == 'te':
        r = 20
        w = 0.5
        gap = 0.2

        wg_bend_radius = 5

    # Import functions from SiEPIC-Tools, and get technology details
    from SiEPIC.utils import select_paths, get_layout_variables
    TECHNOLOGY, lv, ly, cell = get_layout_variables()
    dbu = ly.dbu
    from SiEPIC.extend import to_itype
    from SiEPIC.scripts import path_to_waveguide

    # Layer mapping:
    LayerSiN = ly.layer(TECHNOLOGY['Si'])
    fpLayerN = cell.layout().layer(TECHNOLOGY['FloorPlan'])
    TextLayerN = cell.layout().layer(TECHNOLOGY['Text'])

    # Draw the floor plan
    cell.shapes(fpLayerN).insert(Box(0, 0, 610 / dbu, 405 / dbu))

    #** Create the device under test (directional coupler)
    top_cell = cell

    pcell = ly.create_cell("ebeam_dc_halfring_straight", "EBeam", {
        "r": r,
        "w": w,
        "g": gap,
        "bustype": 0
    })

    x_pos_device = 100
    y_pos_device = 100

    t = Trans(Trans.R90, x_pos_device / dbu, to_itype(y_pos_device, dbu))

    cell.insert(CellInstArray(pcell.cell_index(), t))

    #** input/out GCs
    GC_array = ly.create_cell("ebeam_gc_te1550", "EBeam").cell_index()
    GC_pitch = 127
    x_pos_GC = 33.1
    y_pos_GC = 21.4 / 2
    t = Trans(Trans.R0, x_pos_GC / dbu, to_itype(y_pos_GC, dbu))

    cell.insert(
        CellInstArray(GC_array, t,
                      DPoint(0, GC_pitch).to_itype(dbu),
                      DPoint(0, 0).to_itype(dbu), 4, 1))

    #** routing
    pts = [
        DPoint(x_pos_GC, y_pos_GC),
        DPoint(x_pos_device, y_pos_GC),
        DPoint(x_pos_device, y_pos_device - r - 0.75),
    ]
    dpath = DPath(pts, 0.5).transformed(DTrans(DTrans.R0, 0, 0))
    cell.shapes(LayerSiN).insert(dpath.to_itype(dbu))
Example #15
0
    def produce_impl(self):

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        from SiEPIC.extend import to_itype

        N = self.number_of_periods
        grating_period = int(round(self.grating_period / dbu))
        cdc_period = int(round(self.cdc_period / dbu))
        misalignment = 0

        # Determine the period such that the waveguide length is as desired.  Slight adjustment to period
        N_boxes = N

        # Draw the Bragg grating:
        box_width = int(round(grating_period * self.duty))

        w1 = self.wg1_width / dbu
        half_w1 = w1 / 2
        w2 = self.wg2_width / dbu
        half_w2 = w2 / 2
        w = self.corrugation_width / dbu
        half_w = w / 2
        gap = int(round(self.gap / dbu))

        vertical_offset = int(round(self.wg2_width / 2 / dbu)) + 2 * gap + int(
            round(self.wg1_width / 2 / dbu)) + int(round(w))

        t = Trans(Trans.R0, to_itype(0, dbu), vertical_offset)

        for i in range(0, N_boxes + 1):

            if i % 2 == True:
                x = int(round((i * grating_period - box_width / 2)))

                box1_a = Box(x, -half_w1, x + box_width, half_w1)
                shapes(LayerSiN).insert(box1_a)

                box2_a = Box(x + grating_period, -half_w2,
                             x + grating_period + box_width,
                             half_w2).transformed(t)
                shapes(LayerSiN).insert(box2_a)

            else:
                x = int(round((i * grating_period - box_width / 2)))

                box1_b = Box(x, -half_w1, x + box_width, half_w1)
                shapes(LayerSiN).insert(box1_b)

                box2_b = Box(x + grating_period, -half_w2,
                             x + grating_period + box_width,
                             half_w2).transformed(t)
                shapes(LayerSiN).insert(box2_b)

        # compensate length of SWG boxes vs cdc boxes
        x_cdc = int(round(N_boxes * cdc_period) / 2)
        xk = int(round(N_boxes * grating_period))
        N_cdc_boxes = 2 * int(round((xk - x_cdc) / cdc_period))
        print(N_cdc_boxes)
        for i in range(0, N_boxes + 1 + N_cdc_boxes):

            if i % 2 == True:
                x_cdc = int(round((i * cdc_period / 2 - box_width / 2)))

                boxw_a = Box(
                    x_cdc,
                    -half_w1 - gap,
                    x_cdc + cdc_period / 2,
                    -w - half_w1 - gap,
                )
                shapes(LayerSiN).insert(boxw_a)

                boxw_a = Box(
                    x_cdc,
                    half_w2 + gap,
                    x_cdc + cdc_period / 2,
                    w + half_w2 + gap,
                ).transformed(t)
                shapes(LayerSiN).insert(boxw_a)

            else:
                x_cdc = int(round((i * cdc_period / 2 - box_width / 2)))
                boxw_a = Box(
                    x_cdc,
                    half_w1 + gap,
                    x_cdc + cdc_period / 2,
                    w + half_w1 + gap,
                )
                shapes(LayerSiN).insert(boxw_a)

        # missing periods due to misalignments
        box_final = Box(x + grating_period, -half_w1,
                        x + grating_period + box_width, half_w1)
        shapes(LayerSiN).insert(box_final)
        box_final = Box(-box_width / 2, -half_w2, box_width / 2,
                        half_w2).transformed(t)
        shapes(LayerSiN).insert(box_final)

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0, to_itype(-box_width / 2, dbu * 1000), 0)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0, to_itype(-box_width / 2, dbu * 1000),
                  vertical_offset)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0, to_itype(x + grating_period + box_width,
                                     dbu * 1000), vertical_offset)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin3", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0, to_itype(x + grating_period + box_width,
                                     dbu * 1000), 0)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin4", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
Example #16
0
def layout_waveguide4(cell, dpath, waveguide_type, debug=True):

    if debug:
        print('SiEPIC.utils.layout.layout_waveguide4: ')
        print(' - waveguide_type: %s' % (waveguide_type))

    # get the path and clean it up
    layout = cell.layout()
    dbu = layout.dbu
    dpath = dpath.to_itype(dbu)
    dpath.unique_points()
    pts = dpath.get_points()
    dpts = dpath.get_dpoints()

    # Load the technology and all waveguide types
    from SiEPIC.utils import load_Waveguides_by_Tech
    technology_name = layout.technology_name
    waveguide_types = load_Waveguides_by_Tech(technology_name)
    if debug:
        print(' - technology_name: %s' % (technology_name))
        print(' - waveguide_types: %s' % (waveguide_types))

    # Load parameters for the chosen waveguide type
    params = [t for t in waveguide_types if t['name'] == waveguide_type]
    if type(params) == type([]) and len(params) > 0:
        params = params[0]
    else:
        print('error: waveguide type not found in PDK waveguides')
        raise Exception(
            'error: waveguide type (%s) not found in PDK waveguides' %
            waveguide_type)

    # compound waveguide types:
    if 'compound_waveguide' in params:
        # find the singlemode and multimode waveguides:
        if 'singlemode' in params['compound_waveguide']:
            singlemode = params['compound_waveguide']['singlemode']
        else:
            raise Exception(
                'error: waveguide type (%s) does not have singlemode defined' %
                waveguide_type)
        if 'multimode' in params['compound_waveguide']:
            multimode = params['compound_waveguide']['multimode']
        else:
            raise Exception(
                'error: waveguide type (%s) does not have multimode defined' %
                waveguide_type)
        params_singlemode = [
            t for t in waveguide_types if t['name'] == singlemode
        ]
        params_multimode = [
            t for t in waveguide_types if t['name'] == multimode
        ]
        if type(params_singlemode) == type([]) and len(params_singlemode) > 0:
            params_singlemode = params_singlemode[0]
        else:
            raise Exception(
                'error: waveguide type (%s) not found in PDK waveguides' %
                singlemode)
        if type(params_multimode) == type([]) and len(params_multimode) > 0:
            params_multimode = params_multimode[0]
        else:
            raise Exception(
                'error: waveguide type (%s) not found in PDK waveguides' %
                multimode)
        # find the taper
        if 'taper_library' in params[
                'compound_waveguide'] and 'taper_cell' in params[
                    'compound_waveguide']:
            taper = layout.create_cell(
                params['compound_waveguide']['taper_cell'],
                params['compound_waveguide']['taper_library'])
            if not taper:
                raise Exception(
                    'Cannot import cell %s : %s' %
                    (params['compound_waveguide']['taper_cell'],
                     params['compound_waveguide']['taper_library']))
        else:
            raise Exception(
                'error: waveguide type (%s) does not have taper cell and library defined'
                % waveguide_type)
        from pya import Trans, CellInstArray
        '''
        find sections of waveguides that are larger than (2 x radius + 2 x taper_length)
         - insert two tapers
         - insert multimode straight section
         - insert singlemode waveguides (including bends) before
        '''
        import math
        from SiEPIC.extend import to_itype
        from pya import Point
        radius = to_itype(params_singlemode['radius'], dbu)
        taper_length = taper.find_pins()[0].center.distance(
            taper.find_pins()[1].center)
        min_length = 2 * radius + 2 * taper_length
        offset = radius
        wg_sm_segment_pts = []
        wg_last = 0
        waveguide_length = 0
        for ii in range(1, len(dpts)):
            start_point = dpts[ii - 1]
            end_point = dpts[ii]
            distance_points = end_point.distance(start_point)
            if distance_points < min_length:
                # single mode segment, keep track
                if ii == 1:
                    wg_sm_segment_pts.append(pts[ii - 1])
                wg_sm_segment_pts.append(pts[ii])
                if ii == len(pts) - 1:
                    subcell = layout.create_cell("Waveguide_sm_%s" % ii)
                    cell.insert(CellInstArray(subcell.cell_index(), Trans()))
                    waveguide_length += layout_waveguide3(subcell,
                                                          wg_sm_segment_pts,
                                                          params_singlemode,
                                                          debug=True)
            else:
                # insert two tapers and multimode waveguide
                angle = math.atan2(
                    (end_point.y - start_point.y),
                    (end_point.x - start_point.x)) / math.pi * 180
                if ii == 1:
                    wg_first = offset
                else:
                    wg_first = 0
                if ii == len(pts) - 1:
                    wg_last = offset
                if round(angle) % 360 == 270.0:
                    t = Trans(Trans.R270, start_point.x,
                              start_point.y - offset + wg_first)
                    t2 = Trans(Trans.R90, end_point.x,
                               end_point.y + offset - wg_last)
                    wg_start_pt = Point(
                        start_point.x,
                        start_point.y - offset - taper_length + wg_first)
                    wg_end_pt = Point(
                        end_point.x,
                        end_point.y + offset + taper_length - wg_last)
                if round(angle) % 360 == 90.0:
                    t = Trans(Trans.R90, start_point.x,
                              start_point.y + offset - wg_first)
                    t2 = Trans(Trans.R270, end_point.x,
                               end_point.y - offset + wg_last)
                    wg_start_pt = Point(
                        start_point.x,
                        start_point.y + offset + taper_length - wg_first)
                    wg_end_pt = Point(
                        end_point.x,
                        end_point.y - offset - taper_length + wg_last)
                if round(angle) % 360 == 180.0:
                    t = Trans(Trans.R180, start_point.x - offset + wg_first,
                              start_point.y)
                    t2 = Trans(Trans.R0, end_point.x + offset - wg_last,
                               end_point.y)
                    wg_start_pt = Point(
                        start_point.x - offset - taper_length + wg_first,
                        start_point.y)
                    wg_end_pt = Point(
                        end_point.x + offset + taper_length - wg_last,
                        end_point.y)
                if round(angle) % 360 == 0.0:
                    t = Trans(Trans.R0, start_point.x + offset - wg_first,
                              start_point.y)
                    t2 = Trans(Trans.R180, end_point.x - offset + wg_last,
                               end_point.y)
                    wg_start_pt = Point(
                        start_point.x + offset + taper_length - wg_first,
                        start_point.y)
                    wg_end_pt = Point(
                        end_point.x - offset - taper_length + wg_last,
                        end_point.y)
                inst_taper = cell.insert(CellInstArray(taper.cell_index(), t))
                inst_taper = cell.insert(CellInstArray(taper.cell_index(), t2))
                waveguide_length += taper_length * 2
                subcell = layout.create_cell("Waveguide_mm_%s" % ii)
                cell.insert(CellInstArray(subcell.cell_index(), Trans()))
                waveguide_length += layout_waveguide3(subcell,
                                                      [wg_start_pt, wg_end_pt],
                                                      params_multimode,
                                                      debug=True)
                # compound segment
                if ii > 1:
                    wg_sm_segment_pts.append(t.disp.to_p())
                    subcell = layout.create_cell("Waveguide_sm_%s" % ii)
                    cell.insert(CellInstArray(subcell.cell_index(), Trans()))
                    waveguide_length += layout_waveguide3(subcell,
                                                          wg_sm_segment_pts,
                                                          params_singlemode,
                                                          debug=True)
                    wg_sm_segment_pts = [t2.disp.to_p(), pts[ii]]
                else:
                    wg_sm_segment_pts = [t2.disp.to_p(), pts[ii]]

    else:
        # primitive waveguide type
        waveguide_length = layout_waveguide3(cell, pts, params, debug=True)

    return waveguide_length
Example #17
0
def make_pin(cell, name, center, w, layer, direction):
    '''
    Makes a pin that SiEPIC-Tools will recognize
    cell: which cell to draw it in
    name: text label for the pin
    center: location, int [x,y]
    w: pin width
    layer: layout.layer() type
    direction = 
        0: right
        90: up
        180: left
        270: down

    Units: intput can be float for microns, or int for nm
    '''

    from SiEPIC.extend import to_itype
    import numpy
    dbu = cell.layout().dbu
    if type(w) == type(float()):
        w = to_itype(w, dbu)
        print('SiEPIC.utils.layout.make_pin: w converted to %s' % w)
    else:
        print('SiEPIC.utils.layout.make_pin: w %s' % w)


#    print(type(center[0]))
    if type(center[0]) == type(float()) or type(center[0]) == type(
            numpy.float64()):
        center[0] = to_itype(center[0], dbu)
        center[1] = to_itype(center[1], dbu)
        print('SiEPIC.utils.layout.make_pin: center converted to %s' %
              (center))
    else:
        print('SiEPIC.utils.layout.make_pin: center %s' % (center))

    from SiEPIC._globals import PIN_LENGTH as pin_length

    if direction not in [0, 90, 180, 270]:
        raise ('error in make_pin: direction must be one of [0, 90, 180, 270]')

    # text label
    t = pya.Trans(pya.Trans.R0, center[0], center[1])
    text = pya.Text(name, t)
    shape = cell.shapes(layer).insert(text)
    shape.text_dsize = float(w * dbu)
    shape.text_valign = 1

    if direction == 0:
        p1 = pya.Point(center[0] - pin_length / 2, center[1])
        p2 = pya.Point(center[0] + pin_length / 2, center[1])
        shape.text_halign = 2
    if direction == 90:
        p1 = pya.Point(center[0], center[1] - pin_length / 2)
        p2 = pya.Point(center[0], center[1] + pin_length / 2)
        shape.text_halign = 2
        shape.text_rot = 1
    if direction == 180:
        p1 = pya.Point(center[0] + pin_length / 2, center[1])
        p2 = pya.Point(center[0] - pin_length / 2, center[1])
        shape.text_halign = 3
    if direction == 270:
        p1 = pya.Point(center[0], center[1] + pin_length / 2)
        p2 = pya.Point(center[0], center[1] - pin_length / 2)
        shape.text_halign = 3
        shape.text_rot = 1

    pin = pya.Path([p1, p2], w)
    cell.shapes(layer).insert(pin)
Example #18
0
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier):
  '''
    Create a waveguide, in a specific technology
    inputs
    - TECHNOLOGY, layout, cell:
        from SiEPIC.utils import get_layout_variables
        TECHNOLOGY, lv, layout, cell = get_layout_variables()
    - layers: list of text names, e.g., ['Waveguide']
    - widths: list of floats in units Microns, e.g., [0.50]
    - offsets: list of floats in units Microns, e.g., [0]
    - pts: a list of pya.Points, e.g. 
        L=15/dbu
        pts = [Point(0,0), Point(L,0), Point(L,L)]
    - radius: in Microns, e.g., 5
    - adiab: 1 = Bezier curve, 0 = radial bend (arc)
    - bezier: the bezier parameter, between 0 and 0.45 (almost a radial bend)

    Note: bezier parameters need to be simulated and optimized, and will depend on 
        wavelength, polarization, width, etc.  TM and rib waveguides don't benefit from bezier curves
        most useful for TE 
  '''
  from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal
  from SiEPIC.extend import to_itype
  from pya import Path, Polygon, Trans
  dbu = layout.dbu

  width=widths[0]
  turn=0
  waveguide_length = 0
  for lr in range(0, len(layers)):
    wg_pts = [pts[0]]
    layer = layout.layer(TECHNOLOGY[layers[lr]])
    width = to_itype(widths[lr],dbu)
    offset = to_itype(offsets[lr],dbu)
    for i in range(1,len(pts)-1):
      turn = ((angle_b_vectors(pts[i]-pts[i-1],pts[i+1]-pts[i])+90)%360-90)/90
      dis1 = pts[i].distance(pts[i-1])
      dis2 = pts[i].distance(pts[i+1])
      angle = angle_vector(pts[i]-pts[i-1])/90
      pt_radius = to_itype(radius,dbu)
      # determine the radius, based on how much space is available
      if len(pts)==3:
        pt_radius = min (dis1, dis2, pt_radius)
      else:
        if i==1:
          if dis1 <= pt_radius:
            pt_radius = dis1
        elif dis1 < 2*pt_radius:
          pt_radius = dis1/2
        if i==len(pts)-2:
          if dis2 <= pt_radius:
            pt_radius = dis2
        elif dis2 < 2*pt_radius:
          pt_radius = dis2/2
      # waveguide bends:
      if abs(turn)==1:
        if(adiab):
          wg_pts += Path(arc_bezier(pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]), bezier, DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points()
        else:
          wg_pts += Path(arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]),DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points()
        
    wg_pts += [pts[-1]]
    wg_pts = pya.Path(wg_pts, 0).unique_points().get_points()
    wg_polygon = Polygon(translate_from_normal(wg_pts, width/2 + (offset if turn > 0 else - offset))+translate_from_normal(wg_pts, -width/2 + (offset if turn > 0 else - offset))[::-1])
    cell.shapes(layer).insert(wg_polygon)
  
    if layout.layer(TECHNOLOGY['Waveguide']) == layer:
      waveguide_length = wg_polygon.area() / width * dbu
  return waveguide_length
Example #19
0
def y_splitter_tree(cell,
                    tree_depth=4,
                    y_splitter_cell="y_splitter_1310",
                    library="SiEPICfab_Shuksan_PDK",
                    wg_type='Strip TE 1310 nm, w=350 nm',
                    draw_waveguides=True):
    '''
    Create a tree of splitters
    - cell: layout cell to create the structures in
    - tree_depth: Tree depth (2^N outputs)
    - y_splitter_cell: name of the y-splitter cell
    - library: the library containing the y_splitter_cell
    - wg_type: waveguide type from WAVEGUIDES.XML
    - draw_waveguides: True draws the waveguides, False is faster for debugging
    
    Returns
    - inst_in: instance of the input cell
    - inst_out[]: array of instances of the output cells
    - cell_tree: new cell created
    This is useful for subsequent routing
    
    Limitations:
    - the design uses regular 90 degree bends, rather than S-bends.
      hence it could be made more compact
    '''

    from SiEPIC.scripts import connect_pins_with_waveguide
    from SiEPIC.extend import to_itype
    from math import floor

    # create a new sub-cell where the tree will go
    ly = cell.layout()
    tech = ly.technology().name
    cell_tree = ly.create_cell("y_splitter_tree")

    # load the y-splitter from the library
    y_splitter = ly.create_cell(y_splitter_cell, library)
    if not y_splitter:
        raise Exception('Cannot import cell %s:%s' %
                        (library, y_splitter_cell))

    # Load waveguide information
    from SiEPIC.utils import load_Waveguides_by_Tech
    waveguides = load_Waveguides_by_Tech(tech)
    wg = [w for w in waveguides if wg_type in w['name']][0]
    if not wg:
        raise Exception("Waveguide type not defined in WAVEGUIDES.XML: %s" %
                        wg_type)
        return
    wg_width = to_itype(float(wg['width']), ly.dbu)
    wg_radius = to_itype(float(wg['radius']), ly.dbu)

    # build the tree, using measurements from the cell and waveguide parameters
    x = 0
    dx = y_splitter.bbox().width() + wg_radius * 2
    # calculate the spacing for the y-splitters based on waveguide radius and 90 degree bends
    y_wg_offset = (y_splitter.pinPoint("opt2").y -
                   y_splitter.pinPoint("opt3").y)
    dy = max(y_splitter.bbox().height(), wg_radius * 4 + y_wg_offset)
    # intialize loop
    inst_out = []
    y0 = 0
    for i in range(0, tree_depth):
        inst = []
        y = y0
        for j in range(0, int(2**(tree_depth - i - 1))):
            t = pya.Trans(pya.Trans.R0, x, y)
            inst.append(
                cell_tree.insert(pya.CellInstArray(y_splitter.cell_index(),
                                                   t)))
            # perform waveguide routing
            if (i > 0) and draw_waveguides:
                connect_pins_with_waveguide(inst[j],
                                            'opt2',
                                            inst_higher[j * 2 + 1],
                                            'opt1',
                                            waveguide_type=wg_type)
                connect_pins_with_waveguide(inst[j],
                                            'opt3',
                                            inst_higher[j * 2],
                                            'opt1',
                                            waveguide_type=wg_type)
            y += dy
        inst_higher = inst
        if i == 0:
            inst_out = inst
        if i == tree_depth - 1:
            inst_in = inst[0]
        x += -dx
        y0 = y0 + dy / 2
        dy = dy * 2

    return inst_in, inst_out, cell_tree
Example #20
0
  def produce_impl(self):
    import math

    # fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes

    LayerSi = self.layer
    LayerSiN = ly.layer(LayerSi)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)

    from SiEPIC.extend import to_itype
    
    
    # Draw the Bragg grating (bottom):
    # create chirped period array
    grating_period_start = int(round(self.grating_period_start/dbu))
    grating_period_end = int(round(self.grating_period_end/dbu))
    length = self.number_of_periods
    step = ((grating_period_start-grating_period_end) * 1.0 / length)
    
    grating_period = []
    box_width = []
    misalignment = []
    for i in range(length):
      grating_period.append(grating_period_end+i*step)
      grating_period[i] = round(grating_period_end+i*step)
      box_width.append(int(round(grating_period[i]/2)))
      misalignment.append( int(round(grating_period[i]/2)))
    
    
    w = to_itype(self.wg1_width,dbu)
    GaussianIndex = self.index
    half_w = w/2
    half_corrugation_w = to_itype(self.corrugation_width1/2,dbu)
      
    N = self.number_of_periods
    if self.sinusoidal:
      x = 0
      npoints_sin = 40
      for i in range(0,self.number_of_periods):
        if i != 0:
          x = x + grating_period[i]
        
        profileFunction = math.exp( -0.5*(2*GaussianIndex*(i-N/2)/(N))**2 )
        profile = int(round(self.corrugation_width1/2/dbu))*profileFunction;
        box1 = Box(x, 0, x + box_width[i], half_w+profile)
        pts1 = [Point(x,0)]
        pts3 = [Point(x + misalignment[i],0)]
        for i1 in range(0,npoints_sin+1):
          x1 = i1 * 2* math.pi / npoints_sin
          y1 = round(profile*math.sin(x1))
          x1 = round(x1/2/math.pi*grating_period[i])
          pts1.append( Point(x + x1,half_w+y1 ) )
          pts3.append( Point(x + misalignment[i] + x1,-half_w-y1 ) )
        pts1.append( Point(x + grating_period[i], 0) )
        pts3.append( Point(x + grating_period[i] + misalignment[i], 0) )
        shapes(LayerSiN).insert(Polygon(pts1))
        shapes(LayerSiN).insert(Polygon(pts3))
      length = x + grating_period[i] + misalignment[i]
      # extra piece at the end:
      box2 = Box(x + grating_period[i], 0, length, half_w)
      shapes(LayerSiN).insert(box2)
      # extra piece at the beginning:
      box3 = Box(0, 0, misalignment[0], -half_w)
      shapes(LayerSiN).insert(box3)

    else:
      x = 0
      for i in range(0,self.number_of_periods):
        if i != 0:
          x = x + grating_period[i]
        
        profileFunction = math.exp( -0.5*(2*GaussianIndex*(i-N/2)/(N))**2 )
        profile = int(round(self.corrugation_width1/2/dbu))*profileFunction;
        box1 = Box(x, 0, x + box_width[i], to_itype(half_w+profile,dbu*1000))
        box2 = Box(x + box_width[i], 0, x + grating_period[i], to_itype(half_w-profile,dbu*1000))
        box3 = Box(x + misalignment[i], 0, x + box_width[i] + misalignment[i], to_itype(-half_w-profile,dbu*1000))
        box4 = Box(x + box_width[i] + misalignment[i], 0, x + grating_period[i] + misalignment[i], to_itype(-half_w+profile,dbu*1000))
        shapes(LayerSiN).insert(box1)
        shapes(LayerSiN).insert(box2)
        shapes(LayerSiN).insert(box3)
        shapes(LayerSiN).insert(box4)
      length = x + grating_period[i] + misalignment[i]
      # extra piece at the end:
      box2 = Box(x + grating_period[i], 0, length, half_w)
      shapes(LayerSiN).insert(box2)
      # extra piece at the beginning:
      box3 = Box(0, 0, misalignment[0], -half_w)
      shapes(LayerSiN).insert(box3)




    vertical_offset = int(round(self.wg2_width/2/dbu))+int(round(self.gap/dbu))+int(round(self.wg1_width/2/dbu))
    
    t = Trans(Trans.R0, 0,vertical_offset)
    
    # Draw the Bragg grating (top):
    w = to_itype(self.wg2_width,dbu)
    GaussianIndex = self.index
    half_w = w/2
    half_corrugation_w = int(round(self.corrugation_width2/2/dbu))
    

    N = self.number_of_periods
    if self.sinusoidal:
      npoints_sin = 40
      x = 0
      for i in range(0,self.number_of_periods):
        if i != 0:
          x = x + grating_period[i]
        
        profileFunction = math.exp( -0.5*(2*GaussianIndex*(i-N/2)/(N))**2 )
        profile = int(round(self.corrugation_width2/2/dbu))*profileFunction;
        box1 = Box(x, 0, x + box_width[i], -half_w+profile).transformed(t)
        pts1 = [Point(x,0)]
        pts3 = [Point(x + misalignment[i],0)]
        for i1 in range(0,npoints_sin+1):
          x1 = i1 * 2* math.pi / npoints_sin
          y1 = round(profile*math.sin(x1))
          x1 = round(x1/2/math.pi*grating_period[i])
#          print("x: %s, y: %s" % (x1,y1))
          pts1.append( Point(x + x1,-half_w-y1 ) )
          pts3.append( Point(x + misalignment[i] + x1,+half_w+y1 ) )
        pts1.append( Point(x + grating_period[i], 0) )
        pts3.append( Point(x + grating_period[i] + misalignment[i], 0) )
        shapes(LayerSiN).insert(Polygon(pts1).transformed(t))
        shapes(LayerSiN).insert(Polygon(pts3).transformed(t))
      length = x + grating_period[i] + misalignment[i]
      # extra piece at the end:
      box2 = Box(x + grating_period[i], 0, length, -half_w).transformed(t)
      shapes(LayerSiN).insert(box2)
      # extra piece at the beginning:
      box3 = Box(0, 0, misalignment[0], half_w).transformed(t)
      shapes(LayerSiN).insert(box3)

    else:
      x = 0
      for i in range(0,self.number_of_periods):
        if i != 0:
          x = x + grating_period[i]
        
        profileFunction = math.exp( -0.5*(2*GaussianIndex*(i-N/2)/(N))**2 )
        profile = int(round(self.corrugation_width2/2/dbu))*profileFunction;
        box1 = Box(x, 0, x + box_width[i], -half_w-profile).transformed(t)
        box2 = Box(x + box_width[i], 0, x + grating_period[i], -half_w+profile).transformed(t)
        box3 = Box(x + misalignment[i], 0, x + box_width[i] + misalignment[i], half_w+profile).transformed(t)
        box4 = Box(x + box_width[i] + misalignment[i], 0, x + grating_period[i] + misalignment[i], half_w-profile).transformed(t)
        shapes(LayerSiN).insert(box1)
        shapes(LayerSiN).insert(box2)
        shapes(LayerSiN).insert(box3)
        shapes(LayerSiN).insert(box4)
      length = x + grating_period[i] + misalignment[i]
      box2 = Box(x + grating_period[i], 0, length, -half_w).transformed(t)
      shapes(LayerSiN).insert(box2)
      # extra piece at the beginning:
      box3 = Box(0, 0, misalignment[0], half_w).transformed(t)
      shapes(LayerSiN).insert(box3)
        
         
    # Create the pins on the waveguides, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length

    w = to_itype(self.wg1_width,dbu)
    t = Trans(Trans.R0, 0,0)
    pin = Path([Point(pin_length/2, 0), Point(-pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin1", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    w = to_itype(self.wg2_width,dbu)
    t = Trans(Trans.R0, 0,vertical_offset)
    pin = Path([Point(pin_length/2, 0), Point(-pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin3", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    w = to_itype(self.wg1_width,dbu)
    t = Trans(Trans.R0, length,0)
    pin = Path([Point(-pin_length/2, 0), Point(pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin2", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    w = to_itype(self.wg2_width,dbu)
    t = Trans(Trans.R0, length,vertical_offset)
    pin = Path([Point(-pin_length/2, 0), Point(pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin4", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    # Compact model information
    t = Trans(Trans.R0, 0, 0)
    text = Text ('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/10, 0)
    text = Text ('Component=ebeam_contra_dc_chirped', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/9, 0)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
    t = Trans(Trans.R0, 0,0)
    path = Path([Point(0, vertical_offset/2), Point(length, vertical_offset/2)], 3*w)
    shapes(LayerDevRecN).insert(path.simple_polygon())
Example #21
0
    def produce_impl(self):

        # Layout and layers:
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerSiSPN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        # fetch the PCell parameters, and calculate a few things
        from SiEPIC.extend import to_itype
        wg_width_swg = to_itype(self.wg_width_swg, dbu)
        wg_width_strip = to_itype(self.wg_width_strip, dbu)
        length = to_itype(self.length, dbu)
        w1 = to_itype(self.wg_width_taper, dbu)
        w2 = to_itype(self.wg_width_strip, dbu)

        # Determine the period such that the waveguide length is as desired.  Slight adjustment to period
        N_boxes = int(
            round(self.length / (self.period_swg + self.period_strip) * 2.0) -
            0.5)
        grating_period = self.length / (N_boxes) / dbu
        print("N boxes: %s, grating_period: %s" % (N_boxes, grating_period))

        # taper length, minus last SWG block
        # taper_length = int(round(self.taper_fraction * self.length / dbu))
        taper_length = (N_boxes - 1) * grating_period

        # Find out what is the delta width required between
        # a) the SWG end and b) the SWG with nanotaper
        # Done by simulating the neff versus SWG waveguide width, with an without a 60 nm
        w = wg_width_swg
        if self.fishbone:
            dw = 0
        elif self.wavelength == 1310:
            dw = -3.3736e-5 * w * w + 0.0618752 * w + 3.88577
        else:
            dw = 0
        wg_width_swg_taperend = wg_width_swg - dw

        # Draw the SWG waveguide:

        x = -self.period_swg * self.duty_swg / 2 / dbu
        for i in range(0, N_boxes):
            local_duty = 1.0 * (
                N_boxes - i
            ) / N_boxes * self.duty_swg + 1.0 * i / N_boxes * self.duty_strip
            local_period = to_itype(
                (1.0 * (N_boxes - i) / N_boxes * self.period_swg +
                 1.0 * i / N_boxes * self.period_strip), dbu)
            local_wg_width = (1.0 *
                              (N_boxes - i) / N_boxes * wg_width_swg_taperend +
                              1.0 * i / N_boxes * wg_width_strip)
            if (i == 0) | (i == N_boxes):
                print("local_duty: %s, local_period: %s, local_wg_width: %s" %
                      (local_duty, local_period, local_wg_width))
            local_box_width = int(round(local_period * local_duty))
            #      x = int(round((i * local_period - local_box_width/2)))
            if i != 0:
                box1 = Box(x, -local_wg_width / 2, x + local_box_width,
                           local_wg_width / 2)
            else:
                # Last SWG, that is a bit larger than the one connected to the taper
                box1 = Box(x, -wg_width_swg / 2, x + local_box_width,
                           wg_width_swg / 2)
            shapes(LayerSiN).insert(box1)
            x = x + int(round((local_period)))

        # Taper
        if self.fishbone:
            taper_length = length
        pts = [
            Point(length - taper_length, -w1 / 2),
            Point(length - taper_length, w1 / 2),
            Point(length, w2 / 2),
            Point(length, -w2 / 2)
        ]
        shapes(LayerSiN).insert(Polygon(pts))

        # Pins on the waveguide:

        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.wg_width_swg, dbu)
        t = Trans(Trans.R0, 0, 0)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(max(self.wg_width_strip, self.wg_width_taper), dbu)
        t = Trans(Trans.R0, length, 0)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
        shape.text_halign = 2
        '''
    # Compact model information
    t = Trans(Trans.R0, 0, 0)
    text = Text ('Lumerical_INTERCONNECT_library=Design kits/ebeam_v1.2', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/10, 0)
    text = Text ('Component=NO_MODEL_AVAILABLE', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/9, -w*2)
    text = Text \
      ('Spice_param:length=%.3fu period_swg=%.3fu period_strip=%.3fu wg_width_swg=%.3fu wg_width_strip=%.3fu duty_swg=%.3f duty_strip=%.3f ' %\
      (self.length, self.period_swg, (self.period_strip), self.wg_width_swg, self.wg_width_strip, self.duty_swg, self.duty_strip), t )
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    blabla
    '''

        # Create the device recognition layer
        points = [pya.Point(0, 0), pya.Point(length, 0)]
        path = pya.Path(points,
                        (self.wg_width_strip + self.clad_width * 2) / dbu)
        shapes(LayerDevRecN).insert(path.simple_polygon())

        # waveguide cladding
        points = [pya.Point(0, 0), pya.Point(length, 0)]
        path = pya.Path(points,
                        (self.wg_width_strip + self.clad_width * 2) / dbu)
        shapes(ly.layer(self.layer_clad)).insert(path.simple_polygon())

        print(' - done: Waveguide_SWG_to_Strip')
Example #22
0
def layout_waveguide3(cell, pts, params, debug=True):

    if debug:
        print('SiEPIC.utils.layout.layout_waveguide3: ')

    layout = cell.layout()
    dbu = layout.dbu
    technology_name = layout.technology_name
    from SiEPIC.utils import get_technology_by_name
    TECHNOLOGY = get_technology_by_name(technology_name)

    from SiEPIC.extend import to_itype
    wg_width = to_itype(params['width'], dbu)
    radius = float(params['radius'])
    model = params['model']
    cellName = 'Waveguide2'
    CML = params['CML']

    if debug:
        print(' - waveguide params: %s' % (params))

    if 'compound_waveguide' in params:
        print('error: this function cannot handle compound waveguides')
        raise Exception(
            'error: this function cannot handle compound waveguides (%s)' %
            waveguide_type)

    # draw the waveguide
    waveguide_length = layout_waveguide2(
        TECHNOLOGY, layout, cell, [wg['layer'] for wg in params['component']],
        [wg['width'] for wg in params['component']],
        [wg['offset'] for wg in params['component']], pts, radius,
        params['adiabatic'], params['bezier'])

    # Draw the marking layers
    from SiEPIC.utils import angle_vector
    LayerPinRecN = layout.layer(TECHNOLOGY['PinRec'])

    make_pin(cell, 'opt1', pts[0], wg_width, LayerPinRecN,
             angle_vector(pts[0] - pts[1]) % 360)
    make_pin(cell, 'opt2', pts[-1], wg_width, LayerPinRecN,
             angle_vector(pts[-1] - pts[-2]) % 360)

    from pya import Trans, Text, Path, Point
    '''
    t1 = Trans(angle_vector(pts[0]-pts[1])/90, False, pts[0])
    cell.shapes(LayerPinRecN).insert(Path([Point(-10, 0), Point(10, 0)], wg_width).transformed(t1))
    cell.shapes(LayerPinRecN).insert(Text("opt1", t1, 0.3/dbu, -1))
    
    t = Trans(angle_vector(pts[-1]-pts[-2])/90, False, pts[-1])
    cell.shapes(LayerPinRecN).insert(Path([Point(-10, 0), Point(10, 0)], wg_width).transformed(t))
    cell.shapes(LayerPinRecN).insert(Text("opt2", t, 0.3/dbu, -1))
    '''

    LayerDevRecN = layout.layer(TECHNOLOGY['DevRec'])

    # Compact model information
    angle_vec = angle_vector(pts[0] - pts[1]) / 90
    halign = 0  # left
    angle = 0
    dpt = Point(0, 0)
    if angle_vec == 0:  # horizontal
        halign = 2  # right
        angle = 0
        dpt = Point(0, 0.2 * wg_width)
    if angle_vec == 2:  # horizontal
        halign = 0  # left
        angle = 0
        dpt = Point(0, 0.2 * wg_width)
    if angle_vec == 1:  # vertical
        halign = 2  # right
        angle = 1
        dpt = Point(0.2 * wg_width, 0)
    if angle_vec == -1:  # vertical
        halign = 0  # left
        angle = 1
        dpt = Point(0.2 * wg_width, 0)
    pt2 = pts[0] + dpt
    pt3 = pts[0] - dpt
    pt4 = pts[0] - 6 * dpt
    pt5 = pts[0] + 2 * dpt

    t = Trans(angle, False, pt3)
    text = Text('Lumerical_INTERCONNECT_library=Design kits/%s' % CML, t,
                0.1 * wg_width, -1)
    text.halign = halign
    shape = cell.shapes(LayerDevRecN).insert(text)
    t = Trans(angle, False, pt2)
    text = Text('Component=%s' % model, t, 0.1 * wg_width, -1)
    text.halign = halign
    shape = cell.shapes(LayerDevRecN).insert(text)
    t = Trans(angle, False, pt5)
    text = Text('cellName=%s' % cellName, t, 0.1 * wg_width, -1)
    text.halign = halign
    shape = cell.shapes(LayerDevRecN).insert(text)
    t = Trans(angle, False, pts[0])
    pts_txt = str([[round(p.to_dtype(dbu).x, 3),
                    round(p.to_dtype(dbu).y, 3)]
                   for p in pts]).replace(', ', ',')
    text = Text(
        'Spice_param:wg_length=%.9f wg_width=%.3g points="%s" radius=%.3g' %
        (waveguide_length * 1e-6, wg_width * 1e-9, pts_txt, radius * 1e-6), t,
        0.1 * wg_width, -1)
    text.halign = halign
    shape = cell.shapes(LayerDevRecN).insert(text)
    t = Trans(angle, False, pt4)
    text = Text('Length=%.3f (microns)' % (waveguide_length), t,
                0.5 * wg_width, -1)
    text.halign = halign
    shape = cell.shapes(LayerDevRecN).insert(text)

    return waveguide_length
Example #23
0
  def produce_impl(self):
    
    #fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes
      
    LayerSi = self.layer
    LayerSiN = ly.layer(LayerSi)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)

    from SiEPIC.extend import to_itype
    from math import pi, cos, sin, acos
    
    N = int(self.N) 
    #draw the encoded bragg grating:
    dx = 0.01
    corrugations = self.corrugation_widths
    
    if N != len(self.binary):
      pya.MessageBox.warning("Array length mismatch!", "Number of bits (N) does NOT equal the bits array length!",  pya.MessageBox.Ok)
      return
    elif N != len(self.corrugation_widths):
      pya.MessageBox.warning("Array length mismatch!", "Number of bits (N) does NOT equal the corrugation widths array length!",  pya.MessageBox.Ok)
      return
      
    dlambda = (self.stop_period - self.start_period)/(N-1)
    npoints = int(self.length/dx)
    w = to_itype(self.wg_width,dbu)  
    l = to_itype(self.length,dbu)
    f = self.sum_format
    
    E = []
    wavelengths = []
    for i in range(0,N):
      E.append(int(self.binary[i]))
      wavelengths.append(self.start_period + i*dlambda)
      round(wavelengths[i],3)
    
    x = 0
    y1 = 0
    y2 = 0
    pts1 = [Point(x,0)]
    pts3 = [Point(x,0)]
    for i in range(0, npoints + 1):
      x1 = i*dx
      
      #summation method
      if f == 1:
        for j in range(0, N):
          corrugation = float(self.corrugation_widths[j])/10
          y1 = y1 +  corrugation*E[j]*sin((x1*2*pi)/wavelengths[j])
          y2 = y1
     
      elif f == 2:
      #half half method (11110000 style):
        for j in range(0, int(N/2)):
          corrugation1 = float(self.corrugation_widths[j])/10
          corrugation2 = float(self.corrugation_widths[j+int(N/2)])/10
          y1 = y1 +  corrugation1*E[j]*sin((x1*2*pi)/wavelengths[j]) 
          y2 = y2 + corrugation2*E[j+int(N/2)]*sin((x1*2*pi)/wavelengths[j+int(N/2)])
          
      elif f == 3:
      #half half method (10101010 style):
        for j in range(0, int(N/2)):
          idx1 = int(j*2)
          idx2 = int((j*2+1))
          
          corrugation1 = float(self.corrugation_widths[idx1])/10
          corrugation2 = float(self.corrugation_widths[idx2])/10
          y1 = y1 +  corrugation1*E[idx1]*sin((x1*2*pi)/wavelengths[idx1]) 
          y2 = y2 +  corrugation2*E[idx2]*sin((x1*2*pi)/wavelengths[idx2])

      if self.N == 2:
        dw1 = float(self.corrugation_widths[0])
        dw2 = float(self.corrugation_widths[1])
      else:
        dw1 = 0
        dw2 = 0
        
      pts1.append( Point((x + x1)/dbu, ((self.wg_width-dw1)/2  + y1)/dbu))
      pts3.append( Point((x + x1)/dbu, ((-self.wg_width+dw2)/2 - y2)/dbu))
    
    pts1.append( Point((x + x1 + 20*dx)/dbu, self.wg_width/2/dbu))
    pts3.append( Point((x + x1 + 20*dx)/dbu, -self.wg_width/2/dbu)) 
    
    pts1.append( Point((x + x1 + 20*dx)/dbu, 0))
    pts3.append( Point((x + x1 + 20*dx)/dbu, 0))    
    
    shapes(LayerSiN).insert(Polygon(pts1))
    shapes(LayerSiN).insert(Polygon(pts3))    
    
    #create the pins on the waveguides, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length
    
    t = Trans(Trans.R0,0,0)
    pin = Path([Point(pin_length/2,0), Point(-pin_length/2,0)],w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text("pin1", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    t = Trans(Trans.R0,(self.length+dx*20)/dbu,0)
    pin = Path([Point(-pin_length/2,0),Point(pin_length/2,0)],w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text("pin2",t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu 
    
    def produce_impl(self):
        import math

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        from SiEPIC.extend import to_itype

        N = self.number_of_periods

        # create chirped period array
        grating_period_start = to_itype(self.grating_period_start, dbu)
        grating_period_end = to_itype(self.grating_period_end, dbu)
        length = self.number_of_periods
        step = (float(grating_period_start - grating_period_end) / length)

        grating_period = []
        box_width = []
        misalignment = []
        for i in range(length):
            grating_period.append(grating_period_end + i * step)
            #grating_period[i] = round(grating_period_end+i*step)
            box_width.append(grating_period[i] / 2)

        misalignment = 0
        # Determine the period such that the waveguide length is as desired.  Slight adjustment to period
        N_boxes = N

        # Draw the Bragg grating:
        # box_width = int(round(grating_period*self.duty))

        w1 = self.wg1_width / dbu
        half_w1 = w1 / 2
        w2 = self.wg2_width / dbu
        half_w2 = w2 / 2
        deltaW1_max = to_itype(self.corrugation_width1, dbu)
        deltaW2_max = to_itype(self.corrugation_width2, dbu)

        for i in range(0, N_boxes):

            # apply apodization
            profileFunction = math.exp(-0.5 * (2 * self.a * (i - N / 2) /
                                               (N))**2)
            deltaW1 = deltaW1_max * profileFunction
            deltaW2 = deltaW2_max * profileFunction

            vertical_offset = int(round(self.wg2_width / 2 / dbu)) + int(
                round(self.gap / dbu)) + int(
                    round(self.wg1_width / 2 /
                          dbu))  #+(-int(round(deltaW1))+int(round(deltaW2)))/2
            t = Trans(Trans.R0, 0, vertical_offset)

            if i % 2 == True:

                x = i * grating_period[i] - box_width[i] / 2

                box1_a = Box(x, -half_w1 - deltaW1, x + box_width[i],
                             half_w1 - deltaW1)
                shapes(LayerSiN).insert(box1_a)

                box2_a = Box(x + grating_period[i], -half_w2 - deltaW2,
                             x + grating_period[i] + box_width[i],
                             half_w2 - deltaW2).transformed(t)
                shapes(LayerSiN).insert(box2_a)

            else:

                x = (i * grating_period[i] - box_width[i] / 2)
                box1_b = Box(x, -half_w1, x + box_width[i], half_w1)
                shapes(LayerSiN).insert(box1_b)

                box2_b = Box(x + grating_period[i], -half_w2,
                             x + grating_period[i] + box_width[i],
                             half_w2).transformed(t)
                shapes(LayerSiN).insert(box2_b)

        # missing periods due to misalignments
        box_final = Box(x + grating_period[i - 1], -half_w1,
                        x + grating_period[i - 1] + box_width[i - 1], half_w1)
        shapes(LayerSiN).insert(box_final)
        box_final = Box(-box_width[i - 1] / 2, -half_w2 - deltaW2,
                        box_width[i - 1] / 2, half_w2 - deltaW2).transformed(t)
        shapes(LayerSiN).insert(box_final)

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0, to_itype(-box_width[0] / 2, dbu * 1000),
                  -deltaW1 / 2)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0, to_itype(-box_width[0] / 2, dbu * 1000),
                  vertical_offset - deltaW2 / 2)
        pin = Path([Point(pin_length / 2, 0), Point(-pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg2_width, dbu)
        t = Trans(Trans.R0,
                  to_itype(x + grating_period[0] + box_width[0], dbu * 1000),
                  vertical_offset - deltaW2 / 2)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin3", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu

        w = to_itype(self.wg1_width, dbu)
        t = Trans(Trans.R0,
                  to_itype(x + grating_period[0] + box_width[0], dbu * 1000),
                  -deltaW1 / 2)
        pin = Path([Point(-pin_length / 2, 0), Point(pin_length / 2, 0)], w)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin4", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
Example #25
0
    def produce_impl(self):
        # This is the main part of the implementation: create the layout
        from math import pi, cos, sin
        from SiEPIC.extend import to_itype

        # fetch the parameters
        #    TECHNOLOGY = get_technology_by_name('GSiP')
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.silayer
        LayerSi3 = ly.layer(self.si3layer)
        LayerSiN = ly.layer(LayerSi)
        LayervlN = ly.layer(self.vllayer)
        LayermlN = ly.layer(self.mllayer)
        LayermhN = ly.layer(self.mhlayer)
        TextLayerN = ly.layer(self.textl)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        # Define variables for the Modulator
        # Variables for the Si waveguide
        w = to_itype(self.w, dbu)
        r = to_itype(self.r, dbu)
        g = to_itype(self.g, dbu)
        gmon = to_itype(self.gmon, dbu)

        #Variables for the N layer
        w_1 = 2.0 / dbu  #same for N, P, N+, P+ layer
        r_n = to_itype(self.r - 1.0, dbu)

        #Variables for the VC layer
        w_vc = to_itype(4.0, dbu)
        r_vc1 = to_itype(self.r - 3.75, dbu)
        r_vc2 = to_itype(self.r + 3.75, dbu)

        #Variables for the M1 layer
        w_m1_in = r_vc1 + w_vc / 2.0 + to_itype(0.5, dbu)
        r_m1_in = r_vc1 + w_vc / 2.0 + to_itype(0.5, dbu) / 2.0
        w_m1_out = to_itype(6.0, dbu)
        r_m1_out = to_itype(self.r + 4.25, dbu)

        #Variables for the VL layer
        r_vl = w_m1_in / 2.0 - to_itype(2.1, dbu)
        w_via = to_itype(5.0, dbu)
        h_via = to_itype(5.0, dbu)

        # Variables for the SiEtch2 layer  (Slab)
        w_Si3 = w_m1_out + 2 * (r_m1_out)
        h_Si3 = w_Si3
        taper_bigend = to_itype(2, dbu)
        taper_smallend = to_itype(0.3, dbu)
        taper_length = to_itype(5, dbu)

        #Variables for the MH layer
        w_mh = to_itype(2.0, dbu)
        r_mh = r
        r_mh_in = r_mh - w_mh / 2.0

        #Define Ring centre
        x0 = r + w / 2
        y0 = r + g + w

        ######################
        # Generate the layout:

        # Create the ring resonator
        t = pya.Trans(pya.Trans.R0, (self.r + self.w / 2) / dbu,
                      (self.r + self.g + self.w) / dbu)
        pcell = ly.create_cell("Ring", "GSiP", {
            "layer": LayerSi,
            "radius": self.r,
            "width": self.w
        })
        self.cell.insert(pya.CellInstArray(pcell.cell_index(), t))

        # Create the two waveguides
        wg1 = pya.Box(x0 - (w_Si3 / 2 + taper_length), -w / 2,
                      x0 + (w_Si3 / 2 + taper_length), w / 2)
        shapes(LayerSiN).insert(wg1)
        y_offset = 2 * r + g + gmon + 2 * w
        wg2 = pya.Box(x0 - (w_Si3 / 2 + taper_length), y_offset - w / 2,
                      x0 + (w_Si3 / 2 + taper_length), y_offset + w / 2)
        shapes(LayerSiN).insert(wg2)

        #Create the SiEtch2 (Slab) layer
        boxSi3 = pya.Box(x0 - w_Si3 / 2.0, y0 - h_Si3 / 2.0, x0 + w_Si3 / 2.0,
                         y0 + h_Si3 / 2.0)
        shapes(LayerSi3).insert(boxSi3)
        pin1pts = [
            pya.Point(x0 - w_Si3 / 2.0, -taper_bigend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0 - taper_length, -taper_smallend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0 - taper_length, taper_smallend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0, taper_bigend / 2.0)
        ]
        pin2pts = [
            pya.Point(x0 + w_Si3 / 2.0, -taper_bigend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0 + taper_length, -taper_smallend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0 + taper_length, taper_smallend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0, +taper_bigend / 2.0)
        ]
        pin3pts = [
            pya.Point(x0 - w_Si3 / 2.0, y_offset - taper_bigend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0 - taper_length,
                      y_offset - taper_smallend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0 - taper_length,
                      y_offset + taper_smallend / 2.0),
            pya.Point(x0 - w_Si3 / 2.0, y_offset + taper_bigend / 2.0)
        ]
        pin4pts = [
            pya.Point(x0 + w_Si3 / 2.0, y_offset - taper_bigend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0 + taper_length,
                      y_offset - taper_smallend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0 + taper_length,
                      y_offset + taper_smallend / 2.0),
            pya.Point(x0 + w_Si3 / 2.0, y_offset + taper_bigend / 2.0)
        ]
        shapes(LayerSi3).insert(pya.Polygon(pin1pts))
        shapes(LayerSi3).insert(pya.Polygon(pin2pts))
        shapes(LayerSi3).insert(pya.Polygon(pin3pts))
        shapes(LayerSi3).insert(pya.Polygon(pin4pts))

        from SiEPIC.utils import arc

        # arc angles
        # doping:
        angle_min_doping = -35
        angle_max_doping = 215
        # VC contact:
        angle_min_VC = angle_min_doping + 8
        angle_max_VC = angle_max_doping - 8
        # M1:
        angle_min_M1 = angle_min_VC - 4
        angle_max_M1 = angle_max_VC + 4
        # MH:
        angle_min_MH = -75.0
        angle_max_MH = 255

        #Create the VL Layer, as well as the electrical PinRec geometries
        # heater contacts
        boxVL3 = pya.Box(
            x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 2.5 / dbu,
            -w / 2.0 - 10 / dbu,
            x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 7.5 / dbu,
            -w / 2.0 - 5 / dbu)
        shapes(LayervlN).insert(boxVL3)
        shapes(LayerPinRecN).insert(boxVL3)
        shapes(LayerPinRecN).insert(
            pya.Text(
                "elec2h2",
                pya.Trans(
                    pya.Trans.R0,
                    x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 5.0 / dbu,
                    -w / 2.0 - 7.5 / dbu))).text_size = 0.5 / dbu
        boxVL4 = pya.Box(
            x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 7.5 / dbu,
            -w / 2.0 - 10 / dbu,
            x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 2.5 / dbu,
            -w / 2.0 - 5 / dbu)
        shapes(LayervlN).insert(boxVL4)
        shapes(LayerPinRecN).insert(boxVL4)
        shapes(LayerPinRecN).insert(
            pya.Text(
                "elec2h1",
                pya.Trans(
                    pya.Trans.R0,
                    x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 5.0 / dbu,
                    -w / 2.0 - 7.5 / dbu))).text_size = 0.5 / dbu

        #Create the MH Layer
        poly = pya.Path(arc(self.r / dbu, angle_min_MH, angle_max_MH),
                        w_mh).transformed(t).simple_polygon()
        self.cell.shapes(LayermhN).insert(poly)
        boxMH1 = pya.Box(x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi),
                         -w / 2.0 - 2.5 / dbu,
                         x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + w_mh,
                         y0 + (r_mh_in) * sin(angle_min_MH / 180 * pi))
        shapes(LayermhN).insert(boxMH1)
        boxMH2 = pya.Box(x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - w_mh,
                         -w / 2.0 - 2.5 / dbu,
                         x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi),
                         y0 + (r_mh_in) * sin(angle_min_MH / 180 * pi))
        shapes(LayermhN).insert(boxMH2)
        boxMH3 = pya.Box(
            x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi),
            -w / 2.0 - 12.5 / dbu,
            x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 10 / dbu,
            -w / 2.0 - 2.5 / dbu)
        shapes(LayermhN).insert(boxMH3)
        boxMH4 = pya.Box(
            x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 10 / dbu,
            -w / 2.0 - 12.5 / dbu,
            x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi),
            -w / 2.0 - 2.5 / dbu)
        shapes(LayermhN).insert(boxMH4)

        # Create the pins, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        shapes(LayerPinRecN).insert(
            pya.Path([
                pya.Point(x0 - (w_Si3 / 2 + taper_length) + pin_length / 2, 0),
                pya.Point(x0 - (w_Si3 / 2 + taper_length) - pin_length / 2, 0)
            ], w))
        shapes(LayerPinRecN).insert(
            pya.Text(
                "opt1",
                pya.Trans(pya.Trans.R0, x0 - (w_Si3 / 2 + taper_length),
                          0))).text_size = 0.5 / dbu

        shapes(LayerPinRecN).insert(
            pya.Path([
                pya.Point(x0 + (w_Si3 / 2 + taper_length) - pin_length / 2, 0),
                pya.Point(x0 + (w_Si3 / 2 + taper_length) + pin_length / 2, 0)
            ], w))
        shapes(LayerPinRecN).insert(
            pya.Text(
                "opt2",
                pya.Trans(pya.Trans.R0, x0 + (w_Si3 / 2 + taper_length),
                          0))).text_size = 0.5 / dbu

        shapes(LayerPinRecN).insert(
            pya.Path([
                pya.Point(x0 - (w_Si3 / 2 + taper_length) + pin_length / 2,
                          y_offset),
                pya.Point(x0 - (w_Si3 / 2 + taper_length) - pin_length / 2,
                          y_offset)
            ], w))
        shapes(LayerPinRecN).insert(
            pya.Text(
                "opt3",
                pya.Trans(pya.Trans.R0, x0 - (w_Si3 / 2 + taper_length),
                          y_offset))).text_size = 0.5 / dbu

        shapes(LayerPinRecN).insert(
            pya.Path([
                pya.Point(x0 + (w_Si3 / 2 + taper_length) - pin_length / 2,
                          y_offset),
                pya.Point(x0 + (w_Si3 / 2 + taper_length) + pin_length / 2,
                          y_offset)
            ], w))
        shapes(LayerPinRecN).insert(
            pya.Text(
                "opt4",
                pya.Trans(pya.Trans.R0, x0 + (w_Si3 / 2 + taper_length),
                          y_offset))).text_size = 0.5 / dbu

        # Create the device recognition layer
        shapes(LayerDevRecN).insert(
            pya.Box(x0 - (w_Si3 / 2 + taper_length), -w / 2.0 - 12.5 / dbu,
                    x0 + (w_Si3 / 2 + taper_length),
                    y0 + r_m1_out + w_m1_out + h_via))

        # Compact model information
        shape = shapes(LayerDevRecN).insert(pya.Text('Lumerical_INTERCONNECT_library=Design kits/GSiP', \
          pya.Trans(pya.Trans.R0,0, 0))).text_size = 0.3/dbu
        shapes(LayerDevRecN).insert(pya.Text ('Component=Ring_Filter_DB', \
          pya.Trans(pya.Trans.R0,0, w*2))).text_size = 0.3/dbu
        shapes(LayerDevRecN).insert(pya.Text('Component_ID=%s' % self.component_ID, \
          pya.Trans(pya.Trans.R0,0, w*4))).text_size = 0.3/dbu
        shapes(LayerDevRecN).insert(pya.Text \
          ('Spice_param:radius=%.3fu wg_width=%.3fu gap=%.3fu gap_monitor=%.3fu' %\
          (self.r, self.w, self.g, self.gmon), \
          pya.Trans(pya.Trans.R0,0, -w*2) ) ).text_size = 0.3/dbu

        # Add a polygon text description
        from SiEPIC.utils import layout_pgtext
        if self.textpolygon:
            layout_pgtext(self.cell, self.textl, self.w, self.r + self.w,
                          "%.3f-%g" % (self.r, self.g), 1)
    def produce_impl(self):
        import math
        try:
            from SiEPIC.utils.layout import layout_waveguide_sbend, layout_taper
        except:
            from siepic_tools.utils.layout import layout_waveguide_sbend, layout_taper

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        from SiEPIC.extend import to_itype

        # Draw the Bragg grating (bottom):
        box_width = int(round(self.grating_period / 2 / dbu))
        grating_period = int(round(self.grating_period / dbu))

        w = to_itype(self.wg1_width, dbu)
        GaussianIndex = self.apodization_index
        half_w = w / 2
        half_corrugation_w = to_itype(self.corrugation_width1 / 2, dbu)

        y_offset_top = -w / 2 - to_itype(self.gap / 2, dbu)

        if self.AR:
            misalignment = grating_period / 2
        else:
            misalignment = 0

        N = self.number_of_periods
        if self.sinusoidal:
            npoints_sin = 40
            for i in range(0, self.number_of_periods):
                x = (round((i * self.grating_period) / dbu))
                profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                                   (i - N / 2) / (N))**2)
                profile = int(round(
                    self.corrugation_width1 / 2 / dbu)) * profileFunction
                box1 = Box(x, y_offset_top, x + box_width,
                           y_offset_top + half_w + profile)
                pts1 = [Point(x, y_offset_top)]
                pts3 = [Point(x + misalignment, y_offset_top)]

                for i1 in range(0, npoints_sin + 1):
                    x1 = i1 * 2 * math.pi / npoints_sin
                    y1 = round(profile * math.sin(x1))
                    x1 = round(x1 / 2 / math.pi * grating_period)
                    pts1.append(Point(x + x1, y_offset_top + half_w + y1))
                    pts3.append(
                        Point(x + misalignment + x1,
                              y_offset_top - half_w - y1))

                pts1.append(Point(x + grating_period, y_offset_top))
                pts3.append(
                    Point(x + grating_period + misalignment, y_offset_top))
                shapes(LayerSiN).insert(Polygon(pts1))
                shapes(LayerSiN).insert(Polygon(pts3))
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, y_offset_top, length,
                           y_offset_top + half_w)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, y_offset_top, misalignment,
                           y_offset_top - half_w)
                shapes(LayerSiN).insert(box3)

        else:
            for i in range(0, self.number_of_periods):
                x = int(round((i * self.grating_period) / dbu))

                profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                                   (i - N / 2) / (N))**2)
                profile = int(round(
                    self.corrugation_width1 / 2 / dbu)) * profileFunction

                box1 = Box(
                    x, y_offset_top, x + box_width,
                    y_offset_top + to_itype(half_w + profile, dbu * 1000))
                box2 = Box(
                    x + box_width, y_offset_top, x + grating_period,
                    y_offset_top + to_itype(half_w - profile, dbu * 1000))
                box3 = Box(
                    x + misalignment, y_offset_top,
                    x + box_width + misalignment,
                    y_offset_top + to_itype(-half_w - profile, dbu * 1000))
                box4 = Box(
                    x + box_width + misalignment, y_offset_top,
                    x + grating_period + misalignment,
                    y_offset_top + to_itype(-half_w + profile, dbu * 1000))
                shapes(LayerSiN).insert(box1)
                shapes(LayerSiN).insert(box2)
                shapes(LayerSiN).insert(box3)
                shapes(LayerSiN).insert(box4)
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, y_offset_top, length,
                           y_offset_top + half_w)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, y_offset_top, misalignment,
                           y_offset_top - half_w)
                shapes(LayerSiN).insert(box3)

        vertical_offset = int(round(self.wg2_width / 2 / dbu)) + int(
            round(self.gap / 2 / dbu))

        if misalignment > 0:
            t = Trans(Trans.R0, 0, vertical_offset)
        else:
            t = Trans(Trans.R0, 0, vertical_offset)

        # Draw the Bragg grating (top):
        box_width = int(round(self.grating_period / 2 / dbu))
        grating_period = int(round(self.grating_period / dbu))
        w = to_itype(self.wg2_width, dbu)
        half_w = w / 2
        half_corrugation_w = int(round(self.corrugation_width2 / 2 / dbu))

        N = self.number_of_periods
        if self.sinusoidal:
            npoints_sin = 40
            for i in range(0, self.number_of_periods):
                x = (round((i * self.grating_period) / dbu))
                profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                                   (i - N / 2) / (N))**2)
                profile = int(round(
                    self.corrugation_width2 / 2 / dbu)) * profileFunction
                box1 = Box(x, 0, x + box_width,
                           -half_w + profile).transformed(t)
                pts1 = [Point(x, 0)]
                pts3 = [Point(x + misalignment, 0)]
                for i1 in range(0, npoints_sin + 1):
                    x1 = i1 * 2 * math.pi / npoints_sin
                    y1 = round(profile * math.sin(x1))
                    x1 = round(x1 / 2 / math.pi * grating_period)
                    #          print("x: %s, y: %s" % (x1,y1))
                    pts1.append(Point(x + x1, -half_w - y1))
                    pts3.append(Point(x + misalignment + x1, +half_w + y1))
                pts1.append(Point(x + grating_period, 0))
                pts3.append(Point(x + grating_period + misalignment, 0))
                shapes(LayerSiN).insert(Polygon(pts1).transformed(t))
                shapes(LayerSiN).insert(Polygon(pts3).transformed(t))
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, 0, length,
                           -half_w).transformed(t)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, 0, misalignment, half_w).transformed(t)
                shapes(LayerSiN).insert(box3)

        else:
            for i in range(0, self.number_of_periods):
                x = int(round((i * self.grating_period) / dbu))
                profileFunction = math.exp(-0.5 * (2 * GaussianIndex *
                                                   (i - N / 2) / (N))**2)
                profile = int(round(
                    self.corrugation_width2 / 2 / dbu)) * profileFunction
                box1 = Box(x, 0, x + box_width,
                           -half_w - profile).transformed(t)
                box2 = Box(x + box_width, 0, x + grating_period,
                           -half_w + profile).transformed(t)
                box3 = Box(x + misalignment, 0, x + box_width + misalignment,
                           half_w + profile).transformed(t)
                box4 = Box(x + box_width + misalignment, 0,
                           x + grating_period + misalignment,
                           half_w - profile).transformed(t)
                shapes(LayerSiN).insert(box1)
                shapes(LayerSiN).insert(box2)
                shapes(LayerSiN).insert(box3)
                shapes(LayerSiN).insert(box4)
            length = x + grating_period + misalignment
            if misalignment > 0:
                # extra piece at the end:
                box2 = Box(x + grating_period, 0, length,
                           -half_w).transformed(t)
                shapes(LayerSiN).insert(box2)
                # extra piece at the beginning:
                box3 = Box(0, 0, misalignment, half_w).transformed(t)
                shapes(LayerSiN).insert(box3)

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w1 = to_itype(self.wg1_width, dbu)
        w2 = to_itype(self.wg2_width, dbu)
        if self.sbend:

            port_w = to_itype(self.port_w, dbu)
            sbend_r = 25000
            sbend_length = 15000
            sbend_offset = 2 * port_w + port_w - (w1 + w2) / 2 - int(
                round(self.gap / dbu))
            taper_length = 20 * max(abs(w1 - port_w), abs(w2 - port_w))

            t = Trans(Trans.R180, 0, y_offset_top)
            layout_waveguide_sbend(self.cell, LayerSiN, t, w1, sbend_r,
                                   sbend_offset, sbend_length)
            t = Trans(Trans.R0, -sbend_length - taper_length,
                      y_offset_top - sbend_offset)
            layout_taper(self.cell, LayerSiN, t, port_w, w1, taper_length)
            x = -sbend_length - taper_length
            y = y_offset_top - sbend_offset
            make_pin(self.cell,
                     "opt1", [x, y],
                     port_w,
                     pin_length,
                     LayerPinRecN,
                     vertical=0)

            t = Trans(Trans.R180, 0, vertical_offset)
            layout_taper(self.cell, LayerSiN, t, w2, w2, sbend_length / 2)
            t = Trans(Trans.R180, -sbend_length / 2, vertical_offset)
            layout_taper(self.cell, LayerSiN, t, w2, port_w,
                         taper_length + sbend_length / 2)
            x = -taper_length - sbend_length
            y = vertical_offset
            make_pin(self.cell,
                     "opt2", [x, y],
                     port_w,
                     pin_length,
                     LayerPinRecN,
                     vertical=0)

            t = Trans(Trans.R0, length, y_offset_top)
            layout_waveguide_sbend(self.cell, LayerSiN, t, w1, sbend_r,
                                   -sbend_offset, sbend_length)
            t = Trans(Trans.R0, length + sbend_length,
                      y_offset_top - sbend_offset)
            layout_taper(self.cell, LayerSiN, t, w1, port_w, taper_length)
            x = length + sbend_length + taper_length
            y = y_offset_top - sbend_offset
            make_pin(self.cell,
                     "opt3", [x, y],
                     port_w,
                     -pin_length,
                     LayerPinRecN,
                     vertical=0)

            t = Trans(Trans.R0, length, vertical_offset)
            layout_taper(self.cell, LayerSiN, t, w2, w2, sbend_length / 2)
            t = Trans(Trans.R0, length + sbend_length / 2, vertical_offset)
            layout_taper(self.cell, LayerSiN, t, w2, port_w,
                         taper_length + sbend_length / 2)
            x = length + taper_length + sbend_length
            y = vertical_offset
            make_pin(self.cell,
                     "opt4", [x, y],
                     port_w,
                     -pin_length,
                     LayerPinRecN,
                     vertical=0)

        else:
            x = 0
            y = y_offset_top
            make_pin(self.cell,
                     "opt1", [x, y],
                     w1,
                     pin_length,
                     LayerPinRecN,
                     vertical=0)

            y = vertical_offset
            make_pin(self.cell,
                     "opt2", [x, y],
                     w2,
                     pin_length,
                     LayerPinRecN,
                     vertical=0)

            x = length
            y = y_offset_top
            make_pin(self.cell,
                     "opt3", [x, y],
                     w1,
                     -pin_length,
                     LayerPinRecN,
                     vertical=0)

            x = length
            y = vertical_offset
            make_pin(self.cell,
                     "opt4", [x, y],
                     w2,
                     -pin_length,
                     LayerPinRecN,
                     vertical=0)

        # Compact model information
        t = Trans(Trans.R0, 10, 0)
        text = Text('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, 10, 500)
        text = Text('Component=contra_directional_coupler', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, 10, -500)
        text = Text \
          ('Spice_param:number_of_periods=%s grating_period=%.3fu wg1_width=%.3fu wg2_width=%.3fu corrugation_width1=%.3fu corrugation_width2=%.3fu gap=%.3fu apodization_index=%.3f AR=%s sinusoidal=%s accuracy=%s' %\
          (self.number_of_periods, self.grating_period, self.wg1_width, self.wg2_width, self.corrugation_width1, self.corrugation_width2, self.gap, self.apodization_index, int(self.AR), int(self.sinusoidal), int(self.accuracy)), t )
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu

        # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
        if self.sbend:
            box = pya.Box(
                pya.Point(-taper_length - sbend_length,
                          vertical_offset + 3 / 2 * port_w),
                pya.Point(length + taper_length + sbend_length,
                          y_offset_top - sbend_offset - 3 / 2 * port_w))
        else:
            box = pya.Box(
                pya.Point(0, vertical_offset + 3 / 2 * (w1 + w2) / 2),
                pya.Point(length, y_offset_top - 3 / 2 * (w1 + w2) / 2))
        shapes(LayerDevRecN).insert(box)
Example #27
0
  def produce_impl(self):
    import math
    from SiEPIC.extend import to_itype

    # fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout
    shapes = self.cell.shapes

    LayerSi = self.layer
    LayerSiN = ly.layer(LayerSi)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)
    
    # Draw the Bragg grating (bottom):
    box_width = int(round(self.grating_period/2/dbu))
    grating_period = int(round(self.grating_period/dbu))
    w = to_itype(self.wg1_width,dbu)
    GaussianIndex = self.index
    half_w = w/2
    half_corrugation_w = int(round(self.corrugation_width1/2/dbu))
    
    if self.AR:
      misalignment = grating_period/2
    else:
      misalignment = 0

    N = self.number_of_periods
    if self.sinusoidal:
      npoints_sin = 40
      for i in range(0,self.number_of_periods):
        x = (round((i * self.grating_period)/dbu))
        deltaW1 = int(round(self.corrugation_width1/2/dbu))
        box1 = Box(x, 0, x + box_width, half_w+deltaW1)
        pts1 = [Point(x,0)]
        pts3 = [Point(x + misalignment,0)]
        for i1 in range(0,npoints_sin+1):
          x1 = i1 * 2* math.pi / npoints_sin
          y1 = round(deltaW1*math.sin(x1))
          x1 = round(x1/2/math.pi*grating_period)
#          print("x: %s, y: %s" % (x1,y1))
          pts1.append( Point(x + x1,half_w+y1 ) )
          pts3.append( Point(x + misalignment + x1,-half_w-y1 ) )
        pts1.append( Point(x + grating_period, 0) )
        pts3.append( Point(x + grating_period + misalignment, 0) )
        shapes(LayerSiN).insert(Polygon(pts1))
        shapes(LayerSiN).insert(Polygon(pts3))
      length = x + grating_period + misalignment
      if misalignment > 0:
        # extra piece at the end:
        box2 = Box(x + grating_period, 0, length, half_w)
        shapes(LayerSiN).insert(box2)
        # extra piece at the beginning:
        box3 = Box(0, 0, misalignment, -half_w)
        shapes(LayerSiN).insert(box3)

    else:
    
      
      
      for i in range(0,self.number_of_periods):
        x = int(round((i * self.grating_period)/dbu))
        
        deltaW1 = int(round(self.corrugation_width1/2/dbu))
        box1 = Box(x, 0, x + box_width, half_w+deltaW1)
        box2 = Box(x + box_width, 0, x + grating_period, half_w-deltaW1)
        box3 = Box(x + misalignment, 0, x + box_width + misalignment, -half_w-deltaW1)
        box4 = Box(x + box_width + misalignment, 0, x + grating_period + misalignment, -half_w+deltaW1)
        shapes(LayerSiN).insert(box1)
        shapes(LayerSiN).insert(box2)
        shapes(LayerSiN).insert(box3)
        shapes(LayerSiN).insert(box4)
      length = x + grating_period + misalignment
      if misalignment > 0:
        # extra piece at the end:
        box2 = Box(x + grating_period, 0, length, half_w)
        shapes(LayerSiN).insert(box2)
        # extra piece at the beginning:
        box3 = Box(0, 0, misalignment, -half_w)
        shapes(LayerSiN).insert(box3)

    vertical_offset = int(round(self.wg2_width/2/dbu))+int(round(self.gap/dbu))+int(round(self.wg1_width/2/dbu))
    
    if misalignment > 0:
      t = Trans(Trans.R0, 0,vertical_offset)
    else:
      t = Trans(Trans.R0, 0,vertical_offset)
    
    # Draw the Bragg grating (top):
    box_width = int(round(self.grating_period/2/dbu))
    grating_period = int(round(self.grating_period/dbu))
    w = to_itype(self.wg2_width,dbu)
    GaussianIndex = self.index
    half_w = w/2
    half_corrugation_w = int(round(self.corrugation_width2/2/dbu))
    

    N = self.number_of_periods
    if self.sinusoidal:
      npoints_sin = 40
      for i in range(0,self.number_of_periods):

        periodGap = int(round(self.gap/dbu))
        vertical_offset = int(round(self.wg2_width/2/dbu))+periodGap+int(round(self.wg1_width/2/dbu))
        if misalignment > 0:
          t = Trans(Trans.R0, 0,vertical_offset)
        else:
          t = Trans(Trans.R0, 0,vertical_offset)
      
        x = (round((i * self.grating_period)/dbu))
        deltaW2 = int(round(self.corrugation_width2/2/dbu));
        box1 = Box(x, 0, x + box_width, -half_w+deltaW2).transformed(t)
        pts1 = [Point(x,0)]
        pts3 = [Point(x + misalignment,0)]
        for i1 in range(0,npoints_sin+1):
          x1 = i1 * 2* math.pi / npoints_sin
          y1 = round(deltaW2*math.sin(x1))
          x1 = round(x1/2/math.pi*grating_period)
#          print("x: %s, y: %s" % (x1,y1))
          pts1.append( Point(x + x1,-half_w-y1 ) )
          pts3.append( Point(x + misalignment + x1,+half_w+y1 ) )
        pts1.append( Point(x + grating_period, 0) )
        pts3.append( Point(x + grating_period + misalignment, 0) )
        shapes(LayerSiN).insert(Polygon(pts1).transformed(t))
        shapes(LayerSiN).insert(Polygon(pts3).transformed(t))
      length = x + grating_period + misalignment
      if misalignment > 0:
        # extra piece at the end:
        box2 = Box(x + grating_period, 0, length, -half_w).transformed(t)
        shapes(LayerSiN).insert(box2)
        # extra piece at the beginning:
        box3 = Box(0, 0, misalignment, half_w).transformed(t)
        shapes(LayerSiN).insert(box3)

    else:
    
      
      
      for i in range(0,self.number_of_periods):
        x = int(round((i * self.grating_period)/dbu))
        
        periodGap = int(round(self.gap/dbu)) + 2*int(round(self.H/dbu)) *(1-math.exp( (-self.index*(i-0.5*N)**2)/(N**2) ))
        vertical_offset = int(round(self.wg2_width/2/dbu))+periodGap+int(round(self.wg1_width/2/dbu))
        if misalignment > 0:
          t = Trans(Trans.R0, 0,vertical_offset)
        else:
          t = Trans(Trans.R0, 0,vertical_offset)
          
        deltaW2 = int(round(self.corrugation_width2/2/dbu));
        box1 = Box(x, 0, x + box_width, -half_w-deltaW2).transformed(t)
        box2 = Box(x + box_width, 0, x + grating_period, -half_w+deltaW2).transformed(t)
        box3 = Box(x + misalignment, 0, x + box_width + misalignment, half_w+deltaW2).transformed(t)
        box4 = Box(x + box_width + misalignment, 0, x + grating_period + misalignment, half_w-deltaW2).transformed(t)
        shapes(LayerSiN).insert(box1)
        shapes(LayerSiN).insert(box2)
        shapes(LayerSiN).insert(box3)
        shapes(LayerSiN).insert(box4)
      length = x + grating_period + misalignment
      if misalignment > 0:
        # extra piece at the end:
        box2 = Box(x + grating_period, 0, length, -half_w).transformed(t)
        shapes(LayerSiN).insert(box2)
        # extra piece at the beginning:
        box3 = Box(0, 0, misalignment, half_w).transformed(t)
        shapes(LayerSiN).insert(box3)
        
         
    # Create the pins on the waveguides, as short paths:
    from SiEPIC._globals import PIN_LENGTH as pin_length

    w = to_itype(self.wg1_width,dbu)
    t = Trans(Trans.R0, 0,0)
    pin = Path([Point(pin_length/2, 0), Point(-pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin1", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    w = to_itype(self.wg2_width,dbu)
    t = Trans(Trans.R0, 0,vertical_offset)
    pin = Path([Point(pin_length/2, 0), Point(-pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin3", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    w = to_itype(self.wg1_width,dbu)
    t = Trans(Trans.R0, length,0)
    pin = Path([Point(-pin_length/2, 0), Point(pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin2", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    w = to_itype(self.wg2_width,dbu)
    t = Trans(Trans.R0, length,vertical_offset)
    pin = Path([Point(-pin_length/2, 0), Point(pin_length/2, 0)], w)
    pin_t = pin.transformed(t)
    shapes(LayerPinRecN).insert(pin_t)
    text = Text ("pin4", t)
    shape = shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    # Compact model information
    t = Trans(Trans.R0, 0, 0)
    text = Text ('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/10, 0)
    text = Text ('Component=ebeam_contra_dc', t)
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu
    t = Trans(Trans.R0, length/9, 0)
    text = Text \
      ('Spice_param:number_of_periods=%s grating_period=%.3fu corrugation_width=%.3fu misalignment=%.3fu sinusoidal=%s' %\
      (self.number_of_periods, self.grating_period, self.corrugation_width1, misalignment, int(self.sinusoidal)), t )
    shape = shapes(LayerDevRecN).insert(text)
    shape.text_size = 0.1/dbu

    # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
    t = Trans(Trans.R0, 0,0)
    path = Path([Point(0, vertical_offset/2), Point(length, vertical_offset/2)], 3*w)
    shapes(LayerDevRecN).insert(path.simple_polygon())
Example #28
0
    def produce(self, layout, layers, parameters, cell):

        # coerce parameters (make consistent)

        self._layers = layers
        self.cell = cell
        self._param_values = parameters
        self.layout = layout

        # cell: layout cell to place the layout
        # LayerSiN: which layer to use
        # r: radius
        # w: waveguide width
        # length units in dbu

        from math import pi, cos, sin
        from SiEPIC.utils import arc_wg, arc_wg_xy
        from SiEPIC._globals import PIN_LENGTH
        from SiEPIC.utils.layout import layout_waveguide2
        from SiEPIC.extend import to_itype

        # fetch the parameters
        TECHNOLOGY = get_technology_by_name('EBeam')
        dbu = self.layout.dbu
        ly = self.layout

        LayerSiN = ly.layer(self.silayer)
        LayerSlab = ly.layer(self.slayer)
        #    LayerNN = ly.layer(self.nlayer)
        LayerNPPN = ly.layer(self.npplayer)
        LayerVCN = ly.layer(self.vclayer)
        LayerMN = ly.layer(self.mlayer)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)
        TextLayerN = ly.layer(self.textl)

        ## define parameters for phase shifter
        overlay = to_itype(self.overlay, dbu)
        overlay_ebl = to_itype(self.overlay_ebl, dbu)

        ## define waveguide related parameters
        radius_um, adiab, bezier = 5, 1, 0.2
        w = to_itype(self.width, dbu)  #waveguide width, default 0.5 um
        l = to_itype(self.length, dbu)  #pahse shifter length, default 150 um
        npp_d = to_itype(self.npp_distance,
                         dbu)  #npp to center waveguide distance
        sw = (npp_d + w / 2) * 2  #twice of npp_d that is defined above
        in_rib = to_itype(
            self.input_rib_width, dbu
        )  #the slab width of the input/output waveguide to the phase shifter
        in_taper = to_itype(
            self.in_taper_length, dbu
        )  #the input waveguide to phase shifter dimension transfer taper length, default 15
        edge_slab_width = to_itype(
            4, dbu
        )  #width of the 90 nm slab that is outside of all the folding waveguide, default 2 * 2um
        npp_width = to_itype(self.npp_width, dbu)  #npp width, default 5 um

        ## define waveguide folding parameters
        folding_n = int(round((self.fold_number - 1) /
                              2))  # folding waveguide number on one side
        folding_w1 = w + 50  # one of the folding waveguide width
        folding_w2 = w - 50  # the other one of the folding waveguide width
        folding_gap = to_itype(2, dbu)  # the gap between two folding waveguide
        routing_step = to_itype(
            radius_um,
            dbu)  # define how large the U shape should be, default 20

        ## define node related parameters
        contact_size = to_itype(self.vc_w,
                                dbu)  # square NPP size, for VC purpose
        pin_text_size = to_itype(0.4, dbu)  # pin text size

        metal_routing_distance_to_node = to_itype(
            30, dbu)  # *** calculate from PCell parameters ***
        metal_routing_width = to_itype(self.m_w, dbu)  # width of metal
        vc_to_npp_exclusion = to_itype(
            self.overlay, dbu)  # VC boundary to NPP boundary distance

        ps_sl_w = sw + 2 * contact_size + folding_n * 2 * (
            w + folding_gap + overlay_ebl
        )  # overall pahse shifter 90nm slab width

        # measure the total length of the waveguides
        total_waveguide_length = 0

        ## define strip to slab transfer taper parameters
        N = 100
        # Number of points for the input/output slab taper
        order = 3
        # input/output slab taper curve

        pts = [Point(-l / 2, 0), Point(l / 2, 0)]
        total_waveguide_length += layout_waveguide2(TECHNOLOGY, self.layout,
                                                    self.cell, ['Si'],
                                                    [w * dbu], [0], pts,
                                                    radius_um, adiab, bezier)

        wg2 = pya.Box(-l / 2, -ps_sl_w / 2, l / 2, ps_sl_w / 2)
        wg3 = pya.Box(-l / 2, npp_d + w / 2, l / 2, npp_d + w / 2 + npp_width)
        wg4 = pya.Box(-l / 2, -npp_d - w / 2, l / 2,
                      -npp_d - w / 2 - npp_width)

        self.cell.shapes(LayerNPPN).insert(wg3)
        self.cell.shapes(LayerNPPN).insert(wg4)

        if self.io_wg_type:
            in_slab = to_itype(self.input_slab_width, dbu)
        else:
            in_slab = in_rib

        if folding_n > 0:
            ps_sl_w = contact_size * 2 + sw * 2 + (
                folding_w1 + folding_w2 +
                folding_gap * 2) * folding_n + edge_slab_width
            wg2 = pya.Box(-l / 2, -ps_sl_w / 2, l / 2, ps_sl_w / 2)
            self.cell.shapes(LayerSlab).insert(wg2)

            pts = [
                Point(-l / 2 - in_taper, -w / 2),
                Point(-l / 2, -w / 2),
                Point(-l / 2, w / 2),
                Point(-l / 2 - in_taper, w / 2)
            ]  # fix waveguide width mismatch for left center input taper
            self.cell.shapes(LayerSiN).insert(Polygon(pts))

            # add input slab taper
            pts = []
            for i in range(0, N + 1):
                pts.append(
                    Point(
                        -l / 2 - in_taper + in_taper / N * i,
                        w / 2 + ((sw / 2 + contact_size - w) /
                                 (N**order)) * (i**order)))
            for i in range(0, N + 1):
                pts.append(
                    Point(
                        -l / 2 - in_taper + in_taper / N * (N - i),
                        -w / 2 - ((sw / 2 + contact_size - w) /
                                  (N**order)) * ((N - i)**order)))
            self.cell.shapes(LayerSlab).insert(Polygon(pts))

            # add output strip taper
            pts = [
                Point(l / 2 + in_taper, -w / 2),
                Point(l / 2, -w / 2),
                Point(l / 2, w / 2),
                Point(l / 2 + in_taper, w / 2)
            ]
            #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
            self.cell.shapes(LayerSiN).insert(Polygon(pts))
            total_waveguide_length += in_taper * dbu

            # add input slab taper
            pts = []
            for i in range(0, N + 1):
                pts.append(
                    Point(l / 2 + in_taper - in_taper / N * i,
                          (w - overlay_ebl) / 2 + ((sw / 2 + contact_size -
                                                    (w - overlay_ebl)) /
                                                   (N**order)) * (i**order)))
            for i in range(0, N + 1):
                pts.append(
                    Point(
                        l / 2 + in_taper / N * i, -(w - overlay_ebl) / 2 -
                        ((sw / 2 + contact_size - (w - overlay_ebl)) /
                         (N**order)) * ((N - i)**order)))
            self.cell.shapes(LayerSlab).insert(Polygon(pts))

            for i in range(0, folding_n):
                y_coordinate = contact_size + sw + 2 * vc_to_npp_exclusion  # move up/down the position according to vc_to_npp_exclusion
                y_move = i * (folding_w1 + folding_w2 +
                              folding_gap * 2) / 2 + y_coordinate
                if i % 2:
                    folding_w = folding_w2
                else:
                    folding_w = folding_w1

                # waveguide in the heated region
                pts = [Point(-l / 2, y_move), Point(l / 2, y_move)]
                total_waveguide_length += layout_waveguide2(
                    TECHNOLOGY, self.layout, self.cell, ['Si'],
                    [folding_w * dbu], [0], pts, radius_um, adiab, bezier)
                pts = [Point(-l / 2, -y_move), Point(l / 2, -y_move)]
                total_waveguide_length += layout_waveguide2(
                    TECHNOLOGY, self.layout, self.cell, ['Si'],
                    [folding_w * dbu], [0], pts, radius_um, adiab, bezier)

                # add upper left input taper
                pts = [
                    Point(-l / 2 - in_taper, -w / 2 + y_move),
                    Point(-l / 2, -folding_w / 2 + y_move),
                    Point(-l / 2, folding_w / 2 + y_move),
                    Point(-l / 2 - in_taper, w / 2 + y_move)
                ]
                #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                self.cell.shapes(LayerSiN).insert(Polygon(pts))
                total_waveguide_length += in_taper * dbu

                # slab cubic taper
                pts = []
                for ii in range(0, N + 1):
                    pts.append(
                        Point(-l / 2 - in_taper + in_taper / N * ii,
                              (w - overlay_ebl) / 2 +
                              ((2 / dbu - (w - overlay_ebl)) /
                               (N**order)) * (ii**order) + y_move))
                for ii in range(0, N + 1):
                    pts.append(
                        Point(
                            -l / 2 - in_taper + in_taper / N * (N - ii),
                            -(w - overlay_ebl) / 2 -
                            ((2 / dbu - (w - overlay_ebl)) /
                             (N**order)) * ((N - ii)**order) + y_move))
                self.cell.shapes(LayerSlab).insert(Polygon(pts))

                if (i != folding_n - 1):
                    # add below left taper
                    y_move = -y_move
                    pts = [
                        Point(-l / 2 - in_taper, -w / 2 + y_move),
                        Point(-l / 2, -folding_w / 2 + y_move),
                        Point(-l / 2, folding_w / 2 + y_move),
                        Point(-l / 2 - in_taper, w / 2 + y_move)
                    ]
                    #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                    self.cell.shapes(LayerSiN).insert(Polygon(pts))
                    total_waveguide_length += in_taper * dbu

                    # slab cubic taper
                    pts = []
                    for ii in range(0, N + 1):
                        pts.append(
                            Point(-l / 2 - in_taper + in_taper / N * ii,
                                  (w - overlay_ebl) / 2 +
                                  ((2 / dbu - (w - overlay_ebl)) /
                                   (N**order)) * (ii**order) + y_move))
                    for ii in range(0, N + 1):
                        pts.append(
                            Point(
                                -l / 2 - in_taper + in_taper / N * (N - ii),
                                -(w - overlay_ebl) / 2 -
                                ((2 / dbu - (w - overlay_ebl)) /
                                 (N**order)) * ((N - ii)**order) + y_move))
                    self.cell.shapes(LayerSlab).insert(Polygon(pts))

                    # add upper right taper
                    y_move = -y_move
                    pts = [
                        Point(l / 2 + in_taper, -w / 2 + y_move),
                        Point(l / 2, -folding_w / 2 + y_move),
                        Point(l / 2, folding_w / 2 + y_move),
                        Point(l / 2 + in_taper, w / 2 + y_move)
                    ]
                    #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                    self.cell.shapes(LayerSiN).insert(Polygon(pts))
                    total_waveguide_length += in_taper * dbu

                    # slab cubic taper
                    pts = []
                    for ii in range(0, N + 1):
                        pts.append(
                            Point(l / 2 + in_taper - in_taper / N * ii,
                                  (w - overlay_ebl) / 2 +
                                  ((2 / dbu - (w - overlay_ebl)) /
                                   (N**order)) * (ii**order) + y_move))
                    for ii in range(0, N + 1):
                        pts.append(
                            Point(
                                l / 2 + in_taper / N * ii,
                                -(w - overlay_ebl) / 2 -
                                ((2 / dbu - (w - overlay_ebl)) /
                                 (N**order)) * ((N - ii)**order) + y_move))
                    self.cell.shapes(LayerSlab).insert(Polygon(pts))

                else:
                    y_move = -y_move
                    # add input strip taper
                    pts = [
                        Point(-l / 2 - in_taper, -w / 2 + y_move),
                        Point(-l / 2, -folding_w / 2 + y_move),
                        Point(-l / 2, folding_w / 2 + y_move),
                        Point(-l / 2 - in_taper, w / 2 + y_move)
                    ]
                    #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                    self.cell.shapes(LayerSiN).insert(Polygon(pts))
                    total_waveguide_length += in_taper * dbu

                    # add input slab taper
                    pts = []
                    for i in range(0, N + 1):
                        pts.append(
                            Point(
                                -l / 2 - in_taper + in_taper / N * i,
                                in_slab / 2 + ((edge_slab_width - in_slab) /
                                               (N**order)) * (i**order) +
                                y_move))
                    for i in range(0, N + 1):
                        pts.append(
                            Point(
                                -l / 2 - in_taper + in_taper / N * (N - i),
                                -in_slab / 2 - ((edge_slab_width - in_slab) /
                                                (N**order)) *
                                ((N - i)**order) + y_move))
                    self.cell.shapes(LayerSlab).insert(Polygon(pts))

                    # add output strip taper
                    y_move = -y_move
                    pts = [
                        Point(l / 2 + in_taper, -w / 2 + y_move),
                        Point(l / 2, -folding_w / 2 + y_move),
                        Point(l / 2, folding_w / 2 + y_move),
                        Point(l / 2 + in_taper, w / 2 + y_move)
                    ]
                    #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                    self.cell.shapes(LayerSiN).insert(Polygon(pts))
                    total_waveguide_length += in_taper * dbu

                    # add input slab taper
                    pts = []
                    for i in range(0, N + 1):
                        pts.append(
                            Point(
                                l / 2 + in_taper - in_taper / N * i,
                                in_slab / 2 + ((edge_slab_width - in_slab) /
                                               (N**order)) * (i**order) +
                                y_move))
                    for i in range(0, N + 1):
                        pts.append(
                            Point(
                                l / 2 + in_taper / N * i, -in_slab / 2 -
                                ((edge_slab_width - in_slab) /
                                 (N**order)) * ((N - i)**order) + y_move))
                    self.cell.shapes(LayerSlab).insert(Polygon(pts))

                    # Pin on the left side:
                    wg_start = -(l / 2 + in_taper +
                                 routing_step * folding_n * 3 + w)
                    p1 = [
                        Point(wg_start + PIN_LENGTH / 2, -y_move),
                        Point(wg_start - PIN_LENGTH / 2, -y_move)
                    ]
                    p1c = Point(wg_start, -y_move)
                    self.set_p1 = p1c
                    self.p1 = p1c
                    pin = Path(p1, w)
                    self.cell.shapes(LayerPinRecN).insert(pin)
                    t = Trans(Trans.R0, wg_start, -y_move)
                    text = Text("pin1", t)
                    shape = self.cell.shapes(LayerPinRecN).insert(text)
                    shape.text_size = pin_text_size
                    # Waveguide to route to port, new in SiEPIC-Tools v0.3.64
                    pts = [
                        Point(-l / 2 - in_taper, -y_move),
                        Point(wg_start, -y_move)
                    ]
                    if self.io_wg_type:
                        waveguide_length = layout_waveguide2(
                            TECHNOLOGY, self.layout, self.cell,
                            ['Si', 'Si - 90 nm rib'], [w * dbu, in_slab * dbu],
                            [0, 0], pts, radius_um, adiab, bezier)
                    else:
                        waveguide_length = layout_waveguide2(
                            TECHNOLOGY, self.layout, self.cell, ['Si'],
                            [w * dbu], [0], pts, radius_um, adiab, bezier)

                    # Pin & Waveguide on the right side:
                    wg_end = l / 2 + in_taper + routing_step * folding_n * 3 + w
                    p2 = [
                        Point(wg_end - PIN_LENGTH / 2, y_move),
                        Point(wg_end + PIN_LENGTH / 2, y_move)
                    ]
                    p2c = Point(wg_end, y_move)
                    self.set_p2 = p2c
                    self.p2 = p2c
                    pin = Path(p2, w)
                    self.cell.shapes(LayerPinRecN).insert(pin)
                    t = Trans(Trans.R0, wg_end, y_move)
                    text = Text("pin2", t)
                    shape = self.cell.shapes(LayerPinRecN).insert(text)
                    shape.text_size = pin_text_size
                    # Waveguide to route to port, new in SiEPIC-Tools v0.3.64
                    pts = [
                        Point(l / 2 + in_taper, y_move),
                        Point(wg_end, y_move)
                    ]
                    if self.io_wg_type:
                        total_waveguide_length += layout_waveguide2(
                            TECHNOLOGY, self.layout, self.cell,
                            ['Si', 'Si - 90 nm rib'], [w * dbu, in_slab * dbu],
                            [0, 0], pts, radius_um, adiab, bezier)
                    else:
                        total_waveguide_length += layout_waveguide2(
                            TECHNOLOGY, self.layout, self.cell, ['Si'],
                            [w * dbu], [0], pts, radius_um, adiab, bezier)

                # add below right taper
                y_move = -y_move
                pts = [
                    Point(l / 2 + in_taper, -w / 2 + y_move),
                    Point(l / 2, -folding_w / 2 + y_move),
                    Point(l / 2, folding_w / 2 + y_move),
                    Point(l / 2 + in_taper, w / 2 + y_move)
                ]
                #wg2 = pya.Box(-l/2,-4/2/dbu,l/2,4/2/dbu)
                self.cell.shapes(LayerSiN).insert(Polygon(pts))
                total_waveguide_length += in_taper * dbu
                pts = []
                for ii in range(0, N + 1):
                    pts.append(
                        Point(l / 2 + in_taper - in_taper / N * ii,
                              (w - overlay_ebl) / 2 +
                              ((2 / dbu - (w - overlay_ebl)) /
                               (N**order)) * (ii**order) + y_move))
                for ii in range(0, N + 1):
                    pts.append(
                        Point(
                            l / 2 + in_taper / N * ii, -(w - overlay_ebl) / 2 -
                            ((2 / dbu - (w - overlay_ebl)) /
                             (N**order)) * ((N - ii)**order) + y_move))
                self.cell.shapes(LayerSlab).insert(Polygon(pts))

            # add metal contact and folded waveguides
            for i in range(-folding_n, folding_n):
                y_coordinate = contact_size + sw + 2 * vc_to_npp_exclusion  # move up/down the position according to vc_to_npp_exclusion
                if i < 0:
                    y_origin = (i + 1) * (folding_w1 + folding_w2 +
                                          folding_gap * 2) / 2 - y_coordinate
                if i == 0:
                    y_origin = 0
                if i > 0:
                    y_origin = (i - 1) * (folding_w1 + folding_w2 +
                                          folding_gap * 2) / 2 + y_coordinate

                if (i + 1) < 0:
                    y_end = (i + 2) * (folding_w1 + folding_w2 +
                                       folding_gap * 2) / 2 - y_coordinate
                if (i + 1) == 0:
                    y_end = 0
                if (i + 1) > 0:
                    y_end = i * (folding_w1 + folding_w2 +
                                 folding_gap * 2) / 2 + y_coordinate

                # Calculate the Folded waveguide vertices
                if (i + folding_n) % 2:
                    # Waveguides on the left side
                    if y_origin + routing_step * 2 - y_end < 2 * radius_um:
                        y_routing = max(routing_step * 2, y_end - y_origin)
                    else:
                        y_routing = y_end + routing_step * 2
                    path = Path([
                        Point(-l / 2 - in_taper, y_origin),
                        Point(
                            -l / 2 - in_taper - routing_step *
                            (1.5 * folding_n - 1.5 * i + 1.5), y_origin),
                        Point(
                            -l / 2 - in_taper - routing_step *
                            (1.5 * folding_n - 1.5 * i + 1.5), y_routing),
                        Point(
                            -l / 2 - in_taper - routing_step *
                            (1.5 * folding_n - 1.5 * i - 0.5), y_routing),
                        Point(
                            -l / 2 - in_taper - routing_step *
                            (1.5 * folding_n - 1.5 * i - 0.5), y_end),
                        Point(-l / 2 - in_taper, y_end)
                    ], 0)

                else:
                    # Waveguides on the right side
                    if y_origin - y_end + routing_step * 2 < 2 * radius_um:
                        y_routing = -max(routing_step * 2, y_end - y_origin)
                    else:
                        y_routing = y_origin - routing_step * 2
                    path = Path([
                        Point(l / 2 + in_taper, y_origin),
                        Point(
                            l / 2 + in_taper + routing_step *
                            (1.5 * folding_n + 1.5 * i + 1), y_origin),
                        Point(
                            l / 2 + in_taper + routing_step *
                            (1.5 * folding_n + 1.5 * i + 1), y_routing),
                        Point(
                            l / 2 + in_taper + routing_step *
                            (1.5 * folding_n + 1.5 * i + 3), y_routing),
                        Point(
                            l / 2 + in_taper + routing_step *
                            (1.5 * folding_n + 1.5 * i + 3), y_end),
                        Point(l / 2 + in_taper, y_end)
                    ], 0)

                # Draw the waveguide geometry, new in SiEPIC-Tools v0.3.64
                path.unique_points()
                pts = path.get_points()
                total_waveguide_length += layout_waveguide2(
                    TECHNOLOGY, self.layout, self.cell, ['Si'], [w * dbu], [0],
                    pts, radius_um, adiab, bezier)

        for i in range(0, self.segments + 1):

            wg_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 -
                vc_to_npp_exclusion, sw / 2,
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                vc_to_npp_exclusion,
                sw / 2 + contact_size + 2 * vc_to_npp_exclusion)
            #self.cell.shapes(LayerNN).insert(wg_temp_upper)
            self.cell.shapes(LayerNPPN).insert(wg_temp_upper)
            #        self.cell.shapes(LayerNN).insert(wg_temp_upper)
            wg_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 -
                2 * vc_to_npp_exclusion, sw / 2,
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                2 * vc_to_npp_exclusion,
                sw / 2 + contact_size + 3 * vc_to_npp_exclusion)
            self.cell.shapes(LayerSlab).insert(wg_temp_upper)

            vc_temp_upper = pya.Box(
                (l - contact_size) / self.segments * i - l / 2,
                sw / 2 + vc_to_npp_exclusion,
                (l - contact_size) / self.segments * i - l / 2 + contact_size,
                sw / 2 + contact_size + vc_to_npp_exclusion)
            self.cell.shapes(LayerVCN).insert(vc_temp_upper)

            wg_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 -
                vc_to_npp_exclusion, -sw / 2,
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                vc_to_npp_exclusion,
                -sw / 2 - contact_size - 2 * vc_to_npp_exclusion)
            #self.cell.shapes(LayerNN).insert(wg_temp_lower)
            self.cell.shapes(LayerNPPN).insert(wg_temp_lower)
            wg_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 -
                2 * vc_to_npp_exclusion, -sw / 2,
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                2 * vc_to_npp_exclusion,
                -sw / 2 - contact_size - 3 * vc_to_npp_exclusion)
            self.cell.shapes(LayerSlab).insert(wg_temp_lower)

            #        self.cell.shapes(LayerNN).insert(wg_temp_lower)
            vc_temp_lower = pya.Box(
                (l - contact_size) / self.segments * i - l / 2,
                -sw / 2 - vc_to_npp_exclusion,
                (l - contact_size) / self.segments * i - l / 2 + contact_size,
                -sw / 2 - contact_size - vc_to_npp_exclusion)
            self.cell.shapes(LayerVCN).insert(vc_temp_lower)

            metal_temp = pya.Box(
                (l - contact_size) / self.segments * i - l / 2 -
                vc_to_npp_exclusion,
                -sw / 2 - contact_size - metal_routing_distance_to_node *
                (i % 2) - 2 * vc_to_npp_exclusion,
                (l - contact_size) / self.segments * i - l / 2 + contact_size +
                vc_to_npp_exclusion,
                sw / 2 + contact_size + metal_routing_distance_to_node *
                ((i + 1) % 2) + 2 * vc_to_npp_exclusion)
            self.cell.shapes(LayerMN).insert(metal_temp)

        metal_routing = Path([
            Point(-l / 2,
                  -sw / 2 - metal_routing_distance_to_node - contact_size),
            Point(l / 2,
                  -sw / 2 - metal_routing_distance_to_node - contact_size)
        ], metal_routing_width)
        self.cell.shapes(LayerMN).insert(metal_routing)
        metal_routing = Path([
            Point(-l / 2,
                  sw / 2 + metal_routing_distance_to_node + contact_size),
            Point(l / 2,
                  sw / 2 + metal_routing_distance_to_node + contact_size)
        ], metal_routing_width)
        self.cell.shapes(LayerMN).insert(metal_routing)

        if folding_n > 0:
            dev = Box(
                wg_start, -sw / 2 - metal_routing_distance_to_node -
                contact_size - metal_routing_width, wg_end,
                sw / 2 + metal_routing_distance_to_node + contact_size +
                metal_routing_width)
            self.cell.shapes(LayerDevRecN).insert(dev)

        t = Trans(0, False, Point(0, 0))
        text = Text ( \
          'Waveguide Length=%.3fu' %(total_waveguide_length), t, 3*w, -1)
        shape = self.cell.shapes(LayerDevRecN).insert(text)
Example #29
0
    def produce_impl(self):

        from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal
        from math import cos, sin, pi, sqrt
        import pya
        from SiEPIC.extend import to_itype

        print("GSiP.Wireguide")

        TECHNOLOGY = get_technology_by_name(
            'GSiP') if op_tag == "GUI" else Tech.load_from_xml(
                lyp_filepath).layers
        dbu = self.layout.dbu
        wg_width = to_itype(self.width, dbu)
        path = self.path.to_itype(dbu)

        if not (len(self.layers) == len(self.widths)
                and len(self.layers) == len(self.offsets)
                and len(self.offsets) == len(self.widths)):
            raise Exception(
                "There must be an equal number of layers, widths and offsets")
        path.unique_points()
        turn = 0
        for lr in range(0, len(self.layers)):
            layer = self.layout.layer(TECHNOLOGY[self.layers[lr]])

            width = to_itype(self.widths[lr], dbu)
            offset = to_itype(self.offsets[lr], dbu)

            pts = path.get_points()
            wg_pts = [pts[0]]
            for i in range(1, len(pts) - 1):
                turn = ((angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] -
                                         pts[i]) + 90) % 360 - 90) / 90
                dis1 = pts[i].distance(pts[i - 1])
                dis2 = pts[i].distance(pts[i + 1])
                angle = angle_vector(pts[i] - pts[i - 1]) / 90
                pt_radius = self.radius
                # determine the radius, based on how much space is available
                if len(pts) == 3:
                    pt_radius = min(dis1, dis2, pt_radius)
                else:
                    if i == 1:
                        if dis1 <= pt_radius:
                            pt_radius = dis1
                    elif dis1 < 2 * pt_radius:
                        pt_radius = dis1 / 2
                    if i == len(pts) - 2:
                        if dis2 <= pt_radius:
                            pt_radius = dis2
                    elif dis2 < 2 * pt_radius:
                        pt_radius = dis2 / 2
                # wireguide bends:
                if (self.adiab):
                    wg_pts += Path(
                        arc_bezier(
                            pt_radius,
                            270,
                            270 + inner_angle_b_vectors(
                                pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                            self.bezier,
                            DevRec='DevRec' in self.layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()
                else:
                    wg_pts += Path(
                        arc_xy(-pt_radius,
                               pt_radius,
                               pt_radius,
                               270,
                               270 + inner_angle_b_vectors(
                                   pts[i - 1] - pts[i], pts[i + 1] - pts[i]),
                               DevRec='DevRec' in self.layers[lr]),
                        0).transformed(Trans(angle, turn < 0,
                                             pts[i])).get_points()
            wg_pts += [pts[-1]]
            wg_pts = pya.Path(wg_pts, 0).unique_points().get_points()
            wg_polygon = Path(wg_pts, wg_width)
            self.cell.shapes(layer).insert(wg_polygon)  # insert the wireguide

            #if self.layout.layer(TECHNOLOGY['Wireguide']) == layer:
            waveguide_length = wg_polygon.area() / self.width * dbu**2

        pts = path.get_points()
        LayerPinRecN = self.layout.layer(TECHNOLOGY['PinRecM'])

        # insert pins to wireguide
        t1 = Trans(angle_vector(pts[0] - pts[1]) / 90, False, pts[0])
        self.cell.shapes(LayerPinRecN).insert(
            Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t1))
        self.cell.shapes(LayerPinRecN).insert(Text("pin1", t1, 0.3 / dbu, -1))

        t = Trans(angle_vector(pts[-1] - pts[-2]) / 90, False, pts[-1])
        self.cell.shapes(LayerPinRecN).insert(
            Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t))
        self.cell.shapes(LayerPinRecN).insert(Text("pin2", t, 0.3 / dbu, -1))

        LayerDevRecN = self.layout.layer(TECHNOLOGY['DevRec'])

        # Compact model information
        angle_vec = angle_vector(pts[0] - pts[1]) / 90
        halign = 0  # left
        angle = 0
        pt2 = pts[0]
        pt3 = pts[0]
        if angle_vec == 0:  # horizontal
            halign = 2  # right
            angle = 0
            pt2 = pts[0] + Point(0, wg_width)
            pt3 = pts[0] + Point(0, -wg_width)
        if angle_vec == 2:  # horizontal
            halign = 0  # left
            angle = 0
            pt2 = pts[0] + Point(0, wg_width)
            pt3 = pts[0] + Point(0, -wg_width)
        if angle_vec == 1:  # vertical
            halign = 2  # right
            angle = 1
            pt2 = pts[0] + Point(wg_width, 0)
            pt3 = pts[0] + Point(-wg_width, 0)
        if angle_vec == -1:  # vertical
            halign = 0  # left
            angle = 1
            pt2 = pts[0] + Point(wg_width, 0)
            pt3 = pts[0] + Point(-wg_width, 0)
Example #30
0
    def produce_impl(self):
        from SiEPIC._globals import PIN_LENGTH
        from SiEPIC.extend import to_itype
        import math
        from pya import DPolygon

        pi = math.pi
        # This is the main part of the implementation: create the layout

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes
        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        #variables
        pitch = self.pitch
        w = self.w
        r = self.r
        ff = self.ff
        angle = self.angle
        gap = self.gap
        gap2 = self.gap2
        row = self.row
        busL = self.busL
        taperL = self.taperL
        #doublebus = self.doublebus
        #print(doublebus)

        if (r - w / 2 <= 0):
            r = 5
            print('invalid radius, set r to default: 5')
        if row <= 1:
            row = 1
            print('invalid number of rows, set row to default: 1')
        if busL <= 10:
            busL = taperL * 2 + 10
            print(
                'invalid length of SWG bus waveguide, set length at least 2 times larger than taper length and pluse 10 um'
            )
        #Calculate number of segments
        s1 = pitch * ff  #silicon
        s2 = pitch - s1  #gap

        # Draw the Multi-box Ring
        for i in range(0, int(row)):  # draw different radius SWG rings
            #calculate best radius
            #const = math.ceil(2*pi*r/(s1+s2))
            const = math.floor(2 * pi * r / (s1 + s2))
            #if doesn't divide evenly, replace r with best possible r
            if ((2 * pi * r) % (s1 + s2) != 0):
                r = const * (s1 + s2) / (2 * pi)
                print('r adjusted to ' + str(r) +
                      'um to fit periods perfectly.')

            theta1 = math.atan(s1 / r)
            theta2 = math.atan(s2 / r)
            nSeg = int(
                math.floor(angle /
                           (math.degrees(theta1) +
                            math.degrees(theta2))))  #how many segments to have
            si_first = True  #for alternating between silicon and gap
            j = 0  #index of how many silicon thetas
            jj = 0  #index of how many gap thetas
            ORDER = True  #ordering of the coordinates for polygon drawing

            xo = [(r - w / 2) * math.cos(0)]
            yo = [(r - w / 2) * math.sin(0)]
            xo.append((r + w / 2) * math.cos(0))
            yo.append((r + w / 2) * math.sin(0))

            for i in range(0, nSeg * 2):
                if si_first:
                    j = j + 1
                    si_first = not (si_first)
                else:
                    jj = jj + 1
                    si_first = not (si_first)

                if ORDER:
                    xo.append((r + w / 2) * math.cos(j * theta1 + jj * theta2))
                    yo.append((r + w / 2) * math.sin(j * theta1 + jj * theta2))
                    xo.append((r - w / 2) * math.cos(j * theta1 + jj * theta2))
                    yo.append((r - w / 2) * math.sin(j * theta1 + jj * theta2))
                    ORDER = not (ORDER)
                else:
                    xo.append((r - w / 2) * math.cos(j * theta1 + jj * theta2))
                    yo.append((r - w / 2) * math.sin(j * theta1 + jj * theta2))
                    xo.append((r + w / 2) * math.cos(j * theta1 + jj * theta2))
                    yo.append((r + w / 2) * math.sin(j * theta1 + jj * theta2))
                    ORDER = not (ORDER)

                if len(xo) == 4:
                    dpts = [pya.DPoint(xo[i], yo[i]) for i in range(len(xo))]
                    dpolygon = DPolygon(dpts)
                    element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                    shapes(LayerSiN).insert(element)
                    xo = []
                    yo = []
            r = r - (w + gap)
# Draw the Bus Waveguides
#Draw Bus WG
# to go back to the initial point for Multi-box drawing, ger the first adjusted r value
        r = self.r
        const = math.floor(2 * pi * r / (s1 + s2))
        #if doesn't divide evenly, replace r with best possible r
        if ((2 * pi * r) % (s1 + s2) != 0):
            r = const * (s1 + s2) / (2 * pi)

        #calulate ideal length of bus
        bus_length = busL
        #bus_length = self.cell.bbox().height()*dbu +pitch*2
        constant = math.ceil(bus_length / (s1 + s2))
        if bus_length % (s1 + s2) != 0:
            bus_length = constant * (s1 + s2)

        for ii in range(0, int(row)):
            xo = [(r + w / 2 + gap2 + ii * (w + gap)),
                  (r + w / 2 + gap2 + w + ii * (w + gap)),
                  (r + w / 2 + gap2 + w + ii * (w + gap)),
                  (r + w / 2 + gap2 + ii * (w + gap))]
            yo = [0, 0, s1, s1]
            dpts = [pya.DPoint(xo[i], yo[i]) for i in range(len(xo))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

            # draw the bus waveguide
            for i in range(0, int(math.ceil((constant) / 2))):
                yu = [yo[j] + i * pitch for j in range(len(yo))]
                yd = [yo[j] - i * pitch for j in range(len(yo))]

                dpts = [pya.DPoint(xo[i], yu[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)
                dpts = [pya.DPoint(xo[i], yd[i]) for i in range(len(xo))]
                dpolygon = DPolygon(dpts)
                element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
                shapes(LayerSiN).insert(element)

            # draw the tapers from waveguide to SWG
            xtu = [
                ((r + w / 2 + gap2 + ii * (w + gap)) + (w - 0.06) / 2),
                ((r + w / 2 + gap2 + ii * (w + gap)) + (w - 0.06) / 2 + 0.06),
                ((r + w / 2 + gap2 + ii * (w + gap)) + w + gap / 2),
                ((r + w / 2 + gap2 + ii * (w + gap)) - gap / 2)
            ]
            ytu = [(yu[3] - taperL), (yu[3] - taperL), (yu[3]), (yu[3])]
            dpts = [pya.DPoint(xtu[i], ytu[i]) for i in range(len(xtu))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

            ytd = [(yd[1] + taperL), (yd[1] + taperL), (yd[1]), (yd[1])]
            dpts = [pya.DPoint(xtu[i], ytd[i]) for i in range(len(xtu))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

        # taper connections from multi-tapers to std WG
        xTu = [(r + w / 2 + gap2 - gap / 2),
               (r + w / 2 + gap2 - gap / 2 + row * (gap + w)),
               (r + w / 2 + gap2 + row * (gap + w) / 2 + 0.25),
               (r + w / 2 + gap2 + row * (gap + w) / 2 - 0.25)]
        yTu = [(yu[3]), (yu[3]), (yu[3] + taperL), (yu[3] + taperL)]
        dpts = [pya.DPoint(xTu[i], yTu[i]) for i in range(len(xTu))]
        dpolygon = DPolygon(dpts)
        element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
        shapes(LayerSiN).insert(element)

        yTd = [(yd[1]), (yd[1]), (yd[1] - taperL), (yd[1] - taperL)]
        dpts = [pya.DPoint(xTu[i], yTd[i]) for i in range(len(xTu))]
        dpolygon = DPolygon(dpts)
        element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
        shapes(LayerSiN).insert(element)

        # add std WG
        if 2 * r >= busL + 2 * taperL:
            xstdu = [(r + w / 2 + gap2 + row * (gap + w) / 2 - 0.25),
                     (r + w / 2 + gap2 + row * (gap + w) / 2 + 0.25),
                     (r + w / 2 + gap2 + row * (gap + w) / 2 + 0.25),
                     (r + w / 2 + gap2 + row * (gap + w) / 2 - 0.25)]
            ystdu = [(yu[3] + taperL), (yu[3] + taperL),
                     (yu[3] + r - busL / 2 + 1), (yu[3] + r - busL / 2 + 1)]
            dpts = [pya.DPoint(xstdu[i], ystdu[i]) for i in range(len(xstdu))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)

            ystdd = [(yd[1] - taperL), (yd[1] - taperL),
                     (yd[1] - r + busL / 2 - 1), (yd[1] - r + busL / 2 - 1)]
            dpts = [pya.DPoint(xstdu[i], ystdd[i]) for i in range(len(xstdu))]
            dpolygon = DPolygon(dpts)
            element = Polygon.from_dpoly(dpolygon * (1.0 / dbu))
            shapes(LayerSiN).insert(element)
        else:
            xstdu = xTu
            ystdu = yTu
            ystdd = yTd

        #DEV BOX
        half_l = (self.cell.bbox().width() - row *
                  (gap + w) / dbu - gap2 / dbu + (gap / 2) / dbu) / 2
        half_r = self.cell.bbox().width() - half_l
        dev = Box(-half_l, ystdd[-1] / dbu - 1, half_r, ystdu[-1] / dbu + 1)
        shapes(LayerDevRecN).insert(dev)
        dev_width = self.cell.bbox().width() / 2

        if 2 * r >= busL + 2 * taperL:
            dev_up = yu[-1] / dbu + taperL / dbu + (yu[3] + r - busL / 2 + 1 -
                                                    (yu[3] + taperL)) / dbu
            dev_down = yd[-4] / dbu - taperL / dbu - (yu[3] + r - busL / 2 +
                                                      1 -
                                                      (yu[3] + taperL)) / dbu
        else:
            dev_up = yu[-1] / dbu + taperL / dbu
            dev_down = yd[-4] / dbu - taperL / dbu

        # Create the pins on the waveguides, as short paths:
        from SiEPIC._globals import PIN_LENGTH as pin_length

        w = to_itype(self.w, dbu)
        gap = to_itype(self.gap, dbu)
        bus_length = to_itype(bus_length / 2, dbu)

        #Pin1
        #t = Trans(Trans.R0, dev_width-w/2,dev_up)
        t = Trans(Trans.R0, xstdu[-1] / dbu + 251, dev_up + 1)
        pin = Path([Point(0, -pin_length / 2),
                    Point(0, pin_length / 2)], 500)  #500 is width of std WG
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin1", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu
        print(dev_up)
        print(dev_up * dbu)
        #Pin2
        t = Trans(Trans.R0, xstdu[-1] / dbu + 251, dev_down - 1)
        pin = Path([Point(0, pin_length / 2), Point(0, -pin_length / 2)], 500)
        pin_t = pin.transformed(t)
        shapes(LayerPinRecN).insert(pin_t)
        text = Text("pin2", t)
        shape = shapes(LayerPinRecN).insert(text)
        shape.text_size = 0.4 / dbu