Skip to content

plasma_plots.theory.kinetic

Kinetic dispersion relations of unmagnetized plasmas: Langmuir waves and Landau damping, ion-acoustic waves, beam-plasma, two-stream and bump-on-tail instabilities, and the Weibel instability.

Examples

>>> omega = langmuir(0.5)
>>> round(omega.real, 6), round(omega.imag, 6)
(1.415662, -0.153359)

Attributes

NameDescription
PROTON_ELECTRON_MASS_RATIONo description.

Classes

NameDescription
MaxwellianA drifting Maxwellian species, in the normalized units of this module.

Functions

NameDescription
beam_plasma_coldCompute the cold beam-plasma frequencies: the roots of a quartic.
bohm_grossCompute the Bohm–Gross frequency ω = √(1 + 3k²) of Langmuir waves.
bump_on_tailCompute the most unstable kinetic root of a bump-on-tail distribution.
electrostatic_dielectricCompute the electrostatic dielectric function ε(ω, k) = 1 + Σ_s χ_s of Maxwellian species.
ion_acousticCompute the kinetic ion-acoustic root of Maxwellian electrons and ions.
ion_acoustic_fluidCompute the fluid ion-acoustic frequency with Boltzmann electrons and adiabatic ions.
landau_damping_weakCompute the weak-damping approximation of Langmuir waves: Bohm–Gross plus Landau damping.
langmuirCompute the exact kinetic Langmuir root: the least-damped zero of ε(ω, k) near Bohm–Gross.
maximum_growthFind the wavenumber of maximum growth rate of a dispersion relation.
solve_dispersionFind a complex root ω(k) of a dispersion relation for every wavenumber.
susceptibilityCompute the electrostatic susceptibility χ_s(ω, k) of one Maxwellian species.
two_streamCompute the kinetic purely growing root of two warm counter-streaming electron beams.
two_stream_coldCompute the cold symmetric two-stream frequencies in closed form.
weibelCompute the purely growing (or damped) root of the electron Weibel instability.

PROTON_ELECTRON_MASS_RATIOattributemodule attribute#

PROTON_ELECTRON_MASS_RATIO = 1836.15267343

Maxwellianclassdataclass#

class Maxwellian(density: float = 1.0, charge: float = -1.0, mass: float = 1.0, thermal_speed: float = 1.0, drift: float = 0.0)

A drifting Maxwellian species, in the normalized units of this module.

f(v) = n/(√(2π) v_th) exp(−(v − u)²/(2 v_th²)). The fields may also be arrays that broadcast against the wavenumbers.

Attributes

NameTypeDescription
densityfloatThe density n_s, relative to the reference electron density. Default: 1.0.
chargefloatThe charge q_s in units of e. Default: -1.0 (electrons).
massfloatThe mass m_s in units of m_e. Default: 1.0.
thermal_speedfloatThe thermal speed v_th,s = √(T_s/m_s) in units of v_the, positive. Default: 1.0.
driftfloatThe drift speed u_s in units of v_the. Default: 0.0.

Examples

>>> Maxwellian().plasma_frequency
1.0
>>> beam = Maxwellian(density=0.1, thermal_speed=0.5, drift=4.5)
>>> round(float(beam.plasma_frequency), 4)
0.3162

chargeattributeclass attributeinstance attribute#

charge: float = -1.0

densityattributeclass attributeinstance attribute#

density: float = 1.0

driftattributeclass attributeinstance attribute#

drift: float = 0.0

massattributeclass attributeinstance attribute#

mass: float = 1.0

thermal_speedattributeclass attributeinstance attribute#

thermal_speed: float = 1.0

plasma_frequencyproperty#

plasma_frequency

The plasma frequency ω_ps = √(n_s q_s²/m_s), in units of ω_pe.

ionsmethodclassmethod#

def ions(mass_ratio=PROTON_ELECTRON_MASS_RATIO, temperature_ratio=1.0, charge=1.0, drift=0.0)

Create quasi-neutral ions for the reference electrons.

Parameters

NameTypeDefaultDescription
mass_ratiofloatPROTON_ELECTRON_MASS_RATIOm_i/m_e. Default: the proton mass ratio, 1836.15.
temperature_ratiofloat1.0T_e/T_i. Default: 1.0.
chargefloat1.0The charge number Z; the density is 1/Z. Default: 1.0.
driftfloat0.0The drift speed in units of v_the. Default: 0.0.

Returns

