Skip to content

Numerics and Physics

MagmaThermoKinematics.jl is built around a finite-difference energy solver with semi-Lagrangian advection and tracer-based tracking of injected sill material.

Governing Equation

The thermal state of the magmatic system is described by the advection–diffusion equation for temperature T with latent heat release:

(A1)ρCp(Tt+vT)=(kT)+ρLϕst+H

where

SymbolDescription
ρRock density (kg m⁻³)
CpIsobaric heat capacity (J kg⁻¹ K⁻¹)
TTemperature (K or °C)
tTime (s)
vSolid-state velocity field (m s⁻¹) induced by dike/sill emplacement
kThermal conductivity (W m⁻¹ K⁻¹)
LLatent heat of crystallisation (J kg⁻¹)
ϕs=(1ϕ)Solid fraction (dimensionless, 0–1), with ϕ being the melt fraction
HRadiogenic heat production (W m⁻³)

Operator Splitting

Equation (A1) is solved with a first-order operator split that separates advection from diffusion+latent heat. Each time step Δt proceeds in two sub-steps:

Step 1 — advection (semi-Lagrangian):

(A2a)T=T(xvΔt,tn)

The departure point xvΔt is found by back-tracking each grid node by one time step along the velocity field. The temperature at the departure point is obtained by bi-linear (2D) or tri-linear (3D) interpolation from the current grid values Tn. The semi-Lagrangian scheme is unconditionally stable with respect to the advective CFL criterion.

Step 2 — diffusion and latent heat:

(A2b)ρCpTn+1TΔt=(kTn+1)+ρLϕst|n+1+H

Effective Heat Capacity Formulation

Because melt fraction ϕ depends on temperature, the latent heat term in (A2b) can be rewritten using the chain rule:

ρLϕst=ρLϕsTTt

Substituting into (A2b) and rearranging yields a modified heat capacity:

(A3)ρCpeffTn+1TΔt=(kTn+1)+H

where the effective heat capacity absorbs the latent heat contribution:

(A3a)Cpeff=Cp+LϕT

Where we made use of the fact that ϕs/t=ϕ/t. This formulation is advantageous because it keeps the structure of the standard diffusion equation while automatically capturing latent heat release whenever ϕ/T0 (i.e., within the two-phase region). As this latter effect is taken into account in an implicit manner, it is numerically more stable.

An important point to keep in mind, though, is that ϕ/T should be continous throughout the domain, including at the solidus and liquidus to prevent numerical instabilities. For this reason, the GeoParams package implements smoothening functions for any melting curve (as many parameterisations in use are discontinuous).

Explicit Time Discretisation

The diffusion operator in (A3) is discretised explicitly:

(A4)Ti,jn+1=Ti,j+ΔtρCpeff[(kT)i,jn+Hi,j]

Staggered-Grid Finite Differences

The spatial derivatives in (A4) are evaluated on a staggered grid:

  • Temperature T and scalar material properties (ρ, Cp, ϕ) are defined at cell centres.

  • Heat fluxes q=kT are defined on cell faces (half-integer indices).

  • Conductivity k is harmonically averaged to cell faces to conserve flux continuity across material interfaces.

The discrete Laplacian in 2D is:

(kT)i,jki+12,j(Ti+1,jTi,j)ki12,j(Ti,jTi1,j)Δx2+ki,j+12(Ti,j+1Ti,j)ki,j12(Ti,jTi,j1)Δz2

with the analogous 3D extension for the y-direction.

CFL Stability Criterion

For the explicit thermal diffusion step the time step must satisfy the standard parabolic CFL condition:

(CFL)Δt12min(Δx,Δy,Δz)2max(κ)

where the thermal diffusivity is κ=k/(ρCpeff). In practice the code evaluates κ at every grid point and uses the global maximum to set a conservative Δt.

Nonlinear Iterations (Picard)

Because Cpeff itself depends on Tn+1 through ϕ/T, equation (A4) is nonlinear. The solver uses damped Picard (fixed-point) iterations to resolve this nonlinearity within each time step:

Predictor — evaluate material properties at the current iterate T(k):

(A5)Cpeff,(k)=Cp(T(k))LϕT|T(k)

Corrector — advance temperature with the updated effective heat capacity:

(A6)Ti,j(k+1)=Ti,j+ΔtρCpeff,(k)[(k(k)T(k))i,j+Hi,j]

Damping — to aid convergence the update is damped:

T(k+1)αT(k+1)+(1α)T(k),0<α1

Convergence — iterations continue until the maximum pointwise temperature change falls below a prescribed tolerance ε:

maxi,j|Ti,j(k+1)Ti,j(k)|<ε

Typically three to five Picard iterations are sufficient per time step.

Melt Intrusion Algorithms

Three distinct emplacement modes are available for adding new melt to the system:

ModeDescription
Geneva sill (under-accretion)New magma is injected at the base of the existing melt body and solid host-rock is displaced downward.
UCLA-HD (central injection)Melt is added at the centre of the intrusion; host rock is displaced radially outward while conserving volume.
Elastic dikeAn elliptical dike geometry is used and host rock is displaced by an analytically prescribed elastic displacement field.

All three modes inject a Dike object, update the velocity field v for one time step (used in the semi-Lagrangian advection step A2a), and add tracer particles at the new melt location.

Tracers and Temperature–Time Paths

Passive tracer particles are advected with the host-rock velocity field using the same semi-Lagrangian scheme as the temperature field. At each time step each tracer records its current temperature, producing a continuous Tt path. These paths are the primary input to the ZirconGrowth integration.

Tracers are kept on the CPU, as they generally use a lot of memory.

Dimensions and Geometry

Supported configurations include:

  • 2D Cartesian.

  • 2D axisymmetric (via specific workflows in examples).

  • 3D Cartesian.

Material Parameter Handling

Material properties are integrated through GeoParams-based parameterizations and package-level helper routines for conductivity, density, heat capacity, melt fraction, and related quantities.

One of the highlights is that melting parameterizations and material properties can be changed very easily by using GeoParams (see ).

Changing Melting Parameterizations

Material setup is defined with SetMaterialParams, so changing physics is extremely simple and only requires you to change your MatParam struct. For example, you can switch between the Caricchi melting parameterization and a simple 4th-order polynomial melting curve with:

julia
MatParam = (
	SetMaterialParams(Name="Rock", Phase=1,
		Density=ConstantDensity=2700kg/m^3),
		HeatCapacity=ConstantHeatCapacity(Cp=1000J/kg/K),
		Conductivity=T_Conductivity_Whittington_parameterised(),
		Melting=MeltingParam_Caricchi()
        ),
)
julia
MatParam = (
	SetMaterialParams(Name="Rock", Phase=1,
		Density=ConstantDensity=2700kg/m^3),
		HeatCapacity=ConstantHeatCapacity(Cp=1000J/kg/K),
		Conductivity=T_Conductivity_Whittington_parameterised(),
		Melting=SmoothMelting(MeltingParam_4thOrder())
        ),
)
# Example alternatives:
# Conductivity=ConstantConductivity(k=3.3W/K/m)

This design makes it straightforward to test sensitivity to melt models and thermophysical assumptions without changing solver internals.

Performance and Parallelism

Backend selection through environment! configures CPU threads, or CUDA execution, and the package composes with ParallelStencil finite-difference modules.

  • CPU and CUDA workflows are typically run with Float64 precision.

When your own script uses ParallelStencil macros directly (for example @zeros or @parallel), call @init_parallel_stencil(...) in script scope after environment!(...).

If you run this on a CPU, you can run it in parallel by starting julia in multi-threading mode:

julia
$julia -t auto