Skip to content

Conversation

@pbrubeck
Copy link
Contributor

Description

@pbrubeck pbrubeck force-pushed the pbrubeck/adaptive-mg branch 2 times, most recently from b1a3ac2 to cc7d814 Compare November 18, 2025 08:59
@pbrubeck pbrubeck force-pushed the pbrubeck/adaptive-mg branch from cc7d814 to ff94938 Compare November 18, 2025 14:37
@pbrubeck pbrubeck requested a review from pefarrell January 5, 2026 23:24
"""

def __init__(self, mesh, refinements_per_level=1, nested=True):
self.meshes = tuple(mesh)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it make two independent tuples of mesh?

Then computes the coarse_to_fine and fine_to_coarse mappings.
Constructs intermediate submesh hierarchies with this.
"""
if mesh.topological_dimension <= 2:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these bounds empirically determined, or are they guaranteed by theory?

(coarse_splits, fine_splits, num_children) = split_to_submesh(
mesh, coarse_mesh, c2f, f2c
)
for i in range(1, max_children + 1):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment for what this is doing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More generally some comments for all the steps below would be useful, I don't have the big picture of what they are trying to do.

markers = Function(W)

with eta.dat.vec_ro as eta_:
eta_max = eta_.max()[1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this taking the max over all processes (global communication), or just over the local part of eta?


def adapt(self, eta, theta):
"""
Implement Dorfler marking, refines mesh from error estimator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct, Dörfler 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.


def recombine(self, split_funcs, f, child=True):
"""
Recombines functions on submeshes back full mesh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix comment

__all__ = ("AdaptiveTransferManager",)


class AdaptiveTransferManager(TransferManager):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I wanted to use a custom transfer operator (for e.g. some complicated multigrid thing), does this class compose with that?

@@ -0,0 +1,365 @@
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests look persuasive.

Do we have any profiled runs of using AdaptiveMeshHierarchy (where all elements are refined) vs MeshHierarchy to see how much the overhead is, and where that overhead is spent?

Copy link
Member

@dham dham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs a manual section and docstrings need to document where netgen meshes are required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants