Skip to content

Reconnection X-line

This example traces protons and electrons near a magnetic reconnection X-line. The magnetic field is modeled as a Harris current sheet with a superposed X-type perturbation.

julia
using TestParticle, OrdinaryDiffEq, StaticArrays
import TestParticle as TP
using TestParticle: Rₑ
using LinearAlgebra: norm
using CairoMakie

### Define the Field

# Parameters
const B₀ = 20e-9  # Asymptotic magnetic field [T]
const Bₙ = 1e-9   # Normal magnetic field gradient parameter [T]
const L = 0.5Rₑ   # Current sheet thickness [m]
const Eᵣ = 0.1e-3 # Reconnection electric field [V/m]

function getB(xu)
   x, y, z = xu[1], xu[2], xu[3]
   return SVector{3}(B₀ * tanh(z / L), 0.0, Bₙ * x / L)
end

getE(xu) = SVector{3}(0.0, Eᵣ, 0.0)

### Trace Particles

# Initialize proton
x0_p = [-1.0Rₑ, 0.0, 0.1Rₑ]
Ek_p = 1e3 # eV
v_p = TP.energy2velocity(Ek_p) # magnitude
v0_p = [v_p, 0.0, 0.0]

stateinit_p = [x0_p..., v0_p...]
param_p = prepare(getE, getB, species = TP.Proton)
tspan_p = (0.0, 100.0) # seconds

prob_p = ODEProblem(TP.trace!, stateinit_p, tspan_p, param_p)
sol_p = solve(prob_p, Vern9())

# Initialize electron
x0_e = [-1.0Rₑ, 0.0, 0.1Rₑ]
Ek_e = 1e3 # eV
v_e = TP.energy2velocity(Ek_e, m = TP.mₑ, q = TP.qₑ) # magnitude
v0_e = [v_e, 0.0, 0.0]

stateinit_e = [x0_e..., v0_e...]
param_e = prepare(getE, getB, species = TP.Electron)
tspan_e = (0.0, 15.0) # seconds, electron is much faster

prob_e = ODEProblem(TP.trace!, stateinit_e, tspan_e, param_e)
sol_e = solve(prob_e, Vern9())

### Visualization

f = Figure(size = (1000, 500), fontsize = 18)

function plot_trajectory!(fpos, sol, tspan, title, label, color)
   ax = Axis3(fpos,
      title = title,
      xlabel = "x [Re]",
      ylabel = "y [Re]",
      zlabel = "z [Re]",
      aspect = :data
   )

   n = 10000 # number of timepoints
   ts = range(tspan..., length = n)
   x = sol(ts, idxs = 1) ./ Rₑ |> Vector
   y = sol(ts, idxs = 2) ./ Rₑ |> Vector
   z = sol(ts, idxs = 3) ./ Rₑ |> Vector

   lines!(ax, x, y, z, label = label, color = color)
   axislegend(ax, backgroundcolor = :transparent)
   return ax
end

# Plot Proton
ax1 = plot_trajectory!(f[1, 1], sol_p, tspan_p, "Proton trajectory", "1 keV Proton", :red)

# Plot Electron
ax2 = plot_trajectory!(
   f[1, 2], sol_e, tspan_e, "Electron trajectory", "1 keV Electron", :blue)

# Add B field arrows to proton plot for context
function plot_B!(ax)
   xrange = range(-2, 2, length = 5)
   yrange = range(-1, 1, length = 3)
   zrange = range(-1, 1, length = 5)

   ps = [Point3f(x, y, z) for x in xrange for y in yrange for z in zrange]
   B = map(p -> Vec3f(getB(p .* Rₑ) ./ B₀), ps)
   Bmag = norm.(B)

   arrows!(ax, ps, B, fxaa = true, color = Bmag, lengthscale = 0.4, arrowsize = 0.05)
end

plot_B!(ax1)
plot_B!(ax2)