def update_face_tags(g, delete_faces, new_faces): """Update the face tags of a cell. Delete tags for old faces, and add new tags for their replacements. If the grid has no face tags, no change is done Parameters: g (grid): To be modified delete_faces (np.array or list): Faces to be deleted. new_faces (list of list): For each item in delete_faces, a list of new replacement faces. """ keys = tags.standard_face_tags() for key in keys: if hasattr(g, "tags"): old_tags = g.tags[key].copy() old_tags = np.delete(old_tags, delete_faces) num_new = np.array([len(new_faces[i]) for i in range(len(new_faces))]) new_tags = np.zeros(num_new.sum(), dtype=bool) divides = np.hstack((0, np.cumsum(num_new))) for i, d in enumerate(delete_faces): new_tags[divides[i] : divides[i + 1]] = g.tags[key][d] g.tags[key] = np.hstack((old_tags, new_tags))
def remove_faces(g, face_id, rem_cell_faces=True): """ Remove faces from grid. PARAMETERS: ----------- g - A grid face_id - Indices of faces to remove rem_cell_faces - Defaults to True. If set to false, the g.cell_faces matrix is not changed. """ # update face info keep = np.array([True] * g.num_faces) keep[face_id] = False g.face_nodes = g.face_nodes[:, keep] g.num_faces -= face_id.size g.face_normals = g.face_normals[:, keep] g.face_areas = g.face_areas[keep] g.face_centers = g.face_centers[:, keep] # Not sure if still works for key in tags.standard_face_tags(): g.tags[key] = g.tags[key][keep] if rem_cell_faces: g.cell_faces = g.cell_faces[keep, :]
def _check_tags(self) -> None: for key in tags.standard_node_tags(): if key not in self.tags.keys(): raise ValueError(f"The tag key {key} must be specified") value = self.tags.get(key) if not value.size == self.num_nodes: raise ValueError(f"Wrong size of value for tag {key}") for key in tags.standard_face_tags(): if key not in self.tags.keys(): raise ValueError(f"The tag key {key} must be specified") value = self.tags.get(key) if not value.size == self.num_faces: raise ValueError(f"Wrong size of value for tag {key}")
def initiate_face_tags(self) -> None: keys = tags.standard_face_tags() values = [np.zeros(self.num_faces, dtype=bool) for _ in keys] tags.add_tags(self, dict(zip(keys, values)))
def generate_coarse_grid_single(g, subdiv, face_map): """ Specific function for a single grid. Use the common interface instead. """ subdiv = np.asarray(subdiv) assert subdiv.size == g.num_cells # declare the storage array to build the cell_faces map cell_faces = np.empty(0, dtype=g.cell_faces.indptr.dtype) cells = np.empty(0, dtype=cell_faces.dtype) orient = np.empty(0, dtype=g.cell_faces.data.dtype) # declare the storage array to build the face_nodes map face_nodes = np.empty(0, dtype=g.face_nodes.indptr.dtype) nodes = np.empty(0, dtype=face_nodes.dtype) visit = np.zeros(g.num_faces, dtype=np.bool) # compute the face_node indexes num_nodes_per_face = g.face_nodes.indptr[1:] - g.face_nodes.indptr[:-1] face_node_ind = matrix_compression.rldecode(np.arange(g.num_faces), num_nodes_per_face) cells_list = np.unique(subdiv) cell_volumes = np.zeros(cells_list.size) cell_centers = np.zeros((3, cells_list.size)) for cellId, cell in enumerate(cells_list): # extract the cells of the original mesh associated to a specific label cells_old = np.where(subdiv == cell)[0] # compute the volume cell_volumes[cellId] = np.sum(g.cell_volumes[cells_old]) cell_centers[:, cellId] = np.average(g.cell_centers[:, cells_old], axis=1) # reconstruct the cell_faces mapping faces_old, _, orient_old = sps.find(g.cell_faces[:, cells_old]) mask = np.ones(faces_old.size, dtype=np.bool) mask[np.unique(faces_old, return_index=True)[1]] = False # extract the indexes of the internal edges, to be discared index = np.array( [np.where(faces_old == f)[0] for f in faces_old[mask]], dtype=np.int).ravel() faces_new = np.delete(faces_old, index) cell_faces = np.r_[cell_faces, faces_new] cells = np.r_[cells, np.repeat(cellId, faces_new.shape[0])] orient = np.r_[orient, np.delete(orient_old, index)] # reconstruct the face_nodes mapping # consider only the unvisited faces not_visit = ~visit[faces_new] if not_visit.size == 0 or np.all(~not_visit): continue # mask to consider only the external faces mask = np.atleast_1d( np.sum( [face_node_ind == f for f in faces_new[not_visit]], axis=0, dtype=np.bool, )) face_nodes = np.r_[face_nodes, face_node_ind[mask]] nodes_new = g.face_nodes.indices[mask] nodes = np.r_[nodes, nodes_new] visit[faces_new] = True # Rename the faces cell_faces_unique = np.unique(cell_faces) cell_faces_id = np.arange(cell_faces_unique.size, dtype=cell_faces.dtype) cell_faces = np.array([ cell_faces_id[np.where(cell_faces_unique == f)[0]] for f in cell_faces ]).ravel() shape = (cell_faces_unique.size, cells_list.size) cell_faces = sps.csc_matrix((orient, (cell_faces, cells)), shape=shape) # Rename the nodes face_nodes = np.array([ cell_faces_id[np.where(cell_faces_unique == f)[0]] for f in face_nodes ]).ravel() nodes_list = np.unique(nodes) nodes_id = np.arange(nodes_list.size, dtype=nodes.dtype) nodes = np.array([nodes_id[np.where(nodes_list == n)[0]] for n in nodes]).ravel() # sort the nodes nodes = nodes[np.argsort(face_nodes, kind="mergesort")] data = np.ones(nodes.size, dtype=g.face_nodes.data.dtype) indptr = np.r_[0, np.cumsum(np.bincount(face_nodes))] face_nodes = sps.csc_matrix((data, nodes, indptr)) # store again the data in the same grid g.name.append("coarse") g.nodes = g.nodes[:, nodes_list] g.num_nodes = g.nodes.shape[1] g.face_nodes = face_nodes g.num_faces = g.face_nodes.shape[1] g.face_areas = g.face_areas[cell_faces_unique] g.tags = tags.extract(g.tags, cell_faces_unique, tags.standard_face_tags()) g.face_normals = g.face_normals[:, cell_faces_unique] g.face_centers = g.face_centers[:, cell_faces_unique] g.cell_faces = cell_faces g.num_cells = g.cell_faces.shape[1] g.cell_volumes = cell_volumes g.cell_centers = half_space.star_shape_cell_centers(g) is_nan = np.isnan(g.cell_centers[0, :]) g.cell_centers[:, is_nan] = cell_centers[:, is_nan] if face_map: return np.array([cell_faces_unique, cell_faces_id])
def initiate_face_tags(self): keys = tags.standard_face_tags() values = [ np.zeros(self.num_faces, dtype=bool) for _ in range(len(keys)) ] tags.add_tags(self, dict(zip(keys, values)))
def duplicate_faces(gh, face_cells): """ Duplicate all faces that are connected to a lower-dim cell Parameters ---------- gh - Higher-dim grid face_cells - A list of connection matrices. Each matrix gives the mapping from the cells of a lower-dim grid to the faces of the higher diim grid. """ # We find the indices of the higher-dim faces to be duplicated. # Each of these faces are duplicated, and the duplication is # attached to the same nodes. We do not attach the faces to # any cells as this connection will have to be undone later # anyway. frac_id = face_cells.nonzero()[1] frac_id = np.unique(frac_id) rem = tags.all_face_tags(gh.tags)[frac_id] gh.tags["fracture_faces"][frac_id[rem]] = True gh.tags["tip_faces"][frac_id] = False frac_id = frac_id[~rem] if frac_id.size == 0: return frac_id node_start = gh.face_nodes.indptr[frac_id] node_end = gh.face_nodes.indptr[frac_id + 1] nodes = gh.face_nodes.indices[mcolon(node_start, node_end)] added_node_pos = np.cumsum(node_end - node_start) + gh.face_nodes.indptr[-1] assert added_node_pos.size == frac_id.size assert added_node_pos[-1] - gh.face_nodes.indptr[-1] == nodes.size gh.face_nodes.indices = np.hstack((gh.face_nodes.indices, nodes)) gh.face_nodes.indptr = np.hstack((gh.face_nodes.indptr, added_node_pos)) gh.face_nodes.data = np.hstack( (gh.face_nodes.data, np.ones(nodes.size, dtype=bool))) gh.face_nodes._shape = (gh.num_nodes, gh.face_nodes.shape[1] + frac_id.size) assert gh.face_nodes.indices.size == gh.face_nodes.indptr[-1] node_start = gh.face_nodes.indptr[frac_id] node_end = gh.face_nodes.indptr[frac_id + 1] # frac_nodes = gh.face_nodes[:, frac_id] # gh.face_nodes = sps.hstack((gh.face_nodes, frac_nodes)) # We also copy the attributes of the original faces. gh.num_faces += frac_id.size gh.face_normals = np.hstack((gh.face_normals, gh.face_normals[:, frac_id])) gh.face_areas = np.append(gh.face_areas, gh.face_areas[frac_id]) gh.face_centers = np.hstack((gh.face_centers, gh.face_centers[:, frac_id])) # Not sure if this still does the correct thing. Might have to # send in a logical array instead of frac_id. gh.tags["fracture_faces"][frac_id] = True gh.tags["tip_faces"][frac_id] = False update_fields = tags.standard_face_tags() update_values = [[]] * len(update_fields) for i, key in enumerate(update_fields): update_values[i] = gh.tags[key][frac_id] tags.append_tags(gh.tags, update_fields, update_values) return frac_id
def __init__(self, n_tags): keys = tags.standard_face_tags() values = [np.zeros(n_tags, dtype=bool) for _ in range(len(keys))] tags.add_tags(self, dict(zip(keys, values)))
def check_equivalent_buckets(buckets, decimals=12): """ Checks agreement between number of cells, faces and nodes, their coordinates and the connectivity matrices cell_faces and face_nodes. Also checks the face tags. """ dim_h = buckets[0].dim_max() dim_l = dim_h - 1 num_buckets = len(buckets) cell_maps_h, face_maps_h = [], [] cell_maps_l, face_maps_l = num_buckets * [{}], num_buckets * [{}] # Check that all buckets have the same number of grids in the lower dimension num_grids_l: int = len(buckets[0].grids_of_dimension(dim_h - 1)) for bucket in buckets: assert len(bucket.grids_of_dimension(dim_h - 1)) == num_grids_l for d in range(dim_l, dim_h + 1): for target_grid in range(len(buckets[0].grids_of_dimension(d))): n_cells, n_faces, n_nodes = np.empty(0), np.empty(0), np.empty(0) nodes, face_centers, cell_centers = [], [], [] cell_faces, face_nodes = [], [] for bucket in buckets: g = bucket.grids_of_dimension(d)[target_grid] n_cells = np.append(n_cells, g.num_cells) n_faces = np.append(n_faces, g.num_faces) n_nodes = np.append(n_nodes, g.num_nodes) cell_faces.append(g.cell_faces) face_nodes.append(g.face_nodes) cell_centers.append(g.cell_centers) face_centers.append(g.face_centers) nodes.append(g.nodes) # Check that all buckets have the same number of cells, faces and nodes assert np.unique(n_cells).size == 1 assert np.unique(n_faces).size == 1 assert np.unique(n_nodes).size == 1 # Check that the coordinates agree cell_centers = np.round(cell_centers, decimals) nodes = np.round(nodes, decimals) face_centers = np.round(face_centers, decimals) for i in range(1, num_buckets): assert np.all( sm.ismember_rows(cell_centers[0], cell_centers[i])[0]) assert np.all( sm.ismember_rows(face_centers[0], face_centers[i])[0]) assert np.all(sm.ismember_rows(nodes[0], nodes[i])[0]) # Now we know all nodes, faces and cells are in all grids, we map them # to prepare cell_faces and face_nodes comparison g_0 = buckets[0].grids_of_dimension(d)[target_grid] for i in range(1, num_buckets): bucket = buckets[i] g = bucket.grids_of_dimension(d)[target_grid] cell_map, face_map, node_map = make_maps( g_0, g, bucket.dim_max()) mapped_cf = g.cell_faces[face_map][:, cell_map] mapped_fn = g.face_nodes[node_map][:, face_map] assert np.sum(np.abs(g_0.cell_faces) != np.abs(mapped_cf)) == 0 assert np.sum(np.abs(g_0.face_nodes) != np.abs(mapped_fn)) == 0 if g.dim == dim_h: face_maps_h.append(face_map) cell_maps_h.append(cell_map) else: cell_maps_l[i][g] = cell_map face_maps_l[i][g] = face_map # Also loop on the standard face tags to check that they are # identical between the buckets. tag_keys = tags.standard_face_tags() for key in tag_keys: assert np.all( np.isclose(g_0.tags[key], g.tags[key][face_map])) # Mortar grids g_h_0 = buckets[0].grids_of_dimension(dim_h)[0] for target_grid in range(len(buckets[0].grids_of_dimension(dim_l))): g_l_0 = buckets[0].grids_of_dimension(dim_l)[target_grid] mg_0 = buckets[0].edge_props((g_h_0, g_l_0), "mortar_grid") proj_0 = mg_0.primary_to_mortar_int() for i in range(1, num_buckets): g_l_i = buckets[i].grids_of_dimension(dim_l)[target_grid] g_h_i = buckets[i].grids_of_dimension(dim_h)[0] mg_i = buckets[i].edge_props((g_h_i, g_l_i), "mortar_grid") proj_i = mg_i.primary_to_mortar_int() cm = cell_maps_l[i][g_l_i] cm_extended = np.append(cm, cm + cm.size) fm = face_maps_h[i - 1] mapped_fc = proj_i[cm_extended, :][:, fm] assert np.sum(np.absolute(proj_0) - np.absolute(mapped_fc)) == 0 return cell_maps_h, cell_maps_l, face_maps_h, face_maps_l