def nodal_adjacency(self): """ Returns a :class:`meshmode.mesh.NodalAdjacency` object representing the nodal adjacency of this mesh """ if self._nodal_adjacency is None: plex = self.analog()._plex cStart, cEnd = plex.getHeightStratum(0) vStart, vEnd = plex.getDepthStratum(0) to_fd_id = np.vectorize(self.analog()._cell_numbering.getOffset)( np.arange(cStart, cEnd, dtype=np.int32)) element_to_neighbors = {} verts_checked = set() # dmplex ids of vertex checked # If using all cells, loop over them all if self.icell_to_fd is None: range_ = range(cStart, cEnd) # Otherwise, just the ones you're using else: isin = np.isin(to_fd_id, self.icell_to_fd) range_ = np.arange(cStart, cEnd, dtype=np.int32)[isin] # For each cell for cell_id in range_: # For each vertex touching the cell (that haven't already seen) for vert_id in plex.getTransitiveClosure(cell_id)[0]: if vStart <= vert_id < vEnd and vert_id not in verts_checked: verts_checked.add(vert_id) cells = [] # Record all cells touching that vertex support = plex.getTransitiveClosure(vert_id, useCone=False)[0] for other_cell_id in support: if cStart <= other_cell_id < cEnd: cells.append(to_fd_id[other_cell_id - cStart]) # If only using some cells, clean out extraneous ones # and relabel them to new id cells = set(cells) if self.fd_to_icell is not None: cells = set([self.fd_to_icell[fd_ndx] for fd_ndx in cells if fd_ndx in self.fd_to_icell]) # mark cells as neighbors for cell_one in cells: element_to_neighbors.setdefault(cell_one, set()) element_to_neighbors[cell_one] |= cells # Create neighbors_starts and neighbors neighbors = [] neighbors_starts = np.zeros(self.nelements() + 1, dtype=np.int32) for iel in range(len(element_to_neighbors)): elt_neighbors = element_to_neighbors[iel] neighbors += list(elt_neighbors) neighbors_starts[iel+1] = len(neighbors) neighbors = np.array(neighbors, dtype=np.int32) self._nodal_adjacency = NodalAdjacency(neighbors_starts=neighbors_starts, neighbors=neighbors) return self._nodal_adjacency
def _get_firedrake_nodal_info(fdrake_mesh_topology, cells_to_use=None): """ Get nodal adjacency and vertex indices corresponding to a firedrake mesh topology. Note that as we do not use geometric information, there is no guarantee that elements have a positive orientation. The elements (in firedrake lingo, the cells) are guaranteed to have the same numbering in :mod:`meshmode` as :mod:`firedrdake` :arg fdrake_mesh_topology: A :mod:`firedrake` instance of class `firedrake.mesh.MeshTopology` or `firedrake.mesh.MeshGeometry`. :arg cells_to_use: Ignored if *None*. Otherwise, assumed to be a numpy array holding the firedrake cell indices to use. Any cells not on this array are ignored. Cells used are assumed to appear exactly once in the array. The cell's element index in the nodal adjacency will be its index in *cells_to_use*. :return: Returns *vertex_indices* as a numpy array of shape *(nelements, ref_element.nvertices)* (as described by the ``vertex_indices`` attribute of a :class:`MeshElementGroup`) and a :class:`NodalAdjacency` constructed from *fdrake_mesh_topology* as a tuple *(vertex_indices, nodal_adjacency)*. Even if *cells_to_use* is not *None*, the vertex indices are still the global firedrake vertex indices. """ top = fdrake_mesh_topology.topology # If you don't understand dmplex, look at the PETSc reference # here: https://cse.buffalo.edu/~knepley/classes/caam519/CSBook.pdf # used to get topology info # FIXME : not sure how to get around the private access top_dm = top._topology_dm # Get range of dmplex ids for cells, facets, and vertices f_start, f_end = top_dm.getHeightStratum(1) v_start, v_end = top_dm.getDepthStratum(0) # FIXME : not sure how to get around the private accesses # Maps dmplex vert id -> firedrake vert index vert_id_dmp_to_fd = top._vertex_numbering.getOffset # We will fill in the values of vertex indices as we go if cells_to_use is None: num_cells = top.num_cells() else: num_cells = np.size(cells_to_use) from pyop2.datatypes import IntType vertex_indices = -np.ones((num_cells, top.ufl_cell().num_vertices()), dtype=IntType) # This will map fd cell ndx (or its new index as dictated by # *cells_to_use* if *cells_to_use* # is not *None*) # -> list of fd cell indices which share a vertex cell_to_nodal_neighbors = {} # This will map dmplex facet id -> list of adjacent # (fd cell ndx, firedrake local fac num) facet_to_cells = {} # This will map dmplex vert id -> list of fd cell # indices which touch this vertex, # Primarily used to construct cell_to_nodal_neighbors vert_to_cells = {} # Loop through each cell (cell closure is all the dmplex ids for any # verts, faces, etc. associated with the cell) cell_closure = top.cell_closure if cells_to_use is not None: cell_closure = cell_closure[cells_to_use, :] for fd_cell_ndx, closure_dmp_ids in enumerate(cell_closure): # Store the vertex indices dmp_verts = closure_dmp_ids[np.logical_and(v_start <= closure_dmp_ids, closure_dmp_ids < v_end)] vertex_indices[fd_cell_ndx][:] = np.array([ vert_id_dmp_to_fd(dmp_vert) for dmp_vert in dmp_verts]) # Record this cell as touching the facet and remember its local # facet number (the index at which it appears) dmp_fac_ids = closure_dmp_ids[np.logical_and(f_start <= closure_dmp_ids, closure_dmp_ids < f_end)] for loc_fac_nr, dmp_fac_id in enumerate(dmp_fac_ids): facet_to_cells.setdefault(dmp_fac_id, []).append((fd_cell_ndx, loc_fac_nr)) # Record this vertex as touching the cell, and mark this cell # as nodally adjacent (in cell_to_nodal_neighbors) to any # cells already documented as touching this cell cell_to_nodal_neighbors[fd_cell_ndx] = [] for dmp_vert_id in dmp_verts: vert_to_cells.setdefault(dmp_vert_id, []) for other_cell_ndx in vert_to_cells[dmp_vert_id]: cell_to_nodal_neighbors[fd_cell_ndx].append(other_cell_ndx) cell_to_nodal_neighbors[other_cell_ndx].append(fd_cell_ndx) vert_to_cells[dmp_vert_id].append(fd_cell_ndx) # make sure that no -1s remain in vertex_indices (i.e. none are left unset) assert np.all(vertex_indices >= 0) # Next go ahead and compute nodal adjacency by creating # neighbors and neighbor_starts as specified by :class:`NodalAdjacency` neighbors = [] if cells_to_use is None: num_cells = top.num_cells() else: num_cells = np.size(cells_to_use) neighbors_starts = np.zeros(num_cells + 1, dtype=IntType) for iel in range(len(cell_to_nodal_neighbors)): neighbors += cell_to_nodal_neighbors[iel] neighbors_starts[iel+1] = len(neighbors) neighbors = np.array(neighbors, dtype=IntType) nodal_adjacency = NodalAdjacency(neighbors_starts=neighbors_starts, neighbors=neighbors) return vertex_indices, nodal_adjacency
def generate_nodal_adjacency(self, nelements, nvertices, groups): # medium-term FIXME: make this an incremental update # rather than build-from-scratch vertex_to_element = [[] for i in range(nvertices)] element_index = 0 for grp in groups: for iel_grp in range(len(grp)): for ivertex in grp[iel_grp]: vertex_to_element[ivertex].append(element_index) element_index += 1 element_to_element = [set() for i in range(nelements)] element_index = 0 if self.lazy: for grp in groups: for iel_grp in range(len(grp)): for i in range(len(grp[iel_grp])): for j in range(i + 1, len(grp[iel_grp])): vertex_pair = (min(grp[iel_grp][i], grp[iel_grp][j]), max(grp[iel_grp][i], grp[iel_grp][j])) #print 'iel:', iel_grp, 'pair:', vertex_pair if vertex_pair not in self.seen_tuple: self.propagate_tree( self.get_root(self.pair_map[vertex_pair]), self.hanging_vertex_element, element_to_element) #print self.pair_map[vertex_pair].left_vertex, self.pair_map[vertex_pair].right_vertex, self.pair_map[vertex_pair].adjacent_elements, self.hanging_vertex_element[self.pair_map[vertex_pair].left_vertex], self.hanging_vertex_element[self.pair_map[vertex_pair].right_vertex] else: for grp in groups: for iel_grp in range(len(grp)): for ivertex in grp[iel_grp]: element_to_element[element_index].update( vertex_to_element[ivertex]) if self.hanging_vertex_element[ivertex]: for hanging_element in self.hanging_vertex_element[ ivertex]: if element_index != hanging_element: element_to_element[element_index].update( [hanging_element]) element_to_element[hanging_element].update( [element_index]) for i in range(len(grp[iel_grp])): for j in range(i + 1, len(grp[iel_grp])): vertex_pair = (min(grp[iel_grp][i], grp[iel_grp][j]), max(grp[iel_grp][i], grp[iel_grp][j])) #element_to_element[element_index].update( #self.pair_map[vertex_pair].adjacent_elements) queue = [self.pair_map[vertex_pair]] while queue: vertex = queue.pop(0) #if leaf node if vertex.left is None and vertex.right is None: assert (element_index in vertex.adjacent_elements) element_to_element[element_index].update( vertex.adjacent_elements) else: queue.append(vertex.left) queue.append(vertex.right) ''' if self.hanging_vertex_element[ivertex] and element_index != self.hanging_vertex_element[ivertex][0]: element_to_element[element_index].update([self.hanging_vertex_element[ivertex][0]]) element_to_element[self.hanging_vertex_element[ivertex][0]].update([element_index]) ''' element_index += 1 logger.debug("number of new elements: %d" % len(element_to_element)) for iel, neighbors in enumerate(element_to_element): if iel in neighbors: neighbors.remove(iel) #print(self.ray_elements) ''' for ray in self.rays: curnode = ray.first while curnode is not None: if len(curnode.value.elements) >= 2: if curnode.value.elements[0] is not None: element_to_element[curnode.value.elements[0]].update(curnode.value.elements) if curnode.value.elements[1] is not None: element_to_element[curnode.value.elements[1]].update(curnode.value.elements) if len(curnode.value.velements) >= 2: if curnode.value.velements[0] is not None: element_to_element[curnode.value.velements[0]].update(curnode.value.velements) if curnode.value.velements[1] is not None: element_to_element[curnode.value.velements[1]].update(curnode.value.velements) curnode = curnode.next ''' ''' for i in self.ray_elements: for j in i: #print j[0], j[1] element_to_element[j[0]].update(j) element_to_element[j[1]].update(j) ''' #print element_to_element lengths = [len(el_list) for el_list in element_to_element] neighbors_starts = np.cumsum( np.array([0] + lengths, dtype=self.last_mesh.element_id_dtype), # cumsum silently widens integer types dtype=self.last_mesh.element_id_dtype) from pytools import flatten neighbors = np.array(list(flatten(element_to_element)), dtype=self.last_mesh.element_id_dtype) assert neighbors_starts[-1] == len(neighbors) from meshmode.mesh import NodalAdjacency return NodalAdjacency(neighbors_starts=neighbors_starts, neighbors=neighbors)