Esempio n. 1
0
def tag_faces(grids):
    # Assume only one grid of highest dimension
    assert len(grids[0]) == 1, 'Must be exactly'\
        '1 grid of dim: ' + str(len(grids))
    g_h = grids[0][0]
    bnd_faces = g_h.get_boundary_faces()
    g_h.add_face_tag(bnd_faces, FaceTag.DOMAIN_BOUNDARY)
    bnd_nodes, _, _ = sps.find(g_h.face_nodes[:, bnd_faces])
    bnd_nodes = np.unique(bnd_nodes)
    for g_dim in grids[1:-1]:
        for g in g_dim:
            # We find the global nodes of all boundary faces
            bnd_faces_l = g.get_boundary_faces()
            indptr = g.face_nodes.indptr
            fn_loc = mcolon.mcolon(indptr[bnd_faces_l],
                                   indptr[bnd_faces_l + 1] - 1)
            nodes_loc = g.face_nodes.indices[fn_loc]
            # Convert to global numbering
            nodes_glb = g.global_point_ind[nodes_loc]
            # We then tag each node as a tip node if it is not a global
            # boundary node
            is_tip = np.in1d(nodes_glb, bnd_nodes, invert=True)
            # We reshape the nodes such that each column equals the nodes of
            # one face. If a face only contains global boundary nodes, the
            # local face is also a boundary face. Otherwise, we add a TIP tag.
            nodes_per_face = find_nodes_per_face(g)
            is_tip = np.any(is_tip.reshape((nodes_per_face, bnd_faces_l.size),
                                           order='F'),
                            axis=0)
            g.add_face_tag(bnd_faces_l[is_tip], FaceTag.TIP)
            g.add_face_tag(bnd_faces_l[is_tip == False],
                           FaceTag.DOMAIN_BOUNDARY)
Esempio n. 2
0
def sort_sub_list(indices, indptr):
    ix = np.zeros(indices.size, dtype=int)
    for i in range(indptr.size - 1):
        sub_ind = mcolon(indptr[i], indptr[i + 1] - 1)
        loc_ix = np.argsort(indices[sub_ind])
        ix[sub_ind] = loc_ix + indptr[i]
    indices = indices[ix]
    iv = np.zeros(indices.size, dtype=int)
    iv[ix] = np.arange(indices.size)
    return indices, iv
Esempio n. 3
0
def duplicate_faces(gh, face_cells):
    """
    Duplicate all faces that are connected to a lower-dim cell

    Parameters
    ----------
    gh         - Higher-dim grid
    face_cells - A list of connection matrices. Each matrix gives
                 the mapping from the cells of a lower-dim grid
                 to the faces of the higher diim grid.
    """
    # We find the indices of the higher-dim faces to be duplicated.
    # Each of these faces are duplicated, and the duplication is
    # attached to the same nodes. We do not attach the faces to
    # any cells as this connection will have to be undone later
    # anyway.
    _, frac_id, _ = sps.find(face_cells)
    frac_id = np.unique(frac_id)
    node_start = gh.face_nodes.indptr[frac_id]
    node_end = gh.face_nodes.indptr[frac_id + 1]
    nodes = gh.face_nodes.indices[mcolon(node_start, node_end - 1)]
    added_node_pos = np.cumsum(node_end - node_start) + \
        gh.face_nodes.indptr[-1]
    assert(added_node_pos.size == frac_id.size)
    assert(added_node_pos[-1] - gh.face_nodes.indptr[-1] == nodes.size)
    gh.face_nodes.indices = np.hstack((gh.face_nodes.indices, nodes))
    gh.face_nodes.indptr = np.hstack((gh.face_nodes.indptr, added_node_pos))
    gh.face_nodes.data = np.hstack((gh.face_nodes.data,
                                    np.ones(nodes.size, dtype=bool)))
    gh.face_nodes._shape = (
        gh.num_nodes, gh.face_nodes.shape[1] + frac_id.size)
    assert(gh.face_nodes.indices.size == gh.face_nodes.indptr[-1])

    node_start = gh.face_nodes.indptr[frac_id]
    node_end = gh.face_nodes.indptr[frac_id + 1]

    #frac_nodes = gh.face_nodes[:, frac_id]

    #gh.face_nodes = sps.hstack((gh.face_nodes, frac_nodes))
    # We also copy the attributes of the original faces.
    gh.num_faces += frac_id.size
    gh.face_normals = np.hstack(
        (gh.face_normals, gh.face_normals[:, frac_id]))
    gh.face_areas = np.append(gh.face_areas, gh.face_areas[frac_id])
    gh.face_centers = np.hstack(
        (gh.face_centers, gh.face_centers[:, frac_id]))

    # Not sure if this still does the correct thing. Might have to
    # send in a logical array instead of frac_id.
    gh.add_face_tag(frac_id, FaceTag.FRACTURE | FaceTag.BOUNDARY)
    gh.face_tags = np.append(gh.face_tags, gh.face_tags[frac_id])

    return frac_id
