Skip to content

Solvers: overview ​

Viscosity contrast

MILEVA solves Stokes flow at viscosity contrasts up to 1018 in the 3-D Yin-Yang shell and up to 1012 in the 2-D spherical annulus, measured with the code's own solvers on a viscosity step:

  • 3-D, FGMRES + geometric multigrid. With geometric averaging of the viscosity at velocity faces and matrix-dependent pressure interpolation, FGMRES reaches a relative residual of 10−6 at every contrast from 1 to 1018, in 28 to 73 iterations, and needs fewer iterations as the contrast grows (43 at 106, 28 from 1010 to 1018). Arithmetic face averaging stops converging from 108 on.

  • 2-D, sparse direct (MUMPS, UMFPACK). From contrast 1 to 109 the solution is exact to round-off: the two independent factorisations give the same velocity to 6×10−9 (mid-depth step) and 7×10−5 (thin stiff lid), the divergence stays below 10−10 and the work-dissipation ratio W/D holds its grid value to four digits. At 1012 the two still agree to 7×10−6 (mid-depth) and 3×10−2 (lid), with W/D unchanged. Beyond that double precision sets the limit: a lid step still solves at 1018, while a stiff half-shell fails there.

Each time step MILEVA solves two kinds of linear system. The first is the coupled Stokes saddle-point system for velocity and pressure,

[AGB0][VP]=[b0],

assembled as described in Discretisation. The second is the implicit temperature diffusion step. This section describes the solvers for both, how to select them, and what they cost.

PageContents
Direct solversMUMPS and UMFPACK for the 2-D Stokes system, the pressure pin, factor reuse, BiCGSTAB
Geometric multigridSCGS smoother, Galerkin coarse operators, BC lift, matrix-dependent pressure interpolation, FGMRES wrapper
Yin-Yang Schwarz couplinghow the two 3-D patches are solved and coupled
Parallel solvers (MPI)one rank per patch, distributed MUMPS, block-Jacobi FGMRES, the dispatcher
Energy equationexplicit, Crank-Nicolson and backward-Euler diffusion

Which solver for which problem ​

ProblemRecommendedSettingFunction
2-D Stokes, any viscosity contrastsparse directcfg.solverType = "mumps" or "direct"solve_stokes_mumps, solve_stokes_v2
2-D Stokes, very large grids or solver studiesgeometric multigridcfg.solverType = "multigrid", cfg.mgLevels ≥ 2multigrid_stokes(::MutableGrid2D, ...)
2-D Stokes, Krylov experimentsBiCGSTAB with direct fallbackcfg.solverType = "amg"solve_stokes_amg
3-D Stokes (Yin-Yang shell)FGMRES + multigrid V-cycle per patch, Schwarz between patchescfg.solverType = "multigrid", cfg.mgLevels ≥ 2multigrid_stokes(::MutableGrid3D, ...)
3-D Stokes on several MPI ranksdispatcher, mode = :autocfg.useMPI = true, launch with mpiexecsolve_stokes_distributed!
2-D temperature diffusionCrank-Nicolson (default)cfg.useImplicitTemp = true, cfg.implicitTheta = 0.5diffuse_temperature
3-D temperature diffusionexplicit in the time loopstep limited by cfg.dtMaxdiffuse_temperature(::Array{Float64,3}, ...)

All 2-D Stokes solvers call the same assemble_stokes(...; point_pin = true), so they solve the same discrete problem and differ only in cost and in how tightly they solve it. The 3-D branch of the time loop always calls multigrid_stokes; with cfg.mgLevels = 1 it would factorise each patch with sparse LU, whose memory outgrows a workstation at about 105 unknowns, so keep at least two levels for every 3-D run.

Wall time of one 2-D Stokes solve at Nr×Nt = 64 × 256 (about 49 000 unknowns), assembly included, for an isoviscous shell and for a mid-depth viscosity step of 106. The two direct solvers take a few tenths of a second whatever the contrast; multigrid (FGMRES around a four-level V-cycle) iterated to a residual of 10−6 takes 2 to 3 s at this size. Script: docs/scripts/solvers_2d.jl.

Viscosity-contrast range ​

Measured by docs/scripts/solvers_contrast_range.jl. 2-D: spherical annulus f=0.5, Nr×Nt = 64 × 256, sinker load 100sin⁡(2πr′)sin⁡2θ, viscosity 1020 Pa s below and 1020C Pa s above either mid-depth or the top tenth of the shell. (a) Buoyancy work over viscous dissipation of the MUMPS solution. The identity is exact for the continuous problem; the offset of the mid-depth step is the quadrature of the dissipation across the jump and shrinks under refinement (1.084, 1.039, 1.018 at Nr = 32, 64, 128, contrast 106). (b) Relative difference between the MUMPS and UMFPACK velocities in the no-net-rotation frame (solid) and relative residual of the row-equilibrated system (dashed). (c) Iterations to a relative residual of 10−6: the 3-D Yin-Yang shell of the multigrid page (Nr=Nθ=12, Nφ=36, mid-depth step) with geometric and with arithmetic face viscosity, and the 2-D multigrid (FGMRES around a four-level V-cycle).