Maxwellian
Ions with thermal speed √(T_i/m_i) = 1/√(mass_ratio · temperature_ratio) in units of v_the.

Examples

>>> ions = Maxwellian.ions(mass_ratio=100.0, temperature_ratio=4.0)
>>> ions.thermal_speed, round(float(ions.plasma_frequency), 4)
(0.05, 0.1)

beam_plasma_coldfunction#

def beam_plasma_cold(k, beam_speed, beam_density=0.1, plasma_density=1.0, all_roots=False)

Compute the cold beam-plasma frequencies: the roots of a quartic.

A cold electron beam of density n_b at speed v_b through a cold plasma of density n_p (immobile ions): 1 = n_p/ω² + n_b/(ω − k v_b)², i.e. ω⁴ − 2kv_b ω³ + (k²v_b² − n_p − n_b) ω² + 2kv_b n_p ω − n_p k²v_b² = 0. For n_b ≪ n_p the maximum growth is γ ≈ (√3/2)(n_b/(2 n_p))^(1/3) √n_p at k v_b ≈ √n_p.

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De (any length unit L works, with speeds in ω_pe L).
beam_speedfloat or array_likerequiredv_b.
beam_densityfloat or array_like0.1n_b. Default: 0.1.
plasma_densityfloat or array_like1.0n_p. Default: 1.0.
all_rootsboolFalseReturn all four roots, sorted by real part. Default: False.

Returns

complex or numpy.ndarray
The root with the largest imaginary part where it is unstable, else the real root closest to the slow beam mode k v_b − √n_b. With all_roots, an extra last axis of length 4.

Examples

>>> omega = beam_plasma_cold(1.0, beam_speed=1.0, beam_density=0.001)
>>> round(omega.real, 4), round(omega.imag, 4)
(0.9588, 0.066)

bohm_grossfunction#

def bohm_gross(k)

Compute the Bohm–Gross frequency ω = √(1 + 3k²) of Langmuir waves.

The fluid (adiabatic, γ = 3) Langmuir frequency, the real part of langmuir() for k λ_De ≪ 1.

Parameters

NameTypeDescription
kfloat or array_likeThe wavenumber in units of 1/λ_De.

Returns

complex or numpy.ndarray
ω in units of ω_pe (real-valued).

Examples

>>> bohm_gross(0.0)
(1+0j)
>>> round(bohm_gross(0.5).real, 4)
1.3229

bump_on_tailfunction#

def bump_on_tail(k, beam_density=0.1, beam_speed=4.5, beam_thermal_speed=0.5, bulk_density=None)

Compute the most unstable kinetic root of a bump-on-tail distribution.

A Maxwellian bulk (density n_0, thermal speed 1, at rest) plus a Maxwellian beam (n_b, v_b, v_th,b) over immobile ions. Newton is started from the Bohm–Gross frequency and from phase speeds across the beam (k·v for v from v_b − 3 v_th,b to v_b + v_th,b), and the root with the largest imaginary part is returned: the growing Langmuir/beam mode where the bump makes the distribution unstable (phase speed on its rising flank), the least damped root found where not. For k < 0 the roots are those of |k| mirrored, ω → −conj ω.

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De, nonzero.
beam_densityfloat or array_like0.1n_b. Default: 0.1.
beam_speedfloat or array_like4.5v_b in units of v_the. Default: 4.5.
beam_thermal_speedfloat or array_like0.5v_th,b in units of v_the, positive. Default: 0.5.
bulk_densityfloat or array_likeNonen_0. Default: 1 − n_b, so the total electron density is 1.

Returns

complex or numpy.ndarray
ω in units of ω_pe; nan if no guess converged.

Examples

>>> omega = bump_on_tail(0.3)
>>> round(omega.real, 4), round(omega.imag, 4)
(1.0012, 0.1981)

electrostatic_dielectricfunction#

def electrostatic_dielectric(omega, k, species=None, derivative=0)

Compute the electrostatic dielectric function ε(ω, k) = 1 + Σ_s χ_s of Maxwellian species.

Its zeros are the electrostatic (Langmuir, ion-acoustic, beam) modes.

Parameters

NameTypeDefaultDescription
omegacomplex or array_likerequiredThe complex frequency in units of ω_pe.
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De, nonzero.
speciesMaxwellian or sequence of MaxwellianNoneThe mobile species. Default: the reference electrons, Maxwellian(), with immobile ions.
derivative(0, 1)00 for ε, 1 for ∂ε/∂ω. Default: 0.

