示例#1
0
    def test_cart_3d(self):
        g = structured.CartGrid([4, 3, 3])
        g.nodes = g.nodes + 0.2 * np.random.random((g.dim, g.nodes.shape[1]))
        g.compute_geometry()

        # Pick out cells (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (0, 0, 2), (1, 0, 2)
        c = np.array([0, 1, 4, 12, 24, 25])

        h, sub_f, sub_n = partition.extract_subgrid(g, c)

        # There are 20 nodes in each layer
        nodes_0 = np.array([0, 1, 2, 5, 6, 7, 10, 11])
        nodes_1 = nodes_0 + 20
        nodes_2 = np.array([0, 1, 2, 5, 6, 7]) + 40
        nodes_3 = nodes_2 + 20
        true_nodes = np.hstack((nodes_0, nodes_1, nodes_2, nodes_3))

        faces_x = np.array([0, 1, 2, 5, 6, 15, 16, 30, 31, 32])
        # y-faces start on 45
        faces_y = np.array([45, 46, 49, 50, 53, 61, 65, 77, 78, 81, 82])
        # z-faces start on 93
        faces_z = np.array([93, 94, 97, 105, 106, 109, 117, 118, 129, 130])
        true_faces = np.hstack((faces_x, faces_y, faces_z))

        assert np.array_equal(true_nodes, sub_n)
        assert np.array_equal(true_faces, sub_f)

        self.compare_grid_geometries(g, h, c, true_faces, true_nodes)
示例#2
0
    def test_subgrid_connected(self):
        g, p = self.setup()

        sub_g, _, _ = partition.extract_subgrid(g, np.where(p == 0)[0])
        is_connected, components = partition.grid_is_connected(sub_g)
        assert is_connected
        assert np.array_equal(np.sort(components[0]),
                              np.arange(sub_g.num_cells))
示例#3
0
    def test_subgrid_not_connected(self):
        g, p = self.setup()

        p_sub = np.r_[np.where(p == 0)[0], np.where(p == 3)[0]]
        sub_g, _, _ = partition.extract_subgrid(g, p_sub)
        is_connected, components = partition.grid_is_connected(sub_g)
        assert not is_connected
        assert np.array_equal(np.sort(p_sub[components[0]]),
                              np.array([0, 1, 4, 5]))
        assert np.array_equal(np.sort(p_sub[components[1]]),
                              np.array([10, 11, 14, 15]))
示例#4
0
    def test_simplex_2d(self):
        g = simplex.StructuredTriangleGrid(np.array([3, 2]))
        g.compute_geometry()
        c = np.array([0, 1, 3])
        true_nodes = np.array([0, 1, 4, 5, 6])
        true_faces = np.array([0, 1, 2, 4, 5, 10, 13])

        h, sub_f, sub_n = partition.extract_subgrid(g, c)

        assert np.array_equal(true_nodes, sub_n)
        assert np.array_equal(true_faces, sub_f)

        self.compare_grid_geometries(g, h, c, true_faces, true_nodes)
示例#5
0
    def test_cart_2d(self):
        g = structured.CartGrid([3, 2])
        g.nodes = g.nodes + 0.2 * np.random.random(g.nodes.shape)
        g.compute_geometry()

        c = np.array([0, 1, 3])

        h, sub_f, sub_n = partition.extract_subgrid(g, c)

        true_nodes = np.array([0, 1, 2, 4, 5, 6, 8, 9])
        true_faces = np.array([0, 1, 2, 4, 5, 8, 9, 11, 12, 14])

        assert np.array_equal(true_nodes, sub_n)
        assert np.array_equal(true_faces, sub_f)

        self.compare_grid_geometries(g, h, c, true_faces, true_nodes)
