Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/climate-science/energy_balance.tex
51 views
unlisted
1
\documentclass[11pt,a4paper]{article}
2
3
% Essential packages
4
\usepackage[utf8]{inputenc}
5
\usepackage[T1]{fontenc}
6
\usepackage{amsmath,amssymb,amsthm}
7
\usepackage{graphicx}
8
\usepackage{float}
9
\usepackage{booktabs}
10
\usepackage{hyperref}
11
\usepackage{xcolor}
12
\usepackage{pythontex}
13
\usepackage[margin=1in]{geometry}
14
15
% Custom commands
16
\newcommand{\dd}{\mathrm{d}}
17
\newcommand{\ee}{\mathrm{e}}
18
\newcommand{\pd}[2]{\frac{\partial #1}{\partial #2}}
19
20
% Document metadata
21
\title{Earth's Energy Balance Model:\\Climate Sensitivity and Radiative Forcing}
22
\author{Computational Climate Science}
23
\date{\today}
24
25
\begin{document}
26
27
\maketitle
28
29
\begin{abstract}
30
This document develops the fundamental physics of Earth's energy balance, from the Stefan-Boltzmann law governing planetary radiation to the greenhouse effect and climate sensitivity. We derive the zero-dimensional energy balance model, calculate equilibrium temperatures with and without an atmosphere, and explore how changes in radiative forcing translate to temperature changes. The analysis includes numerical solutions of the time-dependent energy balance equation, demonstrating the transient response to perturbations such as increased CO$_2$ concentrations.
31
\end{abstract}
32
33
\tableofcontents
34
\newpage
35
36
%------------------------------------------------------------------------------
37
\section{Introduction: Earth as a Radiating Body}
38
%------------------------------------------------------------------------------
39
40
Earth receives energy from the Sun and radiates energy back to space. At equilibrium, these two energy flows must balance. Understanding this balance is fundamental to climate science, as any imbalance leads to warming or cooling of the planet.
41
42
The key physical principles governing Earth's energy balance are:
43
\begin{enumerate}
44
\item \textbf{Solar irradiance}: The Sun provides approximately $S_0 = 1361$ W/m$^2$ at Earth's orbital distance (the solar constant).
45
\item \textbf{Planetary albedo}: Earth reflects about 30\% of incoming sunlight back to space ($\alpha \approx 0.30$).
46
\item \textbf{Stefan-Boltzmann radiation}: Earth radiates energy according to the Stefan-Boltzmann law $F = \sigma T^4$.
47
\item \textbf{Greenhouse effect}: The atmosphere absorbs and re-emits longwave radiation, warming the surface.
48
\end{enumerate}
49
50
\begin{pycode}
51
import numpy as np
52
import matplotlib.pyplot as plt
53
from matplotlib.patches import Circle, FancyArrowPatch, Rectangle
54
from scipy.integrate import odeint
55
from scipy.optimize import brentq
56
57
# Physical constants
58
sigma = 5.67e-8 # Stefan-Boltzmann constant [W/m^2/K^4]
59
S0 = 1361 # Solar constant [W/m^2]
60
alpha = 0.30 # Earth's average albedo
61
62
# Style configuration
63
plt.rcParams['figure.figsize'] = (10, 6)
64
plt.rcParams['font.size'] = 11
65
plt.rcParams['axes.labelsize'] = 12
66
plt.rcParams['axes.titlesize'] = 14
67
\end{pycode}
68
69
%------------------------------------------------------------------------------
70
\section{The Stefan-Boltzmann Law and Blackbody Radiation}
71
%------------------------------------------------------------------------------
72
73
All objects with temperature $T > 0$ emit electromagnetic radiation. For a perfect blackbody, the total power radiated per unit area is given by the Stefan-Boltzmann law:
74
75
\begin{equation}
76
F = \sigma T^4
77
\label{eq:stefan-boltzmann}
78
\end{equation}
79
80
where $\sigma = 5.67 \times 10^{-8}$ W/m$^2$/K$^4$ is the Stefan-Boltzmann constant. This $T^4$ dependence is crucial---small temperature changes produce significant changes in radiated power.
81
82
\begin{pycode}
83
# Stefan-Boltzmann demonstration
84
T_range = np.linspace(200, 350, 100) # Temperature range [K]
85
F_range = sigma * T_range**4
86
87
# Key temperatures
88
T_earth_no_atm = 255 # Earth without atmosphere [K]
89
T_earth_with_atm = 288 # Earth with atmosphere [K]
90
T_sun_surface = 5778 # Sun's surface [K]
91
92
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
93
94
# Left plot: Stefan-Boltzmann curve
95
ax = axes[0]
96
ax.plot(T_range, F_range, 'b-', linewidth=2, label=r'$F = \sigma T^4$')
97
ax.axvline(T_earth_no_atm, color='orange', linestyle='--', alpha=0.7,
98
label=f'Earth (no atm): {T_earth_no_atm} K')
99
ax.axvline(T_earth_with_atm, color='red', linestyle='--', alpha=0.7,
100
label=f'Earth (with atm): {T_earth_with_atm} K')
101
102
ax.fill_between(T_range, 0, F_range, alpha=0.2, color='blue')
103
ax.set_xlabel('Temperature [K]')
104
ax.set_ylabel('Radiated Power [W/m$^2$]')
105
ax.set_title('Stefan-Boltzmann Law')
106
ax.legend(loc='upper left')
107
ax.grid(True, alpha=0.3)
108
ax.set_xlim(200, 350)
109
ax.set_ylim(0, 900)
110
111
# Right plot: Log-log showing T^4 behavior
112
ax = axes[1]
113
T_log = np.logspace(1.5, 4, 100) # 30 K to 10000 K
114
F_log = sigma * T_log**4
115
116
ax.loglog(T_log, F_log, 'b-', linewidth=2)
117
ax.axvline(T_earth_with_atm, color='red', linestyle='--', alpha=0.7)
118
ax.axvline(T_sun_surface, color='orange', linestyle='--', alpha=0.7)
119
120
ax.annotate('Earth\n288 K', xy=(T_earth_with_atm, sigma*T_earth_with_atm**4),
121
xytext=(100, sigma*T_earth_with_atm**4),
122
arrowprops=dict(arrowstyle='->', color='red'),
123
fontsize=10, color='red')
124
ax.annotate('Sun\n5778 K', xy=(T_sun_surface, sigma*T_sun_surface**4),
125
xytext=(8000, sigma*T_sun_surface**4/5),
126
arrowprops=dict(arrowstyle='->', color='orange'),
127
fontsize=10, color='orange')
128
129
ax.set_xlabel('Temperature [K]')
130
ax.set_ylabel('Radiated Power [W/m$^2$]')
131
ax.set_title('Stefan-Boltzmann Law (Log Scale)')
132
ax.grid(True, alpha=0.3, which='both')
133
134
plt.tight_layout()
135
plt.savefig('energy_balance_stefan_boltzmann.pdf', bbox_inches='tight')
136
plt.close()
137
\end{pycode}
138
139
\begin{figure}[H]
140
\centering
141
\includegraphics[width=\textwidth]{energy_balance_stefan_boltzmann.pdf}
142
\caption{The Stefan-Boltzmann law relates temperature to radiated power through a fourth-power relationship. Left: Linear scale showing the rapid increase in radiated power with temperature. Earth's surface temperature (288 K) radiates significantly more than it would without an atmosphere (255 K). Right: Log-log scale reveals the four orders of magnitude difference between Earth's surface radiation and the Sun's, despite the Sun being only about 20 times hotter.}
143
\label{fig:stefan-boltzmann}
144
\end{figure}
145
146
%------------------------------------------------------------------------------
147
\section{Zero-Dimensional Energy Balance Model}
148
%------------------------------------------------------------------------------
149
150
The simplest climate model treats Earth as a uniform sphere receiving solar radiation and emitting thermal radiation. At equilibrium, incoming and outgoing energy must balance.
151
152
\subsection{Incoming Solar Radiation}
153
154
The Sun intercepts Earth with a circular cross-section of area $\pi R_E^2$, where $R_E$ is Earth's radius. The total incoming solar power is:
155
156
\begin{equation}
157
P_{\text{in}} = S_0 \cdot \pi R_E^2 \cdot (1 - \alpha)
158
\end{equation}
159
160
where $(1-\alpha)$ accounts for the fraction absorbed (not reflected). Dividing by Earth's surface area $4\pi R_E^2$ gives the average absorbed flux:
161
162
\begin{equation}
163
F_{\text{in}} = \frac{S_0 (1 - \alpha)}{4} \approx 238 \text{ W/m}^2
164
\label{eq:incoming}
165
\end{equation}
166
167
The factor of 4 arises because the sphere's surface area is 4 times its cross-sectional area.
168
169
\subsection{Outgoing Thermal Radiation}
170
171
Earth radiates from its entire surface according to the Stefan-Boltzmann law. For an effective emission temperature $T_e$:
172
173
\begin{equation}
174
F_{\text{out}} = \sigma T_e^4
175
\label{eq:outgoing}
176
\end{equation}
177
178
\subsection{Equilibrium Temperature Without Atmosphere}
179
180
Setting $F_{\text{in}} = F_{\text{out}}$ and solving for temperature:
181
182
\begin{equation}
183
T_e = \left(\frac{S_0 (1 - \alpha)}{4\sigma}\right)^{1/4}
184
\label{eq:equilibrium}
185
\end{equation}
186
187
\begin{pycode}
188
# Calculate equilibrium temperature without atmosphere
189
T_equilibrium = ((S0 * (1 - alpha)) / (4 * sigma))**0.25
190
F_absorbed = S0 * (1 - alpha) / 4
191
192
print(r'\begin{equation*}')
193
print(f'T_e = \\left(\\frac{{{S0:.0f} \\times (1 - {alpha:.2f})}}{{4 \\times {sigma:.2e}}}\\right)^{{1/4}} = {T_equilibrium:.1f} \\text{{ K}} = {T_equilibrium - 273.15:.1f}^\\circ\\text{{C}}')
194
print(r'\end{equation*}')
195
\end{pycode}
196
197
This is 33 K (33$^\circ$C) colder than Earth's actual average surface temperature of approximately 288 K (15$^\circ$C). The difference is due to the greenhouse effect.
198
199
%------------------------------------------------------------------------------
200
\section{The Greenhouse Effect}
201
%------------------------------------------------------------------------------
202
203
The atmosphere is largely transparent to incoming shortwave solar radiation but absorbs and re-emits outgoing longwave (infrared) radiation. Greenhouse gases---primarily H$_2$O, CO$_2$, CH$_4$, N$_2$O, and O$_3$---are responsible for this absorption.
204
205
\subsection{Single-Layer Atmosphere Model}
206
207
Consider a simplified model with a single atmospheric layer at temperature $T_a$ that is:
208
\begin{itemize}
209
\item Transparent to solar radiation
210
\item Perfectly absorbing (emissivity $\epsilon = 1$) for infrared radiation
211
\end{itemize}
212
213
The atmospheric layer radiates both upward (to space) and downward (to the surface). At equilibrium:
214
215
\textbf{Atmosphere energy balance:}
216
\begin{equation}
217
\sigma T_s^4 = 2\sigma T_a^4
218
\end{equation}
219
220
The atmosphere absorbs surface radiation and emits equally up and down.
221
222
\textbf{Surface energy balance:}
223
\begin{equation}
224
F_{\text{in}} + \sigma T_a^4 = \sigma T_s^4
225
\end{equation}
226
227
The surface receives both solar radiation and downwelling radiation from the atmosphere.
228
229
Solving these equations:
230
231
\begin{equation}
232
T_a = T_e \quad \text{and} \quad T_s = 2^{1/4} T_e \approx 1.19 T_e
233
\end{equation}
234
235
\begin{pycode}
236
# Single layer atmosphere model
237
T_surface_1layer = 2**0.25 * T_equilibrium
238
T_atmosphere = T_equilibrium
239
240
print(f'With a single-layer atmosphere:')
241
print(f' - Atmospheric temperature: $T_a = {T_atmosphere:.1f}$ K')
242
print(f' - Surface temperature: $T_s = {T_surface_1layer:.1f}$ K = ${T_surface_1layer - 273.15:.1f}^\\circ$C')
243
print(f' - Greenhouse warming: ${T_surface_1layer - T_equilibrium:.1f}$ K')
244
\end{pycode}
245
246
\subsection{Multi-Layer Atmosphere Model}
247
248
With $n$ atmospheric layers, each transparent to solar but opaque to infrared:
249
250
\begin{equation}
251
T_s = (n+1)^{1/4} T_e
252
\end{equation}
253
254
\begin{pycode}
255
# Multi-layer atmosphere model
256
fig, ax = plt.subplots(figsize=(10, 6))
257
258
n_layers = np.arange(0, 6)
259
T_surface = (n_layers + 1)**0.25 * T_equilibrium
260
261
ax.bar(n_layers, T_surface - 273.15, color='coral', edgecolor='darkred', alpha=0.8)
262
ax.axhline(288 - 273.15, color='green', linestyle='--', linewidth=2,
263
label=f'Observed Earth: 15$^\\circ$C')
264
ax.axhline(T_equilibrium - 273.15, color='blue', linestyle='--', linewidth=2,
265
label=f'No atmosphere: {T_equilibrium - 273.15:.0f}$^\\circ$C')
266
267
ax.set_xlabel('Number of Atmospheric Layers')
268
ax.set_ylabel('Surface Temperature [$^\\circ$C]')
269
ax.set_title('Greenhouse Effect: Multi-Layer Atmosphere Model')
270
ax.legend()
271
ax.grid(True, alpha=0.3, axis='y')
272
ax.set_xticks(n_layers)
273
274
# Annotate
275
for i, (n, T) in enumerate(zip(n_layers, T_surface)):
276
ax.annotate(f'{T-273.15:.0f}$^\\circ$C',
277
xy=(n, T-273.15),
278
xytext=(0, 5),
279
textcoords='offset points',
280
ha='center', fontsize=10)
281
282
plt.tight_layout()
283
plt.savefig('energy_balance_greenhouse.pdf', bbox_inches='tight')
284
plt.close()
285
\end{pycode}
286
287
\begin{figure}[H]
288
\centering
289
\includegraphics[width=0.9\textwidth]{energy_balance_greenhouse.pdf}
290
\caption{Surface temperature as a function of the number of perfectly absorbing atmospheric layers. Each layer adds additional greenhouse warming by trapping outgoing infrared radiation. Earth's actual atmosphere behaves approximately like a 1-2 layer model, producing the observed 33 K of greenhouse warming. The simple model captures the essential physics: adding greenhouse gases (effectively adding partial ``layers'') increases surface temperature.}
291
\label{fig:greenhouse}
292
\end{figure}
293
294
%------------------------------------------------------------------------------
295
\section{Radiative Forcing and Climate Sensitivity}
296
%------------------------------------------------------------------------------
297
298
\subsection{Radiative Forcing}
299
300
Radiative forcing ($\Delta F$) measures the change in net radiative flux at the tropopause due to a perturbation (e.g., increased CO$_2$). For a doubling of CO$_2$:
301
302
\begin{equation}
303
\Delta F_{2\times\text{CO}_2} \approx 5.35 \ln\left(\frac{C}{C_0}\right) \approx 3.7 \text{ W/m}^2
304
\label{eq:forcing}
305
\end{equation}
306
307
where $C$ is the CO$_2$ concentration and $C_0$ is the reference concentration.
308
309
\subsection{Climate Sensitivity Parameter}
310
311
The climate sensitivity parameter $\lambda$ relates radiative forcing to equilibrium temperature change:
312
313
\begin{equation}
314
\Delta T = \lambda \Delta F
315
\label{eq:sensitivity}
316
\end{equation}
317
318
For a blackbody (no feedbacks), differentiating the Stefan-Boltzmann law:
319
320
\begin{equation}
321
\lambda_0 = \frac{\dd T}{\dd F} = \frac{1}{4\sigma T^3} \approx 0.27 \text{ K/(W/m}^2)
322
\end{equation}
323
324
This gives a temperature change of about 1.0 K for CO$_2$ doubling. However, feedbacks amplify this response.
325
326
\begin{pycode}
327
# Climate sensitivity analysis
328
T_ref = 288 # Reference temperature [K]
329
lambda_0 = 1 / (4 * sigma * T_ref**3) # No-feedback sensitivity
330
331
# Radiative forcing for CO2 doubling
332
Delta_F_2xCO2 = 5.35 * np.log(2)
333
334
# Temperature change without feedbacks
335
Delta_T_no_feedback = lambda_0 * Delta_F_2xCO2
336
337
# With feedbacks (IPCC range: 2.5-4.0 K for 2xCO2, central estimate ~3 K)
338
# This corresponds to lambda ~ 0.8-1.2 K/(W/m^2)
339
feedback_factors = np.array([1.0, 2.0, 2.5, 3.0, 3.5]) # Feedback amplification
340
lambda_values = lambda_0 * feedback_factors
341
Delta_T_values = lambda_values * Delta_F_2xCO2
342
343
# Create visualization
344
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
345
346
# Left: Radiative forcing vs CO2
347
ax = axes[0]
348
CO2_ratios = np.linspace(0.5, 4, 100)
349
Delta_F = 5.35 * np.log(CO2_ratios)
350
351
ax.plot(CO2_ratios * 280, Delta_F, 'b-', linewidth=2)
352
ax.axvline(560, color='red', linestyle='--', alpha=0.7, label='2x pre-industrial (560 ppm)')
353
ax.axvline(420, color='orange', linestyle='--', alpha=0.7, label='Current (~420 ppm)')
354
ax.axvline(280, color='green', linestyle='--', alpha=0.7, label='Pre-industrial (280 ppm)')
355
356
ax.set_xlabel('CO$_2$ Concentration [ppm]')
357
ax.set_ylabel('Radiative Forcing [W/m$^2$]')
358
ax.set_title('Radiative Forcing from CO$_2$')
359
ax.legend(loc='upper left')
360
ax.grid(True, alpha=0.3)
361
ax.set_xlim(140, 1120)
362
363
# Right: Temperature response
364
ax = axes[1]
365
bar_colors = ['lightblue', 'skyblue', 'steelblue', 'royalblue', 'navy']
366
bars = ax.bar(range(len(feedback_factors)), Delta_T_values,
367
color=bar_colors, edgecolor='black')
368
369
ax.set_xticks(range(len(feedback_factors)))
370
ax.set_xticklabels([f'{f:.1f}x' for f in feedback_factors])
371
ax.set_xlabel('Feedback Amplification Factor')
372
ax.set_ylabel('Temperature Change for 2xCO$_2$ [K]')
373
ax.set_title('Equilibrium Climate Sensitivity')
374
375
# IPCC likely range
376
ax.axhspan(2.5, 4.0, alpha=0.2, color='red', label='IPCC likely range')
377
ax.axhline(3.0, color='red', linestyle='--', linewidth=2, label='Best estimate: 3 K')
378
ax.legend(loc='upper left')
379
ax.grid(True, alpha=0.3, axis='y')
380
381
for i, dT in enumerate(Delta_T_values):
382
ax.annotate(f'{dT:.1f} K', xy=(i, dT), xytext=(0, 5),
383
textcoords='offset points', ha='center', fontsize=10)
384
385
plt.tight_layout()
386
plt.savefig('energy_balance_sensitivity.pdf', bbox_inches='tight')
387
plt.close()
388
\end{pycode}
389
390
\begin{figure}[H]
391
\centering
392
\includegraphics[width=\textwidth]{energy_balance_sensitivity.pdf}
393
\caption{Left: Radiative forcing increases logarithmically with CO$_2$ concentration. The logarithmic relationship means that each doubling adds the same forcing (~3.7 W/m$^2$). Right: Equilibrium temperature change depends strongly on feedback processes. Without feedbacks (1.0x), CO$_2$ doubling causes ~1 K warming. With realistic feedbacks (water vapor, ice-albedo, clouds), the response is amplified to 2.5-4.0 K (IPCC likely range). The central estimate of 3 K corresponds to a feedback amplification of about 2.8x.}
394
\label{fig:sensitivity}
395
\end{figure}
396
397
%------------------------------------------------------------------------------
398
\section{Time-Dependent Energy Balance}
399
%------------------------------------------------------------------------------
400
401
The equilibrium analysis assumes instantaneous adjustment, but in reality, Earth's climate system has thermal inertia due to the ocean's heat capacity. The time-dependent energy balance equation is:
402
403
\begin{equation}
404
C \frac{\dd T}{\dd t} = F_{\text{in}} - F_{\text{out}} = \frac{S_0(1-\alpha)}{4} - \sigma T^4 + \Delta F
405
\label{eq:time-dependent}
406
\end{equation}
407
408
where $C$ is the effective heat capacity [J/m$^2$/K] and $\Delta F$ is any additional forcing.
409
410
\subsection{Linearized Response}
411
412
Near equilibrium temperature $T_0$, we can linearize:
413
414
\begin{equation}
415
C \frac{\dd(\Delta T)}{\dd t} = \Delta F - \frac{\Delta T}{\lambda}
416
\end{equation}
417
418
This gives an exponential approach to equilibrium with time constant:
419
420
\begin{equation}
421
\tau = C \lambda
422
\end{equation}
423
424
For the ocean mixed layer ($C \approx 4 \times 10^8$ J/m$^2$/K) and $\lambda \approx 1$ K/(W/m$^2$):
425
426
\begin{equation}
427
\tau \approx 4 \times 10^8 \text{ s} \approx 13 \text{ years}
428
\end{equation}
429
430
\begin{pycode}
431
# Time-dependent energy balance model
432
def energy_balance_ode(T, t, C, S0, alpha, sigma, Delta_F_func):
433
"""
434
Time derivative of temperature for the energy balance model.
435
436
Parameters:
437
-----------
438
T : float
439
Current temperature [K]
440
t : float
441
Time [years]
442
C : float
443
Heat capacity [J/m^2/K]
444
Delta_F_func : callable
445
Function returning radiative forcing at time t
446
"""
447
F_in = S0 * (1 - alpha) / 4
448
F_out = sigma * T**4
449
Delta_F = Delta_F_func(t)
450
451
dTdt = (F_in - F_out + Delta_F) / C
452
return dTdt * 3.154e7 # Convert from K/s to K/year
453
454
# Model parameters
455
C_mixed_layer = 4e8 # Ocean mixed layer heat capacity [J/m^2/K]
456
C_deep_ocean = 20e8 # Deep ocean heat capacity [J/m^2/K]
457
458
# Forcing scenarios
459
def step_forcing(t, t_start=10, magnitude=3.7):
460
"""Step increase in forcing (like sudden CO2 doubling)"""
461
return magnitude if t >= t_start else 0
462
463
def ramp_forcing(t, t_start=10, rate=0.037):
464
"""Linear increase in forcing (like gradual CO2 rise)"""
465
return max(0, rate * (t - t_start))
466
467
# Time array
468
t_span = np.linspace(0, 200, 1000)
469
T0 = T_equilibrium # Start at no-atmosphere equilibrium
470
471
# Solve for different scenarios
472
scenarios = {
473
'Step forcing (mixed layer)': (C_mixed_layer, lambda t: step_forcing(t)),
474
'Step forcing (deep ocean)': (C_deep_ocean, lambda t: step_forcing(t)),
475
'Ramp forcing (1%/year)': (C_mixed_layer, lambda t: ramp_forcing(t, rate=0.037)),
476
}
477
478
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
479
480
# Left: Temperature response
481
ax = axes[0]
482
colors = ['blue', 'red', 'green']
483
for (name, (C, forcing)), color in zip(scenarios.items(), colors):
484
solution = odeint(energy_balance_ode, T0, t_span,
485
args=(C, S0, alpha, sigma, forcing))
486
# Calculate Delta T relative to equilibrium
487
T_eq_new = ((S0*(1-alpha)/4 + 3.7) / sigma)**0.25 if 'Step' in name else None
488
ax.plot(t_span, solution[:, 0], color=color, linewidth=2, label=name)
489
490
ax.axhline(T_equilibrium, color='gray', linestyle=':', alpha=0.7)
491
ax.axvline(10, color='gray', linestyle='--', alpha=0.5)
492
493
ax.set_xlabel('Time [years]')
494
ax.set_ylabel('Temperature [K]')
495
ax.set_title('Temperature Response to Forcing')
496
ax.legend(loc='lower right')
497
ax.grid(True, alpha=0.3)
498
ax.set_xlim(0, 200)
499
500
# Right: Energy imbalance
501
ax = axes[1]
502
for (name, (C, forcing)), color in zip(scenarios.items(), colors):
503
solution = odeint(energy_balance_ode, T0, t_span,
504
args=(C, S0, alpha, sigma, forcing))
505
# Calculate energy imbalance
506
imbalance = []
507
for i, t in enumerate(t_span):
508
T = solution[i, 0]
509
F_in = S0 * (1 - alpha) / 4
510
F_out = sigma * T**4
511
Delta_F = forcing(t)
512
imbalance.append(F_in - F_out + Delta_F)
513
ax.plot(t_span, imbalance, color=color, linewidth=2, label=name)
514
515
ax.axhline(0, color='gray', linestyle=':', alpha=0.7)
516
ax.axvline(10, color='gray', linestyle='--', alpha=0.5)
517
518
ax.set_xlabel('Time [years]')
519
ax.set_ylabel('Energy Imbalance [W/m$^2$]')
520
ax.set_title('Top-of-Atmosphere Energy Imbalance')
521
ax.legend(loc='upper right')
522
ax.grid(True, alpha=0.3)
523
ax.set_xlim(0, 200)
524
525
plt.tight_layout()
526
plt.savefig('energy_balance_transient.pdf', bbox_inches='tight')
527
plt.close()
528
\end{pycode}
529
530
\begin{figure}[H]
531
\centering
532
\includegraphics[width=\textwidth]{energy_balance_transient.pdf}
533
\caption{Transient response of the climate system to radiative forcing, solved using the time-dependent energy balance equation. Left: Temperature evolution after forcing begins at year 10. The mixed layer response ($\tau \approx 13$ years) is faster than the deep ocean response ($\tau \approx 65$ years). A gradual ramp forcing produces continuous warming. Right: The top-of-atmosphere energy imbalance---positive values indicate the planet is absorbing more energy than it radiates, driving warming. The imbalance gradually decreases as temperature rises and outgoing radiation increases.}
534
\label{fig:transient}
535
\end{figure}
536
537
%------------------------------------------------------------------------------
538
\section{Feedback Mechanisms}
539
%------------------------------------------------------------------------------
540
541
Climate feedbacks amplify or dampen the initial temperature response. The main feedbacks are:
542
543
\subsection{Water Vapor Feedback (Positive)}
544
545
As temperature increases, more water evaporates, and since water vapor is a greenhouse gas, this amplifies warming:
546
547
\begin{equation}
548
f_{\text{WV}} = \frac{\dd \ln(e_s)}{\dd T} \approx 0.07 \text{ K}^{-1}
549
\end{equation}
550
551
where $e_s$ is the saturation vapor pressure (Clausius-Clapeyron relation).
552
553
\subsection{Ice-Albedo Feedback (Positive)}
554
555
Warming melts ice and snow, which are highly reflective. The exposed ocean or land absorbs more sunlight:
556
557
\begin{equation}
558
f_{\text{ice}} = -\frac{\partial \alpha}{\partial T} \cdot \frac{S_0}{4\sigma T^3}
559
\end{equation}
560
561
\subsection{Planck Feedback (Negative)}
562
563
This is the fundamental stabilizing feedback: as Earth warms, it radiates more energy to space:
564
565
\begin{equation}
566
f_{\text{Planck}} = -4\sigma T^3 \approx -3.2 \text{ W/m}^2/\text{K}
567
\end{equation}
568
569
\begin{pycode}
570
# Feedback visualization
571
fig, ax = plt.subplots(figsize=(10, 6))
572
573
# Feedback contributions (approximate values from IPCC AR6)
574
feedbacks = {
575
'Planck': -3.2,
576
'Water Vapor': 1.8,
577
'Lapse Rate': -0.6,
578
'Ice-Albedo': 0.4,
579
'Cloud (net)': 0.5,
580
}
581
582
names = list(feedbacks.keys())
583
values = list(feedbacks.values())
584
colors = ['green' if v < 0 else 'red' for v in values]
585
586
bars = ax.barh(names, values, color=colors, alpha=0.7, edgecolor='black')
587
ax.axvline(0, color='black', linewidth=1)
588
589
# Net feedback
590
net_feedback = sum(values)
591
ax.axvline(net_feedback, color='purple', linestyle='--', linewidth=2)
592
ax.annotate(f'Net: {net_feedback:.1f}', xy=(net_feedback, -0.5), fontsize=12, color='purple')
593
594
ax.set_xlabel('Feedback Strength [W/m$^2$/K]')
595
ax.set_title('Climate Feedback Contributions')
596
ax.grid(True, alpha=0.3, axis='x')
597
598
# Add legend
599
from matplotlib.patches import Patch
600
legend_elements = [
601
Patch(facecolor='green', alpha=0.7, edgecolor='black', label='Stabilizing (negative)'),
602
Patch(facecolor='red', alpha=0.7, edgecolor='black', label='Amplifying (positive)')
603
]
604
ax.legend(handles=legend_elements, loc='lower right')
605
606
plt.tight_layout()
607
plt.savefig('energy_balance_feedbacks.pdf', bbox_inches='tight')
608
plt.close()
609
610
# Calculate amplification factor
611
lambda_0_value = 1 / 3.2 # No-feedback sensitivity [K/(W/m^2)]
612
lambda_net = 1 / (-net_feedback) # Net sensitivity
613
amplification = lambda_net / lambda_0_value
614
615
print(f'\\noindent Feedback analysis:')
616
print(f'\\begin{{itemize}}')
617
print(f'\\item No-feedback sensitivity: $\\lambda_0 = {lambda_0_value:.2f}$ K/(W/m$^2$)')
618
print(f'\\item Net feedback: ${net_feedback:.1f}$ W/m$^2$/K')
619
print(f'\\item Net sensitivity: $\\lambda = {lambda_net:.2f}$ K/(W/m$^2$)')
620
print(f'\\item Amplification factor: ${amplification:.1f}\\times$')
621
print(f'\\end{{itemize}}')
622
\end{pycode}
623
624
\begin{figure}[H]
625
\centering
626
\includegraphics[width=0.9\textwidth]{energy_balance_feedbacks.pdf}
627
\caption{Climate feedback contributions based on IPCC AR6 estimates. The Planck feedback is the fundamental negative feedback that stabilizes climate. Water vapor provides the strongest positive feedback through the greenhouse effect. The lapse rate feedback is negative because warming increases the rate of temperature decrease with altitude. Ice-albedo and cloud feedbacks are both positive on average. The net feedback (purple line) is negative, meaning the climate is stable, but the positive feedbacks amplify the initial response by roughly a factor of 3.}
628
\label{fig:feedbacks}
629
\end{figure}
630
631
%------------------------------------------------------------------------------
632
\section{Conclusions}
633
%------------------------------------------------------------------------------
634
635
This analysis has developed the fundamental physics of Earth's energy balance:
636
637
\begin{enumerate}
638
\item \textbf{Equilibrium temperature}: Without an atmosphere, Earth's equilibrium temperature would be \pyc{print(f'{T_equilibrium:.1f}')} K (\pyc{print(f'{T_equilibrium - 273.15:.1f}')}$^\circ$C), about 33 K colder than observed.
639
640
\item \textbf{Greenhouse effect}: The atmosphere acts like multiple absorbing layers, raising surface temperature to the observed \pyc{print(f'{288:.0f}')} K through absorption and re-emission of infrared radiation.
641
642
\item \textbf{Climate sensitivity}: A doubling of CO$_2$ produces \pyc{print(f'{Delta_F_2xCO2:.1f}')} W/m$^2$ of radiative forcing. With feedbacks, this translates to 2.5--4.0 K of warming.
643
644
\item \textbf{Thermal inertia}: The ocean's heat capacity delays the climate response, with adjustment timescales of decades to centuries depending on depth.
645
646
\item \textbf{Feedback amplification}: Positive feedbacks (water vapor, ice-albedo, clouds) amplify the initial response by a factor of approximately \pyc{print(f'{amplification:.1f}')}.
647
\end{enumerate}
648
649
The zero-dimensional model captures the essential physics while remaining tractable. More sophisticated models incorporate spatial variations, seasonal cycles, and coupled atmosphere-ocean dynamics, but the fundamental energy balance constraints remain.
650
651
%------------------------------------------------------------------------------
652
\section{References}
653
%------------------------------------------------------------------------------
654
655
\begin{enumerate}
656
\item Hartmann, D.L. (2016). \textit{Global Physical Climatology}, 2nd ed. Academic Press.
657
658
\item Pierrehumbert, R.T. (2010). \textit{Principles of Planetary Climate}. Cambridge University Press.
659
660
\item IPCC (2021). Climate Change 2021: The Physical Science Basis. Cambridge University Press.
661
662
\item Kiehl, J.T. \& Trenberth, K.E. (1997). Earth's Annual Global Mean Energy Budget. \textit{Bulletin of the American Meteorological Society}, 78(2), 197-208.
663
664
\item Roe, G. (2009). Feedbacks, Timescales, and Seeing Red. \textit{Annual Review of Earth and Planetary Sciences}, 37, 93-115.
665
666
\item Sherwood, S.C. et al. (2020). An Assessment of Earth's Climate Sensitivity Using Multiple Lines of Evidence. \textit{Reviews of Geophysics}, 58, e2019RG000678.
667
\end{enumerate}
668
669
\end{document}
670
671