Returns

complex or numpy.ndarray
ε or ∂ε/∂ω, broadcast over omega, k and the species fields.

Examples

>>> abs(electrostatic_dielectric(langmuir(0.3), 0.3)) < 1e-10
True

ion_acousticfunction#

def ion_acoustic(k, temperature_ratio=10.0, mass_ratio=PROTON_ELECTRON_MASS_RATIO)

Compute the kinetic ion-acoustic root of Maxwellian electrons and ions.

The zero of ε = 1 + χ_e + χ_i with the reference electrons and ions of Maxwellian.ions(), damped by electron and ion Landau damping. It is continued from k λ_De = 0.01 and T_e/T_i = max(τ, 30), seeded with the fluid frequency and the weak damping γ/ω = −√(π/8) (√(m_e/m_i) + τ^(3/2) exp(−τ/2 − 3/2)) (Chen, eq. 7.144).

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De, positive (ω(−k) = −conj ω(k)).
temperature_ratiofloat or array_like10.0τ = T_e/T_i. Default: 10.0.
mass_ratiofloat or array_likePROTON_ELECTRON_MASS_RATIOμ = m_i/m_e. Default: the proton mass ratio, 1836.15.

Returns

complex or numpy.ndarray
ω in units of ω_pe; nan where the root was lost.

Examples

>>> omega = ion_acoustic(0.1, temperature_ratio=10.0, mass_ratio=100.0)
>>> round(omega.real, 5), round(omega.imag, 5)
(0.01178, -0.00076)

ion_acoustic_fluidfunction#

def ion_acoustic_fluid(k, temperature_ratio=10.0, mass_ratio=PROTON_ELECTRON_MASS_RATIO, adiabatic_index=3.0)

Compute the fluid ion-acoustic frequency with Boltzmann electrons and adiabatic ions.

ω² = k² (T_e/(1 + k² λ_De²) + γ_i T_i)/m_i, i.e. in normalized units ω = k √((1/(1 + k²) + γ_i/τ)/μ) with τ = T_e/T_i and μ = m_i/m_e; for k λ_De ≪ 1, ω = k c_s with c_s = √((T_e + γ_i T_i)/m_i).

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De.
temperature_ratiofloat or array_like10.0τ = T_e/T_i. Default: 10.0.
mass_ratiofloat or array_likePROTON_ELECTRON_MASS_RATIOμ = m_i/m_e. Default: the proton mass ratio, 1836.15.
adiabatic_indexfloat3.0γ_i of the ions. Default: 3.0 (one-dimensional adiabatic compression).

Returns

complex or numpy.ndarray
ω in units of ω_pe (real-valued).

Examples

>>> round(
... ion_acoustic_fluid(0.1, temperature_ratio=10.0, mass_ratio=100.0).real,
... 5,
... )
0.01136

landau_damping_weakfunction#

def landau_damping_weak(k)

Compute the weak-damping approximation of Langmuir waves: Bohm–Gross plus Landau damping.

ω = √(1 + 3k²) − i √(π/8) k⁻³ exp(−1/(2k²) − 3/2), the textbook expansion for k λ_De ≪ 1 (Chen, eq. 7.133). It overestimates the damping at moderate k (by ~60 % at k = 0.3); use langmuir() for the exact root.

Parameters

NameTypeDescription
kfloat or array_likeThe wavenumber in units of 1/λ_De, nonzero.

Returns

complex or numpy.ndarray
ω in units of ω_pe.

Examples

>>> omega = landau_damping_weak(0.2)
>>> round(omega.real, 4), round(omega.imag, 7)
(1.0583, -6.51e-05)

langmuirfunction#

def langmuir(k)

Compute the exact kinetic Langmuir root: the least-damped zero of ε(ω, k) near Bohm–Gross.

Electrons (Maxwellian, v_th = 1) with immobile ions. The root is continued in k from k λ_De = 0.1, where the weak-damping approximation is accurate.

Parameters

NameTypeDescription
kfloat or array_likeThe wavenumber in units of 1/λ_De.

Returns

complex or numpy.ndarray
ω in units of ω_pe, with ω(−k) = ω(k) and ω(0) = 1; nan where the root was lost.

Examples

>>> omega = langmuir([0.3, 0.4, 0.5, 1.0])
>>> np.round(omega, 4)
array([1.1598-0.0126j, 1.2851-0.0661j, 1.4157-0.1534j, 2.0459-0.8513j])

maximum_growthfunction#

