Energy budget and heat-flow diagnostics
A model that leaks heat can still produce plausible temperatures, velocities and Nusselt numbers. MILEVA therefore logs a discrete energy budget with every row of diagnostics.csv, built from the same fluxes and the same time weighting the solver uses, so its residual tests conservation rather than sampling. This page defines the budget columns and the Nusselt numbers.
The budget
The thermal energy of the domain is
with cell_areas and cell_volumes), scaled to physical walls: in the spherical annulus each column stands for
Each step the main loop accumulates the energy supplied,
where boundary_power(Tg, grid, cfg), cfg.implicitTheta when useImplicitTemp, else 0), and internal_power_last(): radiogenic, latent, heat pipe and any uniform source). Between two CSV rows the residual is
normalised by the larger of the surface power and the internal power, taken every step and averaged over the interval (E_out_cum in main_SphCon.jl), so an internally heated run with a small surface flux still has a meaningful denominator. A conservative scheme gives zero whatever the heating mode.
| Column | Meaning |
|---|---|
E_th_J | |
dEdt_W | mean |
P_supplied_W | mean supplied power since the previous row (boundaries plus internal heating) |
budget_resid | the residual above; the log line prints it as bud= |
E_core_J, E_cmb_cum_J, budget_resid_joint | the same budget for core plus mantle, when the 2-D core cools (cmbHeatfluxMode = "parameterized"); NaN otherwise |
E_cmb_cum_J restarts at zero when a run is resumed; difference it, never read it as an absolute value.

Conduction in the default shell (diffuse_temperature with Crank-Nicolson steps of 20 Myr. Left: the change of thermal_energy and the energy supplied, accumulated from boundary_power and internal_power_last with the solver's docs/scripts/fig_numerics_energy_budget_sections.jl.
Wall fluxes and Nusselt numbers
The wall temperatures are held at the faces
averaged over the wall cells. The Nusselt numbers divide them by the conductive flux of the same geometry. Steady conduction has
(compute_diagnostics in utils/compute_diagnostics.jl, conductive_baseline_C in physics/compressibility.jl). Flux and baseline use the diffusivity the model transports with, which matters under ALA where
Two internal checks follow. On a conducting field Nu = 1, and at a steady state with basal heating Nutests/test_nusselt_conduction.jl asserts both forms on the solver's own conducting steady state: Nu converges to 1 (error

Left: the top of a conducting steady state on a 16-cell column. The surface temperature is held at the face Nu_top and Nu_bot from compute_diagnostics while a uniform 2000 K interior relaxes to conduction (docs/scripts/fig_numerics_energy_budget_sections.jl.
Measured residuals
tests/test_marker_energy.jl pins the marker step: energy delivered equals energy computed to
Residuals on the Hernlund & Tackley (2008) spherical-annulus verification runs (window means; the benchmark comparison itself is documented elsewhere):
| Case | budget_resid | |
|---|---|---|
| Ra = | 128 | |
| Ra = | 128 | |
| Ra = | 64 | |
| Ra = | 32 | |
| Ra = | 64 |

diagnostics.csv of the Ra = budget_resid, scattered between about −0.01 and +0.01.
Sources of small residuals
Reseeding. A cell that has emptied completely gets markers with temperatures interpolated from the grid; that is the one non-conservative marker operation (see Markers).
The delivery cap. Energy withheld by
cfg.deliveryScaleMaxat sparsely populated nodes appears in the residual.Temperature clamps. The bounds applied after diffusion and after the hand-back remove energy only when they bind, which on a well-resolved run they do not.
Grid TVD advection gives a slightly larger residual, as the table shows.

The delivery cap as a residual source. Left: the factor init_markers (9 per cell) and after 600 CFL steps through one fixed two-cell Stokes flow with no reseeding. Advection widens the distribution and pushes a few nodes past deliveryScaleMax = 2. Right: row means and row maxima with depth; the cap binds mostly in single cells and in the bottom wall row. For a uniform increment the cap withholds budget_resid. Script: docs/scripts/fig_numerics_energy_budget_sections.jl.
3-D
In 3-D the row is computed on the Yin patch only (E_th "this patch only" in diagnostics_row), with the patch's own wall areas. Because the Yin patch overlaps Yang (see Markers), the 3-D budget_resid is a diagnostic of that patch rather than a global budget.

Left: the Yin patch (black rectangle) and the boundary of the Yang patch mapped into Yin's frame with yy_yang_to_yin, sampled with random points on the sphere. Each patch covers 53.0 % of the sphere and they overlap on 6.0 % (orange). Right: the 3-D budget row integrates the Yin patch only; cell_volumes gives 0.530 of the shell at docs/scripts/fig_numerics_energy_budget_sections.jl.
Where in the code
| Topic | File | Function |
|---|---|---|
| Budget accumulation | main_SphCon.jl | step (14), E_bnd_cum, E_out_cum, E_cmb_cum |
| Wall powers | utils/diagnostics_csv.jl | boundary_power |
| CSV row and residual | utils/diagnostics_csv.jl | diagnostics_row, _diag_row_common |
| Applied internal power | solvers/diffuse_temperature.jl | internal_power_last |
| Nusselt numbers | utils/compute_diagnostics.jl | compute_diagnostics |
| Conductive baseline | physics/compressibility.jl | conductive_baseline_C |
| Tests | tests/ | test_nusselt_conduction.jl, test_marker_energy.jl, test_conduction_conservation.jl, test_energy_consistency.jl |