Skip to content

plasma_plots.theory.orbits

Charged-particle orbits: gyromotion, guiding-center drifts and trapped particles in a tokamak.

The formulas hold in any consistent units (SI, or Struphy’s normalized units with charge and mass in units of e and m_p) unless a function says otherwise. Vectors are arrays with a trailing axis of length 3, (x, y, z) or any right-handed Cartesian basis; everything broadcasts.

Examples

The bounce frequency of a barely trapped (κ² = 0.9) particle with v = 1 on the ε = 0.1 surface of a tokamak with q = 2 and R₀ = 3:

>>> print(f"{bounce_frequency(1.0, 0.9, 0.1, 2.0, 3.0):.5f}")
0.02271

Functions

NameDescription
banana_widthCompute the full radial width of a banana orbit, Δr = 2√2 q κ ρ / √ε.
bounce_frequencyCompute the bounce frequency of a trapped particle, ω_b = π v √(2ε) / (4 q R₀ K(κ²)).
exb_driftCompute the E×B drift velocity v_E = E × B / B².
grad_b_driftCompute the grad-B drift velocity v_∇B = (m v⊥² / (2q)) B × ∇B / B³.
gyrofrequencyCompute the gyrofrequency Ω = q|B|/m.
gyroradiusCompute the gyroradius ρ = m v⊥ / (|q| B).
magnetic_momentCompute the magnetic moment μ = m v⊥² / (2B), the adiabatic invariant of the gyromotion.
pitch_parameterCompute the pitch parameter λ = μB₀/E from the pitch v∥/v at the poloidal angle θ.
transit_frequencyCompute the poloidal transit frequency of a passing particle.
trapped_fractionCompute the effective fraction of trapped particles on a flux surface of a circular tokamak.
trapping_boundaryCompute the trapped–passing boundary on a flux surface.
trapping_parameterCompute the trapping parameter κ² = (1 + ε − λ) / (2ε).

banana_widthfunction#

def banana_width(gyroradius, kappa2, epsilon, safety_factor)

Compute the full radial width of a banana orbit, Δr = 2√2 q κ ρ / √ε.

From the conservation of the canonical toroidal momentum, the radial excursion is δr = q δv∥ / (ε Ω); v∥ swings between ±κ v √(2ε) at the outboard midplane. The width is largest near the trapped–passing boundary, 2√2 q ρ / √ε, the “q ρ / √ε” of scaling estimates, and vanishes for deeply trapped particles.

Parameters

NameTypeDescription
gyroradiusfloat or array_likeGyroradius ρ = m v / (|q| B₀) with the total speed v (for trapped particles v⊥ ≈ v).
kappa2float or array_likeTrapping parameter κ², 0 ≤ κ² ≤ 1.
epsilonfloat or array_likeInverse aspect ratio ε of the flux surface.
safety_factorfloat or array_likeSafety factor q of the flux surface.

Returns

float or numpy.ndarray
Δr, in the units of gyroradius; nan for passing particles (κ² > 1).

Examples

>>> print(f"{banana_width(0.01, 1.0, 0.1, 2.0):.4f}")
0.1789

bounce_frequencyfunction#

def bounce_frequency(speed, kappa2, epsilon, safety_factor, major_radius)

Compute the bounce frequency of a trapped particle, ω_b = π v √(2ε) / (4 q R₀ K(κ²)).

The period of the banana orbit is τ_b = 2π/ω_b = 8 q R₀ K(κ²) / (v √(2ε)), to leading order in ε. Deeply trapped particles (κ² = 0) bounce at ω_b = v √(ε/2) / (q R₀); ω_b → 0 logarithmically at the trapped–passing boundary κ² → 1.

Parameters

NameTypeDescription
speedfloat or array_likeThe particle speed v.
kappa2float or array_likeTrapping parameter κ² (see trapping_parameter()), 0 ≤ κ² < 1.
epsilonfloat or array_likeInverse aspect ratio ε of the flux surface.
safety_factorfloat or array_likeSafety factor q of the flux surface.
major_radiusfloat or array_likeMajor radius R₀.

Returns

float or numpy.ndarray
ω_b in rad per unit time; nan for passing particles (κ² > 1).

Examples

>>> # √(ε/2) deeply trapped
>>> print(f"{bounce_frequency(1.0, 0.0, 0.02, 1.0, 1.0):.4f}")
0.1000

exb_driftfunction#

def exb_drift(E, B)

Compute the E×B drift velocity v_E = E × B / B².

