Skip to content

Cosmic Ray

This example shows how to trace cosmic rays in a background magnetic field. In the original MHD solution, everything is dimensionless. We are following the normalization procedures in Cosmic ray propagation in sub-Alfvénic magnetohydrodynamic turbulence. The Lorentz equation for each particle of charge q and mass m. The particle has a momentum p=γmv and a velocity v and propagates in an electromagnetic field E (no mean electric field), B=δB+B0:

dpdt=q(E+vc×B)dxdt=v

Each particle is injected with a Lorentz factor γ0. Physically, one can think of γ0 as a measure of the relativity of the particle, i.e., for small γ0 we will recover nonrelativistic equations, and for large γ0 –- ultra-relativistic equations. γ0 also defines the initial Larmor radius

rL0=γ0mc2/(eB0)

where B0 is background magnetic field strength. We also define the particle's synchrotron pulsation

Ω0=c/rL0

This is measured in cyclotron frequency units, a gyration frequency measured in the particle's own frame. A particle with pitch angle cosine μ=cosθ=0 will make a full orbit in the B0 field in 2π time. After normalization, we have

dvdt=γE+v×Bdxdt=rL0Lv

where γ=γ/γ0, v=γv/c, and t=t/(γrL0/c), E=E/(B0) is the normalized electric field, B=B/B0 is the normalized magnetic field, and x=x/L. L is the length scale we can choose to decide how many discrete point to have within one gyroradius. For instance, if L=rL0, then 1 unit distance in the dimensionless system is 1 gyroradius for a particle with γ0 under B0; if L=4rL0, then 1 unit distance in the dimensionless system is 4 gyroradii for a particle with γ0 under B0. The smaller rL0/L is, the more likely a particle will experience an inhomogeneous magnetic field during gyration, and the more likely it will get scattered. Note that γ is also a function of v:

γ=γ/γ0=1v02/c21v2/c2

In practice, at least in the interstellar medium, the effect of the electric field over high-energy (multi TeV) cosmic rays can be neglected. Therefore, energy is conserved and we are interested in looking at the scattering and diffusion processes. γ=1 without considering radiative loss or re-acceleration.

Thus, the normalized equations can be further simplified:

dvdt=v×Bdxdt=rL0Lv

By taking q=1,m=1,c=1,B0=1, the characteristic length and frequency scales are

rL0=γ0mc2eB0=γ0Ω0=eB0mc2=1

This looks good, but there is still an annoying factor rL0/L in the second equation. We can remove that by combining L/rL0 with x:

dxdt=v

It simply means that if the original domain length is 1, now it becomes L/rL0.

A standard procedure is as follows:

  1. Obtain the dimensionless MHD solution.

  2. Normalize the magnetic field with its background mean magnitude, such that in the new field, B0=1. This has a clear physical meaning that a particle with velocity 1 has a gyroradii of 1 and a gyroperiod of 2π.

  3. Manually choose the spatial extent to be L/rL0. For simplicity, we set rL0=1 and the MHD domain extent to be [L/2,L/2]. If we have nx discrete points along that direction, then the grid size is dx=L/nx. If L=nx/4, then dx=1/4 is a quarter of the gyroradius. In this way we can control how well we resolve the magnetic field for the gyromotion and diffusion process.

Now let's demonstrate this with trace_normalized!.

julia
using TestParticle, OrdinaryDiffEqVerner, StaticArrays
using CairoMakie

# Number of cells for the field along each dimension
nx, ny, nz = 4, 6, 2
# Unit conversion factors for length
rL0 = 1.0
L = nx / 4
# Set length scales
x = range(-L/2-1e-2, L/2+1e-2, length = nx) # [rL0]
y = range(-L-1e-2, 1e-2, length = ny) # [rL0]
z = range(-10, 10, length = nz) # [rL0]

B = fill(0.0, 3, nx, ny, nz) # [B0]
B[3, :, :, :] .= 1.0
E(x) = SA[0.0, 0.0, 0.0] # [E₀]
# periodic bc = 2
param = prepare(x, y, z, E, B; species = User, bc = 2)

# Initial condition
stateinit = let
   x0 = [0.0, 0.0, 0.0] # initial position [l₀]
   u0 = [1.0, 0.0, 0.0] # initial velocity [v₀] -> r = 1 * rL0
   [x0..., u0...]
end
# Time span
tspan = (0.0, π) # half gyroperiod

prob = ODEProblem(trace_normalized!, stateinit, tspan, param)
sol = solve(prob, Vern9())

### Visualization
f = Figure(fontsize = 18)
ax = Axis(f[1, 1],
   title = "Proton trajectory",
   xlabel = "X",
   ylabel = "Y",
   limits = (2*x[1]-0.1, 2*x[end]+0.1, 2*y[1]-0.1, 2*y[end]+0.1),
   aspect = DataAspect()
)

lines!(ax, sol, idxs = (1, 2))

xgrid = [i for i in x, _ in y]
ygrid = [j for _ in x, j in y]
scatter!(ax, xgrid[:], ygrid[:], color = :tomato)