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/carbon_cycle.tex
51 views
unlisted
1
% Carbon Cycle Model Template
2
% Topics: Box models, carbon reservoirs, anthropogenic perturbation, feedback loops
3
% Style: Technical report with policy implications
4
5
\documentclass[a4paper, 11pt]{article}
6
\usepackage[utf8]{inputenc}
7
\usepackage[T1]{fontenc}
8
\usepackage{amsmath, amssymb}
9
\usepackage{graphicx}
10
\usepackage{siunitx}
11
\usepackage{booktabs}
12
\usepackage{subcaption}
13
\usepackage[makestderr]{pythontex}
14
15
% Theorem environments
16
\newtheorem{definition}{Definition}[section]
17
\newtheorem{theorem}{Theorem}[section]
18
\newtheorem{example}{Example}[section]
19
\newtheorem{remark}{Remark}[section]
20
21
\title{Global Carbon Cycle Modeling: Reservoirs, Fluxes, and Anthropogenic Perturbation}
22
\author{Earth System Science Research}
23
\date{\today}
24
25
\begin{document}
26
\maketitle
27
28
\begin{abstract}
29
This technical report presents a comprehensive analysis of the global carbon cycle using
30
box models to represent carbon exchange between atmosphere, ocean, and terrestrial biosphere.
31
We examine natural carbon fluxes, anthropogenic emissions, and the resulting changes in
32
atmospheric CO$_2$ concentration. The model explores the airborne fraction of emissions,
33
ocean uptake dynamics, and climate-carbon feedbacks. Projections under different emission
34
scenarios illustrate the long-term implications for atmospheric carbon levels.
35
\end{abstract}
36
37
\section{Introduction}
38
39
The global carbon cycle plays a central role in Earth's climate system. Anthropogenic
40
emissions have perturbed this cycle, leading to rising atmospheric CO$_2$ concentrations
41
and associated climate change.
42
43
\begin{definition}[Carbon Reservoirs]
44
The major carbon reservoirs are:
45
\begin{itemize}
46
\item \textbf{Atmosphere}: $\sim$850 PgC (pre-industrial: 590 PgC)
47
\item \textbf{Ocean}: $\sim$38,000 PgC (surface + deep)
48
\item \textbf{Terrestrial biosphere}: $\sim$2,000 PgC (vegetation + soil)
49
\item \textbf{Fossil fuels}: $\sim$4,000 PgC
50
\end{itemize}
51
(1 PgC = $10^{15}$ g carbon = 1 GtC)
52
\end{definition}
53
54
\section{Theoretical Framework}
55
56
\subsection{Box Model Equations}
57
58
\begin{theorem}[Three-Box Carbon Cycle Model]
59
The evolution of carbon in atmosphere ($C_A$), surface ocean ($C_O$), and biosphere ($C_B$) is:
60
\begin{align}
61
\frac{dC_A}{dt} &= -k_{AO}(C_A - C_A^{eq}) - k_{AB}(C_A - C_A^{eq}) + E(t) \\
62
\frac{dC_O}{dt} &= k_{AO}(C_A - C_A^{eq}) - k_{OD}(C_O - C_O^{eq}) \\
63
\frac{dC_B}{dt} &= k_{AB}(C_A - C_A^{eq}) - k_{BR}C_B
64
\end{align}
65
where $k$ values are exchange coefficients and $E(t)$ is anthropogenic emission.
66
\end{theorem}
67
68
\subsection{CO$_2$ Concentration and Carbon Mass}
69
70
\begin{definition}[Conversion Factors]
71
Atmospheric CO$_2$ concentration (ppm) relates to carbon mass (PgC):
72
\begin{equation}
73
C_A \text{ (PgC)} = \frac{\text{CO}_2 \text{ (ppm)}}{2.13}
74
\end{equation}
75
Thus 1 ppm CO$_2 \approx 2.13$ PgC.
76
\end{definition}
77
78
\subsection{Airborne Fraction}
79
80
\begin{definition}[Airborne Fraction]
81
The fraction of anthropogenic emissions remaining in the atmosphere:
82
\begin{equation}
83
f_{airborne} = \frac{\Delta C_A}{\sum E(t)}
84
\end{equation}
85
Currently $f_{airborne} \approx 0.44$ (the ocean and biosphere absorb $\sim$56\%).
86
\end{definition}
87
88
\begin{remark}[Ocean Chemistry]
89
Ocean CO$_2$ uptake is limited by the Revelle factor:
90
\begin{equation}
91
R = \frac{\Delta[\text{CO}_2]/[\text{CO}_2]}{\Delta\text{DIC}/\text{DIC}} \approx 10
92
\end{equation}
93
Only 1/R of absorbed CO$_2$ remains as dissolved CO$_2$; the rest converts to bicarbonate.
94
\end{remark}
95
96
\section{Computational Analysis}
97
98
\begin{pycode}
99
import numpy as np
100
import matplotlib.pyplot as plt
101
from scipy.integrate import odeint
102
103
np.random.seed(42)
104
105
# Carbon cycle box model
106
def carbon_cycle(y, t, params, emission_func):
107
C_A, C_O, C_B = y
108
k_AO, k_AB, k_OD, k_BR, C_A_eq, C_O_eq = params
109
110
E = emission_func(t)
111
112
dC_A = -k_AO * (C_A - C_A_eq) - k_AB * (C_A - C_A_eq) + E
113
dC_O = k_AO * (C_A - C_A_eq) - k_OD * (C_O - C_O_eq)
114
dC_B = k_AB * (C_A - C_A_eq) - k_BR * C_B
115
116
return [dC_A, dC_O, dC_B]
117
118
# Parameters (based on simplified IPCC values)
119
k_AO = 0.1 # Atmosphere-ocean exchange (1/yr)
120
k_AB = 0.05 # Atmosphere-biosphere exchange (1/yr)
121
k_OD = 0.01 # Surface-deep ocean exchange (1/yr)
122
k_BR = 0.02 # Biosphere respiration (1/yr)
123
C_A_eq = 590 # Pre-industrial atmospheric C (PgC)
124
C_O_eq = 1000 # Surface ocean equilibrium (PgC)
125
params = (k_AO, k_AB, k_OD, k_BR, C_A_eq, C_O_eq)
126
127
# Initial conditions (year 1850)
128
C_A_0 = 590 # PgC
129
C_O_0 = 1000 # PgC
130
C_B_0 = 550 # PgC
131
y0 = [C_A_0, C_O_0, C_B_0]
132
133
# Emission scenarios
134
def emissions_historical(t):
135
# Simplified historical emissions (PgC/yr)
136
if t < 1900:
137
return 0.5 * np.exp(0.02 * (t - 1850))
138
elif t < 2000:
139
return 1.0 * np.exp(0.025 * (t - 1900))
140
else:
141
return 10.0
142
143
def emissions_rcp26(t):
144
# RCP 2.6 - aggressive mitigation
145
if t < 2020:
146
return emissions_historical(t)
147
elif t < 2050:
148
return 10.0 * (1 - 0.8 * (t - 2020) / 30)
149
else:
150
return 2.0 * np.exp(-0.05 * (t - 2050))
151
152
def emissions_rcp45(t):
153
# RCP 4.5 - moderate mitigation
154
if t < 2040:
155
return emissions_historical(t) if t < 2020 else 10.0 + 0.05 * (t - 2020)
156
elif t < 2080:
157
return 11.0 - 0.2 * (t - 2040)
158
else:
159
return 3.0
160
161
def emissions_rcp85(t):
162
# RCP 8.5 - business as usual
163
if t < 2020:
164
return emissions_historical(t)
165
else:
166
return 10.0 * np.exp(0.01 * (t - 2020))
167
168
# Time arrays
169
t_hist = np.linspace(1850, 2020, 171)
170
t_proj = np.linspace(2020, 2100, 81)
171
t_full = np.linspace(1850, 2100, 251)
172
173
# Solve for historical period
174
sol_hist = odeint(carbon_cycle, y0, t_hist, args=(params, emissions_historical))
175
176
# Solve for different scenarios
177
y0_2020 = sol_hist[-1]
178
sol_rcp26 = odeint(carbon_cycle, y0_2020, t_proj, args=(params, emissions_rcp26))
179
sol_rcp45 = odeint(carbon_cycle, y0_2020, t_proj, args=(params, emissions_rcp45))
180
sol_rcp85 = odeint(carbon_cycle, y0_2020, t_proj, args=(params, emissions_rcp85))
181
182
# Convert to CO2 concentration (ppm)
183
ppm_conversion = 2.13
184
CO2_hist = sol_hist[:, 0] / ppm_conversion
185
CO2_rcp26 = sol_rcp26[:, 0] / ppm_conversion
186
CO2_rcp45 = sol_rcp45[:, 0] / ppm_conversion
187
CO2_rcp85 = sol_rcp85[:, 0] / ppm_conversion
188
189
# Calculate cumulative emissions
190
cumulative_hist = np.cumsum([emissions_historical(t) for t in t_hist]) * (t_hist[1] - t_hist[0])
191
192
# Calculate airborne fraction
193
delta_C_A = sol_hist[-1, 0] - C_A_0
194
airborne_fraction = delta_C_A / cumulative_hist[-1]
195
196
# Ocean and land uptake
197
ocean_uptake = sol_hist[:, 1] - C_O_0
198
land_uptake = sol_hist[:, 2] - C_B_0
199
200
# Create annual emissions array
201
emissions_array_hist = np.array([emissions_historical(t) for t in t_hist])
202
emissions_rcp26_arr = np.array([emissions_rcp26(t) for t in t_proj])
203
emissions_rcp45_arr = np.array([emissions_rcp45(t) for t in t_proj])
204
emissions_rcp85_arr = np.array([emissions_rcp85(t) for t in t_proj])
205
206
# Create figure
207
fig = plt.figure(figsize=(14, 12))
208
209
# Plot 1: Historical CO2 concentration
210
ax1 = fig.add_subplot(3, 3, 1)
211
ax1.plot(t_hist, CO2_hist, 'b-', linewidth=2)
212
ax1.axhline(y=280, color='gray', linestyle='--', alpha=0.7, label='Pre-industrial')
213
ax1.set_xlabel('Year')
214
ax1.set_ylabel('CO$_2$ (ppm)')
215
ax1.set_title('Historical Atmospheric CO$_2$')
216
ax1.legend(fontsize=8)
217
218
# Plot 2: Emission scenarios
219
ax2 = fig.add_subplot(3, 3, 2)
220
ax2.plot(t_hist, emissions_array_hist, 'k-', linewidth=2, label='Historical')
221
ax2.plot(t_proj, emissions_rcp26_arr, 'g-', linewidth=2, label='RCP 2.6')
222
ax2.plot(t_proj, emissions_rcp45_arr, 'b-', linewidth=2, label='RCP 4.5')
223
ax2.plot(t_proj, emissions_rcp85_arr, 'r-', linewidth=2, label='RCP 8.5')
224
ax2.set_xlabel('Year')
225
ax2.set_ylabel('Emissions (PgC/yr)')
226
ax2.set_title('CO$_2$ Emission Scenarios')
227
ax2.legend(fontsize=8)
228
229
# Plot 3: Projected CO2 concentrations
230
ax3 = fig.add_subplot(3, 3, 3)
231
ax3.plot(t_hist, CO2_hist, 'k-', linewidth=2, label='Historical')
232
ax3.plot(t_proj, CO2_rcp26, 'g-', linewidth=2, label='RCP 2.6')
233
ax3.plot(t_proj, CO2_rcp45, 'b-', linewidth=2, label='RCP 4.5')
234
ax3.plot(t_proj, CO2_rcp85, 'r-', linewidth=2, label='RCP 8.5')
235
ax3.axhline(y=450, color='orange', linestyle=':', alpha=0.7)
236
ax3.set_xlabel('Year')
237
ax3.set_ylabel('CO$_2$ (ppm)')
238
ax3.set_title('Projected CO$_2$ Concentrations')
239
ax3.legend(fontsize=8)
240
241
# Plot 4: Carbon reservoir changes
242
ax4 = fig.add_subplot(3, 3, 4)
243
ax4.plot(t_hist, sol_hist[:, 0] - C_A_0, 'r-', linewidth=2, label='Atmosphere')
244
ax4.plot(t_hist, ocean_uptake, 'b-', linewidth=2, label='Ocean')
245
ax4.plot(t_hist, land_uptake, 'g-', linewidth=2, label='Land')
246
ax4.set_xlabel('Year')
247
ax4.set_ylabel('$\\Delta$C (PgC)')
248
ax4.set_title('Carbon Reservoir Changes')
249
ax4.legend(fontsize=8)
250
251
# Plot 5: Cumulative emissions and uptake
252
ax5 = fig.add_subplot(3, 3, 5)
253
ax5.fill_between(t_hist, 0, cumulative_hist, alpha=0.3, label='Total emissions')
254
ax5.plot(t_hist, sol_hist[:, 0] - C_A_0, 'r-', linewidth=2, label='Atmosphere')
255
ax5.set_xlabel('Year')
256
ax5.set_ylabel('Cumulative C (PgC)')
257
ax5.set_title(f'Airborne Fraction = {airborne_fraction:.2f}')
258
ax5.legend(fontsize=8)
259
260
# Plot 6: Sink efficiency over time
261
ax6 = fig.add_subplot(3, 3, 6)
262
cumsum = np.cumsum(emissions_array_hist)
263
atm_increase = sol_hist[:, 0] - C_A_0
264
cumsum[cumsum == 0] = 1 # Avoid division by zero
265
airborne_time = atm_increase / cumsum
266
ax6.plot(t_hist[10:], airborne_time[10:], 'purple', linewidth=2)
267
ax6.axhline(y=0.5, color='gray', linestyle='--', alpha=0.7)
268
ax6.set_xlabel('Year')
269
ax6.set_ylabel('Airborne fraction')
270
ax6.set_title('Sink Efficiency Over Time')
271
ax6.set_ylim([0.3, 0.7])
272
273
# Plot 7: CO2 growth rate
274
ax7 = fig.add_subplot(3, 3, 7)
275
growth_rate = np.diff(CO2_hist) / np.diff(t_hist)
276
ax7.plot(t_hist[1:], growth_rate, 'b-', linewidth=1.5)
277
ax7.set_xlabel('Year')
278
ax7.set_ylabel('CO$_2$ growth (ppm/yr)')
279
ax7.set_title('Atmospheric CO$_2$ Growth Rate')
280
281
# Plot 8: Temperature proxy (simplified)
282
ax8 = fig.add_subplot(3, 3, 8)
283
# Climate sensitivity ~3 K per doubling
284
ECS = 3.0 # K
285
dT_hist = ECS * np.log(CO2_hist / 280) / np.log(2)
286
dT_rcp26 = ECS * np.log(CO2_rcp26 / 280) / np.log(2)
287
dT_rcp45 = ECS * np.log(CO2_rcp45 / 280) / np.log(2)
288
dT_rcp85 = ECS * np.log(CO2_rcp85 / 280) / np.log(2)
289
ax8.plot(t_hist, dT_hist, 'k-', linewidth=2, label='Historical')
290
ax8.plot(t_proj, dT_rcp26, 'g-', linewidth=2, label='RCP 2.6')
291
ax8.plot(t_proj, dT_rcp45, 'b-', linewidth=2, label='RCP 4.5')
292
ax8.plot(t_proj, dT_rcp85, 'r-', linewidth=2, label='RCP 8.5')
293
ax8.axhline(y=1.5, color='orange', linestyle=':', label='1.5 K target')
294
ax8.axhline(y=2.0, color='red', linestyle=':', label='2.0 K limit')
295
ax8.set_xlabel('Year')
296
ax8.set_ylabel('$\\Delta T$ (K)')
297
ax8.set_title('Implied Temperature Change')
298
ax8.legend(fontsize=7)
299
300
# Plot 9: Carbon budget
301
ax9 = fig.add_subplot(3, 3, 9)
302
budget_15 = 420 # PgC remaining for 1.5 K
303
budget_20 = 1170 # PgC remaining for 2.0 K
304
emissions_cum_proj = np.cumsum(emissions_rcp45_arr) * (t_proj[1] - t_proj[0])
305
ax9.bar(['1.5 K', '2.0 K'], [budget_15, budget_20], color=['orange', 'red'], alpha=0.7)
306
ax9.axhline(y=emissions_cum_proj[-1], color='blue', linestyle='--',
307
label=f'RCP 4.5 emissions: {emissions_cum_proj[-1]:.0f} PgC')
308
ax9.set_ylabel('Carbon budget (PgC)')
309
ax9.set_title('Remaining Carbon Budget')
310
ax9.legend(fontsize=8)
311
312
plt.tight_layout()
313
plt.savefig('carbon_cycle_analysis.pdf', dpi=150, bbox_inches='tight')
314
plt.close()
315
316
# Final values
317
CO2_2020 = CO2_hist[-1]
318
CO2_2100_rcp26 = CO2_rcp26[-1]
319
CO2_2100_rcp85 = CO2_rcp85[-1]
320
\end{pycode}
321
322
\begin{figure}[htbp]
323
\centering
324
\includegraphics[width=\textwidth]{carbon_cycle_analysis.pdf}
325
\caption{Global carbon cycle analysis: (a) Historical CO$_2$ rise; (b) Emission scenarios;
326
(c) Projected CO$_2$ concentrations; (d) Carbon reservoir changes; (e) Cumulative emissions
327
and airborne fraction; (f) Sink efficiency evolution; (g) CO$_2$ growth rate; (h) Implied
328
temperature change; (i) Remaining carbon budget for climate targets.}
329
\label{fig:carbon}
330
\end{figure}
331
332
\section{Results}
333
334
\subsection{Model Parameters}
335
336
\begin{pycode}
337
print(r"\begin{table}[htbp]")
338
print(r"\centering")
339
print(r"\caption{Carbon Cycle Model Parameters}")
340
print(r"\begin{tabular}{lcc}")
341
print(r"\toprule")
342
print(r"Parameter & Value & Units \\")
343
print(r"\midrule")
344
print(f"Atmosphere-ocean exchange & {k_AO} & yr$^{{-1}}$ \\\\")
345
print(f"Atmosphere-biosphere exchange & {k_AB} & yr$^{{-1}}$ \\\\")
346
print(f"Surface-deep ocean exchange & {k_OD} & yr$^{{-1}}$ \\\\")
347
print(f"Biosphere respiration & {k_BR} & yr$^{{-1}}$ \\\\")
348
print(f"Pre-industrial CO$_2$ & {C_A_eq/ppm_conversion:.0f} & ppm \\\\")
349
print(r"\bottomrule")
350
print(r"\end{tabular}")
351
print(r"\label{tab:parameters}")
352
print(r"\end{table}")
353
\end{pycode}
354
355
\subsection{Scenario Projections}
356
357
\begin{pycode}
358
print(r"\begin{table}[htbp]")
359
print(r"\centering")
360
print(r"\caption{Projected CO$_2$ Concentrations in 2100}")
361
print(r"\begin{tabular}{lcc}")
362
print(r"\toprule")
363
print(r"Scenario & CO$_2$ (ppm) & $\Delta T$ (K) \\")
364
print(r"\midrule")
365
print(f"RCP 2.6 & {CO2_2100_rcp26:.0f} & {ECS * np.log(CO2_2100_rcp26/280)/np.log(2):.1f} \\\\")
366
print(f"RCP 4.5 & {CO2_rcp45[-1]:.0f} & {ECS * np.log(CO2_rcp45[-1]/280)/np.log(2):.1f} \\\\")
367
print(f"RCP 8.5 & {CO2_2100_rcp85:.0f} & {ECS * np.log(CO2_2100_rcp85/280)/np.log(2):.1f} \\\\")
368
print(r"\bottomrule")
369
print(r"\end{tabular}")
370
print(r"\label{tab:projections}")
371
print(r"\end{table}")
372
\end{pycode}
373
374
\section{Discussion}
375
376
\begin{example}[Airborne Fraction]
377
The airborne fraction of $\py{f"{airborne_fraction:.2f}"}$ means that about \py{f"{(1-airborne_fraction)*100:.0f}"}\%
378
of emitted carbon is absorbed by natural sinks. The ocean absorbs $\sim$25\% and the
379
land biosphere $\sim$30\%.
380
\end{example}
381
382
\begin{remark}[Climate-Carbon Feedbacks]
383
This simple model neglects important feedbacks:
384
\begin{itemize}
385
\item \textbf{Ocean warming}: Reduces CO$_2$ solubility
386
\item \textbf{Permafrost thaw}: Releases stored carbon
387
\item \textbf{Forest dieback}: Amazon could become a source
388
\item \textbf{Ocean acidification}: Reduces carbonate buffering
389
\end{itemize}
390
These feedbacks would increase the airborne fraction.
391
\end{remark}
392
393
\section{Conclusions}
394
395
This carbon cycle analysis demonstrates:
396
\begin{enumerate}
397
\item Current CO$_2$ concentration is $\sim$\py{f"{CO2_2020:.0f}"} ppm (2020)
398
\item Airborne fraction is $\py{f"{airborne_fraction:.2f}"}$
399
\item RCP 8.5 leads to $\sim$\py{f"{CO2_2100_rcp85:.0f}"} ppm by 2100
400
\item Only RCP 2.6 scenario keeps warming below 2 K
401
\item Carbon budget for 1.5 K target is rapidly depleting
402
\end{enumerate}
403
404
\section*{Further Reading}
405
406
\begin{itemize}
407
\item IPCC. \textit{Climate Change 2021: The Physical Science Basis}. Cambridge, 2021.
408
\item Archer, D. \textit{The Global Carbon Cycle}. Princeton University Press, 2010.
409
\item Sarmiento, J.L. \& Gruber, N. \textit{Ocean Biogeochemical Dynamics}. Princeton, 2006.
410
\end{itemize}
411
412
\end{document}
413
414