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