Ejemplo n.º 1
0
def star(w, L, layer=1):
    p1 = [(-L * math.cos(math.pi / 3), L * math.sin(math.pi / 3)), (0, 0),
          (-L * math.cos(math.pi / 3), -L * math.sin(math.pi / 3))]
    p2 = [(0, 0), (L, 0)]
    arm1 = gp.PolyPath(p1, w, layer=layer)
    arm2 = gp.PolyPath(p2, w, layer=layer)
    star = gp.fast_boolean(arm1, arm2, "or", layer=layer)
    return star
Ejemplo n.º 2
0
def t_wire(w, L, l=1, up=False, layer=1):
    p1 = [(-L / 2, 0), (L / 2, 0)]
    if up == False:
        p2 = [(0, 0), (-l * math.cos(math.pi / 3), -l * math.sin(math.pi / 3))]
    else:
        p2 = [(0, 0), (l * math.cos(math.pi / 3), l * math.sin(math.pi / 3))]
    arm1 = gp.PolyPath(p1, w, layer=layer)
    arm2 = gp.PolyPath(p2, w, layer=layer)
    t = gp.fast_boolean(arm1, arm2, "or", layer=layer)
    return t
Ejemplo n.º 3
0
def barred_hexagon(w, L, layer=1):
    p1 = [(-L, 0), (-L * math.cos(math.pi / 3), L * math.sin(math.pi / 3)),
          (+L * math.cos(math.pi / 3), L * math.sin(math.pi / 3)), (L, 0),
          (L * math.cos(math.pi / 3), -L * math.sin(math.pi / 3)),
          (-L * math.cos(math.pi / 3), -L * math.sin(math.pi / 3)), (-L, 0)]
    p2 = [(-3 * L, 0), (3 * L, 0)]
    hexagon = gp.PolyPath(p1, w, layer=layer)
    bar = gp.PolyPath(p2, w, layer=layer)
    struct = gp.fast_boolean(hexagon, bar, "or", layer=layer)
    return struct
Ejemplo n.º 4
0
def m_wire(w, L, l=0.5, d=0.5, up=False, layer=1):
    p1 = [(-L / 2, 0), (L / 2, 0)]
    if up == False:
        p2 = [(0, 0), (-l * math.cos(math.pi / 3), -l * math.sin(math.pi / 3))]
    else:
        p2 = [(0, 0), (l * math.cos(math.pi / 3), l * math.sin(math.pi / 3))]
    arm1 = gp.PolyPath(p1, w, layer=layer)
    arm2 = gp.PolyPath(p2, w, layer=layer)
    arm3 = gp.PolyPath(p2, w, layer=layer).translate(-d, 0)
    arm4 = gp.PolyPath(p2, w, layer=layer).translate(d, 0)
    t = gp.fast_boolean(arm1, arm2, "or", layer=layer)
    n = gp.fast_boolean(arm3, arm4, "or", layer=layer)
    m = gp.fast_boolean(t, n, "or", layer=layer)
    return m
Ejemplo n.º 5
0
def single_wire(w, L, layer=1, orientation=0):
    """
    Returns a gdspy shape with one single wire centered at origin
    """
    angle_rad = orientation * math.pi / 180
    p = [(0, 0), (L * math.cos(angle_rad), L * math.sin(angle_rad))]
    wire = gp.PolyPath(p, w, layer=layer)
    return wire
Ejemplo n.º 6
0
def line(dxy, width, width_end=False, layer=0, datatype=0):

    width_end = width if (not width_end) else width_end

    p = [(0, 0), dxy]
    w = [width, width_end]

    poly = gd.PolyPath(p, w, layer=layer, datatype=datatype)
    ends = {'A': p[0], 'B': p[-1]}
    epsz = {'A': w[0], 'B': w[-1]}

    return gtools.classes.GDStructure(poly, ends, epsz)
