Exemplo n.º 1
0
    def __build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # then add it to the Cell
        num_teeth = int(self.length // self.period)
        """ Create a straight grating GratingCoupler
        """
        gap = self.period - (self.period * self.dc)
        path = gdspy.Path(self.wgt.wg_width, (0, 0))
        path.segment(self.taper_length,
                     direction="+x",
                     final_width=self.width,
                     **self.wg_spec)
        teeth = gdspy.L1Path((
            gap + self.taper_length + 0.5 *
            (num_teeth - 1 + self.dc) * self.period,
            -0.5 * self.width,
        ), "+y", self.period * self.dc, [self.width], [], num_teeth,
                             self.period, **self.wg_spec)

        clad_path = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               (0, 0))
        clad_path.segment(self.taper_length,
                          direction="+x",
                          final_width=self.width + 2 * self.wgt.clad_width,
                          **self.clad_spec)
        clad_path.segment(self.length, direction="+x", **self.clad_spec)

        self.add(teeth)
        self.add(path)
        self.add(clad_path)
Exemplo n.º 2
0
    def build_cell(self):
        #Sequentially build all the geometric shapes using gdspy path functions
        #then add it to the Cell
        num_teeth = int(self.length // self.period)
        """ Create a straight grating GratingCoupler
        """
        gap = self.period - (self.period * self.dc)
        path = gdspy.Path(self.wgt.wg_width, self.port)
        path.segment(self.taper_length,
                     direction='+y',
                     final_width=self.width,
                     **self.wg_spec)
        teeth = gdspy.L1Path(
            (self.port[0] - 0.5 * self.width, gap + self.taper_length +
             self.port[1] + 0.5 * (num_teeth - 1 + self.dc) * self.period),
            '+x', self.period * self.dc, [self.width], [], num_teeth,
            self.period, **self.wg_spec)

        clad_path = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               self.port)
        clad_path.segment(self.taper_length,
                          direction='+y',
                          final_width=self.width + 2 * self.wgt.clad_width,
                          **self.clad_spec)
        clad_path.segment(self.length, direction='+y', **self.clad_spec)

        if self.direction == "WEST":
            teeth.rotate(np.pi / 2.0, self.port)
            path.rotate(np.pi / 2.0, self.port)
            clad_path.rotate(np.pi / 2.0, self.port)
        elif self.direction == "SOUTH":
            teeth.rotate(np.pi, self.port)
            path.rotate(np.pi, self.port)
            clad_path.rotate(np.pi, self.port)
        elif self.direction == "EAST":
            teeth.rotate(-np.pi / 2.0, self.port)
            path.rotate(-np.pi / 2.0, self.port)
            clad_path.rotate(-np.pi / 2.0, self.port)
        elif isinstance(self.direction, float):
            teeth.rotate(self.direction - np.pi / 2.0, self.port)
            path.rotate(self.direction - np.pi / 2.0, self.port)
            clad_path.rotate(self.direction - np.pi / 2.0, self.port)
        self.add(teeth)
        self.add(path)
        self.add(clad_path)
Exemplo n.º 3
0
# method. Here we use a radius of 0.2.
# polypath.fillet(0.2)
path_cell.add(polypath)

# L1Paths use only segments in 'x' and 'y' directions, useful for some
# lithography mask writers.  We specify a path composed of 16 segments
# of length 4.  The turns after each segment can be either 90 degrees
# CCW (positive) or CW (negative).  The absolute value of the turns
# produces a scaling of the path width and distance between paths in
# segments immediately after the turn.
lengths = [4] * 8
turns = [-1, -1, 1, 1, -1, -2, 1, 0.5]
l1path = gdspy.L1Path((-1, -11),
                      '+y',
                      0.5,
                      lengths,
                      turns,
                      number_of_paths=3,
                      distance=0.7,
                      layer=6)
path_cell.add(l1path)

# ------------------------------------------------------------------ #
#      POLYGON OPERATIONS
# ------------------------------------------------------------------ #