def maximum_growth(function, k_range, samples=64, tol=1e-08)

Find the wavenumber of maximum growth rate of a dispersion relation.

function is sampled at samples points across k_range, and the largest Im ω is refined by golden-section search between the neighbours of the best sample.

Parameters

NameTypeDefaultDescription
functioncallablerequiredfunction(k) returning the complex ω for an array of wavenumbers, e.g. bump_on_tail() or lambda k: two_stream(k, 3.0, 0.3).
k_range(float, float)requiredThe interval of wavenumbers searched.
samplesint64The number of samples of the initial scan. Default: 64.
tolfloat1e-08The absolute tolerance in k of the refinement. Default: 1e-8.

Returns

tuple of (float, complex)
The wavenumber of maximum growth and ω there.

Raises

ValueError
If function returns no finite value on the scan.

Examples

>>> k, omega = maximum_growth(lambda k: two_stream_cold(k, 1.0), (0.01, 1.4))
>>> round(k, 5), round(omega.imag, 6) # √(3/8), √0.5/2
(0.61237, 0.353553)

solve_dispersionfunction#

def solve_dispersion(function, k, guess, derivative=None, continuation=True, tol=1e-11, maxiter=60)

Find a complex root ω(k) of a dispersion relation for every wavenumber.

Damped Newton iteration in ω, with the analytic derivative when one is given and a central difference otherwise. With continuation, the wavenumbers are solved in the given order and each root seeds the next (linearly extrapolated from the last two), which follows one branch along a k-grid; otherwise every k starts from guess and all are solved at once.

Parameters

NameTypeDefaultDescription
functioncallablerequiredfunction(omega, k), analytic in ω, whose zero is sought, e.g. lambda w, k: electrostatic_dielectric(w, k, species). It must broadcast over arrays.
kfloat or array_likerequiredThe wavenumbers; one-dimensional with continuation, else any shape.
guesscomplex or array_likerequiredThe starting frequency: a scalar for the first k with continuation, else anything that broadcasts against k.
derivativecallableNonederivative(omega, k), the ω-derivative of function. Default: a central difference.
continuationboolTrueContinue the root along k. Default: True.
tolfloat1e-11Converged once the Newton step is below tol · |ω|. Default: 1e-11.
maxiterint60The maximum number of Newton steps per wavenumber. Default: 60.

Returns

complex or numpy.ndarray
ω for every k, nan where Newton did not converge (no exception is raised); with continuation the next wavenumber is then seeded by the last converged root.

Raises

ValueError
With continuation, if k has more than one dimension or guess is not a scalar.

Examples

The Langmuir branch followed from k = 0.2 to 0.5:

>>> k = np.linspace(0.2, 0.5, 7)
>>> omega = solve_dispersion(electrostatic_dielectric, k, guess=1.06)
>>> round(complex(omega[-1]).real, 4), round(complex(omega[-1]).imag, 4)
(1.4157, -0.1534)

susceptibilityfunction#

def susceptibility(omega, k, species, derivative=0)

Compute the electrostatic susceptibility χ_s(ω, k) of one Maxwellian species.

χ_s = (ω_ps²/(k² v_th,s²)) [1 + ζ_s Z(ζ_s)], with ζ_s = (ω − k u_s)/(√2 |k| v_th,s) and Z the plasma dispersion function (Landau’s continuation, valid for any complex ω). For a negative k the drift enters as k u_s, so χ_s(ω, −k) is χ_s(ω, k) with the drift reversed.

Parameters

NameTypeDefaultDescription
omegacomplex or array_likerequiredThe complex frequency in units of ω_pe.
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De, nonzero.
speciesMaxwellianrequiredThe species.
derivative(0, 1)00 for χ_s, 1 for ∂χ_s/∂ω. Default: 0.

Returns

complex or numpy.ndarray
χ_s or ∂χ_s/∂ω, broadcast over omega, k and the species fields.

Raises

ValueError
If derivative is not 0 or 1.

Examples

The cold limit χ → −ω_p²/ω²:

>>> round(susceptibility(10.0, 0.01, Maxwellian()).real, 6)
-0.01

two_streamfunction#

def two_stream(k, beam_speed, thermal_speed, beam_density=0.5)

Compute the kinetic purely growing root of two warm counter-streaming electron beams.

