PlanetaryMagneticFields.jl
A Julia package for planetary magnetic field modeling.
Overview
PlanetaryMagneticFields.jl provides a unified framework for working with magnetic field models of planets in our solar system. It implements spherical harmonic expansions with Schmidt semi-normalization, following standards used in geomagnetism and planetary science.
Features
- Multi-planetary support: Mercury, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, and Ganymede
- Multiple models: 80+ models available across all planets
- Flexible evaluation: Support for both spherical and Cartesian coordinates
- Visualization: Plot magnetic field maps using GeoMakie (Mollweide, Hammer projections)
Installation
using Pkg
Pkg.add("PlanetaryMagneticFields")Quick Start
using PlanetaryMagneticFields
# Load a Jupiter magnetic field model by unique name
model = load_model(:JRM33; max_degree=13)
# Or use the convenience accessor
model = JRM33(max_degree=13)
# Evaluate the field at a position (in planetary radii)
# Position: 1.5 RJ, 45° colatitude, 0° longitude
r, θ, φ = 1.5, π/4, 0.0
B = model(r, θ, φ) # Returns [B_r, B_θ, B_φ] in nT
# Use Cartesian coordinates
B = model(1.0, 0.0, 0.5; in=:cartesian) # Returns [B_x, B_y, B_z] in nT
# Keyword arguments take precedence over constructor arguments
B_sph = model(1.0, 0.0, 0.5; in=:cartesian, out=:spherical) # Returns [B_r, B_θ, B_φ]3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3):
102024.00685710141
201005.43418457863
-24988.588089244273Coordinate Systems
PlanetaryMagneticFields.jl currently supports two coordinate systems:
Spherical Coordinates
r: Radial distance from planet center (in planetary radii or km)θ: Colatitude in radians [0, π] (0 at north pole, π at south pole)φ: East longitude in radians [0, 2π]
Cartesian Coordinates
x,y,z: Right-handed system with z-axis toward north pole- x-axis points to (θ=π/2, φ=0)
- y-axis points to (θ=π/2, φ=π/2)
Visualization
PlanetaryMagneticFields.jl provides visualization capabilities through GeoMakie. To use plotting functions, you need to load CairoMakie (or GLMakie) and GeoMakie:
using CairoMakie, GeoMakie
using PlanetaryMagneticFieldsHere is an example of how to plot a magnetic field map for a single planet:
model = JRM09() # Load Jupiter's JRM09 model
# Create a field map with Mollweide projection
plot_fieldmap(model;
r=1.0,
axis=(; title="Jupiter Radial Magnetic Field (JRM09)"),
dest="+proj=moll"
)
See visualization examples for more details.
Available Models
List all available models:
available_models()84-element Vector{String}:
"gsfc13ev"
"gsfc15ev"
"gsfc15evs"
"isaac"
"jpl15ev"
"jpl15evs"
"jrm09"
"jrm33"
"o4"
"o6"
⋮
"cassini3"
"cassini5"
"p1184"
"p11as"
"soi"
"spv"
"v1"
"v2"
"z3"Loading Models for Any Planet
# Load a model by planet and model name
earth_model = load_model(:earth, "igrf2020")
saturn_model = load_model(:saturn, "cassini11")
neptune_model = load_model(:neptune, "gsfco8")
# Evaluate at the surface
earth_model(1.0, π/4, 0.0)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3):
-40892.20329623209
-22782.62882034594
206.39416714386755Mercury
available_models(:Mercury)14-element Vector{String}:
"anderson2010d"
"anderson2010dsha"
"anderson2010dts04"
"anderson2010q"
"anderson2010qsha"
"anderson2010qts04"
"anderson2010r"
"anderson2012"
"ness1975"
"thebault2018m1"
"thebault2018m2"
"thebault2018m3"
"uno2009"
"uno2009svd"Earth
available_models(:Earth)26-element Vector{String}:
"igrf1900"
"igrf1905"
"igrf1910"
"igrf1915"
"igrf1920"
"igrf1925"
"igrf1930"
"igrf1935"
"igrf1940"
"igrf1945"
⋮
"igrf1985"
"igrf1990"
"igrf1995"
"igrf2000"
"igrf2005"
"igrf2010"
"igrf2015"
"igrf2020"
"igrf2025"The IGRF (International Geomagnetic Reference Field) models span from 1900 to 2025.
Mars
available_models(:Mars)4-element Vector{String}:
"cain2003"
"gao2021"
"langlais2019"
"mh2014"Mars has crustal magnetic fields (no global dynamo).
Jupiter
available_models(:Jupiter)17-element Vector{String}:
"gsfc13ev"
"gsfc15ev"
"gsfc15evs"
"isaac"
"jpl15ev"
"jpl15evs"
"jrm09"
"jrm33"
"o4"
"o6"
"p11a"
"sha"
"u17ev"
"v117ev"
"vip4"
"vipal"
"vit4"julia> model_info(:jrm33)Dict{String, Any} with 9 entries: "name" => "JRM33" "references" => ["Connerney et al. (2022), Journal of Geophysical Res… "year" => 2022 "order" => 30 "doi" => "10.1029/2021JE007055" "notes" => ["Based on Juno's first 33 orbits", "Latest model. Co… "degree" => 30 "description" => "Jupiter Reference Model through Perijove 33" "recommended_degree" => 13julia> model_info("jrm09")Dict{String, Any} with 9 entries: "name" => "JRM09" "year" => 2018 "order" => 10 "reference" => "Connerney et al. (2018), Geophysical Research Letters" "doi" => "10.1002/2018GL077312" "degree" => 10 "mission_phase" => "First 9 Juno orbits" "notes" => "Well-validated standard model for Jupiter's internal fiel… "description" => "Juno Reference Model through Perijove 9"
Saturn
available_models(:Saturn)11-element Vector{String}:
"burton2009"
"cassini11"
"cassini3"
"cassini5"
"p1184"
"p11as"
"soi"
"spv"
"v1"
"v2"
"z3"Uranus
available_models(:uranus)4-element Vector{String}:
"ah5"
"gsfcq3"
"gsfcq3full"
"umoh"Neptune
available_models(:neptune)3-element Vector{String}:
"gsfco8"
"gsfco8full"
"nmoh"Ganymede
available_models(:ganymede)5-element Vector{String}:
"kivelson2002a"
"kivelson2002b"
"kivelson2002c"
"weber2022dip"
"weber2022quad"Physical Parameters
The package uses the following mean radii for unit conversions:
| Body | Mean Radius (km) |
|---|---|
| Mercury | 2,439.7 |
| Earth | 6,371.2 |
| Mars | 3,389.5 |
| Jupiter | 71,492.0 |
| Saturn | 60,268.0 |
| Uranus | 25,559.0 |
| Neptune | 24,764.0 |
| Ganymede | 2,634.1 |
Mathematical Background
The magnetic scalar potential is expanded in spherical harmonics:
\[V(r,θ,φ) = a \sum_{n=1}^{N} \sum_{m=0}^{n} \left(\frac{a}{r}\right)^{n+1} [g_n^m \cos(mφ) + h_n^m \sin(mφ)] P_n^m(\cos θ)\]
where:
ais the planetary radiusg_n^m, h_n^mare the Gauss coefficients (Schmidt semi-normalized)P_n^mare the associated Legendre polynomials (Schmidt semi-normalized)(r,θ,φ)are spherical coordinates
The magnetic field B = -∇V is computed from derivatives of the potential.
References
Connerney, J. E. P., et al. (2018). A new model of Jupiter's magnetic field from Juno's first nine orbits. Geophysical Research Letters, 45(6), 2590-2596. doi:10.1002/2018GL077312
Connerney, J. E. P., et al. (2022). A new model of Jupiter's magnetic field at the completion of Juno's Prime Mission. Journal of Geophysical Research: Planets, 127(2), e2021JE007055. doi:10.1029/2021JE007055
Winch, D. E., et al. (2005). Geomagnetism and Schmidt quasi-normalization. Geophysical Journal International, 160(2), 487-504.
Comparison
using PythonCall
using PlanetaryMagneticFields
using Chairmarks
@py import JupiterMag as jm
r, θ, φ = 1.5, π/4, 0.0
jm.Internal.Config(Model="jrm33", CartesianIn=false, CartesianOut=false)Python: {'Model': 'jrm33', 'CartesianIn': np.False_, 'CartesianOut': np.False_, 'Degree': np.int32(13)}julia> Br, Bt, Bp = jm.Internal.Field(r, θ, φ);julia> B_py = pyconvert(Vector{Float64}, [Br[0], Bt[0], Bp[0]])3-element Vector{Float64}: 118254.5236651993 92694.83054050733 -11952.585361387928julia> model = JRM33(max_degree=13)SphericalHarmonicModel(name=jrm33, obj=PlanetaryMagneticFields.Planet(:jupiter, 71492.0), degree=13, order=13)julia> B = model(r, θ, φ)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): 118254.5236651993 92694.83054050733 -11952.585361387926julia> @assert B_py ≈ Bjulia> @b $model($r, $θ, $φ), jm.Internal.Field($r, $θ, $φ)(1.412 μs, 29.115 μs (29 allocs: 624 bytes))
API Reference
PlanetaryMagneticFields.GaussCoefficientsPlanetaryMagneticFields.SphericalHarmonicModelPlanetaryMagneticFields.TimeVaryingGaussCoefficientsPlanetaryMagneticFields.available_modelsPlanetaryMagneticFields.fieldmapPlanetaryMagneticFields.load_coefficientsPlanetaryMagneticFields.load_modelPlanetaryMagneticFields.model_infoPlanetaryMagneticFields.plot_fieldmapPlanetaryMagneticFields.plot_fieldmap!PlanetaryMagneticFields.plot_models
PlanetaryMagneticFields.GaussCoefficients — Type
GaussCoefficientsStorage for Gauss coefficients in Schmidt semi-normalized form.
Fields
g: Schmidt semi-normalized g coefficients (degree × order)h: Schmidt semi-normalized h coefficients (degree × order)
The degree and order are inferred from matrix dimensions: degree = size(g,1)-1, order = size(g,2)-1.
PlanetaryMagneticFields.SphericalHarmonicModel — Type
SphericalHarmonicModel{C} <: InternalFieldModelA magnetic field model using spherical harmonic expansion.
Fields
name: Model namecoeffs: Gauss coefficients (GaussCoefficients or TimeVaryingGaussCoefficients)obj: Object (planet, body) for which the model is defineddegree: Maximum degree N for evaluationorder: Maximum order M for evaluation
PlanetaryMagneticFields.TimeVaryingGaussCoefficients — Type
TimeVaryingGaussCoefficientsStorage for time-varying Gauss coefficients with multiple epochs. Coefficients are linearly interpolated between epochs.
Fields
epochs: Sorted vector of epoch years (e.g., [1900.0, 1905.0, ..., 2025.0])coefficients: Vector of GaussCoefficients, one per epoch
PlanetaryMagneticFields.available_models — Function
available_models([body])List all available models, optionally specified by a given astronomical body.
Example
available_models()
available_models(:jupiter)PlanetaryMagneticFields.fieldmap — Function
fieldmap(model, r, nlat, nlon; idx = identity)
fieldmap(model, r = 1.0; nlat = 180, nlon = 360, kw...)Compute magnetic fields over a latitude-longitude grid at a given radial distance r [planetary radii] for model model.
Arguments
nlat=180: Number of latitude pointsnlon=360: Number of longitude points`idx: Field component selector / function that works on the output ofmodel(r, θ, φ)(default: identity returns full vector)1: Radial component (Br)2: Colatitude component (Bθ)3: Azimuthal component (Bφ)norm: Field magnitude
Returns
KeyedArray: Magnetic field values at each grid point with axes:lon: Longitude values [-180, 180] degreeslat: Latitude values [-90, 90] degrees
Example
model = load_model(:jupiter, "jrm09")
field_map = fieldmap(model; r=1.0)
# Access data: field_map[lon=0.0, lat=45.0]
# Get axes: axiskeys(field_map, 1) for longitudes, axiskeys(field_map, 2) for latitudesPlanetaryMagneticFields.load_coefficients — Method
load_coefficients(filepath; use_cache=false)::GaussCoefficientsLoad Gauss coefficients from the given filepath.
Set use_cache=true to cache loaded coefficients and reuse them on subsequent calls.
Example
load_coefficients("data/jupiter/jrm09.dat")PlanetaryMagneticFields.load_model — Method
load_model(model; kwargs...)
load_model(planet, model; kwargs...)Load and create a magnetic field model.
Single-argument form (by unique model name)
Load a model by its unique name (e.g., :JRM33, :JRM09).
Two-argument form (by planet and model)
Load a model by specifying both planet and model name.
Arguments
model: Unique model identifier (e.g.,:JRM33,:JRM09)planet: Planet identifier (e.g., :jupiter, :saturn, :earth)max_degree: Maximum degree to use (truncates model if specified)in: Default input coordinate system (:sphericalor:cartesian)out: Default output coordinate system (:sphericalor:cartesian)
Notes
Input positions are assumed to be in planetary radii by default. For physical units (e.g., km), use Unitful.jl which is supported via a package extension.
Returns
A callable object that can be invoked as model(r, θ, φ; kwargs...)
Examples
# Load by unique model name
model = load_model(:JRM33; max_degree=13)
B = model(1.5, π/4, 0.0) # Returns [B_r, B_θ, B_φ] in nT
# Load by planet and model name
model = load_model(:jupiter, "jrm09")
B = model(1.5, π/4, 0.0)
# With custom coordinate systems
model = load_model(:JRM33; max_degree=13, in=:cartesian, out=:cartesian)
B = model(1.0, 0.0, 0.5) # Returns [B_x, B_y, B_z] in nT
# Override output coordinates at call time
B_sph = model(1.0, 0.0, 0.5; out=:spherical) # Returns [B_r, B_θ, B_φ]PlanetaryMagneticFields.model_info — Function
model_info(model)Get detailed information about a magnetic field model.
Example
info = model_info("jrm09")
println(info["description"])PlanetaryMagneticFields.plot_fieldmap — Function
plot_fieldmap(model; r=1.0, dest="+proj=moll", kwargs...)Create a complete figure with a magnetic field map.
Arguments
model: The magnetic field modelr::Real=1.0: Radial distance in planetary radii
Example
using CairoMakie, GeoMakie
using PlanetaryMagneticFields
model = load_model(:jupiter, "jrm09")
plot_fieldmap(model; r=1.0, title="Jupiter JRM09")PlanetaryMagneticFields.plot_fieldmap! — Function
plot_fieldmap!(ax, model; r=1.0, nlat=180, nlon=360, kwargs...)Plot a magnetic field map on an existing GeoAxis ax, with nlat and nlon determining the number of latitude and longitude points, respectively.
Example
using CairoMakie, GeoMakie
using PlanetaryMagneticFields
fig = Figure()
ax = GeoAxis(fig[1,1]; dest="+proj=moll")
model = load_model(:jupiter, "jrm09")
sf = plot_fieldmap!(ax, model; r=1.0)
Colorbar(fig[1,2], sf; label="Br [nT]")
figPlanetaryMagneticFields.plot_models — Function
plot_models(; r=1.0, models=nothing, projection="+proj=moll", kwargs...)Create a figure showing magnetic field maps of all available planets.
Default Models
- Mercury: "anderson2012"
- Earth: "igrf2020"
- Mars: "langlais2019"
- Jupiter: "jrm09"
- Saturn: "cassini11"
- Uranus: "ah5"
- Neptune: "gsfco8"
- Ganymede: "kivelson2002a"