Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions docs/advanced/figures/bench_fmg_vs_gamg_velocity_ksp.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
adapt_step,fmg_vel_ksp_its,fmg_snes_reason,fmg_t_stokes_s,gamg_vel_ksp_its,gamg_snes_reason,gamg_t_stokes_s
1,5,3,2.97,113,3,4.02
2,4,3,2.83,64,3,18.54
3,3,3,5.85,111,3,6.18
4,3,3,4.79,112,3,6.00
5,4,3,2.93,71,3,15.83
6,4,3,3.11,87,3,17.88
7,4,3,2.98,90,3,17.81
8,5,3,4.57,107,3,6.41
9,4,3,10.12,89,3,15.76
10,4,3,9.46,90,3,16.02
11,4,3,9.42,112,3,12.17
12,5,3,7.87,112,3,16.04
13,5,3,5.01,79,3,17.48
14,5,3,8.23,111,3,16.68
15,4,3,8.09,113,3,18.80
16,5,3,8.29,116,3,15.58
17,5,3,8.23,116,3,18.02
18,5,3,9.10,113,3,21.25
19,5,3,10.11,115,3,21.99
20,6,3,9.84,69,3,24.06
21,6,3,10.44,123,3,22.41
22,6,3,11.00,122,3,24.98
23,5,3,12.64,117,3,25.87
24,5,3,13.22,112,3,21.44
25,5,3,16.53,87,3,37.25
26,5,3,15.86,118,3,35.63
27,5,3,20.67,122,3,29.64
28,4,3,21.11,124,3,32.49
29,5,3,32.59,131,3,31.71
30,6,3,33.49,127,3,27.85
31,5,3,21.81,127,3,21.79
32,5,3,25.16,125,3,22.17
33,5,3,20.27,122,3,22.54
34,5,3,16.23,118,3,24.23
35,6,3,15.01,117,3,20.54
36,6,3,14.84,114,3,18.34
37,6,3,12.57,114,3,18.48
38,6,3,12.76,113,3,22.77
39,5,3,13.56,108,3,21.46
40,5,3,12.73,90,3,21.64
41,6,3,12.76,115,3,18.44
42,5,3,12.16,115,3,19.01
43,5,3,11.32,115,3,17.96
44,5,3,10.94,88,3,22.03
45,5,3,10.85,118,3,22.92
46,5,3,10.52,98,3,26.26
47,5,3,9.12,108,3,16.03
48,5,3,9.08,124,3,15.25
49,5,3,8.91,124,3,15.04
50,5,3,8.75,119,3,15.42
121 changes: 121 additions & 0 deletions docs/advanced/figures/bench_fmg_vs_gamg_velocity_ksp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
orphan: true
---

# Handover — FMG vs GAMG benchmark figure + adaptive-convection animation

