PlanetaryMagneticFields.jl

DOI version

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.588089244273

Coordinate 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 PlanetaryMagneticFields

Here 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"
)
Example block output

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.39416714386755

Mercury

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" => 13
julia> 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:

BodyMean Radius (km)
Mercury2,439.7
Earth6,371.2
Mars3,389.5
Jupiter71,492.0
Saturn60,268.0
Uranus25,559.0
Neptune24,764.0
Ganymede2,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:

  • a is the planetary radius
  • g_n^m, h_n^m are the Gauss coefficients (Schmidt semi-normalized)
  • P_n^m are the associated Legendre polynomials (Schmidt semi-normalized)
  • (r,θ,φ) are spherical coordinates

The magnetic field B = -∇V is computed from derivatives of the potential.

References

  1. 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

  2. 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

  3. 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.585361387928
julia> 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.585361387926
julia> @assert B_py ≈ B
julia> @b $model($r, $θ, $φ), jm.Internal.Field($r, $θ, $φ)(1.412 μs, 29.115 μs (29 allocs: 624 bytes))

API Reference

PlanetaryMagneticFields.GaussCoefficientsType
GaussCoefficients

Storage 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.

source
PlanetaryMagneticFields.SphericalHarmonicModelType
SphericalHarmonicModel{C} <: InternalFieldModel

A magnetic field model using spherical harmonic expansion.

Fields

  • name: Model name
  • coeffs: Gauss coefficients (GaussCoefficients or TimeVaryingGaussCoefficients)
  • obj: Object (planet, body) for which the model is defined
  • degree: Maximum degree N for evaluation
  • order: Maximum order M for evaluation
source
PlanetaryMagneticFields.TimeVaryingGaussCoefficientsType
TimeVaryingGaussCoefficients

Storage 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
source
PlanetaryMagneticFields.fieldmapFunction
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 points
  • nlon=360: Number of longitude points`
  • idx: Field component selector / function that works on the output of model(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] degrees
    • lat: 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 latitudes
source
PlanetaryMagneticFields.load_coefficientsMethod
load_coefficients(filepath; use_cache=false)::GaussCoefficients

Load 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")
source
PlanetaryMagneticFields.load_modelMethod
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 (:spherical or :cartesian)
  • out: Default output coordinate system (:spherical or :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_φ]
source
PlanetaryMagneticFields.plot_fieldmapFunction
plot_fieldmap(model; r=1.0, dest="+proj=moll", kwargs...)

Create a complete figure with a magnetic field map.

Arguments

  • model: The magnetic field model
  • r::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")
source
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]")
fig
source
PlanetaryMagneticFields.plot_modelsFunction
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"
source