Ejemplo n.º 7
0
def SBend(Zs=10, Xs=10, waveguideWidth=0.5, layerNumber=1):

    z = numpy.linspace(0, Zs, 1000)

    y = Xs / Zs * z - Xs / (2 * numpy.pi) * numpy.sin(2 * numpy.pi / Zs * z)

    points = numpy.stack([z, y], axis=1)

    poly_cell = gdspy.Cell('sBend_Length=' + str(Zs) + '_Height=' + str(Xs),
                           exclude_from_current=True)
    poly_cell.add(gdspy.PolyPath(points, waveguideWidth, layer=layerNumber))

    return poly_cell
Ejemplo n.º 8
0
def convert_to_layout_objs(objs,
                           layer=1,
                           datatype=None,
                           path_width=1.0,
                           path_pathtype=0,
                           max_points=None,
                           over_fracture_factor=1,
                           max_points_line=None,
                           library='gdscad',
                           grid_steps_per_micron=1000):
    """
    Convert any shapely or list of shapely objects to a list of gdsCAD objects.

    Since Shapely objects do not contain layer information nor line width for Shapely lines, you have to specify
    these during conversion. Typically, you will only convert polygons and specify the *layer*.

    Export options such as *datatype* and maximum number of points per Polygon/Line default to the current module
    default.

    On special feature is the *over_fracture_factor*. The polygons will be fractured into
    *max_points*/*over_fracture_factor* points and then healed again - which results in better fragmentation of some
    geometries. An *over_fracture_factor* of 0 will suppress healing.

    :param objs: Part or Shapely object or list of Parts and/or Shapely objects.
    :param layer: Layer on which to put the objects.
    :type layer: int
    :param datatype: GDS datatype of the converted objects. Defaults to module wide settings.
    :type datatype: int
    :param path_width: With of GDS path, converted from Shapely lines.
    :type path_width: float
    :param path_pathtype: GDS path end type.
    :type path_pathtype: int
    :param max_points: Maximum number of points. Defaults to module wide settings.
    :type max_points: int, None
    :param max_points_line: Maximum number of points for lines. Defaults to module wide settings.
    :type max_points_line: int, None
    :param over_fracture_factor: Break polygons in *over_fracture_factor* times smaller objects first. Then merge them
                                 again. May result in better fracturing but high numbers increase conversion time.

                                 When *over_fracture_factor* is set to 0, no additional healing is done.
    :type over_fracture_factor: int
    :param library: Defines the used library, either gdscad or gdspy
    :type library: str
    :param grid_steps_per_micron: Number of steps of the grid per micron, defaults to 1000 steps per micron
    :type grid_steps_per_micron: int
    """
    if library == 'gdscad':
        import gdsCAD
    elif library == 'gdspy':
        import gdspy
    elif library == 'oasis':
        import fatamorgana.records
    else:
        raise AssertionError('library must be either "gdscad" or "gdspy"')

    # If number of maximum points is not specified, default to the current profile default
    max_points = max_points if max_points is not None else gdshelpers.configuration.point_limit
    max_points_line = max_points_line if max_points_line is not None else gdshelpers.configuration.point_limit_line

    # If datatype is not specified, set it the same as layer
    if datatype is None:
        policy = gdshelpers.configuration.datatype_policy
        if policy == gdshelpers.configuration.DefaultDatatype.zero:
            datatype = 0
        elif policy == gdshelpers.configuration.DefaultDatatype.aslayer:
            datatype = layer
        elif policy == gdshelpers.configuration.DefaultDatatype.dose_factor:
            datatype = raith_eline_dosefactor_to_datatype(
                gdshelpers.configuration.dose_factor)

    objs = objs.get_shapely_object() if hasattr(objs,
                                                'get_shapely_object') else objs

    # Convert a list of objects to a true shapely object or collection first
    if type(objs) in [list, tuple]:
        objs = geometric_union(objs)

    # Convert the object or the collection to a list of basic shapely objects
    objs = shapely_collection_to_basic_objs(objs)

    fractured_objs = itertools.chain(*[
        fracture_intelligently(obj,
                               max_points=max_points,
                               max_points_line=max_points_line,
                               over_fracture_factor=over_fracture_factor)
        for obj in objs if not obj.is_empty
    ])

    exports_objs = list()
    for obj in fractured_objs:
        if type(obj) == shapely.geometry.Point:
            # raise TypeError('Shapely points are not supported to be converted.')
            pass
        elif type(obj) == shapely.geometry.LineString:
            if path_width:
                if library == 'gdscad':
                    exports_objs.append(
                        gdsCAD.core.Path(obj.coords,
                                         layer=layer,
                                         datatype=datatype,
                                         width=path_width,
                                         pathtype=path_pathtype))
                elif library == 'gdspy':
                    exports_objs.append(
                        gdspy.PolyPath(obj.coords,
                                       layer=layer,
                                       datatype=datatype,
                                       width=path_width,
                                       ends=path_pathtype))
                elif library == 'oasis':
                    rounded_coords = np.multiply(
                        obj.coords, grid_steps_per_micron).astype(np.int)
                    exports_objs.append(
                        fatamorgana.records.Path(
                            (rounded_coords[1:] -
                             rounded_coords[:-1]).tolist(),
                            layer=layer,
                            datatype=datatype,
                            half_width=int(path_width * grid_steps_per_micron),
                            extension_start=path_pathtype,
                            extension_end=path_pathtype,
                            x=rounded_coords[0][0],
                            y=rounded_coords[0][1]))

        elif type(obj) == shapely.geometry.Polygon:
            assert len(
                obj.interiors
            ) <= 1, 'No polygons with more than one hole allowed, got %i' % len(
                obj.interiors)
            if library == 'gdscad':
                exports_objs.append(
                    gdsCAD.core.Boundary(obj.exterior.coords,
                                         layer=layer,
                                         datatype=datatype))
            elif library == 'gdspy':
                exports_objs.append(
                    gdspy.Polygon(obj.exterior.coords,
                                  layer=layer,
                                  datatype=datatype))
            elif library == 'oasis':
                rounded_coords = np.multiply(
                    obj.exterior.coords, grid_steps_per_micron).astype(np.int)
                exports_objs.append(
                    fatamorgana.records.Polygon(
                        (rounded_coords[1:] - rounded_coords[:-1]).tolist(),
                        layer=layer,
                        datatype=datatype,
                        x=rounded_coords[0][0],
                        y=rounded_coords[0][1]))

        else:
            raise TypeError('Unhandled type "%s"' % type(obj))
    return exports_objs
