Beispiel #1
0
def _example_ii():
    from gdshelpers.parts.splitter import MMI
    from gdshelpers.geometry import geometric_union

    mmi1 = MMI((0, 0), 0, 1, 42, 7.7, 2, 2)
    mmi2 = MMI((0, 10), 0, 1, 42, 7.7, 2, 2)
    mmi3 = MMI((0, -10), 0, 1, 42, 7.7, 2, 2)

    mmi4 = MMI((0, -20), 0, 1, 42, 7.7, 2, 2)
    mmi5 = MMI((0, -30), 0, 1, 42, 7.7, 2, 2)

    shapely_objects = []

    s3d1 = Shapely3d(
        geometric_union([
            mmi1.get_shapely_object(),
            mmi2.get_shapely_object(),
            mmi3.get_shapely_object()
        ]), 0.0, 0.7, (255, 0, 0))

    s3d2 = Shapely3d(
        geometric_union([mmi4.get_shapely_object(),
                         mmi5.get_shapely_object()]), 0.0, 0.7, (0, 255, 0))

    shapely_objects.append(s3d1)
    shapely_objects.append(s3d2)

    render_image_and_save_as_blend(shapely_objects, "mmi2")
def _example():
    from gdshelpers.geometry.chip import Cell
    from gdshelpers.parts.waveguide import Waveguide
    from gdshelpers.parts.resonator import RingResonator

    # ==== create some sample structures (straight line with ring resonator)
    wg = Waveguide(origin=(0, 0), angle=np.deg2rad(-90), width=1)
    wg.add_straight_segment(length=5)
    wg.add_bend(np.pi / 2, 5)
    wg2 = Waveguide.make_at_port(wg.current_port)
    wg2.add_straight_segment(15)
    reso = RingResonator.make_at_port(port=wg2.current_port, gap=0.2, radius=5)
    wg2.add_straight_segment(length=15)
    coupler2 = GratingCoupler.make_traditional_coupler_from_database_at_port(
        wg2.current_port, db_id='si220', wavelength=1550)

    underetching_parts = geometric_union([wg2, reso, coupler2])
    structure = geometric_union([underetching_parts, wg])
    # create the holes with a radius of 0.5 microns, a distance of 2 microns to the structure borders and
    # a distance of 2 microns between the holes
    holes = create_holes_for_under_etching(underetch_parts=underetching_parts,
                                           complete_structure=structure,
                                           hole_radius=0.5,
                                           hole_distance=2,
                                           hole_spacing=3,
                                           hole_length=3)

    # create a cell with the structures in layer 1 and the holes in layer 2
    cell = Cell('CELL')
    cell.add_to_layer(1, structure)
    cell.add_to_layer(2, holes)
    # Show the cell
    cell.show()
Beispiel #3
0
    def make_electrodes(self):
        bottom_left = self.nanowire_port.origin + np.array(
            [0.5 * self.electrodes_gap, self.nw_length + 25.])
        top_left = bottom_left + (0, self.electrodes_height)
        electrode_width = self.electrodes_pitch - self.electrodes_gap
        top_right = top_left + (electrode_width, 0)
        bottom_right = (top_right[0], bottom_left[1])
        bottom_middle = np.array((bottom_right[0] - 0.5 * electrode_width,
                                  self.wing_pad_bottom_left[1]))
        pad = Polygon([
            self.wing_pad_bottom_left, self.wing_pad_top_left,
            self.wing_pad_top_right, bottom_left, top_left, top_right,
            bottom_right, bottom_middle
        ])
        pad = geometric_union([pad])
        pad = shapely.affinity.translate(pad, yoff=0.5 * self.nw_width)
        pad_l = shapely.affinity.scale(pad,
                                       xfact=-1.0,
                                       yfact=1.0,
                                       zfact=1.0,
                                       origin=[0, 0, 0])
        pad = geometric_union([pad, pad_l])

        pad = shapely.affinity.rotate(pad,
                                      self._origin_port.angle - 0.5 * np.pi,
                                      origin=[0, 0],
                                      use_radians=True)
        self.pad = shapely.affinity.translate(pad,
                                              xoff=self._origin_port.origin[0],
                                              yoff=self._origin_port.origin[1])
