예제 #1
0
    def test_linear_pressure_part_neumann_conditions(self):
        g = self.grid()

        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["neu"]
        # Set Dirichlet conditions. Note that indices are relative to bf,
        # that is, counting only boundary faces.
        bc_type[0] = "dir"
        bc_type[2] = "dir"  # Not [3]
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        bc_val = np.zeros(g.num_faces)
        # Set up unit flow in x-direction, thus pressure gradient the other way
        bc_val[[2, 5]] = 1
        data = make_dictionary(g, bound, bc_val)
        p = self.pressure(fd, g, data)

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * p
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(np.allclose(bound_p[bf], -g.face_centers[0, bf]))
예제 #2
0
def _tpfa_matrix(g, perm=None):
    """
    Compute a two-point flux approximation matrix useful related to a call of
    create_partition.

    Parameters
    ----------
    g: the grid
    perm: (optional) permeability, the it is not given unitary tensor is assumed

    Returns
    -------
    out: sparse matrix
        Two-point flux approximation matrix

    """
    if isinstance(g, grid_bucket.GridBucket):
        g = g.get_grids(lambda g_: g_.dim == g.dim_max())[0]

    if perm is None:
        perm = pp.SecondOrderTensor(np.ones(g.num_cells))

    solver = pp.Tpfa("flow")
    specified_parameters = {
        "second_order_tensor": perm,
        "bc": pp.BoundaryCondition(g, np.empty(0), ""),
    }
    data = pp.initialize_default_data(g, {}, "flow", specified_parameters)
    solver.discretize(g, data)
    return solver.assemble_matrix(g, data)
예제 #3
0
    def __init__(self, gb, flow, model="flow"):

        self.model = model
        self.gb = gb
        self.data = None
        self.assembler = None

        # discretization operator name
        self.discr_name = self.model + "_flux"
        self.discr = pp.Tpfa(self.model)

        self.coupling_name = self.discr_name + "_coupling"
        self.coupling = pp.RobinCoupling(self.model, self.discr)

        self.source_name = self.model + "_source"
        self.source = pp.ScalarSource(self.model)

        # master variable name
        self.variable = self.model + "_variable"
        self.mortar = self.model + "_lambda"

        # post process variables
        self.pressure = "pressure"
        self.flux = "darcy_flux"  # it has to be this one
        self.P0_flux = "P0_darcy_flux"
예제 #4
0
    def test_linear_pressure_part_neumann_conditions_smaller_domain(self):
        # Smaller domain, check that the smaller pressure gradient is captured
        g = pp.CartGrid([2, 2], physdims=[1, 2])
        g.compute_geometry()

        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["neu"]
        bc_type[0] = "dir"
        bc_type[2] = "dir"
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        bc_val = np.zeros(g.num_faces)
        # Set up unit pressure gradient in x-direction
        bc_val[[2, 5]] = 1
        data = make_dictionary(g, bound, bc_val)
        p = self.pressure(fd, g, data)

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * p
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(np.allclose(bound_p[bf], -g.face_centers[0, bf]))
예제 #5
0
    def solve(self, gb, method=None):
        key = "flow"
        if method is None:
            discretization = pp.Tpfa(key)
        elif method == "mpfa":
            discretization = pp.Mpfa(key)
        elif method == "mvem":
            discretization = pp.MVEM(key)
        assembler = test_utils.setup_flow_assembler(gb, discretization, key)
        assembler.discretize()
        A_flow, b_flow = assembler.assemble_matrix_rhs()
        p = sps.linalg.spsolve(A_flow, b_flow)
        assembler.distribute_variable(p)

        if method == "mvem":
            g2d = gb.grids_of_dimension(2)[0]
            p_n = np.zeros(gb.num_cells())
            for g, d in gb:
                if g.dim == 2:
                    p_n[:g2d.num_cells] = d[pp.STATE]["pressure"][g.num_faces:]
                else:
                    p_n[g2d.num_cells:] = d[pp.STATE]["pressure"][g.num_faces:]
                d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][g.num_faces:]
            p = p_n
        return p
