Exemple #1
0
 def __init__(self,
              name,
              holecell,
              arrayaxes=((1, 0), (0, 1)),
              arrayperiods=(1, 1),
              excludepoly=None):
     self.Name = name
     self.Axes = arrayaxes
     self.Periods = arrayperiods
     self.holearray = gdspy.Cell(name)
     self.hole = holecell
     self.excludepoly = excludepoly
     if (len(numpy.array(holecell).shape) == 0):
         for i in range(self.Periods[0]):
             ax0pt = addtup((0, 0), scalartup(i, self.Axes[0]))
             for j in range(self.Periods[1]):
                 ax1pt = addtup((0, 0), scalartup(j, self.Axes[1]))
                 if (excludepoly == None) | (not gdspy.inside(
                     [addtup(ax0pt, ax1pt)], excludepoly)[0]):
                     refcell = gdspy.CellReference(holecell,
                                                   addtup(ax0pt, ax1pt))
                     self.holearray.add(refcell)
     elif (numpy.array(holecell).shape == arrayperiods):
         for i in range(self.Periods[0]):
             ax0pt = addtup((0, 0), scalartup(i, self.Axes[0]))
             for j in range(self.Periods[1]):
                 ax1pt = addtup((0, 0), scalartup(j, self.Axes[1]))
                 if (excludepoly == None) | (not gdspy.inside(
                     [addtup(ax0pt, ax1pt)], excludepoly)[0]):
                     refcell = gdspy.CellReference(holecell[i, j],
                                                   addtup(ax0pt, ax1pt))
                     self.holearray.add(refcell)
     else:
         raise ValueError(
             "Error in the holecell input! Not right dimention")
def _render_text(text,
                 size=None,
                 position=(0, 0),
                 font_prop=None,
                 tolerance=0.1):
    """This function is copied from https://gdspy.readthedocs.io/en/stable/gettingstarted.html#using-system-fonts"""
    path = TextPath(position, text, size=size, prop=font_prop)
    polys = []
    xmax = position[0]
    for points, code in path.iter_segments():
        if code == path.MOVETO:
            c = gdspy.Curve(*points, tolerance=tolerance)
        elif code == path.LINETO:
            c.L(*points)
        elif code == path.CURVE3:
            c.Q(*points)
        elif code == path.CURVE4:
            c.C(*points)
        elif code == path.CLOSEPOLY:
            poly = c.get_points()
            if poly.size > 0:
                if poly[:, 0].min() < xmax:
                    i = len(polys) - 1
                    while i >= 0:
                        if gdspy.inside(poly[:1], [polys[i]],
                                        precision=0.1 * tolerance)[0]:
                            p = polys.pop(i)
                            poly = gdspy.boolean(
                                [p],
                                [poly],
                                "xor",
                                precision=0.1 * tolerance,
                                max_points=0,
                            ).polygons[0]
                            break
                        elif gdspy.inside(polys[i][:1], [poly],
                                          precision=0.1 * tolerance)[0]:
                            p = polys.pop(i)
                            poly = gdspy.boolean(
                                [p],
                                [poly],
                                "xor",
                                precision=0.1 * tolerance,
                                max_points=0,
                            ).polygons[0]
                        i -= 1
                xmax = max(xmax, poly[:, 0].max())
                polys.append(poly)
    return polys
Exemple #3
0
def test_inside():
    polygons = [
        gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180),
        gdspy.Rectangle((20, -10), (40, 10)),
        gdspy.Rectangle((-10, 0), (10, 20))
    ]
    assert gdspy.inside([(0, 0)], polygons) == (True, )
    assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == \
        (True, False, True, False)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'any') == (True, False, True)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'all') == (False, False, True)
