Skip to content

Commit f4e88b5

Browse files
L03: reconstruct earth heat budget, marginal stability, Nu-Ra scaling
1 parent 5779c54 commit f4e88b5

8 files changed

Lines changed: 284 additions & 3 deletions

File tree

2.5 KB
Binary file not shown.
14.4 KB
Binary file not shown.
17.4 KB
Binary file not shown.

book/03_heat_energy/heat_energy.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ The total heat flowing out of Earth's interior is approximately **47 TW** {cite:
103103
:width: 450px
104104
:align: center
105105
106-
Earth's surface heat-flux budget (~47 TW), decomposed into radiogenic (~20 TW), primordial / secular cooling (~15 TW), core cooling and solidification (~10 TW), and lunar tidal dissipation (~0.1 TW). Tidal contribution is too small to render at this scale. After {cite:p}`DaviesDavies2010`. Custom plot.
106+
Earth's surface heat-flux budget (~47 TW), decomposed into radiogenic (~20 TW), primordial / secular cooling (~15 TW), core cooling and solidification (~10 TW), and lunar tidal dissipation (~0.1 TW). Tidal contribution is too small to render at this scale. After {cite:p}`DaviesDavies2010`. Generated by `scripts/figures/L03_heat_energy/fig_earth_heat_budget.py`.
107107
```
108108
109109
Roughly 40% of Earth's current heat loss is powered by ongoing radioactive decay, with the rest being the slow release of primordial heat stored since formation. This means Earth is still cooling: its interior temperature is gradually decreasing over geological time. The relative importance of these sources varies strongly across the solar system: small bodies like the Moon have lost most of their primordial heat long ago, while a tidally heated moon like Io has a heat budget dominated by tidal dissipation rather than radiogenic or primordial heat.
@@ -291,7 +291,7 @@ $$
291291
:width: 600px
292292
:align: center
293293
294-
Marginal stability curve for Rayleigh-Bénard convection between rigid horizontal boundaries (schematic, normalised to the canonical critical values). Convection grows for parameter combinations above the curve; conduction is the only steady transport mode below it. The minimum of the curve is the critical Rayleigh number $\mathrm{Ra}_c\approx 1708$, attained at non-dimensional wavenumber $k_c\approx 3.12$ {cite:p}`Turcotte2002`. Custom plot.
294+
Marginal stability curve for Rayleigh-Bénard convection between rigid horizontal boundaries (schematic, normalised to the canonical critical values). Convection grows for parameter combinations above the curve; conduction is the only steady transport mode below it. The minimum of the curve is the critical Rayleigh number $\mathrm{Ra}_c\approx 1708$, attained at non-dimensional wavenumber $k_c\approx 3.12$ {cite:p}`Turcotte2002`. Generated by `scripts/figures/L03_heat_energy/fig_marginal_stability.py`.
295295
```
296296
297297
For Earth's mantle, typical parameters are $\alpha \sim 2 \times 10^{-5}$ K$^{-1}$, $\rho \sim 4000$ kg m$^{-3}$, $g \sim 10$ m s$^{-2}$, $\Delta T \sim 2500$ K, $d \sim 3 \times 10^6$ m, $\kappa \sim 10^{-6}$ m$^2$ s$^{-1}$, and $\eta \sim 10^{21}$ Pa s. This gives:
@@ -331,7 +331,7 @@ This means convection transports heat roughly 200 times more efficiently than co
331331
:width: 600px
332332
:align: center
333333
334-
Schematic Nusselt-Rayleigh scaling. Below the critical Rayleigh number $\mathrm{Ra}_c\approx 1708$ heat is conducted only ($\mathrm{Nu}=1$); above it the boundary-layer scaling $\mathrm{Nu}\propto\mathrm{Ra}^{1/3}$ applies (Eq. {eq}`eq:nu-ra-scaling`). Earth's mantle, with $\mathrm{Ra}\sim 10^7\text{--}10^8$, transports heat $\sim 200$ to $500$ times more efficiently than conduction alone under this idealised isoviscous scaling. Custom plot.
334+
Schematic Nusselt-Rayleigh scaling. Below the critical Rayleigh number $\mathrm{Ra}_c\approx 1708$ heat is conducted only ($\mathrm{Nu}=1$); above it the boundary-layer scaling $\mathrm{Nu}\propto\mathrm{Ra}^{1/3}$ applies (Eq. {eq}`eq:nu-ra-scaling`). Earth's mantle, with $\mathrm{Ra}\sim 10^7\text{--}10^8$, transports heat $\sim 200$ to $500$ times more efficiently than conduction alone under this idealised isoviscous scaling. Generated by `scripts/figures/L03_heat_energy/fig_nu_ra_scaling.py`.
335335
```
336336
337337
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"purpose": "Fig. fig:earth-heat-budget: Earth surface heat budget pie",
3+
"total_TW": 47.0,
4+
"components": [
5+
{
6+
"label": "Radiogenic\n(mantle + crust)",
7+
"TW": 20.0
8+
},
9+
{
10+
"label": "Primordial\n(secular cooling)",
11+
"TW": 15.0
12+
},
13+
{
14+
"label": "Core cooling\nand solidification",
15+
"TW": 10.0
16+
},
17+
{
18+
"label": "Tidal (lunar)",
19+
"TW": 0.1
20+
}
21+
],
22+
"source": "Davies, J. H. & Davies, D. R. (2010), Solid Earth 1, 5-24",
23+
"doi": "10.5194/se-1-5-2010",
24+
"citation_key": "DaviesDavies2010",
25+
"license_note": "Component figures are conventional review values."
26+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Generate Fig. (`fig:earth-heat-budget`).
2+
3+
Pie chart of Earth's surface heat-flux budget, ~47 TW total,
4+
decomposed into radiogenic, primordial / secular cooling, core
5+
cooling and solidification, and lunar tidal dissipation.
6+
7+
Caption / figure id : `fig:earth-heat-budget`
8+
Markdown source : book/03_heat_energy/heat_energy.md
9+
Citation key : DaviesDavies2010
10+
11+
Component values are static numerics from the Davies & Davies 2010
12+
review and are tabulated in `data/earth_heat_budget.json`.
13+
"""
14+
from __future__ import annotations
15+
16+
import json
17+
from pathlib import Path
18+
19+
import matplotlib.pyplot as plt
20+
21+
from scripts.figures._shared.style import apply_style, save_figure
22+
23+
24+
REPO_ROOT = Path(__file__).resolve().parents[3]
25+
DATA_DIR = Path(__file__).resolve().parent / "data"
26+
META = DATA_DIR / "earth_heat_budget.json"
27+
OUT_AVIF = REPO_ROOT / "book/03_heat_energy/figures/earth_heat_budget.avif"
28+
29+
COMPONENTS = [
30+
("Radiogenic\n(mantle + crust)", 20.0, "#d62728"),
31+
("Primordial\n(secular cooling)", 15.0, "#ff7f0e"),
32+
("Core cooling\nand solidification", 10.0, "#1f77b4"),
33+
("Tidal (lunar)", 0.1, "#2ca02c"),
34+
]
35+
36+
37+
def write_metadata() -> None:
38+
DATA_DIR.mkdir(parents=True, exist_ok=True)
39+
META.write_text(json.dumps({
40+
"purpose": "Fig. fig:earth-heat-budget: Earth surface heat budget pie",
41+
"total_TW": 47.0,
42+
"components": [{"label": l, "TW": v} for l, v, _ in COMPONENTS],
43+
"source": "Davies, J. H. & Davies, D. R. (2010), Solid Earth 1, 5-24",
44+
"doi": "10.5194/se-1-5-2010",
45+
"citation_key": "DaviesDavies2010",
46+
"license_note": "Component figures are conventional review values.",
47+
}, indent=2))
48+
49+
50+
def make_plot() -> Path:
51+
apply_style()
52+
write_metadata()
53+
labels, sizes, colors = zip(*[(l, v, c) for l, v, c in COMPONENTS])
54+
55+
fig, ax = plt.subplots(figsize=(7, 5.5))
56+
wedges, texts = ax.pie(
57+
sizes, colors=colors,
58+
labels=[f"{l}\n~{v:.1f} TW" for l, v in zip(labels, sizes)],
59+
startangle=90, counterclock=False,
60+
wedgeprops={"edgecolor": "white", "linewidth": 1.5},
61+
textprops={"fontsize": 10},
62+
labeldistance=1.1,
63+
)
64+
65+
# Inside-wedge values for the larger components
66+
for w, val in zip(wedges, sizes):
67+
if val >= 5:
68+
ang = (w.theta1 + w.theta2) / 2
69+
import numpy as np
70+
x = 0.6 * np.cos(np.radians(ang))
71+
y = 0.6 * np.sin(np.radians(ang))
72+
ax.text(x, y, f"{val:.0f} TW", ha="center", va="center",
73+
fontsize=11, color="white", fontweight="bold")
74+
75+
ax.set_title("Earth's surface heat-flux budget (~47 TW)", fontsize=12, pad=18)
76+
fig.tight_layout()
77+
return save_figure(fig, OUT_AVIF, avif_quality=80)
78+
79+
80+
def main() -> None:
81+
out = make_plot()
82+
print(f" meta : {META}")
83+
print(f" plot : {out}")
84+
85+
86+
if __name__ == "__main__":
87+
main()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Generate Fig. (`fig:marginal-stability`).
2+
3+
Schematic Rayleigh-Bénard marginal-stability curve normalised to the
4+
canonical critical values: Ra_c ≈ 1708 at non-dimensional wavenumber
5+
k_c ≈ 3.117 between rigid horizontal boundaries.
6+
7+
Caption / figure id : `fig:marginal-stability`
8+
Markdown source : book/03_heat_energy/heat_energy.md
9+
Citation key : Chandrasekhar1961
10+
11+
The exact stability curve solves a transcendental boundary-value
12+
problem; here we plot the standard analytic approximation:
13+
14+
Ra(k) = (k^2 + pi^2)^3 / k^2
15+
16+
This is the *free-slip* (stress-free) result with Ra_c = 657.5 at
17+
k_c = pi/sqrt(2) ≈ 2.221. The classical *rigid-rigid* boundary case
18+
(Ra_c = 1707.762, k_c = 3.117) does not have a closed-form curve
19+
but is well approximated for visualisation by scaling the free-slip
20+
curve so its minimum sits at the rigid values, which is what we do.
21+
"""
22+
from __future__ import annotations
23+
24+
from pathlib import Path
25+
26+
import matplotlib.pyplot as plt
27+
import numpy as np
28+
29+
from scripts.figures._shared.style import apply_style, save_figure
30+
31+
32+
REPO_ROOT = Path(__file__).resolve().parents[3]
33+
OUT_AVIF = REPO_ROOT / "book/03_heat_energy/figures/marginal_stability.avif"
34+
35+
# Rigid-rigid critical values (Chandrasekhar 1961, Table II)
36+
RA_C = 1707.762
37+
K_C = 3.117
38+
39+
40+
def make_plot() -> Path:
41+
apply_style()
42+
43+
# Free-slip stability curve (analytic) shifted to land on the
44+
# rigid-rigid critical values for visualisation.
45+
k = np.linspace(0.4, 8.0, 400)
46+
pi = np.pi
47+
free_slip = (k ** 2 + pi ** 2) ** 3 / k ** 2
48+
free_slip_min = (4.0 / 27.0) * (3.0 * pi ** 2) ** 3 / (3 * pi ** 2) ** 2 # value at k = pi/sqrt(2)
49+
# Scale and shift in k so the minimum hits (K_C, RA_C)
50+
scale_k = K_C / (pi / np.sqrt(2))
51+
k_shifted = k * scale_k
52+
Ra_shifted = free_slip * (RA_C / free_slip_min)
53+
54+
fig, ax = plt.subplots(figsize=(6.5, 4.4))
55+
ax.plot(k_shifted, Ra_shifted, color="#1f77b4", lw=2.0)
56+
57+
# Fill convection-on region
58+
ax.fill_between(k_shifted, Ra_shifted, 1e6, color="#ff7f0e", alpha=0.13,
59+
label="Convection")
60+
ax.fill_between(k_shifted, 0, Ra_shifted, color="#1f77b4", alpha=0.10,
61+
label="Conduction only")
62+
63+
# Mark critical point
64+
ax.plot(K_C, RA_C, "o", color="#d62728", markeredgecolor="black",
65+
markersize=8, zorder=5)
66+
ax.annotate(f"$\\mathrm{{Ra}}_c \\approx {RA_C:.0f}$,\n"
67+
f"$k_c \\approx {K_C:.2f}$",
68+
xy=(K_C, RA_C), xytext=(K_C + 0.5, RA_C * 0.45),
69+
fontsize=10,
70+
arrowprops=dict(arrowstyle="->", lw=0.8, color="dimgray"))
71+
72+
ax.set_yscale("log")
73+
ax.set_xlabel(r"Non-dimensional horizontal wavenumber $k$")
74+
ax.set_ylabel(r"Rayleigh number $\mathrm{Ra}$")
75+
ax.set_xlim(0, 8)
76+
ax.set_ylim(5e2, 5e5)
77+
ax.set_title("Marginal stability curve (rigid horizontal boundaries)")
78+
ax.grid(which="both", linestyle=":", alpha=0.3)
79+
ax.legend(loc="upper right", frameon=False)
80+
81+
fig.tight_layout()
82+
return save_figure(fig, OUT_AVIF, avif_quality=80)
83+
84+
85+
def main() -> None:
86+
out = make_plot()
87+
print(f" plot : {out}")
88+
89+
90+
if __name__ == "__main__":
91+
main()
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""Generate Fig. (`fig:nu-ra-scaling`).
2+
3+
Schematic Nusselt-Rayleigh scaling: Nu = 1 below Ra_c (pure
4+
conduction), Nu ~ Ra^{1/3} above (boundary-layer scaling, after the
5+
asymptotic boundary-layer theory of Howard 1966 and Malkus 1954).
6+
The shaded band marks Earth's mantle (Ra ~ 1e7 to 1e8).
7+
8+
Caption / figure id : `fig:nu-ra-scaling`
9+
Markdown source : book/03_heat_energy/heat_energy.md
10+
Citation key : (textbook scaling; cited as Turcotte2002 in body)
11+
"""
12+
from __future__ import annotations
13+
14+
from pathlib import Path
15+
16+
import matplotlib.pyplot as plt
17+
import numpy as np
18+
19+
from scripts.figures._shared.style import apply_style, save_figure
20+
21+
22+
REPO_ROOT = Path(__file__).resolve().parents[3]
23+
OUT_AVIF = REPO_ROOT / "book/03_heat_energy/figures/nu_ra_scaling.avif"
24+
25+
RA_C = 1708.0
26+
27+
28+
def make_plot() -> Path:
29+
apply_style()
30+
Ra = np.logspace(2, 11, 400)
31+
32+
# Conduction below Ra_c, Nu ~ Ra^(1/3) above (with the canonical
33+
# prefactor that gives Nu = 1 at Ra = Ra_c, i.e. continuous at the
34+
# bifurcation).
35+
Nu = np.ones_like(Ra)
36+
above = Ra > RA_C
37+
Nu[above] = (Ra[above] / RA_C) ** (1.0 / 3.0)
38+
39+
fig, ax = plt.subplots(figsize=(7, 4.4))
40+
ax.plot(Ra, Nu, color="#1f77b4", lw=2.0,
41+
label=r"$\mathrm{Nu}(\mathrm{Ra})$")
42+
43+
ax.axvline(RA_C, color="#d62728", lw=1.0, linestyle="--",
44+
label=fr"$\mathrm{{Ra}}_c = {RA_C:.0f}$")
45+
46+
# Earth-mantle band
47+
ax.axvspan(1e7, 1e8, color="#ff7f0e", alpha=0.18,
48+
label=r"Earth's mantle (Ra $\sim 10^7$-$10^8$)")
49+
50+
# Asymptotic slope label
51+
ax.text(1e9, (1e9 / RA_C) ** (1.0 / 3.0) * 1.4,
52+
r"$\mathrm{Nu} \propto \mathrm{Ra}^{1/3}$",
53+
fontsize=11, color="#1f77b4")
54+
ax.text(20, 0.7, r"$\mathrm{Nu} = 1$ (conduction)",
55+
fontsize=10, color="#1f77b4")
56+
57+
ax.set_xscale("log")
58+
ax.set_yscale("log")
59+
ax.set_xlim(1e2, 1e11)
60+
ax.set_ylim(0.5, 1e3)
61+
ax.set_xlabel("Rayleigh number $\\mathrm{Ra}$")
62+
ax.set_ylabel("Nusselt number $\\mathrm{Nu}$")
63+
ax.set_title("Heat-transport efficiency: $\\mathrm{Nu}$ vs $\\mathrm{Ra}$")
64+
ax.grid(which="both", linestyle=":", alpha=0.3)
65+
ax.legend(loc="lower right", frameon=False)
66+
67+
fig.tight_layout()
68+
return save_figure(fig, OUT_AVIF, avif_quality=80)
69+
70+
71+
def main() -> None:
72+
out = make_plot()
73+
print(f" plot : {out}")
74+
75+
76+
if __name__ == "__main__":
77+
main()

0 commit comments

Comments
 (0)