Two Maxwellian electron beams of density n_b and thermal speed v_t at ±v_b over immobile ions. By symmetry ε(iγ, k) is real, and the two-stream instability is purely growing, ω = iγ: it exists where ε(0, k) < 0, and γ is the largest zero of ε(iγ, k), found by a scan and bisection. Where the beams are stable, the least damped root reached by Newton from phase speeds between 0 and v_b is returned instead, with Re ω ≥ 0 (−conj ω is a root too): past the marginal wavenumber the growing root iγ meets its mirror −iγ near γ = 0 and turns into a weakly damped oscillating pair, so γ(k) stays continuous. For v_t → 0 the growth approaches two_stream_cold().

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De (ω(−k) = ω(k)).
beam_speedfloat or array_likerequiredv_b in units of v_the.
thermal_speedfloat or array_likerequiredv_t of each beam in units of v_the, positive.
beam_densityfloat or array_like0.5n_b, each beam’s density. Default: 0.5, so the total density is 1.

Returns

complex or numpy.ndarray
ω in units of ω_pe: iγ where unstable; nan where stable and Newton found no root.

Examples

>>> omega = two_stream(0.2, beam_speed=3.0, thermal_speed=0.3)
>>> round(omega.real, 6), round(omega.imag, 4)
(0.0, 0.3491)

two_stream_coldfunction#

def two_stream_cold(k, beam_speed, beam_density=0.5, all_roots=False)

Compute the cold symmetric two-stream frequencies in closed form.

Two cold electron beams of density n_b each at ±v_b over immobile ions: 1 = n_b/(ω − k v_b)² + n_b/(ω + k v_b)², a quadratic in ω² with the roots ω² = k²v_b² + n_b ± √(4 n_b k² v_b² + n_b²). The “slow” root ω² < 0, i.e. the purely growing ω = iγ, exists for k² v_b² < 2 n_b; the maximum growth is γ = √n_b/2 at k² v_b² = 3 n_b/4.

Parameters

NameTypeDefaultDescription
kfloat or array_likerequiredThe wavenumber in units of 1/λ_De (any length unit L works, with speeds in ω_pe L).
beam_speedfloat or array_likerequiredv_b, each beam’s speed.
beam_densityfloat or array_like0.5n_b, each beam’s density (its ω_pb²). Default: 0.5, so the total density is 1.
all_rootsboolFalseReturn all four roots instead of the slow one. Default: False.

Returns

complex or numpy.ndarray
The slow root √(ω₋²) with Im ω ≥ 0: iγ where unstable, the real slow beam mode where stable. With all_roots, an extra last axis of length 4: (√(ω₊²), −√(ω₊²), √(ω₋²), −√(ω₋²)).

Examples

>>> omega = two_stream_cold(np.sqrt(3 / 8), beam_speed=1.0)
>>> round(omega.real, 6), round(omega.imag, 6)
(0.0, 0.353553)

weibelfunction#

def weibel(k, anisotropy, parallel_thermal_speed)

Compute the purely growing (or damped) root of the electron Weibel instability.

Transverse electromagnetic waves along k ∥ z in bi-Maxwellian electrons (T⊥ across k, T∥ along k) with immobile ions:

ω² − k²c² − ω_pe² + ω_pe² A [1 + ζ Z(ζ)] = 0, A = T⊥/T∥, ζ = ω/(√2 k v_∥),

with v_∥ = √(T∥/m_e). It reduces to light waves ω² = ω_pe² + k²c² for T → 0. The root is ω = iγ, with γ > 0 exactly for k²c² < (A − 1) ω_pe² and γ < 0 (a damped, non-oscillating mode) beyond; γ is found by bisection of the real function D(iγ), which decreases in γ. Near the cutoff γ ≈ √(2/π) k v_∥ (A − 1 − k²c²/ω_pe²)/A.

Units: unlike the rest of this module, k in ω_pe/c, ω in ω_pe and speeds in c.

Parameters

NameTypeDescription
kfloat or array_likeThe wavenumber in units of ω_pe/c (ω(−k) = ω(k), ω(0) = 0).
anisotropyfloat or array_likeA = T⊥/T∥, positive; unstable for A > 1.
parallel_thermal_speedfloat or array_likev_∥ = √(T∥/m_e) in units of c, positive.

Returns

complex or numpy.ndarray
ω = iγ in units of ω_pe.

Examples

>>> round(weibel(1.0, anisotropy=4.0, parallel_thermal_speed=0.1).imag, 4)
0.061
>>> weibel(
... np.sqrt(3.0), anisotropy=4.0, parallel_thermal_speed=0.1
... ).imag < 1e-12
True