Source code for firedrake.mg.adaptive_hierarchy

from firedrake.mesh import MeshGeometry
from firedrake.cofunction import Cofunction
from firedrake.function import Function
from firedrake.mg import HierarchyBase
from firedrake.mg.utils import set_level

__all__ = ["AdaptiveMeshHierarchy"]


[docs] class AdaptiveMeshHierarchy(HierarchyBase): """ HierarchyBase for hierarchies of adaptively refined meshes. Parameters ---------- base_mesh The coarsest mesh in the hierarchy. nested: bool A flag to indicate whether the meshes are nested. """ def __init__(self, base_mesh: MeshGeometry, nested: bool = True): self.meshes = [] self._meshes = [] self.nested = nested self.add_mesh(base_mesh)
[docs] def add_mesh(self, mesh: MeshGeometry): """ Adds a mesh into the hierarchy. Parameters ---------- mesh The mesh to be added to the finest level. """ level = len(self.meshes) self._meshes.append(mesh) self.meshes.append(mesh) set_level(mesh, self, level)
[docs] def adapt(self, eta: Function | Cofunction, theta: float): """ Adds a new mesh to the hierarchy by locally refining the finest mesh with a simplified variant of Dorfler marking. The finest mesh must come from a netgen mesh. Parameters ---------- eta A DG0 :class:`~firedrake.function.Function` with the local error estimator. theta The threshold for marking as a fraction of the maximum error. Note ---- Dorfler marking involves sorting all of the elements by decreasing error estimator and taking the minimal set that exceeds some fixed fraction of the total error. What this code implements is the simpler variant that doesn't have a proof of convergence (as far as I know) but works as well in practice. """ if not isinstance(eta, (Function, Cofunction)): raise TypeError(f"eta must be a Function or Cofunction, not a {type(eta).__name__}") M = eta.function_space() if M.finat_element.space_dimension() != 1: raise ValueError("eta must be a Function or Cofunction in DG0") mesh = self.meshes[-1] if M.mesh() is not mesh: raise ValueError("eta must be defined on the finest mesh of the hierarchy") # Take the maximum over all processes with eta.dat.vec_ro as evec: _, eta_max = evec.max() threshold = theta * eta_max should_refine = eta.dat.data_ro > threshold markers = Function(M) markers.dat.data_wo[should_refine] = 1 refined_mesh = mesh.refine_marked_elements(markers) self.add_mesh(refined_mesh) return refined_mesh