# Boolean operations can be executed with either gdspy polygons or
# point lists).  The operations are union, intersection, subtraction,
# symmetric subtracion (respectively 'or', 'and', 'not', 'xor').
oper_cell = gdspy.Cell('OPERATIONS')

# Here we subtract the previously created spiral from a rectangle with
Exemplo n.º 4
0
def grating(
    period,
    number_of_teeth,
    fill_frac,
    width,
    position,
    direction,
    lda=1,
    sin_theta=0,
    focus_distance=-1,
    focus_width=-1,
    tolerance=0.001,
    layer=0,
    datatype=0,
):
    """
    Straight or focusing grating.

    period          : grating period
    number_of_teeth : number of teeth in the grating
    fill_frac       : filling fraction of the teeth (w.r.t. the period)
    width           : width of the grating
    position        : grating position (feed point)
    direction       : one of {'+x', '-x', '+y', '-y'}
    lda             : free-space wavelength
    sin_theta       : sine of incidence angle
    focus_distance  : focus distance (negative for straight grating)
    focus_width     : if non-negative, the focusing area is included in
                      the result (usually for negative resists) and this
                      is the width of the waveguide connecting to the
                      grating
    tolerance       : same as in `path.parametric`
    layer           : GDSII layer number
    datatype        : GDSII datatype number

    Return `PolygonSet`
    """
    if focus_distance < 0:
        p = gdspy.L1Path(
            (
                position[0] - 0.5 * width,
                position[1] + 0.5 * (number_of_teeth - 1 + fill_frac) * period,
            ),
            "+x",
            period * fill_frac,
            [width],
            [],
            number_of_teeth,
            period,
            layer=layer,
            datatype=datatype,
        )
    else:
        neff = lda / float(period) + sin_theta
        qmin = int(focus_distance / float(period) + 0.5)
        p = gdspy.Path(period * fill_frac, position)
        c3 = neff ** 2 - sin_theta ** 2
        w = 0.5 * width
        for q in range(qmin, qmin + number_of_teeth):
            c1 = q * lda * sin_theta
            c2 = (q * lda) ** 2
            p.parametric(
                lambda t: (
                    width * t - w,
                    (c1 + neff * numpy.sqrt(c2 - c3 * (width * t - w) ** 2)) / c3,
                ),
                tolerance=tolerance,
                max_points=0,
                layer=layer,
                datatype=datatype,
            )
            p.x = position[0]
            p.y = position[1]
        sz = p.polygons[0].shape[0] // 2
        if focus_width == 0:
            p.polygons[0] = numpy.vstack((p.polygons[0][:sz, :], [position]))
        elif focus_width > 0:
            p.polygons[0] = numpy.vstack(
                (
                    p.polygons[0][:sz, :],
                    [
                        (position[0] + 0.5 * focus_width, position[1]),
                        (position[0] - 0.5 * focus_width, position[1]),
                    ],
                )
            )
        p.fracture()
    if direction == "-x":
        return p.rotate(0.5 * numpy.pi, position)
    elif direction == "+x":
        return p.rotate(-0.5 * numpy.pi, position)
    elif direction == "-y":
        return p.rotate(numpy.pi, position)
    else:
        return p
Exemplo n.º 5
0
        # of segments for our bend radius, we'll first route the waveguide
        # down towards the bottom waveguide, and then back up...just to be safe.
        stretch = chipDim - k * couplePitch + RingcellWidth / 2
        sub1 = taperWidth
        travel = couplePitch - middleTapperHeightBuffer
        sub2 = stretch - sub1
        length = [
            sub1, travel, sub2,
            travel + couplePitch - RingcellHeight + waveguideWidth,
            couplerBufferMiddle + 1
        ]
        turn = [1, -1, -1, -1]
        l1path = gdspy.L1Path(
            initial_point=(chipDim - taperWidth,
                           -(k + 1) * couplePitch - couplerYOffset),
            direction='-x',
            width=waveguideWidth,
            length=length,
            turn=turn,
            layer=layerNumber)
        l1path.fillet(radius=waveguideBendRadius)
        RingUnitCell.add(l1path)

        # consolidate cells to master cell
        RRLatticeCell.add(gdspy.CellReference(RingUnitCell))

        incrementOffset = incrementOffset + 1

