Magnetism Models
This example demonstrates the pytcl.magnetism module capabilities, including World Magnetic Model (WMM2020) coefficients, dipole moment calculations, and geomagnetic field properties.
Overview
Earth’s magnetic field models are essential for:
Navigation: Compass corrections and heading reference
Aerospace: Attitude determination using magnetometers
Geophysics: Understanding Earth’s core dynamics
Space weather: Radiation environment modeling
WMM2020 Coefficients
The World Magnetic Model uses spherical harmonic coefficients:
- Gauss Coefficients (g, h)
g[n,m]: coefficients for cos(m*lambda) terms
h[n,m]: coefficients for sin(m*lambda) terms
Units: nanoTesla (nT)
- Secular Variation (g_dot, h_dot)
Rate of change of coefficients
Units: nT/year
Used for temporal extrapolation
- Epoch and Validity
WMM2020 epoch: 2020.0
Valid period: 2020-2025
Maximum order: n_max = 12
Global Magnetic Field: Earth’s magnetic field varies with latitude and longitude, with field strength strongest near the poles.
Dipole Properties
- Magnetic Dipole Moment
Earth’s main field approximated as dipole
Moment: ~8 x 10^22 A*m^2
Decreasing ~5% per century
- Dipole Axis
Tilted ~11° from rotation axis
Magnetic poles vs geographic poles
Axis drifts over time (secular variation)
- Harmonic Strength by Order
n=1: Dipole (dominant)
n=2-4: Quadrupole, octupole terms
Higher orders: smaller contributions
Code Highlights
The example demonstrates:
WMM2020 coefficient creation with
create_wmm2020_coefficients()Dipole moment calculation with
dipole_moment()Dipole axis orientation with
dipole_axis()Coefficient structure and magnitudes
Source Code
1"""Magnetism module demonstration with geomagnetic models.
2
3This example demonstrates the pytcl.magnetism module capabilities, including
4World Magnetic Model (WMM2020) coefficients, dipole moment calculations, and
5geomagnetic field properties.
6
7Functions demonstrated:
8- create_wmm2020_coefficients(): Create WMM2020 magnetic coefficients
9- dipole_moment(): Calculate Earth's magnetic dipole moment
10- dipole_axis(): Calculate dipole axis orientation
11"""
12
13from pathlib import Path
14
15import numpy as np
16import plotly.graph_objects as go
17from plotly.subplots import make_subplots
18
19from pytcl.magnetism import (
20 create_wmm2020_coefficients,
21 dipole_axis,
22 dipole_moment,
23)
24
25# Controls for visualization
26SHOW_PLOTS = False
27
28
29def demo_wmm2020_coefficients() -> None:
30 """Demonstrate WMM2020 magnetic coefficients."""
31 print("\n" + "=" * 60)
32 print("WMM2020 Magnetic Coefficients")
33 print("=" * 60)
34
35 # Create WMM2020 coefficients
36 coeffs = create_wmm2020_coefficients()
37
38 print(f"\nCoefficients created for epoch: {coeffs.epoch}")
39 print(f"Maximum order (n_max): {coeffs.n_max}")
40 print(f"G coefficients shape (Gauss): {coeffs.g.shape}")
41 print(f"H coefficients shape (Gauss): {coeffs.h.shape}")
42 print(f"G-dot coefficients shape (Gauss/year): {coeffs.g_dot.shape}")
43 print(f"H-dot coefficients shape (Gauss/year): {coeffs.h_dot.shape}")
44
45 # Show some sample coefficients
46 print("\nSample Gauss coefficients (g) [nT]:")
47 print(f" g[1,0] = {coeffs.g[1, 0]:.2f}")
48 print(f" g[1,1] = {coeffs.g[1, 1]:.2f}")
49 print(f" g[2,0] = {coeffs.g[2, 0]:.2f}")
50
51 print("\nSample Schmidt coefficients (h) [nT]:")
52 print(f" h[1,1] = {coeffs.h[1, 1]:.2f}")
53 print(f" h[2,1] = {coeffs.h[2, 1]:.2f}")
54 print(f" h[2,2] = {coeffs.h[2, 2]:.2f}")
55
56 # Show secular variation rates
57 print("\nSample secular variation rates [nT/year]:")
58 print(f" g_dot[1,0] = {coeffs.g_dot[1, 0]:.2f}")
59 print(f" h_dot[1,1] = {coeffs.h_dot[1, 1]:.2f}")
60
61 # Visualization: Coefficient magnitudes by order
62 fig = make_subplots(
63 rows=2,
64 cols=1,
65 subplot_titles=("G Coefficients by Order", "H Coefficients by Order"),
66 vertical_spacing=0.12,
67 )
68
69 orders = np.arange(coeffs.n_max + 1)
70 g_means = [np.mean(np.abs(coeffs.g[n, :])) for n in orders]
71 h_means = [np.mean(np.abs(coeffs.h[n, :])) for n in orders]
72
73 fig.add_trace(
74 go.Bar(x=orders, y=g_means, name="G coefficients", marker_color="steelblue"),
75 row=1,
76 col=1,
77 )
78 fig.add_trace(
79 go.Bar(x=orders, y=h_means, name="H coefficients", marker_color="coral"),
80 row=2,
81 col=1,
82 )
83
84 fig.update_xaxes(title_text="Order (n)", row=1, col=1)
85 fig.update_xaxes(title_text="Order (n)", row=2, col=1)
86 fig.update_yaxes(title_text="Mean |Coefficient| [nT]", row=1, col=1)
87 fig.update_yaxes(title_text="Mean |Coefficient| [nT]", row=2, col=1)
88 fig.update_layout(height=500, showlegend=True)
89
90 if SHOW_PLOTS:
91 fig.show()
92 else:
93 fig.write_html(str(OUTPUT_DIR / "magnetism_demo.html"))
94
95
96def demo_dipole_moment() -> None:
97 """Demonstrate dipole moment calculation."""
98 print("\n" + "=" * 60)
99 print("Earth's Magnetic Dipole Moment")
100 print("=" * 60)
101
102 # Get WMM2020 coefficients
103 coeffs = create_wmm2020_coefficients()
104
105 # Calculate dipole moment
106 moment = dipole_moment(coeffs)
107 print(f"\nMagnetic dipole moment: {moment:.4e} A·m²")
108 print(f"Equivalent magnitude: {moment:.2e} Tesla·m³")
109
110 # Extract individual dipole components from coefficients
111 g10 = coeffs.g[1, 0] # Axial dipole coefficient
112 g11 = coeffs.g[1, 1] # Equatorial dipole component
113 h11 = coeffs.h[1, 1] # Equatorial dipole component
114
115 print(f"\nDipole components:")
116 print(f" g10 (axial): {g10:.2f} nT")
117 print(f" g11: {g11:.2f} nT")
118 print(f" h11: {h11:.2f} nT")
119
120 # Calculate dipole direction and magnitude
121 dipole_magnitude = np.sqrt(g10**2 + g11**2 + h11**2)
122 print(f"\nDipole magnitude from coefficients: {dipole_magnitude:.2f} nT")
123
124 # Visualization: Dipole strength over harmonic orders
125 fig = go.Figure()
126
127 orders = np.arange(1, coeffs.n_max + 1)
128 order_moments = []
129
130 for n in orders:
131 order_coeffs = np.sqrt(
132 np.sum(coeffs.g[n, :] ** 2) + np.sum(coeffs.h[n, :] ** 2)
133 )
134 order_moments.append(order_coeffs)
135
136 fig.add_trace(
137 go.Scatter(
138 x=orders,
139 y=order_moments,
140 mode="lines+markers",
141 name="Harmonic strength",
142 line=dict(color="darkblue", width=2),
143 marker=dict(size=8),
144 )
145 )
146
147 fig.update_layout(
148 title="Magnetic Field Harmonic Strength by Order",
149 xaxis_title="Harmonic Order (n)",
150 yaxis_title="RMS Strength [nT]",
151 height=400,
152 hovermode="x unified",
153 )
154
155 if SHOW_PLOTS:
156 fig.show()
157 else:
158 fig.write_html(str(OUTPUT_DIR / "magnetism_demo.html"))
159
160
161def demo_dipole_axis() -> None:
162 """Demonstrate dipole axis calculation."""
163 print("\n" + "=" * 60)
164 print("Magnetic Dipole Axis")
165 print("=" * 60)
166
167 # Get WMM2020 coefficients
168 coeffs = create_wmm2020_coefficients()
169
170 # Calculate dipole axis
171 dipole_axis_result = dipole_axis(coeffs)
172 print(f"\nDipole axis: {dipole_axis_result}")
173
174 # Calculate poles from coefficients
175 # Magnetic poles are where field lines are vertical
176 g10 = coeffs.g[1, 0]
177 g11 = coeffs.g[1, 1]
178 h11 = coeffs.h[1, 1]
179
180 # Calculate magnetic inclination (dip angle) at equator
181 # At magnetic equator, inclination = arctan(2 * g10 / sqrt(g11^2 + h11^2))
182 equatorial_dip = 2 * g10 / np.sqrt(g11**2 + h11**2)
183 inclination_deg = np.degrees(np.arctan(equatorial_dip))
184
185 print(f"\nDipole field properties:")
186 print(f" Axial dipole ratio: {g10 / np.sqrt(g11**2 + h11**2):.4f}")
187 print(f" Field inclination estimate: {inclination_deg:.2f}°")
188
189 # Visualization: Dipole offset from center
190 # Geographic pole vs Magnetic pole
191 fig = go.Figure()
192
193 # Add geographic pole
194 fig.add_trace(
195 go.Scattergeo(
196 lon=[0],
197 lat=[90],
198 mode="markers",
199 marker=dict(size=12, color="blue", symbol="star"),
200 name="Geographic North Pole",
201 )
202 )
203
204 # Add magnetic dipole approximation
205 # Magnetic declination and inclination affect pole position
206 mag_lat_offset = np.degrees(np.arctan2(h11, g11))
207 mag_lon_offset = np.degrees(np.arctan2(g11, g10))
208
209 fig.add_trace(
210 go.Scattergeo(
211 lon=[mag_lon_offset],
212 lat=[90 - np.degrees(np.arctan2(np.sqrt(g11**2 + h11**2), g10))],
213 mode="markers",
214 marker=dict(size=12, color="red", symbol="x"),
215 name="Magnetic Dipole Location",
216 )
217 )
218
219 fig.update_layout(
220 title="Magnetic Dipole Axis Orientation (Approximate)",
221 geo=dict(projection_type="orthographic"),
222 height=500,
223 showlegend=True,
224 )
225
226 if SHOW_PLOTS:
227 fig.show()
228 else:
229 fig.write_html(str(OUTPUT_DIR / "magnetism_demo.html"))
230
231
232def main() -> None:
233 """Run all demonstrations."""
234 print("\n" + "=" * 60)
235 print("Magnetism Module Demonstration")
236 print("=" * 60)
237
238 demo_wmm2020_coefficients()
239 demo_dipole_moment()
240 demo_dipole_axis()
241
242 print("\n" + "=" * 60)
243 print("Demonstration Complete")
244 print("=" * 60)
245
246
247OUTPUT_DIR = Path("docs/_static/images/examples")
248OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
249
250if __name__ == "__main__":
251 main()
Running the Example
python examples/magnetism_demo.py
See Also
Geophysical Models - Gravity and magnetic field models
ins_gnss_navigation - Navigation applications
coordinate_systems - Coordinate transformations