Fix quadratic cost in adaptive mesh refinement's coarse/fine cell-map construction - #5326
Merged
Conversation
… construction adaptive_parent_child_cell_maps resolved each fine cell's coarse parent with DMLabelGetValue, called once per fine cell. DMLabelGetValue should resolve a point in O(1); instead it scans every stratum of the label linearly. set_adaptive_parent_label gives every coarse cell its own stratum, so the loop was effectively O(nfine * ncoarse). Walk the label by stratum instead (DMLabelGetStratumSize/GetStratumIS, one call per coarse cell), which uses PETSc's O(1) value->stratum hash map and touches each fine cell exactly once: O(nfine + ncoarse). Also wrap refine_marked_elements's previously-unattributed sub-steps in PETSc.Log.Event so -log_view attributes time to the call that spent it instead of lumping it into refine_marked_elements's own self-time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pbrubeck
commented
Aug 5, 2026
The recorded multigrid iteration counts and convergence plot predate #5215's DMPlexTransform-based mesh adaptivity; regenerate both against current refine_marked_elements output. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Describe why walking by stratum is fast rather than reciting the removed point-wise loop's complexity. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pbrubeck
commented
Aug 5, 2026
connorjward
approved these changes
Aug 6, 2026
Contributor
Author
|
Thanks. CI failures are known. Merging |
leo-collins
pushed a commit
that referenced
this pull request
Aug 6, 2026
… construction (#5326) * Fix quadratic cost in adaptive mesh refinement's coarse/fine cell-map construction
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
adaptive_parent_child_cell_mapsresolved each fine cell's coarse parent with PETSc'sDMLabelGetValue, called once per fine cell.DMLabelGetValueshould resolve a point in O(1); instead it scans every stratum of the label linearly until it finds the one containing the queried point.set_adaptive_parent_labelgives every coarse cell its own stratum value, so on an adaptively refined mesh the per-fine-cell loop was effectively O(nfine · ncoarse), not O(nfine). Profilingadaptive_multigrid.pyunder-log_viewshowedrefine_marked_elementsdominated not by PETSc'srefine_sbrmesh transform itself, but by time attributed to this uninstrumented loop.adaptive_parent_child_cell_mapsnow walks the label by stratum instead, withDMLabelGetStratumSize/DMLabelGetStratumIS, one call per coarse cell. That uses PETSc's O(1) value→stratum hash map and touches each fine cell exactly once, so the loop is O(nfine + ncoarse). Output is unchanged — cross-checked bit-for-bit against the original point-wise result on refined netgen meshes.On the
AdaptiveMeshHierarchydemo (first 10 Dörfler-marked refinement levels of an L-shaped netgen mesh),adaptive_parent_child_cell_maps's share of time insiderefine_marked_elementsdrops from 59% to 8%, andrefine_marked_elements's own total drops by 55%. The dominant cost left insiderefine_marked_elementsis now legitimately PETSc's own mesh-refinement transform.Collateral changes
_adapt_marked_cellsandrefine_marked_elements(firedrake/adapt.py) gainedPETSc.Log.Eventwrappers around each of their previously-unattributed sub-steps (label marking,set_adaptive_parent_label, theadaptLabeltransform,Mesh()construction,adaptive_parent_child_cell_maps, re-marking, Netgen re-curving). Without them,-log_viewattributed all of this work torefine_marked_elements's own self-time rather than the call that actually spent it, which is what obscured this cost in the first place.The
adaptive_multigriddemo's recorded multigrid iteration counts and convergence plot predated #5215's DMPlexTransform-based mesh adaptivity; both are regenerated here against currentrefine_marked_elementsoutput.Tests
tests/firedrake/multigrid/test_adaptive_multigrid.pyalready exercisesadaptive_parent_child_cell_mapsacross firedrake/netgen meshes and process counts; it passes unchanged at nprocs 1/2/4.🤖 Generated with Claude Code