Beispiel #1
0
    def __init__(self, wgt, poles, start_width=None, end_width=None):
        tk.Component.__init__(self, "BBend", locals())

        self.portlist = {}
        self.port = (0, 0)

        if start_width != None:
            self.start_width = start_width
        else:
            self.start_width = wgt.wg_width
        if end_width != None:
            self.end_width = end_width
        else:
            self.end_width = wgt.wg_width

        self.input_port = (poles[0][0], poles[0][1])
        self.output_port = (poles[-1][0], poles[-1][1])

        self.poles = poles

        self.input_direction = tk.get_exact_angle(poles[1], poles[0])
        self.output_direction = tk.get_exact_angle(poles[-2], poles[-1])

        self.wgt = wgt
        self.wg_spec = {"layer": wgt.wg_layer, "datatype": wgt.wg_datatype}
        self.clad_spec = {"layer": wgt.clad_layer, "datatype": wgt.clad_datatype}

        self.__build_cell()
        self.__build_ports()

        """ Translate & rotate the ports corresponding to this specific component object
Beispiel #2
0
 def build_ports(self):
     # Portlist format:
     # example: example:  {'port':(x_position, y_position), 'direction': 'NORTH'}
     self.portlist["input"] = {
         'port': (self.trace[0][0], self.trace[0][1]),
         'direction': tk.get_exact_angle(self.trace[1], self.trace[0])
     }
     self.portlist["output"] = {
         'port': (self.trace[-1][0], self.trace[-1][1]),
         'direction': tk.get_exact_angle(self.trace[-2], self.trace[-1])
     }
Beispiel #3
0
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell

        angle = tk.get_exact_angle(self.trace[0], self.trace[1])
        angle_opp = tk.get_exact_angle(self.trace[1], self.trace[0])

        # Add strip waveguide taper
        path_strip = gdspy.Path(self.wgt_strip.wg_width, self.trace[0])
        path_strip.segment(self.length,
                           final_width=self.end_strip_width,
                           direction=angle,
                           **self.wg_spec)

        # Add slot waveguide taper
        path_slot = gdspy.Path(self.wgt_slot.rail,
                               self.trace[1],
                               number_of_paths=2,
                               distance=self.wgt_slot.rail_dist)
        path_slot.segment(self.length,
                          final_width=self.end_slot_width,
                          final_distance=(self.wgt_strip.wg_width +
                                          2 * self.d + self.end_slot_width),
                          direction=angle_opp,
                          **self.wg_spec)

        # Cladding for waveguide taper
        path_clad = gdspy.Path(
            2 * self.wgt_strip.clad_width + self.wgt_strip.wg_width,
            self.trace[0])
        path_clad.segment(self.length,
                          final_width=2 * self.wgt_slot.clad_width +
                          self.wgt_slot.wg_width,
                          direction=angle,
                          **self.clad_spec)

        if not self.input_strip:
            center_pt = ((self.trace[0][0] + self.trace[1][0]) / 2.0,
                         (self.trace[0][1] + self.trace[1][1]) / 2.0)
            path_strip.rotate(np.pi, center_pt)
            path_slot.rotate(np.pi, center_pt)
            path_clad.rotate(np.pi, center_pt)

        self.add(path_strip)
        self.add(path_slot)
        self.add(path_clad)
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell

        angle = tk.get_exact_angle(self.trace[0], self.trace[1])

        # Add MMI region
        path_mmi = gdspy.Path(self.w_mmi, self.trace[0])
        path_mmi.segment(self.l_mmi, direction=angle, **self.wg_spec)

        print("path_mmi_coords = "+str((path_mmi.x, path_mmi.y)))

        # Add slot tapered region
        path_taper = gdspy.Path((self.w_mmi - self.wgt_slot.slot)/2.0,
                                initial_point=(path_mmi.x, path_mmi.y),
                                number_of_paths=2,
                                distance=(self.w_mmi + self.wgt_slot.slot)/2.0)
        path_taper.segment(self.length - self.l_mmi,
                           final_width = self.wgt_slot.rail,
                           final_distance = self.wgt_slot.rail_dist,
                           direction=angle,
                           **self.wg_spec)

        # Cladding for waveguide taper
        path_clad = gdspy.Path(2*self.wgt_strip.clad_width+self.wgt_strip.wg_width, self.trace[0])
        path_clad.segment(self.length, final_width=2*self.wgt_slot.clad_width+self.wgt_slot.wg_width, direction=angle, **self.clad_spec)

        if not self.input_strip:
            center_pt = ((self.trace[0][0]+self.trace[1][0])/2.0, (self.trace[0][1]+self.trace[1][1])/2.0)
            path_mmi.rotate(np.pi, center_pt)
            path_taper.rotate(np.pi, center_pt)
            path_clad.rotate(np.pi, center_pt)

        self.add(path_mmi)
        self.add(path_taper)
        self.add(path_clad)
Beispiel #5
0
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell
        br = self.wgt.bend_radius

        if len(self.trace) == 2:
            if self.wgt.wg_type == 'strip':
                path = gdspy.Path(self.wgt.wg_width, self.trace[0])
                path.segment(tk.dist(self.trace[0], self.trace[1]),
                             direction=tk.get_exact_angle(
                                 self.trace[0], self.trace[1]),
                             **self.wg_spec)
            elif self.wgt.wg_type == 'slot':
                path = gdspy.Path(self.wgt.rail,
                                  self.trace[0],
                                  number_of_paths=2,
                                  distance=self.wgt.rail_dist)
                path.segment(tk.dist(self.trace[0], self.trace[1]),
                             direction=tk.get_exact_angle(
                                 self.trace[0], self.trace[1]),
                             **self.wg_spec)
            path2 = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               self.trace[0])
            path2.segment(tk.dist(self.trace[0], self.trace[1]),
                          direction=tk.get_exact_angle(self.trace[0],
                                                       self.trace[1]),
                          **self.clad_spec)

        else:
            if self.wgt.wg_type == 'strip':
                path = gdspy.Path(self.wgt.wg_width, self.trace[0])
            elif self.wgt.wg_type == 'slot':
                path = gdspy.Path(self.wgt.rail,
                                  self.trace[0],
                                  number_of_paths=2,
                                  distance=self.wgt.rail_dist)
            path2 = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               self.trace[0])

            prev_dl = 0.0
            for i in range(len(self.trace) - 2):
                start_angle = tk.get_exact_angle(self.trace[i],
                                                 self.trace[i + 1])
                next_angle = tk.get_exact_angle(self.trace[i + 1],
                                                self.trace[i + 2])

                #dl is the amount of distance that is taken *off* the waveguide from the curved section
                dl = abs(br * np.tan((next_angle - start_angle) / 2.0))
                if (dl + prev_dl) > tk.dist(self.trace[i], self.trace[i + 1]):
                    raise ValueError("Warning! The waypoints " +
                                     str(self.trace[i]) + " and " +
                                     str(self.trace[i + 1]) +
                                     " are too close to accommodate "
                                     " the necessary bend-radius of " +
                                     str(br) +
                                     ", the points were closer than " +
                                     str(dl + prev_dl))

                path.segment(tk.dist(self.trace[i], self.trace[i + 1]) - dl -
                             prev_dl,
                             direction=start_angle,
                             **self.wg_spec)
                path2.segment(tk.dist(self.trace[i], self.trace[i + 1]) - dl -
                              prev_dl,
                              direction=start_angle,
                              **self.clad_spec)

                # The following makes sure the turn-by angle is *always* between -pi and +pi
                turnby = (next_angle - start_angle) % (2 * np.pi)
                turnby = turnby - 2 * np.pi if turnby > np.pi else turnby

                path.turn(br, turnby, number_of_points=0.1, **self.wg_spec)
                path2.turn(br, turnby, number_of_points=0.1, **self.clad_spec)
                prev_dl = dl

            path.segment(tk.dist(self.trace[-2], self.trace[-1]) - prev_dl,
                         direction=next_angle,
                         **self.wg_spec)
            path2.segment(tk.dist(self.trace[-2], self.trace[-1]) - prev_dl,
                          direction=next_angle,
                          **self.clad_spec)

        self.add(path)
        self.add(path2)
Beispiel #6
0
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell
        br = self.wgt.bend_radius

        # add waveguide
        if self.wgt.wg_type == 'swg':
            # SWG waveguides consist of both straight segments and bends that are built individually
            segments = [[None, None] for i in range(len(self.trace) - 1)
                        ]  # list of endpoints for all straight segments
            bends = [
                [None, None, None] for i in range(len(self.trace) - 2)
            ]  # list of arc-centers, start angular positions, and end angular positions for all bends
            prev_dl = 0.0
            for i in range(len(self.trace)):
                if i == 0:
                    segments[i][0] = self.trace[
                        i]  # if first point in trace, just add as start point of first segment
                elif i == len(self.trace) - 1:
                    segments[i - 1][1] = self.trace[
                        i]  # if last point in trace, just add as end point of last segment
                else:
                    start_angle = tk.get_exact_angle(self.trace[i - 1],
                                                     self.trace[i])
                    next_angle = tk.get_exact_angle(self.trace[i],
                                                    self.trace[i + 1])
                    angle_change = tk.normalize_angle(next_angle - start_angle)

                    #dl is the amount of distance that is taken *off* the waveguide from the curved section
                    dl = abs(br * np.tan(angle_change / 2.0))
                    if (dl + prev_dl) > tk.dist(self.trace[i - 1],
                                                self.trace[i]) + 1E-6:
                        raise ValueError("Warning! The waypoints " +
                                         str(self.trace[i - 1]) + " and " +
                                         str(self.trace[i]) +
                                         " are too close to accommodate "
                                         " the necessary bend-radius of " +
                                         str(br) +
                                         ", the points were closer than " +
                                         str(dl + prev_dl))

                    # assign start and end points for segments around this trace point
                    segments[i - 1][1] = tk.translate_point(
                        self.trace[i], dl, start_angle + np.pi)
                    segments[i][0] = tk.translate_point(
                        self.trace[i], dl, next_angle)

                    # calculate arc-center for the bend
                    chord_angle = tk.get_exact_angle(segments[i - 1][1],
                                                     segments[i][0])
                    bisect_len = abs(br / np.cos(angle_change / 2.0))
                    if angle_change > 0:
                        bends[i - 1][0] = tk.translate_point(
                            self.trace[i], bisect_len, chord_angle + np.pi / 2)
                    else:
                        bends[i - 1][0] = tk.translate_point(
                            self.trace[i], bisect_len, chord_angle - np.pi / 2)

                    # calculate start and end angular positions for the bend
                    if angle_change > 0:
                        bends[i - 1][1] = tk.normalize_angle(start_angle -
                                                             np.pi / 2)
                        bends[i - 1][2] = tk.normalize_angle(next_angle -
                                                             np.pi / 2)
                    else:
                        bends[i - 1][1] = tk.normalize_angle(start_angle +
                                                             np.pi / 2)
                        bends[i - 1][2] = tk.normalize_angle(next_angle +
                                                             np.pi / 2)

                    prev_dl = dl

            # need to account for partial periods in the following segment and bend building
            # so need to do them interleaving
            remaining_period = 0.0
            for i in range(len(segments)):
                # add straight segment
                segment = segments[i]
                direction = tk.get_exact_angle(segment[0], segment[1])
                direction_deg = direction / np.pi * 180
                total_dist = tk.dist(segment[0], segment[1])
                curr_point = segment[0]
                if total_dist > remaining_period:  # if the total distance will complete the remaining period from before
                    # finish any partial period leftover from previous segment/bend
                    if remaining_period > self.wgt.period * (
                            1 - self.wgt.duty_cycle):
                        first_path = gdspy.Path(self.wgt.wg_width,
                                                initial_point=curr_point)
                        first_path.segment(remaining_period - self.wgt.period *
                                           (1 - self.wgt.duty_cycle),
                                           direction=direction,
                                           **self.wg_spec)
                        self.add(first_path)
                    # add in all whole periods in remaining length
                    curr_point = tk.translate_point(curr_point,
                                                    remaining_period,
                                                    direction)
                    remaining_length = total_dist - remaining_period
                    num_periods = int(remaining_length // self.wgt.period)
                    for j in range(num_periods):
                        self.add(
                            gdspy.CellReference(self.wgt.straight_period_cell,
                                                origin=curr_point,
                                                rotation=direction_deg))
                        curr_point = tk.translate_point(
                            curr_point, self.wgt.period, direction)
                    # finish any partial period at end of this segment
                    if tk.dist(curr_point, segment[1]
                               ) < self.wgt.period * self.wgt.duty_cycle:
                        last_path = gdspy.Path(self.wgt.wg_width,
                                               initial_point=curr_point)
                        last_path.segment(tk.dist(curr_point, segment[1]),
                                          direction=direction,
                                          **self.wg_spec)
                        self.add(last_path)
                    else:
                        self.add(
                            gdspy.CellReference(self.wgt.straight_period_cell,
                                                origin=curr_point,
                                                rotation=direction_deg))
                    remaining_period = self.wgt.period - tk.dist(
                        curr_point, segment[1])
                else:  # if total distance did not complete the remaining period from before
                    if remaining_period > self.wgt.period * (
                            1 - self.wgt.duty_cycle):
                        if total_dist > remaining_period - self.wgt.period * (
                                1 - self.wgt.duty_cycle):
                            first_path = gdspy.Path(self.wgt.wg_width,
                                                    initial_point=curr_point)
                            first_path.segment(remaining_period -
                                               self.wgt.period *
                                               (1 - self.wgt.duty_cycle),
                                               direction=direction,
                                               **self.wg_spec)
                            self.add(first_path)
                        elif total_dist > 0:
                            first_path = gdspy.Path(self.wgt.wg_width,
                                                    initial_point=curr_point)
                            first_path.segment(total_dist,
                                               direction=direction,
                                               **self.wg_spec)
                            self.add(first_path)
                    remaining_period = remaining_period - total_dist

                # add bend
                if i != len(bends):
                    bend = bends[i]
                    angle_change = tk.normalize_angle(bend[2] - bend[1])
                    angular_period = self.wgt.period / br
                    curr_angle = bend[1]
                    remaining_angle = remaining_period / br
                    if abs(
                            angle_change
                    ) > remaining_angle:  # if the angle change will complete the remaining period from before
                        # finish any partial period leftover from previous segment/bend
                        if angle_change > 0:
                            if remaining_angle > angular_period * (
                                    1 - self.wgt.duty_cycle):
                                first_path = gdspy.Path(
                                    self.wgt.wg_width,
                                    initial_point=tk.translate_point(
                                        bend[0], br, curr_angle))
                                first_path.arc(
                                    br, curr_angle,
                                    curr_angle + remaining_angle -
                                    angular_period * (1 - self.wgt.duty_cycle),
                                    **self.wg_spec)
                                self.add(first_path)
                            curr_angle += remaining_angle
                        else:
                            if remaining_angle > angular_period * (
                                    1 - self.wgt.duty_cycle):
                                first_path = gdspy.Path(
                                    self.wgt.wg_width,
                                    initial_point=tk.translate_point(
                                        bend[0], br, curr_angle))
                                first_path.arc(
                                    br, curr_angle, curr_angle -
                                    (remaining_angle - angular_period *
                                     (1 - self.wgt.duty_cycle)),
                                    **self.wg_spec)
                                self.add(first_path)
                            curr_angle -= remaining_angle
                        # add in all whole periods in remaining angle
                        num_periods = int(
                            br * (abs(angle_change) - remaining_angle) //
                            self.wgt.period)
                        if angle_change > 0:
                            for j in range(num_periods):
                                self.add(
                                    gdspy.CellReference(
                                        self.wgt.bend_period_cell,
                                        origin=bend[0],
                                        rotation=curr_angle / np.pi * 180))
                                curr_angle += angular_period
                            # finish any partial period at end of this bend
                            if abs(tk.normalize_angle(bend[2] - curr_angle)
                                   ) < angular_period * self.wgt.duty_cycle:
                                last_path = gdspy.Path(
                                    self.wgt.wg_width,
                                    initial_point=tk.translate_point(
                                        bend[0], br, curr_angle))
                                last_path.arc(br, curr_angle, bend[2],
                                              **self.wg_spec)
                                self.add(last_path)
                            else:
                                self.add(
                                    gdspy.CellReference(
                                        self.wgt.bend_period_cell,
                                        origin=bend[0],
                                        rotation=curr_angle / np.pi * 180))
                        else:
                            for j in range(num_periods):
                                self.add(
                                    gdspy.CellReference(
                                        self.wgt.bend_period_cell,
                                        origin=bend[0],
                                        rotation=curr_angle / np.pi * 180,
                                        x_reflection=True))
                                curr_angle -= angular_period
                            # finish any partial period at end of this bend
                            if abs(tk.normalize_angle(bend[2] - curr_angle)
                                   ) < angular_period * self.wgt.duty_cycle:
                                last_path = gdspy.Path(
                                    self.wgt.wg_width,
                                    initial_point=tk.translate_point(
                                        bend[0], br, bend[2]))
                                last_path.arc(
                                    br, bend[2], bend[2] + abs(
                                        tk.normalize_angle(bend[2] -
                                                           curr_angle)),
                                    **self.wg_spec)
                                self.add(last_path)
                            else:
                                self.add(
                                    gdspy.CellReference(
                                        self.wgt.bend_period_cell,
                                        origin=bend[0],
                                        rotation=curr_angle / np.pi * 180,
                                        x_reflection=True))
                        remaining_period = self.wgt.period - br * abs(
                            tk.normalize_angle(bend[2] - curr_angle))
                    else:  # if the angle change did not complete the remaining period from before
                        if remaining_angle > angular_period * (
                                1 - self.wgt.duty_cycle):
                            if abs(angle_change
                                   ) > remaining_angle - angular_period * (
                                       1 - self.wgt.duty_cycle):
                                if angle_change > 0:
                                    first_path = gdspy.Path(
                                        self.wgt.wg_width,
                                        initial_point=tk.translate_point(
                                            bend[0], br, curr_angle))
                                    first_path.arc(
                                        br, curr_angle, curr_angle +
                                        remaining_angle - angular_period *
                                        (1 - self.wgt.duty_cycle),
                                        **self.wg_spec)
                                    self.add(first_path)
                                else:
                                    first_path = gdspy.Path(
                                        self.wgt.wg_width,
                                        initial_point=tk.translate_point(
                                            bend[0], br, curr_angle))
                                    first_path.arc(
                                        br, curr_angle, curr_angle -
                                        (remaining_angle - angular_period *
                                         (1 - self.wgt.duty_cycle)),
                                        **self.wg_spec)
                                    self.add(first_path)
                            else:
                                if angle_change > 0:
                                    first_path = gdspy.Path(
                                        self.wgt.wg_width,
                                        initial_point=tk.translate_point(
                                            bend[0], br, curr_angle))
                                    first_path.arc(br, curr_angle,
                                                   curr_angle + angle_change,
                                                   **self.wg_spec)
                                    self.add(first_path)
                                else:
                                    first_path = gdspy.Path(
                                        self.wgt.wg_width,
                                        initial_point=tk.translate_point(
                                            bend[0], br,
                                            curr_angle + angle_change))
                                    first_path.arc(br,
                                                   curr_angle + angle_change,
                                                   curr_angle, **self.wg_spec)
                                    self.add(first_path)
                        remaining_period = remaining_period - br * abs(
                            angle_change)

        else:
            # Strip and slot waveguide generation below
            if len(self.trace) == 2:
                if self.wgt.wg_type == 'strip':
                    path = gdspy.Path(self.wgt.wg_width, self.trace[0])
                    path.segment(tk.dist(self.trace[0], self.trace[1]),
                                 direction=tk.get_exact_angle(
                                     self.trace[0], self.trace[1]),
                                 **self.wg_spec)
                elif self.wgt.wg_type == 'slot':
                    path = gdspy.Path(self.wgt.rail,
                                      self.trace[0],
                                      number_of_paths=2,
                                      distance=self.wgt.rail_dist)
                    path.segment(tk.dist(self.trace[0], self.trace[1]),
                                 direction=tk.get_exact_angle(
                                     self.trace[0], self.trace[1]),
                                 **self.wg_spec)
            else:
                if self.wgt.wg_type == 'strip':
                    path = gdspy.Path(self.wgt.wg_width, self.trace[0])
                elif self.wgt.wg_type == 'slot':
                    path = gdspy.Path(self.wgt.rail,
                                      self.trace[0],
                                      number_of_paths=2,
                                      distance=self.wgt.rail_dist)

                prev_dl = 0.0
                for i in range(len(self.trace) - 2):
                    start_angle = tk.get_exact_angle(self.trace[i],
                                                     self.trace[i + 1])
                    next_angle = tk.get_exact_angle(self.trace[i + 1],
                                                    self.trace[i + 2])

                    #dl is the amount of distance that is taken *off* the waveguide from the curved section
                    dl = abs(br * np.tan((next_angle - start_angle) / 2.0))
                    if (dl + prev_dl) > tk.dist(self.trace[i],
                                                self.trace[i + 1]) + 1E-6:
                        raise ValueError("Warning! The waypoints " +
                                         str(self.trace[i]) + " and " +
                                         str(self.trace[i + 1]) +
                                         " are too close to accommodate "
                                         " the necessary bend-radius of " +
                                         str(br) +
                                         ", the points were closer than " +
                                         str(dl + prev_dl))

                    path.segment(tk.dist(self.trace[i], self.trace[i + 1]) -
                                 dl - prev_dl,
                                 direction=start_angle,
                                 **self.wg_spec)

                    # The following makes sure the turn-by angle is *always* between -pi and +pi
                    turnby = tk.normalize_angle(next_angle - start_angle)

                    path.turn(br, turnby, number_of_points=0.1, **self.wg_spec)
                    prev_dl = dl

                path.segment(tk.dist(self.trace[-2], self.trace[-1]) - prev_dl,
                             direction=next_angle,
                             **self.wg_spec)

            self.add(path)

        # add cladding
        if len(self.trace) == 2:
            path2 = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               self.trace[0])
            path2.segment(tk.dist(self.trace[0], self.trace[1]),
                          direction=tk.get_exact_angle(self.trace[0],
                                                       self.trace[1]),
                          **self.clad_spec)
        else:
            path2 = gdspy.Path(self.wgt.wg_width + 2 * self.wgt.clad_width,
                               self.trace[0])
            prev_dl = 0.0
            for i in range(len(self.trace) - 2):
                start_angle = tk.get_exact_angle(self.trace[i],
                                                 self.trace[i + 1])
                next_angle = tk.get_exact_angle(self.trace[i + 1],
                                                self.trace[i + 2])

                #dl is the amount of distance that is taken *off* the waveguide from the curved section
                dl = abs(br * np.tan((next_angle - start_angle) / 2.0))
                if (dl + prev_dl) > tk.dist(self.trace[i],
                                            self.trace[i + 1]) + 1E-6:
                    raise ValueError("Warning! The waypoints " +
                                     str(self.trace[i]) + " and " +
                                     str(self.trace[i + 1]) +
                                     " are too close to accommodate "
                                     " the necessary bend-radius of " +
                                     str(br) +
                                     ", the points were closer than " +
                                     str(dl + prev_dl))

                path2.segment(tk.dist(self.trace[i], self.trace[i + 1]) - dl -
                              prev_dl,
                              direction=start_angle,
                              **self.clad_spec)

                turnby = tk.normalize_angle(next_angle - start_angle)

                path2.turn(br, turnby, number_of_points=0.1, **self.clad_spec)
                prev_dl = dl

            path2.segment(tk.dist(self.trace[-2], self.trace[-1]) - prev_dl,
                          direction=next_angle,
                          **self.clad_spec)
        self.add(path2)
Beispiel #7
0
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell
        angle = tk.get_exact_angle(self.trace[0], self.trace[1])
        # Add waveguide tapers leading to DBR region
        taper = gdspy.Path(self.wgt.wg_width, self.trace[0])
        taper.segment(self.taper_length,
                      direction=angle,
                      final_width=self.w_phc,
                      **self.wg_spec)
        taper.segment(self.length, **self.wg_spec)
        taper.segment(self.taper_length,
                      final_width=self.wgt.wg_width,
                      **self.wg_spec)
        # Cladding for DBR region
        clad = gdspy.Path(2 * self.wgt.clad_width + self.wgt.wg_width,
                          self.trace[0])
        clad.segment(tk.dist(self.trace[0], self.trace[1]),
                     direction=angle,
                     **self.clad_spec)

        self.add(taper)
        self.add(clad)
        """ Now add the periodic PhC components """
        num_blocks = (2 * self.taper_length + self.length) // self.period
        blockx = self.period * self.dc
        startx = self.trace[0][0] + self.taper_length + self.length / 2.0 - (
            num_blocks - 1) * self.period / 2.0 - blockx / 2.0
        y0 = self.trace[0][1]
        block_list = []
        for i in range(int(num_blocks)):
            x = startx + i * self.period
            block_list.append(
                gdspy.Rectangle((x, y0 - self.wgt.wg_width / 2.0),
                                (x + blockx, y0 + self.wgt.wg_width / 2.0),
                                **self.wg_spec))
        """ And add the 'fins' if self.fins==True """
        if self.fins:
            num_fins = self.wgt.wg_width // (2 * self.fin_size[1])
            x0, y0 = self.trace[0][0], self.trace[0][1] - num_fins * (
                2 * self.fin_size[1]) / 2.0 + self.fin_size[1] / 2.0
            xend = self.trace[0][0] + 2 * self.taper_length + self.length
            for i in range(int(num_fins)):
                y = y0 + i * 2 * self.fin_size[1]
                block_list.append(
                    gdspy.Rectangle(
                        (x0, y), (x0 + self.fin_size[0], y + self.fin_size[1]),
                        **self.fin_spec))
                block_list.append(
                    gdspy.Rectangle((xend - self.fin_size[0], y),
                                    (xend, y + self.fin_size[1]),
                                    **self.fin_spec))

        angle = 0
        if self.direction == "NORTH":
            angle = np.pi / 2.0
        elif self.direction == "WEST":
            angle = np.pi
        elif self.direction == "SOUTH":
            angle = -np.pi / 2.0
        elif isinstance(self.direction, float):
            angle = self.direction
        for block in block_list:
            block.rotate(angle, self.trace[0])
            self.add(block)
    def build_cell(self):
        # Sequentially build all the geometric shapes using gdspy path functions
        # for waveguide, then add it to the Cell
        angle = tk.get_exact_angle(self.trace[0], self.trace[1])
        
        # Add bus waveguide, and cladding
        bus = gdspy.Path(self.wgt.wg_width, self.trace[0])
        bus.segment(self.total_length, direction=angle, **self.wg_spec)
        # Cladding for bus waveguide
        bus_clad = gdspy.Path(2*self.wgt.clad_width+self.wgt.wg_width, self.trace[0])
        bus_clad.segment(self.total_length, direction=angle, **self.clad_spec)

        self.add(bus)
        self.add(bus_clad)        

        # Add nanobeam waveguide
        beam_x = self.trace[0][0] - np.sin(angle)*(self.gap + 2*self.wgt.wg_width)
        beam_y = self.trace[0][1] + np.cos(angle)*(self.gap + 2*self.wgt.wg_width)
        nanobeam = gdspy.Path(self.wgt.wg_width, (beam_x,beam_y))
        nanobeam.segment(self.total_length, direction=angle, **self.wg_spec)
        # Cladding for nanobeam
        nanobeam_clad = gdspy.Path(2*self.wgt.clad_width+self.wgt.wg_width, (beam_x,beam_y))
        nanobeam_clad.segment(self.total_length, direction=angle, **self.clad_spec)        

        """ Add the mirror holes """
        startx = beam_x + np.cos(angle)*(self.wgt_beam_length + self.taper_length + self.period/2)
        starty = beam_y + np.sin(angle)*(self.wgt_beam_length + self.taper_length + self.period/2)
        hole_list = []
        for i in range(int(self.nbr_holes)):
            x = startx + i*np.cos(angle)*self.period
            y = starty + i*np.sin(angle)*self.period
            hole_list.append(gdspy.Round((x,y), self.radius))

        """ Add the taper holes """
        if self.taper_type=="FF":
            startx_in = beam_x + np.cos(angle)*(self.wgt_beam_length + self.period/2)
            startx_out = beam_x + np.cos(angle)*(self.total_length - self.wgt_beam_length - self.period/2)
            starty_in = beam_y + np.sin(angle)*(self.wgt_beam_length + self.period/2)
            starty_out = beam_y + np.sin(angle)*(self.total_length - self.wgt_beam_length - self.period/2)
            taper_list_in = []
            taper_list_out = []
            for i in range(int(self.nbr_taper)):
                fill_factor = np.pi*np.square(self.radius_taper/self.period) + i*np.pi*(np.square(self.radius/self.period) - np.square(self.radius_taper/self.period))/(self.nbr_taper - 1)
                taper_radii = np.sqrt(fill_factor/np.pi)*self.period
                x_in = startx_in + i*np.cos(angle)*self.period
                y_in = starty_in + i*np.sin(angle)*self.period
                taper_list_in.append(gdspy.Round((x_in,y_in), taper_radii))
                x_out = startx_out - i*np.cos(angle)*self.period
                y_out = starty_out - i*np.sin(angle)*self.period
                taper_list_out.append(gdspy.Round((x_out,y_out), taper_radii))
        elif self.taper_type=="ratio":
            startx_in = beam_x + np.cos(angle)*self.wgt_beam_length
            startx_out = beam_x + np.cos(angle)*(self.total_length - self.wgt_beam_length)
            starty_in = beam_y + np.sin(angle)*self.wgt_beam_length
            starty_out = beam_y + np.sin(angle)*(self.total_length - self.wgt_beam_length)
            taper_list_in = []
            taper_list_out = []
            for i in range(int(self.nbr_taper)):
                ratio = self.period/self.radius
                taper_radii = self.radius_taper + i*(self.radius-self.radius_taper)/(self.nbr_taper-1)
                taper_period = taper_radii*ratio
                x_in = startx_in + i*np.cos(angle)*taper_period
                y_in = starty_in + i*np.sin(angle)*taper_period
                taper_list_in.append(gdspy.Round((x_in,y_in), taper_radii))
                x_out = startx_out - i*np.cos(angle)*taper_period
                y_out = starty_out - i*np.sin(angle)*taper_period
                taper_list_out.append(gdspy.Round((x_out,y_out), taper_radii))

        for hole in hole_list:
            nanobeam = gdspy.fast_boolean(nanobeam,hole,'xor')
        for hole_in in taper_list_in:
            nanobeam = gdspy.fast_boolean(nanobeam,hole_in,'xor')        
        for hole_out in taper_list_out:
            nanobeam = gdspy.fast_boolean(nanobeam,hole_out,'xor')
            
        self.add(nanobeam)
        self.add(nanobeam_clad)