def get_node_set(mesh, nodes_per_entity): """Get the :class:`node set <pyop2.Set>`. :arg mesh: The mesh to use. :arg nodes_per_entity: The number of function space nodes per topological entity. :returns: A :class:`pyop2.Set` for the function space nodes. """ global_numbering = get_global_numbering(mesh, nodes_per_entity) # Use a DM to create the halo SFs dm = PETSc.DMShell().create(mesh.comm) dm.setPointSF(mesh._plex.getPointSF()) dm.setDefaultSection(global_numbering) node_classes = tuple(numpy.dot(nodes_per_entity, mesh._entity_classes)) node_set = op2.Set(node_classes, halo=halo_mod.Halo(dm), comm=mesh.comm) # Don't need it any more, explicitly destroy. dm.destroy() extruded = bool(mesh.layers) if extruded: node_set = op2.ExtrudedSet(node_set, layers=mesh.layers) assert global_numbering.getStorageSize() == node_set.total_size if not extruded and node_set.total_size >= (1 << (IntType.itemsize * 8 - 4)): raise RuntimeError( "Problems with more than %d nodes per process unsupported", (1 << (IntType.itemsize * 8 - 4))) return node_set
def _dm(self): """A PETSc DM describing the data layout for fieldsplit solvers.""" dm = PETSc.DMShell().create() dm.setAttr('__fs__', weakref.ref(self)) dm.setCreateFieldDecomposition(self.create_field_decomp) dm.setCreateSubDM(self.create_subdm) dm.setGlobalVector(self.dof_dset.layout_vec) return dm
def _dm(self): """A PETSc DM describing the data layout for this FunctionSpace.""" dm = PETSc.DMShell().create() dm.setAttr('__fs__', weakref.ref(self)) dm.setPointSF(self.mesh()._plex.getPointSF()) dm.setDefaultSection(self._shared_data.global_numbering) dm.setGlobalVector(self.dof_dset.layout_vec) return dm
def __new__(cls, spaces, name=None): """ :param spaces: a list (or tuple) of :class:`FunctionSpace`\s The function space may be created as :: V = MixedFunctionSpace(spaces) ``spaces`` may consist of multiple occurances of the same space: :: P1 = FunctionSpace(mesh, "CG", 1) P2v = VectorFunctionSpace(mesh, "Lagrange", 2) ME = MixedFunctionSpace([P2v, P1, P1, P1]) """ # Check that function spaces are on the same mesh meshes = [space.mesh() for space in spaces] for i in xrange(1, len(meshes)): if meshes[i] is not meshes[0]: raise ValueError( "All function spaces must be defined on the same mesh!") # Select mesh mesh = meshes[0] # Get topological spaces spaces = flatten(spaces) if mesh is mesh.topology: spaces = tuple(spaces) else: spaces = tuple(space.topological for space in spaces) # Ask object from cache self = ObjectCached.__new__(cls, mesh, spaces, name) if not self._initialized: self._spaces = [ IndexedFunctionSpace(s, i, self) for i, s in enumerate(spaces) ] self._mesh = mesh.topology self._ufl_element = ufl.MixedElement( *[fs.ufl_element() for fs in spaces]) self.name = name or '_'.join(str(s.name) for s in spaces) self._initialized = True dm = PETSc.DMShell().create() with self.make_dat().vec_ro as v: dm.setGlobalVector(v.duplicate()) dm.setAttr('__fs__', weakref.ref(self)) dm.setCreateFieldDecomposition(self.create_field_decomp) dm.setCreateSubDM(self.create_subdm) self._dm = dm self._ises = self.dof_dset.field_ises self._subspaces = [] if mesh is not mesh.topology: self = WithGeometry(self, mesh) return self
def initialize(self, pc): # Make a new DM. # Hook up a (new) coarsen routine on that DM. # Make a new PC, of type MG. # Assign the DM to that PC. odm = pc.getDM() ctx = get_appctx(odm) test, trial = ctx.J.arguments() if test.function_space() != trial.function_space(): raise NotImplementedError("test and trial spaces must be the same") prefix = pc.getOptionsPrefix() options_prefix = prefix + "pmg_" pdm = PETSc.DMShell().create(comm=pc.comm) pdm.setOptionsPrefix(options_prefix) # Get the coarse degree from PETSc options self.coarse_degree = PETSc.Options(options_prefix).getInt("mg_coarse_degree", default=1) # Construct a list with the elements we'll be using V = test.function_space() ele = V.ufl_element() elements = [ele] while True: try: ele_ = self.coarsen_element(ele) assert ele_.value_shape() == ele.value_shape() ele = ele_ except ValueError: break elements.append(ele) sf = odm.getPointSF() section = odm.getDefaultSection() attach_hooks(pdm, level=len(elements)-1, sf=sf, section=section) # Now overwrite some routines on the DM pdm.setRefine(None) pdm.setCoarsen(self.coarsen) pdm.setCreateInterpolation(self.create_interpolation) # We need this for p-FAS pdm.setCreateInjection(self.create_injection) pdm.setSNESJacobian(_SNESContext.form_jacobian) pdm.setSNESFunction(_SNESContext.form_function) pdm.setKSPComputeOperators(_SNESContext.compute_operators) set_function_space(pdm, get_function_space(odm)) parent = get_parent(odm) assert parent is not None add_hook(parent, setup=partial(push_parent, pdm, parent), teardown=partial(pop_parent, pdm, parent), call_setup=True) add_hook(parent, setup=partial(push_appctx, pdm, ctx), teardown=partial(pop_appctx, pdm, ctx), call_setup=True) self.ppc = self.configure_pmg(pc, pdm) self.ppc.setFromOptions() self.ppc.setUp()
def __init__(self, spaces, name=None): """ :param spaces: a list (or tuple) of :class:`FunctionSpace`\s The function space may be created as :: V = MixedFunctionSpace(spaces) ``spaces`` may consist of multiple occurances of the same space: :: P1 = FunctionSpace(mesh, "CG", 1) P2v = VectorFunctionSpace(mesh, "Lagrange", 2) ME = MixedFunctionSpace([P2v, P1, P1, P1]) """ if self._initialized: return self._spaces = [ IndexedFunctionSpace(s, i, self) for i, s in enumerate(flatten(spaces)) ] self._mesh = self._spaces[0].mesh() self._ufl_element = ufl.MixedElement( *[fs.ufl_element() for fs in self._spaces]) self.name = name or '_'.join(str(s.name) for s in self._spaces) self.rank = 1 self._index = None self._initialized = True dm = PETSc.DMShell().create() from firedrake.function import Function with Function(self).dat.vec_ro as v: dm.setGlobalVector(v.duplicate()) dm.setAttr('__fs__', weakref.ref(self)) dm.setCreateFieldDecomposition(self.create_field_decomp) dm.setCreateSubDM(self.create_subdm) self._dm = dm self._ises = self.dof_dset.field_ises self._subspaces = []
def get_node_set(mesh, nodes_per_entity): """Get the :class:`node set <pyop2.Set>`. :arg mesh: The mesh to use. :arg nodes_per_entity: The number of function space nodes per topological entity. :returns: A :class:`pyop2.Set` for the function space nodes. """ global_numbering = get_global_numbering(mesh, nodes_per_entity) # Use a DM to create the halo SFs dm = PETSc.DMShell().create() dm.setPointSF(mesh._plex.getPointSF()) dm.setDefaultSection(global_numbering) node_classes = tuple(numpy.dot(nodes_per_entity, mesh._entity_classes)) node_set = op2.Set(node_classes, halo=halo_mod.Halo(dm)) # Don't need it any more, explicitly destroy. dm.destroy() extruded = bool(mesh.layers) if extruded: node_set = op2.ExtrudedSet(node_set, layers=mesh.layers) assert global_numbering.getStorageSize() == node_set.total_size return node_set
def __init__(self, dm, section): super(Halo, self).__init__() # Use a DM to create the halo SFs self.dm = PETSc.DMShell().create(dm.comm) self.dm.setPointSF(dm.getPointSF()) self.dm.setDefaultSection(section)
def initialize(self, pc): # Make a new DM. # Hook up a (new) coarsen routine on that DM. # Make a new PC, of type MG. # Assign the DM to that PC. odm = pc.getDM() ctx = get_appctx(odm) test, trial = ctx.J.arguments() if test.function_space() != trial.function_space(): raise NotImplementedError("test and trial spaces must be the same") # Construct a list with the elements we'll be using V = test.function_space() ele = V.ufl_element() elements = [ele] while True: try: ele_ = self.coarsen_element(ele) assert ele_.value_shape() == ele.value_shape() ele = ele_ except ValueError: break elements.append(ele) pdm = PETSc.DMShell().create(comm=pc.comm) sf = odm.getPointSF() section = odm.getDefaultSection() attach_hooks(pdm, level=len(elements) - 1, sf=sf, section=section) # Now overwrite some routines on the DM pdm.setRefine(None) pdm.setCoarsen(self.coarsen) pdm.setCreateInterpolation(self.create_interpolation) pdm.setOptionsPrefix(pc.getOptionsPrefix() + "pmg_") set_function_space(pdm, get_function_space(odm)) parent = get_parent(odm) assert parent is not None add_hook(parent, setup=partial(push_parent, pdm, parent), teardown=partial(pop_parent, pdm, parent), call_setup=True) add_hook(parent, setup=partial(push_appctx, pdm, ctx), teardown=partial(pop_appctx, pdm, ctx), call_setup=True) ppc = PETSc.PC().create(comm=pc.comm) ppc.setOptionsPrefix(pc.getOptionsPrefix() + "pmg_") ppc.setType("mg") ppc.setOperators(*pc.getOperators()) ppc.setDM(pdm) ppc.incrementTabLevel(1, parent=pc) # PETSc unfortunately requires us to make an ugly hack. # We would like to use GMG for the coarse solve, at least # sometimes. But PETSc will use this p-DM's getRefineLevels() # instead of the getRefineLevels() of the MeshHierarchy to # decide how many levels it should use for PCMG applied to # the p-MG's coarse problem. So we need to set an option # for the user, if they haven't already; I don't know any # other way to get PETSc to know this at the right time. opts = PETSc.Options(pc.getOptionsPrefix() + "pmg_") if "mg_coarse_pc_mg_levels" not in opts: opts["mg_coarse_pc_mg_levels"] = odm.getRefineLevel() + 1 ppc.setFromOptions() ppc.setUp() self.ppc = ppc
def __init__(self, mesh, element, name=None, dim=1, rank=0): """ :param mesh: :class:`Mesh` to build this space on :param element: :class:`ufl.FiniteElementBase` to build this space from :param name: user-defined name for this space :param dim: vector space dimension of a :class:`.VectorFunctionSpace` :param rank: rank of the space, not the value rank """ self._ufl_element = element # Compute the FIAT version of the UFL element above self.fiat_element = fiat_utils.fiat_from_ufl_element(element) if isinstance(mesh, mesh_t.ExtrudedMesh): # Set up some extrusion-specific things # The bottom layer maps will come from element_dof_list # dof_count is the total number of dofs in the extruded mesh # Get the flattened version of the FIAT element self.flattened_element = fiat_utils.FlattenedElement( self.fiat_element) # Compute the number of DoFs per dimension on top/bottom and sides entity_dofs = self.fiat_element.entity_dofs() top_dim = mesh._plex.getDimension() self._xtr_hdofs = [ len(entity_dofs[(d, 0)][0]) for d in range(top_dim + 1) ] self._xtr_vdofs = [ len(entity_dofs[(d, 1)][0]) for d in range(top_dim + 1) ] # Compute the dofs per column self.dofs_per_column = eutils.compute_extruded_dofs( self.fiat_element, self.flattened_element.entity_dofs(), mesh._layers) # Compute the offset for the extrusion process self.offset = eutils.compute_offset( self.fiat_element.entity_dofs(), self.flattened_element.entity_dofs(), self.fiat_element.space_dimension()) # Compute the top and bottom masks to identify boundary dofs # # Sorting the keys of the closure entity dofs, the whole cell # comes last [-1], before that the horizontal facet [-2], before # that vertical facets [-3]. We need the horizontal facets here. closure_dofs = self.fiat_element.entity_closure_dofs() b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0] t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1] self.bt_masks = (b_mask, t_mask) # conversion to tuple self.extruded = True self._dofs_per_entity = self.dofs_per_column else: # If not extruded specific, set things to None/False, etc. self.offset = None self.bt_masks = None self.dofs_per_column = np.zeros(1, np.int32) self.extruded = False entity_dofs = self.fiat_element.entity_dofs() self._dofs_per_entity = [ len(entity[0]) for d, entity in entity_dofs.iteritems() ] self.name = name self._dim = dim self._mesh = mesh self._index = None dm = PETSc.DMShell().create() dm.setAttr('__fs__', weakref.ref(self)) dm.setPointSF(mesh._plex.getPointSF()) # Create the PetscSection mapping topological entities to DoFs sec = mesh._plex.createSection([1], self._dofs_per_entity, perm=mesh._plex_renumbering) dm.setDefaultSection(sec) self._global_numbering = sec self._dm = dm self._ises = None self._halo = halo.Halo(dm) # Compute entity class offsets self.dof_classes = [0, 0, 0, 0] for d in range(mesh._plex.getDimension() + 1): ndofs = self._dofs_per_entity[d] for i in range(4): self.dof_classes[i] += ndofs * mesh._entity_classes[d, i] # Tell the DM about the layout of the global vector from firedrake.function import Function with Function(self).dat.vec_ro as v: self._dm.setGlobalVector(v.duplicate()) self._node_count = self._global_numbering.getStorageSize() self.cell_node_list = mesh.create_cell_node_list( self._global_numbering, self.fiat_element) if mesh._plex.getStratumSize("interior_facets", 1) > 0: self.interior_facet_node_list = \ dmplex.get_facet_nodes(mesh.interior_facets.facet_cell, self.cell_node_list) else: self.interior_facet_node_list = np.array([], dtype=np.int32) if mesh._plex.getStratumSize("exterior_facets", 1) > 0: self.exterior_facet_node_list = \ dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell, self.cell_node_list) else: self.exterior_facet_node_list = np.array([], dtype=np.int32) # Note: this is the function space rank. The value rank may be different. self.rank = rank # Empty map caches. This is a sui generis cache # implementation because of the need to support boundary # conditions. self._cell_node_map_cache = {} self._exterior_facet_map_cache = {} self._interior_facet_map_cache = {}
def __new__(cls, mesh, element, name=None, shape=()): """ :param mesh: :class:`MeshTopology` to build this space on :param element: :class:`ufl.FiniteElementBase` to build this space from :param name: user-defined name for this space :param shape: shape of a :class:`.VectorFunctionSpace` or :class:`.TensorFunctionSpace` """ assert mesh.ufl_cell() == element.cell() self = super(FunctionSpaceBase, cls).__new__(cls, mesh, element, name, shape) if self._initialized: return self self._mesh = mesh self._ufl_element = element self.name = name self._shape = shape # Compute the FIAT version of the UFL element above self.fiat_element = fiat_utils.fiat_from_ufl_element(element) entity_dofs = self.fiat_element.entity_dofs() dofs_per_entity = mesh.make_dofs_per_plex_entity(entity_dofs) self.extruded = bool(mesh.layers) self.offset = mesh.make_offset(entity_dofs, self.fiat_element.space_dimension()) if mesh.layers: # Compute the top and bottom masks to identify boundary dofs # # Sorting the keys of the closure entity dofs, the whole cell # comes last [-1], before that the horizontal facet [-2], before # that vertical facets [-3]. We need the horizontal facets here. closure_dofs = self.fiat_element.entity_closure_dofs() b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0] t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1] self.bt_masks = {} self.bt_masks["topological"] = (b_mask, t_mask ) # conversion to tuple # Geometric facet dofs facet_dofs = horiz_facet_support_dofs(self.fiat_element) self.bt_masks["geometric"] = (facet_dofs[0], facet_dofs[1]) else: self.bt_masks = None dm = PETSc.DMShell().create() dm.setAttr('__fs__', weakref.ref(self)) dm.setPointSF(mesh._plex.getPointSF()) # Create the PetscSection mapping topological entities to DoFs sec = mesh._plex.createSection([1], dofs_per_entity, perm=mesh._plex_renumbering) dm.setDefaultSection(sec) self._global_numbering = sec self._dm = dm self._ises = None self._halo = halo.Halo(dm) # Compute entity class offsets self.dof_classes = [0, 0, 0, 0] for d in range(mesh._plex.getDimension() + 1): ndofs = dofs_per_entity[d] for i in range(4): self.dof_classes[i] += ndofs * mesh._entity_classes[d, i] # Tell the DM about the layout of the global vector with self.make_dat().vec_ro as v: self._dm.setGlobalVector(v.duplicate()) self._node_count = self._global_numbering.getStorageSize() self.cell_node_list = mesh.make_cell_node_list(self._global_numbering, entity_dofs) if mesh._plex.getStratumSize("interior_facets", 1) > 0: self.interior_facet_node_list = \ dmplex.get_facet_nodes(mesh.interior_facets.facet_cell, self.cell_node_list) else: self.interior_facet_node_list = np.array([], dtype=np.int32) if mesh._plex.getStratumSize("exterior_facets", 1) > 0: self.exterior_facet_node_list = \ dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell, self.cell_node_list) else: self.exterior_facet_node_list = np.array([], dtype=np.int32) # Empty map caches. This is a sui generis cache # implementation because of the need to support boundary # conditions. self._cell_node_map_cache = {} self._exterior_facet_map_cache = {} self._interior_facet_map_cache = {} self._initialized = True return self