Measured values (2-D, MUMPS unless stated):

ContrastW/D mid-depthW/D lidMUMPS vs UMFPACK, mid-depthMUMPS vs UMFPACK, lid2-D multigrid iterations (mid-depth / lid)3-D FGMRES iterations
11.00171.00175×10−135×10−1329 / 2931
1031.03781.00191×10−132×10−1022 / 28772 (102), 73 (104)
1061.03861.00194×10−122×10−728 / 17143
1091.03861.00196×10−97×10−533 / no convergence34 (108), 28 (1010)
10121.03861.00067×10−63×10−261 / no convergence28 (1014)
10151.03771.00447×10−39×10−3164 / no convergence28 (1014)
1018fails1.0037fails6×10−3no convergence28

On the mid-depth step the 2-D multigrid matches MUMPS to 2×10−9 (106) and 7×10−6 (1012). The thin lid, six cells deep, is coarsened below one cell on the coarse levels: there the iteration is slow at 103, and from 106 on it reaches the residual target with velocities that still differ from MUMPS by 7×10−2. This is why the direct solvers are the 2-D choice.

Configuration fields ​

FieldDefaultMeaning
solverType"direct"2-D Stokes solver: "direct" (UMFPACK), "mumps", "amg", "multigrid"
mgLevels4multigrid levels, including the finest; at least 2 for 3-D
mgSmooth2pre- and post-smoothing sweeps of the 2-D V-cycle
krylovTol10−8relative residual target of FGMRES (2-D multigrid and 3-D)
krylovMaxIter200FGMRES iteration cap (2-D multigrid and 3-D)
luCacheTol10−4reuse the MUMPS factor while the largest relative viscosity change stays below this
luReuseMaxIter, luReuseTol0, 10−11precondition GMRES with a stale MUMPS factor (0 disables)
useGeometricEtatruegeometric rather than arithmetic viscosity averaging at velocity faces (3-D)
useImplicitTemp, implicitThetatrue, 0.52-D diffusion scheme: θ = 0.5 is Crank-Nicolson, 1 is backward Euler
nTSchwarz3temperature Schwarz sweeps between the 3-D patches per step
useMPI, mpiNr, mpiNtfalse3-D domain decomposition (see Parallel solvers)

The nonlinear loop ​

With a yield law the viscosity depends on the strain rate of the flow it produces. main_SphCon.jl therefore wraps the Stokes solve in a Picard loop:

  1. Solve Stokes with the current viscosity.

  2. In 2-D, remove the net rotation (_net_rotation_rate).

  3. Measure the relative change of Vmax from the previous sweep; stop if it is below cfg.picardTol (default 10−4).

  4. Recompute the strain rate from the new velocity and rebuild the viscosity with composite_rheology (when cfg.useCompositeRheology is on). The new field is blended with the previous one in log10⁡η with the weight cfg.picardDamping (default 1, undamped); if the change stops decreasing, the weight is halved, down to 0.05. Damping changes the path to the fixed point, not the fixed point. Damage and viscoelastic state advance once per time step, not per sweep.

cfg.picardMax = 0 (default) means 50 sweeps when a yield law is active and one sweep otherwise; a contracting rheology without yielding needs no iteration. Steps that hit the cap unconverged are counted and logged, and every row of diagnostics.csv carries picard_n and picard_rel. With a direct solver each sweep refactorises, because the viscosity has changed.

The loop above rebuilt outside the time loop from the same calls (solve_stokes_v2, _net_rotation_rate, compute_strain_rate, composite_rheology, _picard_viscosity_update), on a 64 × 256 spherical annulus with a 100 km conductive lid and a 400 K cold drip below it, started from a uniform strain rate of 10−15 s−1. (A) The stopping quantity, the relative change of Vmax; (B) the largest change of log10⁡η in a sweep. With a weak yield law (cohesion 1 MPa, friction 0.02, chosen so that the lid above the drip yields; with the default 20 MPa and 0.2 nothing in this field reaches the yield stress) the loop needs 11 sweeps, with the undamped weight throughout. Without yielding the dislocation-creep nonlinearity contracts fast; the time loop solves that case once per step and starts from the previous step's strain rate. Script: docs/scripts/solvers_overview_sections.jl.

Where in the code ​

TopicFileFunction
Solver dispatch, Picard loopmain_SphCon.jltime loop, step (5)
UMFPACKsolvers/solve_stokes_v2.jlsolve_stokes_v2
MUMPSsolvers/solve_stokes_mumps.jlsolve_stokes_mumps
BiCGSTABsolvers/solve_stokes_amg.jlsolve_stokes_amg
Multigrid, Schwarzsolvers/multigrid_stokes.jlmultigrid_stokes
MPI dispatchersolvers/solve_stokes_distributed.jlsolve_stokes_distributed!
Temperature diffusionsolvers/diffuse_temperature.jldiffuse_temperature
Teststests/test_stokes.jl, test_2d_vcycle_scgs.jl, test_mdpi_eta_contrast.jl, test_diffusion.jl, test_mpi_*.jl