Produced 2026-06-11 from the boundary-slip / anisotropic-mover branch (PR #228).
Two assets: a solver-scaling **benchmark figure** (for `docs/advanced/`) and an
**animation** of the same run (for the PR description / a docs gallery).

## Absolute locations (the worktree may differ — use these)

- **Figure + CSV + this note** — currently *uncommitted* in the feature worktree:
`/Users/lmoresi/+Underworld/underworld3-pixi/.claude/worktrees/gmg-geometric-interp/docs/advanced/figures/`
Once PR #228 merges they live in the main checkout at
`/Users/lmoresi/+Underworld/underworld3-pixi/docs/advanced/figures/`
(repo-relative `docs/advanced/figures/` — stable in any checkout).
- **Animation, per-step PNGs, render scripts** — on disk, not in the repo:
`/Users/lmoresi/+Simulations/StagnantLid/anim_full_Ra1e7_dEta1e3_res32_R8_mode1/`
(frames + GIFs) and `/Users/lmoresi/+Simulations/StagnantLid/` (`_render_clean.py`,
`_render_watch.py`).
- **Harness** — `scripts/stagnant_lid_adapt_loop.py` in the repo (currently
`/Users/lmoresi/+Underworld/underworld3-pixi/.claude/worktrees/gmg-geometric-interp/scripts/stagnant_lid_adapt_loop.py`).

The repo-relative paths used in the docs-reference snippets below are intentional
— image references resolve relative to the docs page, not the filesystem.

---

## 1. Benchmark figure — `bench_fmg_vs_gamg_velocity_ksp.svg`

**Files (here, `docs/advanced/figures/`):**
- `bench_fmg_vs_gamg_velocity_ksp.svg` — two-panel figure (text is `svg.fonttype=none`, so selectable/scalable).
- `bench_fmg_vs_gamg_velocity_ksp.csv` — the underlying per-step data:
`adapt_step, fmg_vel_ksp_its, fmg_snes_reason, fmg_t_stokes_s, gamg_vel_ksp_its, gamg_snes_reason, gamg_t_stokes_s`.

**What it shows:**
- *Top* — inner velocity-block KSP iterations vs adaptation step. FMG (geometric full multigrid) holds a **mesh-independent ~5**; GAMG (algebraic) is **volatile ~64–131 (≈22×)** and does **not** cliff at R=8 over 50 steps.
- *Bottom* — Stokes-solve wall time. GAMG is only **~1.7× FMG**; FMG even spikes to match GAMG around the hardest adapts (steps 25–32) — that spike is the **cold-start Stokes solve** after an adapt (common to both engines), not the preconditioner.
- The **outer Schur-complement KSP converges in 1 iteration for both** — the entire difference lives in the inner velocity block.

**Suggested caption:**
> **Velocity-block solver scaling under adaptive remeshing.** Inner velocity-block
> KSP iterations (top) and Stokes-solve wall time (bottom) versus adaptation step
> for a Ra = 10⁷, Δη = 10³ annulus convection model adapted every timestep with the
> MMPDE mover (res 32, resolution-ratio R = 8, np = 5). Geometric full multigrid
> (FMG) keeps a mesh-independent ≈ 5 inner iterations as the cells stretch, where
> algebraic multigrid (GAMG) runs a volatile ≈ 64–131 (≈ 22×) without cliffing at
> this anisotropy. The wall-clock gap is only ≈ 1.7×: each GAMG V-cycle is far
> cheaper than an FMG F-cycle, and the cold-start Stokes solve after each adapt
> (common to both) dominates the time. The outer Schur KSP converges in a single
> iteration for both — the difference is entirely in the inner velocity block. The
> value of geometric FMG here is *predictability and mesh-independence* (which widen
> with problem size and multigrid levels), not a large raw speed-up.

**Docs wiring** (Markdown/MyST under the benchmark table):
```markdown
![Velocity-block solver scaling under adaptive remeshing](figures/bench_fmg_vs_gamg_velocity_ksp.svg)
```
(Typst equivalent: `#image("figures/bench_fmg_vs_gamg_velocity_ksp.svg")`.)

---

## 2. Animation companion — adaptive convection GIF

**File (NOT in the repo — multi-MB — in the simulation directory):**
`/Users/lmoresi/+Simulations/StagnantLid/anim_full_Ra1e7_dEta1e3_res32_R8_mode1/`
- `anim_clean_Ra1e7_dEta1e3_res32_R8_mode1.gif` — **docs/PR size**: 8 MB, 63 frames (every 4th step), 480 px, clean style (T field + adaptive-mesh edges; no scalebar, streamlines, or text).
- `anim_clean_…_HQ.gif` — 24 MB, 125 frames, 600 px.
- `frame_clean_step0001…0250.png` — all 250 clean PNGs, kept for re-cutting cadence/size.

**What it shows:** the 250-step run — a degree-1 perturbation breaking symmetry into
vigorous, irregular stagnant-lid convection (Nu 1 → 4.15), with the mesh
redistributing every step to track the inner thermal boundary layer and the plumes.
It is the *same run* whose Stokes solves stay flat under FMG in the figure above.

**Suggested caption:**
> Adaptive-mesh convection in an annulus (Ra = 10⁷, Δη = 10³): temperature with the
> MMPDE-adapted mesh redistributing every timestep to follow the thermal boundary
> layer and plumes, mesh-owned tangent-slip keeping boundary nodes on the curved
> surface. 250 steps, np = 5 — the same run whose velocity solves stay
> mesh-independent under geometric FMG (see the benchmark figure).

**Placement:** for the PR description, drag-drop the 8 MB GIF into the #228 comment
box via the GitHub web UI (under the 10 MB limit; `gh` can't upload binary
attachments). For docs, host/link it or commit a lighter cut — don't commit the
multi-MB GIF to the repo.

---

## Reproduction

Run (boundary-slip / mover branch; `scripts/stagnant_lid_adapt_loop.py`):
```bash
REFINE=2 PCVEL=gmg MG_TYPE=full MOVER=mmpde MMPDE_ACCEL=cg MOVER_SLIP=ring \
mpirun -np 5 python scripts/stagnant_lid_adapt_loop.py \
--from-perturbation --pert-mode 1 --Ra 1e7 --delta-eta 1e3 \
--dt-cell-percentile 50 --skip-threshold 99 --adapt-every 1 \
--resolution-ratio 8 --n-steps 250 --res 32 --snapshot-every 1 --out-tag <name>
```
- **FMG vs GAMG** (figure data): same config; `PCVEL=gmg MG_TYPE=full` (FMG) vs
`PCVEL=amg` (GAMG), 50 steps. Inner velocity iterations captured with a temporary
`FMG_DIAG` env-gated diagnostic in the harness
(`stokes.snes.getKSP().getPC().getFieldSplitSubKSP()[0].getIterationNumber()`,
plus `len(mesh.dm_hierarchy)` and the converged reason) — reverted after the runs.
- **Prerequisite** for FMG: the mesh must be built with `refinement` (so
`len(mesh.dm_hierarchy) > 1`) and adapted with a *coordinate-deforming* mover
(MMPDE preserves topology, so the hierarchy survives — confirmed `levels=3` on all
50 steps). A checkpoint-resumed mesh has **no** hierarchy (it isn't persisted), so
`--resume` cannot be used for the FMG arm.
- **Render:** `_render_clean.py <run_dir>` (clean — no scalebar/streamlines) or
`_render_watch.py <run_dir>` (default — with scalebar + streamlines), both in
`/Users/lmoresi/+Simulations/StagnantLid/`. GIF assembled with Pillow (crop white margin →
resize → sample frames).

## Status
- SVG + CSV + this note: **uncommitted** in `docs/advanced/figures/` — commit them
with the docs reference.
- The harness is at its committed state (the `FMG_DIAG` diagnostic was temporary).
- PR #228 (movers consume `mesh.boundary_slip` + the anisotropic-mover work) is
green and mergeable; this benchmark is its "why this works" companion.
Loading
Loading