Benchmarks and verification
MILET's verification story has three layers: fast smoke tests that pin the pointwise physics to analytic results, solver gates that require the iterative and reduced formulations to reproduce the direct/reference solution to tight tolerances, and community benchmarks (SolCx, Blankenbach, Glerum, Busse) with published reference values. Everything below lives in test/ and runs against the same source files as production (test/runtests.jl includes the identical module graph as main.jl).
# smoke + solver gates (minutes)
julia --project=. test/runtests.jl
# additionally run the short physics benchmarks
RUN_BENCHMARKS=1 julia --project=. test/runtests.jl
# convergence studies (longer)
julia --project=. test/validation/solcx_convergence.jl
julia --project=. test/validation/blankenbach_convergence.jl
# laptop-budget long bench (≈ 30–45 min)
julia --project=. test/long_bench.jlSolCx — variable-viscosity Stokes convergence
test/validation/solcx_convergence.jl runs the SolCx benchmark (Duretz et al. 2011) — a sharp 10⁶ viscosity jump at x = 0.5 with the analytic body force cases/solcx.toml and the fixed-resolution series cases/solcx_fixed_n24…n128.toml; the short gated variant (test/benchmarks/run_solcx.jl, RUN_BENCHMARKS=1) asserts finiteness and brackets vmax. Because the viscosity jump is element-aligned for even cell counts, this benchmark exercises exactly the discontinuous-coefficient regime the Q2/Q1 Taylor–Hood pair (see Discretization) must handle.
Blankenbach 1A — thermal convection references
test/validation/blankenbach_convergence.jl runs Case 1A of Blankenbach et al. (1989) — isoviscous Ra = 10⁴ convection, nondimensional unit box — at nx = 41/61/81 to quasi-steady state and compares against the canonical steady-state references:
Both diagnostics are FE-integral-accurate (nusselt and vrms in src/io/Diagnostics.jl): Nu is computed as marker_T_mode = "pic_increment" (markers carry and advect temperature, the FE step supplies the diffusion increment) plus the buoyancy_from_T Stokes coupling. The cases/blankenbach_sg_n41/65/97 series repeats the study with Gerya & Yuen (2003) subgrid diffusion enabled (do_subgrid_diffusion = true), the configuration used in the methods paper. The 3D analogue is cases/busse_1a.toml (Busse et al. 1993: Nu ≈ 3.539, V_rms ≈ 40.999).
Geometric multigrid gates
test/smoke/test_gmg.jl contains three gates for the GMG solver stack (src/solvers/GMG.jl, src/solvers/BlockMG.jl; see Geometric multigrid):
2D V-cycle on the real Q2 velocity space with a 4-decade viscosity contrast (stiff block in a soft matrix): the Galerkin hierarchy (
) must contract the residual by ≥ 10⁴ within 8 V-cycles with a mean per-cycle rate < 0.5, and gmg_update!(new matrix values, same pattern — the Picard-iteration path) must keep converging.3D hierarchy: the same machinery on a 16³ Q2 vector space with a viscosity contrast — relative residual < 10⁻³ after 8 cycles. This validates transfers, Galerkin products, and Chebyshev smoothing in 3D.
End-to-end Stokes: GMG-preconditioned FGMRES must reproduce the MUMPS direct solution of a buoyancy-driven variable-viscosity flow to a relative velocity difference < 2×10⁻³ (measured agreement ≈ 4×10⁻⁴ — the gate reflects the backward-error limit of a fully dimensional system with η ~ 10²⁰ Pa·s, not discretization error). The test runs
n_picard = 2deliberately so the cached in-place reassembly (assemble_stokes_cached!), the MUMPS numeric-only refactorization, andgmg_update!— the paths production runs live on — are all exercised.
The runnable demos for the iterative path are cases/plume3d_cube_gmg.toml and cases/plume3d_slab_gmg.toml.
Two-phase flow — the φ = 0 gate
test/smoke/test_twophase.jl enforces the degeneracy requirement of the McKenzie three-field formulation (src/physics/TwoPhase.jl; see Two-phase flow): as picard_stokes! and with solve_twophase! at φ = 0 and asserts
relative velocity difference < 5×10⁻³, and
relative difference of the total pressure
(mean-free, since the split between the two multipliers is regularization-dependent at φ = 0) against the single-phase pressure < 5×10⁻³.
A companion testset checks the constitutive closures pointwise (permeability power law, compaction viscosity, melt weakening
Grain-size evolution — analytic tests
test/smoke/test_grainsize.jl pins the grain-size module (src/materials/GrainSize.jl, design in doc/design/grain_size.md; see Grain-size evolution) to closed-form results:
Growth-only analytic: with
the ODE integrates exactly to ; update_grain_sizemust match within 1 % (it does so in a single substep, because the growth sub-flow is integrated in closed form).Wattmeter steady state: integrating from 10× above and 0.1× below the Austin & Evans (2007) fixed point
must converge to the same value within 5 % of the analytic (and to each other within 10⁻⁶ — a unique fixed point). Composite-rheology identity: with diffusion creep enabled, the pre-clamp harmonic identity
must hold to 10⁻¹⁰; diff_A = 0must regress exactly to the single-mechanism path.Mechanism-partition consistency (
viscous_mechanism_partition): stress continuity requiresand , both to 10⁻¹⁰.
Softening and healing tests
test/smoke/test_softening.jl covers the strain-softening additions (design in doc/design/softening_healing.md; see Softening & healing):
Healing decay:
halves after at ; the Arrhenius τ(T) must shrink for hotter and grow for colder material. Viscous strain-softening ramp:
visc_soft_factor = 0.1must leave fresh material at η₀, reach exactly 0.1 η₀ beyondstrain_thresh_weak, and be monotonic in between; the default factor 1.0 must be a no-op.Configurable yield cap: at 3 GPa confining pressure the implied stress
must respect yield_stress_max = 1e8, and disabling the cap (≤ 0) must let the Drucker–Prager yield grow with depth.Yielded flag:
compute_VEP_viscositymust report plasticity governing (the flag that feeds the per-cell yield fraction gating strain accumulation) for a low-cohesion/high-η rock, and never for a purely viscous one.
Other smoke tests
test/smoke/test_rheology.jl— pointwise rheology invariants: constant Newtonian rock returns exactly η₀; Arrhenius ∂η/∂T < 0; Maxwell VEP gives Z ∈ (0, 1], χ + Z = 1, η_VEP ≤ η_viscous; strain weakening is monotonic. Plus density: ρ(T_ref) = ρ₀, thermal contraction, additive phase Δρ.test/smoke/test_mesh.jl,test/smoke/test_fespaces.jl— 2D/3D mesh construction, wall tagging, and Taylor–Hood space sanity.test/smoke/test_phase_melt.jl— depth-triggered phase change and the Katz-lite solidus/liquidus melt fraction.
Gated short benchmarks and the long bench
With RUN_BENCHMARKS=1, test/runtests.jl additionally runs short end-to-end models (test/benchmarks/): SolCx (analytic ρ/η), the falling block (50 steps), a 20-step plume, and a short Blankenbach 1A that logs Nu and V_rms against 4.884 / 42.86. test/long_bench.jl is the curated laptop-budget suite (SolCx at two resolutions, falling block, plume, Blankenbach with ~200 steps) used to track wall-clock and physics regressions together.
Related pages
The case files under
cases/— the runnable TOML definitions behind each benchmark.Testing — how the test harness is organised.
Linear solvers, Geometric multigrid — the solver architecture the GMG gates protect.