Skip to content

Heat transport

The energy equation is solved implicitly on the FE grid (src/physics/Heat.jl, driven by solve_heat_step! in src/time_stepping/Driver.jl) with sources assembled in src/physics/HeatSources.jl. Temperature advection is, by default, handled in the Lagrangian frame by the markers (PIC pattern below), so the grid solve is a pure diffusion + source step.

Strong form and backward-Euler discretization

ρcp(Tt+uT)=(kT)+H,

where H aggregates radiogenic, shear, adiabatic, and latent sources. Backward Euler in time:

ρcpTn+1TnΔt+ρcpuTn+1=(kTn+1)+H.

Testing with q and integrating the Fourier flux by parts (build_heat_forms):

ΩρcpΔtTqdΩ+Ωρcp(uT)qdΩonly if with_advection+ΩkTqdΩ=ΩρcpΔtTnqdΩ+ΩHqdΩ.

Temperature uses Q1 elements (fe_order_T = 1). The system is solved with a cached MUMPS factorization (CachedMumps in state.heat_solver_cache) — the sparsity pattern is constant across steps, so only the numeric factorization repeats.

Density convention: the heat equation uses the constant Boussinesq reference density, ρcp= rho_ref_heat cp (per-cell marker-mean cp), not the perturbed ρ(T) — which can go negative in non-dimensional cases (e.g. Blankenbach with α=104) and would destabilize the BE mass term. The ρ(T) buoyancy lives only in the Stokes RHS (see Governing equations).

Stabilized FE advection (optional)

With do_supg_heat = true (or heat_stabilisation = "supg"), the FE field advects temperature directly and the cell-Péclet > 1 regime is stabilized by SUPG: the test function is augmented qq+τ(uq), adding

Ωρcpτ(uT)(uq)dΩ(LHS),ΩτH(uq)dΩ(RHS),

with the Codina (2000) parameter

τ=[(2|u|h)2+(4kρcph2)2+(1Δt)2]1/2,

so τh/(2|u|) when advection dominates, h2ρcp/(4k) when diffusion dominates, Δt when storage dominates. The cell size is h=ΔxΔy (2D) or (ΔxΔyΔz)1/3 (3D).

heat_stabilisation = "entropy" instead adds residual-driven artificial diffusion (Guermond–Pasquetti–Popov 2011; entropy_viscosity in src/physics/EntropyViscosity.jl):

νe(K)=min(cmaxh|u|K,cEh2|RE(T)|KTT¯),RE=(TT¯)(TToldΔt+uT),

with cmax=0.5, cE=1.0 (Kronbichler–Heister–Bangerth 2012 §3.4 defaults) and entropy S=12(TT¯)2 about the volume-mean temperature. It enters the diffusion term as keff=k+ρcpνe per cell (solve_heat_step!). Default is heat_stabilisation = "none" (PIC advection, diffusion-only FE operator).

Boundary conditions

Configured per wall in [boundary_temperature] (build_heat_flux_bcs in Heat.jl; Dirichlet values in src/boundary_conditions/Temperature.jl):

bcT_surface / bcT_deepWeak-form contributionKeys
"dirichlet" (default)strong, via the FE space: T= T_top (surface), T_bot (deep)T_top, T_bot
"flux"kTn=q: adds Γqq~dΓ to the RHSq_surface, q_deep (W/m²)
"robin"kTn=h(TTamb): adds ΓhTq~dΓ (LHS) and ΓhTambq~dΓ (RHS)h_robin, T_amb
"insulating"natural zero-flux Neumann, no contribution

Lateral walls are insulating by default.

Heat sources

build_heat_source (src/physics/HeatSources.jl) assembles H (W/m³) from per-cell constants plus CellField expressions that track the current FE solution:

  • Radiogenic (do_radiogenic = true): per-cell marker mean of the per-rock radiogenic_heating hr (W/m³; typical 106 continental crust, 107 oceanic crust, 108 mantle), held in state.ht_c.

  • Constant / functional: H_const adds a uniform W/m³ everywhere; cfg.H_fn (set programmatically, not from TOML) evaluates H(x,y[,z]) at cell centres — used by prescribed-source benchmarks.

  • Shear heating (do_shear_heating = true): viscous dissipation σ:ε˙=2ηε:ε; with MILET's invariant convention ε˙II=12ε:ε this is

    Hshear=4ηε˙II2 0,

    built from the cell fields eta_c (the effective ηVEP, so only the visco-plastic part dissipates) and eii_c.

  • Adiabatic (do_adiabatic = false by default): Hadiab=αT(up) with the hydrostatic simplification pρrefg:

    Hadiab=αTρrefgyuy,

    positive for downward flow (uy>0 in the y-down convention — sinking material heats). Implemented with a representative αref=3×105 K⁻¹, ρref= rho_ref_heat, gy= gy.

  • Latent (phase change + melting): Hlatent=ρLphaseϕ˙phase+ρLmeltdF/dt, accumulated on markers by apply_marker_phase_and_melt! and passed in as the per-cell vector H_marker_c. Marker contributions are averaged per cell, not summed, so dense marker packing cannot inflate the source. Sign convention: L>0 endothermic. See Phase changes and Melting.