Esempio n. 4
0
    def get_boundary_nodes(self):
        """
        Get nodes on the boundary

        Returns:
            np.ndarray (1d), index of nodes on the boundary

        """
        b_faces = self.get_boundary_faces()
        first = self.face_nodes.indptr[b_faces]
        second = self.face_nodes.indptr[b_faces + 1] - 1
        return np.unique(self.face_nodes.indices[mcolon.mcolon(first, second)])
Esempio n. 5
0
def block_diag_index(m, n=None):
    """
    Get row and column indices for block diagonal matrix

    This is intended as the equivalent of the corresponding method in MRST.

    Examples:
    >>> m = np.array([2, 3])
    >>> n = np.array([1, 2])
    >>> i, j = block_diag_index(m, n)
    >>> i, j
    (array([0, 1, 2, 3, 4, 2, 3, 4]), array([0, 0, 1, 1, 1, 2, 2, 2]))
    >>> a = np.array([1, 3])
    >>> i, j = block_diag_index(a)
    >>> i, j
    (array([0, 1, 2, 3, 1, 2, 3, 1, 2, 3]), array([0, 1, 1, 1, 2, 2, 2, 3, 3, 3]))

    Parameters:
        m - ndarray, dimension 1
        n - ndarray, dimension 1, defaults to m

    """
    if n is None:
        n = m

    start = np.hstack((np.zeros(1, dtype='int'), m))
    pos = np.cumsum(start)
    p1 = pos[0:-1]
    p2 = pos[1:]-1
    p1_full = matrix_compression.rldecode(p1, n)
    p2_full = matrix_compression.rldecode(p2, n)

    i = mcolon.mcolon(p1_full, p2_full)
    sumn = np.arange(np.sum(n))
    m_n_full = matrix_compression.rldecode(m, n)
    j = matrix_compression.rldecode(sumn, m_n_full)
    return i, j
Esempio n. 6
0
def grid_sequence_fixed_lines(basedim,
                              num_levels,
                              grid_type,
                              pert=0,
                              ref_rate=2,
                              domain=None,
                              subdom_func=None):
    dim = basedim.shape[0]

    if domain is None:
        domain = np.ones(dim)

    for iter1 in range(num_levels):
        nx = basedim * ref_rate**iter1
        g = make_grid(grid_type, nx, domain, dim)

        if pert > 0:
            g.compute_geometry()
            old_nodes = g.nodes.copy()
            dx = np.max(domain / nx)
            g = perturb(g, pert, dx)
            if subdom_func is not None:
                # Characteristic function for all cell centers
                xc = g.cell_centers
                chi = subdom_func(xc[0], xc[1])
                #
                chi_face = np.abs(g.cell_faces * chi)
                bnd_face = np.argwhere(chi_face > 0).squeeze(1)
                node_ptr = g.face_nodes.indptr
                node_ind = g.face_nodes.indices
                bnd_nodes = node_ind[mcolon.mcolon(node_ptr[bnd_face],
                                                   node_ptr[bnd_face + 1] - 1)]
                g.nodes[:, bnd_nodes] = old_nodes[:, bnd_nodes]

        g.compute_geometry()
        yield g
Esempio n. 7
0
def test_mcolon_one_missing():
    a = np.array([1, 2])
    b = np.array([2, 1])
    c = mcolon.mcolon(a, b)
    assert np.all((c - np.array([1, 2])) == 0)
Esempio n. 8
0
def test_mcolon_simple():
    a = np.array([1, 2])
    b = np.array([2, 3])
    c = mcolon.mcolon(a, b)
    assert np.all((c - np.array([1, 2, 2, 3])) == 0)
