Grain-size evolution
MILET evolves a grain size src/materials/GrainSize.jl, the rheological coupling in src/materials/Rheology.jl and src/materials/FlowLaws.jl, the driver wiring in update_marker_grain_size! (src/time_stepping/Driver.jl); the design spec is doc/design/grain_size.md.
Evolution equation
Per marker, at fixed
Growth is the normal grain-growth law grain_growth_coeff.
Reduction is the Austin–Evans wattmeter: the fraction
Steady state (the wattmeter)
Setting growth = reduction gives the closed-form fixed point (grain_size_steady_state):
reproducing the test/smoke/test_grainsize.jl), approached from both above and below.
Exact-sub-flow integrator
The ODE is stiff far from equilibrium (reduction update_grain_size uses operator splitting in which both sub-flows integrate exactly in closed form:
Consequences: with
net-rate limiter:
— vanishes at the fixed point, where an equilibrium early-exit ( ) makes steady-state markers nearly free; split-error control: each sub-flow capped at 5 % of
per substep (a 50 % cap left a 10 % offset from the analytic ; 5 % gives < 1 %); bounds: floor
d_min = 1e-6m (1 µm), capd_max = 0.1m, at mostmax_substeps = 400substeps.
The update is pure per-marker arithmetic (no Gridap calls) and is threaded over markers on the Cartesian fast path.
Mechanism partition (who pays for the wattmeter)
The composite viscous rheology assumes both creep mechanisms act in parallel at common stress, so compliances add (see Rheology):
viscous_mechanism_partition (src/materials/Rheology.jl) recovers the per-mechanism rates under stress continuity:
Two implementation points matter:
The partition uses the unclamped constitutive viscosity — the
eta_min/eta_maxclamps are numerical guards for the FE solve; applying them here would break the identityand inflate the work rate wherever a clamp engages. With no calibrated diffusion law (
diff_A = 0) the entire viscous strain rate is attributed to the dislocation/legacy branch — the conservative choice for grain-size reduction.
The diffusion-creep viscosity is the Hirth & Kohlstedt (2003) form (diffusion_viscosity, src/materials/FlowLaws.jl):
with the laboratory convention DIFF_CREEP_LAWS) usable via diff_prof: "Dry_Olivine_diff-Hirth_Kohlstedt_2003" ("Wet_Olivine_diff-Hirth_Kohlstedt_2003" (
Driver wiring and feedback loop
Per step, after marker advection and gated on any(rk -> rk.grain_G0 > 0), update_marker_grain_size! runs per marker: 1.
from mk.T; lithostatic pressure state.eii_c).
viscous_mechanism_partitionat the marker's own grain size →. update_grain_sizeadvancesmk.grain_size[m].
The loop closes through the projection: project_markers_to_cells! (src/particles/Projection.jl) passes each marker's grain size to compute_VEP_viscosity, where diff_A > 0 activates the
Marker state: mk.grain_size::Vector{Float32} is initialized per rock from grain_init (src/initialization/Markers.jl), advects with the marker, is inherited on reseeding, checkpointed, and written to the marker VTK output as grain_size_mm.
A legacy path is kept for backward compatibility: the global [rheology] key grain_exponent (eta0-path creep viscosity by diff_A = 0 and grain_G0 = 0 behavior is identical to the pre-grain-size code (regression-tested).
Configuration (per [[rock]])
Defaults from src/io/TOMLLoader.jl; see also Parameter file and doc/Parameter-file-example.md.
| Key | Default | Units | Meaning |
|---|---|---|---|
diff_prof | "" | — | named catalog diffusion-creep law (overrides the four below) |
diff_A | 0.0 | MPa⁻¹ µm | diffusion-creep prefactor; 0 = mechanism off |
diff_m | 3.0 | — | grain-size exponent |
diff_E | 375e3 | J/mol | activation energy |
diff_V | 6e-6 | m³/mol | activation volume |
grain_G0 | 0.0 | m | growth prefactor |
grain_p | 3.0 | — | growth exponent |
grain_Eg | 350e3 | J/mol | growth activation energy |
grain_Vg | 8e-6 | m³/mol | growth activation volume |
grain_lambda | 0.1 | — | work partition |
grain_gamma | 1.0 | J/m² | grain-boundary surface energy |
grain_c | 3π | — | geometric constant |
grain_init | 1e-3 | m | initial marker grain size |
Tests
test/smoke/test_grainsize.jl checks: (1) the growth-only analytic law over a large diff_A = 0 regression; (4) mechanism-partition stress consistency (