Skip to content

Phase changes

Solid–solid phase transitions are applied per marker, after the heat solve and marker advection, by apply_marker_phase_and_melt! (src/time_stepping/Driver.jl), which calls apply_phase_change! (src/materials/PhaseChange.jl) for every marker against every [[phase]] entry whose rock_from matches the marker's current rock type. The module is enabled by do_phase_change in the [physics] section (default false in cases/_defaults.toml).

Each marker carries a cumulative density anomaly phase_drho (kg/m³, Float32, defined in src/particles/Particles.jl). It is the state variable of the phase-change module: compute_density (src/materials/Density.jl) adds it directly to the solid density,

ρsolid(T,P)=ρ0(1α(TTref))(1+β(PPref))+Δρphase,

so a transition changes buoyancy exactly once per marker (no re-counting from cell-wise PT lookups). The field is written to the markers VTU as phase_drho_kg_m3 and stored in checkpoints.

Pressure. The trigger pressure is the lithostatic estimate P=ρrefgy (computed in bar in the driver, P_bar = rk.reference_density * cfg.gy_grav * y / 1e5, converted back to Pa inside apply_phase_change!). Using the FE pressure field instead is a noted TODO in apply_marker_phase_and_melt!.

Mode 1 — Clapeyron PT transition (transition = 1)

Univariant transitions such as olivine → wadsleyite (≈ 410 km) and ringwoodite → bridgmanite (≈ 660 km). The phase boundary is a straight line in PT space through the reference point (Tref,Pref) with Clausius–Clapeyron slope γ=dT/dP (config key clapeyron, K/Pa):

Tlocus(P)=Tref+γ(PPref).

A marker has crossed when T>Tlocus(P), i.e. it lies on the high-pressure-phase side of the line. On crossing, apply_phase_change!

  • reassigns the rock type to rock_to (may equal rock_from to apply only the density jump and latent heat),

  • adds drho (kg/m³, positive = densified) to the marker's phase_drho,

  • accumulates latent (J/kg) into the returned latent-heat budget.

Sign convention for the slope (see the header comment of src/materials/PhaseChange.jl): positive clapeyron → exothermic transition, boundary deflects upward around cold slabs (enhanced penetration); negative clapeyron → endothermic, boundary deflects downward (the textbook 660 km barrier).

Mode 2 — depth-triggered transition (transition = 2)

For reactions whose temperature dependence is negligible at the depth of interest (e.g. basalt → eclogite as a sharp jump near 70 km), the locus is a depth threshold: the marker crosses when y>ytrigger (the y axis points down). The same rock_to / drho / latent effects apply as in mode 1.

Parsed key In mode 2 the P_ref slot is reinterpreted as the trigger depth in metres (if y > ph.P_ref in apply_phase_change!). The TOML loader (src/io/TOMLLoader.jl) parses P_ref only — a depth key in a [[phase]] block is silently ignored and P_ref falls back to its default of 0.0, which triggers the transition everywhere below the surface. Set P_ref = 70000.0 (metres) for a 70 km trigger. :::

Mode 3 — divariant, rate-limited eclogitization (transition = 3)

Eclogitization of subducted crust is not a univariant jump: the gabbro/blueschist → eclogite reaction progresses over a pressure band and is kinetically inhibited in cold, dry slabs. Mode 3 models this as a continuous reaction-progress variable X[0,1] (the eclogite fraction) with an equilibrium target and an optional forward-only relaxation.

Equilibrium (S1). The reaction-band centre is a line in PT space (here clapeyron is the slope dP/dT in Pa/K, transposed relative to mode 1):

Pc(T)=Pref+γ(TTref),Xeq(P,T)=clamp(PPc(T)ΔPband+12,0,1),

with band width ΔPband = band_width (Pa). With react_tau_ref = 0 (the default), the marker is set to equilibrium each step, X=Xeq — an instantaneous divariant transition.

Kinetics (S2). With react_tau_ref > 0 the eclogite fraction relaxes forward only (the reaction is irreversible; X never decreases) toward Xeq with an Arrhenius reaction time modelled on dry volume diffusion (Ahrens & Schubert 1975):

τrxn(T)=τrefexp[QrxnR(1T1Trxn,ref)],XX+(XeqX)(1eΔt/τrxn),

