Skip to content

Commit 3665006

Browse files
authored
Reorganize demos (#134)
* Reorganize demos * fieldline -> dipole_fieldline; return StaticArrays * Fix the sign of dipole moment * Add magnetosphere demo * Add link to pluto presentations * Bump patch
1 parent 19a59ba commit 3665006

21 files changed

+251
-125
lines changed

Project.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "TestParticle"
22
uuid = "953b605b-f162-4481-8f7f-a191c2bb40e3"
33
authors = ["Hongyang Zhou <[email protected]>, and Tiancheng Liu <[email protected]>"]
4-
version = "0.8.0"
4+
version = "0.8.1"
55

66
[deps]
77
ChunkSplitters = "ae650224-84b6-46f8-82ea-d812ca08434e"
@@ -24,15 +24,15 @@ Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
2424
TestParticleMakie = "Makie"
2525

2626
[compat]
27-
ChunkSplitters = "2.0"
27+
ChunkSplitters = "2"
2828
Distributions = "0.25"
29-
Elliptic = "1.0"
29+
Elliptic = "1"
3030
Interpolations = "0.14, 0.15"
3131
Makie = "0.20"
3232
Meshes = "0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40"
33-
PrecompileTools = "1.0"
33+
PrecompileTools = "1"
3434
SciMLBase = "2"
35-
SpecialFunctions = "1.5, 2.0"
35+
SpecialFunctions = "1.5, 2"
3636
StaticArrays = "1.2"
3737
Statistics = "1"
3838
julia = "1.9"

docs/examples/advanced/config.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"order": [
3+
"demo_boris_outofdomain.jl",
4+
"demo_ensemble.jl",
5+
"demo_savingcallback.jl",
6+
"demo_output_func.jl",
7+
"demo_currentsheet.jl",
8+
"demo_magneticmirror.jl",
9+
"demo_magneticbottle.jl",
10+
"demo_proton_dipole.jl",
11+
"demo_analytic_magnetosphere.jl",
12+
"demo_tokamak_coil.jl",
13+
"demo_tokamak_profile.jl",
14+
"demo_batsrus_3dstructured.md"
15+
]
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# ---
2+
# title: Analytical magnetosphere
3+
# id: demo_analytic_magnetosphere
4+
# date: 2024-02-02
5+
# author: "[Hongyang Zhou](https://github.com/henry2004y)"
6+
# julia: 1.10.0
7+
# description: Tracing charged particle in an analytical magnetosphere
8+
# ---
9+
10+
# This demo shows how to trace particles in a vacuum superposition of a dipolar magnetic field ``\mathbf{B}_D`` with a uniform background magnetic field ``\mathbf{B}_\mathrm{IMF}``.
11+
# In this slightly modified dipole field, magnetic null points appear near 14 Earth's radii, and the particle orbits are also distorted from the idealized motions in [Demo: magnetic dipole](@ref demo_dipole).
12+
13+
import DisplayAs #hide
14+
using TestParticle
15+
using TestParticle: getB_dipole, getE_dipole, sph2cart, mᵢ, qᵢ, c, Rₑ
16+
using OrdinaryDiffEq
17+
using StaticArrays
18+
using FieldTracer
19+
using CairoMakie
20+
CairoMakie.activate!(type = "png")
21+
22+
function getB_superposition(xu)
23+
getB_dipole(xu) + SA[0.0, 0.0, -10e-9]
24+
end
25+
26+
"Boundary condition check."
27+
function isoutofdomain(u, p, t)
28+
rout = 18Rₑ
29+
if hypot(u[1], u[2], u[3]) < 1.1Rₑ ||
30+
abs(u[1]) > rout || abs(u[2]) > rout || abs(u[3]) > rout
31+
return true
32+
else
33+
return false
34+
end
35+
end
36+
37+
"Set initial conditions."
38+
function prob_func(prob, i, repeat)
39+
## initial particle energy
40+
Ek = 5e3 # [eV]
41+
## initial velocity, [m/s]
42+
v₀ = sph2cart(c*sqrt(1-1/(1+Ek*qᵢ/(mᵢ*c^2))^2), 0.0, π/4)
43+
## initial position, [m]
44+
r₀ = sph2cart(13*Rₑ, π*i, π/2)
45+
prob.u0 .= [r₀..., v₀...]
46+
47+
prob
48+
end
49+
50+
## obtain field
51+
param = prepare(getE_dipole, getB_superposition)
52+
stateinit = zeros(6) # particle position and velocity to be modified
53+
tspan = (0.0, 2000.0)
54+
trajectories = 2
55+
56+
prob = ODEProblem(trace!, stateinit, tspan, param)
57+
ensemble_prob = EnsembleProblem(prob; prob_func, safetycopy=false)
58+
59+
## See https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/
60+
## for the solver options
61+
sols = solve(ensemble_prob, Vern9(), EnsembleSerial(); reltol=1e-5,
62+
trajectories, isoutofdomain, dense=true, save_on=true)
63+
64+
### Visualization
65+
66+
f = Figure()
67+
ax = Axis3(f[1, 1],
68+
title = "5 keV Protons in a vacuum superposition magnetosphere",
69+
xlabel = "x [Re]",
70+
ylabel = "y [Re]",
71+
zlabel = "z [Re]",
72+
aspect = :data,
73+
)
74+
75+
invRE = 1 / Rₑ
76+
for sol in sols
77+
l = lines!(ax, sol)
78+
scale!(l, invRE, invRE, invRE)
79+
end
80+
81+
## Field lines
82+
function get_numerical_field(x, y, z)
83+
bx = zeros(length(x), length(y), length(z))
84+
by = similar(bx)
85+
bz = similar(bx)
86+
87+
for i in CartesianIndices(bx)
88+
pos = [x[i[1]], y[i[2]], z[i[3]]]
89+
bx[i], by[i], bz[i] = getB_superposition(pos)
90+
end
91+
92+
bx, by, bz
93+
end
94+
95+
function trace_field!(ax, x, y, z, unitscale)
96+
bx, by, bz = get_numerical_field(x, y, z)
97+
98+
zs = 0.0
99+
nr, nϕ = 8, 4
100+
= 2π /
101+
for r in range(8Rₑ, 16Rₑ, length=nr), ϕ in range(0, 2π-dϕ, length=nϕ)
102+
xs = r * cos(ϕ)
103+
ys = r * sin(ϕ)
104+
105+
x1, y1, z1 = FieldTracer.trace(bx, by, bz, xs, ys, zs, x, y, z; ds=0.1, maxstep=10000)
106+
107+
lines!(ax, x1.*unitscale, y1.*unitscale, z1.*unitscale, color=:gray)
108+
end
109+
end
110+
111+
x = range(-18Rₑ, 18Rₑ, length=50)
112+
y = range(-18Rₑ, 18Rₑ, length=50)
113+
z = range(-18Rₑ, 18Rₑ, length=50)
114+
115+
trace_field!(ax, x, y, z, invRE)
116+
117+
f = DisplayAs.PNG(f) #hide

docs/examples/basics/demo_currentsheet.jl docs/examples/advanced/demo_currentsheet.jl

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ using TestParticle
1616
using TestParticle: getB_CS_harris
1717
using OrdinaryDiffEq
1818
using StaticArrays
19-
using Statistics: mean
2019
using CairoMakie
2120
CairoMakie.activate!(type = "png")
2221

File renamed without changes.

docs/examples/basics/demo_magneticbottle.jl docs/examples/advanced/demo_magneticbottle.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ---
22
# title: Electron motion in a magnetic bottle
3-
# id: demo_proton_bottle
3+
# id: demo_electron_bottle
44
# date: 2023-04-20
55
# author: "[Hongyang Zhou](https://github.com/henry2004y)"
66
# julia: 1.9.0

docs/examples/basics/demo_magneticmirror.jl docs/examples/advanced/demo_magneticmirror.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function getE(xu)
4242
SA[0.0, 0.0, 0.0]
4343
end
4444

45-
## the velocity along with the direction perpendicular to the magnetic field
45+
## velocity in the direction perpendicular to the magnetic field
4646
function v_perp(xu)
4747
vu = @view xu[4:6]
4848
B = getB(xu)

docs/examples/basics/demo_proton_dipole.jl docs/examples/advanced/demo_proton_dipole.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import DisplayAs #hide
1313
using TestParticle
14-
using TestParticle: getB_dipole, getE_dipole, sph2cart, fieldline, mᵢ, qᵢ, c, Rₑ
14+
using TestParticle: getB_dipole, getE_dipole, sph2cart, dipole_fieldline, mᵢ, qᵢ, c, Rₑ
1515
using OrdinaryDiffEq
1616
using CairoMakie
1717
CairoMakie.activate!(type = "png")
@@ -48,7 +48,7 @@ l = lines!(ax, sol)
4848
scale!(l, invRE, invRE, invRE)
4949

5050
for ϕ in range(0, stop=2*π, length=10)
51-
lines!(fieldline(ϕ)..., color=:tomato, alpha=0.3)
51+
lines!(dipole_fieldline(ϕ)..., color=:tomato, alpha=0.3)
5252
end
5353

5454
f = DisplayAs.PNG(f) #hide
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,90 @@
1-
# ---
2-
# title: Tokamak profile
3-
# id: demo_tokamak_profile
4-
# date: 2023-04-20
5-
# author: "[Tiancheng Liu](https://github.com/TCLiuu)"
6-
# julia: 1.9.0
7-
# description: Tracing passing and trapped proton in a Tokamak
8-
# ---
9-
10-
# This example shows how to trace protons in a stationary magnetic field that
11-
# corresponds to an ITER-like Tokamak.
12-
13-
import DisplayAs #hide
14-
using TestParticle
15-
using TestParticle: getB_tokamak_profile
16-
using OrdinaryDiffEq
17-
using StaticArrays
18-
using GeometryBasics
19-
using CairoMakie
20-
CairoMakie.activate!(type = "png")
21-
22-
## parameters from ITER, see http://fusionwiki.ciemat.es/wiki/ITER
23-
const R₀ = 6.2 # Major radius [m]
24-
const Bζ0 = 5.3 # toroidal field on axis [T]
25-
const a = 2.0 # Minor radius [m]
26-
27-
## variable must be a radius normalized by minor radius.
28-
function q_profile(nr::Float64)
29-
return nr^2 + 2*nr + 0.5
30-
end
31-
32-
function B(xu)
33-
SVector{3}(getB_tokamak_profile(xu[1], xu[2], xu[3], q_profile, a, R₀, Bζ0))
34-
end
35-
36-
function E(xu)
37-
SA[0.0, 0.0, 0.0]
38-
end
39-
40-
# Passing proton in a Tokamak
41-
42-
## initial velocity for passing particle
43-
v₀ = [0.0, 2.15, 3.1] .* 1e6
44-
## initial position, [m]. where q≈2, (2, 1) flux surface.
45-
r₀ = [7.3622, 0.0, 0.0]
46-
stateinit = [r₀..., v₀...]
47-
48-
param = prepare(E, B; species=Proton)
49-
tspan = (0.0, 4e-5) # [s]
50-
51-
prob = ODEProblem(trace!, stateinit, tspan, param)
52-
sol = solve(prob, Vern7(); dt=2e-11)
53-
54-
fig1 = orbit(sol)
55-
## contruct the topology of Tokamak
56-
= LinRange(0, 2π, 30)
57-
= LinRange(0, 2π, 30)
58-
nx = [R₀*cos(ζ) + a*cos(θ)*cos(ζ) for θ in nθ, ζ in nζ]
59-
ny = [R₀*sin(ζ) + a*cos(θ)*sin(ζ) for θ in nθ, ζ in nζ]
60-
nz = [a*sin(θ) for θ in nθ, ζ in nζ]
61-
points = vec([Point3f(xv, yv, zv) for (xv, yv, zv) in zip(nx, ny, nz)])
62-
faces = decompose(QuadFace{GLIndex}, Tesselation(Rect(0, 0, 1, 1), size(nz)))
63-
tor_mesh = GeometryBasics.Mesh(points, faces)
64-
## plot the surface of Tokamak
65-
wireframe!(fig1[1, 1], tor_mesh, color=(:blue, 0.1), linewidth=0.5, transparency=true)
66-
Label(fig1[1, 1, Top()], "passing particle", padding = (0, 0, 10, 0), fontsize = 22)
67-
68-
fig1 = DisplayAs.PNG(fig1) #hide
69-
70-
# Trapped proton in a Tokamak that shows the banana orbit
71-
72-
## initial velocity for trapped particle
73-
v₀ = [0.0, 1.15, 5.1] .* 1e6
74-
## initial position, [m]. where q≈1, (1, 1) flux surface.
75-
r₀ = [6.6494, 0.0, 0.0]
76-
stateinit = [r₀..., v₀...]
77-
78-
param = prepare(E, B; species=Proton)
79-
tspan = (0.0, 4e-5)
80-
81-
prob = ODEProblem(trace!, stateinit, tspan, param)
82-
sol = solve(prob, Vern7(); dt=1e-11)
83-
84-
fig2 = orbit(sol)
85-
86-
wireframe!(fig2[1, 1], tor_mesh, color=(:blue, 0.1), linewidth=0.5, transparency=true)
87-
Label(fig2[1, 1, Top()], "trapped particle", padding = (0, 0, 10, 0), fontsize = 22)
88-
89-
## banana orbit
1+
# ---
2+
# title: Tokamak profile
3+
# id: demo_tokamak_profile
4+
# date: 2023-04-20
5+
# author: "[Tiancheng Liu](https://github.com/TCLiuu)"
6+
# julia: 1.9.0
7+
# description: Tracing passing and trapped proton in a Tokamak
8+
# ---
9+
10+
# This example shows how to trace protons in a stationary magnetic field that
11+
# corresponds to an ITER-like Tokamak.
12+
13+
import DisplayAs #hide
14+
using TestParticle
15+
using TestParticle: getB_tokamak_profile
16+
using OrdinaryDiffEq
17+
using StaticArrays
18+
using GeometryBasics
19+
using CairoMakie
20+
CairoMakie.activate!(type = "png")
21+
22+
## parameters from ITER, see http://fusionwiki.ciemat.es/wiki/ITER
23+
const R₀ = 6.2 # Major radius [m]
24+
const Bζ0 = 5.3 # toroidal field on axis [T]
25+
const a = 2.0 # Minor radius [m]
26+
27+
## variable must be a radius normalized by minor radius.
28+
function q_profile(nr::Float64)
29+
return nr^2 + 2*nr + 0.5
30+
end
31+
32+
function B(xu)
33+
SVector{3}(getB_tokamak_profile(xu[1], xu[2], xu[3], q_profile, a, R₀, Bζ0))
34+
end
35+
36+
function E(xu)
37+
SA[0.0, 0.0, 0.0]
38+
end
39+
40+
# Passing proton in a Tokamak
41+
42+
## initial velocity for passing particle
43+
v₀ = [0.0, 2.15, 3.1] .* 1e6
44+
## initial position, [m]. where q≈2, (2, 1) flux surface.
45+
r₀ = [7.3622, 0.0, 0.0]
46+
stateinit = [r₀..., v₀...]
47+
48+
param = prepare(E, B; species=Proton)
49+
tspan = (0.0, 4e-5) # [s]
50+
51+
prob = ODEProblem(trace!, stateinit, tspan, param)
52+
sol = solve(prob, Vern7(); dt=2e-11)
53+
54+
fig1 = orbit(sol)
55+
## contruct the topology of Tokamak
56+
= LinRange(0, 2π, 30)
57+
= LinRange(0, 2π, 30)
58+
nx = [R₀*cos(ζ) + a*cos(θ)*cos(ζ) for θ in nθ, ζ in nζ]
59+
ny = [R₀*sin(ζ) + a*cos(θ)*sin(ζ) for θ in nθ, ζ in nζ]
60+
nz = [a*sin(θ) for θ in nθ, ζ in nζ]
61+
points = vec([Point3f(xv, yv, zv) for (xv, yv, zv) in zip(nx, ny, nz)])
62+
faces = decompose(QuadFace{GLIndex}, Tesselation(Rect(0, 0, 1, 1), size(nz)))
63+
tor_mesh = GeometryBasics.Mesh(points, faces)
64+
## plot the surface of Tokamak
65+
wireframe!(fig1[1, 1], tor_mesh, color=(:blue, 0.1), linewidth=0.5, transparency=true)
66+
Label(fig1[1, 1, Top()], "passing particle", padding = (0, 0, 10, 0), fontsize = 22)
67+
68+
fig1 = DisplayAs.PNG(fig1) #hide
69+
70+
# Trapped proton in a Tokamak that shows the banana orbit
71+
72+
## initial velocity for trapped particle
73+
v₀ = [0.0, 1.15, 5.1] .* 1e6
74+
## initial position, [m]. where q≈1, (1, 1) flux surface.
75+
r₀ = [6.6494, 0.0, 0.0]
76+
stateinit = [r₀..., v₀...]
77+
78+
param = prepare(E, B; species=Proton)
79+
tspan = (0.0, 4e-5)
80+
81+
prob = ODEProblem(trace!, stateinit, tspan, param)
82+
sol = solve(prob, Vern7(); dt=1e-11)
83+
84+
fig2 = orbit(sol)
85+
86+
wireframe!(fig2[1, 1], tor_mesh, color=(:blue, 0.1), linewidth=0.5, transparency=true)
87+
Label(fig2[1, 1, Top()], "trapped particle", padding = (0, 0, 10, 0), fontsize = 22)
88+
89+
## banana orbit
9090
fig2 = DisplayAs.PNG(fig2) #hide

0 commit comments

Comments
 (0)