예제 #6
0
def test_symmetry_periodic_pressure_field_2d(method):
    """
    Test that we obtain a symmetric solution accross the periodic boundary.
    The test consider the unit square with periodic boundary conditions
    on the top and bottom boundary. A source is added to the bottom row of
    cells and we test that the solution is periodic.
    Setup, with x denoting the source:
           --------
          |       |
    p = 0 |       | p = 0
          |   x   |
           -------
    """
    # Structured Cartesian grid
    g, kxx = setup_cart_2d(np.array([5, 5]), [1, 1])

    bot_faces = np.argwhere(g.face_centers[1] < 1e-5).ravel()
    top_faces = np.argwhere(g.face_centers[1] > 1 - 1e-5).ravel()

    left_faces = np.argwhere(g.face_centers[0] < 1e-5).ravel()
    right_faces = np.argwhere(g.face_centers[0] > 1 - 1e-5).ravel()

    dir_faces = np.hstack((left_faces, right_faces))

    g.set_periodic_map(np.vstack((bot_faces, top_faces)))

    bound = pp.BoundaryCondition(g, dir_faces, "dir")

    # Solve
    key = "flow"
    d = pp.initialize_default_data(
        g, {}, key, {
            "second_order_tensor": pp.SecondOrderTensor(kxx),
            "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]
    flux, bound_flux = matrix_dictionary["flux"], matrix_dictionary[
        "bound_flux"]

    div = g.cell_faces.T

    a = div * flux

    pr_bound = np.zeros(g.num_faces)
    src = np.zeros(g.num_cells)
    src[2] = 1

    rhs = -div * bound_flux * pr_bound + src
    pr = np.linalg.solve(a.todense(), rhs)

    p_diff = pr[5:15] - np.hstack((pr[-5:], pr[-10:-5]))
    assert np.max(np.abs(p_diff)) < 1e-10
예제 #7
0
def setup_discr_tpfa(gb, key="flow"):
    """ Setup the discretization Tpfa. """
    discr = pp.Tpfa(key)
    p_trace = pp.CellDofFaceDofMap(key)
    interface = pp.FluxPressureContinuity(key, discr, p_trace)

    for g, d in gb:
        if g.dim == gb.dim_max():
            d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1}}
            d[pp.DISCRETIZATION] = {key: {"flux": discr}}
        else:
            d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1}}
            d[pp.DISCRETIZATION] = {key: {"flux": p_trace}}

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {key: {"cells": 1}}
        d[pp.COUPLING_DISCRETIZATION] = {
            "flux": {
                g_slave: (key, "flux"),
                g_master: (key, "flux"),
                e: (key, interface),
            }
        }

    return pp.Assembler(gb), (discr, p_trace)
예제 #8
0
def set_params_disrcetize(g, ambient_dim, method, periodic=False):
    g.compute_geometry()
    keyword = "flow"

    if periodic:
        south = g.face_centers[1] < np.min(g.nodes[1]) + 1e-8
        north = g.face_centers[1] > np.max(g.nodes[1]) - 1e-8
        bc = pp.BoundaryCondition(g, north + south, "per")
        south_idx = np.argwhere(south).ravel()
        north_idx = np.argwhere(north).ravel()
        bc.set_periodic_map(np.vstack((south_idx, north_idx)))
    else:
        bc = pp.BoundaryCondition(g)
    k = pp.SecondOrderTensor(np.ones(g.num_cells))

    params = {
        "bc": bc,
        "second_order_tensor": k,
        "mpfa_inverter": "python",
        "ambient_dimension": ambient_dim,
    }

    data = pp.initialize_data(g, {}, keyword, params)
    if method == "mpfa":
        discr = pp.Mpfa(keyword)
    elif method == "tpfa":
        discr = pp.Tpfa(keyword)
    discr.discretize(g, data)

    flux = data[pp.DISCRETIZATION_MATRICES][keyword][discr.flux_matrix_key]
    vector_source = data[pp.DISCRETIZATION_MATRICES][keyword][
        discr.vector_source_matrix_key]
    div = pp.fvutils.scalar_divergence(g)
    return flux, vector_source, div
예제 #9
0
    def test_two_cart_grids(self):
        """
        We set up the test case -----|---------
                                |    |        |
                                | g1 |    g2  |
                                |    |        |
                                -----|---------
        with a linear pressure increase from left to right
        """
        n = 2
        xmax = 3
        ymax = 1
        split = 2
        gb = self.generate_grids(n, xmax, ymax, split)
        tol = 1e-6
        for g, d in gb:
            left = g.face_centers[0] < tol
            right = g.face_centers[0] > xmax - tol
            dir_bc = left + right
            bound = pp.BoundaryCondition(g, dir_bc, "dir")
            bc_val = np.zeros(g.num_faces)
            bc_val[left] = xmax
            bc_val[right] = 0
            specified_parameters = {"bc": bound, "bc_values": bc_val}
            pp.initialize_default_data(g, d, "flow", specified_parameters)

        for e, d in gb.edges():
            mg = d["mortar_grid"]
            d[pp.PARAMETERS] = pp.Parameters(mg, ["flow"], [{}])
            pp.params.data.add_discretization_matrix_keyword(d, "flow")
        # assign discretization
        data_key = "flow"
        tpfa = pp.Tpfa(data_key)
        coupler = pp.FluxPressureContinuity(data_key, tpfa)
        assembler = test_utils.setup_flow_assembler(gb,
                                                    tpfa,
                                                    data_key,
                                                    coupler=coupler)
        test_utils.solve_and_distribute_pressure(gb, assembler)

        # test pressure
        for g, d in gb:
            self.assertTrue(
                np.allclose(d[pp.STATE]["pressure"], xmax - g.cell_centers[0]))

        # test mortar solution
        for e, d_e in gb.edges():
            mg = d_e["mortar_grid"]
            g2, g1 = gb.nodes_of_edge(e)
            master_to_m = mg.master_to_mortar_avg()
            slave_to_m = mg.slave_to_mortar_avg()

            master_area = master_to_m * g1.face_areas
            slave_area = slave_to_m * g2.face_areas

            self.assertTrue(
                np.allclose(d_e[pp.STATE]["mortar_flux"] / master_area, 1))
            self.assertTrue(
                np.allclose(d_e[pp.STATE]["mortar_flux"] / slave_area, 1))