def create_holes_for_under_etching(underetch_parts,
                                   complete_structure,
                                   hole_radius,
                                   hole_distance,
                                   hole_spacing,
                                   hole_length=0,
                                   cap_style='round'):
    """
    Creates holes around given parts which can be used for underetching processes

    :param underetch_parts: List of gdshelpers parts around which the holes shall be placed
    :param complete_structure: geometric union of the complete structure, needed to avoid collisions between
        underetching holes and other structures, e.g. waveguides
    :param hole_radius: Radius of the holes in microns
    :param hole_distance: Distance between the holes edges from the the structures in microns
    :param hole_spacing: Distance between the holes in microns
    :param hole_length: Length of the holes (if 0 creates circles, else rectangle like)
    :param cap_style: CAP_STYLE of the holes (i.e. 'round' or 'square', see Shapely Docs)
    :return: Geometric union of the created holes
    """
    cap_style = {
        'round': CAP_STYLE.round,
        'square': CAP_STYLE.square
    }[cap_style]
    union = geometric_union(underetch_parts)
    no_hole_zone = complete_structure.buffer(0.9 *
                                             (hole_distance + hole_radius),
                                             resolution=32,
                                             cap_style=3)
    poly = union.buffer(hole_distance + hole_radius,
                        resolution=32,
                        cap_style=CAP_STYLE.square)

    base_polygon = shapely_adapter.shapely_collection_to_basic_objs(poly)

    holes = []
    for obj in base_polygon:
        for interior in [obj.exterior] + list(obj.interiors):
            dist = 0
            while dist < interior.length:
                if hole_length == 0:
                    hole = interior.interpolate(distance=dist)
                    dist += hole_spacing + 2 * hole_radius
                else:
                    positions = [
                        interior.interpolate(distance=d) for d in np.linspace(
                            dist - hole_length / 2 + hole_radius, dist +
                            hole_length / 2 - hole_radius, 10)
                    ]
                    dist += hole_spacing + hole_length

                    hole = LineString(positions)
                if not no_hole_zone.contains(hole):
                    holes.append(hole.buffer(hole_radius, cap_style=cap_style))

    return geometric_union(holes)
Beispiel #5
0
def convert_to_positive_resist(parts,
                               buffer_radius,
                               outer_resolution=None,
                               clearance_features=None,
                               exclude=None):
    """
    Convert a list of parts and shapely objects to a positive resist design by
    adding a buffer around the actual design.

    :param parts: List of parts and shapely objects.
    :param buffer_radius: Buffer radius
    :param outer_resolution: Outer buffer circumference resolution. Defaults to one 20th of the buffer radius.
    :param clearance_features: List of additional features to include in the generated structure. Can be useful for
                               providing clearance areas around couplers or other features.
    :param exclude: List of features to subtract from the generated structure. Can be used for interconnects between
                    structures from different cells, such that the end of a waveguide remains "open".
    :return: Converted Shapely geometry.
    :rtype: shapely.base.BaseGeometry
    """
    outer_resolution = buffer_radius / 20. if outer_resolution is None else outer_resolution

    assert buffer_radius > 0, 'The buffer radius must be positive.'
    assert outer_resolution >= 0, 'Resolution must be positive or zero.'

    parts = (parts, ) if not isinstance(parts, (tuple, list)) else parts

    # First merge all parts into one big shapely object
    union = geometric_union(parts)

    # Sometimes those polygons do not touch correctly and have micro gaps due to
    # floating point precision. We work around this by inflating the object a tiny bit.
    fixed_union = union.buffer(np.finfo(np.float32).eps, resolution=0)

    # Generate the outer polygon and simplify if required
    outer_poly = union.buffer(buffer_radius)

    if outer_resolution:
        outer_poly = outer_poly.simplify(outer_resolution)

    # Add clearance features (before subtracting the actual parts)
    if clearance_features is not None:
        clearance = (clearance_features, ) if not isinstance(
            clearance_features, (tuple, list)) else clearance_features
        outer_poly = geometric_union((outer_poly, *clearance))

    # Substract the original parts from outer poly
    inverted = outer_poly.difference(fixed_union)

    # Exclude other exclusion features from the generated structure
    if exclude is not None:
        exclude = (exclude, ) if not isinstance(exclude,
                                                (tuple, list)) else exclude
        exclude = geometric_union(exclude)
        inverted = inverted.difference(exclude)

    return inverted
Beispiel #6
0
 def make_waveguide(self):
     wg = Waveguide.make_at_port(self._origin_port)
     wg.add_straight_segment(self.nw_length + 0.5 * self.nw_width +
                             self.wing_height)
     if self.waveguide_tapering:
         wg.add_straight_segment(2. * self._origin_port.width,
                                 final_width=0.01)
     self.waveguide_port = wg.current_port
     wg = geometric_union([wg])
     nw = self.nw.difference(wg)
     buffer = nw.buffer(.2)
     self.wg = geometric_union([wg, buffer])