# ------------------------------------------------------------------ #
#      Center Parent Cell for fab
# ------------------------------------------------------------------ #
centeredCell = gdspy.Cell('centeredCell')
Exemplo n.º 6
0
def grating(period,
            number_of_teeth,
            fill_frac,
            width,
            position,
            direction,
            lda=1,
            sin_theta=0,
            focus_distance=-1,
            focus_width=-1,
            evaluations=99,
            layer=0,
            datatype=0):
    '''
    Straight or focusing grating.

    period          : grating period
    number_of_teeth : number of teeth in the grating
    fill_frac       : filling fraction of the teeth (w.r.t. the period)
    width           : width of the grating
    position        : grating position (feed point)
    direction       : one of {'+x', '-x', '+y', '-y'}
    lda             : free-space wavelength
    sin_theta       : sine of incidence angle
    focus_distance  : focus distance (negative for straight grating)
    focus_width     : if non-negative, the focusing area is included in
                      the result (usually for negative resists) and this
                      is the width of the waveguide connecting to the
                      grating
    evaluations     : number of evaluations of `path.parametric`
    layer           : GDSII layer number
    datatype        : GDSII datatype number

    Return `PolygonSet`
    '''
    if focus_distance < 0:
        path = gdspy.L1Path((position[0] - 0.5 * width, position[1] + 0.5 *
                             (number_of_teeth - 1 + fill_frac) * period),
                            '+x',
                            period * fill_frac, [width], [],
                            number_of_teeth,
                            period,
                            layer=layer,
                            datatype=datatype)
    else:
        neff = lda / float(period) + sin_theta
        qmin = int(focus_distance / float(period) + 0.5)
        path = gdspy.Path(period * fill_frac, position)
        max_points = 199 if focus_width < 0 else 2 * evaluations
        c3 = neff**2 - sin_theta**2
        w = 0.5 * width
        for q in range(qmin, qmin + number_of_teeth):
            c1 = q * lda * sin_theta
            c2 = (q * lda)**2
            path.parametric(
                lambda t: (width * t - w,
                           (c1 + neff * numpy.sqrt(c2 - c3 *
                                                   (width * t - w)**2)) / c3),
                number_of_evaluations=evaluations,
                max_points=max_points,
                layer=layer,
                datatype=datatype)
            path.x = position[0]
            path.y = position[1]
        if focus_width >= 0:
            path.polygons[0] = numpy.vstack(
                (path.polygons[0][:evaluations, :],
                 ([position] if focus_width == 0 else [(position[0] +
                                                        0.5 * focus_width,
                                                        position[1]),
                                                       (position[0] -
                                                        0.5 * focus_width,
                                                        position[1])])))
            path.fracture()
    if direction == '-x':
        return path.rotate(0.5 * numpy.pi, position)
    elif direction == '+x':
        return path.rotate(-0.5 * numpy.pi, position)
    elif direction == '-y':
        return path.rotate(numpy.pi, position)
    else:
        return path
