Esempio n. 1
0
                    [np.array([49]), np.array([55])]]
    return gb, split_scheme


# The main test function
@pytest.mark.parametrize(
    "geometry",
    [
        _two_fractures_overlapping_regions,
        _two_fractures_non_overlapping_regions,
        _two_fractures_regions_become_overlapping,
    ],
)
@pytest.mark.parametrize(
    "method",
    [pp.Mpfa("flow"),
     pp.Mpsa("mechanics"),
     pp.Biot("mechanics", "flow")])
def test_propagation(geometry, method):
    # Method to test partial discretization (aimed at finite volume methods) under
    # fracture propagation. The test is based on first discretizing, and then do one
    # or several fracture propagation steps. after each step, we do a partial
    # update of the discretization scheme, and compare with a full discretization on
    # the newly split grid. The test fails unless all discretization matrices generated
    # are identical.
    #
    # NOTE: Only the highest-dimensional grid in the GridBucket is used.

    # Get GridBucket and splitting schedule
    gb, faces_to_split = geometry()
Esempio n. 2
0
    def set_variables_discretizations_cell_basis(self, gb):
        """
        Assign variables, and set discretizations for the micro gb.

        NOTE: keywords and variable names are hardcoded here. This should be centralized.
        @Eirik we are keeping the same nomenclature, since the gb are different maybe we can
        change it a bit

        Args:
            gb (TYPE): the micro gb.

        Returns:
            None.

        """
        # Use mpfa for the fine-scale problem for now. We may generalize this at some
        # point, but that should be a technical detail.
        fine_scale_dicsr = pp.Mpfa(self.keyword)
        # In 1d, mpfa will end up calling tpfa, so use this directly, in a hope that
        # the reduced amount of boilerplate will save some time.
        fine_scale_dicsr_1d = pp.Tpfa(self.keyword)

        void_discr = pp.EllipticDiscretizationZeroPermeability(self.keyword)

        for g, d in gb:
            d[pp.PRIMARY_VARIABLES] = {
                self.cell_variable: {
                    "cells": 1,
                    "faces": 0
                }
            }
            if g.dim > 1:
                d[pp.DISCRETIZATION] = {
                    self.cell_variable: {
                        self.cell_discr: fine_scale_dicsr
                    }
                }
            else:
                d[pp.DISCRETIZATION] = {
                    self.cell_variable: {
                        self.cell_discr: fine_scale_dicsr_1d
                    }
                }

            d[pp.DISCRETIZATION_MATRICES] = {self.keyword: {}}

        # Loop over the edges in the GridBucket, define primary variables and discretizations
        # NOTE: No need to differ between Mpfa and Tpfa here; their treatment of interface
        # discretizations are the same.
        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)

            # Set the mortar variable.
            # NOTE: This is overriden in the case where the higher-dimensional grid is
            # auxiliary, see below.
            d[pp.PRIMARY_VARIABLES] = {self.mortar_variable: {"cells": 1}}

            # The type of lower-dimensional discretization depends on whether this is a
            # (part of a) fracture, or a transition between two line or surface grids.
            if g1.dim == 2 and g2.dim == 2:
                mortar_discr = pp.FluxPressureContinuity(
                    self.keyword, fine_scale_dicsr, fine_scale_dicsr)
            elif hasattr(g1, "is_auxiliary") and g1.is_auxiliary:
                if g2.dim > 1:
                    # This is a connection between a surface and an auxiliary line.
                    # Impose continuity conditions over the line.

                    assert g1.dim == 1  # Cannot imagine this is not True
                    mortar_discr = pp.FluxPressureContinuity(
                        self.keyword, fine_scale_dicsr, void_discr)
                else:
                    # Connection between a 1d line (an interaction region edge) and a
                    # point along that line (could be a coner along the edge.
                    mortar_discr = pp.FluxPressureContinuity(
                        self.keyword, fine_scale_dicsr_1d, void_discr)
            elif hasattr(g2, "is_auxiliary") and g2.is_auxiliary:
                # This is an auxiliary line being cut by a point, which should then
                # be a fracture point. Impose no condition here.
                assert g2.dim == 1
                # No variable for this edge - we have no equation for it.
                d[pp.PRIMARY_VARIABLES] = {}
                continue
            else:
                # Standard coupling, with resistance, for the final case.
                if g1.dim > 1:
                    mortar_discr = pp.RobinCoupling(self.keyword,
                                                    fine_scale_dicsr,
                                                    fine_scale_dicsr)
                elif g1.dim == 1:
                    mortar_discr = pp.RobinCoupling(self.keyword,
                                                    fine_scale_dicsr,
                                                    fine_scale_dicsr_1d)
                else:
                    mortar_discr = pp.RobinCoupling(self.keyword,
                                                    fine_scale_dicsr_1d,
                                                    fine_scale_dicsr_1d)

            d[pp.COUPLING_DISCRETIZATION] = {
                self.mortar_discr: {
                    g1: (self.cell_variable, self.cell_discr),
                    g2: (self.cell_variable, self.cell_discr),
                    e: (self.mortar_variable, mortar_discr),
                }
            }
            d[pp.DISCRETIZATION_MATRICES] = {self.keyword: {}}