Beispiel #7
0
    def get_shapely_object(self):
        size_half = self.size / 2.
        p1 = shapely.geometry.Polygon(
            [(-size_half, size_half + self.frame_width), (size_half, size_half + self.frame_width),
             (0, size_half)])
        p2 = shapely.geometry.Polygon([(size_half, size_half), (size_half, size_half + self.frame_width),
                                       (size_half + self.frame_width, size_half)])

        one_side = geometric_union([p1, p2])

        marker = geometric_union([shapely.affinity.rotate(one_side, phi, (0, 0)) for phi in (0, 90, 180, 270)])
        return shapely.affinity.translate(marker, self.origin[0], self.origin[1])
Beispiel #8
0
    def _make_electrodes(self):
        phi = np.linspace(math.pi, 2 * math.pi, self.points)

        circle_points = np.array(
            [self.radius * np.cos(phi), self.radius * np.sin(phi)]).T

        first_part_points = [
            circle_points[0], (-self.radius, self.el_l_fine),
            (self.radius, self.el_l_fine), circle_points[-1]
        ]

        taper_points = [
            first_part_points[1],
            (-self.final_width / 2, self.el_l_fine + self.el_l_taper),
            (self.final_width / 2, self.el_l_fine + self.el_l_taper),
            first_part_points[-2]
        ]

        last_part_points = [
            taper_points[1],
            (-self.final_width / 2,
             self.el_l_fine + self.el_l_taper + self.el_l_straight),
            (self.final_width / 2,
             self.el_l_fine + self.el_l_taper + self.el_l_straight),
            taper_points[-2]
        ]

        cirlce_polygon = shapely.geometry.Polygon(circle_points)
        first_part_polygon = shapely.geometry.Polygon(first_part_points)
        taper_polygon = shapely.geometry.Polygon(taper_points)
        last_part_polygon = shapely.geometry.Polygon(last_part_points)

        polygon = geometric_union([
            cirlce_polygon, taper_polygon, first_part_polygon,
            last_part_polygon
        ])

        upper_electrode = shapely.affinity.translate(polygon, self.el_shift_x,
                                                     self.el_shift_y)
        lower_electrode = shapely.affinity.scale(upper_electrode,
                                                 xfact=-1,
                                                 yfact=-1,
                                                 origin=(0, 0))

        electrode = geometric_union([lower_electrode, upper_electrode])
        electrode = shapely.affinity.rotate(electrode,
                                            self._cnt_port.angle,
                                            use_radians=True)
        electrode = shapely.affinity.translate(electrode,
                                               self._cnt_port.origin[0],
                                               self._cnt_port.origin[1])
        self.electrodes = electrode
Beispiel #9
0
    def get_reduced_layer(self, layer: int):
        """
        Returns a single shapely object containing the structures on a certain layer from this cell and all added cells.

        :param layer: the layer whose structures will be returned
        :return: a single shapely-geometry
        """
        def translate_and_rotate(geometry, offset, angle, columns, rows,
                                 spacing):
            if not geometry:
                return geometry

            if not spacing:
                return translate(
                    rotate(geometry,
                           angle if angle else 0,
                           use_radians=True,
                           origin=(0, 0)), *offset)

            return translate(
                geometric_union(
                    translate(
                        rotate(geometry,
                               angle if angle else 0,
                               use_radians=True,
                               origin=(0, 0)), spacing[0] * c, spacing[1] * r)
                    for c in range(columns) for r in range(rows)), *offset)

        return geometric_union(
            (self.layer_dict[layer] if layer in self.layer_dict else []) + [
                translate_and_rotate(cell['cell'].get_reduced_layer(
                    layer), cell['origin'], cell['angle'], cell['columns'],
                                     cell['rows'], cell['spacing'])
                for cell in self.cells
            ])
Beispiel #10
0
def surround_with_holes(geometry, hole_spacing, hole_radius, padding,
                        max_distance):
    """
    Surrounds the given geometry with holes, which are arranged in a square lattice around the structure.
    This can be used for generating vortex traps like presented in https://doi.org/10.1103/PhysRevApplied.11.064053

    :param geometry: The geometry around which the holes are generated
    :param hole_spacing: Spacing between the holes
    :param hole_radius: Radius of the holes
    :param padding: Padding around the geometry
    :param max_distance: Maximum distance of a hole from the geometry
    :return: Shapely object, which describes the holes
    """
    geometry = geometric_union(geometry if isinstance(geometry, (
        tuple, list)) else (geometry, ))
    buffer_around_waveguide = geometry.buffer(max_distance)
    area_for_holes = prep(
        buffer_around_waveguide.difference(
            geometry.buffer(hole_radius + padding)))
    area = buffer_around_waveguide.bounds
    points = (Point(x, y) for x in np.arange(area[0], area[2], hole_spacing)
              for y in np.arange(area[1], area[3], hole_spacing))
    return MultiPolygon([
        point.buffer(hole_radius) for point in points
        if area_for_holes.contains(point)
    ])