Parameters

NameTypeDescription
Earray_likeElectric field, shape (…, 3).
Barray_likeMagnetic field, shape (…, 3).

Returns

numpy.ndarray
v_E, shape (…, 3); independent of charge and mass, |v_E| = E⊥/B.

Raises

ValueError
If a vector has no trailing axis of length 3.

Examples

>>> print(exb_drift([1.0, 0.0, 0.0], [0.0, 0.0, 2.0]))
[ 0. -0.5 0. ]

grad_b_driftfunction#

def grad_b_drift(perpendicular_speed, B, grad_B, charge=1.0, mass=1.0)

Compute the grad-B drift velocity v_∇B = (m v⊥² / (2q)) B × ∇B / B³.

Parameters

NameTypeDefaultDescription
perpendicular_speedfloat or array_likerequiredThe speed v⊥ perpendicular to B.
Barray_likerequiredMagnetic field, shape (…, 3).
grad_Barray_likerequiredGradient of the field strength ∇|B|, shape (…, 3).
chargefloat or array_like1.0Charge q; ions and electrons drift in opposite directions. Default: 1.
massfloat or array_like1.0Mass m. Default: 1.

Returns

numpy.ndarray
v_∇B, shape (…, 3).

Raises

ValueError
If a vector has no trailing axis of length 3.

Examples

>>> # B along z, ∇B along x
>>> print(grad_b_drift(1.0, [0.0, 0.0, 1.0], [0.1, 0.0, 0.0]))
[0. 0.05 0. ]

gyrofrequencyfunction#

def gyrofrequency(field, charge=1.0, mass=1.0)

Compute the gyrofrequency Ω = q|B|/m.

Parameters

NameTypeDefaultDescription
fieldfloat or array_likerequiredMagnetic field strength |B| (its sign doesn’t matter).
chargefloat or array_like1.0Charge q; Ω has its sign (negative for electrons). Default: 1.
massfloat or array_like1.0Mass m. Default: 1.

Returns

float or numpy.ndarray
Ω, in rad per unit time (a particle with q > 0 gyrates clockwise when viewed along B).

Examples

>>> print(gyrofrequency(2.0, charge=-1.0, mass=0.5))
-4.0

gyroradiusfunction#

def gyroradius(perpendicular_speed, field, charge=1.0, mass=1.0)

Compute the gyroradius ρ = m v⊥ / (|q| B).

Parameters

NameTypeDefaultDescription
perpendicular_speedfloat or array_likerequiredThe speed v⊥ perpendicular to B.
fieldfloat or array_likerequiredMagnetic field strength |B|.
chargefloat or array_like1.0Charge q (its sign doesn’t matter). Default: 1.
massfloat or array_like1.0Mass m. Default: 1.

Returns

float or numpy.ndarray
ρ (positive).

Examples

>>> print(gyroradius(3.0, 2.0))
1.5

magnetic_momentfunction#

def magnetic_moment(perpendicular_speed, field, mass=1.0)

Compute the magnetic moment μ = m v⊥² / (2B), the adiabatic invariant of the gyromotion.

Parameters

NameTypeDefaultDescription
perpendicular_speedfloat or array_likerequiredThe speed v⊥ perpendicular to B.
fieldfloat or array_likerequiredMagnetic field strength |B|.
massfloat or array_like1.0Mass m. Default: 1.

Returns

float or numpy.ndarray
μ.

Examples

>>> print(magnetic_moment(2.0, 4.0, mass=2.0))
1.0

pitch_parameterfunction#

def pitch_parameter(pitch, epsilon, theta=0.0)

Compute the pitch parameter λ = μB₀/E from the pitch v∥/v at the poloidal angle θ.

λ = (1 − (v∥/v)²) B₀/B(θ) = (1 − (v∥/v)²)(1 + ε cos θ).

Parameters

NameTypeDefaultDescription
pitchfloat or array_likerequiredv∥/v, between −1 and 1, at the angle theta.
epsilonfloat or array_likerequiredInverse aspect ratio ε of the flux surface.
thetafloat or array_like0.0Poloidal angle θ where the pitch is given (0: outboard midplane). Default: 0.

Returns

float or numpy.ndarray
λ.

Examples

>>> print(f"{pitch_parameter(0.3, 0.1):.4f}")
1.0010

transit_frequencyfunction#

def transit_frequency(speed, kappa2, epsilon, safety_factor, major_radius)