Esempio n. 9
0
def create_partition(A, cdepth=2, epsilon=0.25, seeds=None):
    """
    Create the partition based on an input matrix using the algebraic multigrid
    method coarse/fine-splittings based on direct couplings. The standard values
    for cdepth and epsilon are taken from the following reference.

    For more information see: U. Trottenberg, C. W. Oosterlee, and A. Schuller.
    Multigrid. Academic press, 2000.

    Parameters
    ----------
    A: sparse matrix used for the agglomeration
    cdepth: the greather is the more intense the aggregation will be, e.g. less
        cells if it is used combined with generate_coarse_grid
    epsilon: weight for the off-diagonal entries to define the "strong
        negatively cupling"
    seeds: (optional) to define a-priori coarse cells

    Returns
    -------
    out: agglomeration indices

    How to use
    ----------
    part = create_partition(tpfa_matrix(g))
    g = generate_coarse_grid(g, part)

    """

    if A.size == 0: return np.zeros(1)
    Nc = A.shape[0]

    # For each node, which other nodes are strongly connected to it
    ST = sps.lil_matrix((Nc, Nc), dtype=np.bool)

    # In the first instance, all cells are strongly connected to each other
    At = A.T

    for i in np.arange(Nc):
        ci, _, vals = sps.find(At[:, i])
        neg = vals < 0.
        nvals = vals[neg]
        nci = ci[neg]
        minId = np.argmin(nvals)
        ind = -nvals >= epsilon * np.abs(nvals[minId])
        ST[nci[ind], i] = True

    # Temporary field, will store connections of depth 1
    STold = ST.copy()
    for _ in np.arange(2, cdepth + 1):
        for j in np.arange(Nc):
            rowj = np.array(STold.rows[j])
            row = np.hstack([STold.rows[r] for r in rowj])
            ST[j, np.concatenate((rowj, row))] = True
        STold = ST.copy()

    del STold

    ST.setdiag(False)
    lmbda = np.array([len(s) for s in ST.rows])

    # Define coarse nodes
    candidate = np.ones(Nc, dtype=np.bool)
    is_fine = np.zeros(Nc, dtype=np.bool)
    is_coarse = np.zeros(Nc, dtype=np.bool)

    # cells that are not important for any other cells are on the fine scale.
    for row_id, row in enumerate(ST.rows):
        if not row:
            is_fine[row_id] = True
            candidate[row_id] = False

    ST = ST.tocsr()
    it = 0
    while np.any(candidate):
        i = np.argmax(lmbda)
        is_coarse[i] = True
        j = ST.indices[ST.indptr[i]:ST.indptr[i + 1]]
        jf = j[candidate[j]]
        is_fine[jf] = True
        candidate[np.r_[i, jf]] = False
        loop = ST.indices[mcolon.mcolon(ST.indptr[jf], ST.indptr[jf + 1] - 1)]
        for row in np.unique(loop):
            s = ST.indices[ST.indptr[row]:ST.indptr[row + 1]]
            lmbda[row] = s[candidate[s]].size + 2 * s[is_fine[s]].size
        lmbda[np.logical_not(candidate)] = -1
        it = it + 1

        # Something went wrong during aggregation
        assert it <= Nc

    del lmbda, ST

    if seeds is not None:
        is_coarse[seeds] = True
        is_fine[seeds] = False

    # If two neighbors are coarse, eliminate one of them
    c2c = np.abs(A) > 0
    c2c_rows, _, _ = sps.find(c2c)

    pairs = np.empty((2, 0), dtype=np.int)
    for idx, it in enumerate(np.where(is_coarse)[0]):
        loc = slice(c2c.indptr[it], c2c.indptr[it + 1])
        ind = np.setdiff1d(c2c_rows[loc], it)
        cind = ind[is_coarse[ind]]
        new_pair = np.stack((np.repeat(it, cind.size), cind))
        pairs = np.append(pairs, new_pair, axis=1)

    if pairs.size:
        pairs = unique.unique_np113(np.sort(pairs, axis=0), axis=1)
        for ij in pairs.T:
            mi = np.argmin(A[ij, ij])
            is_coarse[ij[mi]] = False
            is_fine[ij[mi]] = True

    coarse = np.where(is_coarse)[0]

    # Primal grid
    NC = coarse.size
    primal = sps.lil_matrix((NC, Nc), dtype=np.bool)
    for i in np.arange(NC):
        primal[i, coarse[i]] = True

    connection = sps.lil_matrix((Nc, Nc), dtype=np.double)
    for it in np.arange(Nc):
        n = np.setdiff1d(c2c_rows[c2c.indptr[it]:c2c.indptr[it + 1]], it)
        connection[it, n] = np.abs(A[it, n] / At[it, it])

    connection = connection.tocsr()

    candidates_rep = np.ediff1d(connection.indptr)
    candidates_idx = np.repeat(is_coarse, candidates_rep)
    candidates = np.stack(
        (connection.indices[candidates_idx],
         np.repeat(np.arange(NC), candidates_rep[is_coarse])),
        axis=-1)

    connection_idx = mcolon.mcolon(connection.indptr[coarse],
                                   connection.indptr[coarse + 1] - 1)
    vals = accumarray.accum(candidates,
                            connection.data[connection_idx],
                            size=[Nc, NC])
    del candidates_rep, candidates_idx, connection_idx

    mcind = np.argmax(vals, axis=0)
    mcval = [vals[r, c] for c, r in enumerate(mcind)]

    it = NC
    not_found = np.logical_not(is_coarse)
    # Process the strongest connection globally
    while np.any(not_found):
        mi = np.argmax(mcval)
        nadd = mcind[mi]

        primal[mi, nadd] = True
        not_found[nadd] = False
        vals[nadd, :] *= 0

        nc = connection.indices[connection.indptr[nadd]:connection.indptr[nadd
                                                                          + 1]]
        af = not_found[nc]
        nc = nc[af]
        nv = mcval[mi] * connection[nadd, :]
        nv = nv.data[af]
        if len(nc) > 0:
            vals += sps.csr_matrix((nv, (nc, np.repeat(mi, len(nc)))),
                                   shape=(Nc, NC)).todense()
        mcind = np.argmax(vals, axis=0)
        mcval = [vals[r, c] for c, r in enumerate(mcind)]

        it = it + 1
        if it > Nc + 5: break

    coarse, fine = primal.tocsr().nonzero()
    return coarse[np.argsort(fine)]