Beispiel #11
0
    def get_shapely_object(self):
        if not self._in_wgs or not self._out_wgs:
            self._calculate(do_in_wgs=True, do_out_wgs=True)

        markers = [DLWMarker(pos) for pos in self.marker_positions]

        return geometric_union(self._out_wgs + self._in_wgs + markers)
Beispiel #12
0
def _example_iii():
    from gdshelpers.parts.waveguide import Waveguide
    from gdshelpers.parts.coupler import GratingCoupler
    from gdshelpers.geometry import geometric_union
    import numpy as np

    coupler1 = GratingCoupler.make_traditional_coupler((250 / 2, 0),
                                                       1.3,
                                                       np.deg2rad(40),
                                                       1.13,
                                                       0.85,
                                                       20,
                                                       taper_length=16,
                                                       ap_max_ff=0.985,
                                                       n_ap_gratings=10)
    wave_guide = Waveguide.make_at_port(coupler1.port)
    wave_guide.add_straight_segment(20)
    wave_guide.add_bend(0.5 * np.pi, 40)
    wave_guide.add_straight_segment(250 - 2 * 40)
    wave_guide.add_bend(0.5 * np.pi, 40)
    wave_guide.add_straight_segment(20)
    coupler2 = GratingCoupler.make_traditional_coupler(
        (wave_guide.current_port.origin[0], wave_guide.current_port.origin[1]),
        1.3,
        np.deg2rad(40),
        1.13,
        0.85,
        20,
        taper_length=16,
        ap_max_ff=0.985,
        n_ap_gratings=10)

    shapely_objects = [
        Shapely3d(
            geometric_union([
                coupler1.get_shapely_object(),
                wave_guide.get_shapely_object(),
                coupler2.get_shapely_object()
            ]), 0.0, 0.7, (255, 255, 255))
    ]

    render_image_and_save_as_blend(shapely_objects,
                                   "test_device_under_right",
                                   camera_position_y='under',
                                   camera_position_x='right')

    render_image_and_save_as_blend(shapely_objects,
                                   "test_device_above_left",
                                   camera_position_y='above',
                                   camera_position_x='left')

    render_image_and_save_as_blend(shapely_objects,
                                   "test_device_under_left",
                                   camera_position_y='under',
                                   camera_position_x='left')

    render_image_and_save_as_blend(shapely_objects,
                                   "test_device_above_right",
                                   camera_position_y='above',
                                   camera_position_x='right')
Beispiel #13
0
    def get_shapely_object(self):
        splitter1 = Splitter(self.origin, self.angle, self.splitter_length, self.width, self.splitter_separation)

        upper_wg = Waveguide.make_at_port(splitter1.left_branch_port)
        upper_wg.add_bend(np.deg2rad(90), self.bend_radius)
        upper_wg.add_straight_segment(self.upper_vertical_length)
        upper_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        upper_wg.add_straight_segment(self.horizontal_length)
        upper_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        upper_wg.add_straight_segment(self.upper_vertical_length)
        upper_wg.add_bend(np.deg2rad(90), self.bend_radius)

        lower_wg = Waveguide.make_at_port(splitter1.right_branch_port)
        lower_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        lower_wg.add_straight_segment(self.lower_vertical_length)
        lower_wg.add_bend(np.deg2rad(90), self.bend_radius)
        lower_wg.add_straight_segment(self.horizontal_length)
        lower_wg.add_bend(np.deg2rad(90), self.bend_radius)
        lower_wg.add_straight_segment(self.lower_vertical_length)
        lower_wg.add_bend(np.deg2rad(-90), self.bend_radius)

        splitter2 = Splitter.make_at_right_branch_port(upper_wg.current_port, self.splitter_length,
                                                       self.splitter_separation)

        return geometric_union([splitter1, splitter2, upper_wg, lower_wg])
