Skip to content

MHD plumbing ​

IDGroupMilestoneBackendsFigureRegression
— (mhd/plumbing, M2-P1)Ideal MHDM2 (#41, P1)CPU, FNLno—

Case and scope ​

M2-P1 wired the ideal-MHD model through FLUME end to end: the input predicate (state width and names), the MHD conversions and fast magnetosonic speed, the per-model kernel instances, the initial- and boundary-condition keys and the wall rule, the outputs and the restart. The leg checks that plumbing, for both variants divergence_control = none (nv=8) and glm (nv=9, with ψ), on a seeded uniform state:

  1. time step: one step of the unperturbed uniform state (s=0). The step must equal CFL/∑d(|ud|+cf,d)/Δxd, with the fast speed computed by the oracle independently of the Fortran; under GLM it is bounded by CFL/(ch∑d1/Δxd), the active bound here (M2-P4);
  2. auxiliary fields: the saved MHD auxiliaries equal the values recomputed from the saved conservative fields;
  3. restart: 5 steps, a restart and 5 more steps of the seeded (s=0.05) state equal the continuous 10-step run bit for bit, the residual and conservation histories byte for byte, and every model variable (bx, by, bz [, psi]) is saved;
  4. refusals (variant none): an unknown divergence_control and isentropic-vortex with MHD stop with their error messages.

What the case catches: a wrong fast-speed formula, a wrong B index, a wrong auxiliary layout on the device (the dt check exercises the device auxiliary and fast-speed kernels on FNL), a kernel instance of the wrong model, ch missing from the time step, a missing B or ψ field in the output, a restart that loses ψ, and a silently accepted invalid input.

The retired zero-residual legs

At M2-P1 the MHD face fluxes did not exist yet, so the residual was exactly zero and the leg also required constant integrals and 10 steps equal to 1 step. Since M2-P3 the face fluxes are live and those legs are retired; the exact steady state is checked by MV-2 (zero field, uniform state, bitwise). The oracle's module docstring still describes the P1 state ("no face fluxes yet"); its --static mode is no longer called by check.sh.

Models and numerics ​

ItemChoiceCode
Equationsideal MHD, γ=cp/cv=2.5/1.5=5/3; none (nv=8) or mixed GLM (nv=9)models; initialize, adam_flume_physics_object.F90
GLMch=3, glm_alpha = 0.18, glm_damping_length = 1, glm_ch_check = warningmodels; adam_flume_mhd_object.F90
SpaceWENO5 (weno-u-5) flux splitting on characteristic variablescompute_residuals_weno, adam_flume_cpu_object.F90; mhd_face_split_fluxes, mhd_glm_face_split_fluxes, adam_flume_mhd_library.F90
Time step$\mathrm{CFL} / \max \sum_d (u_d
TimeSSP Runge–Kutta, 3 stages, CFL 0.8adam_rk_object.F90
Auxiliary fieldsρ,u,v,w,p,T,H,a,Bx,By,Bz from the conservative statecompute_q_aux, adam_flume_cpu_object.F90; mhd_conservative_to_auxiliary, adam_flume_mhd_library.F90; models
Output and restartHDF5 checkpoints; restart filessave_xh5f, save_restart_files, load_restart_files, adam_flume_common_object.F90
Refusalsunknown divergence_control; isentropic-vortex requires eulerload_from_file, adam_flume_mhd_object.F90, adam_flume_ic_object.F90
Boundariesextrapolation, wall-inviscid, inflow (with B)adam_flume_bc_object.F90; boundary conditions
FNL backendthe same kernels on the deviceadam_flume_fnl_object.F90

Initial and boundary conditions ​

ItemValue
Domain[0,1]3
Gridoctree, two uniform levels (iu_ref_levels = 2): 64 blocks of 83 cells, 323 cells, Δx=1/32, ngc = 3 (both ranks own blocks, so the restart check is meaningful)
Ranks2
Initial conditionuniform: (ρ,u,v,w,p)=(1,0.3,−0.2,0.1,1), B=(0.8,0.5,−0.3), seeded density/pressure perturbation s=0.05 (s=0 in the dt check)
Boundariesx: extrapolation; y: wall-inviscid; zmin: inflow with the region state; zmax: extrapolation
Stepsdt check 1; auxiliary check 10; restart check 5 + 5 against 10
CheckVariant (leg)ChangeExpected
dtnone, glms=0, it_max = 1step 1 equals the oracle's dt to 10−13 relative
auxnone, glm—auxiliaries equal the recomputed ones to 10−12 relative
restartnone, glmrestart_save = 5, then restart = .true.bitwise fields, identical histories, model variables saved
refusednonedivergence_control = bogusunknown [mhd].(divergence_control) "bogus"
refusednonetype = isentropic-vortexisentropic-vortex requires [physics].(physical_model) = euler

Input files ​

FileRole
src/tests/flume/verification/mhd/plumbing/mhd-uniform-none.inithe case, divergence_control = none
src/tests/flume/verification/mhd/plumbing/mhd-uniform-glm.inithe case, divergence_control = glm
src/tests/flume/verification/mhd/plumbing/check.shruns every leg (--np N, --build, --legs LIST: none, glm, refused; FLUME_EXE selects the backend); a leg is a variant, none and glm each run the dt, aux and restart checks
src/tests/flume/verification/mhd/plumbing/mhd_plumbing_oracle.py--dt, --aux, --compare; also --zero and --steady used by MV-2
bash
cd src/tests/flume/verification/mhd/plumbing && ./check.sh           # CPU
FLUME_EXE=$PWD/../../../../../../exe/adam_flume_fnl ./check.sh       # FNL

Results ​

A contract leg: no figure. The work directories of both backends are kept (plumbing/work-adam_flume_{cpu,fnl}-np2-*), with their logs and histories; the checkpoints are deleted, and the oracle's printed lines are not kept. The table quotes what those files still show:

CheckBoundCPUFNL
dt of step 1, none (history *-dt)oracle 4.7620653358110355⋅10−3, 10−13 relative4.7620653358110363⋅10−3 (1.7⋅10−16)the same digits
dt of step 1, glm: the ch bound 0.8/(3⋅3⋅32) is active (ch⋅3=9 against ∑d(|ud|+cf,d)=5.25)oracle 2.7777777777777778⋅10−32.7777777777777779⋅10−3the same digits
restart: residual and conservation histories against the continuous run (*-A vs *-B, cmp)byte-identicalidentical, both variantsidentical, both variants
auxiliary fields against the recomputed ones10−12 relativenot keptnot kept
restart: interior fields, every variable, model variables presentbitwisenot keptnot kept
unknown divergence_controlrefusedunknown [mhd].(divergence_control) "bogus"; expected one of glm, nonethe same
isentropic-vortex with MHDrefused[initial_conditions].(type) = isentropic-vortex requires [physics].(physical_model) = eulerthe same

The dt oracle values are recomputed from the oracle's formula and the input; the measured values are the step-1 rows of the kept conservation histories.

Related cases: zero field (MV-2) took over the exact-steady-state legs; GLM divergence cleaning verifies the ch time-step bound and the damping physically.

Findings ​

  • The fast-speed time step agrees with the independent textbook formula to one ulp on both backends, and the GLM step is set by ch, so a ch missing from the time step would fail the leg.
  • The restart reproduces the continuous run's histories byte for byte on both backends and both variants.
  • The work directories *-none-C and *-glm-C (dated before the others) belong to the retired "10 steps = 1 step" leg; check.sh no longer writes them.
  • The auxiliary and bitwise-field verdicts rest on the check.sh run; the checkpoints they read are deleted after the oracle, so this page cannot re-derive them.