示例#1
0
    def test_assemble_biot_rhs_transient(self):
        """ Test the assembly of a Biot problem with a non-zero rhs using the assembler.

        The test checks whether the discretization matches that of the Biot class and
        that the solution reaches the expected steady state.
        """
        gb = pp.meshing.cart_grid([], [3, 3], physdims=[1, 1])
        g = gb.grids_of_dimension(2)[0]
        d = gb.node_props(g)

        # Parameters identified by two keywords. Non-default parameters of somewhat
        # arbitrary values are assigned to make the test more revealing.
        kw_m = "mechanics"
        kw_f = "flow"
        variable_m = "displacement"
        variable_f = "pressure"
        bound_mech, bound_flow = self.make_boundary_conditions(g)
        val_mech = np.ones(g.dim * g.num_faces)
        val_flow = np.ones(g.num_faces)
        initial_disp, initial_pressure, initial_state = self.make_initial_conditions(
            g, x0=1, y0=2, p0=0)
        dt = 1e0
        biot_alpha = 0.6
        state = {
            variable_f: initial_pressure,
            variable_m: initial_disp,
            kw_m: {
                "bc_values": val_mech
            },
        }
        parameters_m = {
            "bc": bound_mech,
            "bc_values": val_mech,
            "time_step": dt,
            "biot_alpha": biot_alpha,
        }
        parameters_f = {
            "bc": bound_flow,
            "bc_values": val_flow,
            "time_step": dt,
            "biot_alpha": biot_alpha,
            "mass_weight": 0.1 * np.ones(g.num_cells),
        }
        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)
        # Initial condition fot the Biot class
        #        d["state"] = initial_state

        # 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: IE_discretizations.ImplicitMassMatrix(kw_f, v_1),
                term_11_1: IE_discretizations.ImplicitMpfa(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)
            },
        }

        # Discretize the mechanics related terms using the Biot class
        biot_discretizer = pp.Biot()
        biot_discretizer._discretize_mech(g, d)

        general_assembler = pp.Assembler(gb)
        # Discretize terms that are not handled by the call to biot_discretizer
        general_assembler.discretize(term_filter=["fluid_mass", "fluid_flux"])

        times = np.arange(5)
        for _ in times:
            # Assemble. Also discretizes the flow terms (fluid_mass and fluid_flux)
            A, b = general_assembler.assemble_matrix_rhs()

            # Assemble using the Biot class
            A_class, b_class = biot_discretizer.matrix_rhs(g,
                                                           d,
                                                           discretize=False)

            # 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)))

            # Store the current solution for the next time step.
            x_i = sps.linalg.spsolve(A_class, b_class)
            u_i = x_i[:(g.dim * g.num_cells)]
            p_i = x_i[(g.dim * g.num_cells):]
            state = {variable_f: p_i, variable_m: u_i}
            pp.set_state(d, state)

        # Check that the solution has converged to the expected, uniform steady state
        # dictated by the BCs.
        self.assertTrue(
            np.all(np.isclose(x_i, np.ones((g.dim + 1) * g.num_cells))))