Beispiel #14
0
def convert_to_positive_resist(parts, buffer_radius, outer_resolution=None):
    """
    Convert a list of parts and shapely objects to a positive resist design by
    adding a buffer around the actual design.

    :param parts: List of parts and shapely objects.
    :param buffer_radius: Buffer radius
    :param outer_resolution: Outer buffer circumference resolution. Defaults to one 20th of the buffer radius.
    :return: Converted Shapely geometry.
    :rtype: shapely.base.BaseGeometry
    """
    outer_resolution = buffer_radius / 20. if outer_resolution is None else outer_resolution

    assert buffer_radius > 0, 'The buffer radius must be positive.'
    assert outer_resolution >= 0, 'Resolution must be positive or zero.'

    parts = (parts,) if not isinstance(parts, (tuple, list)) else parts

    # First merge all parts into one big shapely object
    union = geometric_union(parts)

    # Sometimes those polygons do not touch correctly and have micro gaps due to
    # floating point precision. We work around this by inflating the object a tiny bit.
    fixed_union = union.buffer(np.finfo(np.float32).eps, resolution=0)

    # Generate the outer polygon and simplify if required
    outer_poly = union.buffer(buffer_radius)

    if outer_resolution:
        outer_poly = outer_poly.simplify(outer_resolution)

    # Substract the original parts from outer poly
    inverted = outer_poly.difference(fixed_union)

    return inverted
Beispiel #15
0
    def get_shapely_object(self):
        splitter1 = MMI(origin=self.origin, angle=self.angle, wg_width=self.width, length=self.splitter_length,
                        width=self.splitter_width, num_inputs=1, num_outputs=2)
        print(splitter1.output_ports)
        upper_wg = Waveguide.make_at_port(splitter1.left_branch_port)
        upper_wg.add_bend(np.deg2rad(90), self.bend_radius)
        upper_wg.add_straight_segment(self.upper_vertical_length)
        upper_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        upper_wg.add_straight_segment(self.horizontal_length)
        upper_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        upper_wg.add_straight_segment(self.upper_vertical_length)
        upper_wg.add_bend(np.deg2rad(90), self.bend_radius)

        lower_wg = Waveguide.make_at_port(splitter1.right_branch_port)
        lower_wg.add_bend(np.deg2rad(-90), self.bend_radius)
        lower_wg.add_straight_segment(self.lower_vertical_length)
        lower_wg.add_bend(np.deg2rad(90), self.bend_radius)
        lower_wg.add_straight_segment(self.horizontal_length)
        lower_wg.add_bend(np.deg2rad(90), self.bend_radius)
        lower_wg.add_straight_segment(self.lower_vertical_length)
        lower_wg.add_bend(np.deg2rad(-90), self.bend_radius)

        splitter2 = MMI(origin=[self.origin[0] + self.dev_width, self.origin[1]], angle=self.angle + np.pi,
                        wg_width=self.width, length=self.splitter_length,
                        width=self.splitter_width, num_inputs=1, num_outputs=2)
        print(splitter2.input_ports)

        return geometric_union([splitter1, splitter2, upper_wg, lower_wg])
Beispiel #16
0
    def get_patches(self, origin=(0, 0), angle_sum=0, angle=0, layers=None):
        from descartes import PolygonPatch

        def rotate_pos(pos, rotation_angle):
            if rotation_angle is None:
                return pos
            c, s = np.cos(rotation_angle), np.sin(rotation_angle)
            result = np.array([[c, -s], [s, c]]).dot(pos)
            return result

        own_patches = []
        for layer, geometry in self.layer_dict.items():
            if layers is not None and layer not in layers:
                continue
            geometry = geometric_union(geometry)
            if geometry.is_empty:
                continue
            geometry = translate(rotate(geometry, angle_sum, use_radians=True, origin=(0, 0)), *origin)
            own_patches.append(
                PolygonPatch(geometry, color=['red', 'green', 'blue', 'teal', 'pink'][(layer - 1) % 5], linewidth=0))

        sub_cells_patches = [p for cell_dict in self.cells for p in
                             cell_dict['cell'].get_patches(
                                 np.array(origin) + rotate_pos(cell_dict['origin'], angle),
                                 angle_sum=angle_sum + (cell_dict['angle'] or 0), angle=cell_dict['angle'],
                                 layers=layers)]

        return own_patches + sub_cells_patches
Beispiel #17
0
def _example_mmi():
    import gdsCAD.core
    from gdshelpers.geometry import convert_to_gdscad

    mmi = MMI((80, 0), 0, 1, 20, 10, 2, 2)

    cell = gdsCAD.core.Cell('Splitter')
    cell.add(convert_to_gdscad(geometric_union([mmi])))
    cell.show()
