def test_flip_axis(self): """ We want to test the rotation of mixed conditions, but this is not so easy to compare because rotating the basis will change the type of boundary condition that is applied in the different directions. This test overcomes that by flipping the x- and y-axis and the flipping the boundary conditions also. """ g = pp.CartGrid([2, 2], [1, 1]) g.compute_geometry() nf = g.num_faces basis = np.array([[[0] * nf, [1] * nf], [[1] * nf, [0] * nf]]) bc = pp.BoundaryConditionVectorial(g) west = g.face_centers[0] < 1e-7 south = g.face_centers[1] < 1e-7 north = g.face_centers[1] > 1 - 1e-7 east = g.face_centers[0] > 1 - 1e-7 bc.is_dir[0, west] = True bc.is_rob[1, west] = True bc.is_rob[0, north] = True bc.is_neu[1, north] = True bc.is_dir[0, south] = True bc.is_neu[1, south] = True bc.is_dir[:, east] = True bc.is_neu[bc.is_dir + bc.is_rob] = False k = pp.FourthOrderTensor(np.random.rand(g.num_cells), np.random.rand(g.num_cells)) # Solve without rotations stress, bound_stress, _, _ = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") div = pp.fvutils.vector_divergence(g) u_bound = np.random.rand(g.dim, g.num_faces) u = np.linalg.solve((div * stress).A, -div * bound_stress * u_bound.ravel("F")) # Solve with rotations bc = pp.BoundaryConditionVectorial(g) bc.basis = basis bc.is_dir[1, west] = True bc.is_rob[0, west] = True bc.is_rob[1, north] = True bc.is_neu[0, north] = True bc.is_dir[1, south] = True bc.is_neu[0, south] = True bc.is_dir[:, east] = True bc.is_neu[bc.is_dir + bc.is_rob] = False stress_b, bound_stress_b, _, _ = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") u_bound_b = np.sum(basis * u_bound, axis=1) u_b = np.linalg.solve((div * stress_b).A, -div * bound_stress_b * u_bound_b.ravel("F")) # Assert that solutions are the same self.assertTrue(np.allclose(u, u_b))
def test_rotation(self): # we do a 45 degree rotation g = pp.CartGrid([1, 1]) bc = pp.BoundaryConditionVectorial(g) subcell_topology = pp.fvutils.SubcellTopology(g) bc.basis = np.array( [[[1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [-1, -1, -1, -1]]] ) BM = pp.fvutils.ExcludeBoundaries(subcell_topology, bc, g.dim).basis_matrix bm_ref = np.array( [ [1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, -1, 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, 1, 0, 0, 0, 0, 0, 0, 0, -1, 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, 1, 0, 0, 0, 0, 0, 0, 0, -1, 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, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1], ] ) self.assertTrue(np.allclose(BM.A, bm_ref))
def test_structured_triang(self): nx = 1 ny = 1 g = pp.StructuredTriangleGrid([nx, ny], physdims=[1, 1]) g.compute_geometry() bot = g.face_centers[1] < 1e-10 top = g.face_centers[1] > 1 - 1e-10 left = g.face_centers[0] < 1e-10 right = g.face_centers[0] > 1 - 1e-10 is_dir = left is_neu = top is_rob = right + bot bnd = pp.BoundaryConditionVectorial(g) bnd.is_neu[:] = False bnd.is_dir[:, is_dir] = True bnd.is_rob[:, is_rob] = True bnd.is_neu[:, is_neu] = True sc_top = pp.fvutils.SubcellTopology(g) bnd = pp.fvutils.boundary_to_sub_boundary(bnd, sc_top) bnd_excl = pp.fvutils.ExcludeBoundaries(sc_top, bnd, g.dim) rhs = pp.numerics.fv.mpsa.create_bound_rhs(bnd, bnd_excl, sc_top, g, True) hf2f = pp.fvutils.map_hf_2_f(sc_top.fno_unique, sc_top.subfno_unique, g.dim) rhs = rhs * hf2f.T rhs_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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 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, 1.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, 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, 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, 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, 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, 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, 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, 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, 0.0, 0.0, 0.0, 0.0, 0.0], ]) self.assertTrue(np.all(np.abs(rhs_known - rhs) < 1e-12))
def test_changing_bc(self): """ We test that we can change the boundary condition """ g = pp.StructuredTriangleGrid([2, 2], physdims=(1, 1)) g.compute_geometry() bc = pp.BoundaryConditionVectorial(g) k = pp.FourthOrderTensor(g.dim, np.ones(g.num_cells), np.ones(g.num_cells)) stress_neu, bound_stress_neu = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") bc.is_dir[:, g.get_all_boundary_faces()] = True bc.is_neu[bc.is_dir] = False stress_dir, bound_stress_dir = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") # Partiall should give same result as full faces = g.get_all_boundary_faces() stress, bound_stress = pp.numerics.fv.mpsa.mpsa_update_partial( stress_neu, bound_stress_neu, g, k, bc, faces=faces, inverter="python") self.assertTrue(np.allclose((stress - stress_dir).data, 0)) self.assertTrue(np.allclose((bound_stress - bound_stress_dir).data, 0))
def test_changing_bc_by_cells(self): """ Test that we can change the boundary condition by specifying the boundary cells """ g = pp.StructuredTetrahedralGrid([2, 2, 2], physdims=(1, 1, 1)) g.compute_geometry() bc = pp.BoundaryConditionVectorial(g) k = pp.FourthOrderTensor(g.dim, np.ones(g.num_cells), np.ones(g.num_cells)) stress_neu, bound_stress_neu = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") faces = g.face_centers[2] < 1e-10 bc.is_rob[:, faces] = True bc.is_neu[bc.is_rob] = False stress_rob, bound_stress_rob = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") # Update should not change anything cells = np.argwhere(g.cell_faces[faces, :])[:, 1].ravel() cells = np.unique(cells) stress, bound_stress = pp.numerics.fv.mpsa.mpsa_update_partial( stress_neu, bound_stress_neu, g, k, bc, cells=cells, inverter="python") self.assertTrue(np.allclose((stress - stress_rob).data, 0)) self.assertTrue(np.allclose((bound_stress - bound_stress_rob).data, 0))
def test_default(self): g = pp.CartGrid([1, 1]) bc = pp.BoundaryConditionVectorial(g) subcell_topology = pp.fvutils.SubcellTopology(g) BM = pp.fvutils.ExcludeBoundaries(subcell_topology, bc, g.dim).basis_matrix bm_ref = np.eye(2 * 2 * 4) self.assertTrue(np.allclose(BM.A, bm_ref))
def test_cart_2d(self): """ When not changing the parameters the output should equal the input """ g = pp.CartGrid([1, 1], physdims=(1, 1)) g.compute_geometry() bc = pp.BoundaryConditionVectorial(g) k = pp.FourthOrderTensor(np.ones(g.num_cells), np.ones(g.num_cells)) stress_full, bound_stress_full, hf_cell_full, hf_bound_full = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") # Update should not change anything faces = np.array([0, 3]) stress, bound_stress, hf_cell, hf_bound = pp.numerics.fv.mpsa.mpsa_update_partial( stress_full, bound_stress_full, hf_cell_full, hf_bound_full, g, k, bc, faces=faces, inverter="python", ) self.assertTrue(np.allclose((stress - stress_full).data, 0)) self.assertTrue(np.allclose((bound_stress - bound_stress_full).data, 0)) self.assertTrue(np.allclose((hf_cell - hf_cell_full).data, 0)) self.assertTrue(np.allclose((hf_bound - hf_bound_full).data, 0))
def test_uniform_displacement(self): g_list = setup_grids.setup_2d() for g in g_list: bound_faces = np.argwhere( np.abs(g.cell_faces).sum(axis=1).A.ravel("F") == 1) bound = pp.BoundaryConditionVectorial(g, bound_faces.ravel("F"), ["dir"] * bound_faces.size) constit = setup_stiffness(g) # Python inverter is most efficient for small problems stress, bound_stress, _, _ = mpsa.mpsa(g, constit, bound, inverter="python") div = fvutils.vector_divergence(g) a = div * stress d_x = np.random.rand(1) d_y = np.random.rand(1) d_bound = np.zeros((g.dim, g.num_faces)) d_bound[0, bound.is_dir[0]] = d_x d_bound[1, bound.is_dir[1]] = d_y rhs = div * bound_stress * d_bound.ravel("F") d = np.linalg.solve(a.todense(), -rhs) traction = stress * d + bound_stress * d_bound.ravel("F") self.assertTrue(np.max(np.abs(d[::2] - d_x)) < 1e-8) self.assertTrue(np.max(np.abs(d[1::2] - d_y)) < 1e-8) self.assertTrue(np.max(np.abs(traction)) < 1e-8)
def test_cart_2d(self): g = pp.CartGrid([2, 1], physdims=(1, 1)) g.compute_geometry() right = g.face_centers[0] > 1 - 1e-10 top = g.face_centers[1] > 1 - 1e-10 bc = pp.BoundaryConditionVectorial(g) bc.is_dir[:, top] = True bc.is_dir[0, right] = True bc.is_neu[bc.is_dir] = False g = true_2d(g) subcell_topology = pp.fvutils.SubcellTopology(g) # Mat boundary to subfaces bc = pp.fvutils.boundary_to_sub_boundary(bc, subcell_topology) bound_exclusion = pp.fvutils.ExcludeBoundaries(subcell_topology, bc, g.dim) cell_node_blocks = np.array([[0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 3, 4, 1, 2, 4, 5]]) ncasym_np = np.arange(32 * 32).reshape((32, 32)) ncasym = sps.csr_matrix(ncasym_np) pp.Mpsa("")._eliminate_ncasym_neumann(ncasym, subcell_topology, bound_exclusion, cell_node_blocks, 2) eliminate_ind = np.array([0, 1, 16, 17, 26, 27]) ncasym_np[eliminate_ind] = 0 self.assertTrue(np.allclose(ncasym.A, ncasym_np))
def setup_biot(self): g = pp.CartGrid([5, 5]) g.compute_geometry() stiffness = pp.FourthOrderTensor(np.ones(g.num_cells), np.ones(g.num_cells)) bnd = pp.BoundaryConditionVectorial(g) specified_data = { "fourth_order_tensor": stiffness, "bc": bnd, "inverter": "python", "biot_alpha": 1, } keyword_mech = "mechanics" keyword_flow = "flow" data = pp.initialize_default_data(g, {}, keyword_mech, specified_parameters=specified_data) data = pp.initialize_default_data(g, data, keyword_flow) discr = pp.Biot() discr.discretize(g, data) div_u = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.div_u_matrix_key] bound_div_u = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.bound_div_u_matrix_key] stab = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.stabilization_matrix_key] grad_p = data[pp.DISCRETIZATION_MATRICES][keyword_mech][ discr.grad_p_matrix_key] bound_pressure = data[pp.DISCRETIZATION_MATRICES][keyword_mech][ discr.bound_pressure_matrix_key] return g, stiffness, bnd, div_u, bound_div_u, grad_p, stab, bound_pressure
def test_changing_bc_by_nodes(self): """ Test that we can change the boundary condition by specifying the boundary nodes """ g = pp.CartGrid([2, 2], physdims=(1, 1)) g.compute_geometry() bc = pp.BoundaryConditionVectorial(g) k = pp.FourthOrderTensor(g.dim, np.ones(g.num_cells), np.ones(g.num_cells)) stress_neu, bound_stress_neu = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") faces = g.face_centers[1] > 1 - 1e-10 bc.is_dir[:, faces] = True bc.is_neu[bc.is_dir] = False stress_dir, bound_stress_dir = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") # Update should not change anything nodes = np.array([3, 5, 4, 6, 7, 8]) stress, bound_stress = pp.numerics.fv.mpsa.mpsa_update_partial( stress_neu, bound_stress_neu, g, k, bc, nodes=nodes, inverter="python") self.assertTrue(np.allclose((stress - stress_dir).data, 0)) self.assertTrue(np.allclose((bound_stress - bound_stress_dir).data, 0))
def setup(self): g = pp.CartGrid([5, 5]) g.compute_geometry() stiffness = pp.FourthOrderTensor(np.ones(g.num_cells), np.ones(g.num_cells)) bnd = pp.BoundaryConditionVectorial(g) specified_data = { "fourth_order_tensor": stiffness, "bc": bnd, "inverter": "python", } keyword = "mechanics" data = pp.initialize_default_data(g, {}, keyword, specified_parameters=specified_data) discr = pp.Mpsa(keyword) discr.discretize(g, data) stress = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.stress_matrix_key] bound_stress = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.bound_stress_matrix_key] return g, stiffness, bnd, stress, bound_stress
def test_no_change_input(self): """ The input matrices should not be changed """ g = pp.CartGrid([4, 4], physdims=(1, 1)) g.compute_geometry() bc = pp.BoundaryConditionVectorial(g) k = pp.FourthOrderTensor(np.ones(g.num_cells), np.ones(g.num_cells)) stress, bound_stress, hf_cell, hf_bound = pp.numerics.fv.mpsa.mpsa( g, k, bc, inverter="python") stress_old = stress.copy() bound_stress_old = bound_stress.copy() hf_cell_old = hf_cell.copy() hf_bound_old = hf_bound.copy() # Update should not change anything faces = np.array([0, 4, 5, 6]) _ = pp.numerics.fv.mpsa.mpsa_update_partial( stress, bound_stress, hf_cell, hf_bound, g, k, bc, faces=faces, inverter="python", ) self.assertTrue(np.allclose((stress - stress_old).data, 0)) self.assertTrue(np.allclose((bound_stress - bound_stress_old).data, 0)) self.assertTrue(np.allclose((hf_cell - hf_cell_old).data, 0)) self.assertTrue(np.allclose((hf_bound - hf_bound_old).data, 0))
def test_mix(self): nx = 2 ny = 1 g = pp.CartGrid([nx, ny], physdims=[1, 1]) g.compute_geometry() basis = np.random.rand(g.dim, g.dim, g.num_faces) bot = g.face_centers[1] < 1e-10 top = g.face_centers[1] > 1 - 1e-10 left = g.face_centers[0] < 1e-10 right = g.face_centers[0] > 1 - 1e-10 bc = pp.BoundaryConditionVectorial(g) bc.is_neu[:] = False bc.is_dir[0, left] = True bc.is_neu[1, left] = True bc.is_rob[0, right] = True bc.is_dir[1, right] = True bc.is_neu[0, bot] = True bc.is_rob[1, bot] = True bc.is_rob[0, top] = True bc.is_dir[1, top] = True self.run_test(g, basis, bc)
def make_boundary_conditions(self, g): bound_faces = g.get_all_boundary_faces() bound_flow = pp.BoundaryCondition(g, bound_faces.ravel("F"), ["dir"] * bound_faces.size) bound_mech = pp.BoundaryConditionVectorial(g, bound_faces.ravel("F"), ["dir"] * bound_faces.size) return bound_mech, bound_flow
def _bc_type(self, g: pp.Grid) -> pp.BoundaryConditionVectorial: """ We set Neumann values imitating an anisotropic background stress regime on all but three faces, which are fixed to ensure a unique solution. """ bc = pp.BoundaryConditionVectorial(g, g.get_all_boundary_faces(), "dir") return bc
def setup(self): g = pp.CartGrid([5, 5]) g.compute_geometry() stiffness = pp.FourthOrderTensor(np.ones(g.num_cells), np.ones(g.num_cells)) bnd = pp.BoundaryConditionVectorial(g) stress, bound_stress, _, _ = mpsa.mpsa(g, stiffness, bnd, inverter="python") return g, stiffness, bnd, stress, bound_stress
def bc_type_mechanics(self, g): all_bf, east, west, north, south, top, bottom = self.domain_boundary_sides( g) bc = pp.BoundaryConditionVectorial(g, north + south, "dir") frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc
def _bc_type_mechanics(self, g) -> pp.BoundaryConditionVectorial: """ Dirichlet values at top and bottom. """ all_bf, east, west, north, south, _, _ = self._domain_boundary_sides(g) dir_faces = south + north + g.tags["fracture_faces"] bc = pp.BoundaryConditionVectorial(g, dir_faces, "dir") return bc
def test_uniform_strain(self): g_list = setup_grids.setup_2d() for g in g_list: bound_faces = np.argwhere( np.abs(g.cell_faces).sum(axis=1).A.ravel("F") == 1) bound = pp.BoundaryConditionVectorial(g, bound_faces.ravel("F"), ["dir"] * bound_faces.size) mu = 1 l = 1 constit = setup_stiffness(g, mu, l) # Python inverter is most efficient for small problems stress, bound_stress, _, _ = mpsa.mpsa(g, constit, bound, inverter="python") div = fvutils.vector_divergence(g) a = div * stress xc = g.cell_centers xf = g.face_centers gx = np.random.rand(1) gy = np.random.rand(1) dc_x = np.sum(xc * gx, axis=0) dc_y = np.sum(xc * gy, axis=0) df_x = np.sum(xf * gx, axis=0) df_y = np.sum(xf * gy, axis=0) d_bound = np.zeros((g.dim, g.num_faces)) d_bound[0, bound.is_dir[0]] = df_x[bound.is_dir[0]] d_bound[1, bound.is_dir[1]] = df_y[bound.is_dir[1]] rhs = div * bound_stress * d_bound.ravel("F") d = np.linalg.solve(a.todense(), -rhs) traction = stress * d + bound_stress * d_bound.ravel("F") s_xx = (2 * mu + l) * gx + l * gy s_xy = mu * (gx + gy) s_yx = mu * (gx + gy) s_yy = (2 * mu + l) * gy + l * gx n = g.face_normals traction_ex_x = s_xx * n[0] + s_xy * n[1] traction_ex_y = s_yx * n[0] + s_yy * n[1] self.assertTrue(np.max(np.abs(d[::2] - dc_x)) < 1e-8) self.assertTrue(np.max(np.abs(d[1::2] - dc_y)) < 1e-8) self.assertTrue( np.max(np.abs(traction[::2] - traction_ex_x)) < 1e-8) self.assertTrue( np.max(np.abs(traction[1::2] - traction_ex_y)) < 1e-8)
def test_unit_slip(self): """ test unit slip of fractures """ frac = np.array([[1, 1, 1], [1, 2, 1], [2, 2, 1], [2, 1, 1]]).T physdims = np.array([3, 3, 2]) g = pp.meshing.cart_grid([frac], [3, 3, 2], physdims=physdims).grids_of_dimension(3)[0] data = {"param": pp.Parameters(g)} bound = pp.BoundaryConditionVectorial(g, g.get_all_boundary_faces(), "dir") data["param"].set_bc("mechanics", bound) frac_slip = np.zeros((g.dim, g.num_faces)) frac_bnd = g.tags["fracture_faces"] frac_slip[:, frac_bnd] = np.ones((g.dim, np.sum(frac_bnd))) data["param"].set_slip_distance(frac_slip.ravel("F")) solver = pp.FracturedMpsa() A, b = solver.matrix_rhs(g, data, inverter="python") u = np.linalg.solve(A.A, b) u_f = solver.extract_frac_u(g, u) u_c = solver.extract_u(g, u) u_c = u_c.reshape((3, -1), order="F") # obtain fracture faces and cells frac_faces = g.frac_pairs frac_left = frac_faces[0] frac_right = frac_faces[1] cell_left = np.ravel(np.argwhere(g.cell_faces[frac_left, :])[:, 1]) cell_right = np.ravel(np.argwhere(g.cell_faces[frac_right, :])[:, 1]) # Test traction T = solver.traction(g, data, u) T = T.reshape((3, -1), order="F") T_left = T[:, frac_left] T_right = T[:, frac_right] self.assertTrue(np.allclose(T_left, T_right)) # we have u_lhs - u_rhs = 1 so u_lhs should be positive self.assertTrue(np.all(u_c[:, cell_left] > 0)) self.assertTrue(np.all(u_c[:, cell_right] < 0)) mid_ind = int(round(u_f.size / 2)) u_left = u_f[:mid_ind] u_right = u_f[mid_ind:] self.assertTrue(np.all(np.abs(u_left - u_right - 1) < 1e-10)) # fracture displacement should be symetric since everything else is # symetric self.assertTrue(np.allclose(u_left, 0.5)) self.assertTrue(np.allclose(u_right, -0.5))
def test_neu(self): g = pp.StructuredTriangleGrid([2, 2]) basis = np.random.rand(g.dim, g.dim, g.num_faces) bc = pp.BoundaryConditionVectorial(g, g.get_all_boundary_faces(), "neu") # Add a Dirichlet condition so the system is well defined bc.is_dir[:, g.get_boundary_faces()[0]] = True bc.is_neu[bc.is_dir] = False self.run_test(g, basis, bc)
def test_default_basis_2d(self): g = pp.StructuredTriangleGrid([1, 1]) bc = pp.BoundaryConditionVectorial(g) basis_known = np.array([ [[1.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, 0.0], [1.0, 1.0, 1.0, 1.0, 1.0]], ]) self.assertTrue(np.allclose(bc.basis, basis_known))
def test_cart_2d(self): """ Test that mpsa gives out the correct matrices for reconstruction of the displacement at the faces """ nx = 1 ny = 1 g = pp.CartGrid([nx, ny], physdims=[2, 2]) g.compute_geometry() lam = np.array([1]) mu = np.array([2]) k = pp.FourthOrderTensor(mu, lam) bc = pp.BoundaryConditionVectorial(g) _, _, grad_cell, grad_bound = pp.numerics.fv.mpsa.mpsa( g, k, bc, hf_disp=True, inverter="python") grad_bound_known = np.array([ [0.10416667, 0.0, 0.0, 0.0, 0.0, -0.02083333, 0.0, 0.0], [0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.10416667, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02083333], [0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.10416667, 0.0, 0.0, 0.02083333, 0.0, 0.0], [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.10416667, 0.0, 0.0, 0.0, 0.0, -0.02083333], [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0], [-0.02083333, 0.0, 0.0, 0.0, 0.0, 0.10416667, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0], [0.0, 0.0, 0.02083333, 0.0, 0.0, 0.10416667, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0], [0.02083333, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.10416667], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0], [0.0, 0.0, -0.02083333, 0.0, 0.0, 0.0, 0.0, 0.10416667], ]) grad_cell_known = np.array([ [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], [1.0, 0.0], [0.0, 1.0], ]) self.assertTrue(np.all(np.abs(grad_bound - grad_bound_known) < 1e-7)) self.assertTrue(np.all(np.abs(grad_cell - grad_cell_known) < 1e-12))
def test_default_basis_3d(self): g = pp.StructuredTetrahedralGrid([1, 1, 1]) bc = pp.BoundaryConditionVectorial(g) basis_known = np.array([ [[1] * 18, [0] * 18, [0] * 18], [[0] * 18, [1] * 18, [0] * 18], [[0] * 18, [0] * 18, [1] * 18], ]) self.assertTrue(np.allclose(bc.basis, basis_known))
def bc_type(self, g): _, _, _, north, south, _, _ = self.domain_boundary_sides(g) bc = pp.BoundaryConditionVectorial(g, north + south, "dir") # Default internal BC is Neumann. We change to Dirichlet for the contact # problem. I.e., the mortar variable represents the displacement on the # fracture faces. frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc
def bc_type_mechanics(self, g): """ Dirichlet values at top and bottom. """ all_bf, east, west, north, south, _, _ = self.domain_boundary_sides(g) bc = pp.BoundaryConditionVectorial(g, south + north, "dir") frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc
def bc_type_mechanics(self, g: pp.Grid) -> pp.BoundaryConditionVectorial: # noqa # Define boundary regions all_bf = g.get_boundary_faces() bc = pp.BoundaryConditionVectorial(g, all_bf, "dir") # noqa # Internal faces are Neumann by default. We change them to # Dirichlet for the contact problem. That is: The mortar # variable represents the displacement on the fracture faces. frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc
def bc_type(self, g): """ Define type of boundary conditions: Dirichlet on all global boundaries, Dirichlet also on fracture faces. """ all_bf = g.get_boundary_faces() bc = pp.BoundaryConditionVectorial(g, all_bf, "dir") # Default internal BC is Neumann. We change to Dirichlet for the contact # problem. I.e., the mortar variable represents the displacement on the # fracture faces. frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc
def bc_type_mechanics(self, g) -> pp.BoundaryConditionVectorial: """ We set Neumann values imitating an anisotropic background stress regime on all but three faces, which are fixed to ensure a unique solution. """ all_bf, *_, bottom = self.domain_boundary_sides(g) faces = self.faces_to_fix(g) # write_fixed_faces_to_csv(g, faces, self) bc = pp.BoundaryConditionVectorial(g, faces, "dir") frac_face = g.tags["fracture_faces"] bc.is_neu[:, frac_face] = False bc.is_dir[:, frac_face] = True return bc