Esempio n. 3
0
 def run_mpfa(self, gb):
     key = "flow"
     method = pp.Mpfa(key)
     self._solve(gb, method, key)
Esempio n. 4
0
    def test_assemble_biot(self):
        """ Test the assembly of the Biot problem using the assembler.

        The test checks whether the discretization matches that of the Biot class.
        """
        gb = pp.meshing.cart_grid([], [2, 1])
        g = gb.grids_of_dimension(2)[0]
        d = gb.node_props(g)
        # Parameters identified by two keywords
        kw_m = "mechanics"
        kw_f = "flow"
        variable_m = "displacement"
        variable_f = "pressure"
        bound_mech, bound_flow = self.make_boundary_conditions(g)
        initial_disp, initial_pressure, initial_state = self.make_initial_conditions(
            g, x0=0, y0=0, p0=0
        )
        state = {
            variable_f: initial_pressure,
            variable_m: initial_disp,
            kw_m: {"bc_values": np.zeros(g.num_faces * g.dim)},
        }
        parameters_m = {"bc": bound_mech, "biot_alpha": 1}

        parameters_f = {"bc": bound_flow, "biot_alpha": 1}
        pp.initialize_default_data(g, d, kw_m, parameters_m)
        pp.initialize_default_data(g, d, kw_f, parameters_f)
        pp.set_state(d, state)
        # Discretize the mechanics related terms using the Biot class
        biot_discretizer = pp.Biot()
        biot_discretizer._discretize_mech(g, d)

        # Set up the structure for the assembler. First define variables and equation
        # term names.
        v_0 = variable_m
        v_1 = variable_f
        term_00 = "stress_divergence"
        term_01 = "pressure_gradient"
        term_10 = "displacement_divergence"
        term_11_0 = "fluid_mass"
        term_11_1 = "fluid_flux"
        term_11_2 = "stabilization"
        d[pp.PRIMARY_VARIABLES] = {v_0: {"cells": g.dim}, v_1: {"cells": 1}}
        d[pp.DISCRETIZATION] = {
            v_0: {term_00: pp.Mpsa(kw_m)},
            v_1: {
                term_11_0: pp.MassMatrix(kw_f),
                term_11_1: pp.Mpfa(kw_f),
                term_11_2: pp.BiotStabilization(kw_f),
            },
            v_0 + "_" + v_1: {term_01: pp.GradP(kw_m)},
            v_1 + "_" + v_0: {term_10: pp.DivU(kw_m)},
        }
        # Assemble. Also discretizes the flow terms (fluid_mass and fluid_flux)
        general_assembler = pp.Assembler(gb)
        general_assembler.discretize(term_filter=["fluid_mass", "fluid_flux"])
        A, b = general_assembler.assemble_matrix_rhs()

        # Re-discretize and assemble using the Biot class
        A_class, b_class = biot_discretizer.assemble_matrix_rhs(g, d)

        # Make sure the variable ordering of the matrix assembled by the assembler
        # matches that of the Biot class.
        grids = [g, g]
        variables = [v_0, v_1]
        A, b = permute_matrix_vector(
            A,
            b,
            general_assembler.block_dof,
            general_assembler.full_dof,
            grids,
            variables,
        )

        # Compare the matrices and rhs vectors
        self.assertTrue(np.all(np.isclose(A.A, A_class.A)))
        self.assertTrue(np.all(np.isclose(b, b_class)))
