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
| Name | Description |
|---|---|
PROTON_ELECTRON_MASS_RATIO | No description. |
Classes
| Name | Description |
|---|---|
Maxwellian | A drifting Maxwellian species, in the normalized units of this module. |
Functions
| Name | Description |
|---|---|
beam_plasma_cold | Compute the cold beam-plasma frequencies: the roots of a quartic. |
bohm_gross | Compute the Bohm–Gross frequency ω = √(1 + 3k²) of Langmuir waves. |
bump_on_tail | Compute the most unstable kinetic root of a bump-on-tail distribution. |
electrostatic_dielectric | Compute the electrostatic dielectric function ε(ω, k) = 1 + Σ_s χ_s of Maxwellian species. |
ion_acoustic | Compute the kinetic ion-acoustic root of Maxwellian electrons and ions. |
ion_acoustic_fluid | Compute the fluid ion-acoustic frequency with Boltzmann electrons and adiabatic ions. |
landau_damping_weak | Compute the weak-damping approximation of Langmuir waves: Bohm–Gross plus Landau damping. |
langmuir | Compute the exact kinetic Langmuir root: the least-damped zero of ε(ω, k) near Bohm–Gross. |
maximum_growth | Find the wavenumber of maximum growth rate of a dispersion relation. |
solve_dispersion | Find a complex root ω(k) of a dispersion relation for every wavenumber. |
susceptibility | Compute the electrostatic susceptibility χ_s(ω, k) of one Maxwellian species. |
two_stream | Compute the kinetic purely growing root of two warm counter-streaming electron beams. |
two_stream_cold | Compute the cold symmetric two-stream frequencies in closed form. |
weibel | Compute the purely growing (or damped) root of the electron Weibel instability. |
PROTON_ELECTRON_MASS_RATIOattributemodule attribute#
PROTON_ELECTRON_MASS_RATIO = 1836.15267343Maxwellianclassdataclass#
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
| Name | Type | Description |
|---|---|---|
density | float | The density n_s, relative to the reference electron density. Default: 1.0. |
charge | float | The charge q_s in units of e. Default: -1.0 (electrons). |
mass | float | The mass m_s in units of m_e. Default: 1.0. |
thermal_speed | float | The thermal speed v_th,s = √(T_s/m_s) in units of v_the, positive. Default: 1.0. |
drift | float | The drift speed u_s in units of v_the. Default: 0.0. |
Examples
>>> Maxwellian().plasma_frequency1.0>>> beam = Maxwellian(density=0.1, thermal_speed=0.5, drift=4.5)>>> round(float(beam.plasma_frequency), 4)0.3162chargeattributeclass attributeinstance attribute#
charge: float = -1.0densityattributeclass attributeinstance attribute#
density: float = 1.0driftattributeclass attributeinstance attribute#
drift: float = 0.0massattributeclass attributeinstance attribute#
mass: float = 1.0thermal_speedattributeclass attributeinstance attribute#
thermal_speed: float = 1.0plasma_frequencyproperty#
plasma_frequencyThe 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
| Name | Type | Default | Description |
|---|---|---|---|
mass_ratio | float | PROTON_ELECTRON_MASS_RATIO | m_i/m_e. Default: the proton mass ratio, 1836.15. |
temperature_ratio | float | 1.0 | T_e/T_i. Default: 1.0. |
charge | float | 1.0 | The charge number Z; the density is 1/Z. Default: 1.0. |
drift | float | 0.0 | The 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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De (any length unit L works, with speeds in ω_pe L). |
beam_speed | float or array_like | required | v_b. |
beam_density | float or array_like | 0.1 | n_b. Default: 0.1. |
plasma_density | float or array_like | 1.0 | n_p. Default: 1.0. |
all_roots | bool | False | Return 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
| Name | Type | Description |
|---|---|---|
k | float or array_like | The 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.3229bump_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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De, nonzero. |
beam_density | float or array_like | 0.1 | n_b. Default: 0.1. |
beam_speed | float or array_like | 4.5 | v_b in units of v_the. Default: 4.5. |
beam_thermal_speed | float or array_like | 0.5 | v_th,b in units of v_the, positive. Default: 0.5. |
bulk_density | float or array_like | None | n_0. Default: 1 − n_b, so the total electron density is 1. |
Returns
complex or numpy.ndarray- ω in units of ω_pe;
nanif 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
| Name | Type | Default | Description |
|---|---|---|---|
omega | complex or array_like | required | The complex frequency in units of ω_pe. |
k | float or array_like | required | The wavenumber in units of 1/λ_De, nonzero. |
species | Maxwellian or sequence of Maxwellian | None | The mobile species. Default: the reference electrons, Maxwellian(), with immobile
ions. |
derivative | (0, 1) | 0 | 0 for ε, 1 for ∂ε/∂ω. Default: 0. |
Returns
complex or numpy.ndarray- ε or ∂ε/∂ω, broadcast over
omega,kand the species fields.
Examples
>>> abs(electrostatic_dielectric(langmuir(0.3), 0.3)) < 1e-10Trueion_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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De, positive (ω(−k) = −conj ω(k)). |
temperature_ratio | float or array_like | 10.0 | τ = T_e/T_i. Default: 10.0. |
mass_ratio | float or array_like | PROTON_ELECTRON_MASS_RATIO | μ = m_i/m_e. Default: the proton mass ratio, 1836.15. |
Returns
complex or numpy.ndarray- ω in units of ω_pe;
nanwhere 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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De. |
temperature_ratio | float or array_like | 10.0 | τ = T_e/T_i. Default: 10.0. |
mass_ratio | float or array_like | PROTON_ELECTRON_MASS_RATIO | μ = m_i/m_e. Default: the proton mass ratio, 1836.15. |
adiabatic_index | float | 3.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.01136landau_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
| Name | Type | Description |
|---|---|---|
k | float or array_like | The 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
| Name | Type | Description |
|---|---|---|
k | float or array_like | The wavenumber in units of 1/λ_De. |
Returns
complex or numpy.ndarray- ω in units of ω_pe, with ω(−k) = ω(k) and ω(0) = 1;
nanwhere 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
| Name | Type | Default | Description |
|---|---|---|---|
function | callable | required | function(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) | required | The interval of wavenumbers searched. |
samples | int | 64 | The number of samples of the initial scan. Default: 64. |
tol | float | 1e-08 | The 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
functionreturns 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
| Name | Type | Default | Description |
|---|---|---|---|
function | callable | required | function(omega, k), analytic in ω, whose zero is sought, e.g.
lambda w, k: electrostatic_dielectric(w, k, species). It must broadcast over arrays. |
k | float or array_like | required | The wavenumbers; one-dimensional with continuation, else any shape. |
guess | complex or array_like | required | The starting frequency: a scalar for the first k with continuation, else anything that
broadcasts against k. |
derivative | callable | None | derivative(omega, k), the ω-derivative of function. Default: a central difference. |
continuation | bool | True | Continue the root along k. Default: True. |
tol | float | 1e-11 | Converged once the Newton step is below tol · |ω|. Default: 1e-11. |
maxiter | int | 60 | The maximum number of Newton steps per wavenumber. Default: 60. |
Returns
complex or numpy.ndarray- ω for every k,
nanwhere Newton did not converge (no exception is raised); withcontinuationthe next wavenumber is then seeded by the last converged root.
Raises
ValueError- With
continuation, ifkhas more than one dimension orguessis 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
| Name | Type | Default | Description |
|---|---|---|---|
omega | complex or array_like | required | The complex frequency in units of ω_pe. |
k | float or array_like | required | The wavenumber in units of 1/λ_De, nonzero. |
species | Maxwellian | required | The species. |
derivative | (0, 1) | 0 | 0 for χ_s, 1 for ∂χ_s/∂ω. Default: 0. |
Returns
complex or numpy.ndarray- χ_s or ∂χ_s/∂ω, broadcast over
omega,kand the species fields.
Raises
ValueError- If
derivativeis not 0 or 1.
Examples
The cold limit χ → −ω_p²/ω²:
>>> round(susceptibility(10.0, 0.01, Maxwellian()).real, 6)-0.01two_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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De (ω(−k) = ω(k)). |
beam_speed | float or array_like | required | v_b in units of v_the. |
thermal_speed | float or array_like | required | v_t of each beam in units of v_the, positive. |
beam_density | float or array_like | 0.5 | n_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;
nanwhere 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
| Name | Type | Default | Description |
|---|---|---|---|
k | float or array_like | required | The wavenumber in units of 1/λ_De (any length unit L works, with speeds in ω_pe L). |
beam_speed | float or array_like | required | v_b, each beam’s speed. |
beam_density | float or array_like | 0.5 | n_b, each beam’s density (its ω_pb²). Default: 0.5, so the total density is 1. |
all_roots | bool | False | Return 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
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-12True