def extract_subgrid(g, c, sort=True): """ Extract a subgrid based on cell indices. For simplicity the cell indices will be sorted before the subgrid is extracted. If the parent grid has geometry attributes (cell centers etc.) these are copied to the child. No checks are done on whether the cells form a connected area. The method should work in theory for non-connected cells, the user will then have to decide what to do with the resulting grid. This option has however not been tested. Parameters: g (core.grids.Grid): Grid object, parent c (np.array, dtype=int): Indices of cells to be extracted Returns: core.grids.Grid: Extracted subgrid. Will share (note, *not* copy) geometric fileds with the parent grid. Also has an additional field parent_cell_ind giving correspondance between parent and child cells. np.ndarray, dtype=int: Index of the extracted faces, ordered so that element i is the global index of face i in the subgrid. np.ndarray, dtype=int: Index of the extracted nodes, ordered so that element i is the global index of node i in the subgrid. """ if sort: c = np.sort(c) # Local cell-face and face-node maps. cf_sub, unique_faces = __extract_submatrix(g.cell_faces, c) fn_sub, unique_nodes = __extract_submatrix(g.face_nodes, unique_faces) # Append information on subgrid extraction to the new grid's history name = list(g.name) name.append('Extract subgrid') # Construct new grid. h = Grid(g.dim, g.nodes[:, unique_nodes], fn_sub, cf_sub, name) # Copy geometric information if any if hasattr(g, 'cell_centers'): h.cell_centers = g.cell_centers[:, c] if hasattr(g, 'cell_volumes'): h.cell_volumes = g.cell_volumes[c] if hasattr(g, 'face_centers'): h.face_centers = g.face_centers[:, unique_faces] if hasattr(g, 'face_normals'): h.face_normals = g.face_normals[:, unique_faces] if hasattr(g, 'face_areas'): h.face_areas = g.face_areas[unique_faces] h.parent_cell_ind = c return h, unique_faces, unique_nodes
def grid_2d(self, pert_node=False): nodes = np.array([ [0, 0, 0], [1, 0, 0], [1, 0.5, 0], [0.5, 0.5, 0], [0, 0.5, 0], [0, 0.5, 0], [0.5, 0.5, 0], [1, 0.5, 0], [1, 1, 0], [0, 1, 0], ]).T if pert_node: nodes[0, 3] = 0.75 fn = np.array([ [0, 1], [1, 2], [2, 3], [3, 4], [4, 0], [0, 3], [3, 1], [5, 6], [6, 7], [7, 8], [8, 9], [9, 5], [9, 6], [6, 8], ]).T cf = np.array([[3, 4, 5], [0, 6, 5], [1, 2, 6], [7, 12, 11], [12, 13, 10], [8, 9, 13]]).T cols = np.tile(np.arange(fn.shape[1]), (fn.shape[0], 1)).ravel("F") face_nodes = sps.csc_matrix( (np.ones_like(cols), (fn.ravel("F"), cols))) cols = np.tile(np.arange(cf.shape[1]), (cf.shape[0], 1)).ravel("F") data = np.array( [1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1]) cell_faces = sps.csc_matrix((data, (cf.ravel("F"), cols))) g = Grid(2, nodes, face_nodes, cell_faces, "TriangleGrid") g.compute_geometry() g.tags["fracture_faces"][[2, 3, 7, 8]] = 1 # g.face_normals[1, [2, 3]] = -0.5 # g.face_normals[1, [7, 8]] = 0.5 g.global_point_ind = np.arange(nodes.shape[1]) return g
def refine_grid_1d(g: pp.Grid, ratio: int = 2) -> pp.Grid: """Refine cells in a 1d grid. Parameters: g (pp.Grid): A 1d grid, to be refined. ratio (int): Returns: grid: New grid, with finer cells. """ # Implementation note: The main part of the function is the construction of # the new cell-face relation. Since the grid is 1d, nodes and faces are # equivalent, and notation used mostly refers to nodes instead of faces. # Cell-node relation cell_nodes = g.cell_nodes() nodes, cells, _ = sps.find(cell_nodes) # Every cell will contribute (ratio - 1) new nodes num_new_nodes = (ratio - 1) * g.num_cells + g.num_nodes x = np.zeros((3, num_new_nodes)) # Cooridates for splitting of cells theta = np.arange(1, ratio) / float(ratio) pos = 0 shift = 0 # Array that indicates whether an item in the cell-node relation represents # a node not listed before (e.g. whether this is the first or second # occurence of the cell) if_add = np.r_[1, np.ediff1d(cell_nodes.indices)].astype(bool) indices = np.empty(0, dtype=int) # Template array of node indices for refined cells ind = np.vstack((np.arange(ratio), np.arange(ratio) + 1)).flatten("F") nd = np.r_[np.diff(cell_nodes.indices)[1::2], 0] # Loop over all old cells and refine them. for c in np.arange(g.num_cells): # Find start and end nodes of the old cell loc = slice(cell_nodes.indptr[c], cell_nodes.indptr[c + 1]) start, end = cell_nodes.indices[loc] # Flags for whether this is the first occurences of the the nodes of # the old cell. If so, they should be added to the new node array if_add_loc = if_add[loc] # Local cell-node (thus cell-face) relations of the new grid indices = np.r_[indices, shift + ind] # Add coordinate of the startpoint to the node array if relevant if if_add_loc[0]: x[:, pos:(pos + 1)] = g.nodes[:, start, np.newaxis] pos += 1 # Add coordinates of the internal nodes x[:, pos:( pos + ratio - 1)] = g.nodes[:, start, np.newaxis] * theta + g.nodes[:, end, np.newaxis] * ( 1 - theta) pos += ratio - 1 shift += ratio + (2 - np.sum(if_add_loc) * (1 - nd[c])) - nd[c] # Add coordinate to the endpoint, if relevant if if_add_loc[1]: x[:, pos:(pos + 1)] = g.nodes[:, end, np.newaxis] pos += 1 # For 1d grids, there is a 1-1 relation between faces and nodes face_nodes = sps.identity(x.shape[1], format="csc") cell_faces = sps.csc_matrix(( np.ones(indices.size, dtype=bool), indices, np.arange(0, indices.size + 1, 2), )) g = Grid(1, x, face_nodes, cell_faces, "Refined 1d grid") g.compute_geometry() return g