Appearance
GLM divergence cleaning
| ID | Group | Milestone | Backends | Figure | Regression |
|---|---|---|---|---|---|
| MV-3, MV-10 | Ideal MHD | M2 (#41); the MV-10 monitor M6 (#68, G1) | CPU, FNL | yes | glm-pulse |
Case and scope
MV-3, the GLM pulse. A Gaussian pulse in
with an exact solution: the error splits into two pulses travelling at glm_alpha, glm_damping_length). The oracle computes it mode by mode (d'Alembert without damping).
What MV-3 catches:
- a wrong GLM block in the face flux:
of and against the exact solution under a bound, and the observed order; - a wrong damping source or rate: a wrong rate is an
relative error (1.23 with no damping at , against ), and the min-celldamping length is checked on its own; missing from the time step: is above the fastest wave (1.29), so it sets , and glm_ch_check = errormust not trip;- a wrong wall parity of
: reflecting walls ( odd, even); - a leaking
nonepath: without cleaningmust stay frozen, bit for bit.
MV-10, the Dedner peak. A peak in divb_tol monitor.
Models and numerics
| Item | Choice | Code |
|---|---|---|
| Equations | ideal MHD with mixed GLM, | models; mhd_glm_flux, mhd_glm_eigenvectors, adam_flume_mhd_library.F90 |
| Space | WENO5 flux splitting on characteristic variables; the | mhd_glm_face_split_fluxes, adam_flume_mhd_library.F90; compute_residuals_weno, adam_flume_cpu_object.F90 |
| Damping | source min-cell (the minimum cell size) | add_glm_damping, adam_flume_cpu_mhd_glm_kernels.F90; set_glm_damping, adam_flume_mhd_object.F90 |
glm_ch_check = error (MV-3, MV-10) | check_glm_ch, adam_flume_cpu_object.F90 | |
| div(B) history and monitor | max, divb_tol on the normalised | compute_divb_history, compute_dflux_norms, adam_flume_cpu_object.F90; save_divb_row, adam_flume_diagnostics_object.F90 |
| Time | SSP Runge–Kutta, 3 stages, CFL 0.5 | adam_rk_object.F90 |
| AMR (MV-10) | 2:1 seams: restriction, tricubic ghost fill, reflux | interp_seam_ghost, adam_field_object.F90; numerics |
| Boundaries | periodic; reflecting walls (wall-inviscid: | adam_flume_bc_object.F90; boundary conditions |
| FNL backend | the same kernels on the device | adam_flume_fnl_object.F90, adam_flume_fnl_mhd_glm_kernels.F90 |
Initial and boundary conditions
MV-3 (mhd/glm-pulse):
| Item | Value |
|---|---|
| Domain | |
| Grid | the Sod grid of V1, 4 blocks along |
| Ranks | 2 |
| Initial condition | glm-pulse: background |
| Cleaning |
| Leg | glm_alpha | glm_damping_length | |||
|---|---|---|---|---|---|
| d'Alembert | 64, 128, 256 | 0 | 1.0 | periodic | 0.3 (the pulses cross the boundary) |
| damped | 64, 128, 256 | 0.5 | 0.1 ( | periodic | 0.3 |
min-cell | 128 | 0.1 (rate 25.6) | min-cell | periodic | 0.3 |
| walls | 128 | 0 | 1.0 | wall-inviscid (both pulses reflected once) | 0.4 |
none | 128 | — | — | periodic | 0.3 |
MV-10 (mhd/divb-peak):
| Item | Value |
|---|---|
| Domain | |
| Grid | the periodic grid of V3 (octree) at level 2: nk = 4 (the 2:1 seam fill needs 4 cells on every axis, null ones included) |
| AMR leg | |
| Ranks | 2 |
| Initial condition | divb-peak: |
| Cleaning | GLM, glm_alpha = 0.4, damping length min-cell; and none |
| Final time |
Input files
| File | Role |
|---|---|
src/tests/flume/verification/mhd/glm-pulse/make_glm_pulse.py | writes the MV-3 input from sod/sod-x.ini |
src/tests/flume/verification/mhd/glm-pulse/check.sh | runs the MV-3 legs (--np N, --divergence-control glm|eglm, --legs LIST: mv3-dalembert, mv3-damped, mv3-mincell, mv3-walls, mv3-none, the last GLM-only) |
src/tests/flume/verification/mhd/glm-pulse/glm_pulse_oracle.py | the exact telegraph solution, the none run |
src/tests/flume/verification/mhd/divb-peak/make_divb_peak.py | writes the MV-10 input from conservation/amr-periodic.ini |
src/tests/flume/verification/mhd/divb-peak/check.sh | runs the MV-10 legs and the monitor legs (--np N, --legs LIST: mv10-uniform, mv10-amr, mv10-monitor for the monitor runs) |
src/tests/flume/verification/mhd/divb-peak/divb_peak_oracle.py | the decay, |
src/tests/flume/verification/make_doc_figures.py fig_glm_pulse | draws glm-pulse.png from <runs>/glm-pulse (--only glm-pulse) |
bash
cd src/tests/flume/verification/mhd
glm-pulse/check.sh # MV-3, CPU
FLUME_EXE=$PWD/../../../../../exe/adam_flume_fnl glm-pulse/check.sh # MV-3, FNL
divb-peak/check.sh # MV-10make_doc_runs.sh <runs> mhd writes the figure run (<runs>/glm-pulse: 128 cells, GLM, amplitude 0.1); make_doc_figures.py --runs <runs> draws it.
Results

The undamped case (glm_alpha = 0, periodic, 128 cells,
MV-3 (bounds: CPU baseline M2-P4a + 2%):
| Check | Bound | CPU | FNL |
|---|---|---|---|
| d'Alembert, | pass | ||
| damped, | pass | ||
| observed order, both ladders | 4.1 and 3.6 (WENO5 in space still visible) | pass | |
min-cell, | pass | ||
| walls, | pass | ||
| pass | |||
none: | bitwise | bitwise | bitwise |
MV-10 (CPU baselines M2-P4b):
| Check | Bound | CPU | FNL |
|---|---|---|---|
| GLM final / initial | 0.1 | 0.057 | pass |
GLM / none final | 0.1 | 0.027 | pass |
| AMR: GLM final / initial | 0.2 | 0.091 | pass |
| pass | |||
| pass | |||
saved pt, beta, bmag against their definitions; saved | exact | pass | |
| AMR seam column: zero at step 0, never above the global maximum, positive at the end | — | pass | pass |
monitor, divb_tol = 0.01, divb_error = .false. (the peak starts near 0.2) | warnings, run completes | pass | pass |
monitor, divb_error = .true. | run stops with its message | pass | pass |
divb_tol > 0 without [diagnostics] divb_flux | refused at initialisation | pass | pass |
FNL ran every leg (work directories of both backends); the tables record the CPU values, and the backends agree to the printed digits.
Related cases: EGLM cleaning runs MV-3 under EGLM (EV-2); Orszag–Tang and field loop measure the seam div(B) of shocked and smooth flows; the seam div(B) studies of M6 are in divergence across seams.
Findings
- The observed order is that of SSP-33 in time with the WENO5 spatial error still visible (4.1 and 3.6), above the asserted 3.0.
- The
of the Dedner peak is not monotone under GLM: a few-percent transient while the peak spreads into outgoing waves. The leg therefore asserts "never above the initial value" and the final ratio, not a monotone decay. - On AMR the final ratio doubles (0.091 against 0.057): the 2:1 seam injects div(B) (the seam source of #29); GLM keeps it bounded.
- Since #68 G1 the
divb_tolmonitor acts on the normalised, which needs [diagnostics] divb_fluxand GLM; adivb_tolwithoutdivb_fluxis refused at initialisation instead of monitoring nothing.