Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/geophysics/magnetic_field.tex
51 views
unlisted
1
\documentclass[a4paper, 11pt]{article}
2
\usepackage[utf8]{inputenc}
3
\usepackage[T1]{fontenc}
4
\usepackage{amsmath, amssymb, amsthm}
5
\usepackage{graphicx}
6
\usepackage{booktabs}
7
\usepackage{siunitx}
8
\usepackage{subcaption}
9
\usepackage[makestderr]{pythontex}
10
11
\newtheorem{definition}{Definition}
12
\newtheorem{theorem}{Theorem}
13
\newtheorem{example}{Example}
14
\newtheorem{remark}{Remark}
15
16
\title{Earth's Magnetic Field: Dipole Model, Secular Variation, and IGRF Analysis}
17
\author{Computational Geophysics Laboratory}
18
\date{\today}
19
20
\begin{document}
21
\maketitle
22
23
\begin{abstract}
24
This technical report presents comprehensive computational analysis of Earth's main magnetic field using the geocentric axial dipole model and spherical harmonic representations. We implement field component calculations (radial, meridional, total intensity, inclination, declination), model the International Geomagnetic Reference Field (IGRF), and analyze secular variation. Applications include navigation, paleomagnetic studies, and space weather prediction.
25
\end{abstract}
26
27
\section{Theoretical Framework}
28
29
\begin{definition}[Magnetic Scalar Potential]
30
In current-free regions, the geomagnetic field $\mathbf{B}$ can be derived from a scalar potential $V$:
31
\begin{equation}
32
\mathbf{B} = -\nabla V
33
\end{equation}
34
where $V$ satisfies Laplace's equation $\nabla^2 V = 0$.
35
\end{definition}
36
37
\begin{theorem}[Spherical Harmonic Expansion]
38
The geomagnetic potential can be expanded in spherical harmonics:
39
\begin{equation}
40
V(r, \theta, \phi) = a \sum_{n=1}^{N} \sum_{m=0}^{n} \left(\frac{a}{r}\right)^{n+1} [g_n^m \cos(m\phi) + h_n^m \sin(m\phi)] P_n^m(\cos\theta)
41
\end{equation}
42
where $a$ is Earth's radius, $g_n^m$ and $h_n^m$ are Gauss coefficients, and $P_n^m$ are Schmidt semi-normalized associated Legendre functions.
43
\end{theorem}
44
45
\subsection{Dipole Field Components}
46
47
For the centered dipole (n=1, m=0), the field components in spherical coordinates:
48
\begin{align}
49
B_r &= 2B_0 \left(\frac{a}{r}\right)^3 \cos\theta \\
50
B_\theta &= B_0 \left(\frac{a}{r}\right)^3 \sin\theta
51
\end{align}
52
53
where $B_0 \approx 31,000$ nT is the equatorial surface field.
54
55
\begin{example}[Inclination and Declination]
56
The magnetic inclination $I$ and declination $D$ are:
57
\begin{align}
58
\tan I &= \frac{-B_r}{B_H} = 2\cot\theta \quad \text{(dipole)} \\
59
\tan D &= \frac{B_\phi}{B_\theta}
60
\end{align}
61
The dipole equation $\tan I = 2\tan\lambda$ relates inclination to magnetic latitude.
62
\end{example}
63
64
\section{Computational Analysis}
65
66
\begin{pycode}
67
import numpy as np
68
import matplotlib.pyplot as plt
69
from scipy.special import lpmv
70
plt.rc('text', usetex=True)
71
plt.rc('font', family='serif', size=10)
72
73
# Physical constants
74
a = 6371.2e3 # Earth mean radius (m)
75
mu0 = 4 * np.pi * 1e-7 # Permeability of free space
76
77
# Dipole field parameters
78
B0 = 31000e-9 # Equatorial surface field (T)
79
g10 = -29404.8e-9 # Gauss coefficient g_1^0 (T) for 2020
80
g11 = -1450.9e-9 # g_1^1
81
h11 = 4652.5e-9 # h_1^1
82
83
# Dipole moment
84
m_dipole = 4 * np.pi * a**3 * abs(g10) / mu0 # A*m^2
85
86
# Dipole tilt
87
theta_tilt = np.arctan(np.sqrt(g11**2 + h11**2) / abs(g10))
88
phi_tilt = np.arctan2(h11, g11)
89
90
# Magnetic pole positions
91
lat_NMP = 90 - np.rad2deg(theta_tilt) # North magnetic pole latitude
92
lon_NMP = np.rad2deg(phi_tilt)
93
94
def dipole_field(r, theta):
95
"""Calculate dipole field components."""
96
Br = 2 * abs(g10) * (a/r)**3 * np.cos(theta)
97
Btheta = abs(g10) * (a/r)**3 * np.sin(theta)
98
return Br, Btheta
99
100
def total_field(r, theta):
101
"""Total field magnitude."""
102
Br, Btheta = dipole_field(r, theta)
103
return np.sqrt(Br**2 + Btheta**2)
104
105
def inclination(theta):
106
"""Magnetic inclination for dipole field."""
107
return np.arctan(2 * np.cos(theta) / np.sin(theta))
108
109
# Create global grid
110
lat = np.linspace(-90, 90, 181)
111
lon = np.linspace(-180, 180, 361)
112
LAT, LON = np.meshgrid(lat, lon)
113
THETA = np.deg2rad(90 - LAT) # Colatitude
114
115
# Surface field calculations
116
Br, Btheta = dipole_field(a, THETA)
117
B_total = total_field(a, THETA)
118
B_horizontal = np.abs(Btheta)
119
I = np.rad2deg(inclination(THETA))
120
121
# Field line tracing
122
def field_line(L, n_points=100):
123
"""Calculate field line for given L-value (in Earth radii)."""
124
theta_line = np.linspace(0.01, np.pi - 0.01, n_points)
125
r_line = L * a * np.sin(theta_line)**2
126
return r_line, theta_line
127
128
# Secular variation (simplified model)
129
years = np.arange(1900, 2025)
130
# g_1^0 secular variation (approximate, nT/year)
131
g10_history = -31000 + 15 * (years - 1900) - 0.1 * (years - 1900)**1.2
132
133
# IGRF coefficients for different epochs (simplified)
134
igrf_epochs = [1960, 1980, 2000, 2020]
135
igrf_g10 = [-30421, -29992, -29615, -29404.8]
136
137
# Magnetic pole wandering (approximate positions)
138
pole_years = np.arange(1900, 2025, 10)
139
pole_lat = 70 + 0.12 * (pole_years - 1900)
140
pole_lon = -96 - 0.5 * (pole_years - 1900)
141
142
# Field at different altitudes (magnetosphere)
143
altitudes = np.array([0, 1, 2, 4, 6, 10]) * a # Earth radii
144
r_alt = a + altitudes
145
B_altitude = total_field(r_alt, np.pi/4) * 1e9 # nT at 45 deg latitude
146
147
# Power spectrum (Lowes-Mauersberger spectrum)
148
n_range = np.arange(1, 14)
149
# Approximate Rn values (nT^2) at Earth's surface
150
Rn_surface = np.array([1.7e9, 3.0e8, 1.3e8, 4.4e7, 2.1e7,
151
1.2e7, 6.0e6, 4.5e6, 3.0e6, 2.0e6,
152
1.5e6, 1.2e6, 1.0e6])
153
154
# Extrapolate to core-mantle boundary (r = 3480 km)
155
r_cmb = 3480e3
156
Rn_cmb = Rn_surface * (a / r_cmb)**(2*n_range + 4)
157
158
# Create visualization
159
fig = plt.figure(figsize=(12, 10))
160
gs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.35)
161
162
# Plot 1: Total field intensity map
163
ax1 = fig.add_subplot(gs[0, 0])
164
c1 = ax1.contourf(LON, LAT, B_total*1e9, levels=20, cmap='viridis')
165
plt.colorbar(c1, ax=ax1, label='$|B|$ (nT)')
166
ax1.set_xlabel('Longitude')
167
ax1.set_ylabel('Latitude')
168
ax1.set_title('Total Field Intensity')
169
170
# Plot 2: Inclination map
171
ax2 = fig.add_subplot(gs[0, 1])
172
c2 = ax2.contourf(LON, LAT, I, levels=np.linspace(-90, 90, 19), cmap='RdBu_r')
173
plt.colorbar(c2, ax=ax2, label='Inclination (deg)')
174
ax2.contour(LON, LAT, I, levels=[0], colors='black', linewidths=2)
175
ax2.set_xlabel('Longitude')
176
ax2.set_ylabel('Latitude')
177
ax2.set_title('Magnetic Inclination')
178
179
# Plot 3: Field vs latitude
180
ax3 = fig.add_subplot(gs[0, 2])
181
lat_plot = np.linspace(-90, 90, 181)
182
theta_plot = np.deg2rad(90 - lat_plot)
183
B_lat = total_field(a, theta_plot) * 1e9
184
B_H_lat = np.abs(dipole_field(a, theta_plot)[1]) * 1e9
185
ax3.plot(lat_plot, B_lat, 'b-', lw=2, label='Total')
186
ax3.plot(lat_plot, B_H_lat, 'r--', lw=1.5, label='Horizontal')
187
ax3.set_xlabel('Latitude (degrees)')
188
ax3.set_ylabel('Field (nT)')
189
ax3.set_title('Field Intensity vs Latitude')
190
ax3.legend(fontsize=8)
191
ax3.grid(True, alpha=0.3)
192
193
# Plot 4: Field lines (meridional plane)
194
ax4 = fig.add_subplot(gs[1, 0])
195
L_values = [2, 3, 4, 6, 8]
196
colors = plt.cm.viridis(np.linspace(0.2, 0.8, len(L_values)))
197
for L, color in zip(L_values, colors):
198
r_line, theta_line = field_line(L)
199
# Convert to Cartesian
200
x_line = r_line * np.sin(theta_line) / a
201
z_line = r_line * np.cos(theta_line) / a
202
ax4.plot(x_line, z_line, color=color, lw=1.5)
203
ax4.plot(-x_line, z_line, color=color, lw=1.5)
204
205
# Earth
206
earth = plt.Circle((0, 0), 1, color='blue', alpha=0.5)
207
ax4.add_patch(earth)
208
ax4.set_xlim([-10, 10])
209
ax4.set_ylim([-8, 8])
210
ax4.set_xlabel('$x/R_E$')
211
ax4.set_ylabel('$z/R_E$')
212
ax4.set_title('Dipole Field Lines')
213
ax4.set_aspect('equal')
214
ax4.grid(True, alpha=0.3)
215
216
# Plot 5: Field decay with altitude
217
ax5 = fig.add_subplot(gs[1, 1])
218
ax5.semilogy(altitudes/a, B_altitude, 'bo-', lw=2, ms=8)
219
ax5.set_xlabel('Altitude ($R_E$)')
220
ax5.set_ylabel('Field (nT)')
221
ax5.set_title('Field Decay with Altitude')
222
ax5.grid(True, alpha=0.3, which='both')
223
224
# Plot 6: Secular variation
225
ax6 = fig.add_subplot(gs[1, 2])
226
ax6.plot(years, g10_history, 'b-', lw=2)
227
ax6.scatter(igrf_epochs, igrf_g10, color='red', s=50, zorder=5, label='IGRF')
228
ax6.set_xlabel('Year')
229
ax6.set_ylabel('$g_1^0$ (nT)')
230
ax6.set_title('Secular Variation of Dipole')
231
ax6.legend(fontsize=8)
232
ax6.grid(True, alpha=0.3)
233
234
# Plot 7: Pole wandering
235
ax7 = fig.add_subplot(gs[2, 0])
236
sc = ax7.scatter(pole_lon, pole_lat, c=pole_years, cmap='plasma', s=30)
237
ax7.plot(pole_lon, pole_lat, 'k-', alpha=0.3)
238
plt.colorbar(sc, ax=ax7, label='Year')
239
ax7.set_xlabel('Longitude')
240
ax7.set_ylabel('Latitude')
241
ax7.set_title('North Magnetic Pole Wandering')
242
ax7.grid(True, alpha=0.3)
243
244
# Plot 8: Power spectrum
245
ax8 = fig.add_subplot(gs[2, 1])
246
ax8.semilogy(n_range, Rn_surface, 'b-o', lw=2, ms=6, label='Surface')
247
ax8.semilogy(n_range, Rn_cmb, 'r-s', lw=2, ms=6, label='CMB')
248
ax8.set_xlabel('Degree $n$')
249
ax8.set_ylabel('$R_n$ (nT$^2$)')
250
ax8.set_title('Lowes-Mauersberger Spectrum')
251
ax8.legend(fontsize=8)
252
ax8.grid(True, alpha=0.3, which='both')
253
ax8.set_xlim([0, 14])
254
255
# Plot 9: Inclination vs latitude comparison
256
ax9 = fig.add_subplot(gs[2, 2])
257
lat_test = np.linspace(-90, 90, 181)
258
# Dipole formula: tan(I) = 2*tan(lat)
259
I_dipole = np.rad2deg(np.arctan(2 * np.tan(np.deg2rad(lat_test))))
260
# Actual measured (approximate)
261
I_measured = I_dipole + 5 * np.sin(np.deg2rad(2 * lat_test))
262
263
ax9.plot(lat_test, I_dipole, 'b-', lw=2, label='Dipole')
264
ax9.plot(lat_test, I_measured, 'r--', lw=1.5, label='Measured')
265
ax9.set_xlabel('Geographic Latitude')
266
ax9.set_ylabel('Inclination (degrees)')
267
ax9.set_title('Dipole vs Actual Inclination')
268
ax9.legend(fontsize=8)
269
ax9.grid(True, alpha=0.3)
270
271
plt.savefig('magnetic_field_plot.pdf', bbox_inches='tight', dpi=150)
272
print(r'\begin{center}')
273
print(r'\includegraphics[width=\textwidth]{magnetic_field_plot.pdf}')
274
print(r'\end{center}')
275
plt.close()
276
277
# Calculate key values
278
B_equator = total_field(a, np.pi/2) * 1e9
279
B_pole = total_field(a, 0.01) * 1e9
280
ratio_pole_eq = B_pole / B_equator
281
I_45 = np.rad2deg(np.arctan(2 * np.tan(np.deg2rad(45))))
282
\end{pycode}
283
284
\section{Results and Analysis}
285
286
\subsection{Dipole Field Characteristics}
287
288
\begin{pycode}
289
print(r'\begin{table}[htbp]')
290
print(r'\centering')
291
print(r'\caption{Geomagnetic Dipole Field Parameters}')
292
print(r'\begin{tabular}{lc}')
293
print(r'\toprule')
294
print(r'Parameter & Value \\')
295
print(r'\midrule')
296
print(f'Equatorial surface field & {B_equator:.0f} nT \\\\')
297
print(f'Polar surface field & {B_pole:.0f} nT \\\\')
298
print(f'Pole/Equator ratio & {ratio_pole_eq:.2f} \\\\')
299
print(f'Dipole moment & {m_dipole:.2e} A$\\cdot$m$^2$ \\\\')
300
print(f'Dipole tilt angle & {np.rad2deg(theta_tilt):.1f}$^\\circ$ \\\\')
301
print(f'$g_1^0$ (IGRF 2020) & {igrf_g10[-1]:.1f} nT \\\\')
302
print(r'\bottomrule')
303
print(r'\end{tabular}')
304
print(r'\end{table}')
305
\end{pycode}
306
307
\subsection{Field Components at Selected Locations}
308
309
\begin{pycode}
310
print(r'\begin{table}[htbp]')
311
print(r'\centering')
312
print(r'\caption{Magnetic Field at Selected Geographic Locations}')
313
print(r'\begin{tabular}{lcccc}')
314
print(r'\toprule')
315
print(r'Location & Lat & Total (nT) & Incl (deg) & $B_H$ (nT) \\')
316
print(r'\midrule')
317
318
locations = [
319
('North Pole', 90),
320
('London', 51.5),
321
('Equator', 0),
322
('Sydney', -33.9),
323
('South Pole', -90)
324
]
325
326
for name, lat in locations:
327
theta = np.deg2rad(90 - lat)
328
B_t = total_field(a, theta) * 1e9
329
I_loc = np.rad2deg(inclination(theta)) if 0.01 < theta < np.pi - 0.01 else 90 if lat > 0 else -90
330
B_h = np.abs(dipole_field(a, theta)[1]) * 1e9
331
print(f'{name} & {lat}$^\\circ$ & {B_t:.0f} & {I_loc:.1f} & {B_h:.0f} \\\\')
332
333
print(r'\bottomrule')
334
print(r'\end{tabular}')
335
print(r'\end{table}')
336
\end{pycode}
337
338
\begin{remark}
339
The dipole model predicts a pole-to-equator field ratio of exactly 2.0. The actual ratio varies due to non-dipole contributions from higher-order spherical harmonic terms.
340
\end{remark}
341
342
\subsection{Secular Variation}
343
344
The geomagnetic field changes over time due to dynamo processes in the outer core:
345
\begin{itemize}
346
\item $g_1^0$ secular variation: approximately +15 nT/year (dipole weakening)
347
\item North Magnetic Pole drift: currently $\sim$50 km/year toward Siberia
348
\item Dipole tilt: \py{f"{np.rad2deg(theta_tilt):.1f}"}$^\circ$ from rotation axis
349
\end{itemize}
350
351
\section{Applications}
352
353
\begin{example}[Navigation]
354
Magnetic compasses align with the horizontal field component. The declination (angle between magnetic and geographic north) must be known for accurate navigation. At latitude 45$^\circ$N, the expected inclination is \py{f"{I_45:.1f}"}$^\circ$.
355
\end{example}
356
357
\begin{example}[Paleomagnetism]
358
The dipole inclination formula $\tan I = 2\tan\lambda$ allows paleomagnetic reconstructions. Measuring inclination in ancient rocks constrains their paleolatitude at the time of magnetization.
359
\end{example}
360
361
\begin{example}[Space Weather]
362
The magnetosphere's L-shells (field line parameter) trap charged particles in radiation belts. L-values of 2--8 correspond to the Van Allen belts, where field intensity decreases as $r^{-3}$.
363
\end{example}
364
365
\section{Discussion}
366
367
The dipole model captures approximately 90\% of Earth's surface field but has limitations:
368
369
\begin{enumerate}
370
\item \textbf{Regional anomalies}: Continental-scale magnetic anomalies from crustal sources are not represented.
371
\item \textbf{Non-dipole field}: Higher-order terms (quadrupole, octupole) contribute up to 10\% of surface field.
372
\item \textbf{External fields}: Ionospheric and magnetospheric currents create time-varying fields not included in IGRF.
373
\item \textbf{Secular variation}: The field changes continuously, requiring periodic model updates.
374
\end{enumerate}
375
376
\section{Conclusions}
377
378
This computational analysis demonstrates:
379
\begin{itemize}
380
\item Equatorial field strength: \py{f"{B_equator:.0f}"} nT
381
\item Polar field strength: \py{f"{B_pole:.0f}"} nT
382
\item Dipole magnetic moment: \py{f"{m_dipole:.2e}"} A$\cdot$m$^2$
383
\item Expected inclination at 45$^\circ$ latitude: \py{f"{I_45:.1f}"}$^\circ$
384
\item Current dipole tilt: \py{f"{np.rad2deg(theta_tilt):.1f}"}$^\circ$
385
\end{itemize}
386
387
The IGRF provides practical field models updated every 5 years for navigation, satellite operations, and geophysical surveys.
388
389
\section{Further Reading}
390
\begin{itemize}
391
\item Merrill, R.T., McElhinny, M.W., McFadden, P.L., \textit{The Magnetic Field of the Earth}, Academic Press, 1996
392
\item Campbell, W.H., \textit{Introduction to Geomagnetic Fields}, Cambridge University Press, 2003
393
\item Thebault, E., et al., International Geomagnetic Reference Field: the 12th generation, \textit{Earth, Planets and Space}, 2015
394
\end{itemize}
395
396
\end{document}
397
398