Esempio n. 5
0
def test_fv_cart_2d(method):
    """ Apply TPFA and MPFA on Cartesian grid, should obtain Laplacian stencil."""

    # Set up 3 X 3 Cartesian grid
    nx = np.array([3, 3])
    g = pp.CartGrid(nx)
    g.compute_geometry()

    kxx = np.ones(g.num_cells)
    perm = pp.SecondOrderTensor(kxx)

    bound_faces = np.array([0, 3, 12])
    bound = pp.BoundaryCondition(g, bound_faces, ["dir"] * bound_faces.size)

    key = "flow"
    d = pp.initialize_default_data(
        g, {}, key, {"second_order_tensor": perm, "bc": bound}
    )
    if method == "tpfa":
        discr = pp.Tpfa(key)
    elif method == "mpfa":
        discr = pp.Mpfa(key)
    else:
        assert False

    discr.discretize(g, d)
    matrix_dictionary = d[pp.DISCRETIZATION_MATRICES][key]
    trm, bound_flux = matrix_dictionary["flux"], matrix_dictionary["bound_flux"]
    div = g.cell_faces.T
    a = div * trm
    b = -(div * bound_flux).A

    # Checks on interior cell
    mid = 4
    assert a[mid, mid] == 4
    assert a[mid - 1, mid] == -1
    assert a[mid + 1, mid] == -1
    assert a[mid - 3, mid] == -1
    assert a[mid + 3, mid] == -1

    assert np.all(b[mid, :] == 0)

    # The first cell should have two Dirichlet bnds
    assert a[0, 0] == 6
    assert a[0, 1] == -1
    assert a[0, 3] == -1

    assert b[0, 0] == 2
    assert b[0, 12] == 2

    # Cell 3 has one Dirichlet, one Neumann face
    assert a[2, 2] == 4
    assert a[2, 1] == -1
    assert a[2, 5] == -1

    assert b[2, 3] == 2
    assert b[2, 14] == -1
    # Cell 2 has one Neumann face
    assert a[1, 1] == 3
    assert a[1, 0] == -1
    assert a[1, 2] == -1
    assert a[1, 4] == -1

    assert b[1, 13] == -1

    return a
Esempio n. 6
0
    def test_hydrostatic_pressure(self):

        # Test mpfa_gravity in 2D Cartesian
        # and triangular grids
        # Should be exact for hydrostatic pressure
        # with stepwise gravity variation

        grids = ["cart", "triangular"]

        x, y = sympy.symbols("x y")
        g1 = 10
        g2 = 1
        p0 = 1  # reference pressure
        p = p0 + sympy.Piecewise(((1 - y) * g1, y >= 0.5),
                                 (0.5 * g1 + (0.5 - y) * g2, y < 0.5))
        an_sol = _SolutionHomogeneousDomainFlowWithGravity(p, x, y)

        for gr in grids:

            domain = np.array([1, 1])
            basedim = np.array([4, 4])
            pert = 0.5
            g = make_grid(gr, basedim, domain)
            g.compute_geometry()
            dx = np.max(domain / basedim)
            g = perturb(g, pert, dx)
            g.compute_geometry()
            xc = g.cell_centers
            xf = g.face_centers

            k = pp.SecondOrderTensor(np.ones(g.num_cells))

            # Gravity
            gforce = np.zeros((2, g.num_cells))
            gforce[0, :] = an_sol.gx_f(xc[0], xc[1])
            gforce[1, :] = an_sol.gy_f(xc[0], xc[1])
            gforce = gforce.ravel("F")

            # Set type of boundary conditions
            p_bound = np.zeros(g.num_faces)
            left_faces = np.ravel(np.argwhere(g.face_centers[0] < 1e-10))
            right_faces = np.ravel(
                np.argwhere(g.face_centers[0] > domain[0] - 1e-10))
            dir_faces = np.concatenate((left_faces, right_faces))

            bound_cond = pp.BoundaryCondition(g, dir_faces,
                                              ["dir"] * dir_faces.size)

            # set value of boundary condition
            p_bound[dir_faces] = an_sol.p_f(xf[0, dir_faces], xf[1, dir_faces])

            # GCMPFA discretization, and system matrix
            flux, bound_flux, _, _, div_g = pp.Mpfa("flow").mpfa(
                g, k, bound_cond, vector_source=True, inverter="python")
            div = pp.fvutils.scalar_divergence(g)
            a = div * flux
            flux_g = div_g * gforce
            b = -div * bound_flux * p_bound - div * flux_g
            p = scipy.sparse.linalg.spsolve(a, b)
            q = flux * p + bound_flux * p_bound + flux_g
            p_ex = an_sol.p_f(xc[0], xc[1])
            q_ex = np.zeros(g.num_faces)
            self.assertTrue(np.allclose(p, p_ex))
            self.assertTrue(np.allclose(q, q_ex))