示例#2
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.matrix_rhs(g, d, discretize=False)

        # 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)))
    def test_upwind_coupling_3d_2d_1d_0d(self):
        f1 = np.array([[0, 1, 1, 0], [0, 0, 1, 1], [0.5, 0.5, 0.5, 0.5]])
        f2 = np.array([[0.5, 0.5, 0.5, 0.5], [0, 1, 1, 0], [0, 0, 1, 1]])
        f3 = np.array([[0, 1, 1, 0], [0.5, 0.5, 0.5, 0.5], [0, 0, 1, 1]])

        gb = pp.meshing.cart_grid([f1, f2, f3], [2, 2, 2],
                                  **{"physdims": [1, 1, 1]})
        gb.compute_geometry()
        gb.assign_node_ordering()

        cell_centers1 = np.array([[0.25, 0.75, 0.25, 0.75],
                                  [0.25, 0.25, 0.75, 0.75],
                                  [0.5, 0.5, 0.5, 0.5]])
        cell_centers2 = np.array([[0.5, 0.5, 0.5, 0.5],
                                  [0.25, 0.25, 0.75, 0.75],
                                  [0.75, 0.25, 0.75, 0.25]])
        cell_centers3 = np.array([[0.25, 0.75, 0.25,
                                   0.75], [0.5, 0.5, 0.5, 0.5],
                                  [0.25, 0.25, 0.75, 0.75]])
        cell_centers4 = np.array([[0.5], [0.25], [0.5]])
        cell_centers5 = np.array([[0.5], [0.75], [0.5]])
        cell_centers6 = np.array([[0.75], [0.5], [0.5]])
        cell_centers7 = np.array([[0.25], [0.5], [0.5]])
        cell_centers8 = np.array([[0.5], [0.5], [0.25]])
        cell_centers9 = np.array([[0.5], [0.5], [0.75]])

        for g, d in gb:
            if np.allclose(g.cell_centers[:, 0], cell_centers1[:, 0]):
                d["node_number"] = 1
            elif np.allclose(g.cell_centers[:, 0], cell_centers2[:, 0]):
                d["node_number"] = 2
            elif np.allclose(g.cell_centers[:, 0], cell_centers3[:, 0]):
                d["node_number"] = 3
            elif np.allclose(g.cell_centers[:, 0], cell_centers4[:, 0]):
                d["node_number"] = 4
            elif np.allclose(g.cell_centers[:, 0], cell_centers5[:, 0]):
                d["node_number"] = 5
            elif np.allclose(g.cell_centers[:, 0], cell_centers6[:, 0]):
                d["node_number"] = 6
            elif np.allclose(g.cell_centers[:, 0], cell_centers7[:, 0]):
                d["node_number"] = 7
            elif np.allclose(g.cell_centers[:, 0], cell_centers8[:, 0]):
                d["node_number"] = 8
            elif np.allclose(g.cell_centers[:, 0], cell_centers9[:, 0]):
                d["node_number"] = 9
            else:
                pass

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            n1 = gb.node_props(g1, "node_number")
            n2 = gb.node_props(g2, "node_number")
            if n1 == 1 and n2 == 0:
                d["edge_number"] = 0
            elif n1 == 2 and n2 == 0:
                d["edge_number"] = 1
            elif n1 == 3 and n2 == 0:
                d["edge_number"] = 2
            elif n1 == 4 and n2 == 1:
                d["edge_number"] = 3
            elif n1 == 5 and n2 == 1:
                d["edge_number"] = 4
            elif n1 == 6 and n2 == 1:
                d["edge_number"] = 5
            elif n1 == 7 and n2 == 1:
                d["edge_number"] = 6
            elif n1 == 4 and n2 == 2:
                d["edge_number"] = 7
            elif n1 == 5 and n2 == 2:
                d["edge_number"] = 8
            elif n1 == 8 and n2 == 2:
                d["edge_number"] = 9
            elif n1 == 9 and n2 == 2:
                d["edge_number"] = 10
            elif n1 == 6 and n2 == 3:
                d["edge_number"] = 11
            elif n1 == 7 and n2 == 3:
                d["edge_number"] = 12
            elif n1 == 8 and n2 == 3:
                d["edge_number"] = 13
            elif n1 == 9 and n2 == 3:
                d["edge_number"] = 14
            elif n1 == 10 and n2 == 4:
                d["edge_number"] = 15
            elif n1 == 10 and n2 == 5:
                d["edge_number"] = 16
            elif n1 == 10 and n2 == 6:
                d["edge_number"] = 17
            elif n1 == 10 and n2 == 7:
                d["edge_number"] = 18
            elif n1 == 10 and n2 == 8:
                d["edge_number"] = 19
            elif n1 == 10 and n2 == 9:
                d["edge_number"] = 20
            else:
                raise ValueError

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # assign parameters
        tol = 1e-3
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}
            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:

                bound_face_centers = g.face_centers[:, bound_faces]

                left = bound_face_centers[0, :] < tol
                right = bound_face_centers[0, :] > 1 - tol

                labels = np.array(["neu"] * bound_faces.size)
                labels[np.logical_or(left, right)] = ["dir"]

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})

            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)
        assembler = pp.Assembler(gb)

        assembler.discretize()
        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"
        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)

        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)
        (
            U_known,
            rhs_known,
        ) = (_helper_test_upwind_coupling.
             matrix_rhs_for_test_upwind_coupling_3d_2d_1d_0d())

        theta_known = np.array([
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1,
            1,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -0.25,
            -0.25,
            -0.25,
            -0.25,
            0.25,
            0.25,
            0.25,
            0.25,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -5.0e-03,
            5.0e-03,
            -5.0e-03,
            5.0e-03,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            -5e-03,
            5e-03,
            -5e-03,
            5e-03,
            0,
            0,
            -1e-04,
            1e-04,
            0,
            0,
        ])

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
    def test_upwind_coupling_2d_1d_left_right(self):
        gb, _ = pp.grid_buckets_2d.single_horizontal([1, 2], simplex=False)

        tol = 1e-3
        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # assign parameters

        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:

            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}
            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:
                bound_face_centers = g.face_centers[:, bound_faces]

                left = bound_face_centers[0, :] < tol
                right = bound_face_centers[0, :] > 1 - tol

                labels = np.array(["neu"] * bound_faces.size)
                labels[np.logical_or(left, right)] = ["dir"]

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})

            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)

        U_known = np.array([
            [0.5, 0.0, 0.0, 0.0, 1.0],
            [0.0, 0.5, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.01, -1.0, -1.0],
            [0.0, 0.0, 0.0, -1.0, 0.0],
            [0.0, 0.0, 0.0, 0.0, -1.0],
        ])

        rhs_known = np.array([0.5, 0.5, 1e-2, 0, 0])
        theta_known = np.array([1, 1, 1, 0, 0])

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
    def test_upwind_coupling_2d_1d_left_right_cross(self):
        gb, _ = pp.grid_buckets_2d.two_intersecting([2, 2], simplex=False)

        # Enforce node orderning because of Python 3.5 and 2.7.
        # Don't do it in general.
        cell_centers_1 = np.array([
            [7.50000000e-01, 2.5000000e-01],
            [0.50000000e00, 0.50000000e00],
            [-5.55111512e-17, 5.55111512e-17],
        ])
        cell_centers_2 = np.array([
            [0.50000000e00, 0.50000000e00],
            [7.50000000e-01, 2.5000000e-01],
            [-5.55111512e-17, 5.55111512e-17],
        ])

        for g, d in gb:
            if g.dim == 2:
                d["node_number"] = 0
            elif g.dim == 1:
                if np.allclose(g.cell_centers, cell_centers_1):
                    d["node_number"] = 1
                elif np.allclose(g.cell_centers, cell_centers_2):
                    d["node_number"] = 2
                else:
                    raise ValueError("Grid not found")
            elif g.dim == 0:
                d["node_number"] = 3
            else:
                raise ValueError

        for e, d in gb.edges():
            g1, g2 = gb.nodes_of_edge(e)
            n1 = gb.node_props(g1, "node_number")
            n2 = gb.node_props(g2, "node_number")
            if n1 == 1 and n2 == 0:
                d["edge_number"] = 0
            elif n1 == 2 and n2 == 0:
                d["edge_number"] = 1
            elif n1 == 3 and n2 == 1:
                d["edge_number"] = 2
            elif n1 == 3 and n2 == 2:
                d["edge_number"] = 3
            else:
                raise ValueError

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        # define parameters
        tol = 1e-3
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}

            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            if bound_faces.size != 0:
                bound_face_centers = g.face_centers[:, bound_faces]

                left = bound_face_centers[0, :] < tol
                right = bound_face_centers[0, :] > 1 - tol

                labels = np.array(["neu"] * bound_faces.size)
                labels[np.logical_or(left, right)] = ["dir"]

                bc_val = np.zeros(g.num_faces)
                bc_dir = bound_faces[np.logical_or(left, right)]
                bc_val[bc_dir] = 1

                bound = pp.BoundaryCondition(g, bound_faces, labels)
                specified_parameters.update({"bc": bound, "bc_values": bc_val})
            else:
                bound = pp.BoundaryCondition(g, np.empty(0), np.empty(0))
                specified_parameters.update({"bc": bound})
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 0, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"
        U, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(U.A, rhs)
        #        deltaT = solver.cfl(gb)
        U_known = np.array([
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.5,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -0.01,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
            ],
        ])

        theta_known = np.array([
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            0,
            0,
            0,
            0,
            -0.5,
            -0.5,
            0.5,
            0.5,
            0.01,
            -0.01,
            0,
            0,
        ])

        rhs_known = np.array([
            0.5,
            0.0,
            0.5,
            0.0,
            0.0,
            0.01,
            0.0,
            0.0,
            0.0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ])

        rtol = 1e-15
        atol = rtol

        self.assertTrue(np.allclose(U.todense(), U_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
    def test_upwind_2d_full_beta_bc_dir(self):

        f = np.array([[2, 2], [0, 2]])
        gb = pp.meshing.cart_grid([f], [4, 2])
        gb.assign_node_ordering()
        gb.compute_geometry()

        # define discretization
        key = "transport"
        variable = "T"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        assign_discretization(gb, upwind, upwind_coupling, variable)

        a = 1e-1
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            specified_parameters = {"aperture": aperture}

            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            labels = np.array(["dir"] * bound_faces.size)
            bc_val = np.zeros(g.num_faces)
            bc_val[bound_faces] = 3

            bound = pp.BoundaryCondition(g, bound_faces, labels)
            specified_parameters.update({"bc": bound, "bc_values": bc_val})
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [1, 1, 0], a)

        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        M, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)
        theta = np.linalg.solve(M.A, rhs)
        M_known = np.array([
            [
                2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 1.0
            ],
            [
                0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, -1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                -1.0,
                0.0,
                0.0,
                -1.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
            ],
            [
                0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                -1.0,
                2.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.1,
                -0.1,
                -1.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.1,
                0.0,
                -1.0,
                0.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                -1.0, 0.0
            ],
            [
                0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, -1.0
            ],
        ])

        rhs_known = np.array([
            6.0, 3.0, 3.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0,
            0.0
        ])

        theta_known = np.array([
            3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, -3.0, -3.0, 3.0,
            3.0
        ])

        rtol = 1e-15
        atol = rtol
        self.assertTrue(np.allclose(M.todense(), M_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))
    def test_upwind_2d_beta_positive(self):

        f = np.array([[2, 2], [0, 2]])
        gb = pp.meshing.cart_grid([f], [4, 2])
        gb.assign_node_ordering()
        gb.compute_geometry()

        # define discretization
        key = "transport"
        upwind = pp.Upwind(key)
        upwind_coupling = pp.UpwindCoupling(key)
        variable = "T"
        assign_discretization(gb, upwind, upwind_coupling, variable)

        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim)
            bf = g.tags["domain_boundary_faces"].nonzero()[0]
            bc = pp.BoundaryCondition(g, bf, bf.size * ["neu"])
            specified_parameters = {"aperture": aperture, "bc": bc}
            pp.initialize_default_data(g, d, "transport", specified_parameters)

        add_constant_darcy_flux(gb, upwind, [2, 0, 0], a)
        assembler = pp.Assembler(gb)
        assembler.discretize()

        U_tmp, rhs = assembler.assemble_matrix_rhs()

        grids = np.empty(gb.num_graph_nodes() + gb.num_graph_edges(),
                         dtype=np.object)
        variables = np.empty_like(grids)
        for g, d in gb:
            grids[d["node_number"]] = g
            variables[d["node_number"]] = variable
        for e, d in gb.edges():
            grids[d["edge_number"] + gb.num_graph_nodes()] = e
            variables[d["edge_number"] + gb.num_graph_nodes()] = "lambda_u"

        M, rhs = permute_matrix_vector(U_tmp, rhs, assembler.block_dof,
                                       assembler.full_dof, grids, variables)

        # add generic mass matrix to solve system
        I_diag = np.zeros(M.shape[0])
        I_diag[:gb.num_cells()] = 1
        I = np.diag(I_diag)
        theta = np.linalg.solve(M + I, I_diag + rhs)
        M_known = np.array([
            [
                2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 1.0
            ],
            [
                0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                1.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, 0.0
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -1.0,
                0.0,
                -1.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -2.0,
                0.0,
                -1.0,
                0.0,
                0.0,
                0.0,
            ],
            [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                -2.0,
                0.0,
                -1.0,
                0.0,
                0.0,
            ],
            [
                0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                -1.0, 0.0
            ],
            [
                0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                0.0, -1.0
            ],
        ])
        rhs_known = np.zeros(14)
        theta_known = np.array([
            0.33333333,
            0.55555556,
            0.80246914,
            2.60493827,
            0.33333333,
            0.55555556,
            0.80246914,
            2.60493827,
            0.7037037,
            0.7037037,
            -1.40740741,
            -1.40740741,
            1.11111111,
            1.11111111,
        ])

        rtol = 1e-8
        atol = rtol

        self.assertTrue(np.allclose(M.A, M_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
        self.assertTrue(np.allclose(theta, theta_known, rtol, atol))