Beispiel #18
0
    def get_reduced_layer(self, layer):
        def translate_and_rotate(geometry, offset, angle):
            if not geometry:
                return geometry
            return translate(rotate(geometry, angle if angle else 0, use_radians=True, origin=(0, 0)), *offset)

        return geometric_union(
            (self.layer_dict[layer] if layer in self.layer_dict else []) +
            [translate_and_rotate(cell['cell'].get_reduced_layer(layer), cell['origin'], cell['angle'])
             for cell in self.cells])
Beispiel #19
0
 def get_shapely_object(self):
     shapely_object = geometric_union([
         self._gate(),
         self._choke_channel(),
         self._choke_left(),
         self._choke_right(),
         self._channel()
     ])
     rotated_object = rotate(shapely_object, self._angle, (0, 0), True)
     return translate(rotated_object, self._origin[0], self._origin[1], 0)
Beispiel #20
0
def _cnt_example():
    import gdsCAD.core
    from gdshelpers.geometry import convert_to_gdscad
    from gdshelpers.parts.waveguide import Waveguide

    # photonics
    start_port = Port((0, 0), 0, 1.1)
    wg = Waveguide.make_at_port(start_port)
    wg.add_straight_segment(20)
    cnt_port = wg.current_port
    cnt = CNT.make_at_port(cnt_port, gap=0.4, l_taper=100, w_taper=0.1)
    wg2 = Waveguide.make_at_port(cnt.out_port)
    wg2.add_bend(np.pi / 4, 100)

    cnt2 = CNT.make_at_port(wg2.current_port, gap=0.15)

    union = geometric_union([wg, cnt, wg2, cnt2])

    # electrodes
    el1_l = Waveguide.make_at_port(cnt.left_electrode_port)
    el1_l.add_straight_segment(100, 100)
    el1_r = Waveguide.make_at_port(cnt.right_electrode_port)
    # el1_r.add_straight_segment(100)

    port = cnt2.left_electrode_port
    port.width = 20
    el2_l = Waveguide.make_at_port(port)
    el2_l.add_straight_segment(30)

    el = geometric_union(
        [cnt.electrodes, cnt2.electrodes, el1_l, el1_r, el2_l])

    cell = gdsCAD.core.Cell('test')
    cell.add(convert_to_gdscad(union))
    cell.add(convert_to_gdscad(el, layer=2))
    layout = gdsCAD.core.Layout()
    layout.add(cell)
    layout.show()
    layout.save('CNT_Device_Test.gds')
Beispiel #21
0
def _example():
    from gdshelpers.geometry.chip import Cell
    from gdshelpers.geometry import geometric_union

    # Generate a coupler, which ought to be identical to
    # coupler_sn330_1550_bf_ff_ap( 0:0 1550 0.7 22 0.96 10 22 1 "active")
    # also known as
    # coupler_bf_ap_mff( 0:0 1 40.0 1.13 0.7 22 0.96 10 22 200 "active")
    coupler = GratingCoupler.make_traditional_coupler([150, 0],
                                                      1,
                                                      np.deg2rad(40),
                                                      1.13,
                                                      0.7,
                                                      22,
                                                      0.96,
                                                      10,
                                                      22,
                                                      angle=-np.pi)

    coupler2 = GratingCoupler.make_traditional_coupler_from_database([0, 0], 1,
                                                                     'sn330',
                                                                     1550)

    print(coupler.get_description_str())

    whole_layout = (coupler, coupler2)

    layout = Cell('LIBRARY')
    cell = Cell('TOP')
    cell.add_to_layer(1, *whole_layout)
    cell.add_to_layer(StandardLayers.parnamelayer1,
                      coupler.get_description_text())
    cell.add_to_layer(StandardLayers.parnamelayer1,
                      coupler2.get_description_text())

    cell.add_to_layer(1, coupler.get_description_text())
    cell.add_to_layer(1, coupler2.get_description_text())
    cell.add_to_layer(1, coupler2.get_description_text(side='left'))
    layout.add_cell(cell)

    # We could also easily generate a dark field layout out of this
    def make_dark_field(obj, buffer_size=1.5):
        return obj.buffer(buffer_size).difference(obj)

    cell_df = Cell('TOP_DF')
    cell_df.add_to_layer(2, make_dark_field(geometric_union(whole_layout)))
    layout.add_cell(cell_df)

    layout.save('coupler.gds')
    cell.show()
