def test_boundary_faces_cart(self): g = pp.CartGrid([2, 1]) int_faces = g.get_internal_faces() self.assertTrue(int_faces.size == 1) self.assertTrue(int_faces[0] == 1)
def test_2d_horizontal_periodic_ambient_dim_2(method): # Cartesian grid in xy-plane with periodic boundary conditions. # Random size of the domain dx = np.random.rand(1)[0] # 2x2 grid of the random size g = pp.CartGrid([2, 2], [2 * dx, 2 * dx]) # The vector source is a 2-vector per cell ambient_dim = 2 # Discretization flux, vector_source_discr, div = set_params_disrcetize( g, ambient_dim, method, True) # Prepare to solve problem A = div * flux rhs = -div * vector_source_discr # Make source strength another random number grav_strength = np.random.rand(1) # introduce a source term in x-direction g_x = np.zeros(g.num_cells * ambient_dim) g_x[::ambient_dim] = -1 * grav_strength p_x = np.linalg.pinv(A.toarray()).dot(rhs * g_x) # The solution should be higher in the first x-row of cells, with magnitude # controlled by grid size and source stregth assert np.allclose(p_x[0] - p_x[1], dx * grav_strength) assert np.allclose(p_x[2] - p_x[3], dx * grav_strength) # The solution should be equal for equal x-coordinate assert np.allclose(p_x[0], p_x[2]) assert np.allclose(p_x[1], p_x[3]) flux_x = flux * p_x + vector_source_discr * g_x # The net flux should still be zero assert np.allclose(flux_x, 0) # Check matrices: A_known = np.array([ [3.0, -1.0, -2.0, 0.0], [-1.0, 3.0, 0.0, -2.0], [-2.0, 0.0, 3.0, -1.0], [0.0, -2.0, -1.0, 3.0], ]) # why 0.5? vct_src_known = (0.5 * dx * np.array([ [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, 0.0], [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, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], [0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], [0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], ])) assert np.allclose(A.A, A_known) assert np.allclose(vector_source_discr.A, vct_src_known)
def test_mixed_condition(self): nx = 2 ny = 1 g = pp.CartGrid([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 bnd = pp.BoundaryConditionVectorial(g) bnd.is_neu[:] = False bnd.is_dir[0, left] = True bnd.is_neu[1, left] = True bnd.is_rob[0, right] = True bnd.is_dir[1, right] = True bnd.is_neu[0, bot] = True bnd.is_rob[1, bot] = True bnd.is_rob[0, top] = True bnd.is_dir[1, top] = True sc_top = pp.fvutils.SubcellTopology(g) bnd_excl = pp.fvutils.ExcludeBoundaries(sc_top, bnd, g.dim) rhs = pp.numerics.fv.mpsa.create_bound_rhs_nd(bnd, bnd_excl, sc_top, g) 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.5, 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.5, 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0., 0., 0., 0., 0.], [0., 0.5, 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., 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., 0., 0.5, 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., 0., 0.5, 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.5, 0.], [0., 0., 0., 0., 0., 0., 0., 0.5, 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.5, 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0., 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., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 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., 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., 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.], ] ) self.assertTrue(np.all(np.abs(rhs_known - rhs) < 1e-12))
def test_overlap_2_layers(self): g = pp.CartGrid([5, 5]) ci = np.array([0, 1, 5, 6]) ci_overlap = np.array( [0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18]) assert np.array_equal(pp.partition.overlap(g, ci, 2), ci_overlap)
def test_2d(self): g = pp.CartGrid([1, 1]) z = np.arange(2) gn, *rest = pp.grid_extrusion.extrude_grid(g, z) self.assertTrue(gn.dim == 3)
def test_one_cell_a_time_node_keyword(self): # Update one and one cell, and verify that the result is the same as # with a single computation. The test is similar to what will happen # with a memory-constrained splitting. g = pp.CartGrid([3, 3]) g.compute_geometry() # Assign random permeabilities, for good measure np.random.seed(42) mu = np.random.random(g.num_cells) lmbda = np.random.random(g.num_cells) stiffness = pp.FourthOrderTensor(mu=mu, lmbda=lmbda) stress = sps.csr_matrix((g.num_faces * g.dim, g.num_cells * g.dim)) bound_stress = sps.csr_matrix( (g.num_faces * g.dim, g.num_faces * g.dim)) faces_covered = np.zeros(g.num_faces, np.bool) 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_full = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.stress_matrix_key] bound_stress_full = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.bound_stress_matrix_key] cn = g.cell_nodes() for ci in range(g.num_cells): ind = np.zeros(g.num_cells) ind[ci] = 1 nodes = np.squeeze(np.where(cn * ind > 0)) data[pp.PARAMETERS][keyword]["specified_nodes"] = nodes discr.discretize(g, data) partial_stress = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.stress_matrix_key] partial_bound = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.bound_stress_matrix_key] active_faces = data[pp.PARAMETERS][keyword]["active_faces"] if np.any(faces_covered): del_faces = self.expand_indices_nd( np.where(faces_covered)[0], g.dim) # del_faces is already expanded, set dimension to 1 pp.fvutils.remove_nonlocal_contribution( del_faces, 1, partial_stress, partial_bound) faces_covered[active_faces] = True stress += partial_stress bound_stress += partial_bound self.assertTrue((stress_full - stress).max() < 1e-8) self.assertTrue((stress_full - stress).min() > -1e-8) self.assertTrue((bound_stress - bound_stress_full).max() < 1e-8) self.assertTrue((bound_stress - bound_stress_full).min() > -1e-8)
def setUp(self): self.g = pp.CartGrid([3, 2])
def test_mass_matrix_2d(self): """ Test mass matrix in 2d for a simple geometry """ g = pp.CartGrid([3, 2], [1, 1]) g.compute_geometry() # Mass weight is scaled by aperture 0.01 specified_parameters = {"mass_weight": 0.5 * 1e-2} data = pp.initialize_default_data(g, {}, "flow", specified_parameters) discr = pp.MixedMassMatrix() discr.discretize(g, data) lhs, rhs = discr.assemble_matrix_rhs(g, data) lhs_known = ( 1.0 / 1200 * 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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], [ 0.0, 0.0, 0.0, 0.0, 0.0, 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, 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, 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, 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, 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, 1.0, ], ] ) ) self.assertTrue(np.allclose(lhs.toarray(), lhs_known)) self.assertTrue(np.allclose(rhs, 0))
Single grid only. The UpwindCouplingAd is not implemented yet (should be simple), and this example should be updated accordingly. Contact person: Eirik Keilegavlen """ import numpy as np import scipy.sparse as sps import scipy.sparse.linalg as spla import porepy as pp transport_key = "transport" g = pp.CartGrid([10]) g.compute_geometry() gb = pp.GridBucket() gb.add_nodes(g) data = gb.node_props(g) bc = pp.BoundaryCondition(g, np.array([0]), np.array(["dir"])) bc_values = np.zeros(g.num_faces) bc_values[0] = 1 transport_data = { "darcy_flux": np.ones(g.num_faces), "bc": bc, "bc_values": bc_values,
def _cart_grid_2d(fracs, nx, physdims=None): """ Create grids for a domain with possibly intersecting fractures in 2d. Based on lines describing the individual fractures, the method constructs grids in 2d (whole domain), 1d (individual fracture), and 0d (fracture intersections). Parameters ---------- fracs (list of np.ndarray, each 2x2): Vertexes of the line for each fracture. The fracture lines must align to the coordinat axis. The fractures will snap to the closest grid nodes. nx (np.ndarray): Number of cells in each direction. Should be 2D. physdims (np.ndarray): Physical dimensions in each direction. Defaults to same as nx, that is, cells of unit size. Returns ------- list (length 3): For each dimension (2 -> 0), a list of all grids in that dimension. Examples -------- frac1 = np.array([[1, 4], [2, 2]]) frac2 = np.array([[2, 2], [1, 4]]) fracs = [frac1, frac2] gb = cart_grid_2d(fracs, [5, 5]) """ nx = np.asarray(nx) if physdims is None: physdims = nx elif np.asarray(physdims).size != nx.size: raise ValueError("Physical dimension must equal grid dimension") else: physdims = np.asarray(physdims) g_2d = pp.CartGrid(nx, physdims=physdims) g_2d.global_point_ind = np.arange(g_2d.num_nodes) g_2d.compute_geometry() g_1d = [] g_0d = [] # 1D grids: shared_nodes = np.zeros(g_2d.num_nodes) for f in fracs: is_x_frac = f[1, 0] == f[1, 1] is_y_frac = f[0, 0] == f[0, 1] assert is_x_frac != is_y_frac, "Fracture must align to x- or y-axis" if f.shape[0] == 2: f = np.vstack((f, np.zeros(f.shape[1]))) nodes = _find_nodes_on_line(g_2d, nx, f[:, 0], f[:, 1]) # nodes = np.unique(nodes) loc_coord = g_2d.nodes[:, nodes] g = mesh_2_grid.create_embedded_line_grid(loc_coord, nodes) g_1d.append(g) shared_nodes[nodes] += 1 # Create 0-D grids if np.any(shared_nodes > 1): for global_node in np.argwhere(shared_nodes > 1).ravel(): g = pp.PointGrid(g_2d.nodes[:, global_node]) g.global_point_ind = np.asarray(global_node) g_0d.append(g) grids = [[g_2d], g_1d, g_0d] return grids
def test_3d_coarse_dims_specified_unequal_size(self): g = pp.CartGrid(np.array([6, 5, 4])) coarse_dims = np.array([3, 2, 2]) p = pp.partition.partition_structured(g, coarse_dims) # This just happens to be correct p_known = np.array([ 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 3, 3, 4, 4, 5, 5, 3, 3, 4, 4, 5, 5, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 3, 3, 4, 4, 5, 5, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 9, 9, 10, 10, 11, 11, 9, 9, 10, 10, 11, 11, 6, 6, 7, 7, 8, 8, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 9, 9, 10, 10, 11, 11, 9, 9, 10, 10, 11, 11, ]) self.assertTrue(np.allclose(p, p_known))
def _cart_grid_3d(fracs, nx, physdims=None): """ Create grids for a domain with possibly intersecting fractures in 3d. Based on rectangles describing the individual fractures, the method constructs grids in 3d (the whole domain), 2d (one for each individual fracture), 1d (along fracture intersections), and 0d (meeting between intersections). Parameters ---------- fracs (list of np.ndarray, each 3x4): Vertexes in the rectangle for each fracture. The vertices must be sorted and aligned to the axis. The fractures will snap to the closest grid faces. nx (np.ndarray): Number of cells in each direction. Should be 3D. physdims (np.ndarray): Physical dimensions in each direction. Defaults to same as nx, that is, cells of unit size. Returns ------- list (length 4): For each dimension (3 -> 0), a list of all grids in that dimension. Examples -------- frac1 = np.array([[1, 1, 4, 4], [1, 4, 4, 1], [2, 2, 2, 2]]) frac2 = np.array([[2, 2, 2, 2], [1, 1, 4, 4], [1, 4, 4, 1]]) fracs = [frac1, frac2] gb = cart_grid_3d(fracs, [5, 5, 5]) """ nx = np.asarray(nx) if physdims is None: physdims = nx elif np.asarray(physdims).size != nx.size: raise ValueError("Physical dimension must equal grid dimension") else: physdims = np.asarray(physdims) # We create a 3D cartesian grid. The global node mapping is trivial. g_3d = pp.CartGrid(nx, physdims=physdims) g_3d.global_point_ind = np.arange(g_3d.num_nodes) g_3d.compute_geometry() g_2d = [] g_1d = [] g_0d = [] # We set the tolerance for finding points in a plane. This can be any # small number, that is smaller than .25 of the cell sizes. tol = 0.1 * physdims / nx # Create 2D grids for fi, f in enumerate(fracs): assert np.all(f.shape == (3, 4)), "fractures must have shape [3,4]" is_xy_frac = np.allclose(f[2, 0], f[2]) is_xz_frac = np.allclose(f[1, 0], f[1]) is_yz_frac = np.allclose(f[0, 0], f[0]) assert (is_xy_frac + is_xz_frac + is_yz_frac == 1), "Fracture must align to x-, y- or z-axis" # snap to grid f_s = (np.round(f * nx[:, np.newaxis] / physdims[:, np.newaxis]) * physdims[:, np.newaxis] / nx[:, np.newaxis]) if is_xy_frac: flat_dim = [2] active_dim = [0, 1] elif is_xz_frac: flat_dim = [1] active_dim = [0, 2] else: flat_dim = [0] active_dim = [1, 2] # construct normal vectors. If the rectangle is ordered # clockwise we need to flip the normals so they point # outwards. sign = 2 * pp.geometry_property_checks.is_ccw_polygon( f_s[active_dim]) - 1 tangent = f_s.take(np.arange(f_s.shape[1]) + 1, axis=1, mode="wrap") - f_s normal = tangent normal[active_dim] = tangent[active_dim[1::-1]] normal[active_dim[1]] = -normal[active_dim[1]] normal = sign * normal # We find all the faces inside the convex hull defined by the # rectangle. To find the faces on the fracture plane, we remove any # faces that are further than tol from the snapped fracture plane. in_hull = pp.utils.half_space.half_space_int(normal, f_s, g_3d.face_centers) f_tag = np.logical_and( in_hull, np.logical_and( f_s[flat_dim, 0] - tol[flat_dim] <= g_3d.face_centers[flat_dim], g_3d.face_centers[flat_dim] < f_s[flat_dim, 0] + tol[flat_dim], ), ) f_tag = f_tag.ravel() nodes = sps.find(g_3d.face_nodes[:, f_tag])[0] nodes = np.unique(nodes) loc_coord = g_3d.nodes[:, nodes] g = _create_embedded_2d_grid(loc_coord, nodes) g.frac_num = fi g_2d.append(g) # Create 1D grids: # Here we make use of the network class to find the intersection of # fracture planes. We could maybe avoid this by doing something similar # as for the 2D-case, and count the number of faces belonging to each edge, # but we use the FractureNetwork class for now. frac_list = [] for f in fracs: frac_list.append(pp.Fracture(f)) # Combine the fractures into a network network = pp.FractureNetwork3d(frac_list) # Impose domain boundary. For the moment, the network should be immersed in # the domain, or else gmsh will complain. box = { "xmin": 0, "ymin": 0, "zmin": 0, "xmax": physdims[0], "ymax": physdims[1], "zmax": physdims[2], } network.impose_external_boundary(box) # Find intersections and split them. network.find_intersections() network.split_intersections() # Extract geometrical network information. pts = network.decomposition["points"] edges = network.decomposition["edges"] poly = network._poly_2_segment() # And tags identifying points and edges corresponding to normal # fractures, domain boundaries and subdomain boundaries. Only the # entities corresponding to normal fractures should actually be gridded. # TODO: Constraints have not been implemented for structured DFM grids. # Simply pass nothing for now, not sure how do deal with this, or if it at all is # meaningful. edge_tags, _, _ = network._classify_edges(poly, []) const = constants.GmshConstants() auxiliary_points, edge_tags = network._on_domain_boundary(edges, edge_tags) bound_and_aux = np.array([const.DOMAIN_BOUNDARY_TAG, const.AUXILIARY_TAG]) # From information of which lines are internal, we can find intersection points. # This part will become more elaborate if we introduce constraints, see the # FractureNetwork3d class. # Find all points on fracture intersection lines isect_p = edges[:, edge_tags == const.FRACTURE_INTERSECTION_LINE_TAG].ravel() # Count the number of occurences num_occ_pt = np.bincount(isect_p) # Intersection poitns if intersection_points = np.where(num_occ_pt > 1)[0] edges = np.vstack((edges, edge_tags)) # Loop through the edges to make 1D grids. Ommit the auxiliary edges. for e in np.ravel( np.where(edges[2] == const.FRACTURE_INTERSECTION_LINE_TAG)): # We find the start and end point of each fracture intersection (1D # grid) and then the corresponding global node index. if np.isin(edge_tags[e], bound_and_aux): continue s_pt = pts[:, edges[0, e]] e_pt = pts[:, edges[1, e]] nodes = _find_nodes_on_line(g_3d, nx, s_pt, e_pt) loc_coord = g_3d.nodes[:, nodes] assert (loc_coord.shape[1] > 1), "1d grid in intersection should span\ more than one node" g = mesh_2_grid.create_embedded_line_grid(loc_coord, nodes) g_1d.append(g) # Create 0D grids # Here we also use the intersection information from the FractureNetwork # class. No grids for auxiliary points. for p in intersection_points: if auxiliary_points[p] == const.DOMAIN_BOUNDARY_TAG: continue node = np.argmin(pp.distances.point_pointset(pts[:, p], g_3d.nodes)) assert np.allclose(g_3d.nodes[:, node], pts[:, p]) g = pp.PointGrid(g_3d.nodes[:, node]) g.global_point_ind = np.asarray(node) g_0d.append(g) grids = [[g_3d], g_2d, g_1d, g_0d] return grids
def test_get_internal_nodes_empty(self): g = pp.CartGrid([2, 1]) int_nodes = g.get_internal_nodes() self.assertTrue(int_nodes.size == 0)
def test_get_internal_nodes_cart(self): g = pp.CartGrid([2, 2]) int_nodes = g.get_internal_nodes() self.assertTrue(int_nodes.size == 1) self.assertTrue(int_nodes[0] == 4)
def conv_test(n): # Analytical solution def mandel_solution(g, Nx, Ny, times, F, B, nu_u, nu, c_f, mu_s): # Some needed parameters a = np.max(g.face_centers[0]) # a = Lx x_cntr = g.cell_centers[0][:Nx] # [m] vector of x-centers y_cntr = g.cell_centers[1][::Nx] # [m] vector of y-centers # Solutions to tan(x) - ((1-nu)/(nu_u-nu)) x = 0 """ This is somehow tricky, we have to solve the equation numerically in order to find all the positive solutions to the equation. Later we will use them to compute the infinite sums. Experience has shown that 200 roots are more than enough to achieve accurate results. Note that we find the roots using the bisection method. """ f = lambda x: np.tan(x) - ( (1 - nu) / (nu_u - nu)) * x # define the algebraic eq. as a lambda function n_series = 200 # number of roots a_n = np.zeros(n_series) # initializing roots array x0 = 0 # initial point for i in range(0, len(a_n)): a_n[i] = opt.bisect( f, # function x0 + np.pi / 4, # left point x0 + np.pi / 2 - 10000 * 2.2204e-16, # right point (a tiny bit less than pi/2) xtol=1e-30, # absolute tolerance rtol=1e-15 # relative tolerance ) x0 += np.pi # apply a phase change of pi to get the next root # Creating dictionary to store analytical solutions mandel_sol = dict() mandel_sol['p'] = np.zeros((len(times), len(x_cntr))) mandel_sol['u_x'] = np.zeros((len(times), len(x_cntr))) mandel_sol['u_y'] = np.zeros((len(times), len(y_cntr))) mandel_sol['sigma_yy'] = np.zeros((len(times), len(x_cntr))) # Terms needed to compute the solutions (these are constants) p0 = (2 * F * B * (1 + nu_u)) / (3 * a) ux0_1 = ((F * nu) / (2 * mu_s * a)) ux0_2 = -((F * nu_u) / (mu_s * a)) ux0_3 = F / mu_s uy0_1 = (-F * (1 - nu)) / (2 * mu_s * a) uy0_2 = (F * (1 - nu_u) / (mu_s * a)) sigma0_1 = -F / a sigma0_2 = (-2 * F * B * (nu_u - nu)) / (a * (1 - nu)) sigma0_3 = (2 * F) / a # Saving solutions for the initial conditions mandel_sol['p'][0] = ((F * B * (1 + nu_u)) / (3 * a)) * np.ones(Nx) mandel_sol['u_x'][0] = (F * nu_u * x_cntr) / (2 * mu_s * a) mandel_sol['u_y'][0] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * y_cntr # Storing solutions for the subsequent time steps for ii in range(1, len(times)): # Analytical Pressures p_sum = 0 for n in range(len(a_n)): p_sum += (((np.sin(a_n[n])) / (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) * (np.cos((a_n[n] * x_cntr) / a) - np.cos(a_n[n])) * np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2))) mandel_sol['p'][ii] = p0 * p_sum # Analytical horizontal displacements ux_sum1 = 0 ux_sum2 = 0 for n in range(len(a_n)): ux_sum1 += ((np.sin(a_n[n]) * np.cos(a_n[n])) / (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n])) * np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2))) ux_sum2 += ((np.cos(a_n[n]) / (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) * np.sin(a_n[n] * (x_cntr / a)) * np.exp( (-(a_n[n]**2) * c_f * times[ii]) / (a**2))) mandel_sol['u_x'][ii] = ( ux0_1 + ux0_2 * ux_sum1) * x_cntr + ux0_3 * ux_sum2 # Analytical vertical displacements uy_sum = 0 for n in range(len(a_n)): uy_sum += (((np.sin(a_n[n]) * np.cos(a_n[n])) / (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) * np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2))) mandel_sol['u_y'][ii] = (uy0_1 + uy0_2 * uy_sum) * y_cntr # Analitical vertical stress sigma_sum1 = 0 sigma_sum2 = 0 for n in range(len(a_n)): sigma_sum1 += (((np.sin(a_n[n])) / (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) * np.cos(a_n[n] * (x_cntr / a)) * np.exp( (-(a_n[n]**2) * c_f * times[ii]) / (a**2))) sigma_sum2 += (((np.sin(a_n[n]) * np.cos(a_n[n])) / (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) * np.exp( (-(a_n[n]**2) * c_f * times[ii]) / (a**2))) mandel_sol['sigma_yy'][ii] = (sigma0_1 + sigma0_2 * sigma_sum1) + ( sigma0_3 * sigma_sum2) return mandel_sol # Computing the initial condition def get_mandel_init_cond(g, F, B, nu_u, mu_s): # Initialing pressure and displacement arrays p0 = np.zeros(g.num_cells) u0 = np.zeros(g.num_cells * 2) # Some needed parameters a = np.max(g.face_centers[0]) # a = Lx p0 = ((F * B * (1 + nu_u)) / (3 * a)) * np.ones(g.num_cells) u0[::2] = (F * nu_u * g.cell_centers[0]) / (2 * mu_s * a) u0[1::2] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * g.cell_centers[1] return p0, u0 # Getting the time-dependent boundary condition def get_mandel_bc(g, y_max, times, F, B, nu_u, nu, c_f, mu_s): # Initializing top boundary array u_top = np.zeros((len(times), len(y_max))) # Some needed parameters a = np.max(g.face_centers[0]) # a = Lx b = np.max(g.face_centers[1]) # b = Ly y_top = g.face_centers[1][ y_max] # [m] y-coordinates at the top boundary # Solutions to tan(x) - ((1-nu)/(nu_u-nu)) x = 0 """ This is somehow tricky, we have to solve the equation numerically in order to find all the positive solutions to the equation. Later we will use them to compute the infinite sums. Experience has shown that 200 roots are more than enough to achieve accurate results. Note that we find the roots using the bisection method. """ f = lambda x: np.tan(x) - ( (1 - nu) / (nu_u - nu)) * x # define the algebraic eq. as a lambda function n_series = 200 # number of roots a_n = np.zeros(n_series) # initializing roots array x0 = 0 # initial point for i in range(0, len(a_n)): a_n[i] = opt.bisect( f, # function x0 + np.pi / 4, # left point x0 + np.pi / 2 - 10000 * 2.2204e-16, # right point (a tiny bit less than pi/2) xtol=1e-30, # absolute tolerance rtol=1e-15 # relative tolerance ) x0 += np.pi # apply a phase change of pi to get the next root # Terms needed to compute the solutions (these are constants) uy0_1 = (-F * (1 - nu)) / (2 * mu_s * a) uy0_2 = (F * (1 - nu_u) / (mu_s * a)) # For the initial condition: u_top[0] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * b for i in range(1, len(times)): # Analytical vertical displacements at the top boundary uy_sum = 0 for n in range(len(a_n)): uy_sum += (((np.sin(a_n[n]) * np.cos(a_n[n])) / (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) * np.exp((-(a_n[n]**2) * c_f * times[i]) / (a**2))) u_top[i] = (uy0_1 + uy0_2 * uy_sum) * y_top # Returning array of u_y at the top boundary return u_top # Getting mechanics boundary conditions def get_bc_mechanics(g, u_top, times, b_faces, x_min, x_max, west, east, y_min, y_max, south, north): # Setting the tags at each boundary side for the mechanics problem labels_mech = np.array([None] * b_faces.size) labels_mech[west] = 'dir_x' # roller labels_mech[east] = 'neu' # traction free labels_mech[south] = 'dir_y' # roller labels_mech[ north] = 'dir_y' # roller (with non-zero displacement in the vertical direction) # Constructing the bc object for the mechanics problem bc_mech = pp.BoundaryConditionVectorial(g, b_faces, labels_mech) # Constructing the boundary values array for the mechanics problem bc_val_mech = np.zeros(( len(times), g.num_faces * g.dim, )) for i in range(len(times)): # West side boundary conditions (mech) bc_val_mech[i][2 * x_min] = 0 # [m] bc_val_mech[i][2 * x_min + 1] = 0 # [Pa] # East side boundary conditions (mech) bc_val_mech[i][2 * x_max] = 0 # [Pa] bc_val_mech[i][2 * x_max + 1] = 0 # [Pa] # South Side boundary conditions (mech) bc_val_mech[i][2 * y_min] = 0 # [Pa] bc_val_mech[i][2 * y_min + 1] = 0 # [m] # North Side boundary conditions (mech) bc_val_mech[i][2 * y_max] = 0 # [Pa] bc_val_mech[i][2 * y_max + 1] = u_top[i] # [m] return bc_mech, bc_val_mech # Getting flow boundary conditions def get_bc_flow(g, b_faces, x_min, x_max, west, east, y_min, y_max, south, north): # Setting the tags at each boundary side for the mechanics problem labels_flow = np.array([None] * b_faces.size) labels_flow[west] = 'neu' # no flow labels_flow[east] = 'dir' # constant pressure labels_flow[south] = 'neu' # no flow labels_flow[north] = 'neu' # no flow # Constructing the bc object for the flow problem bc_flow = pp.BoundaryCondition(g, b_faces, labels_flow) # Constructing the boundary values array for the flow problem bc_val_flow = np.zeros(g.num_faces) # West side boundary condition (flow) bc_val_flow[x_min] = 0 # [Pa] # East side boundary condition (flow) bc_val_flow[x_max] = 0 # [m^3/s] # South side boundary condition (flow) bc_val_flow[y_min] = 0 # [m^3/s] # North side boundary condition (flow) bc_val_flow[y_max] = 0 # [m^3/s] return bc_flow, bc_val_flow # ## Setting up the grid # In[7]: Nx = 40 Ny = 40 Lx = 100 Ly = 10 g = pp.CartGrid([Nx, Ny], [Lx, Ly]) #g.nodes = g.nodes + 1E-7*np.random.randn(3, g.num_nodes) g.compute_geometry() V = g.cell_volumes # Physical parameters # Skeleton parameters mu_s = 2.475E+09 # [Pa] Shear modulus lambda_s = 1.65E+09 # [Pa] Lame parameter K_s = (2 / 3) * mu_s + lambda_s # [Pa] Bulk modulus E_s = mu_s * ((9 * K_s) / (3 * K_s + mu_s)) # [Pa] Young's modulus nu_s = (3 * K_s - 2 * mu_s) / (2 * (3 * K_s + mu_s) ) # [-] Poisson's coefficient k_s = 100 * 9.869233E-13 # [m^2] Permeabiliy # Fluid parameters mu_f = 10.0E-3 # [Pa s] Dynamic viscosity # Porous medium parameters alpha_biot = 1. # [m^2] Intrinsic permeability S_m = 6.0606E-11 # [1/Pa] Specific Storage K_u = K_s + (alpha_biot**2) / S_m # [Pa] Undrained bulk modulus B = alpha_biot / (S_m * K_u) # [-] Skempton's coefficient nu_u = (3 * nu_s + B * (1 - 2 * nu_s)) / (3 - B * (1 - 2 * nu_s)) # [-] Undrained Poisson's ratio c_f = (2 * k_s * (B**2) * mu_s * (1 - nu_s) * (1 + nu_u)**2) / (9 * mu_f * (1 - nu_u) * (nu_u - nu_s)) # [m^2/s] Fluid diffusivity # Creating second and fourth order tensors # Permeability tensor perm = pp.SecondOrderTensor(g.dim, k_s * np.ones(g.num_cells)) # Stiffness matrix constit = pp.FourthOrderTensor(g.dim, mu_s * np.ones(g.num_cells), lambda_s * np.ones(g.num_cells)) # Time parameters t0 = 0 # [s] Initial time tf = 100 # [s] Final simulation time tLevels = 100 # [-] Time levels times = np.linspace(t0, tf, tLevels + 1) # [s] Vector of time evaluations dt = np.diff(times) # [s] Vector of time steps # Boundary conditions pre-processing b_faces = g.tags['domain_boundary_faces'].nonzero()[0] # Extracting indices of boundary faces w.r.t g x_min = b_faces[g.face_centers[0, b_faces] < 0.0001] x_max = b_faces[g.face_centers[0, b_faces] > 0.9999 * Lx] y_min = b_faces[g.face_centers[1, b_faces] < 0.0001] y_max = b_faces[g.face_centers[1, b_faces] > 0.9999 * Ly] # Extracting indices of boundary faces w.r.t b_faces west = np.in1d(b_faces, x_min).nonzero() east = np.in1d(b_faces, x_max).nonzero() south = np.in1d(b_faces, y_min).nonzero() north = np.in1d(b_faces, y_max).nonzero() # Applied load and top boundary condition F_load = 6.8E+8 # [N/m] Applied load u_top = get_mandel_bc(g, y_max, times, F_load, B, nu_u, nu_s, c_f, mu_s) # [m] Vector of imposed vertical displacements # MECHANICS BOUNDARY CONDITIONS bc_mech, bc_val_mech = get_bc_mechanics(g, u_top, times, b_faces, x_min, x_max, west, east, y_min, y_max, south, north) # FLOW BOUNDARY CONDITIONS bc_flow, bc_val_flow = get_bc_flow(g, b_faces, x_min, x_max, west, east, y_min, y_max, south, north) # Initialiazing solution and solver dicitionaries # Solution dictionary sol = dict() sol['time'] = np.zeros(tLevels + 1, dtype=float) sol['displacement'] = np.zeros((tLevels + 1, g.num_cells * g.dim), dtype=float) sol['displacement_faces'] = np.zeros( (tLevels + 1, g.num_faces * g.dim * 2), dtype=float) sol['pressure'] = np.zeros((tLevels + 1, g.num_cells), dtype=float) sol['traction'] = np.zeros((tLevels + 1, g.num_faces * g.dim), dtype=float) sol['flux'] = np.zeros((tLevels + 1, g.num_faces), dtype=float) sol['iter'] = np.array([], dtype=int) sol['time_step'] = np.array([], dtype=float) sol['residual'] = np.array([], dtype=float) # Solver dictionary newton_param = dict() newton_param['tol'] = 1E-6 # maximum tolerance newton_param['max_iter'] = 20 # maximum number of iterations newton_param['res_norm'] = 1000 # initializing residual newton_param['iter'] = 1 # iteration # Discrete operators and discrete equations # Flow operators F = lambda x: biot_F * x # Flux operator boundF = lambda x: biot_boundF * x # Bound Flux operator compat = lambda x: biot_compat * x # Compatibility operator (Stabilization term) divF = lambda x: biot_divF * x # Scalar divergence operator # Mechanics operators S = lambda x: biot_S * x # Stress operator boundS = lambda x: biot_boundS * x # Bound Stress operator divU = lambda x: biot_divU * x # Divergence of displacement field divS = lambda x: biot_divS * x # Vector divergence operator gradP = lambda x: biot_divS * biot_gradP * x # Pressure gradient operator boundDivU = lambda x: biot_boundDivU * x # Bound Divergence of displacement operator boundUCell = lambda x: biot_boundUCell * x # Contribution of displacement at cells -> Face displacement boundUFace = lambda x: biot_boundUFace * x # Contribution of bc_mech at the boundaries -> Face displacement boundUPressure = lambda x: biot_boundUPressure * x # Contribution of pressure at cells -> Face displacement # Discrete equations # Generalized Hooke's law T = lambda u, bc_val_mech: S(u) + boundS(bc_val_mech) # Momentum conservation equation (I) u_eq1 = lambda u, bc_val_mech: divS(T(u, bc_val_mech)) # Momentum conservation equation (II) u_eq2 = lambda p: -gradP(p) # Darcy's law Q = lambda p: (1. / mu_f) * (F(p) + boundF(bc_val_flow)) # Mass conservation equation (I) p_eq1 = lambda u, u_n, bc_val_mech, bc_val_mech_n: alpha_biot * (divU( u - u_n) + boundDivU(bc_val_mech - bc_val_mech_n)) # Mass conservation equation (II) p_eq2 = lambda p, p_n, dt: (p - p_n) * S_m * V + divF(Q( p)) * dt + alpha_biot * compat(p - p_n) # Creating AD variables # Retrieve initial conditions p_init, u_init = get_mandel_init_cond(g, F_load, B, nu_u, mu_s) # Create displacement AD-variable u_ad = Ad_array(u_init.copy(), sps.diags(np.ones(g.num_cells * g.dim))) # Create pressure AD-variable p_ad = Ad_array(p_init.copy(), sps.diags(np.ones(g.num_cells))) # The time loop tt = 0 # time counter while times[tt] < times[-1]: ################################ # Initializing data dictionary # ################################ d = dict() # initialize dictionary to store data ################################ # Creating the data objects # ################################ # Mechanics data object specified_parameters_mech = { "fourth_order_tensor": constit, "bc": bc_mech, "biot_alpha": 1., "bc_values": bc_val_mech[tt], "mass_weight": S_m } pp.initialize_default_data(g, d, "mechanics", specified_parameters_mech) # Flow data object specified_parameters_flow = { "second_order_tensor": perm, "bc": bc_flow, "biot_alpha": 1., "bc_values": bc_val_flow, "mass_weight": S_m, "time_step": dt[tt - 1] } pp.initialize_default_data(g, d, "flow", specified_parameters_flow) ################################ # CALLING MPFA/MPSA ROUTINES # ################################ # Biot discretization solver_biot = pp.Biot("mechanics", "flow") solver_biot.discretize(g, d) # Mechanics discretization matrices biot_S = d['discretization_matrices']['mechanics']['stress'] biot_boundS = d['discretization_matrices']['mechanics']['bound_stress'] biot_divU = d['discretization_matrices']['mechanics']['div_d'] biot_gradP = d['discretization_matrices']['mechanics']['grad_p'] biot_boundDivU = d['discretization_matrices']['mechanics'][ 'bound_div_d'] biot_boundUCell = d['discretization_matrices']['mechanics'][ 'bound_displacement_cell'] biot_boundUFace = d['discretization_matrices']['mechanics'][ 'bound_displacement_face'] biot_boundUPressure = d['discretization_matrices']['mechanics'][ 'bound_displacement_pressure'] biot_divS = pp.fvutils.vector_divergence(g) # Flow discretization matrices biot_F = d['discretization_matrices']['flow']['flux'] biot_boundF = d['discretization_matrices']['flow']['bound_flux'] biot_compat = d['discretization_matrices']['flow'][ 'biot_stabilization'] biot_divF = pp.fvutils.scalar_divergence(g) ################################ # Saving Initial Condition # ################################ if times[tt] == 0: sol['pressure'][tt] = p_ad.val sol['displacement'][tt] = u_ad.val sol['displacement_faces'][tt] = ( boundUCell(sol['displacement'][tt]) + boundUFace(bc_val_mech[tt]) + boundUPressure(sol['pressure'][tt])) sol['time'][tt] = times[tt] sol['traction'][tt] = T(u_ad.val, bc_val_mech[tt]) sol['flux'][tt] = Q(p_ad.val) tt += 1 # increasing time counter ################################ # Solving the set of PDE's # ################################ # Displacement and pressure at the previous time step u_n = u_ad.val.copy() p_n = p_ad.val.copy() # Updating residual and iteration at each time step newton_param.update({'res_norm': 1000, 'iter': 1}) # Newton loop while newton_param['res_norm'] > newton_param['tol'] and newton_param[ 'iter'] <= newton_param['max_iter']: # Calling equations eq1 = u_eq1(u_ad, bc_val_mech[tt]) eq2 = u_eq2(p_ad) eq3 = p_eq1(u_ad, u_n, bc_val_mech[tt], bc_val_mech[tt - 1]) eq4 = p_eq2(p_ad, p_n, dt[tt - 1]) # Assembling Jacobian of the coupled system J_mech = np.hstack( (eq1.jac, eq2.jac)) # Jacobian blocks (mechanics) J_flow = np.hstack((eq3.jac, eq4.jac)) # Jacobian blocks (flow) J = sps.bmat(np.vstack((J_mech, J_flow)), format='csc') # Jacobian (coupled) # Determining residual of the coupled system R_mech = eq1.val + eq2.val # Residual (mechanics) R_flow = eq3.val + eq4.val # Residual (flow) R = np.hstack((R_mech, R_flow)) # Residual (coupled) y = sps.linalg.spsolve(J, -R) # u_ad.val = u_ad.val + y[:g.dim * g.num_cells] # Newton update p_ad.val = p_ad.val + y[g.dim * g.num_cells:] # newton_param['res_norm'] = np.linalg.norm(R) # Updating residual if newton_param['res_norm'] <= newton_param[ 'tol'] and newton_param['iter'] <= newton_param['max_iter']: print('Iter: {} \t Error: {:.8f} [m]'.format( newton_param['iter'], newton_param['res_norm'])) elif newton_param['iter'] > newton_param['max_iter']: print('Error: Newton method did not converge!') else: newton_param['iter'] += 1 ################################ # Saving the variables # ################################ sol['iter'] = np.concatenate( (sol['iter'], np.array([newton_param['iter']]))) sol['residual'] = np.concatenate( (sol['residual'], np.array([newton_param['res_norm']]))) sol['time_step'] = np.concatenate((sol['time_step'], dt)) sol['pressure'][tt] = p_ad.val sol['displacement'][tt] = u_ad.val sol['displacement_faces'][tt] = (boundUCell(sol['displacement'][tt]) + boundUFace(bc_val_mech[tt]) + boundUPressure(sol['pressure'][tt])) sol['time'][tt] = times[tt] sol['traction'][tt] = T(u_ad.val, bc_val_mech[tt]) sol['flux'][tt] = Q(p_ad.val) # Calling analytical solution sol_mandel = mandel_solution(g, Nx, Ny, times, F_load, B, nu_u, nu_s, c_f, mu_s) # Creating analytical and numerical results arrays p_num = (Lx * sol['pressure'][-1][:Nx]) / F p_ana = (Lx * sol_mandel['p'][-1]) / F # Returning values return p_num, p_ana
def test_dir_neu_rob(self): nx = 2 ny = 1 g = pp.CartGrid([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.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, -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, 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_one_cell_a_time_node_keyword(self): # Update one and one cell, and verify that the result is the same as # with a single computation. # The test is similar to what will happen with a memory-constrained # splitting. g = pp.CartGrid([3, 3]) g.compute_geometry() # Assign random permeabilities, for good measure np.random.seed(42) kxx = np.random.random(g.num_cells) kyy = np.random.random(g.num_cells) # Ensure positive definiteness kxy = np.random.random(g.num_cells) * kxx * kyy perm = pp.SecondOrderTensor(kxx=kxx, kyy=kyy, kxy=kxy) flux = sps.csr_matrix((g.num_faces, g.num_cells)) bound_flux = sps.csr_matrix((g.num_faces, g.num_faces)) vc = sps.csr_matrix((g.num_faces, g.num_cells * g.dim)) faces_covered = np.zeros(g.num_faces, np.bool) bnd = pp.BoundaryCondition(g) cn = g.cell_nodes() for ci in range(g.num_cells): ind = np.zeros(g.num_cells) ind[ci] = 1 nodes = np.squeeze(np.where(cn * ind > 0)) specified_data = { "second_order_tensor": perm, "bc": bnd, "inverter": "python", "specified_nodes": nodes, } keyword = "flow" data = pp.initialize_default_data( g, {}, keyword, specified_parameters=specified_data) discr = pp.Mpfa(keyword) discr.discretize(g, data) partial_flux = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.flux_matrix_key] partial_bound = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.bound_flux_matrix_key] partial_vector_source = data[pp.DISCRETIZATION_MATRICES][keyword][ discr.vector_source_matrix_key] active_faces = data[pp.PARAMETERS][keyword]["active_faces"] if np.any(faces_covered): fi = np.where(faces_covered)[0] pp.fvutils.remove_nonlocal_contribution( fi, 1, partial_flux, partial_bound, partial_vector_source) faces_covered[active_faces] = True flux += partial_flux bound_flux += partial_bound vc += partial_vector_source flux_full, bound_flux_full, *_, vc_full, _ = pp.Mpfa( "flow")._flux_discretization(g, perm, bnd, inverter="python") self.assertTrue((flux_full - flux).max() < 1e-8) self.assertTrue((flux_full - flux).min() > -1e-8) self.assertTrue((bound_flux - bound_flux_full).max() < 1e-8) self.assertTrue((bound_flux - bound_flux_full).min() > -1e-8) self.assertTrue((vc - vc_full).max() < 1e-8) self.assertTrue((vc - vc_full).min() > -1e-8)
def test_tag_3d_cart(self): g = pp.CartGrid([4] * 3, [1] * 3) self.assertTrue( np.array_equal(g.tags["fracture_faces"], [False] * g.num_faces)) self.assertTrue( np.array_equal(g.tags["fracture_nodes"], [False] * g.num_nodes)) self.assertTrue( np.array_equal(g.tags["tip_faces"], [False] * g.num_faces)) self.assertTrue( np.array_equal(g.tags["tip_nodes"], [False] * g.num_nodes)) known = np.array( [ True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, ], dtype=bool, ) self.assertTrue(np.array_equal(g.tags["domain_boundary_faces"], known)) known = np.array( [ True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, True, True, False, False, False, True, True, False, False, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, ], dtype=bool, ) self.assertTrue(np.array_equal(g.tags["domain_boundary_nodes"], known))
def _test_one_cell_a_time_node_keyword(self): # EK: this test makes less sense after the notion of partial updates were # changed (git commit 41f754940). Decactive the test for now, pending an update # of the notion of discretization updates for FV methods. # Update one and one cell, and verify that the result is the same as # with a single computation. The test is similar to what will happen # with a memory-constrained splitting. g = pp.CartGrid([3, 3]) g.compute_geometry() # Assign random permeabilities, for good measure np.random.seed(42) mu = np.random.random(g.num_cells) lmbda = np.random.random(g.num_cells) stiffness = pp.FourthOrderTensor(mu=mu, lmbda=lmbda) nd = g.dim nf = g.num_faces nc = g.num_cells grad_p = sps.csr_matrix((nf * nd, nc)) div_u = sps.csr_matrix((nc, nc * nd)) bound_div_u = sps.csr_matrix((nc, nf * nd)) stab = sps.csr_matrix((nc, nc)) bound_displacement_pressure = sps.csr_matrix((nf * nd, nc)) faces_covered = np.zeros(g.num_faces, np.bool) cells_covered = np.zeros(g.num_cells, np.bool) 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_full = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.div_u_matrix_key] bound_div_u_full = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.bound_div_u_matrix_key] stab_full = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.stabilization_matrix_key] grad_p_full = data[pp.DISCRETIZATION_MATRICES][keyword_mech][ discr.grad_p_matrix_key] bound_pressure_full = data[pp.DISCRETIZATION_MATRICES][keyword_mech][ discr.bound_pressure_matrix_key] cn = g.cell_nodes() for ci in range(g.num_cells): ind = np.zeros(g.num_cells) ind[ci] = 1 nodes = np.squeeze(np.where(cn * ind > 0)) data[pp.PARAMETERS][keyword_mech]["specified_nodes"] = nodes discr.discretize(g, data) partial_div_u = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.div_u_matrix_key] partial_bound_div_u = data[pp.DISCRETIZATION_MATRICES][ keyword_flow][discr.bound_div_u_matrix_key] partial_grad_p = data[pp.DISCRETIZATION_MATRICES][keyword_mech][ discr.grad_p_matrix_key] partial_stab = data[pp.DISCRETIZATION_MATRICES][keyword_flow][ discr.stabilization_matrix_key] partial_bound_pressure = data[pp.DISCRETIZATION_MATRICES][ keyword_mech][discr.bound_pressure_matrix_key] active_faces = data[pp.PARAMETERS][keyword_mech]["active_faces"] if np.any(faces_covered): del_faces = self.expand_indices_nd( np.where(faces_covered)[0], g.dim) del_cells = np.where(cells_covered)[0] pp.fvutils.remove_nonlocal_contribution( del_cells, 1, partial_div_u, partial_bound_div_u, partial_stab) # del_faces is already expanded, set dimension to 1 pp.fvutils.remove_nonlocal_contribution( del_faces, 1, partial_grad_p, partial_bound_pressure) faces_covered[active_faces] = True cells_covered[ci] = True div_u += partial_div_u bound_div_u += partial_bound_div_u grad_p += partial_grad_p stab += partial_stab bound_displacement_pressure += partial_bound_pressure self.assertTrue((div_u_full - div_u).max() < 1e-8) self.assertTrue((bound_div_u_full - bound_div_u).min() > -1e-8) self.assertTrue((grad_p_full - grad_p).max() < 1e-8) self.assertTrue((stab_full - stab).min() > -1e-8) self.assertTrue( (bound_displacement_pressure - bound_pressure_full).min() > -1e-8)
def test_2d(self): """ The domain consists of a 3x3 mesh. Bottom faces are dirichlet Left and right faces are rolling along y (dir_x and neu_y) Top mid face is rolling along x (neu_x and dir_y) Top left and right faces are neumann """ g = pp.CartGrid([3, 3]) g.compute_geometry() nd = g.dim dir_x = np.array([0, 3, 4, 7, 8, 11]) dir_y = np.array([22]) dir_both = np.array([12, 13, 14]) bound = pp.BoundaryConditionVectorial(g) bound.is_dir[0, dir_x] = True bound.is_neu[0, dir_x] = False bound.is_dir[1, dir_y] = True bound.is_neu[1, dir_y] = False bound.is_dir[:, dir_both] = True bound.is_neu[:, dir_both] = False subcell_topology = pp.fvutils.SubcellTopology(g) # Move the boundary conditions to sub-faces bound.is_dir = bound.is_dir[:, subcell_topology.fno_unique] bound.is_rob = bound.is_rob[:, subcell_topology.fno_unique] bound.is_neu = bound.is_neu[:, subcell_topology.fno_unique] bound.robin_weight = bound.robin_weight[:, :, subcell_topology.fno_unique] bound.basis = bound.basis[:, :, subcell_topology.fno_unique] # Obtain the face number for each coordinate subfno = subcell_topology.subfno_unique subfno_nd = np.tile(subfno, (nd, 1)) * nd + np.atleast_2d(np.arange(0, nd)).T bound_exclusion = pp.fvutils.ExcludeBoundaries(subcell_topology, bound, nd) # expand the indices # Define right hand side for Neumann boundary conditions # First row indices in rhs matrix # Pick out the subface indices subfno_neu = bound_exclusion.exclude_robin_dirichlet( subfno_nd.ravel("C")).ravel("F") # Pick out the Neumann boundary is_neu_nd = (bound_exclusion.exclude_robin_dirichlet( bound.is_neu.ravel("C")).ravel("F").astype(np.bool)) neu_ind = np.argsort(subfno_neu) neu_ind = neu_ind[is_neu_nd[neu_ind]] self.assertTrue( np.alltrue(neu_ind == [ 30, 31, 36, 37, 38, 39, 44, 45, 46, 47, 52, 53, 24, 66, 25, 67, 26, 27, 28, 68, 29, 69, ])) subfno_dir = bound_exclusion.exclude_neumann_robin( subfno_nd.ravel("C")).ravel("F") is_dir_nd = (bound_exclusion.exclude_neumann_robin( bound.is_dir.ravel("C")).ravel("F").astype(np.bool)) dir_ind = np.argsort(subfno_dir) dir_ind = dir_ind[is_dir_nd[dir_ind]] self.assertTrue( np.alltrue(dir_ind == [ 0, 1, 6, 7, 8, 9, 14, 15, 16, 17, 22, 23, 24, 54, 25, 55, 26, 56, 27, 57, 28, 58, 29, 59, 72, 73, ]))
def test_overlap_1_layer(self): g = pp.CartGrid([5, 5]) ci = np.array([0, 1, 5, 6]) ci_overlap = np.array([0, 1, 2, 5, 6, 7, 10, 11, 12]) assert np.array_equal(pp.partition.overlap(g, ci, 1), ci_overlap)
r1 = np.ravel(np.argwhere((g.nodes[0] < domain[0] - 1e-10) & (g.nodes[0] > 1e-10) & (g.nodes[1] < hi - alpha) & (g.nodes[1] > 1e-10))) r2 = np.ravel(np.argwhere((g.nodes[0] < domain[0] - 1e-10) & (g.nodes[0] > 1e-10) & (g.nodes[1] < ht - 1e-10) & (g.nodes[1] > hi + alpha))) #r3 = np.ravel(np.argwhere((g.nodes[0] < 1 - 1e-10) & (g.nodes[0] > 1e-10) & (g.nodes[1] < 0.75 - 1e-10) & (g.nodes[1] > 0.5 + 1e-10))) #r4 = np.ravel(np.argwhere((g.nodes[0] < 1 - 1e-10) & (g.nodes[0] > 1e-10) & (g.nodes[1] < 1.0 - 1e-10) & (g.nodes[1] > 0.75 + 1e-10))) pert_nodes = np.concatenate((r1, r2)) npertnodes = pert_nodes.size rand = np.vstack((np.random.rand(g.dim, npertnodes), np.repeat(0., npertnodes))) g.nodes[:,pert_nodes] += rate * dx * (rand - 0.5) # Ensure there are no perturbations in the z-coordinate if g.dim == 2: g.nodes[2, :] = 0 np.random.seed(42) return g g = pp.CartGrid(grid_dims, domain) dx = np.max(domain / grid_dims) alpha = 0.5 * dx if pert != 0: g = perturb(g, pert, dx, alpha) g.compute_geometry() t, s, p, q = solve_two_phase_flow_upwind(g) # Create a workbook and add a worksheet. workbook = xlsxwriter.Workbook('upwind_hperm_n64.xlsx') worksheet = workbook.add_worksheet()
def setup(self): g = pp.CartGrid([4, 4]) p = pp.partition.partition_structured(g, np.array([2, 2])) return g, p
def test_cart_2d(self): nx = 1 ny = 1 g = pp.CartGrid([nx, ny], physdims=[2, 2]) g.compute_geometry() g = make_true_2d(g) sc_top = pp.fvutils.SubcellTopology(g) D_g, CC = pp.numerics.fv.mpsa.reconstruct_displacement(g, sc_top, eta=0) D_g_known = np.array([ [ -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, -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, -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, 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, 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, -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, -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, -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, 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, 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, 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, 1.0, ], ]) CC_known = np.array([ [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], [1, 0.0], [0, 1.0], ]) self.assertTrue(np.all(np.abs(D_g - D_g_known) < 1e-12)) self.assertTrue(np.all(np.abs(CC - CC_known) < 1e-12))
def test_3d(self): g = pp.CartGrid([1, 1, 1]) z = np.arange(2) self.assertRaises(ValueError, pp.grid_extrusion.extrude_grid, g, z)
def test_cart_3d(self): g = pp.CartGrid([1, 1, 1], physdims=[2, 2, 2]) g.compute_geometry() sc_top = pp.fvutils.SubcellTopology(g) D_g, CC = pp.numerics.fv.mpsa.reconstruct_displacement(g, sc_top, eta=1) data = 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.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.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.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, ]) indices = np.array([ 0, 24, 48, 1, 25, 49, 2, 26, 50, 12, 33, 51, 13, 34, 52, 14, 35, 53, 3, 36, 57, 4, 37, 58, 5, 38, 59, 15, 45, 54, 16, 46, 55, 17, 47, 56, 9, 27, 60, 10, 28, 61, 11, 29, 62, 21, 30, 63, 22, 31, 64, 23, 32, 65, 6, 39, 69, 7, 40, 70, 8, 41, 71, 18, 42, 66, 19, 43, 67, 20, 44, 68, ]) indptr = np.array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, ]) CC_known = np.array([ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], ]) D_g_known = sps.csc_matrix((data, indices, indptr)) self.assertTrue(np.all(np.abs(D_g - D_g_known).A < 1e-12)) self.assertTrue(np.all(np.abs(CC - CC_known) < 1e-12))
def make_grid(grid, grid_dims, domain): if grid.lower() == "cart": return pp.CartGrid(grid_dims, domain) elif grid.lower() == "triangular": return pp.StructuredTriangleGrid(grid_dims, domain)
# print(norm_now) x_prev = x_new f_prev = f_new if norm_now < norm_orig * 1e-10: return x_new # If we get here, convergence has not been achieved. Not sure what to do then. # Take a break before continuing? breakpoint() return x_new # Define a grid, and wrap it in a GridBucket (this makes the future extension to true # md problems easier). g = pp.CartGrid([150]) g.compute_geometry() gb = pp.GridBucket() gb.add_nodes(g) # Use the above functions to find intial composition of the system, based on # given values for total concentrations T. # NOTE: For Momas, insert medium B will have a different composition init_T_B. init_T_A = np.array([0, -2, 0, 2, 0]) # Initial guess. guess_x0 = np.array([1, -1, 1, 0.3, 0.01]) # Initial values for X_i on log form init_X_A_log = newton_on_function(equilibration_func, guess_x0, init_T_A) # .. and on standard form init_X_A = np.exp(init_X_A_log)
def test_cart_3d(self): g = pp.CartGrid([1, 1, 1]) g.compute_geometry() bot = g.face_centers[2] < 1e-10 top = g.face_centers[2] > 1 - 1e-10 south = g.face_centers[1] < 1e-10 north = g.face_centers[1] > 1 - 1e-10 west = g.face_centers[0] < 1e-10 east = g.face_centers[0] > 1 - 1e-10 is_dir = south + top is_neu = east + west is_rob = north + 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_excl = pp.fvutils.ExcludeBoundaries(sc_top, bnd, g.dim) rhs = pp.numerics.fv.mpsa.create_bound_rhs_nd(bnd, bnd_excl, sc_top, g) rhs_indptr = np.array( [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, ], dtype=np.int32, ) rhs_indices = np.array( [ 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2, 5, 5, 5, 5, 9, 9, 9, 9, 12, 12, 12, 12, 10, 10, 10, 10, 13, 13, 13, 13, 11, 11, 11, 11, 14, 14, 14, 14, 6, 6, 6, 6, 15, 15, 15, 15, 7, 7, 7, 7, 16, 16, 16, 16, 8, 8, 8, 8, 17, 17, 17, 17, ], dtype=np.int32, ) rhs_data = np.array( [ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, -1., -1., -1., -1., 1., 1., 1., 1., -1., -1., -1., -1., 1., 1., 1., 1., -1., -1., -1., -1., 1., 1., 1., 1., ] ) rhs_known = sps.csr_matrix((rhs_data, rhs_indices, rhs_indptr), shape=(72, 18)) self.assertTrue(np.all(np.abs((rhs_known - rhs).data) < 1e-12))
def test_bounary_node_cart(self): g = pp.CartGrid([2, 2]) bound_ind = g.get_boundary_nodes() known_bound = np.array([0, 1, 2, 3, 5, 6, 7, 8]) self.assertTrue(np.allclose(np.sort(bound_ind), known_bound))