def callback(self): del self._callback if op2.MPI.comm.size > 1: self._plex.distributeOverlap(1) self._grown_halos = True if reorder: with timed_region("Mesh: reorder"): old_to_new = self._plex.getOrdering(PETSc.Mat.OrderingType.RCM).indices reordering = np.empty_like(old_to_new) reordering[old_to_new] = np.arange(old_to_new.size, dtype=old_to_new.dtype) else: # No reordering reordering = None # Mark OP2 entities and derive the resulting Plex renumbering with timed_region("Mesh: renumbering"): dmplex.mark_entity_classes(self._plex) self._entity_classes = dmplex.get_entity_classes(self._plex) self._plex_renumbering = dmplex.plex_renumbering(self._plex, self._entity_classes, reordering) with timed_region("Mesh: cell numbering"): # Derive a cell numbering from the Plex renumbering entity_dofs = np.zeros(topological_dim+1, dtype=np.int32) entity_dofs[-1] = 1 self._cell_numbering = self._plex.createSection([1], entity_dofs, perm=self._plex_renumbering) entity_dofs[:] = 0 entity_dofs[0] = 1 self._vertex_numbering = self._plex.createSection([1], entity_dofs, perm=self._plex_renumbering) # Note that for bendy elements, this needs to change. with timed_region("Mesh: coordinate field"): if periodic_coords is not None: if self.ufl_cell().geometric_dimension() != 1: raise NotImplementedError("Periodic coordinates in more than 1D are unsupported") # We've been passed a periodic coordinate field, so use that. self._coordinate_fs = functionspace.VectorFunctionSpace(self, "DG", 1) self.coordinates = function.Function(self._coordinate_fs, val=periodic_coords, name="Coordinates") else: self._coordinate_fs = functionspace.VectorFunctionSpace(self, "Lagrange", 1) coordinates = dmplex.reordered_coords(self._plex, self._coordinate_fs._global_numbering, (self.num_vertices(), geometric_dim)) self.coordinates = function.Function(self._coordinate_fs, val=coordinates, name="Coordinates") self._ufl_domain = ufl.Domain(self.coordinates) # Build a new ufl element for this function space with the # correct domain. This is necessary since this function space # is in the cache and will be picked up by later # VectorFunctionSpace construction. self._coordinate_fs._ufl_element = self._coordinate_fs.ufl_element().reconstruct(domain=self.ufl_domain()) # HACK alert! # Replace coordinate Function by one that has a real domain on it (but don't copy values) self.coordinates = function.Function(self._coordinate_fs, val=self.coordinates.dat) # Add subdomain_data to the measure objects we store with # the mesh. These are weakrefs for consistency with the # "global" measure objects self._dx = ufl.Measure('cell', subdomain_data=weakref.ref(self.coordinates)) self._ds = ufl.Measure('exterior_facet', subdomain_data=weakref.ref(self.coordinates)) self._dS = ufl.Measure('interior_facet', subdomain_data=weakref.ref(self.coordinates)) # Set the subdomain_data on all the default measures to this # coordinate field. # We don't set the domain on the measure since this causes # an uncollectable reference in the global space (dx is # global). Furthermore, it's never used anyway. for measure in [ufl.dx, ufl.ds, ufl.dS]: measure._subdomain_data = weakref.ref(self.coordinates)
def _from_dmplex(self, plex, geometric_dim=0, periodic_coords=None, reorder=None): """ Create mesh from DMPlex object """ self._plex = plex self.uid = utils._new_uid() # Mark exterior and interior facets # Note. This must come before distribution, because otherwise # DMPlex will consider facets on the domain boundary to be # exterior, which is wrong. dmplex.label_facets(self._plex) if geometric_dim == 0: geometric_dim = plex.getDimension() # Distribute the dm to all ranks if op2.MPI.comm.size > 1: self.parallel_sf = plex.distribute(overlap=1) self._plex = plex if reorder: old_to_new = self._plex.getOrdering(PETSc.Mat.OrderingType.RCM).indices reordering = np.empty_like(old_to_new) reordering[old_to_new] = np.arange(old_to_new.size, dtype=old_to_new.dtype) else: # No reordering reordering = None # Mark OP2 entities and derive the resulting Plex renumbering dmplex.mark_entity_classes(self._plex) self._plex_renumbering = dmplex.plex_renumbering(self._plex, reordering) cStart, cEnd = self._plex.getHeightStratum(0) # cells cell_vertices = self._plex.getConeSize(cStart) self._ufl_cell = ufl.Cell(fiat_utils._cells[geometric_dim][cell_vertices], geometric_dimension=geometric_dim) self._ufl_domain = ufl.Domain(self.ufl_cell(), data=self) dim = self._plex.getDimension() self._cells, self.cell_classes = dmplex.get_cells_by_class(self._plex) # Derive a cell numbering from the Plex renumbering cell_entity_dofs = np.zeros(dim+1, dtype=np.int32) cell_entity_dofs[-1] = 1 self._cell_numbering = self._plex.createSection(1, [1], cell_entity_dofs, perm=self._plex_renumbering) self._cell_closure = None self.interior_facets = None self.exterior_facets = None # Note that for bendy elements, this needs to change. if periodic_coords is not None: if self.ufl_cell().geometric_dimension() != 1: raise NotImplementedError("Periodic coordinates in more than 1D are unsupported") # We've been passed a periodic coordinate field, so use that. self._coordinate_fs = functionspace.VectorFunctionSpace(self, "DG", 1) self.coordinates = function.Function(self._coordinate_fs, val=periodic_coords, name="Coordinates") else: self._coordinate_fs = functionspace.VectorFunctionSpace(self, "Lagrange", 1) coordinates = dmplex.reordered_coords(self._plex, self._coordinate_fs._global_numbering, (self.num_vertices(), geometric_dim)) self.coordinates = function.Function(self._coordinate_fs, val=coordinates, name="Coordinates") self._ufl_domain = ufl.Domain(self.coordinates) # Build a new ufl element for this function space with the # correct domain. This is necessary since this function space # is in the cache and will be picked up by later # VectorFunctionSpace construction. self._coordinate_fs._ufl_element = self._coordinate_fs.ufl_element().reconstruct(domain=self.ufl_domain()) # HACK alert! # Replace coordinate Function by one that has a real domain on it (but don't copy values) self.coordinates = function.Function(self._coordinate_fs, val=self.coordinates.dat) # Add domain and subdomain_data to the measure objects we store with the mesh. self._dx = ufl.Measure('cell', domain=self, subdomain_data=self.coordinates) self._ds = ufl.Measure('exterior_facet', domain=self, subdomain_data=self.coordinates) self._dS = ufl.Measure('interior_facet', domain=self, subdomain_data=self.coordinates) # Set the subdomain_data on all the default measures to this # coordinate field. Also set the domain on the measure. for measure in [ufl.dx, ufl.ds, ufl.dS]: measure._subdomain_data = self.coordinates measure._domain = self.ufl_domain()