-
Notifications
You must be signed in to change notification settings - Fork 201
Adaptive Multigrid #4726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Adaptive Multigrid #4726
Changes from 13 commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
ff94938
Adaptive Multigrid
pbrubeck b585c34
Merge branch 'main' into pbrubeck/adaptive-mg
pbrubeck cf0b36e
Fix complex tests
pbrubeck 8312598
complex
pbrubeck 94a0fd0
merge conflict
pbrubeck 6b69bf9
Apply suggestions from code review
pbrubeck fa2cce8
Merge branch 'main' into pbrubeck/adaptive-mg
pbrubeck 18de9b8
WIP
pbrubeck 5c23e5e
Remove Submesh
pbrubeck 433a4b0
Fix tests
pbrubeck 706e303
Apply suggestions from code review
pbrubeck 8dd0e66
fixup
pbrubeck c40a36b
Apply suggestions from code review
pbrubeck 76c2d59
enable tests
leo-collins 67a5a0c
remove check
leo-collins e637d6f
add test
leo-collins 4d23dc2
update test
leo-collins 5c84b12
update tests
leo-collins d8a1ac3
WIP
leo-collins 8c255e2
fix test
leo-collins 40c1252
WIP
leo-collins b5ebf32
fix target_space
leo-collins a2789da
two-form assembly working
leo-collins 986ce11
Apply suggestions from code review
pbrubeck e1dba6b
docs
pbrubeck 10f8516
forward and adjoint one-form
leo-collins fc17045
fixes
leo-collins cb92d81
working
leo-collins cf1d747
add zero-form test
leo-collins 170bcb4
fix tests
leo-collins 76a9323
docs
leo-collins 5979f71
fixes
leo-collins 1625b3b
Added demo for performing adaptive multigrid (#4535)
AnuragRao1 76f3942
Edits
pefarrell eedf0ad
fix test
leo-collins 139ec33
MG iteration counts
pbrubeck 862b943
fixes
pbrubeck f3352c3
review suggestions
leo-collins 0ea4dc7
fix latex
pbrubeck 86aa644
Merge branch 'leo/cross-mesh-non-lagrange' into pbrubeck/adaptive-mg
pbrubeck 9b46f42
Use native interpolation
pbrubeck b7289f3
merge conflict
pbrubeck c643c52
merge conflict
pbrubeck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| """ | ||
| This module contains the class for the AdaptiveMeshHierarchy and | ||
| related helper functions | ||
| """ | ||
|
|
||
| from collections import defaultdict | ||
|
|
||
| from firedrake.cofunction import Cofunction | ||
| from firedrake.function import Function | ||
| from firedrake.mg import HierarchyBase | ||
| from firedrake.mg.utils import set_level | ||
|
|
||
| __all__ = ["AdaptiveMeshHierarchy"] | ||
|
|
||
|
|
||
| class AdaptiveMeshHierarchy(HierarchyBase): | ||
| """ | ||
| HierarchyBase for hierarchies of adaptively refined meshes | ||
| """ | ||
| def __init__(self, base_mesh, refinements_per_level=1, nested=True): | ||
| self.meshes = [] | ||
| self._meshes = [] | ||
| self.refinements_per_level = refinements_per_level | ||
| self.nested = nested | ||
| self.add_mesh(base_mesh) | ||
|
|
||
| def add_mesh(self, mesh): | ||
| """ | ||
| Adds newly refined mesh into hierarchy. | ||
| """ | ||
| self._meshes.append(mesh) | ||
| self.meshes.append(mesh) | ||
| level = len(self.meshes) | ||
| set_level(self.meshes[-1], self, level - 1) | ||
| self._shared_data_cache = defaultdict(dict) | ||
|
|
||
| def adapt(self, eta: Function | Cofunction, theta: float): | ||
| """ | ||
| Add a refinement level to the hierarchy by local refinement | ||
| with a simplified variant of Dorfler marking. | ||
|
|
||
| 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 eta_: | ||
| eta_max = eta_.max()[1] | ||
|
pbrubeck marked this conversation as resolved.
Outdated
|
||
|
|
||
| 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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| """ | ||
| This module contains the AdaptiveTransferManager used to perform | ||
| transfer operations on AdaptiveMeshHierarchies | ||
| """ | ||
| from firedrake.mg.embedded import TransferManager | ||
| from firedrake.ufl_expr import action, TrialFunction | ||
| from firedrake.functionspace import FunctionSpace, TensorFunctionSpace | ||
| from firedrake.interpolation import interpolate | ||
| from firedrake.preconditioners.bddc import is_lagrange | ||
| from finat.quadrature import QuadratureRule | ||
| from functools import partial | ||
|
|
||
| import numpy | ||
|
|
||
|
|
||
| __all__ = ("AdaptiveTransferManager",) | ||
|
|
||
|
|
||
| class AdaptiveTransferManager(TransferManager): | ||
|
pbrubeck marked this conversation as resolved.
|
||
| """ | ||
| TransferManager for adaptively refined mesh hierarchies | ||
| """ | ||
| def __init__(self, *, native_transfers=None, use_averaging=True): | ||
| super().__init__(native_transfers=native_transfers, use_averaging=use_averaging) | ||
| self.cache = {} | ||
|
|
||
| def get_operators(self, Vc, Vf): | ||
| key = (Vc, Vf) | ||
| try: | ||
| return self.cache[key] | ||
| except KeyError: | ||
| ops = get_mg_interpolator(Vc, Vf) | ||
| return self.cache.setdefault(key, ops) | ||
|
|
||
| def forward(self, uc, uf): | ||
| from firedrake.assemble import assemble | ||
| Vc = uc.function_space() | ||
| Vf = uf.function_space() | ||
| ops = self.get_operators(Vc, Vf) | ||
|
|
||
| expr = uc | ||
| for op in ops: | ||
| expr = action(op, expr) | ||
| return assemble(expr, tensor=uf) | ||
|
|
||
| def adjoint(self, uf, uc): | ||
| from firedrake.assemble import assemble | ||
| Vc = uc.function_space().dual() | ||
| Vf = uf.function_space().dual() | ||
| ops = self.get_operators(Vc, Vf) | ||
|
|
||
| expr = uf | ||
| for op in reversed(ops): | ||
| expr = action(expr, op) | ||
| return assemble(expr, tensor=uc) | ||
|
|
||
| def prolong(self, uf, uc): | ||
| return self.forward(uf, uc) | ||
|
|
||
| def inject(self, uc, uf): | ||
| return self.forward(uc, uf) | ||
|
|
||
| def restrict(self, uc, uf): | ||
| return self.adjoint(uc, uf) | ||
|
|
||
|
|
||
| def make_quadrature_space(V): | ||
| fe = V.finat_element | ||
| _, ps = fe.dual_basis | ||
| wts = numpy.full(len(ps.points), numpy.nan) | ||
| scheme = QuadratureRule(ps, wts, ref_el=fe.cell) | ||
| if V.value_shape == (): | ||
| make_space = FunctionSpace | ||
| else: | ||
| make_space = partial(TensorFunctionSpace, shape=V.value_shape) | ||
| return make_space(V.mesh(), "Quadrature", degree=fe.degree, quad_scheme=scheme) | ||
|
|
||
|
|
||
| def get_mg_interpolator(V1, V2): | ||
| from firedrake.assemble import assemble | ||
| if is_lagrange(V2.finat_element): | ||
| spaces = (V1, V2) | ||
| else: | ||
| Q2 = make_quadrature_space(V2) | ||
| spaces = (V1, Q2, V2) | ||
|
|
||
| ops = [] | ||
| for i in range(len(spaces)-1): | ||
| Vsrc = spaces[i] | ||
| Vdest = spaces[i+1] | ||
| Iexpr = interpolate(TrialFunction(Vsrc), Vdest) | ||
| op = assemble(Iexpr, mat_type="aij") | ||
| ops.append(op) | ||
| return ops | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.