Skip to content

Governing equations ​

MILET solves creeping (zero-Reynolds-number) thermo-mechanical flow: a mixed Stokes problem for velocity and pressure with visco-elasto-plastic (VEP) rheology, coupled to an energy equation (Heat transport) and a marker-in-cell material description (Markers). This page covers the Stokes system as implemented in src/physics/Stokes.jl, the buoyancy term from src/physics/Gravity.jl / src/time_stepping/PicardLoop.jl; the compressible (TALA) form is on the Compressibility page.

Strong form ​

In the default Boussinesq formulation (formulation = "boussinesq"):

−∇⋅(2ηVEPε(u))+∇p=ρg(momentum)∇⋅u=0(mass)

with ε(u)=12(∇u+∇uT) the symmetric strain-rate tensor and ηVEP the effective visco-elasto-plastic viscosity (see Rheology). MILET uses a y-positive-down convention, so gravity is gy = +9.81 in the [gravity] TOML section.

Weak form ​

build_stokes_forms (src/physics/Stokes.jl) assembles the bilinear and linear forms. Multiplying momentum by a test function v∈V, integrating the stress term by parts, and testing continuity with q∈Q:

a((u,p),(v,q))=∫Ω2ηVEPε(u):ε(v)dΩ−∫Ωp(∇⋅v)dΩ−∫Ωq(∇⋅u)dΩ+∑Γfs∫Γγ(u⋅n)(v⋅n)dΓl((v,q))=∫Ωρg⋅vdΩ+∫Ωχσold:ε(v)dΩ+∑Γt∫Γt⋅vdΓ

The system is discretized with inf-sup stable Q2–Q1 Taylor–Hood elements (fe_order_v = 2, fe_order_p = 1 in the [fe] section; see Discretization). ηVEP enters as a piecewise-constant CellField projected from the markers (project_markers_to_cells! in src/particles/Projection.jl). assemble_stokes wraps the forms into a Gridap AffineFEOperator.

Free-slip penalty ​

Walls flagged free_slip (bc_left, bc_right, bc_surface, bc_deep, plus bc_front/bc_back in 3D) contribute the penalty term

∫Γγ(u⋅n)(v⋅n)dΓ,

which weakly enforces no-penetration (u⋅n=0) while leaving the tangential component free. build_free_slip_bcs sets the penalty scale per wall as

γ=free_slip_penalty⋅ηrefhx,

where ηref is the volume-mean viscosity of the current iteration (floored at eta_min) and hx the cell width — so the dimensionless config key free_slip_penalty (default 1000) is portable across viscosity regimes and resolutions.

Traction (Neumann) walls ​

Walls flagged traction impose σ⋅n=t via the RHS boundary integral ∫Γt⋅vdΓ. build_traction_bcs composes the global-frame traction vector from the per-wall config keys t_traction_<wall>_n (normal, positive outward) and t_traction_<wall>_t (tangential), where <wall> is one of left | right | surface | deep. Walls flagged prescribed use strong Dirichlet values instead (src/boundary_conditions/Velocity.jl).

VEP elastic memory source ​

For Maxwell visco-elasticity the previous-step deviatoric stress enters the RHS as

∫Ωχσold:ε(v)dΩ,χ=1−Z,

where Z=GΔt/(ηVP+GΔt) is the visco-elasticity factor and χ the elastic-memory weight (derivation in Rheology — Maxwell elasticity). σold is a cell-piecewise SymTensorValue field built from the marker-averaged stress components by build_sigma_old_cellfield. picard_stokes! only constructs this term when any cell has χ>0 (i.e. some rock has shear_modulus G>0); with χ=0 everywhere the system reduces to pure visco-plastic Stokes.

After each Stokes solve, update_marker_stresses! applies the marker-level stress update (Gerya 2010, eq. 12.13)

σnew=2ηVEPε˙(u)+χσold

followed by an explicit Jaumann co-rotation increment Δt(Wσ−σW) with spin tensor W=12(∇u−∇uT); the 3D variant _update_marker_stresses_3d! carries all six deviatoric components and the full three-component spin. recover_invariants! computes cell-mean ε˙II=12ε:ε and σII=2ηε˙II for diagnostics and for the next nonlinear iteration.

Buoyancy: Boussinesq perturbation form ​

buoyancy_cellfield (src/physics/Gravity.jl) builds the body-force CellField used in l. By default the perturbation form is used:

fbuoy=(ρ−ρ¯)g,

where ρ¯ is the volume-weighted mean cell density of the current Picard iteration (a plain arithmetic mean would bias toward refined regions on AMR meshes and produce spurious buoyancy). The hydrostatic component ρ¯g is absorbed into a reference pressure that is dropped from the system entirely — this prevents direct-solver pivoting on the singular saddle point from leaking the hydrostatic gradient into the velocity field (observed as 104× overestimated plume velocities before the fix; see the commentary in src/time_stepping/PicardLoop.jl).

Options:

Config keyDefaultEffect
body_force_fullfalsetrue → use full ρg (I2ELVIS/FD convention), no subtraction
buoyancy_from_Tfalsetrue → build ρ(Th)=ρ0(1−α(Th−Tref)) from the continuous FE temperature (resolves thermal boundary layers that the cell-constant marker projection under-drives at high Ra); Tref = T_ref_density
gravity.model"vertical_const""vertical_const" (constant (gx,gy[,gz]) from gx,gy,gz) or "radial" (−gmagr^ toward the origin, magnitude g_mag) — gravity_fn in src/physics/Gravity.jl

Compressible flow (TALA) ​

formulation = "tala" replaces the Boussinesq equations with the truncated anelastic liquid approximation of King et al. (2010). The equations, the reference state and their verification are on the Compressibility page.

Nonlinear (Picard) iteration ​

The viscosity depends on strain rate, η=η(ε˙II), so the Stokes operator is nonlinear. picard_stokes! (src/time_stepping/PicardLoop.jl) iterates:

  1. project markers → cell fields (η, ρ, χ, σold),

  2. assemble and solve the linear Stokes system with frozen η(k),

  3. recover ε˙II(k+1),

  4. test ‖u(k+1)−u(k)‖/‖u(k+1)‖<picard_tol.

Controls in [fe]: n_picard (default 3), picard_tol (default 1e-3), nonlinear_method = "picard" | "newton" and newton_damping (α∈(0,1] under-relaxation; α=1 recovers Picard). Sparse patterns, factorizations, and multigrid hierarchies are cached across iterations — see Linear solvers and Geometric multigrid.