コード例 #1
0
ファイル: mesh.py プロジェクト: benSepanski/fd2mm
    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
コード例 #2
0
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
コード例 #3
0
ファイル: __init__.py プロジェクト: matthiasdiener/meshmode
    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)