Found while re-running the adaptivity demos with the new mesh.relax() / adapt(..., relax=...).
In 3D, relaxing an adapted mesh can make the mesh-owned custom-P geometric-MG hierarchy fail to build:
custom_mg: mesh-owned FMG build failed (transfer 6->7 has 26 zero columns
(coarse DOFs with no fine image) — BC-per-level reduction failed; coarse
operator would be singular.); using the solver default preconditioner.
The solver then silently falls back to GAMG — correct answers, but much slower, and nothing tells the user their geometric hierarchy is gone.
Measured
Poisson MG gate, 3D box, refinement=2:
| config |
cells |
pc |
its |
| adapt only |
24594 |
mg |
2 |
| adapt + relax (at end) |
24594 |
mg |
2 |
adapt + relax "per-generation" |
24160 |
gamg |
23 |
and in the larger combine_mmpde_nvb_3d.py demo (max_levels=2, ~36k cells), relax-at-end also failed — transfer 6->7 has 26 zero columns, pc=gamg, 26 its. So both placements are affected; whether it trips appears to depend on mesh size / depth rather than on the placement.
2D is unaffected in everything tested: pc=mg throughout, Stokes velocity block and Poisson, 2 its.
Likely mechanism
The custom-P prolongation is built by locating fine DOFs inside coarse cells (barycentric). Relaxation moves the fine level coordinates; some coarse DOF then has no fine DOF mapping to it, giving a zero column and a singular coarse operator. 3D is presumably more exposed because tetrahedral point location is less forgiving than triangular.
Why it matters
adapt(..., relax=True) is documented as safe for MG on the strength of 2D measurements. That claim is wrong in 3D and the docs are being corrected alongside this issue.
Suggested directions
- The fallback should be loud — an adapted+relaxed mesh silently losing its geometric hierarchy is the kind of thing that shows up as "why is my 3D solve slow" months later.
- The transfer builder could tolerate zero columns by falling back to nearest-neighbour / RBF for the orphaned coarse DOFs rather than rejecting the whole level (an RBF builder already exists).
- Or relaxation could be constrained so no fine DOF leaves its coarse parent cell — a step cap tied to the coarse cell size.
Reproducer: ~/+Simulations/nvb_3d_adapt_evaluation/combine_mmpde_nvb_3d.py (case C), and the smaller isolation above.
Found while re-running the adaptivity demos with the new
mesh.relax()/adapt(..., relax=...).In 3D, relaxing an adapted mesh can make the mesh-owned custom-P geometric-MG hierarchy fail to build:
The solver then silently falls back to GAMG — correct answers, but much slower, and nothing tells the user their geometric hierarchy is gone.
Measured
Poisson MG gate, 3D box,
refinement=2:mgmg"per-generation"gamgand in the larger
combine_mmpde_nvb_3d.pydemo (max_levels=2, ~36k cells), relax-at-end also failed —transfer 6->7 has 26 zero columns,pc=gamg, 26 its. So both placements are affected; whether it trips appears to depend on mesh size / depth rather than on the placement.2D is unaffected in everything tested:
pc=mgthroughout, Stokes velocity block and Poisson, 2 its.Likely mechanism
The custom-P prolongation is built by locating fine DOFs inside coarse cells (barycentric). Relaxation moves the fine level coordinates; some coarse DOF then has no fine DOF mapping to it, giving a zero column and a singular coarse operator. 3D is presumably more exposed because tetrahedral point location is less forgiving than triangular.
Why it matters
adapt(..., relax=True)is documented as safe for MG on the strength of 2D measurements. That claim is wrong in 3D and the docs are being corrected alongside this issue.Suggested directions
Reproducer:
~/+Simulations/nvb_3d_adapt_evaluation/combine_mmpde_nvb_3d.py(case C), and the smaller isolation above.