Exemple #4
0
def test_inside():
    polygons = [
        gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180),
        gdspy.Rectangle((20, -10), (40, 10)),
        gdspy.Rectangle((-10, 0), (10, 20))
    ]
    assert gdspy.inside([(0, 0)], polygons) == (True, )
    assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == \
        (True, False, True, False)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'any') == (True, False, True)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'all') == (False, False, True)
Exemple #5
0
def render_text(text,
                size=None,
                position=(0, 0),
                font_prop=None,
                tolerance=0.1):
    path = TextPath(position, text, size=size, prop=font_prop)
    polys = []
    xmax = position[0]
    for points, code in path.iter_segments():
        if code == path.MOVETO:
            c = gdspy.Curve(*points, tolerance=tolerance)
        elif code == path.LINETO:
            c.L(*points)
        elif code == path.CURVE3:
            c.Q(*points)
        elif code == path.CURVE4:
            c.C(*points)
        elif code == path.CLOSEPOLY:
            poly = c.get_points()
            if poly.size > 0:
                if poly[:, 0].min() < xmax:
                    i = len(polys) - 1
                    while i >= 0:
                        if gdspy.inside(poly[:1], [polys[i]],
                                        precision=0.1 * tolerance)[0]:
                            p = polys.pop(i)
                            poly = gdspy.boolean(
                                [p],
                                [poly],
                                "xor",
                                precision=0.1 * tolerance,
                                max_points=0,
                            ).polygons[0]
                            break
                        elif gdspy.inside(polys[i][:1], [poly],
                                          precision=0.1 * tolerance)[0]:
                            p = polys.pop(i)
                            poly = gdspy.boolean(
                                [p],
                                [poly],
                                "xor",
                                precision=0.1 * tolerance,
                                max_points=0,
                            ).polygons[0]
                        i -= 1
                xmax = max(xmax, poly[:, 0].max())
                polys.append(poly)
    return polys
Exemple #6
0
def test_inside():
    polygons = [
        gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180),
        gdspy.Rectangle((20, -10), (40, 10)).polygons[0],
        gdspy.CellReference(
            gdspy.Cell("X").add(gdspy.Rectangle((-10, 0), (10, 20)))),
    ]
    assert gdspy.inside([(0, 0)], polygons[0]) == (False, )
    assert gdspy.inside([(0, 0)], polygons[2]) == (True, )
    assert gdspy.inside([(0, 0)], polygons) == (True, )
    assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == (
        True,
        False,
        True,
        False,
    )
    assert gdspy.inside(
        [[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1),
                                               (0, 30)], [(0, 0), (30, 0)]],
        polygons,
        "any",
    ) == (True, False, True)
    assert gdspy.inside(
        [[(0, 0), (0, 30), (30, 0), (0, -1)], [(0, -1),
                                               (0, 30)], [(0, 0), (30, 0)]],
        polygons,
        "all",
    ) == (False, False, True)
Exemple #7
0
def bench_gdspy():
    r = gdspy.Rectangle((0, 0), (20, 10))
    pts = [[(1, 1), (-1, -1)], [(2, 2), (-2, 2), (2, -2)], [(5, 5), (10, 5)],
           [(-1, -1), (-2, -2)], [(2, 3)]]
    assert gdspy.inside(pts[0], r) == (True, False)
    assert gdspy.inside(pts[1], r) == (True, False, False)
    assert gdspy.inside(pts[1:2], r, "any") == (True, )
    assert gdspy.inside(pts[1:2], r, "all") == (False, )
    assert gdspy.inside(pts[4], r) == (True, )
    assert gdspy.inside(pts, r, "any") == (True, True, True, False, True)
    assert gdspy.inside(pts, r, "all") == (False, False, True, False, True)