示例#6
0
def mpfa_partial(g,
                 k,
                 bnd,
                 eta=0,
                 inverter='numba',
                 cells=None,
                 faces=None,
                 nodes=None,
                 apertures=None):
    """
    Run an MPFA discretization on subgrid, and return discretization in terms
    of global variable numbers.

    Scenarios where the method will be used include updates of permeability,
    and the introduction of an internal boundary (e.g. fracture growth).

    The subgrid can be specified in terms of cells, faces and nodes to be
    updated. For details on the implementation, see
    fv_utils.cell_ind_for_partial_update()

    Parameters:
        g (porepy.grids.grid.Grid): grid to be discretized
        k (porepy.params.tensor.SecondOrderTensor) permeability tensor
        bnd (porepy.params.bc.BoundarCondition) class for boundary conditions
        faces (np.ndarray) faces to be considered. Intended for partial
            discretization, may change in the future
        eta Location of pressure continuity point. Should be 1/3 for simplex
            grids, 0 otherwise. On boundary faces with Dirichlet conditions,
            eta=0 will be enforced.
        inverter (string) Block inverter to be used, either numba (default),
            cython or python. See fvutils.invert_diagonal_blocks for details.
        cells (np.array, int, optional): Index of cells on which to base the
            subgrid computation. Defaults to None.
        faces (np.array, int, optional): Index of faces on which to base the
            subgrid computation. Defaults to None.
        nodes (np.array, int, optional): Index of nodes on which to base the
            subgrid computation. Defaults to None.
        apertures (np.ndarray, float, optional) apertures of the cells for scaling of the face
            normals. Defaults to None.

        Note that if all of {cells, faces, nodes} are None, empty matrices will
        be returned.

    Returns:
        sps.csr_matrix (g.num_faces x g.num_cells): Flux discretization,
            computed on a subgrid.
        sps.csr_matrix (g,num_faces x g.num_faces): Boundary flux
            discretization, computed on a subgrid
        np.array (int): Global of the faces where the flux discretization is
            computed.

    """
    if cells is not None:
        warnings.warn('Cells keyword for partial mpfa has not been tested')
    if faces is not None:
        warnings.warn('Faces keyword for partial mpfa has not been tested')

    # Find computational stencil, based on specified cells, faces and nodes.
    ind, active_faces = fvutils.cell_ind_for_partial_update(g,
                                                            cells=cells,
                                                            faces=faces,
                                                            nodes=nodes)

    # Extract subgrid, together with mappings between local and global
    # cells
    sub_g, l2g_faces, _ = partition.extract_subgrid(g, ind)
    l2g_cells = sub_g.parent_cell_ind

    # Local parameter fields
    # Copy permeability field, and restrict to local cells
    loc_k = k.copy()
    loc_k.perm = loc_k.perm[::, ::, l2g_cells]

    glob_bound_face = g.get_all_boundary_faces()

    # Boundary conditions are slightly more complex. Find local faces
    # that are on the global boundary.
    loc_bound_ind = np.argwhere(np.in1d(l2g_faces, glob_bound_face)).ravel('F')
    loc_cond = np.array(loc_bound_ind.size * ['neu'])
    # Then pick boundary condition on those faces.
    if loc_bound_ind.size > 0:
        # We could have avoided to explicitly define Neumann conditions,
        # since these are default.
        # For primal-like discretizations like the MPFA, internal boundaries
        # are handled by assigning Neumann conditions.
        is_dir = np.logical_and(bnd.is_dir, np.logical_not(bnd.is_internal))
        is_neu = np.logical_or(bnd.is_neu, bnd.is_internal)

        is_dir = is_dir[l2g_faces[loc_bound_ind]]
        is_neu = is_neu[l2g_faces[loc_bound_ind]]

        loc_cond[is_dir] = 'dir'
    loc_bnd = bc.BoundaryCondition(sub_g, faces=loc_bound_ind, cond=loc_cond)

    # Discretization of sub-problem
    flux_loc, bound_flux_loc = _mpfa_local(sub_g,
                                           loc_k,
                                           loc_bnd,
                                           eta=eta,
                                           inverter=inverter,
                                           apertures=apertures)

    # Map to global indices
    face_map, cell_map = fvutils.map_subgrid_to_grid(g,
                                                     l2g_faces,
                                                     l2g_cells,
                                                     is_vector=False)
    flux_glob = face_map * flux_loc * cell_map
    bound_flux_glob = face_map * bound_flux_loc * face_map.transpose()

    # By design of mpfa, and the subgrids, the discretization will update faces
    # outside the active faces. Kill these.
    outside = np.setdiff1d(np.arange(g.num_faces),
                           active_faces,
                           assume_unique=True)
    flux_glob[outside, :] = 0
    bound_flux_glob[outside, :] = 0

    return flux_glob, bound_flux_glob, active_faces