Beispiel #22
0
 def get_fractured_layer_dict(self, max_points=4000, max_line_points=4000):
     from gdshelpers.geometry.shapely_adapter import shapely_collection_to_basic_objs, fracture_intelligently
     fractured_layer_dict = {}
     for layer, geometries in self.layer_dict.items():
         fractured_geometries = []
         for geometry in geometries:
             geometry = geometry.get_shapely_object() if hasattr(geometry, 'get_shapely_object') else geometry
             if type(geometry) in [list, tuple]:
                 geometry = geometric_union(geometry)
             geometry = shapely_collection_to_basic_objs(geometry)
             geometry = itertools.chain(
                 *[fracture_intelligently(geo, max_points, max_line_points) for geo in geometry if not geo.is_empty])
             fractured_geometries.append(geometry)
         fractured_layer_dict[layer] = itertools.chain(*fractured_geometries)
     return fractured_layer_dict
Beispiel #23
0
def create_holes_for_under_etching(underetch_parts, complete_structure,
                                   hole_radius, hole_distance, hole_spacing):
    """
    Creates holes around given parts which can be used for underetching processes

    :param underetch_parts: List of gdshelpers parts around which the holes shall be placed
    :param complete_structure: geometric union of the complete structure, needed to avoid collisions between
        underetching holes and other structures, e.g. waveguides
    :param hole_radius: Radius of the holes in microns
    :param hole_distance: Distance of the holes center from the the structures in microns
    :param hole_spacing: Distance between the holes in microns
    :return: Geometric union of the created holes
    """

    union = geometric_union(underetch_parts)
    no_hole_zone = complete_structure.buffer(0.9 * hole_distance,
                                             resolution=32,
                                             cap_style=3)
    poly = union.buffer(hole_distance, resolution=32, cap_style=3)

    base_polygon = shapely_adapter.shapely_collection_to_basic_objs(poly)

    holes = []
    for obj in base_polygon:
        ext = obj.exterior
        for dist in np.arange(0, ext.length, hole_spacing):
            pos = ext.interpolate(distance=dist)
            if not no_hole_zone.contains(pos):
                holes.append(pos.buffer(hole_radius))
        for interior in obj.interiors:
            for dist in np.arange(0, interior.length, hole_spacing):
                pos = interior.interpolate(distance=dist)
                if not no_hole_zone.contains(pos):
                    holes.append(pos.buffer(hole_radius))

    return geometric_union(holes)
Beispiel #24
0
def _example():
    import gdsCAD.core
    from gdshelpers.geometry import convert_to_gdscad

    dc = DirectionalCoupler((0, 0), np.pi / 4, 1, 10, 1, 10)
    dc2 = DirectionalCoupler.make_at_port(dc.right_ports[1], 5, 2, 10, which=0)
    wg = Waveguide.make_at_port(dc.left_ports[1])
    wg.add_straight_segment(12)
    wg2 = Waveguide.make_at_port(dc2.right_ports[0])
    wg2.add_straight_segment(12)

    mmi = MMI((80, 0), 0, 1, 20, 10, 2, 1)
    mmi2 = MMI.make_at_port(dc2.right_ports[1], 10, 10, 2, 2, 'i1')

    cell = gdsCAD.core.Cell('Splitter')
    cell.add(convert_to_gdscad(geometric_union((dc, dc2, wg, wg2, mmi, mmi2))))
    cell.show()
Beispiel #25
0
    def get_shapely_object(self):
        wg = Waveguide.make_at_port(self._origin_port)
        opposite_wg = Waveguide.make_at_port(
            self.opposite_side_port_in.inverted_direction)

        if self.straight_feeding:
            wg.add_straight_segment(self.radius)
            if self.draw_opposite_side_wg:
                opposite_wg.add_straight_segment(self.radius)

        ring_port = wg.current_port.parallel_offset(self._offset)
        ring_port.width = self.res_wg_width
        ring = Waveguide.make_at_port(ring_port)

        if self.race_length:
            wg.add_straight_segment(self.race_length)

            if self.draw_opposite_side_wg:
                opposite_wg.add_straight_segment(self.race_length)

        if self.straight_feeding:
            wg.add_straight_segment(self.radius)
            if self.draw_opposite_side_wg:
                opposite_wg.add_straight_segment(self.radius)

        # Build the ring
        bend_angle = math.copysign(0.5 * np.pi, self.gap)
        if self.race_length:
            ring.add_straight_segment(self.race_length)

        ring.add_bend(bend_angle, self.radius, n_points=self.points)
        if self.vertical_race_length:
            ring.add_straight_segment(self.vertical_race_length)

        ring.add_bend(bend_angle, self.radius, n_points=self.points)
        if self.race_length:
            ring.add_straight_segment(self.race_length)

        ring.add_bend(bend_angle, self.radius, n_points=self.points)
        if self.vertical_race_length:
            ring.add_straight_segment(self.vertical_race_length)

        ring.add_bend(bend_angle, self.radius, n_points=self.points)

        return geometric_union([ring, wg, opposite_wg])