Exemple #8
0
def inside(points, cellref, dist, nop = 3, precision = 0.001):
    #=====================
    # Save cell to a file \\
    #=========================================================================
    # Arguments:    points      :   list of points to check                 ||
    #               cellref     :   gdspy cell reference object             ||
    #               dist        :   distance from points to search          ||
    #               nop         :   number of probe points within dist      ||
    #               precision   :   gdspy.inside precision parameter        ||
    #=========================================================================
    # Force uneven
    if nop % 2 == 0:
        nop += 1

    search_ps = []
    for p in points:
        px = np.linspace(p[0] - dist/2, p[0] + dist/2, nop)
        py = np.linspace(p[1] - dist/2, p[1] + dist/2, nop)
        search_ps.append([[i, j] for i in px for j in py])

    return gd.inside(search_ps, cellref, precision = precision)
Exemple #9
0
def cut_out_holes(polygons, layer=0, datatype=0):
    top_level_polygons = []
    used_polygons = set()
    for polygon_ext in polygons:
        polygons_to_cut = [polygon_ext]
        for polygon_int in polygons:
            if polygon_ext is polygon_int:
                continue
            # if g.inside([polygon_ext], g.Polygon(polygon_int))[0]:
            if g.inside([polygon_int], g.Polygon(polygon_ext))[0]:
                polygons_to_cut.append(polygon_int)
                used_polygons.add(make_hashable(polygon_int))
        if len(polygons_to_cut) >= 2:
            used_polygons.add(make_hashable(
                polygons_to_cut[0]))  # don't add an un-cut exterior
            top_level_polygons.append(polygons_to_cut)
    for polygon in polygons:
        if make_hashable(polygon) not in used_polygons:
            top_level_polygons.append([polygon])
    result = [
        reduce(partial(cut_out_hole, layer=layer, datatype=datatype),
               polygons_to_cut) for polygons_to_cut in top_level_polygons
    ]
    return g.PolygonSet(result, layer=layer, datatype=datatype)
Exemple #10
0
def test_inside():
    gdspy.current_library = gdspy.GdsLibrary()
    polygons = [
        gdspy.Round((0, 0), 10, inner_radius=5, number_of_points=180),
        gdspy.Rectangle((20, -10), (40, 10)).polygons[0],
        gdspy.CellReference(
            gdspy.Cell('X').add(gdspy.Rectangle((-10, 0), (10, 20)))),
    ]
    assert gdspy.inside([(0, 0)], polygons[0]) == (False, )
    assert gdspy.inside([(0, 0)], polygons[2]) == (True, )
    assert gdspy.inside([(0, 0)], polygons) == (True, )
    assert gdspy.inside([(0, 0), (0, 30), (30, 0), (0, -1)], polygons) == \
        (True, False, True, False)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'any') == (True, False, True)
    assert gdspy.inside([[(0, 0), (0, 30), (30, 0),
                          (0, -1)], [(0, -1), (0, 30)], [(0, 0), (30, 0)]],
                        polygons, 'all') == (False, False, True)