예제 #10
0
def homo_tpfa(g):
    return {
        "scheme": pp.Tpfa("flow"),
        "dof": {
            "cells": 1
        },
        "label": "homo_tpfa"
    }
예제 #11
0
    def test_uniform_flow_cart_2d_1d_simplex(self):
        # Unstructured simplex grid
        gb = setup_2d_1d(np.array([10, 10]), simplex_grid=True)

        key = "flow"
        tpfa = pp.Tpfa(key)
        assembler = test_utils.setup_flow_assembler(gb, tpfa, key)
        test_utils.solve_and_distribute_pressure(gb, assembler)
        self.assertTrue(check_pressures(gb))
예제 #12
0
def solve_tpfa(gb, folder, discr_3d=None):
    # Choose and define the solvers and coupler
    flow_discretization = pp.Tpfa("flow")
    source_discretization = pp.ScalarSource("flow")
    run_flow(gb,
             flow_discretization,
             source_discretization,
             folder,
             is_FV=True,
             discr_3d=discr_3d)
예제 #13
0
def test_fv_cart_2d_periodic(method):
    """ Apply TPFA and MPFA on a periodic 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)

    left_faces = [0, 4, 8, 12, 13, 14]
    right_faces = [3, 7, 11, 21, 22, 23]
    periodic_face_map = np.vstack((left_faces, right_faces))
    g.set_periodic_map(periodic_face_map)

    bound = pp.BoundaryCondition(g)

    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

    # Create laplace matrix
    A_lap = np.array([
        [4.0, -1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0],
        [-1.0, 4.0, -1.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0],
        [-1.0, -1.0, 4.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0],
        [-1.0, 0.0, 0.0, 4.0, -1.0, -1.0, -1.0, 0.0, 0.0],
        [0.0, -1.0, 0.0, -1.0, 4.0, -1.0, 0.0, -1.0, 0.0],
        [0.0, 0.0, -1.0, -1.0, -1.0, 4.0, 0.0, 0.0, -1.0],
        [-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 4.0, -1.0, -1.0],
        [0.0, -1.0, 0.0, 0.0, -1.0, 0.0, -1.0, 4.0, -1.0],
        [0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, -1.0, 4.0],
    ])

    assert np.allclose(a.A, A_lap)
    assert np.allclose(b, 0)
    return a
예제 #14
0
    def set_param_flow(self, gb, no_flow=False, kn=1e3, method="mpfa"):
        # Set up flow field with uniform flow in y-direction
        kw = "flow"
        for g, d in gb:
            parameter_dictionary = {}

            perm = pp.SecondOrderTensor(kxx=np.ones(g.num_cells))
            parameter_dictionary["second_order_tensor"] = perm

            b_val = np.zeros(g.num_faces)
            if g.dim == 2:
                bound_faces = pp.face_on_side(g, ["ymin", "ymax"])
                if no_flow:
                    b_val[bound_faces[0]] = 1
                    b_val[bound_faces[1]] = 1
                bound_faces = np.hstack((bound_faces[0], bound_faces[1]))
                labels = np.array(["dir"] * bound_faces.size)
                parameter_dictionary["bc"] = pp.BoundaryCondition(
                    g, bound_faces, labels)

                y_max_faces = pp.face_on_side(g, "ymax")[0]
                b_val[y_max_faces] = 1
            else:
                parameter_dictionary["bc"] = pp.BoundaryCondition(g)
            parameter_dictionary["bc_values"] = b_val
            parameter_dictionary["mpfa_inverter"] = "python"

            d[pp.PARAMETERS] = pp.Parameters(g, [kw], [parameter_dictionary])
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        gb.add_edge_props("kn")
        for e, d in gb.edges():
            mg = d["mortar_grid"]
            flow_dictionary = {
                "normal_diffusivity": 2 * kn * np.ones(mg.num_cells)
            }
            d[pp.PARAMETERS] = pp.Parameters(keywords=["flow"],
                                             dictionaries=[flow_dictionary])
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        discretization_key = kw + "_" + pp.DISCRETIZATION

        for g, d in gb:
            # Choose discretization and define the solver
            if method == "mpfa":
                discr = pp.Mpfa(kw)
            elif method == "mvem":
                discr = pp.MVEM(kw)
            else:
                discr = pp.Tpfa(kw)

            d[discretization_key] = discr

        for _, d in gb.edges():
            d[discretization_key] = pp.RobinCoupling(kw, discr)
예제 #15
0
def elliptic_disc(gb, keyword, use_mpfa=False):
    """
    Discretize the elliptic operator on each graph node
    """
    for g, d in gb:
        if use_mpfa:
            pp.Mpfa(keyword).discretize(g, d)
        else:
            pp.Tpfa(keyword).discretize(g, d)
        d[pp.DISCRETIZATION_MATRICES][keyword][
            "div"] = pp.fvutils.scalar_divergence(g)
예제 #16
0
def test_periodic_pressure_field_2d(method):
    """
    Test that TPFA approximate an analytical periodic solution by imposing
    periodic boundary conditions to the bottom and top faces of the unit square.
    """
    # Structured Cartesian grid
    g, kxx = setup_cart_2d(np.array([10, 10]), [1, 1])

    bot_faces = np.argwhere(g.face_centers[1] < 1e-5).ravel()
    top_faces = np.argwhere(g.face_centers[1] > 1 - 1e-5).ravel()

    left_faces = np.argwhere(g.face_centers[0] < 1e-5).ravel()
    right_faces = np.argwhere(g.face_centers[0] > 1 - 1e-5).ravel()

    dir_faces = np.hstack((left_faces, right_faces))

    g.set_periodic_map(np.vstack((bot_faces, top_faces)))

    bound = pp.BoundaryCondition(g, dir_faces, "dir")

    # Solve
    key = "flow"
    d = pp.initialize_default_data(
        g, {}, key, {
            "second_order_tensor": pp.SecondOrderTensor(kxx),
            "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]
    flux, bound_flux = matrix_dictionary["flux"], matrix_dictionary[
        "bound_flux"]

    div = g.cell_faces.T

    a = div * flux

    pr_bound, pr_cell, src = setup_periodic_pressure_field(g, kxx)

    rhs = -div * bound_flux * pr_bound + src * g.cell_volumes
    pr = np.linalg.solve(a.todense(), rhs)

    p_diff = pr - pr_cell

    assert np.max(np.abs(p_diff)) < 0.06
예제 #17
0
 def solve(self, method):
     key = "flow"
     gb = self.gb
     if method == "tpfa":
         discretization = pp.Tpfa(key)
     elif method == "mpfa":
         discretization = pp.Mpfa(key)
     elif method == "mvem":
         discretization = pp.MVEM(key)
     assembler = test_utils.setup_flow_assembler(gb, discretization, key)
     assembler.discretize()
     A_flow, b_flow = assembler.assemble_matrix_rhs()
     p = sps.linalg.spsolve(A_flow, b_flow)
     assembler.distribute_variable(p)
     return p
예제 #18
0
    def test_zero_pressure(self):
        g = self.grid()
        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["dir"]
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        data = make_dictionary(g, bound)
        p = self.pressure(fd, g, data)
        self.assertTrue(np.allclose(p, np.zeros_like(p)))
        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = matrix_dictionary["bound_pressure_cell"] * p + matrix_dictionary[
            "bound_pressure_face"
        ] * np.zeros(g.num_faces)
        self.assertTrue(np.allclose(bound_p, np.zeros_like(bound_p)))
예제 #19
0
    def diffusive_disc(self):
        "Discretization of term \nabla K \nabla T"

        class DiffusiveMixedDim(pp.TpfaMixedDim):
            def __init__(self, physics="flow", has_advective_term=False):
                pp.TpfaMixedDim.__init__(self, physics=physics)
                if has_advective_term:
                    self.coupling_conditions = [None, self.coupling_conditions]
                self.solver = pp.numerics.mixed_dim.coupler.Coupler(
                    self.discr, self.coupling_conditions)

        if self.is_GridBucket:
            diffusive_discr = DiffusiveMixedDim(self.physics,
                                                self.advective_term)
        else:
            diffusive_discr = pp.Tpfa(physics=self.physics)
        return diffusive_discr
예제 #20
0
def hete2(g):
    if g.dim == 2:
        scheme = {
            "scheme": pp.MVEM("flow"),
            "dof": {
                "cells": 1,
                "faces": 1
            },
            "label": "hete2"
        }
    else:
        scheme = {
            "scheme": pp.Tpfa("flow"),
            "dof": {
                "cells": 1
            },
            "label": "hete2"
        }
    return scheme
예제 #21
0
    def test_linear_pressure_dirichlet_conditions(self):
        g = self.grid()

        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["dir"]
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        bc_val = 1 * g.face_centers[0] + 2 * g.face_centers[1]
        data = make_dictionary(g, bound, bc_val)

        p = self.pressure(fd, g, data)

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * p
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(np.allclose(bound_p[bf], bc_val[bf]))
예제 #22
0
    def test_sign_trouble_two_neumann_sides(self):
        g = pp.CartGrid(np.array([2, 2]), physdims=[2, 2])
        g.compute_geometry()
        bc_val = np.zeros(g.num_faces)
        bc_val[[0, 3]] = 1
        bc_val[[2, 5]] = -1
        t = pp.Tpfa("flow")
        data = make_dictionary(g, pp.BoundaryCondition(g), bc_val)
        t.discretize(g, data)
        t.assemble_matrix_rhs(g, data)
        # The problem is singular, and spsolve does not work well on all systems.
        # Instead, set a consistent solution, and check that the boundary
        # pressure is recovered.
        x = g.cell_centers[0]

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * x
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(bound_p[0] == x[0] - 0.5)
        self.assertTrue(bound_p[2] == x[1] + 0.5)
예제 #23
0
    def test_constant_pressure_simplex_grid(self):
        g = self.simplex_grid()

        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["dir"]
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        bc_val = np.ones(g.num_faces)
        data = make_dictionary(g, bound, bc_val)

        p = self.pressure(fd, g, data)

        self.assertTrue(np.allclose(p, np.ones_like(p)))

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * p
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(np.allclose(bound_p[bf], bc_val[bf]))
예제 #24
0
    def test_linear_pressure_part_neumann_conditions_reverse_sign(self):
        g = self.grid()

        bf = np.where(g.tags["domain_boundary_faces"].ravel())[0]
        bc_type = bf.size * ["neu"]
        bc_type[0] = "dir"
        bc_type[2] = "dir"
        bound = pp.BoundaryCondition(g, bf, bc_type)

        fd = pp.Tpfa("flow")

        bc_val = np.zeros(g.num_faces)
        # Set up pressure gradient in x-direction, with value -1
        bc_val[[2, 5]] = -1
        data = make_dictionary(g, bound, bc_val)
        p = self.pressure(fd, g, data)

        matrix_dictionary = data[pp.DISCRETIZATION_MATRICES]["flow"]
        bound_p = (
            matrix_dictionary["bound_pressure_cell"] * p
            + matrix_dictionary["bound_pressure_face"] * bc_val
        )
        self.assertTrue(np.allclose(bound_p[bf], g.face_centers[0, bf]))
예제 #25
0
    def solve(self, kf, description, multi_point):
        gb, domain = pp.grid_buckets_2d.benchmark_regular(
            {"mesh_size_frac": 0.045})
        # Assign parameters
        setup.add_data(gb, domain, kf)

        key = "flow"
        if multi_point:
            method = pp.Mpfa(key)
        else:
            method = pp.Tpfa(key)

        coupler = pp.RobinCoupling(key, method)

        for g, d in gb:
            d[pp.PRIMARY_VARIABLES] = {"pressure": {"cells": 1}}
            d[pp.DISCRETIZATION] = {"pressure": {"diffusive": method}}
        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            d[pp.PRIMARY_VARIABLES] = {"mortar_solution": {"cells": 1}}
            d[pp.COUPLING_DISCRETIZATION] = {
                "lambda": {
                    g1: ("pressure", "diffusive"),
                    g2: ("pressure", "diffusive"),
                    e: ("mortar_solution", coupler),
                }
            }
            d[pp.DISCRETIZATION_MATRICES] = {"flow": {}}

        assembler = pp.Assembler(gb)

        # Discretize
        assembler.discretize()
        A, b = assembler.assemble_matrix_rhs()
        p = sps.linalg.spsolve(A, b)

        assembler.distribute_variable(p)
예제 #26
0
def advdiff(gb, param, model_flow):

    model = "transport"

    model_data_adv, model_data_diff = data.advdiff(gb, model, model_flow,
                                                   param)

    # discretization operator names
    adv_id = "advection"
    diff_id = "diffusion"

    # variable names
    variable = "scalar"
    mortar_adv = "lambda_" + variable + "_" + adv_id
    mortar_diff = "lambda_" + variable + "_" + diff_id

    # discretization operatr
    discr_adv = pp.Upwind(model_data_adv)
    discr_diff = pp.Tpfa(model_data_diff)

    coupling_adv = pp.UpwindCoupling(model_data_adv)
    coupling_diff = pp.RobinCoupling(model_data_diff, discr_diff)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {
            variable: {
                adv_id: discr_adv,
                diff_id: discr_diff
            }
        }

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {
            mortar_adv: {
                "cells": 1
            },
            mortar_diff: {
                "cells": 1
            }
        }

        d[pp.COUPLING_DISCRETIZATION] = {
            adv_id: {
                g_slave: (variable, adv_id),
                g_master: (variable, adv_id),
                e: (mortar_adv, coupling_adv)
            },
            diff_id: {
                g_slave: (variable, diff_id),
                g_master: (variable, diff_id),
                e: (mortar_diff, coupling_diff)
            }
        }

    # setup the advection-diffusion problem
    assembler = pp.Assembler()
    logger.info(
        "Assemble the advective and diffusive terms of the transport problem")
    A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    # mass term
    mass_id = "mass"
    discr_mass = pp.MassMatrix(model_data_adv)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {variable: {mass_id: discr_mass}}

    gb.remove_edge_props(pp.COUPLING_DISCRETIZATION)

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {
            mortar_adv: {
                "cells": 1
            },
            mortar_diff: {
                "cells": 1
            }
        }

    logger.info("Assemble the mass term of the transport problem")
    M, _, _, _ = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    # Perform an LU factorization to speedup the solver
    #IE_solver = sps.linalg.factorized((M + A).tocsc())

    # time loop
    logger.info("Prepare the exporting")
    save = pp.Exporter(gb, "solution", folder=param["folder"])
    logger.info("done")
    variables = [variable, param["pressure"], param["P0_flux"]]

    x = np.ones(A.shape[0]) * param["initial_advdiff"]
    logger.info("Start the time loop with " + str(param["n_steps"]) + " steps")
    for i in np.arange(param["n_steps"]):
        #x = IE_solver(b + M.dot(x))
        logger.info("Solve the linear system for time step " + str(i))
        x = sps.linalg.spsolve(M + A, b + M.dot(x))
        logger.info("done")

        logger.info("Variable post-process")
        assembler.distribute_variable(gb, x, block_dof, full_dof)
        logger.info("done")

        logger.info("Export variable")
        save.write_vtk(variables, time_step=i)
        logger.info("done")

    save.write_pvd(np.arange(param["n_steps"]) * param["time_step"])
예제 #27
0
    def solve(self, gb, analytic_p):

        # Parameter-discretization keyword:
        kw = "flow"
        # Terms
        key_flux = "flux"
        key_src = "src"
        # Primary variables
        key_p = "pressure"  # pressure name
        key_m = "mortar"  # mortar name

        tpfa = pp.Tpfa(kw)
        src = pp.ScalarSource(kw)
        for g, d in gb:
            d[pp.DISCRETIZATION] = {key_p: {key_src: src, key_flux: tpfa}}
            d[pp.PRIMARY_VARIABLES] = {key_p: {"cells": 1}}

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            d[pp.PRIMARY_VARIABLES] = {key_m: {"cells": 1}}
            if g1.dim == g2.dim:
                mortar_disc = pp.FluxPressureContinuity(kw, tpfa)
            else:
                mortar_disc = pp.RobinCoupling(kw, tpfa)
            d[pp.COUPLING_DISCRETIZATION] = {
                key_flux: {
                    g1: (key_p, key_flux),
                    g2: (key_p, key_flux),
                    e: (key_m, mortar_disc),
                }
            }

        assembler = pp.Assembler(gb)
        assembler.discretize()
        A, b = assembler.assemble_matrix_rhs()
        x = sps.linalg.spsolve(A, b)

        assembler.distribute_variable(x)

        # test pressure
        for g, d in gb:
            ap, _, _ = analytic_p(g.cell_centers)
            self.assertTrue(np.max(np.abs(d[pp.STATE][key_p] - ap)) < 5e-2)

        # test mortar solution
        for e, d_e in gb.edges():
            mg = d_e["mortar_grid"]
            g1, g2 = gb.nodes_of_edge(e)
            if g1 == g2:
                left_to_m = mg.master_to_mortar_avg()
                right_to_m = mg.slave_to_mortar_avg()
            else:
                continue
            d1 = gb.node_props(g1)
            d2 = gb.node_props(g2)

            _, analytic_flux, _ = analytic_p(g1.face_centers)
            # the aperture is assumed constant
            left_flux = np.sum(analytic_flux * g1.face_normals[:2], 0)
            left_flux = left_to_m * (
                d1[pp.DISCRETIZATION_MATRICES][kw]["bound_flux"] * left_flux
            )
            # right flux is negative lambda
            right_flux = np.sum(analytic_flux * g2.face_normals[:2], 0)
            right_flux = -right_to_m * (
                d2[pp.DISCRETIZATION_MATRICES][kw]["bound_flux"] * right_flux
            )
            self.assertTrue(np.max(np.abs(d_e[pp.STATE][key_m] - left_flux)) < 5e-2)
            self.assertTrue(np.max(np.abs(d_e[pp.STATE][key_m] - right_flux)) < 5e-2)
예제 #28
0
    def set_parameters(
        self,
        neu_val_top=None,
        dir_val_top=None,
        kn: float = 1e0,
        method="mpfa",
        aperture: float = 1e-1,
        gravity_angle: float = 0,
    ) -> None:
        """
        Parameters:
            neu_val_top (float): Default None implies Dirichlet on top. If not None,
                the prescribed value will be applied as the Neumann bc value.
            dir_val_top (float): If not None, the prescribed value will be
                applied as the Dirichlet bc value. Note that neu_val_top takes precedent
                over dir_val_top.
            method: Discretization method.
            kn: Normal permeability of the fracture. Will be multiplied by aperture/2
                to yield the normal diffusivity.
            aperture: Fracture aperture.
            gravity_angle: Angle by which to rotate the applied vector source field.
        """
        # Set up flow field with uniform flow in y-direction
        kw = "flow"
        gb = self.gb
        for g, d in gb:
            a = np.power(aperture, gb.dim_max() - g.dim)
            perm = pp.SecondOrderTensor(kxx=a * np.ones(g.num_cells))
            gravity = np.zeros((gb.dim_max(), g.num_cells))
            # Angle of zero means force vector of [0, -1]
            gravity[1, :] = -np.cos(gravity_angle)
            gravity[0, :] = np.sin(gravity_angle)

            b_val = np.zeros(g.num_faces)
            if g.dim == self.gb.dim_max():
                if neu_val_top is not None:
                    dir_faces = np.atleast_1d(pp.face_on_side(g, ["ymin"])[0])
                    neu_faces = np.atleast_1d(pp.face_on_side(g, ["ymax"])[0])
                    b_val[neu_faces] = neu_val_top
                else:
                    dir_faces = pp.face_on_side(g, ["ymin", "ymax"])
                    b_val[dir_faces[0]] = 0
                    if dir_val_top is not None:
                        b_val[dir_faces[1]] = dir_val_top
                    dir_faces = np.hstack((dir_faces[0], dir_faces[1]))
                labels = np.array(["dir"] * dir_faces.size)
                bc = pp.BoundaryCondition(g, dir_faces, labels)

            else:
                bc = pp.BoundaryCondition(g)
            parameter_dictionary = {
                "bc_values": b_val,
                "bc": bc,
                "ambient_dimension": gb.dim_max(),
                "mpfa_inverter": "python",
                "second_order_tensor": perm,
                "vector_source": gravity.ravel("F"),
            }
            pp.initialize_data(g, d, "flow", parameter_dictionary)

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            mg = d["mortar_grid"]
            a = aperture * np.ones(mg.num_cells)
            gravity = np.zeros((gb.dim_max(), mg.num_cells))
            # Angle of zero means force vector of [0, -1]
            gravity[1, :] = -np.cos(gravity_angle)
            gravity[0, :] = np.sin(gravity_angle)
            gravity *= a / 2
            parameter_dictionary = {
                "normal_diffusivity": 2 / a * kn,
                "ambient_dimension": gb.dim_max(),
                "vector_source": gravity.ravel("F"),
            }
            pp.initialize_data(mg, d, "flow", parameter_dictionary)

        # discretization_key = kw + "_" + pp.DISCRETIZATION

        for g, d in gb:
            # Choose discretization and define the solver
            if method == "mpfa":
                discr = pp.Mpfa(kw)
            elif method == "tpfa":
                discr = pp.Tpfa(kw)
            else:
                raise ValueError("Unexpected discretization method ")
예제 #29
0
def test_md_flow():

    # Three fractures, will create intersection lines and point
    frac_1 = np.array([[2, 4, 4, 2], [3, 3, 3, 3], [0, 0, 6, 6]])
    frac_2 = np.array([[3, 3, 3, 3], [2, 4, 4, 2], [0, 0, 6, 6]])
    frac_3 = np.array([[0, 6, 6, 0], [2, 2, 4, 4], [3, 3, 3, 3]])

    gb = pp.meshing.cart_grid(fracs=[frac_1, frac_2, frac_3],
                              nx=np.array([6, 6, 6]))
    gb.compute_geometry()

    pressure_variable = "pressure"
    flux_variable = "mortar_flux"

    keyword = "flow"
    discr = pp.Tpfa(keyword)
    source_discr = pp.ScalarSource(keyword)
    coupling_discr = pp.RobinCoupling(keyword, discr, discr)

    for g, d in gb:

        # Assign data
        if g.dim == gb.dim_max():
            upper_left_ind = np.argmax(np.linalg.norm(g.face_centers, axis=0))
            bc = pp.BoundaryCondition(g, np.array([0, upper_left_ind]),
                                      ["dir", "dir"])
            bc_values = np.zeros(g.num_faces)
            bc_values[0] = 1
            sources = np.random.rand(g.num_cells) * g.cell_volumes
            specified_parameters = {
                "bc": bc,
                "bc_values": bc_values,
                "source": sources
            }
        else:
            sources = np.random.rand(g.num_cells) * g.cell_volumes
            specified_parameters = {"source": sources}

        # Initialize data
        pp.initialize_default_data(g, d, keyword, specified_parameters)

        # Declare grid primary variable
        d[pp.PRIMARY_VARIABLES] = {pressure_variable: {"cells": 1}}

        # Assign discretization
        d[pp.DISCRETIZATION] = {
            pressure_variable: {
                "diff": discr,
                "source": source_discr
            }
        }

        # Initialize state
        d[pp.STATE] = {
            pressure_variable: np.zeros(g.num_cells),
            pp.ITERATE: {
                pressure_variable: np.zeros(g.num_cells)
            },
        }
    for e, d in gb.edges():
        mg = d["mortar_grid"]
        pp.initialize_data(mg, d, keyword, {"normal_diffusivity": 1})

        d[pp.PRIMARY_VARIABLES] = {flux_variable: {"cells": 1}}
        d[pp.COUPLING_DISCRETIZATION] = {}
        d[pp.COUPLING_DISCRETIZATION]["coupling"] = {
            e[0]: (pressure_variable, "diff"),
            e[1]: (pressure_variable, "diff"),
            e: (flux_variable, coupling_discr),
        }
        d[pp.STATE] = {
            flux_variable: np.zeros(mg.num_cells),
            pp.ITERATE: {
                flux_variable: np.zeros(mg.num_cells)
            },
        }

    dof_manager = pp.DofManager(gb)
    assembler = pp.Assembler(gb, dof_manager)
    assembler.discretize()

    # Reference discretization
    A_ref, b_ref = assembler.assemble_matrix_rhs()

    manager = pp.ad.EquationManager(gb, dof_manager)

    grid_list = [g for g, _ in gb]
    edge_list = [e for e, _ in gb.edges()]

    node_discr = pp.ad.MpfaAd(keyword, grid_list)

    edge_discr = pp.ad.RobinCouplingAd(keyword, edge_list)

    bc_val = pp.ad.BoundaryCondition(keyword, grid_list)

    source = pp.ad.ParameterArray(param_keyword=keyword,
                                  array_keyword='source',
                                  grids=grid_list)

    projections = pp.ad.MortarProjections(gb=gb)
    div = pp.ad.Divergence(grids=grid_list)

    p = manager.merge_variables([(g, pressure_variable) for g in grid_list])
    lmbda = manager.merge_variables([(e, flux_variable) for e in edge_list])

    flux = (node_discr.flux * p + node_discr.bound_flux * bc_val +
            node_discr.bound_flux * projections.mortar_to_primary_int * lmbda)
    flow_eq = div * flux - projections.mortar_to_secondary_int * lmbda - source

    interface_flux = edge_discr.mortar_scaling * (
        projections.primary_to_mortar_avg * node_discr.bound_pressure_cell * p
        + projections.primary_to_mortar_avg * node_discr.bound_pressure_face *
        projections.mortar_to_primary_int * lmbda -
        projections.secondary_to_mortar_avg * p +
        edge_discr.mortar_discr * lmbda)

    flow_eq_ad = pp.ad.Expression(flow_eq, dof_manager, "flow on nodes")
    flow_eq_ad.discretize(gb)

    interface_eq_ad = pp.ad.Expression(interface_flux, dof_manager,
                                       "flow on interface")

    manager.equations += [flow_eq_ad, interface_eq_ad]

    state = np.zeros(gb.num_cells() + gb.num_mortar_cells())
    A, b = manager.assemble_matrix_rhs(state=state)
    diff = A - A_ref
    if diff.data.size > 0:
        assert np.max(np.abs(diff.data)) < 1e-10
    assert np.max(np.abs(b - b_ref)) < 1e-10
예제 #30
0
    def test_tpfa_cart_2d(self):
        """ Apply TPFA 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
        })
        discr = pp.Tpfa(key)

        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
        self.assertTrue(a[mid, mid] == 4)
        self.assertTrue(a[mid - 1, mid] == -1)
        self.assertTrue(a[mid + 1, mid] == -1)
        self.assertTrue(a[mid - 3, mid] == -1)
        self.assertTrue(a[mid + 3, mid] == -1)

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

        # The first cell should have two Dirichlet bnds
        self.assertTrue(a[0, 0] == 6)
        self.assertTrue(a[0, 1] == -1)
        self.assertTrue(a[0, 3] == -1)

        self.assertTrue(b[0, 0] == 2)
        self.assertTrue(b[0, 12] == 2)

        # Cell 3 has one Dirichlet, one Neumann face
        self.assertTrue(a[2, 2] == 4)
        self.assertTrue(a[2, 1] == -1)
        self.assertTrue(a[2, 5] == -1)

        self.assertTrue(b[2, 3] == 2)
        self.assertTrue(b[2, 14] == -1)
        # Cell 2 has one Neumann face
        self.assertTrue(a[1, 1] == 3)
        self.assertTrue(a[1, 0] == -1)
        self.assertTrue(a[1, 2] == -1)
        self.assertTrue(a[1, 4] == -1)

        self.assertTrue(b[1, 13] == -1)

        return a