Number Density Calculation
This example demonstrates how to calculate the number density of a group of particles and compares it with the analytical solution for a freely expanding Maxwellian cloud.
using TestParticle
using Meshes
using OrdinaryDiffEq
using StaticArrays
using Statistics
using LinearAlgebra
using Random
using CairoMakie
Random.seed!(1234);Simulation Setup
Parameters
N = 100_000
m = 1.0
q = 1.0
T = 1.01.0Thermal velocity:
vth = sqrt(2 * T / m)
t_end = 2.02.0Initialize particles Point source at origin:
x0 = [SVector(0.0, 0.0, 0.0) for _ in 1:N];Maxwellian velocity distribution
vdf = TestParticle.Maxwellian([0.0, 0.0, 0.0], T, 1.0; m = m)VelocityDistributionFunctions.ShiftedPDF{Float64, VelocityDistributionFunctions.MaxwellianPDF{Float64}, Vector{Float64}}(
base: VelocityDistributionFunctions.MaxwellianPDF{Float64}(vth=1.4142135623730951)
u0: [0.0, 0.0, 0.0]
)Use the vectorized rand to get a Vector of SVectors
v0 = rand(vdf, N);Create TraceProblem template Construct an EnsembleProblem to simulate multiple trajectories.
prob_func(prob, i, repeat) = remake(prob, u0 = vcat(x0[i], v0[i]))prob_func (generic function with 1 method)Define a single problem template
u0_dummy = vcat(x0[1], v0[1])
# Zero fields
param = prepare(TestParticle.ZeroField(), TestParticle.ZeroField(); q, m)
tspan = (0.0, t_end)
prob = ODEProblem(trace, u0_dummy, tspan, param);
ensemble_prob = EnsembleProblem(prob; prob_func)EnsembleProblem with problem ODEProblemSolve
sols = solve(ensemble_prob, Tsit5(), EnsembleThreads(), trajectories = N);Density Calculation
Define a grid for density calculation The cloud expands to
L = 6.0
dims = (50, 50, 50)
grid = CartesianGrid((-L, -L, -L), (L, L, L); dims)50×50×50 CartesianGrid
├─ minimum: Point(x: -6.0 m, y: -6.0 m, z: -6.0 m)
├─ maximum: Point(x: 6.0 m, y: 6.0 m, z: 6.0 m)
└─ spacing: (0.24 m, 0.24 m, 0.24 m)Calculate density at get_number_density returns count / volume
density = TestParticle.get_number_density(sols, grid, t_end);Extract a 1D slice along x-axis (approx.
mid_y = dims[2] ÷ 2
mid_z = dims[3] ÷ 2
density_x = density[:, mid_y, mid_z];Grid coordinates for plotting get_cell_centers returns ranges for each dimension
grid_x, grid_y, grid_z = TestParticle.get_cell_centers(grid)
xs_plot = collect(grid_x);Analytical Solution
The analytical number density
The velocity distribution is:
For free expansion, the position of a particle at time
Conservation of particle number implies
Compare with
r2 = xs_plot .^ 2
sigma_param = vth * t_end
n_analytic = @. N / (sqrt(π) * sigma_param)^3 * exp(-r2 / sigma_param^2);Visualization
f = Figure(fontsize = 18)
ax = Axis(f[1, 1],
title = "Free Expansion Density (t = $(t_end))",
xlabel = "x",
ylabel = "Number Density")
scatter!(ax, xs_plot, density_x, label = "Simulation", color = :blue, markersize = 10)
lines!(ax, xs_plot, n_analytic, label = "Analytical", color = :red, linewidth = 2)
axislegend(ax)