Exemple #11
0
    def __init__(self,
                 cell,
                 grid_size,
                 buffer=None,
                 layers=None,
                 precision=0.001):

        start_time = time.time()

        self.grid_size = grid_size
        if layers is None:
            layers = list(cell.get_layers())
        if not isinstance(layers, list):
            layers = [layers]
        if buffer is None:
            buffer = grid_size / 2

        bounding_box = cell.get_bounding_box()
        x_length = int(
            (bounding_box[1][0] - bounding_box[0][0] + 2 * grid_size) /
            grid_size) + 1
        y_length = int(
            (bounding_box[1][1] - bounding_box[0][1] + 2 * grid_size) /
            grid_size) + 1
        out_string = '-- Constructing map with ' + str(int(
            x_length * y_length)) + ' (' + str(int(x_length)) + ' x ' + str(
                int(y_length)) + ') entries'
        print(out_string, end=(7 - len(out_string) // 8) * '\t', flush=True)

        x_linspace = np.linspace(bounding_box[0][0] - grid_size,
                                 bounding_box[1][0] + grid_size, x_length)
        y_linspace = np.flip(
            np.linspace(bounding_box[0][1] - grid_size,
                        bounding_box[1][1] + grid_size, y_length))
        x_array, y_array = np.meshgrid(x_linspace, y_linspace)
        xy_array = np.array(list(zip(x_array.ravel(),
                                     y_array.ravel()))).reshape(
                                         *x_array.shape, 2)

        self.mask = np.zeros((y_length, x_length))

        self.copy_cell = cell.copy(cell.name + "_copy", deep_copy=True)
        self.copy_cell.remove_polygons(
            lambda pts, layer, datatype: layer not in layers)
        self.copy_polygonset = gp.offset(self.copy_cell.get_polygons(),
                                         distance=buffer)
        map_gdspy = np.array(
            gp.inside(np.array(xy_array).reshape(-1, 2),
                      self.copy_polygonset,
                      precision=precision)).reshape((y_length, x_length))

        for i in range(y_length):
            for j in range(x_length):
                if not map_gdspy[i][j]:
                    if self.mask[i][j] != 1:
                        self.mask[i][j] = 0
                else:
                    try:
                        self.mask[i][j] = self.mask[i - 1][j] = self.mask[
                            i + 1][j] = self.mask[i][j -
                                                     1] = self.mask[i][j +
                                                                       1] = 1
                    except:
                        pass

        elapsed_time = round(time.time() - start_time, 3)
        print('| Finished after ' + str(elapsed_time) + ' s --')

        self.x_length = x_length
        self.y_length = y_length
        self.x_linspace = x_linspace
        self.y_linspace = y_linspace
        self.x_array = x_array
        self.y_array = y_array
        self.xy_array = xy_array
Exemple #12
0
def gen_gds(poly_coords: List[np.ndarray],
            filepath: str,
            extra_structures: List[np.ndarray] = None,
            deembed: bool = True) -> None:
    """Generate GDS given a list of polygon coordinates.

    Output GDS has units of microns and precision in nanometers.

    Args:
        poly_coords: List of polygon coordinates. Elements of list are
            n x 2 numpy.ndarrays. Assumes coordinates in nanometers.
        filepath: Name of the filepath to output gds file.
        extra_structures: List of polygons to be added to the gds that are
            not part of the levelset function.
        deembed: Boolean to control if polygon deembeding will occur or not.
    """
    poly_cell = gdspy.Cell("POLYGONS", exclude_from_current=True)

    test_points = []
    gds_polygons = []

    # Convert polygon coordinates from nanometers to microns since
    # output is in microns.
    poly_coords = [np.array(poly) / NM_PER_UM for poly in poly_coords]

    for polygon in poly_coords:
        test_points.append(tuple(polygon[0]))
        gds_polygons.append(gdspy.Polygon(polygon, 0))

    if deembed:

        containment_mx = []
        for polygon in gds_polygons:
            containment_mx.append(gdspy.inside(test_points, [polygon]))

        # Subtract by identity matrix since polygon_i trivially contains
        # polygon_i.
        containment_mx = np.array(containment_mx) - np.eye(len(gds_polygons))
        # overlap_list[i] tells how many polygons are contained in polygon i.
        overlap_list = np.sum(containment_mx, axis=1)

        overlap_num = 0
        while sum(overlap_list) != 0:

            overlap_num = overlap_num + 1

            # We loop until there are no longer any more polygons of a specific
            # overlap number before going to the next overlap number.
            #
            # The reasoning for this is as we begin to delete polygons,
            # the overlap number changes and so polygons which were of
            # overlap_num > 1, may become polygons of overlap_num = 1.
            #
            # np.where(overlap_list==overlap_num)[0].size is how we see if
            # any polygons satisfy the current overlap number.

            target_polys = np.where(overlap_list == overlap_num)[0]
            while target_polys.size != 0:

                # We iterate through each polygon in our polygon list until no
                # polygon satisfies the current overlap number.
                for i in target_polys[::-1]:
                    containment_list = np.nonzero(containment_mx[i, :])[0]
                    for j in containment_list[::-1]:
                        # The boolean 'not' operation is performed here.
                        # We replace polygon[i] of the two polygons with the
                        # result of the operation and delete polygon[j].
                        gds_polygons[i] = gdspy.fast_boolean(gds_polygons[i],
                                                             gds_polygons[j],
                                                             'not',
                                                             layer=0)
                        gds_polygons[j] = None
                        test_points[j] = None

                for k in range(len(gds_polygons) - 1, -1, -1):
                    if gds_polygons[k] is None:
                        del gds_polygons[k]
                        del test_points[k]

                containment_mx = []
                for polygon in gds_polygons:
                    containment_mx.append(gdspy.inside(test_points, [polygon]))

                containment_mx = np.array(containment_mx) - np.eye(
                    len(gds_polygons))
                overlap_list = np.sum(containment_mx, axis=1)

                target_polys = np.where(overlap_list == overlap_num)[0]

    for polygon in gds_polygons:
        poly_cell.add(polygon)

    if extra_structures is not None:
        for extra_polygon in extra_structures:
            poly_cell.add(gdspy.Polygon(extra_polygon, 0))

    gdspy.write_gds(filepath, cells=[poly_cell], unit=1.0e-6, precision=1.0e-9)
Exemple #13
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
Exemple #14
0
def bench_gdspy():
    gdspy.inside(points, gdspy_ring)
    gdspy.inside([points], gdspy_ring, "any")
    gdspy.inside([points], gdspy_ring, "all")
    gdspy.inside(points, [gdspy_ring, gdspy_circle])
    gdspy.inside([points], [gdspy_ring, gdspy_circle], "any")
    gdspy.inside([points], [gdspy_ring, gdspy_circle], "all")
def main():

    # load file
    comsol_filename = "fourQ_test_pattern_cell_divide.java"
    parser = cp.comsol_parser()
    parser.load(comsol_filename)
    
    # show info
    #parser.ls_g_params()
    #parser.ls_geom()
    #parser.ls_objs("wp2")

    # change_paramter
    ## parser.g_params['read_D_pad'] = '0.660[mm]'

    # change geometric object
    parser.activate_geom_obj('wp2', ['c15', 'c16', 'c18', 'c17'], False)  # c15-18: positioning via
    parser.activate_geom_obj('wp2', ['c8'], False)  # c8: center via
    #print (parser.get_geom_obj('wp2', 'c15').__dict__)


    ## TiN pattern
    dry_etch_layer = 11
    cell_qc = gdspy.Cell('Qubit_Coplanar')
    poly_q = parser.export('wp1', layer=11, n_points_for_circle=256)
    poly_c = parser.export('wp5', layer=11, n_points_for_circle=128)
    poly_qc = gdspy.boolean(poly_q, poly_c, 'or', max_points=0, layer=dry_etch_layer)  ## disable max_points check


    ## JJ
    cell_JJ = gdspy.Cell('JJ')
    JJ_polys = generate_JJ()
    cell_JJ.add(JJ_polys)

    q_r_outer_hole = 300
    q_r_inner = 95
    q_gap = q_r_inner + (q_r_outer_hole - q_r_inner)/2
    q_dist = 2400

    p_JJ0 = (-q_dist/2+q_gap/np.sqrt(2), q_dist/2-q_gap/np.sqrt(2))
    p_JJ1 = (q_dist/2-q_gap/np.sqrt(2), q_dist/2-q_gap/np.sqrt(2))
    p_JJ2 = (-q_dist/2+q_gap/np.sqrt(2), -q_dist/2+q_gap/np.sqrt(2))
    p_JJ3 = (q_dist/2-q_gap/np.sqrt(2), -q_dist/2+q_gap/np.sqrt(2))
    p_JJ_list = [p_JJ0, p_JJ1, p_JJ2, p_JJ3]

    JJ_list = map(lambda x: gdspy.CellReference(cell_JJ, x), p_JJ_list)
    cell_qc.add(JJ_list)
    

    ## hook for JJ
    gap_for_JJ = 90/np.sqrt(2)
    hook_path_base = gdspy.FlexPath([(0, 0), (0, -4.5), (-3.5, -4.5)], 3, layer=dry_etch_layer)
    hook_path_base.translate(5, gap_for_JJ/2)

    hook_path_list = map(lambda x: gdspy.copy(hook_path_base).translate(*x), p_JJ_list)
    hook_path_union = None
    for path in hook_path_list:
        hook_path_union = gdspy.boolean(hook_path_union, path, 'or', max_points=0, layer=dry_etch_layer)

    #poly_qc_hook = gdspy.boolean(poly_qc, hook_path_union, 'not', max_points=0, layer=dry_etch_layer)
    #cell_qc.add(poly_qc_hook)
    cell_qc.add(hook_path_union)
    cell_qc.add(poly_c)
    cell_qc.add(poly_q)


   ## mask
    mask_layer = 100

    shift = 20

    cell_mask_shifted = gdspy.Cell('Shifted Pattern Mask')

    polyset_shifted = cp.gdspy_shift_size(poly_qc, shift ,layer=mask_layer)
    unit_size = 4000

    rect_fill_lr = gdspy.Path(150, (-unit_size/2, 0))
    rect_fill_lr.segment(unit_size, '+x', layer=mask_layer)
    rect_fill_bt = gdspy.Path(150, (0, -unit_size/2))
    rect_fill_bt.segment(unit_size, '+y', layer=mask_layer)

    rect_list = [gdspy.copy(rect_fill_lr).translate(0, -q_dist/2), gdspy.copy(rect_fill_lr).translate(0, q_dist/2),
                 gdspy.copy(rect_fill_bt).translate(-q_dist/2, 0), gdspy.copy(rect_fill_bt).translate(q_dist/2, 0)]

    rect_union = None
    for rect in rect_list:
        rect_union = gdspy.boolean(rect_union, rect, 'or', max_points=0, layer=mask_layer)

    mask_shifted = gdspy.boolean(polyset_shifted, rect_union, 'or', max_points=0, layer=mask_layer)

    cell_mask_shifted.add(mask_shifted)


    ## Via
    via_layer = 13
    top_Al_layer = 8
    bottom_Al_layer = 9

    cell_via = gdspy.Cell('Via')
    via_poly = parser.export('wp2', layer=via_layer)
    via_poly_Al_t = cp.gdspy_shift_size(via_poly, 35, layer=top_Al_layer)
    via_poly_Al_b = cp.gdspy_shift_size(via_poly, 20, layer=bottom_Al_layer)

    via_poly_Al_t = gdspy.boolean(via_poly_Al_t, mask_shifted, 'not', layer=top_Al_layer)   ## mask the top pattern

    cell_via.add([via_poly, via_poly_Al_t, via_poly_Al_b])

    ### center via
    center_via = gdspy.Round((0, 0), 75, layer=via_layer)
    center_via_Al_t = gdspy.Round((0, 0), 95, layer=top_Al_layer)
    center_via_Al_b = gdspy.Round((0, 0), 95, layer=bottom_Al_layer)
    cell_via.add([center_via, center_via_Al_t, center_via_Al_b])

    ### positioning via
    pos_via_dist = 7400
    pos_via_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 520, layer=via_layer)
    pos_via_lt_Al_t = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 620, layer=top_Al_layer)
    pos_via_lt_Al_b = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 600, layer=bottom_Al_layer)
    pos_via_rb = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 520, layer=via_layer)
    pos_via_rb_Al_t = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 620, layer=top_Al_layer)
    pos_via_rb_Al_b = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 600, layer=bottom_Al_layer)
    cell_via.add([pos_via_lt, pos_via_lt_Al_t, pos_via_lt_Al_b, pos_via_rb, pos_via_rb_Al_t, pos_via_rb_Al_b])

    ### tiling Via
    cell_single_via = gdspy.Cell('single_via')
    via_s = gdspy.Round((0, 0), 75, layer=via_layer)
    via_s_Al_t = gdspy.Round((0, 0), 110, layer=top_Al_layer)
    via_s_Al_b = gdspy.Round((0, 0), 95, layer=bottom_Al_layer)
    cell_single_via.add([via_s, via_s_Al_t, via_s_Al_b])

    tiled_via_list = tile_cell(cell_single_via, (-4500, -4500), (4500, 4500), 500)

    cell_mask_via = gdspy.Cell('Via Mask')

    rect_mask_lr = gdspy.Rectangle((-2300, -400), (2300, 400), layer=mask_layer)
    rect_mask_bt = gdspy.Rectangle((-400, -2300), (400, 2300), layer=mask_layer)
    rect_mask_c =  gdspy.Rectangle((-1200, -1200), (1200, 1200), layer=mask_layer)
    rect_mask_lr1 = gdspy.copy(rect_mask_lr).translate(0, -1200)
    rect_mask_lr2 = gdspy.copy(rect_mask_lr).translate(0, 1200)
    rect_mask_bt1 = gdspy.copy(rect_mask_bt).translate(-1200, 0)
    rect_mask_bt2 = gdspy.copy(rect_mask_bt).translate(1200, 0)
    pos_via_mask_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 600, layer=mask_layer)
    pos_via_mask_br = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 600, layer=mask_layer)

    cell_mask_via.add([rect_mask_lr1, rect_mask_lr2, rect_mask_bt1, rect_mask_bt2, rect_mask_c, pos_via_mask_lt, pos_via_mask_br])

    for via_ref in tiled_via_list:
        if np.any(gdspy.inside([via_ref.origin], cell_mask_via.polygons)):
            pass
        else:
            cell_via.add(via_ref)

 
    generate_flux_trap = False

    if generate_flux_trap:
        # Flux trap
        cell_single_flux_trap = gdspy.Cell('single_flux_trap')

        trap_size = np.array([5, 5])
        cell_single_flux_trap.add(gdspy.Rectangle(-trap_size/2, trap_size/2, layer=dry_etch_layer))

        cell_flux_trap = gdspy.Cell('Flux trap')
        flux_trap_list = tile_cell(cell_single_flux_trap, (-2500, -2500), (2500, 2500), 20)

        cell_mask_flux_trap = gdspy.Cell("Mask for flux trap")

        mask_flux_trap_on_via = cp.gdspy_shift_size(via_poly, 40, layer=mask_layer)
        mask_pos_via_lt = gdspy.Round((-pos_via_dist/2, pos_via_dist/2), 630, layer=mask_layer)
        mask_pos_via_rb = gdspy.Round((pos_via_dist/2, -pos_via_dist/2), 630, layer=mask_layer)
        cell_mask_flux_trap.add([mask_shifted, mask_flux_trap_on_via, mask_pos_via_lt, mask_pos_via_rb])


        ###
        for flux_trap_ref in flux_trap_list:
            if np.any(gdspy.inside([flux_trap_ref.origin], cell_mask_flux_trap.polygons)):
                pass
            else:
                cell_flux_trap.add(flux_trap_ref)


    # Top
    total_cell = gdspy.Cell('4Q total pattern')
    total_cell.add(gdspy.CellReference(cell_qc))
    total_cell.add(gdspy.CellReference(cell_via))

    if generate_flux_trap:
        total_cell.add(gdspy.CellReference(cell_flux_trap))

    #gdspy.LayoutViewer()

    gdspy.write_gds("4Q_pattern.gds", unit=1.0e-6, precision=1.0e-9)

    return 0