PIC temperature pattern

Markers carry temperature; how they exchange it with the grid is set by marker_T_mode ([temperature], default "pic_increment" in cases/_defaults.toml). The per-step sequence in src/time_stepping/Driver.jl is:

  1. pic_increment only — project marker T to cell means (project_marker_T_to_cells) and L2-fit the piecewise-constant field onto Q1 (_project_cellfield_to_T, bound-preserving: the projection is clamped to the marker-data range widened to the Dirichlet endpoints), stamping the post-advection marker temperature into state.Th.

  2. Optional subgrid diffusion (below), then re-project so the grid solve sees the corrected field.

  3. FE heat solve (solve_heat_step!) → Tn+1 with diffusion + sources.

  4. Marker update (update_marker_temperatures! in src/particles/Projection.jl):

  • mode = :pic_increment: Tm+=Thnew(xm)Thpre(xm) — the I2ELVIS/PIC pattern: markers keep their advected temperature identity and absorb only the diffusion + source increment. Required for vigorous convection (Blankenbach-class) and for cold slabs that must not lose their thermal identity.

  • mode = :overwrite: Tm=Th(xm) — markers track the FE field entirely. Caveat: combined with the default diffusion-only heat operator, temperature then does not advect at all; use overwrite only deliberately, e.g. together with do_supg_heat = true so the FE operator supplies the advection.

Subgrid diffusion (Gerya & Yuen 2003)

With do_subgrid_diffusion = true, apply_subgrid_diffusion! (src/particles/Projection.jl) relaxes each marker toward the grid-interpolated temperature Tn at the subgrid diffusion timescale:

TmTn+(TmTn)exp(dκΔtgfac),gfac=2Δx2+2Δy2(+2Δz2),

with κ=kc/(ρrefcp,c) from the host cell and the dimensionless coefficient d= subgrid_d (default 1.0). This suppresses the marker–grid temperature inconsistency that otherwise accumulates in PIC thermal convection and stalls it at fine grids. The correction only acts in pic_increment mode, is restricted to uniform Cartesian meshes, and is followed by a re-projection so it is energy-conservative on the grid.

Bound-preserving clamp

Galerkin/BE produces small over/undershoots near sharp gradients (sticky-air interface, slab tips) that compound over many PIC steps. _heat_clamp_bounds (src/time_stepping/Driver.jl) computes per-step bounds from the pre-solve field range united with the Dirichlet endpoints, widened by a 5 % slack:

[Tlo,Thi]=[min(minTn,Ttop,Tbot)s,max(maxTn,Ttop,Tbot)+s],s=0.05|TbotTtop|.

The rationale: by the maximum principle, pure BE diffusion cannot exceed the pre-solve range; the slack admits legitimate source-driven growth (shear/radiogenic/latent heating) per step. The same bounds are applied to the FE dofs after the solve and to the marker temperatures in update_marker_temperatures!, so grid and markers stay consistent. (Clamping to the Dirichlet endpoints alone — an earlier scheme — flattened internal anomalies hotter than the boundary range.)

Time-step interaction

compute_dt (src/time_stepping/CFL.jl) limits Δt by both the advection CFL and a thermal-diffusion accuracy bound Δtmaxxysteph2ρcp/k (BE is unconditionally stable; the bound keeps the Fourier number small for accuracy). See Time stepping.

Key reference

Config keyDefaultMeaning
do_heattruesolve the energy equation
T_top, T_bot273, 1623 KDirichlet surface / bottom temperature
rho_ref_heat3300constant ρ in ρcp (and in subgrid κ)
marker_T_mode"pic_increment"pic_increment (ΔT → markers) or overwrite (FE → markers)
heat_stabilisation"none"none (PIC) | supg | entropy
do_supg_heatfalselegacy alias for SUPG-stabilized FE advection
do_subgrid_diffusion, subgrid_dfalse, 1.0Gerya–Yuen marker-grid relaxation
do_radiogenic, do_shear_heating, do_adiabatictrue, true, falsesource toggles
H_const0.0uniform extra source (W/m³)
bcT_surface, bcT_deep"dirichlet"dirichlet | flux | insulating | robin
q_surface, q_deep, h_robin, T_amb0, 0, 0, 298.15flux / Robin BC data
radiogenic_heating (per [[rock]])hr (W/m³)
specific_heat, thermal_conductivity (per [[rock]])cp, k (harmonic cell mean for k)