Skip to content

Field loop advection ​

IDGroupMilestoneBackendsFigureRegression
MV-9Ideal MHDM2 (#41); --agree #79CPU, FNLyesfield-loop

Case and scope ​

A weak magnetic loop, Az=A0(R−r) with A0=10−3, R=0.3 (plasma β≈106), is advected obliquely across the periodic box (Gardiner & Stone 2005; Mignone & Tzeferacos 2010, section 4.4.1). The field is divergence-free pointwise but jumps at r=R, and a collocated scheme cannot keep the discrete div(B) zero there. With the out-of-plane velocity w=1 the equations give

∂tBz=w∇⋅B,

so the generated ⟨|Bz|⟩ measures the divergence error that GLM leaves, and the decay of the magnetic energy measures the numerical dissipation of the loop.

What the case catches:

  • a divergence error above the GLM level: ⟨|Bz|⟩/A0 under a bound and decreasing under refinement;
  • excess dissipation: EB(T)/EB(0) above a bound;
  • a seam div(B) source that does not decay (--amr): the seam div(B) must fall from its peak;
  • backend disagreement on B (--agree): the CPU and FNL runs compared field by field.

Models and numerics ​

ItemChoiceCode
Equationsideal MHD, γ=5/3models
SpaceWENO5 flux splitting on characteristic variables; weno-riemann under --numericsmhd_glm_face_split_fluxes, mhd_eigenvectors_core, adam_flume_mhd_library.F90; numerics
Divergence controlGLM, ch=4 (glm_ch_check = error), glm_alpha = 0.18, glm_damping_length = 1.0models
TimeSSP Runge–Kutta, 5 stages (runge-kutta-ssp-54), CFL 0.4adam_rk_object.F90
AMR (--amr)primitive-box marker at initialisation; 2:1 restriction, tricubic ghost fill, reflux; seam div(B) column of the historyinterp_seam_ghost, adam_field_object.F90; compute_divb_history, adam_flume_cpu_object.F90
Boundariesperiodicboundary conditions
FNL backendthe same kernels on the deviceadam_flume_fnl_object.F90

Initial and boundary conditions ​

ItemValue
Domain[−1,1]×[−0.5,0.5], z null
Gridthe vortex grid of V2 (quadtree, 4×4 blocks) stretched to the box, N×N/2 square cells, ladder N=64,128
Grid, --amrladder N=32,64, [0,1]×[−0.5,0.5] refined once (2:1 seams at x=0 and x=1, crossed twice by the loop); octree with null z, nk = 4
Ranks2
Initial conditionfield-loop: ρ=1, p=1, v=(2,1,1), loop at the origin, R=0.3, A0=10−3
Boundariesperiodic on x and y
Final timet=2 (two crossings along each axis); --amr t=1 (one crossing)

Input files ​

FileRole
src/tests/flume/verification/mhd/field-loop/make_field_loop.pywrites the input from vortex/vortex-n064.ini (--cells, --time-max, --glm-ch, --vz, --refine-box)
src/tests/flume/verification/mhd/field-loop/check.shruns the ladder (--amr, --agree, --numerics SPEC, --legs mv9)
src/tests/flume/verification/mhd/field-loop/field_loop_oracle.py⟨|Bz|⟩/A0, its rate, EB(T)/EB(0), the CPU–FNL agreement
src/tests/flume/verification/mhd/seam_divb_oracle.pythe seam div(B) decay (--amr)
src/tests/flume/verification/make_doc_figures.py fig_field_loopdraws field-loop.png from <runs>/field-loop (--only field-loop)
bash
cd src/tests/flume/verification/mhd
field-loop/check.sh                                                     # CPU (about 10 min)
FLUME_EXE=$PWD/../../../../../exe/adam_flume_fnl field-loop/check.sh    # FNL
field-loop/check.sh --agree                                             # CPU against FNL, after both runs
field-loop/check.sh --amr                                               # 2:1 seams (about 28 min)

make_doc_runs.sh <runs> mhd writes the figure run (<runs>/field-loop: 128×64); make_doc_figures.py --runs <runs> draws it.

Results ​

Field loop

Magnetic pressure |B|2/2 of the loop at the final time.

CheckBoundCPUFNL
⟨|Bz|⟩/A0, N=64/1281.040⋅10−3 / 6.003⋅10−4 (baseline + 2%)1.02⋅10−3 / 5.89⋅10−4pass
its rate under refinement>00.79 (0.20 from 128 to 256)pass
EB(T)/EB(0), N=64/128≥0.87011 / 0.93544 (baseline − 0.2%)0.872 / 0.937pass
--amr: ⟨|Bz|⟩/A0, N=32/642.277⋅10−3 / 1.118⋅10−32.23⋅10−3 / 1.10⋅10−3, rate +1.03pass
--amr: EB(T)/EB(0), N=32/64≥0.80066 / 0.898880.802 / 0.901pass
--amr: final seam div(B) / its peak0.10.033 / 0.011pass
--agree: CPU against FNL, field by field (B relative to A0)10−10—∼10−14 at step 4

The uniform N=256 run (26 more minutes, not in the ladder) gives 5.13⋅10−4 and EB 0.967. The uniform 32/64 runs that the --amr ladder is compared with give 1.99⋅10−3, 1.11⋅10−3 and EB 0.759, 0.884. The weno-riemann energies are in MHD on weno-riemann.

Related cases: glm cleaning measures the GLM transport and damping on an exact solution; runtime regrids and accuracy of runtime AMR track this loop with a moving refinement (regression field-loop-regrid); the M6 seam studies G3a and G3b run it across a 2:1 seam under GLM and EGLM.

Findings ​

  • The loop field jumps at r=R, so the discrete div(B) there is ∼A0/h over a ring ∼h wide: the Bz source is O(1) in h and the decrease is slow. No convergence order is expected; the measured level matches the GLM level of Mignone & Tzeferacos (∼10−3).
  • On AMR the refined half dissipates less (EB 0.802, 0.901 against 0.759, 0.884 uniform); the seams add Bz at N=32 and none at N=64. The seam div(B) peaks at the first step (the initial-data error of the loop edge) and GLM removes it; the collocated PRISM seam runs away instead (#29).
  • The backends agree to round-off on B as on the fluid. Until #79 they differed by ∼10−6 on B: the slow-wave normalisation of the eigenvectors cancelled catastrophically; it is now cancellation-free (numerics).