where τref = react_tau_ref (s), Qrxn = react_Q (J/mol) and Trxn,ref = react_Tref (K, default 973.15). The update is the exact integral of X˙=(XeqX)/τ over the step, so the result is independent of the time-step size.

State and coupling. Mode 3 does not reassign the rock type. The state variable is the marker's phase_drho, which is overwritten each step as Δρphase=drhoX (a state function of P, T and reaction history, not a cumulative jump); the eclogite fraction is recovered as X=phase_drho/drho. Two couplings follow:

  • Densification: the full drhoX enters compute_density, driving slab pull as the reaction progresses.

  • Reaction softening: if weaken_decades > 0, the marker viscosity is reduced during marker→cell projection (_eclogite_softening_params and project_markers_to_cells! in src/particles/Projection.jl):

    ηmax(η10wX, ηmin),w=weaken_decades.

No latent heat in mode 3 The mode-3 branch returns before the latent-heat accumulation in apply_phase_change!; the latent key has no effect for transition = 3. Latent heating/cooling is applied only by modes 1 and 2 (and by melting). :::

Latent heat

apply_phase_change! returns the latent heat Qlat (J/kg) of all transitions crossed by the marker this step. Sign convention: positive = endothermic (heat absorbed by the reaction, surroundings cool), negative = exothermic (released). In apply_marker_phase_and_melt! this becomes a volumetric source for the next heat solve,

Hlatent=ρrefQlatΔt[W/m3],

accumulated into the per-cell vector H_marker_latent and averaged over the markers in each cell (not summed) so the source is independent of marker packing density. The cell vector is added to the right-hand side of the heat equation by build_heat_source (src/physics/HeatSources.jl) — see Heat transport.

Configuration

Phase transitions are declared as repeated [[phase]] blocks (the user file's array replaces the defaults; see load_config_toml in src/io/TOMLLoader.jl). Parsed keys and defaults:

KeyDefaultUnitsUsed byMeaning
rock_from— (required)allrock type the transition applies to
rock_to— (required)1, 2rock type assigned after crossing
transition1all1 = Clapeyron, 2 = depth trigger, 3 = divariant eclogitization
T_ref0.0K1, 3reference temperature on the locus
P_ref0.0Pa (mode 1, 3); m (mode 2)allreference pressure / trigger depth
clapeyron0.0K/Pa (mode 1); Pa/K (mode 3)1, 3locus slope (dT/dP vs. dP/dT)
drho0.0kg/m³alldensity jump (mode 3: at X=1)
latent0.0J/kg1, 2latent heat, + endothermic / − exothermic
band_width0.0Pa3divariant reaction-band width
react_tau_ref0.0s3reaction time at react_Tref; 0 = instantaneous
react_Q0.0J/mol3reaction activation energy
react_Tref973.15K3reference temperature for react_tau_ref
weaken_decades0.0decades3viscosity drop 10wX at full eclogitization

Example (from cases/subduction_thermomech.toml): the 410 km and 660 km mantle transitions plus crustal eclogitization,

toml
[physics]
do_phase_change = true

# olivine → wadsleyite, 410 km (exothermic, positive Clapeyron slope)
[[phase]]
rock_from  = 5
rock_to    = 5
transition = 1
T_ref      = 1700.0
P_ref      = 14e9      # 410 km ≈ 14 GPa
clapeyron  = 2.5e-9    # K/Pa
drho       = 270.0
latent     = -90000.0  # released

# ringwoodite → bridgmanite, 660 km (endothermic, negative slope)
[[phase]]
rock_from  = 5
rock_to    = 5
transition = 1
T_ref      = 1900.0
P_ref      = 23e9      # 660 km ≈ 23 GPa
clapeyron  = -2.0e-9
drho       = 400.0
latent     = 180000.0  # absorbed

# basalt → eclogite at ~70 km, sharp depth trigger
[[phase]]
rock_from  = 2
rock_to    = 4
transition = 2
P_ref      = 70000.0   # trigger depth (m)
drho       = 200.0

check_config_sanity (src/io/UserHelpers.jl) warns when do_phase_change = true but the domain is shallower than 660 km, since the mantle transitions then never fire.

  • Melting — the other consumer of the shared per-marker latent-heat accumulator.

  • Heat transport — how H_marker_latent enters the heat solve.

  • Rheology — the visco-elasto-plastic viscosity that mode-3 reaction softening modifies.

  • Markers — marker state, projection and averaging conventions.