Compute the poloidal transit frequency of a passing particle.

ω_t = π κ v √(2ε) / (2 q R₀ K(1/κ²)), to leading order in ε: 2π/ω_t is the time for one poloidal turn. Far from the boundary (κ² ≫ 1) it tends to |v∥| / (q R₀); ω_t → 0 logarithmically at κ² → 1.

Parameters

NameTypeDescription
speedfloat or array_likeThe particle speed v.
kappa2float or array_likeTrapping parameter κ² (see trapping_parameter()), κ² > 1.
epsilonfloat or array_likeInverse aspect ratio ε of the flux surface.
safety_factorfloat or array_likeSafety factor q of the flux surface.
major_radiusfloat or array_likeMajor radius R₀.

Returns

float or numpy.ndarray
ω_t in rad per unit time; nan for trapped particles (κ² < 1).

Examples

>>> # ≈ v∥/(qR₀) = 1
>>> print(f"{transit_frequency(1.0, 50.0, 0.01, 1.0, 1.0):.4f}")
0.9950

trapped_fractionfunction#

def trapped_fraction(epsilon, approximation='exact')

Compute the effective fraction of trapped particles on a flux surface of a circular tokamak.

f_t = 1 − (3/4) ⟨B²⟩ ∫₀^{1/B_max} λ dλ / ⟨√(1 − λB)⟩ with B = B₀/(1 + ε cos θ) and the flux-surface average ⟨A⟩ = ∮ A (1 + ε cos θ) dθ / 2π, the fraction that enters neoclassical transport (bootstrap current, neoclassical resistivity).

Parameters

NameTypeDefaultDescription
epsilonfloat or array_likerequiredInverse aspect ratio ε = r/R₀ of the flux surface, 0 ≤ ε < 1.
approximation('exact', 'lin-liu', 'sqrt')"exact""exact": the integral above, by quadrature (relative accuracy 1e-8 or better for ε ≥ 1e-8); "lin-liu": Lin-Liu and Miller’s fit 1 − (1 − ε)² / (√(1 − ε²) (1 + 1.46 √ε)), within a few per cent at any ε; "sqrt": the small-ε limit 1.46 √ε. Default: "exact".

Returns

float or numpy.ndarray
f_t, 0 at ε = 0 and 1 at ε = 1.

Raises

ValueError
If approximation is unknown.

Examples

>>> fractions = [
... trapped_fraction(0.1, a) for a in ("exact", "lin-liu", "sqrt")
... ]
>>> print(", ".join(f"{f:.4f}" for f in fractions))
0.4492, 0.4431, 0.4617

trapping_boundaryfunction#

def trapping_boundary(epsilon, quantity='lambda', theta=0.0)

Compute the trapped–passing boundary on a flux surface.

Particles with λ = μB₀/E > λ_c = B₀/B_max = 1 − ε are trapped, equivalently those with a pitch |v∥/v| < √(1 − (1 − ε)/(1 + ε cos θ)) at the angle θ (√(2ε/(1 + ε)) on the outboard midplane).

Parameters

NameTypeDefaultDescription
epsilonfloat or array_likerequiredInverse aspect ratio ε of the flux surface.
quantity('lambda', 'pitch')"lambda""lambda": the critical λ_c; "pitch": the critical |v∥/v| at theta. Default: "lambda".
thetafloat or array_like0.0Poloidal angle for quantity="pitch". Default: 0.

Returns

float or numpy.ndarray
λ_c or the critical pitch.

Raises

ValueError
If quantity is unknown.

Examples

>>> print(
... f"{trapping_boundary(0.1):.2f}, {trapping_boundary(0.1, 'pitch'):.4f}"
... )
0.90, 0.4264

trapping_parameterfunction#

def trapping_parameter(lam, epsilon)

Compute the trapping parameter κ² = (1 + ε − λ) / (2ε).

κ² < 1 for trapped particles, which bounce at sin²(θ/2) = κ²; κ² = 0 for particles deeply trapped at θ = 0 (λ = 1 + ε), κ² = 1 on the trapped–passing boundary (λ = 1 − ε) and κ² > 1 for passing ones.

Parameters

NameTypeDescription
lamfloat or array_likePitch parameter λ = μB₀/E (see pitch_parameter()).
epsilonfloat or array_likeInverse aspect ratio ε > 0 of the flux surface.

Returns

float or numpy.ndarray
κ².

Examples

>>> print(f"{trapping_parameter(1.0, 0.1):.2f}")
0.50