Ejemplo n.º 9
0
def spiral_circular(
    length: float = 1e3,
    wg_width: float = 0.5,
    spacing: float = 3.0,
    min_bend_radius: float = 5.0,
    points: int = 1000,
    layer: Tuple[int, int] = gf.LAYER.WG,
) -> Component:
    """Returns a circular spiral.

    FIXME, has some issues

    Args:
        length: length in um
        wg_width:
        spacing: between straights
        min_bend_radius:
        points:
        layer:

    """
    wg_datatype = layer[1]
    wg_layer = layer[0]

    def pol_to_rect(radii, angles_deg):
        angles_rad = np.radians(angles_deg)
        z = radii * np.exp(1.0j * angles_rad)
        return z.real, z.imag

    ps = []

    # Estimate number of revolutions
    length_total = 0.0
    i = 0
    while length_total <= length:
        length_total += 3.0 * np.pi * (min_bend_radius * 2.0 +
                                       (i + 0.5) * spacing)
        i += 1
    revolutions = i + 1

    # Long spiral
    inner_revs = min_bend_radius * 4.0 / (spacing * 4.0)
    theta_1 = np.linspace(360.0 * inner_revs, 360.0 * (revolutions - 1) + 270,
                          points)
    theta_2 = np.linspace(360.0 * inner_revs, 360.0 * revolutions, points)
    a = np.sqrt(spacing / 180.0)
    radii_1 = a**2 * theta_1
    radii_2 = -(a**2) * theta_2
    x_1, y_1 = pol_to_rect(radii_1, theta_1)
    x_1 = np.append(x_1, x_1[-1] + 0.03)
    y_1 = np.append(y_1, y_1[-1])

    p = gds.PolyPath(np.c_[x_1, y_1],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    x_2, y_2 = pol_to_rect(radii_2, theta_2)
    x_2 = np.append(x_2, x_2[-1])
    y_2 = np.append(y_2, y_2[-1] - 0.03)
    p = gds.PolyPath(np.c_[x_2, y_2],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)

    start_1 = (x_1[-1], y_1[-1])
    start_2 = (x_2[-1], y_2[-1])
    end_1 = (x_1[0], y_1[0])
    end_2 = (x_2[0], y_2[0])

    length_1 = np.sum(np.hypot(np.diff(x_1), np.diff(y_1)))
    length_2 = np.sum(np.hypot(np.diff(x_2), np.diff(y_2)))

    # Inner bend
    theta_inner = np.linspace(360.0 * inner_revs, 360.0 * inner_revs + 180.0,
                              50)
    radii_inner_1 = min_bend_radius
    radii_inner_2 = -min_bend_radius
    x_1, y_1 = pol_to_rect(radii_inner_1, theta_inner)
    x_1 -= end_1[0] / 2.0
    y_1 -= end_1[1] / 2.0
    x_1 = np.append(x_1, x_1[-1])
    y_1 = np.append(y_1, y_1[-1] - 0.03)
    p = gds.PolyPath(np.c_[x_1, y_1],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    x_2, y_2 = pol_to_rect(radii_inner_2, theta_inner)
    x_2 -= end_2[0] / 2.0
    y_2 -= end_2[1] / 2.0
    x_2 = np.append(x_2, x_2[-1])
    y_2 = np.append(y_2, y_2[-1] + 0.03)
    p = gds.PolyPath(np.c_[x_2, y_2],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    length_3 = np.sum(np.hypot(np.diff(x_2), np.diff(y_2)))

    # Output straight
    p, _, e = straight(wg_width,
                       radii_1[-1],
                       start_1,
                       layer=wg_layer,
                       datatype=wg_datatype)
    ps.append(p)

    # Outer bend
    theta_input = np.linspace(0.0, -90.0, 50)
    r_input = min_bend_radius * 2.0
    x_input, y_input = pol_to_rect(r_input, theta_input)
    x_input += start_2[0] - r_input
    y_input += start_1[1] + r_input
    s = (x_input[-1], y_input[-1])
    end_input = (x_input[0], y_input[0])
    x_input = np.append(x_input[0], x_input)
    y_input = np.append(y_input[0] + 0.03, y_input)
    x_input = np.append(x_input, x_input[-1] - 0.03)
    y_input = np.append(y_input, y_input[-1])
    p = gds.PolyPath(np.c_[x_input, y_input],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    length = start_2[1] - end_input[1]
    p, _, _ = straight(
        length,
        wg_width,
        (end_input[0] - wg_width / 2.0, end_input[1] + length / 2.0),
        layer=wg_layer,
        datatype=wg_datatype,
    )
    ps.append(p)

    length = length_1 + length_2 + length_3

    # Electrode ring
    # inner_radius = min_bend_radius * 2.
    # outer_radius = a**2 * theta_2[-1]
    # mid_radius = 0.5*(inner_radius + outer_radius)
    # thickness = outer_radius - mid_radius
    # r = gds.Round((0.,0.), outer_radius, inner_radius, layer=1, max_points=1000)

    ps = gds.fast_boolean(ps, None, "or")

    c = gf.Component()
    c.info.length = snap_to_grid(length)
    c.add_polygon(ps, layer=layer)

    c.add_port(
        name="o1",
        midpoint=(s[0], s[1]),
        orientation=180,
        layer=layer,
        width=wg_width,
    )
    c.add_port(
        name="o2",
        midpoint=(e[0], e[1]),
        orientation=180,
        layer=layer,
        width=wg_width,
    )
    return c
Ejemplo n.º 10
0
# width along is whole extension, or as a list, where each element is
# the width of the path at one point.  Our path will have width 0.5 in
# all points, except the last, where it will tapper up to 1.5.  More
# than 1 path can be defined in parallel as well (useful for buses).
# The distance between the paths work the same way as the width: it's
# either a constant number, or a list.  We create 5 parallel paths that
# are larger and further apart on the last point. The paths are put in
# layers 4 and 5. Since we have 5 paths, the list of layers will be
# run more than once, so the 5 paths will actually be in layers 4, 5, 4,
# 5, and 4.
points = [(20, 12), (24, 8), (24, 4), (24, -2)]
widths = [0.5] * (len(points) - 1) + [1.5]
distances = [0.8] * (len(points) - 1) + [2.4]
polypath = gdspy.PolyPath(points,
                          widths,
                          number_of_paths=5,
                          distance=distances,
                          layer=[4, 5])

# We can round the corners of any Polygon or PolygonSet with the fillet
# 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
Ejemplo n.º 11
0
def router(cell,
           fr_str,
           fr_ep,
           to_str,
           to_ep,
           width,
           bmul,
           grid_s=1,
           xr=False,
           yr=False,
           uniform_width=False,
           precision=0.001,
           pref='y',
           switch_pref=False,
           layer=0,
           debug=False,
           nop=21,
           dist_multi=2,
           pathmethod='poly',
           detect='native'):

    fr = fr_str.endpoints[fr_ep]
    to = to_str.endpoints[to_ep]

    border_s = bmul * grid_s
    box = [fr, to]

    # Make sure first box coord is always the top-left corner and add additional border points
    xs = [box[0][0], box[1][0]]
    ys = [box[0][1], box[1][1]]
    box = [[min(xs) - border_s, max(ys) + border_s],
           [max(xs) + border_s, min(ys) - border_s]]

    # Build list of gridpoints that are outside all structures in cell
    lxr = int((box[1][0] - box[0][0]) / grid_s) + 1
    lyr = int((box[0][1] - box[1][1]) / grid_s) + 1

    if type(xr) not in [list, np.ndarray]:
        xr = np.linspace(box[0][0], box[1][0], lxr)
    else:
        lxr = len(xr)

    if type(yr) not in [list, np.ndarray]:
        yr = np.linspace(box[0][1], box[1][1], lyr)
    else:
        lyr = len(yr)

    p = []
    p_d_to = []
    p_d_fr = []
    for y in yr:
        for x in xr:

            c = (x, y)
            p.append(c)

            # Compute squared Euclidean distance from to and fr coords for each gridpoint
            # For optimization we don't need to sqrt() since minimal in squared is minimal in sqrt
            dist_fr = (x - fr[0])**2 + (y - fr[1])**2
            dist_to = (x - to[0])**2 + (y - to[1])**2

            p_d_fr.append(dist_fr)
            p_d_to.append(dist_to)

    p_i = np.array(p)
    p_d_fr = np.array(p_d_fr)
    p_d_to = np.array(p_d_to)

    # Build list of points that are inside a structure
    cell_ref = gd.CellReference(cell)
    if detect == 'native':
        inside = np.array(gd.inside(p, cell_ref, precision=precision))
    elif detect == 'custom':
        inside = np.array(
            gtools.funcs.inside(p,
                                cell_ref,
                                dist=dist_multi * grid_s,
                                nop=nop,
                                precision=precision))
    else:
        raise ValueError(
            'Parameter \'detect\' is only allowed to have values [\'native\', \'custom\'], cannot continue'
        )

    p_d_fr_min = np.min(p_d_fr[np.argwhere(inside == False)])
    p_d_to_min = np.min(p_d_to[np.argwhere(inside == False)])

    # Get p_i index of starting values
    start_i = np.argwhere(p_d_fr == p_d_fr_min).tolist()
    end_i = np.argwhere(p_d_to == p_d_to_min).tolist()

    start_i = [item for sublist in start_i for item in sublist]
    end_i = [item for sublist in end_i for item in sublist]

    start = p_i[start_i]
    end = p_i[end_i]

    # Now start stepping from start to end, labelling all gridpoints accordingly by the number of steps required from starting point to reach it
    n = [0] * 4
    lp = len(p)
    p_g = [0] * lp
    path_found = False
    k = 0

    while not path_found and start_i:

        k += 1
        next_start_i = []

        if debug:
            print(start_i)

        for i in start_i:

            # Look up, down, left and right, store the index
            n = lookaround(i, lxr, pref=pref)

            # Check if any of the neighbouring points are not in a structure and not in p_g
            for nb in n:

                if nb in end_i:
                    path_found = True
                    p_g[nb] = k
                    final_index = nb

                    if debug:
                        # Visualize
                        circ = gd.Round(p[nb], 0.1, layer=10)
                        cell.add(circ)
                        txt = gd.Text(str(k), 0.5, p[nb], layer=11)
                        cell.add(txt)

                    break

# Point is out of bounds, marked as structure (< 0) or already has a step value (> 0)
                if nb < 0 or nb >= lp or p_g[nb] != 0 or (
                        i % lxr == 0 and nb % lxr == 1) or (i % lxr == 1
                                                            and nb % lxr == 0):
                    continue  # Skip this iteration

                if inside[nb]:
                    p_g[nb] = -1
                else:
                    p_g[nb] = k
                    next_start_i.append(nb)

                    if debug:
                        # Visualize
                        circ = gd.Round(p[nb], 0.1, layer=1)
                        cell.add(circ)
                        txt = gd.Text(str(k), 0.5, p[nb], layer=2)
                        cell.add(txt)

        start_i = copy.copy(next_start_i)

    # Routing ended, checking whether we succeeded
    if not path_found:
        print('>> ERROR: No existing route was found.')
        return False

    print('>> Found a route in ' + str(k) + ' steps.')

    # Backtrace path
    this_index = final_index
    backtraced = [to, p[final_index]]
    switched = False
    for this_k in range(k, -1, -1):

        # Change move preference after switch_pref moves
        if switch_pref and not switched and this_k < switch_pref * k:
            pref = 'x' if pref == 'y' else 'y'
            switched = True

        n = lookaround(this_index, lxr, pref=pref)
        for nb in n:
            if nb < lp and p_g[nb] == this_k:
                this_index = nb
                backtraced.append(p[nb])
                break

    backtraced.append(fr)

    if debug:
        print('>> Points of found route:')
        print(backtraced)

    # Generate list of widths for the route
    if not uniform_width:
        to_w = to_str.endpoint_dims[to_ep]
        fr_w = fr_str.endpoint_dims[fr_ep]
        ws = [to_w if to_w != None else width] * 2 + [width] * (
            len(backtraced) - 4) + [fr_w if fr_w != None else width] * 2
    else:
        ws = width

    # Create backtraced path
    if pathmethod == 'poly':
        r = gd.PolyPath(backtraced, ws, layer=layer)
    elif pathmethod == 'flex':
        r = gd.FlexPath(backtraced, ws, corners='smooth', layer=layer)
    else:
        raise ValueError(
            'Parameter \'pathmethod\' only has allowed values [\'poly\', \'flex\']'
        )

    ends = {'A': backtraced[0], 'B': backtraced[-1]}
    epsz = {
        'A': ws[0] if not uniform_width else width,
        'B': ws[-1] if not uniform_width else width
    }

    structure = gtools.classes.GDStructure(r, ends, epsz)

    # Connect to 'to' and 'from' structures
    fr_str.next['AUTOROUTE_A'] = structure
    to_str.next['AUTOROUTE_B'] = structure
    structure.prev['AUTOROUTE_A'] = fr_str
    structure.prev['AUTOROUTE_B'] = to_str

    return structure
Ejemplo n.º 12
0
def spiral_circular(
    length_delay,
    wg_width=0.5,
    spacing=3,
    min_bend_radius=5,
    points=1000,
    wg_layer=pp.LAYER.WG,
    wg_datatype=0,
):
    """ Returns a circular spiral

    .. plot::
        :include-source:

        import pp

        c = pp.c.spiral_circular(length_delay=1e3)
        pp.plotgds(c)

    """
    def pol_to_rect(radii, angles_deg):
        angles_rad = np.radians(angles_deg)
        z = radii * np.exp(1.0j * angles_rad)
        return z.real, z.imag

    ps = []

    # Estimate number of revolutions
    length_total = 0.0
    i = 0
    while length_total <= length_delay:
        length_total += 3.0 * np.pi * (min_bend_radius * 2.0 +
                                       (i + 0.5) * spacing)
        i += 1
    revolutions = i + 1

    # Long spiral
    inner_revs = min_bend_radius * 4.0 / (spacing * 4.0)
    theta_1 = np.linspace(360.0 * inner_revs, 360.0 * (revolutions - 1) + 270,
                          points)
    theta_2 = np.linspace(360.0 * inner_revs, 360.0 * revolutions, points)
    a = np.sqrt(spacing / 180.0)
    radii_1 = a**2 * theta_1
    radii_2 = -(a**2) * theta_2
    x_1, y_1 = pol_to_rect(radii_1, theta_1)
    x_1 = np.append(x_1, x_1[-1] + 0.03)
    y_1 = np.append(y_1, y_1[-1])
    p = gds.PolyPath(np.c_[x_1, y_1],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    x_2, y_2 = pol_to_rect(radii_2, theta_2)
    x_2 = np.append(x_2, x_2[-1])
    y_2 = np.append(y_2, y_2[-1] - 0.03)
    p = gds.PolyPath(np.c_[x_2, y_2],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)

    start_1 = (x_1[-1], y_1[-1])
    start_2 = (x_2[-1], y_2[-1])
    end_1 = (x_1[0], y_1[0])
    end_2 = (x_2[0], y_2[0])

    length_1 = np.sum(np.hypot(np.diff(x_1), np.diff(y_1)))
    length_2 = np.sum(np.hypot(np.diff(x_2), np.diff(y_2)))

    # Inner bend
    theta_inner = np.linspace(360.0 * inner_revs, 360.0 * inner_revs + 180.0,
                              50)
    radii_inner_1 = min_bend_radius
    radii_inner_2 = -min_bend_radius
    x_1, y_1 = pol_to_rect(radii_inner_1, theta_inner)
    x_1 -= end_1[0] / 2.0
    y_1 -= end_1[1] / 2.0
    x_1 = np.append(x_1, x_1[-1])
    y_1 = np.append(y_1, y_1[-1] - 0.03)
    p = gds.PolyPath(np.c_[x_1, y_1],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    x_2, y_2 = pol_to_rect(radii_inner_2, theta_inner)
    x_2 -= end_2[0] / 2.0
    y_2 -= end_2[1] / 2.0
    x_2 = np.append(x_2, x_2[-1])
    y_2 = np.append(y_2, y_2[-1] + 0.03)
    p = gds.PolyPath(np.c_[x_2, y_2],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    length_3 = np.sum(np.hypot(np.diff(x_2), np.diff(y_2)))

    # Output straight
    p, _, e = straight(wg_width,
                       radii_1[-1],
                       start_1,
                       layer=wg_layer,
                       datatype=wg_datatype)
    ps.append(p)

    # Outer bend
    theta_input = np.linspace(0.0, -90.0, 50)
    r_input = min_bend_radius * 2.0
    x_input, y_input = pol_to_rect(r_input, theta_input)
    x_input += start_2[0] - r_input
    y_input += start_1[1] + r_input
    s = (x_input[-1], y_input[-1])
    end_input = (x_input[0], y_input[0])
    x_input = np.append(x_input[0], x_input)
    y_input = np.append(y_input[0] + 0.03, y_input)
    x_input = np.append(x_input, x_input[-1] - 0.03)
    y_input = np.append(y_input, y_input[-1])
    p = gds.PolyPath(np.c_[x_input, y_input],
                     wg_width,
                     layer=wg_layer,
                     datatype=wg_datatype)
    ps.append(p)
    l = start_2[1] - end_input[1]
    p, _, _ = straight(
        l,
        wg_width,
        (end_input[0] - wg_width / 2.0, end_input[1] + l / 2.0),
        layer=wg_layer,
        datatype=wg_datatype,
    )
    ps.append(p)

    length = length_1 + length_2 + length_3

    # Electrode ring
    # inner_radius = min_bend_radius * 2.
    # outer_radius = a**2 * theta_2[-1]
    # mid_radius = 0.5*(inner_radius + outer_radius)
    # thickness = outer_radius - mid_radius
    # r = gds.Round((0.,0.), outer_radius, inner_radius, layer=1, max_points=1000)

    ps = gds.fast_boolean(ps, None, "or")
    """ component """
    c = pp.Component()
    c.add_polygon(ps, layer=wg_layer)

    c.add_port(
        name="W0",
        midpoint=(s[0], s[1]),
        orientation=180,
        layer=wg_layer,
        width=wg_width,
    )
    c.add_port(
        name="E0",
        midpoint=(e[0], e[1]),
        orientation=180,
        layer=wg_layer,
        width=wg_width,
    )
    c.length = length
    return c
Ejemplo n.º 13
0
def modified_hall_bar(width,
                      length_total=5,
                      length_leg=1,
                      length_xx=2,
                      leg_offset=0,
                      orientation=0,
                      leg_type='default',
                      reservoir_enable=False,
                      layer=1):
    """
    :param width: nanowire width
    :param length_total: left to right
    :param length_leg: each leg
    :param length_xx: between legs
    :param leg_offset: allows to move upper leg to the left and lower leg to the right a bit
    :param orientation: degrees. 0 = horizontal
    :param leg_type: 'default' or 'fishbone'
    :param reservoir_enable: bool
    :param layer: shapes on 1 by default
    :return: gdspy object
    """
    leg_type_checklist = {'fishbone', 'default'}
    if leg_type not in leg_type_checklist:
        print('Hall bar type must be in ' + str(leg_type_checklist))
        raise ValueError

    p = [(-length_total / 2, 0), (length_total / 2, 0)]
    if leg_type == 'fishbone':
        p1 = [(0, 0),
              (-length_leg * math.cos(math.pi / 3),
               length_leg * math.sin(math.pi / 3))]
    else:
        p1 = [(0, 0),
              (length_leg * math.cos(math.pi / 3),
               length_leg * math.sin(math.pi / 3))]
    p2 = [(0, 0),
          (-length_leg * math.cos(math.pi / 3),
           -length_leg * math.sin(math.pi / 3))]

    b = gp.PolyPath(p, width, layer=layer)
    leg1 = gp.PolyPath(p1, width, layer=layer).translate(-leg_offset / 2, 0)
    leg2 = gp.PolyPath(p2, width, layer=layer).translate(leg_offset / 2, 0)
    slash1 = gp.fast_boolean(leg1, leg2, "or",
                             layer=layer).translate(-length_xx / 2, 0)
    slash2 = gp.fast_boolean(leg1, leg2, "or",
                             layer=layer).translate(length_xx / 2, 0)
    h = gp.fast_boolean(slash1, slash2, "or", layer=layer)
    hb = gp.fast_boolean(h, b, "or", layer=layer)

    reservoir_width = 2
    reservoir_height = 0.5
    if reservoir_enable:
        hb = add_reservoir_to_shape(
            hb,
            reservoir_width,
            reservoir_height,
            position=(-(length_total + reservoir_width) / 2, 0))
        hb = add_reservoir_to_shape(
            hb,
            reservoir_width,
            reservoir_height,
            position=((length_total + reservoir_width) / 2, 0))

    angle_rad = orientation * math.pi / 180
    return hb.rotate(angle_rad)