Beispiel #26
0
        def translate_and_rotate(geometry, offset, angle, columns, rows,
                                 spacing):
            if not geometry:
                return geometry

            if not spacing:
                return translate(
                    rotate(geometry,
                           angle if angle else 0,
                           use_radians=True,
                           origin=(0, 0)), *offset)

            return translate(
                geometric_union(
                    translate(
                        rotate(geometry,
                               angle if angle else 0,
                               use_radians=True,
                               origin=(0, 0)), spacing[0] * c, spacing[1] * r)
                    for c in range(columns) for r in range(rows)), *offset)
Beispiel #27
0
 def get_shapely_object(self):
     if not self.wg_in or not self.wg_out:
         self._generate()
     return geometric_union([self.wg_in, self.wg_out])
Beispiel #28
0
 def get_shapely_object(self):
     return geometric_union(self.waveguide)
Beispiel #29
0
    def _generate(self):
        if self._sep < self._wr:
            raise ValueError(
                'The separation gap must be larger than the branch width.')

        if self._implement_cadence_bug:
            v1 = Splitter._connect_two_points(
                [self._wl / 2, 0],
                [self._sep / 2 + self._wr / 2, self._total_length],
                self._n_points)
            if self._wl < 2 * self._wr:
                v2 = (v1 - [self._wr, 0])[::-1, :]
            else:
                # NOTE: In this obscure case, the generated splitter looks different than the cadence version.
                #       But probably it is better, since the paths are all smooth and curvy instead of just painting a
                #       triangle.
                v2 = Splitter._connect_two_points(
                    [-self._wr / 2, 0],
                    [self._sep / 2 - self._wr / 2, self._total_length],
                    self._n_points)[::-1, :]

            v = np.vstack((v1, v2))
            polygon1 = shapely.geometry.Polygon(v)
            polygon1 = polygon1.difference(
                shapely.geometry.box(-self._sep / 2, 0, 0, self._total_length))
            polygon2 = shapely.affinity.scale(polygon1,
                                              xfact=-1,
                                              origin=[0, 0, 0])

            polygon = polygon1.union(polygon2)

            polygon = shapely.affinity.rotate(polygon,
                                              -np.pi / 2 + self._angle,
                                              origin=[0, 0],
                                              use_radians=True)
            polygon = shapely.affinity.translate(polygon, self._origin[0],
                                                 self._origin[1])

            # Keep track of the ports
            port_points = shapely.geometry.MultiPoint([
                (0, 0), (-self._sep / 2, self._total_length),
                (+self._sep / 2, self._total_length)
            ])
            port_points = shapely.affinity.rotate(port_points,
                                                  -np.pi / 2 + self._angle,
                                                  origin=[0, 0],
                                                  use_radians=True)
            port_points = shapely.affinity.translate(port_points,
                                                     self._origin[0],
                                                     self._origin[1])

            self._polygon = polygon
            self._ports['root'] = Port(port_points[0].coords[0],
                                       self._angle + np.pi,
                                       width=self._wl)
            self._ports['left_branch'] = Port(port_points[1].coords[0],
                                              self._angle,
                                              width=self._wr)
            self._ports['right_branch'] = Port(port_points[2].coords[0],
                                               self._angle,
                                               width=self._wr)

        else:
            # Simpler version which also cares for a constant wave guide width
            alpha = np.arctan(4.0 * self._total_length * self._sep /
                              (4.0 * self._total_length**2.0 - self._sep**2.0))
            radius = 1.0 / 8.0 * (4.0 * self._total_length**2.0 +
                                  self._sep**2.0) / self._sep

            root_port = Port(self._origin, self._angle, self._wl)
            half_final_width = (self._wl + self._wr) / 2.

            upper_wg = Waveguide.make_at_port(root_port)
            upper_wg.add_bend(alpha, radius, final_width=half_final_width)
            upper_wg.add_bend(-alpha, radius, final_width=self._wr)

            lower_wg = Waveguide.make_at_port(root_port)
            lower_wg.add_bend(-alpha, radius, final_width=half_final_width)
            lower_wg.add_bend(alpha, radius, final_width=self._wr)

            self._polygon = geometric_union([upper_wg, lower_wg])
            self._ports['root'] = root_port.inverted_direction
            self._ports['left_branch'] = upper_wg.current_port
            self._ports['right_branch'] = lower_wg.current_port
Beispiel #30
0
 def get_shapely_object(self):
     return geometric_union(self._wgs)