def test_merge_grids_reverse_order(self): g = pp.TensorGrid(np.arange(3)) h = pp.TensorGrid(np.arange(3)) h.nodes = h.nodes[:, ::-1] g.compute_geometry() h.compute_geometry() weights, new, old = pp.match_grids.match_1d(g, h, tol=1e-4) self.assertTrue(np.allclose(weights, np.array([1, 1]))) # In this case, we don't know which ordering the combined grid uses # Instead, make sure that the two mappings are ordered in separate # directions self.assertTrue(np.allclose(new[::-1], old))
def test_merge_grids_non_matching(self): g = pp.TensorGrid(np.arange(3)) h = pp.TensorGrid(np.arange(3)) h.nodes[0, 1] = 0.5 g.compute_geometry() h.compute_geometry() weights, new, old = pp.match_grids.match_1d(g, h, tol=1e-4) # Weights give mappings from h to g. The first cell in h is # fully within the first cell in g. The second in h is split 1/3 # in first of g, 2/3 in second. self.assertTrue(np.allclose(weights, np.array([1, 1.0 / 3, 2.0 / 3]))) self.assertTrue(np.allclose(new, np.array([0, 0, 1]))) self.assertTrue(np.allclose(old, np.array([0, 1, 1])))
def test_1d_ambient_dim_1(method): dx = np.random.rand(1)[0] g = pp.TensorGrid(np.array([0, dx, 2 * dx])) ambient_dim = 1 flux, vector_source_discr, div = set_params_disrcetize( g, ambient_dim, method) # 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 # /2 * dx p_x = np.linalg.pinv(A.toarray()).dot(rhs * g_x) # The solution should decrease with increasing x coordinate, with magnitude # controlled by grid size and source stregth assert np.allclose(p_x[0] - p_x[1], dx * grav_strength) flux_x = flux * p_x + vector_source_discr * g_x # The net flux should still be zero assert np.allclose(flux_x, 0)
def generate_2d_grid(self, n, xmax, ymax): g1 = pp.CartGrid([xmax * n, ymax * n], physdims=[xmax, ymax]) g1.compute_geometry() gb = pp.GridBucket() gb.add_nodes(g1) tol = 1e-6 left_faces = np.argwhere(g1.face_centers[1] > ymax - tol).ravel() right_faces = np.argwhere(g1.face_centers[1] < 0 + tol).ravel() val = np.ones(left_faces.size, dtype=np.bool) shape = [g1.num_faces, g1.num_faces] face_faces = sps.coo_matrix((val, (right_faces, left_faces)), shape=shape) gb.add_edge((g1, g1), face_faces) mg = pp.TensorGrid(np.linspace(0, xmax, n + 1)) mg.nodes[1] = ymax mg.compute_geometry() d_e = gb.edge_props((g1, g1)) d_e["mortar_grid"] = pp.BoundaryMortar(g1.dim - 1, mg, face_faces) gb.assign_node_ordering() return gb
def test_merge_1d_grids_partly_equal_nodes(self): g = pp.TensorGrid(np.array([0, 1, 2])) h = pp.TensorGrid(np.array([0, 0.5, 1, 2])) g.compute_geometry() h.compute_geometry() ( gh, offset, g_in_comb, h_in_comb, g_sort, h_sort, ) = non_conforming.merge_1d_grids(g, h, global_ind_offset=0, tol=1e-4) self.assertTrue(np.allclose(gh.nodes[:, g_in_comb], g.nodes[:, g_sort])) self.assertTrue(np.allclose(gh.nodes[:, h_in_comb], h.nodes[:, h_sort]))
def grid_1d(self, n_nodes=2): x = np.linspace(0, 1, n_nodes) g = pp.TensorGrid(x) g.nodes = np.tile(x, (3, 1)) g.compute_geometry() g.global_point_ind = 1 + np.arange(n_nodes) return g
def test_merge_1d_grids_equal_nodes(self): g = pp.TensorGrid(np.array([0, 1, 2])) g.compute_geometry() h, offset, g_in_comb, g_in_comb, g_sort, _ = non_conforming.merge_1d_grids( g, g, global_ind_offset=0, tol=1e-4 ) self.assertTrue(np.allclose(h.nodes[:, g_in_comb], g.nodes[:, g_sort]))
def grid_1d(self, num_pts=3) -> pp.Grid: g = pp.TensorGrid(np.arange(num_pts)) g.nodes = np.vstack( (np.linspace(0, 1, num_pts), 0.5 * np.ones(num_pts), np.zeros(num_pts)) ) g.compute_geometry() g.global_point_ind = np.arange(g.num_nodes) return g
def test_merge_grids_all_common(self): g = pp.TensorGrid(np.arange(3)) g.compute_geometry() weights, new, old = pp.match_grids.match_1d(g, g, tol=1e-4) self.assertTrue(np.allclose(weights, np.ones(2))) self.assertTrue(np.allclose(old, np.arange(2))) self.assertTrue(np.allclose(new, np.arange(2)))
def test_merge_1d_permuted_nodes(self): g = pp.TensorGrid(np.array([0, 1, 2])) g.nodes = np.array([[1, -1, 0], [0, 0, 0], [0, 0, 0]]) g.global_point_ind = np.array([2, 0, 1]) g.face_nodes.indices = np.array([1, 2, 0]) h = pp.TensorGrid(np.array([-1, 0, 1])) h.global_point_ind = np.array([0, 1, 2]) g.compute_geometry() h.compute_geometry() c, _, _, _, _, _ = non_conforming.merge_1d_grids(g, h) ismem, maps = ismember_rows(c.global_point_ind, g.global_point_ind) self.assertTrue(ismem.sum() == c.num_nodes) self.assertTrue(np.allclose(g.nodes[:, maps], c.nodes)) ismem, maps = ismember_rows(c.global_point_ind, h.global_point_ind) self.assertTrue(ismem.sum() == c.num_nodes) self.assertTrue(np.allclose(h.nodes[:, maps], c.nodes))
def test_merge_1d_grids_rotation(self): # 1d grids rotated g = pp.TensorGrid(np.array([0, 1, 2])) g.nodes = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]]).T g.compute_geometry() h = pp.TensorGrid(np.array([0, 1, 2])) h.nodes = np.array([[0, 0, 0], [0.5, 0.5, 0.5], [2, 2, 2]]).T h.compute_geometry() ( gh, offset, g_in_comb, h_in_comb, g_sort, h_sort, ) = non_conforming.merge_1d_grids(g, h, global_ind_offset=0) self.assertTrue(np.allclose(gh.nodes[:, g_in_comb], g.nodes[:, g_sort])) self.assertTrue(np.allclose(gh.nodes[:, h_in_comb], h.nodes[:, h_sort]))
def test_merge_two_grids(self): # Merge two grids that have a common face. Check that global indices are # updated to match, and that they point to the same point coordinates data = np.ones(3) rows = np.array([0, 1, 2]) cols = np.array([0, 0, 0]) cf = sps.coo_matrix((data, (rows, cols))) data = np.ones(6) rows = np.array([0, 1, 1, 2, 2, 0]) cols = np.array([0, 0, 1, 1, 2, 2]) fn = sps.coo_matrix((data, (rows, cols))) nodes_1 = np.array([[0, 1, 0], [0, 0, 1], [0, 0, 0]]) nodes_2 = np.array([[0, 1, 0], [0, 0, -1], [0, 0, 0]]) g1 = MockGrid( 2, num_faces=3, face_nodes=fn, cell_faces=cf, num_cells=1, nodes=nodes_1 ) g2 = MockGrid( 2, num_faces=3, face_nodes=fn, cell_faces=cf, num_cells=1, nodes=nodes_2 ) g_11 = pp.TensorGrid(np.array([0, 1])) g_11.global_point_ind = np.arange(2) g_22 = pp.TensorGrid(np.array([0, 1])) g_22.global_point_ind = np.arange(2) gl = [[[g1], [g_11]], [[g2], [g_22]]] intersections = [np.array([1]), np.array([0])] list_of_grids, glob_ind = non_conforming.init_global_ind(gl) grid_list_1d = non_conforming.process_intersections( gl, intersections, glob_ind, list_of_grids, tol=1e-4 ) g_1d = grid_list_1d[0] ismem, maps = ismember_rows(g_1d.global_point_ind, g1.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g1.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, g2.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g2.nodes[:, maps], g_1d.nodes))
def _extrude_0d( g: pp.PointGrid, z: np.ndarray ) -> Tuple[pp.Grid, np.ndarray, np.ndarray]: """ Extrude a 0d grid into 1d by prismatic extension in the z-direction. The original grid is assumed to be in the xy-plane, that is, any existing non-zero z-direction is ignored. Both the original and the new grid will have their geometry computed. Parameters: g (pp.Grid): Original grid to be extruded. Should have dimension 1. z (np.ndarray): z-coordinates of the nodes in the extruded grid. Should be either non-negative or non-positive, and be sorted in increasing or decreasing order, respectively. Returns: pp.TensorGrid: A grid of dimension 1. np.array of np.arrays: Cell mappings, so that element ci gives all indices of cells in the extruded grid that comes from cell ci in the original grid. np.array of np.arrays: Face mappings, so that element fi gives all indices of faces in the extruded grid that comes from face fi in the original grid. """ # Number of nodes num_pt = z.size # x and y coordinates of the right size x = g.nodes[0, 0] * np.ones(num_pt) y = g.nodes[1, 0] * np.ones(num_pt) # Initial 1d grid. Coordinates are wrong, but this we will fix later # There is no need to do anything special with tags here; the tags of a 0d grid are # trivial, and the 1d extrusion can be based on this. g_new = pp.TensorGrid(x) g_info = g.name.copy() g_info.append("Extrude 0d->1d") g_new.name = g_info # Update coordinates g_new.nodes = np.vstack((x, y, z)) g_new.compute_geometry() # The single cell in g has produced all cells in g_new cell_map = np.empty(1, dtype=np.object) cell_map[0] = np.arange(g_new.num_cells) face_map = np.empty(0) return g_new, cell_map, face_map
def test_merge_grids_split(self): g1 = pp.TensorGrid(np.linspace(0, 2, 2)) g2 = pp.TensorGrid(np.linspace(2, 4, 2)) g_nodes = np.hstack((g1.nodes, g2.nodes)) g_face_nodes = sps.block_diag((g1.face_nodes, g2.face_nodes), "csc") g_cell_faces = sps.block_diag((g1.cell_faces, g2.cell_faces), "csc") g = pp.Grid(1, g_nodes, g_face_nodes, g_cell_faces, "pp.TensorGrid") h1 = pp.TensorGrid(np.linspace(0, 2, 3)) h2 = pp.TensorGrid(np.linspace(2, 4, 3)) h_nodes = np.hstack((h1.nodes, h2.nodes)) h_face_nodes = sps.block_diag((h1.face_nodes, h2.face_nodes), "csc") h_cell_faces = sps.block_diag((h1.cell_faces, h2.cell_faces), "csc") h = pp.Grid(1, h_nodes, h_face_nodes, h_cell_faces, "pp.TensorGrid") g.compute_geometry() h.compute_geometry() weights, new, old = pp.match_grids.match_1d(g, h, tol=1e-4) # Weights give mappings from h to g. All cells are split in two self.assertTrue(np.allclose(weights, np.array([1.0, 1.0, 1.0, 1.0]))) self.assertTrue(np.allclose(new, np.array([0, 0, 1, 1]))) self.assertTrue(np.allclose(old, np.array([0, 1, 2, 3])))
def generate_grids(self, n, xmax, ymax, split): g1 = pp.CartGrid([split * n, ymax * n], physdims=[split, ymax]) g2 = pp.CartGrid([(xmax - split) * n, ymax * n], physdims=[xmax - split, ymax]) g2.nodes[0] += split g1.compute_geometry() g2.compute_geometry() grids = [g2, g1] gb = pp.GridBucket() [gb.add_nodes(g) for g in grids] [g2, g1] = gb.grids_of_dimension(2) tol = 1e-6 if np.any(g2.cell_centers[0] > split): right_grid = g2 left_grid = g1 else: right_grid = g1 left_grid = g2 gb.set_node_prop(left_grid, "node_number", 1) gb.set_node_prop(right_grid, "node_number", 0) left_faces = np.argwhere( left_grid.face_centers[0] > split - tol).ravel() right_faces = np.argwhere( right_grid.face_centers[0] < split + tol).ravel() val = np.ones(left_faces.size, dtype=np.bool) shape = [right_grid.num_faces, left_grid.num_faces] face_faces = sps.coo_matrix((val, (right_faces, left_faces)), shape=shape) gb.add_edge((right_grid, left_grid), face_faces) mg = pp.TensorGrid(np.array([split] * ((n + 1) * ymax))) mg.nodes[1] = np.linspace(0, ymax, (n + 1) * ymax) mg.compute_geometry() side_g = {pp.grids.mortar_grid.LEFT_SIDE: mg} d_e = gb.edge_props((g1, g2)) d_e["mortar_grid"] = pp.BoundaryMortar(g1.dim - 1, side_g, face_faces) d_e["edge_number"] = 0 return gb
def grid_1d(self, num_pts=3, rotate_fracture=False): g = pp.TensorGrid(np.arange(num_pts)) if rotate_fracture: g.nodes = np.vstack(( np.linspace(0.4, 0.6, num_pts), np.linspace(0.25, 0.75, num_pts), np.zeros(num_pts), )) else: g.nodes = np.vstack(( 0.5 * np.ones(num_pts), np.linspace(0.25, 0.75, num_pts), np.zeros(num_pts), )) g.compute_geometry() g.global_point_ind = np.arange(g.num_nodes) return g
def test_cart_1d(self): g = pp.TensorGrid(np.array([0, 1, 2])) g.nodes = g.nodes + 0.2 * np.random.random(g.nodes.shape) g.compute_geometry() face_pos = [0, 1, 2] for f in face_pos: h, sub_f, sub_n = pp.partition.extract_subgrid(g, f, faces=True) true_nodes = np.array([f]) true_faces = np.array([f]) self.assertTrue(np.array_equal(true_nodes, sub_n)) self.assertTrue(np.array_equal(true_faces, sub_f)) self.compare_grid_geometries(g, h, f, true_faces, true_nodes)
def _create_embedded_2d_grid(loc_coord, glob_id): """ Create a 2d grid that is embedded in a 3d grid. """ loc_center = np.mean(loc_coord, axis=1).reshape((-1, 1)) loc_coord -= loc_center # Check that the points indeed form a line assert pp.geometry_property_checks.points_are_planar(loc_coord) # Find the tangent of the line # Projection matrix rot = pp.map_geometry.project_plane_matrix(loc_coord) loc_coord_2d = rot.dot(loc_coord) # The points are now 2d along two of the coordinate axis, but we # don't know which yet. Find this. sum_coord = np.sum(np.abs(loc_coord_2d), axis=1) active_dimension = np.logical_not(np.isclose(sum_coord, 0)) # Check that we are indeed in 2d assert np.sum(active_dimension) == 2 # Sort nodes, and create grid coord_2d = loc_coord_2d[active_dimension] sort_ind = np.lexsort((coord_2d[0], coord_2d[1])) sorted_coord = coord_2d[:, sort_ind] sorted_coord = np.round(sorted_coord * 1e10) / 1e10 unique_x = np.unique(sorted_coord[0]) unique_y = np.unique(sorted_coord[1]) # assert unique_x.size == unique_y.size g = pp.TensorGrid(unique_x, unique_y) assert np.all(g.nodes[0:2] - sorted_coord == 0) # Project back to active dimension nodes = np.zeros(g.nodes.shape) nodes[active_dimension] = g.nodes[0:2] g.nodes = nodes # Project back again to 3d coordinates irot = rot.transpose() g.nodes = irot.dot(g.nodes) g.nodes += loc_center # Add mapping to global point numbers g.global_point_ind = glob_id[sort_ind] return g
def create_embedded_line_grid(loc_coord: np.ndarray, glob_id: np.ndarray, tol: float = 1e-4) -> pp.Grid: """ Create a 1d grid embedded in a higher dimensional space. Args: loc_coord (np.ndarray): Coordinates of points to be used in the grid. glob_id (np.ndarray): Global indexes of the points. Typically refers to a global mesh, where the points of this grid is a subset. tol (float, optional): Tolerance used for check of collinearity of the points. Defaults to 1e-4. Returns: g (TYPE): DESCRIPTION. """ loc_center = np.mean(loc_coord, axis=1).reshape((-1, 1)) ( sorted_coord, rot, active_dimension, sort_ind, ) = pp.map_geometry.project_points_to_line(loc_coord, tol) g = pp.TensorGrid(sorted_coord) # Project back to active dimension nodes = np.zeros(g.nodes.shape) nodes[active_dimension] = g.nodes[0] g.nodes = nodes # Project back again to 3d coordinates irot = rot.transpose() g.nodes = irot.dot(g.nodes) g.nodes += loc_center # Add mapping to global point numbers g.global_point_ind = glob_id[sort_ind] return g
def test_merge_three_grids_no_common_point(self): # Merge three grids: One in the mid data = np.ones(3) rows = np.array([0, 1, 2]) cols = np.array([0, 0, 0]) cf_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(6) rows = np.array([0, 1, 2, 1, 3, 4]) cols = np.array([0, 0, 0, 1, 1, 1]) cf_2 = sps.coo_matrix((data, (rows, cols))) data = np.ones(6) rows = np.array([0, 1, 1, 2, 2, 0]) cols = np.array([0, 0, 1, 1, 2, 2]) fn_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(10) rows = np.array([0, 1, 1, 3, 3, 0, 1, 2, 2, 3]) cols = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) fn_2 = sps.coo_matrix((data, (rows, cols))) nodes_1 = np.array([[0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]]) nodes_2 = np.array([[0, 1, 0], [0, 0, -1], [0, 0, 0]]) nodes_3 = np.array([[0, 1, 0], [2, 1, 1], [0, 0, 0]]) # Middle grid, unit square divided into two. Will have neighbors on top and # bottom. g1 = MockGrid( 2, num_faces=5, face_nodes=fn_2, cell_faces=cf_2, num_cells=2, nodes=nodes_1 ) # Neighbor on bottom g2 = MockGrid( 2, num_faces=3, face_nodes=fn_1, cell_faces=cf_1, num_cells=1, nodes=nodes_2 ) # Neighbor on top. g3 = MockGrid( 2, num_faces=3, face_nodes=fn_1, cell_faces=cf_1, num_cells=1, nodes=nodes_3 ) # Bottom 1d grid, as seen from g1 g_11 = pp.TensorGrid(np.array([0, 1])) g_11.global_point_ind = np.arange(2) # Top 1d grid, as seen from g1 g_13 = pp.TensorGrid(np.array([0, 1])) g_13.nodes = np.array([[0, 1], [1, 1], [0, 0]]) # Note global point indices here, in accordance with the ordering in # nodes_1 g_13.global_point_ind = np.array([2, 3]) # Bottom 1d grid, as seen from g2 g_22 = pp.TensorGrid(np.array([0, 1])) g_22.global_point_ind = np.arange(2) # Top 1d grid, as seen from g3 g_33 = pp.TensorGrid(np.array([1, 2])) g_33.nodes = np.array([[0, 1], [1, 1], [0, 0]]) # Global point indices, as ordered in nodes_3 g_33.global_point_ind = np.array([1, 2]) gl = [[[g1], [g_11, g_13]], [[g2], [g_22]], [[g3], [g_33]]] intersections = [np.array([1, 2]), np.array([0]), np.array([0])] list_of_grids, glob_ind = non_conforming.init_global_ind(gl) grid_list_1d = non_conforming.process_intersections( gl, intersections, glob_ind, list_of_grids, tol=1e-4 ) self.assertTrue(len(grid_list_1d) == 2) g_1d = grid_list_1d[0] ismem, maps = ismember_rows(g_1d.global_point_ind, g1.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g1.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, g2.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g2.nodes[:, maps], g_1d.nodes)) g_1d = grid_list_1d[1] ismem, maps = ismember_rows(g_1d.global_point_ind, g1.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g1.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, g3.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g3.nodes[:, maps], g_1d.nodes))
def test_merge_three_grids_hanging_node_shared_node(self): # Merge three grids, where a central cell share one face each with the two # other. Importantly, one node will be involved in both shared faces. data = np.ones(10) rows = np.array([0, 1, 1, 2, 2, 3, 3, 0, 3, 1]) cols = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) fn_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(6) rows = np.array([0, 1, 1, 2, 2, 0]) cols = np.array([0, 0, 1, 1, 2, 2]) fn_2 = sps.coo_matrix((data, (rows, cols))) data = np.ones(6) rows = np.array([0, 4, 3, 1, 2, 4]) cols = np.array([0, 0, 0, 1, 1, 1]) cf_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(3) rows = np.array([0, 1, 2]) cols = np.array([0, 0, 0]) cf_2 = sps.coo_matrix((data, (rows, cols))) nodes_1 = np.array([[0, 1, 2, 1], [0, 0, 0, 1], [0, 0, 0, 0]]) nodes_2 = np.array([[0, 2, 1], [0, 0, -1], [0, 0, 0]]) nodes_3 = np.array([[0, 1, 0], [0, 1, 1], [0, 0, 0]]) # Central grid g1 = MockGrid( 2, num_faces=5, face_nodes=fn_1, cell_faces=cf_1, num_cells=2, nodes=nodes_1 ) # First neighboring grid g2 = MockGrid( 2, num_faces=3, face_nodes=fn_2, cell_faces=cf_2, num_cells=1, nodes=nodes_2 ) g3 = MockGrid( 2, num_faces=3, face_nodes=fn_2, cell_faces=cf_2, num_cells=1, nodes=nodes_3 ) # First 1d grid, as seen from g1 g_11 = pp.TensorGrid(np.array([0, 1, 2])) g_11.global_point_ind = np.arange(3) # Second 1d grid, as seen from g1 g_13 = pp.TensorGrid(np.array([0, 1])) g_13.nodes = np.array([[0, 1], [0, 1], [0, 0]]) # Point indices adjusted according to ordering in nodes_1 g_13.global_point_ind = np.array([0, 3]) # First 1d grid, as seen from g2 g_22 = pp.TensorGrid(np.array([0, 2])) g_22.global_point_ind = np.arange(2) # Second 1d grid, as seen from g3 g_33 = pp.TensorGrid(np.array([0, 1])) g_33.nodes = np.array([[0, 1], [0, 1], [0, 0]]) g_33.global_point_ind = np.arange(2) gl = [[[g1], [g_11, g_13]], [[g2], [g_22]], [[g3], [g_33]]] intersections = [np.array([1, 2]), np.array([0]), np.array([0])] list_of_grids, glob_ind = non_conforming.init_global_ind(gl) grid_list_1d = non_conforming.process_intersections( gl, intersections, glob_ind, list_of_grids, tol=1e-4 ) self.assertTrue(len(grid_list_1d) == 2) g_1d = grid_list_1d[0] ismem, maps = ismember_rows(g_1d.global_point_ind, g1.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g1.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, g2.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g2.nodes[:, maps], g_1d.nodes)) g_1d = grid_list_1d[1] ismem, maps = ismember_rows(g_1d.global_point_ind, g1.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g1.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, g3.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(g3.nodes[:, maps], g_1d.nodes))
def setUp(self): self.x = np.array([0, 1, 3]) self.y = np.array([1, 3, 7]) self.g = pp.TensorGrid(self.x) self.g.nodes = np.vstack((self.x, self.y, np.zeros(3)))
def merge_1d_grids(g, h, global_ind_offset=0, tol=1e-4): """Merge two 1d grids with non-matching nodes to a single grid. The grids should have common start and endpoints. They can be into 3d space in a genreal way. The function is primarily intended for merging non-conforming DFN grids. Parameters: g: 1d tensor grid. h: 1d tensor grid glob_ind_offset (int, defaults to 0): Off set for the global point index of the new grid. tol (double, defaults to 1e-4): Tolerance for when two nodes are merged into one. Returns: TensorGrid: New tensor grid, containing the combined node definition. int: New global ind offset, increased by the number of cells in the combined grid. np.array (int): Indices of common nodes (after sorting) of g and the new grid. np.array (int): Indices of common nodes (after sorting) of h and the new grid. np.array (int): Permutation indices that sort the node coordinates of g. The common indices between g and the new grid are found as new_grid.nodes[:, g_in_combined] = g.nodes[:, sorted] np.array (int): Permutation indices that sort the node coordinates of h. The common indices between h and the new grid are found as new_grid.nodes[:, h_in_combined] = h.nodes[:, sorted] """ # Nodes of the two 1d grids, combine them gp = g.nodes hp = h.nodes combined = np.hstack((gp, hp)) num_g = gp.shape[1] num_h = hp.shape[1] # Keep track of where we put the indices of the original grids g_in_full = np.arange(num_g) h_in_full = num_g + np.arange(num_h) # The tolerance should not be larger than the smallest distance between # two points on any of the grids. diff_gp = np.min(pp.distances.pointset(gp, True)) diff_hp = np.min(pp.distances.pointset(hp, True)) min_diff = np.minimum(tol, 0.5 * np.minimum(diff_gp, diff_hp)) # Uniquify points combined_unique, _, new_2_old = unique_columns_tol(combined, tol=min_diff) # Follow locations of the original grid points g_in_unique = new_2_old[g_in_full] h_in_unique = new_2_old[h_in_full] # The combined nodes must be sorted along their natural line. # Find the dimension with the largest spatial extension, and sort those # coordinates max_coord = combined_unique.max(axis=1) min_coord = combined_unique.min(axis=1) dx = max_coord - min_coord sort_dim = np.argmax(dx) sort_ind = np.argsort(combined_unique[sort_dim]) combined_sorted = combined_unique[:, sort_ind] # Follow the position of the orginial nodes through sorting _, g_sorted = ismember_rows(g_in_unique, sort_ind) _, h_sorted = ismember_rows(h_in_unique, sort_ind) num_new_grid = combined_sorted.shape[1] # Create a new 1d grid. # First use a 1d coordinate to initialize topology new_grid = pp.TensorGrid(np.arange(num_new_grid)) # Then set the right, 3d coordinates new_grid.nodes = pp.map_geometry.force_point_collinearity(combined_sorted) # Set global point indices new_grid.global_point_ind = global_ind_offset + np.arange(num_new_grid) global_ind_offset += num_new_grid return ( new_grid, global_ind_offset, g_sorted, h_sorted, np.arange(num_g), np.arange(num_h), )
def test_merge_three_grids_internal_intersection_hanging_node(self): # Merge three grids, where a central cell share one face each with the two # other. Importantly, one node will be involved in both shared faces. data = np.ones(20) rows = np.array([0, 1, 1, 2, 2, 3, 0, 4, 0, 5, 1, 4, 2, 4, 2, 5, 3, 4, 3, 5]) cols = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]) fn_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(15) rows = np.array([0, 5, 3, 1, 5, 6, 0, 4, 7, 2, 6, 8, 2, 7, 9]) cols = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]) cf_1 = sps.coo_matrix((data, (rows, cols))) data = np.ones(16) rows = np.array([0, 1, 1, 2, 0, 3, 0, 4, 1, 3, 1, 4, 2, 3, 2, 4]) cols = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7]) fn_2 = sps.coo_matrix((data, (rows, cols))) data = np.ones(12) rows = np.array([0, 5, 3, 1, 7, 5, 0, 2, 4, 1, 4, 6]) cols = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]) cf_2 = sps.coo_matrix((data, (rows, cols))) nodes_1 = np.array( [[-1, -0.5, 0, 1, 0, 0], [0, 0, 0, 0, -1, 1], [0, 0, 0, 0, 0, 0]] ) nodes_2 = np.array([[-1, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, -1, 1]]) nodes_3 = np.array([[0, 0, 0, 0, 0], [-1, 0, 1, 0, 0], [0, 0, 0, -1, 1]]) # Central grid gxy = MockGrid( 2, num_faces=10, face_nodes=fn_1, cell_faces=cf_1, num_cells=5, nodes=nodes_1, ) # First neighboring grid gxz = MockGrid( 2, num_faces=8, face_nodes=fn_2, cell_faces=cf_2, num_cells=4, nodes=nodes_2 ) gyz = MockGrid( 2, num_faces=8, face_nodes=fn_2, cell_faces=cf_2, num_cells=4, nodes=nodes_3 ) # First 1d grid, as seen from g1 g_1x = pp.TensorGrid(np.array([0, 1, 2, 3])) g_1x.nodes = np.array([[-1, -0.5, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]]) g_1x.global_point_ind = np.arange(4) # Third 1d grid, as seen from g1 g_1y = pp.TensorGrid(np.array([0, 1, 2])) g_1y.nodes = np.array([[0, 0, 0], [-1, 0, 1], [0, 0, 0]]) # Point indices adjusted according to ordering in nodes_1 g_1y.global_point_ind = np.array([4, 2, 5]) # First 1d grid, as seen from g2 g_2x = pp.TensorGrid(np.array([0, 1, 2])) g_2x.nodes = np.array([[-1, 0, 1], [0, 0, 0], [0, 0, 0]]) g_2x.global_point_ind = np.arange(3) # Third 1d grid, as seen from g2 g_2z = pp.TensorGrid(np.array([0, 1, 2])) g_2z.nodes = np.array([[0, 0, 0], [0, 0, 0], [-1, 0, 1]]) # Point indices adjusted according to ordering in nodes_1 g_2z.global_point_ind = np.array([3, 1, 4]) g_3y = pp.TensorGrid(np.array([0, 1, 2])) g_3y.nodes = np.array([[0, 0, 0], [-1, 0, 1], [0, 0, 0]]) g_3y.global_point_ind = np.arange(3) # Second 1d grid, as seen from g1 g_3z = pp.TensorGrid(np.array([0, 1, 2])) g_3z.nodes = np.array([[0, 0, 0], [0, 0, 0], [-1, 0, 1]]) # Point indices adjusted according to ordering in nodes_1 g_3z.global_point_ind = np.array([3, 1, 4]) gl = [[[gxz], [g_2z, g_2x]], [[gyz], [g_3z, g_3y]], [[gxy], [g_1x, g_1y]]] intersections = [np.array([1, 2]), np.array([0, 2]), np.array([0, 1])] list_of_grids, glob_ind = non_conforming.init_global_ind(gl) grid_list_1d = non_conforming.process_intersections( gl, intersections, glob_ind, list_of_grids, tol=1e-4 ) self.assertTrue(len(grid_list_1d) == 3) g_1d = grid_list_1d[0] ismem, maps = ismember_rows(g_1d.global_point_ind, gxz.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gxz.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, gyz.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gyz.nodes[:, maps], g_1d.nodes)) g_1d = grid_list_1d[1] ismem, maps = ismember_rows(g_1d.global_point_ind, gxy.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gxy.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, gxz.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gxz.nodes[:, maps], g_1d.nodes)) g_1d = grid_list_1d[2] ismem, maps = ismember_rows(g_1d.global_point_ind, gxy.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gxy.nodes[:, maps], g_1d.nodes)) ismem, maps = ismember_rows(g_1d.global_point_ind, gyz.global_point_ind) self.assertTrue(ismem.sum() == g_1d.num_nodes) self.assertTrue(np.allclose(gyz.nodes[:, maps], g_1d.nodes))