Exemplo n.º 7
0
                [taperWidth, -k * couplePitch + waveguideWidth / 2], [
                    k * couplePitch - MZIcellWidth / 2,
                    -k * couplePitch - waveguideWidth / 2
                ],
                layer=layerNumber))

        # connect middle taper to coupler
        length = [
            k * couplePitch - taperWidth + MZIcellWidth / 2 +
            couplerBufferMiddle, couplePitch, couplerBufferMiddle + 1
        ]
        turn = [1, 1]
        l1path = gdspy.L1Path(initial_point=(taperWidth,
                                             -(k + 1) * couplePitch),
                              direction='+x',
                              width=waveguideWidth,
                              length=length,
                              turn=turn,
                              layer=layerNumber)
        l1path.fillet(radius=waveguideBendRadius)
        MZIUnitCell.add(l1path)

        # connect bottom taper to coupler
        length = [
            k * couplePitch - taperWidth + MZIcellWidth / 2 +
            couplerBufferBottom,
            2 * couplePitch + 2 * yOffset - waveguideWidth,
            couplerBufferBottom + 1
        ]
        turn = [1, 1]
        l2path = gdspy.L1Path(initial_point=(taperWidth,
Exemplo n.º 8
0
def MZI(deltaL=40,
        Lref=40,
        gapLength=20,
        waveguideWidth=0.5,
        bendRadius=5,
        coupleType="Y",
        polarization="TM",
        layerNumber=1,
        maxH=100):

    # Decide which coupler to use
    if coupleType == "Y":
        Coupler = YBranch()
    elif coupleType == "C":
        Coupler = branchCoupler(layerNumber=1, polarization=polarization)
    else:
        raise Exception('Invalid Coupler Type Specified; must be Y or C')

    # Calculate how many, and how long each leg of the coupling arm needs to be
    numLegs = 2
    if deltaL / 2 > maxH:
        numLegs = numpy.floor((deltaL) / maxH + 1)
        if numLegs % 2 == 1:
            numLegs = numLegs + 1
    leg = (deltaL / numLegs) + (4 * bendRadius - numpy.pi * bendRadius
                                )  # compensate with half circumf of circle

    # Connect bottom branch
    bottomBranch = gdspy.Cell('referenceBranch_' + (coupleType),
                              exclude_from_current=True)
    bottomBranch.add(
        gdspy.Rectangle([-Lref / 2, waveguideWidth / 2],
                        [Lref / 2, -waveguideWidth / 2],
                        layer=1))

    # Connect top branch
    gapLength = Lref / (numLegs + 1)

    #outerArm = (Lref-gapLength)/2
    basicTurn = [1, -1, -1, 1]
    basicLength = [gapLength, leg, gapLength, leg]
    turn = []
    length = []
    for k in range(0, int(numLegs / 2)):
        length.extend(basicLength)
        turn.extend(basicTurn)
    length.append(gapLength)
    topBranch = gdspy.Cell('deltaBranch_' + (coupleType),
                           exclude_from_current=True)
    topBranchPoly = gdspy.L1Path((0, 0),
                                 '+x',
                                 waveguideWidth,
                                 length,
                                 turn,
                                 layer=1)
    topBranchPoly.fillet(radius=bendRadius)
    leftSquare = gdspy.Rectangle([0, -waveguideWidth / 2],
                                 [waveguideWidth, waveguideWidth / 2],
                                 layer=1)
    rightSquare = gdspy.Rectangle([Lref - waveguideWidth, -waveguideWidth / 2],
                                  [Lref, waveguideWidth / 2],
                                  layer=1)

    union = gdspy.fast_boolean(topBranchPoly, [leftSquare, rightSquare],
                               'or',
                               layer=layerNumber)

    topBranch.add(union)

    # Get Branch dimensions
    CouplerDims = Coupler.get_bounding_box()
    CouplerWidth = abs(CouplerDims[0, 0] - CouplerDims[1, 0])
    CouplerHeight = abs(CouplerDims[0, 1] - CouplerDims[1, 1])

    # Since the coupler isn't centered, let's compensate for the later translation
    if coupleType == "Y":
        CouplerWidth = 2 * CouplerWidth

    MZIcell = gdspy.Cell('MZI_deltaL=' + str(deltaL) + '_Lref=' + str(Lref) +
                         '_coupleType=' + coupleType)
    MZIcell.add(gdspy.CellReference(Coupler,
                                    (-Lref / 2 - CouplerWidth / 2, 0)))
    MZIcell.add(
        gdspy.CellReference(Coupler, (Lref / 2 + CouplerWidth / 2, 0),
                            rotation=180))
    MZIcell.add(
        gdspy.CellReference(bottomBranch,
                            (0, -(CouplerHeight / 2 - waveguideWidth / 2.0))))
    MZIcell.add(
        gdspy.CellReference(
            topBranch,
            (-Lref / 2, +(CouplerHeight / 2 - waveguideWidth / 2.0))))

    MZIcell.flatten()

    return MZIcell