Formula reference: atomic

Generated from the docstrings of vaft.formula.atomic: 11 public functions. Each entry is what vaft.formula.describe("atomic.<name>") prints. All formula categories

Overview

The equilibrium construction follows MIT-licensed work, Copyright (c) 2021 Francesco Sciortino. See the third-party notices in the project README.

This module is the numerical layer of VAFT’s atomic package. It accepts SI electron densities, evaluates native ADF11 tables in log10 space, and returns charge-state fractions or cooling coefficients without depending on OMAS.

Functions

coronal_relaxation_timeSlowest relaxation time of the ionisation balance towards coronal equilibrium.
fractional_abundancesIonisation-equilibrium (coronal) fractional abundances from ACD and SCD tables. Convention
hydrogenic_energy_levelBohr energy of level $n$ of a one-electron ion, with the reduced-mass correction.
hydrogenic_transition_wavelengthVacuum wavelength of the $n_u \to n_l$ line of a one-electron ion (Rydberg formula). Convention
impurity_fraction_from_effective_chargeImpurity-to-electron density ratio that produces a given effective charge.
interpolate_adf11Interpolate every charge-state block of an ADF11 table at given $(n_e, T_e)$. Convention
line_cooling_coefficientEquilibrium line-radiation cooling coefficient $L_{line}(n_e, T_e)$ of a species. Convention
mean_charge_from_charge_state_densitiesMean charge of one element over its charge states. Convention
mean_square_charge_from_charge_state_densitiesMean square charge of one element over its charge states. Convention
transient_fractional_abundancesFractional abundances a time tau after neutral atoms enter a plasma of fixed n_e, T_e.
z_eff_from_n_s_Z_sEffective charge of a mixture of ion species. Convention

coronal_relaxation_time

source
coronal_relaxation_time(ne_m3, te_eV, acd, scd)
Show source vaft/formula/atomic.py, lines 428–480
def coronal_relaxation_time(ne_m3, te_eV, acd: ADF11Source, scd: ADF11Source):
    r"""Slowest relaxation time of the ionisation balance towards coronal equilibrium.

    $$\tau_\mathrm{relax} = \frac{1}{\min_{\lambda\neq 0}|\mathrm{Re}\,\lambda(\mathsf M)|}$$

    over the non-zero eigenvalues of the rate matrix of
    :func:`transient_fractional_abundances`.

    Parameters
    ----------
    ne_m3 : array-like
        Electron density, finite and positive [m^-3].
    te_eV : array-like
        Electron temperature, finite and positive [eV].
    acd : ADF11Data or path-like
        Effective recombination table [n/a].
    scd : ADF11Data or path-like
        Effective ionisation table [n/a].

    Returns
    -------
    np.ndarray
        $\tau_\mathrm{relax}$ with the broadcast profile shape [s].

    Raises
    ------
    ValueError
        Non-finite or non-positive profiles, or tables of incompatible shape.

    Physical interpretation
    -----------------------
    A plasma younger than a few $\tau_\mathrm{relax}$ (or whose impurities
    stay in it for less, $\tau_p$) is not in coronal balance, and its
    charge states lag low.  $n_e\tau_\mathrm{relax}$ is the usual
    $n_e\tau$ criterion, here evaluated rather than quoted.

    References
    ----------
    .. [1] H. P. Summers, *The ADAS User Manual*, version 2.6 (2004), Sec. on
           ADF11 (ionisation balance).
    .. [2] R. J. Hawryluk et al., Nucl. Fusion 19 (1979) 607.

    See Also
    --------
    transient_fractional_abundances
    """
    matrix = _rate_matrix(ne_m3, te_eV, acd, scd)
    eigen = np.linalg.eigvals(matrix)
    rates = np.abs(eigen.real)
    scale = np.max(rates, axis=-1, keepdims=True)
    rates = np.where(rates > 1e-10 * np.where(scale > 0.0, scale, 1.0), rates, np.inf)
    slowest = np.min(rates, axis=-1)
    return np.where(np.isfinite(slowest), 1.0 / slowest, np.inf)

Slowest relaxation time of the ionisation balance towards coronal equilibrium.

\[\tau_\mathrm{relax} = \frac{1}{\min_{\lambda\neq 0}|\mathrm{Re}\,\lambda(\mathsf M)|}\]

over the non-zero eigenvalues of the rate matrix of transient_fractional_abundances.

NameTypeUnitDescription
ne_m3array-likem^-3

Electron density, finite and positive.

te_eVarray-likeeV

Electron temperature, finite and positive.

acdADF11Data or path-liken/a

Effective recombination table.

scdADF11Data or path-liken/a

Effective ionisation table.

Returns
—np.ndarrays

$\tau_\mathrm{relax}$ with the broadcast profile shape.

Raises

  • ValueError Non-finite or non-positive profiles, or tables of incompatible shape.
Physical interpretation · See Also · References

Physical interpretation

A plasma younger than a few $\tau_\mathrm{relax}$ (or whose impurities stay in it for less, $\tau_p$) is not in coronal balance, and its charge states lag low. $n_e\tau_\mathrm{relax}$ is the usual $n_e\tau$ criterion, here evaluated rather than quoted.

See Also

transient_fractional_abundances

References

  1. H. P. Summers, The ADAS User Manual, version 2.6 (2004), Sec. on ADF11 (ionisation balance).
  2. R. J. Hawryluk et al., Nucl. Fusion 19 (1979) 607.

fractional_abundances

Convention-sensitive source
fractional_abundances(ne_m3, te_eV, acd, scd)

Ionisation-equilibrium (coronal) fractional abundances from ACD and SCD tables.

\[\frac{f_{z+1}}{f_z} = \frac{S_z(n_e, T_e)}{\alpha_{z+1}(n_e, T_e)}, \qquad \tilde f_0 = 1, \quad \tilde f_z = \prod_{j=0}^{z-1}\frac{S_j}{\alpha_{j+1}}, \quad f_z = \frac{\tilde f_z}{\sum_k\tilde f_k}\]

with $S_z$ the SCD effective ionisation and $\alpha_{z+1}$ the ACD effective recombination coefficients.

NameTypeUnitDescription
ne_m3array-likem^-3

Electron density, finite and positive.

te_eVarray-likeeV

Electron temperature, finite and positive.

acdADF11Data or path-liken/a

Effective recombination table.

scdADF11Data or path-liken/a

Effective ionisation table.

Returns
—np.ndarray-

Fractional abundances, summing to one over the last axis. That axis has n_rate_blocks + 1 charge states, neutral to fully stripped.

Convention

Effective (collisional-radiative, density-dependent) coefficients in the ADAS sense, evaluated in cm^-3 internally; the density cancels in the ratio, so the result is dimensionless.

Raises

  • ValueError Mismatched charge-state counts, wrong table class, or non-finite rates.
Assumptions · Limitations · References

Assumptions

Steady state, no transport: the local balance of ionisation and recombination alone sets the charge-state distribution.

Limitations

Transport in a real edge or start-up plasma shifts the distribution toward lower charge states than coronal equilibrium predicts (the effect Aurora models with an impurity transport solve).

References

  1. H. P. Summers, The ADAS User Manual, version 2.6 (2004), Sec. on ADF11 (ionisation balance).
  2. F. Sciortino et al., Plasma Phys. Control. Fusion 63 (2021) 112001, Sec. 2 (equilibrium construction; MIT-licensed, see the module docstring).

hydrogenic_energy_level

source
hydrogenic_energy_level(n, Z=1, mass_number=None)
Show source vaft/formula/atomic.py, lines 770–821
def hydrogenic_energy_level(n, Z=1, mass_number=None):
    r"""Bohr energy of level $n$ of a one-electron ion, with the reduced-mass correction.

    $$E_n = -\frac{\mu}{m_e}\,\frac{Z^2}{n^2}\,R_\infty hc,\qquad
      R_\infty hc = \frac{m_ee^4}{8\varepsilon_0^2h^2}\approx 13.606\ \mathrm{eV}$$

    Parameters
    ----------
    n : int or np.ndarray
        Principal quantum number, at least 1 [-].
    Z : int, optional
        Nuclear charge of the one-electron ion (1 for H I, 2 for He II) [-].
    mass_number : int or None, optional
        1, 2 or 3 for H, D, T (the reduced mass $\mu = m_eM/(m_e + M)$), only with
        ``Z = 1``; ``None`` for an infinitely heavy nucleus [-].

    Returns
    -------
    float or np.ndarray
        $E_n$, negative, from the ionisation limit [eV].

    Raises
    ------
    ValueError
        ``n`` below one, ``Z`` below one, an unknown ``mass_number``, or a
        ``mass_number`` with ``Z > 1``.

    Assumptions
    -----------
    Non-relativistic Bohr/Schroedinger levels of a one-electron ion: no fine
    structure, Lamb shift or hyperfine splitting (H-alpha's fine structure
    spans about 0.016 nm). Not a stand-in for many-electron levels, which need
    atomic data (ADF04).

    References
    ----------
    .. [1] H. A. Bethe and E. E. Salpeter, *Quantum Mechanics of One- and
           Two-Electron Atoms*, Springer (1957), Sec. 2.
    """
    from .constants import EPS0, H_PLANCK, ME, QE

    n = np.asarray(n, dtype=float)
    if np.any(n < 1) or np.any(n != np.round(n)):
        raise ValueError("n must be a positive integer")
    if int(Z) != Z or Z < 1:
        raise ValueError(f"Z must be a positive integer, not {Z!r}")
    if mass_number is not None and Z != 1:
        raise ValueError("mass_number names a hydrogen isotope (H, D, T): it cannot give the nuclear mass of a "
                         f"Z = {Z} ion; pass None (infinite nuclear mass)")
    rydberg_eV = ME * QE**4 / (8.0 * EPS0**2 * H_PLANCK**2) / QE
    out = -_reduced_mass_factor(mass_number) * rydberg_eV * Z**2 / n**2
    return float(out) if np.ndim(out) == 0 else out

Bohr energy of level $n$ of a one-electron ion, with the reduced-mass correction.

\[E_n = -\frac{\mu}{m_e}\,\frac{Z^2}{n^2}\,R_\infty hc,\qquad R_\infty hc = \frac{m_ee^4}{8\varepsilon_0^2h^2}\approx 13.606\ \mathrm{eV}\]
NameTypeUnitDescription
nint or np.ndarray-

Principal quantum number, at least 1.

Zint, optional-

Nuclear charge of the one-electron ion (1 for H I, 2 for He II).

mass_numberint or None, optional-

1, 2 or 3 for H, D, T (the reduced mass $\mu = m_eM/(m_e + M)$), only with Z = 1; None for an infinitely heavy nucleus.

Returns
—float or np.ndarrayeV

$E_n$, negative, from the ionisation limit.

Raises

  • ValueError n below one, Z below one, an unknown mass_number, or a mass_number with Z > 1.
Assumptions · References

Assumptions

Non-relativistic Bohr/Schroedinger levels of a one-electron ion: no fine structure, Lamb shift or hyperfine splitting (H-alpha’s fine structure spans about 0.016 nm). Not a stand-in for many-electron levels, which need atomic data (ADF04).

References

  1. H. A. Bethe and E. E. Salpeter, Quantum Mechanics of One- and Two-Electron Atoms, Springer (1957), Sec. 2.

hydrogenic_transition_wavelength

Convention-sensitive source
hydrogenic_transition_wavelength(n_upper, n_lower, Z=1, mass_number=None)
Show source vaft/formula/atomic.py, lines 824–872
def hydrogenic_transition_wavelength(n_upper, n_lower, Z=1, mass_number=None):
    r"""Vacuum wavelength of the $n_u \to n_l$ line of a one-electron ion (Rydberg formula).

    $$\frac{1}{\lambda} = \frac{\mu}{m_e}R_\infty Z^2\left(\frac{1}{n_l^2} - \frac{1}{n_u^2}\right),\qquad
      R_\infty = \frac{m_ee^4}{8\varepsilon_0^2h^3c}$$

    Parameters
    ----------
    n_upper : int or np.ndarray
        Upper principal quantum number, above ``n_lower`` [-].
    n_lower : int
        Lower principal quantum number, at least 1 [-].
    Z : int, optional
        Nuclear charge of the one-electron ion [-].
    mass_number : int or None, optional
        1, 2 or 3 for H, D, T; ``None`` for infinite nuclear mass [-].

    Returns
    -------
    float or np.ndarray
        Vacuum wavelength [m].

    Raises
    ------
    ValueError
        ``n_upper <= n_lower`` or an argument of ``hydrogenic_energy_level`` is invalid.

    Convention
    ----------
    **Vacuum** wavelength. Tabulated visible lines are usually quoted in air
    (H-alpha 656.28 nm air, 656.47 nm vacuum): the difference is the
    refractive index of air, about $2.8\times10^{-4}$. The series of the
    fusion-diagnostic names is Balmer: alpha is $3 \to 2$, beta $4 \to 2$.
    The isotope shift from the reduced mass (D-alpha about 0.18 nm below
    H-alpha) is what separates H and D lines.

    References
    ----------
    .. [1] H. A. Bethe and E. E. Salpeter, *Quantum Mechanics of One- and
           Two-Electron Atoms*, Springer (1957), Sec. 2.
    """
    from .constants import C_LIGHT, H_PLANCK, QE

    n_upper = np.asarray(n_upper, dtype=float)
    if np.any(n_upper <= n_lower):
        raise ValueError("n_upper must exceed n_lower")
    delta_eV = hydrogenic_energy_level(n_upper, Z, mass_number) - hydrogenic_energy_level(n_lower, Z, mass_number)
    out = H_PLANCK * C_LIGHT / (np.asarray(delta_eV) * QE)
    return float(out) if np.ndim(out) == 0 else out

Vacuum wavelength of the $n_u \to n_l$ line of a one-electron ion (Rydberg formula).

\[\frac{1}{\lambda} = \frac{\mu}{m_e}R_\infty Z^2\left(\frac{1}{n_l^2} - \frac{1}{n_u^2}\right),\qquad R_\infty = \frac{m_ee^4}{8\varepsilon_0^2h^3c}\]
NameTypeUnitDescription
n_upperint or np.ndarray-

Upper principal quantum number, above n_lower.

n_lowerint-

Lower principal quantum number, at least 1.

Zint, optional-

Nuclear charge of the one-electron ion.

mass_numberint or None, optional-

1, 2 or 3 for H, D, T; None for infinite nuclear mass.

Returns
—float or np.ndarraym

Vacuum wavelength.

Convention

Vacuum wavelength. Tabulated visible lines are usually quoted in air (H-alpha 656.28 nm air, 656.47 nm vacuum): the difference is the refractive index of air, about $2.8\times10^{-4}$. The series of the fusion-diagnostic names is Balmer: alpha is $3 \to 2$, beta $4 \to 2$. The isotope shift from the reduced mass (D-alpha about 0.18 nm below H-alpha) is what separates H and D lines.

Raises

  • ValueError n_upper <= n_lower or an argument of hydrogenic_energy_level is invalid.
References

References

  1. H. A. Bethe and E. E. Salpeter, Quantum Mechanics of One- and Two-Electron Atoms, Springer (1957), Sec. 2.

impurity_fraction_from_effective_charge

source
impurity_fraction_from_effective_charge(z_eff, z_impurity)
Show source vaft/formula/atomic.py, lines 689–749
def impurity_fraction_from_effective_charge(z_eff, z_impurity):
    r"""Impurity-to-electron density ratio that produces a given effective charge.

    $$\frac{n_I}{n_e} = \frac{Z_{\mathrm{eff}} - 1}{Z_I\,(Z_I - 1)}$$

    the inverse of :func:`z_eff_from_n_s_Z_s` for one fully ionised impurity of
    charge $Z_I$ in a hydrogenic main ion.

    Parameters
    ----------
    z_eff : float or array-like
        Effective charge, within $[1, Z_I]$ [-].
    z_impurity : float
        Impurity charge $Z_I$, greater than one [-].

    Returns
    -------
    float or np.ndarray
        $n_I/n_e$, of the shape of ``z_eff``; the main-ion fraction is
        $n_H/n_e = 1 - Z_I\,n_I/n_e$ [-].

    Raises
    ------
    ValueError
        ``z_impurity`` not greater than one, or ``z_eff`` non-finite or
        outside $[1, Z_I]$, where no non-negative density pair exists.

    Assumptions
    -----------
    Quasi-neutrality $n_e = n_H + Z_I n_I$ and exactly two ion species: a
    hydrogenic main ion ($Z = 1$, any isotope) and one impurity in a single
    charge state.  Those two conditions and the definition
    $Z_{\mathrm{eff}} n_e = n_H + Z_I^2 n_I$ fix both fractions.

    Limitations
    -----------
    One impurity only: a measured $Z_{\mathrm{eff}}$ does not determine a
    mixture, so the answer is the fraction of the named impurity that would
    alone account for it.  At $Z_{\mathrm{eff}} = 2$ that is $1/30$ for
    carbon but $1/5402$ for fully stripped tungsten.

    References
    ----------
    .. [1] J. Wesson, *Tokamaks*, 4th ed., Oxford University Press (2011),
           Ch. 2 (collisions, resistivity and the effective charge).

    See Also
    --------
    z_eff_from_n_s_Z_s
    """
    charge = float(z_impurity)
    if not np.isfinite(charge) or charge <= 1.0:
        raise ValueError(f"an impurity needs Z > 1; got {z_impurity!r}")
    target = np.asarray(z_eff, dtype=float)
    if not np.all(np.isfinite(target)) or np.any(target < 1.0) or np.any(target > charge):
        raise ValueError(
            f"Z_eff = {z_eff!r} is unreachable with a Z = {charge:g} impurity in "
            f"hydrogen: it must lie between 1 (no impurity) and {charge:g} (no main ion)"
        )
    fraction = (target - 1.0) / (charge * (charge - 1.0))
    return float(fraction) if fraction.ndim == 0 else fraction

Impurity-to-electron density ratio that produces a given effective charge.

\[\frac{n_I}{n_e} = \frac{Z_{\mathrm{eff}} - 1}{Z_I\,(Z_I - 1)}\]

the inverse of z_eff_from_n_s_Z_s for one fully ionised impurity of charge $Z_I$ in a hydrogenic main ion.

NameTypeUnitDescription
z_efffloat or array-like-

Effective charge, within $[1, Z_I]$.

z_impurityfloat-

Impurity charge $Z_I$, greater than one.

Returns
—float or np.ndarray-

$n_I/n_e$, of the shape of z_eff; the main-ion fraction is $n_H/n_e = 1 - Z_I\,n_I/n_e$.

Raises

  • ValueError z_impurity not greater than one, or z_eff non-finite or outside $[1, Z_I]$, where no non-negative density pair exists.
Assumptions · Limitations · See Also · References

Assumptions

Quasi-neutrality $n_e = n_H + Z_I n_I$ and exactly two ion species: a hydrogenic main ion ($Z = 1$, any isotope) and one impurity in a single charge state. Those two conditions and the definition $Z_{\mathrm{eff}} n_e = n_H + Z_I^2 n_I$ fix both fractions.

Limitations

One impurity only: a measured $Z_{\mathrm{eff}}$ does not determine a mixture, so the answer is the fraction of the named impurity that would alone account for it. At $Z_{\mathrm{eff}} = 2$ that is $1/30$ for carbon but $1/5402$ for fully stripped tungsten.

See Also

z_eff_from_n_s_Z_s

References

  1. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Ch. 2 (collisions, resistivity and the effective charge).

interpolate_adf11

Convention-sensitive source
interpolate_adf11(table, ne_m3, te_eV, *, multiply_density=False)

Interpolate every charge-state block of an ADF11 table at given $(n_e, T_e)$.

\[C_z(n_e, T_e) = 10^{\,\mathcal{I}_2[\log_{10}C_z]}\]

where $\mathcal{I}2$ is bilinear interpolation on the table’s rectangular grid of $\log{10}n_e\,[\mathrm{cm^{-3}}]$ and $\log_{10}T_e\,[\mathrm{eV}]$.

NameTypeUnitDescription
tableADF11Datan/a

Parsed ADF11 table (acd, scd, plt, …).

ne_m3array-likem^-3

Electron density, finite and positive.

te_eVarray-likeeV

Electron temperature, finite and positive.

multiply_densitybool, optionalbool

Multiply by $n_e$ in cm^-3 to turn coefficients into rates; default False.

Returns
—np.ndarrayany

Coefficients in the table’s own unit, or rates with multiply_density. Shape broadcast(ne_m3, te_eV).shape + (n_blocks,); cm^3/s for ACD/SCD and W cm^3 for PLT, s^-1 when multiplied by density.

Convention

ADF11 stores densities in cm^-3 and rate coefficients in cm^3 s^-1; the SI input is converted to cm^-3 internally and the output is not converted back, so callers multiply by $10^{-6}$ for m^3 s^-1 (as line_cooling_coefficient does for W m^3).

Raises

  • ValueError Empty, non-finite or non-positive profiles.
Validity · Limitations · Numerical notes · References

Validity

Inside the tabulated grid (typically $10^{8}$-$10^{15}$ cm^-3 and 1 eV-10 keV for iso-nuclear ADF11 files).

Limitations

Linear extrapolation in log space is retained outside the grid to match the established ADF11 calculation path; extrapolated coefficients are not physical and are not flagged.

Numerical notes

scipy.interpolate.RegularGridInterpolator with bounds_error=False, fill_value=None, one interpolator per charge-state block.

References

  1. H. P. Summers, The ADAS User Manual, version 2.6 (2004), https://www.adas.ac.uk/manual.php, ADF11 format.
  2. F. Sciortino et al., Plasma Phys. Control. Fusion 63 (2021) 112001 (Aurora; the calculation path this follows).

line_cooling_coefficient

Convention-sensitive source
line_cooling_coefficient(species, ne_m3, te_eV, *, acd=None, scd=None, plt=None, cache_dir=None)

Equilibrium line-radiation cooling coefficient $L_{line}(n_e, T_e)$ of a species.

\[L_{\mathrm{line}}(n_e, T_e) = 10^{-6}\sum_{q=0}^{Z-1} f_q(n_e, T_e)\, P^{\mathrm{PLT}}_q(n_e, T_e)\]

the PLT coefficients weighted by the coronal abundances of fractional_abundances; the fully stripped state has no line radiation and is omitted.

NameTypeUnitDescription
speciesstrstr

Atomic symbol with configured default ADF11 files, e.g. "C".

ne_m3array-likem^-3

Electron density, finite and positive.

te_eVarray-likeeV

Electron temperature, finite and positive.

acdADF11Data or path-like or None, optionaln/a

Recombination table; None resolves the configured file.

scdADF11Data or path-like or None, optionaln/a

Ionisation table; None resolves the configured file.

pltADF11Data or path-like or None, optionaln/a

Line-power table; None resolves the configured file.

cache_dirstr or path-like or None, optionaln/a

OPEN-ADAS cache directory; downloads on a miss.

Returns
—np.ndarrayW m^3

Cooling coefficient with the broadcast input shape. Multiply by $n_e n_Z$ for a power density.

Convention

ADF11 PLT is stored in W cm^3; the factor $10^{-6}$ converts to W m^3. Coronal equilibrium, no transport, no recombination/bremsstrahlung continuum (that is the separate PRB class).

Raises

  • KeyError Unconfigured species.
  • ADASDataError Lookup, download or parsing failure.
  • ValueError Invalid inputs or mismatched charge-state dimensions.
References

References

  1. H. P. Summers, The ADAS User Manual, version 2.6 (2004), ADF11 PLT class.
  2. D. E. Post et al., At. Data Nucl. Data Tables 20 (1977) 397 (coronal cooling curves).

mean_charge_from_charge_state_densities

Convention-sensitive source
mean_charge_from_charge_state_densities(n_z, axis=-1)
Show source vaft/formula/atomic.py, lines 483–545
def mean_charge_from_charge_state_densities(n_z, axis=-1):
    r"""Mean charge of one element over its charge states.

    $$\langle Z\rangle = \sum_j j\,f_j = \frac{\sum_j j\,n_j}{\sum_j n_j},
      \qquad f_j = \frac{n_j}{\sum_k n_k}$$

    Parameters
    ----------
    n_z : array-like
        Density of each charge state along ``axis``, ordered neutral first, so
        that index $j$ is charge $j$; finite and non-negative [m^-3].
    axis : int, optional
        Axis that runs over the charge states [-].

    Returns
    -------
    float or np.ndarray
        Mean charge, with ``axis`` removed [-].

    Raises
    ------
    ValueError
        A non-finite or negative density, or a slice whose densities sum to
        zero, which has no charge distribution to average.

    Convention
    ----------
    **Index is charge, neutral first**, the layout
    :func:`fractional_abundances` returns -- so its output can be passed
    straight in, and densities need not be normalised first because the
    fractions $f_j$ are formed here.  Spectroscopic notation counts from one
    (C I is neutral carbon); pass charge, not ionisation stage, or every value
    comes out one high.

    References
    ----------
    .. [1] J. Wesson, *Tokamaks*, 4th ed., Oxford University Press (2011),
           Sec. 4.25 (impurity charge states).

    See Also
    --------
    fractional_abundances
    z_eff_from_n_s_Z_s
    """
    density = np.asarray(n_z, dtype=float)
    if density.ndim == 0:
        raise ValueError("n_z needs at least one charge state along axis")
    try:
        axis = normalize_axis_index(axis, density.ndim)
    except (IndexError, np.exceptions.AxisError) as exc:  # numpy raises AxisError, an IndexError subclass
        raise ValueError(f"axis {axis} is out of range for a {density.ndim}-D n_z") from exc
    if density.shape[axis] == 0:
        raise ValueError("n_z needs at least one charge state along axis")
    if not np.all(np.isfinite(density)) or np.any(density < 0.0):
        raise ValueError("n_z must be finite and non-negative")
    total = np.sum(density, axis=axis)
    if np.any(total <= 0.0):
        raise ValueError("a charge-state distribution with zero total density has no mean charge")
    shape = [1] * density.ndim
    shape[axis] = density.shape[axis]
    charge = np.arange(density.shape[axis], dtype=float).reshape(shape)
    mean = np.sum(charge * density, axis=axis) / total
    return float(mean) if np.ndim(mean) == 0 else mean

Mean charge of one element over its charge states.

\[\langle Z\rangle = \sum_j j\,f_j = \frac{\sum_j j\,n_j}{\sum_j n_j}, \qquad f_j = \frac{n_j}{\sum_k n_k}\]
NameTypeUnitDescription
n_zarray-likem^-3

Density of each charge state along axis, ordered neutral first, so that index $j$ is charge $j$; finite and non-negative.

axisint, optional-

Axis that runs over the charge states.

Returns
—float or np.ndarray-

Mean charge, with axis removed.

Convention

Index is charge, neutral first, the layout fractional_abundances returns – so its output can be passed straight in, and densities need not be normalised first because the fractions $f_j$ are formed here. Spectroscopic notation counts from one (C I is neutral carbon); pass charge, not ionisation stage, or every value comes out one high.

Raises

  • ValueError A non-finite or negative density, or a slice whose densities sum to zero, which has no charge distribution to average.
See Also · References

See Also

fractional_abundances z_eff_from_n_s_Z_s

References

  1. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Sec. 4.25 (impurity charge states).

mean_square_charge_from_charge_state_densities

Convention-sensitive source
mean_square_charge_from_charge_state_densities(n_z, axis=-1)
Show source vaft/formula/atomic.py, lines 548–611
def mean_square_charge_from_charge_state_densities(n_z, axis=-1):
    r"""Mean square charge of one element over its charge states.

    $$\langle Z^2\rangle = \sum_j j^2 f_j = \frac{\sum_j j^2\,n_j}{\sum_j n_j},
      \qquad f_j = \frac{n_j}{\sum_k n_k}$$

    Parameters
    ----------
    n_z : array-like
        Density of each charge state along ``axis``, ordered neutral first, so
        that index $j$ is charge $j$; finite and non-negative [m^-3].
    axis : int, optional
        Axis that runs over the charge states [-].

    Returns
    -------
    float or np.ndarray
        Mean square charge, with ``axis`` removed [-].

    Raises
    ------
    ValueError
        A non-finite or negative density, or a slice whose densities sum to
        zero, which has no charge distribution to average.

    Convention
    ----------
    **Index is charge, neutral first**, as in
    :func:`mean_charge_from_charge_state_densities`.  An element of density
    $n_I$ contributes $n_I\langle Z^2\rangle$ to $Z_\mathrm{eff} n_e$ and
    $n_I\langle Z\rangle$ to quasi-neutrality; $\langle Z^2\rangle -
    \langle Z\rangle^2$ is the charge-state variance that collapsing onto the
    mean charge would drop.

    References
    ----------
    .. [1] J. Wesson, *Tokamaks*, 4th ed., Oxford University Press (2011),
           Sec. 4.25 (impurity charge states).

    See Also
    --------
    mean_charge_from_charge_state_densities
    fractional_abundances
    z_eff_from_n_s_Z_s
    """
    density = np.asarray(n_z, dtype=float)
    if density.ndim == 0:
        raise ValueError("n_z needs at least one charge state along axis")
    try:
        axis = normalize_axis_index(axis, density.ndim)
    except (IndexError, np.exceptions.AxisError) as exc:  # numpy raises AxisError, an IndexError subclass
        raise ValueError(f"axis {axis} is out of range for a {density.ndim}-D n_z") from exc
    if density.shape[axis] == 0:
        raise ValueError("n_z needs at least one charge state along axis")
    if not np.all(np.isfinite(density)) or np.any(density < 0.0):
        raise ValueError("n_z must be finite and non-negative")
    total = np.sum(density, axis=axis)
    if np.any(total <= 0.0):
        raise ValueError("a charge-state distribution with zero total density has no mean square charge")
    shape = [1] * density.ndim
    shape[axis] = density.shape[axis]
    charge = np.arange(density.shape[axis], dtype=float).reshape(shape)
    mean = np.sum(charge**2 * density, axis=axis) / total
    return float(mean) if np.ndim(mean) == 0 else mean

Mean square charge of one element over its charge states.

\[\langle Z^2\rangle = \sum_j j^2 f_j = \frac{\sum_j j^2\,n_j}{\sum_j n_j}, \qquad f_j = \frac{n_j}{\sum_k n_k}\]
NameTypeUnitDescription
n_zarray-likem^-3

Density of each charge state along axis, ordered neutral first, so that index $j$ is charge $j$; finite and non-negative.

axisint, optional-

Axis that runs over the charge states.

Returns
—float or np.ndarray-

Mean square charge, with axis removed.

Convention

Index is charge, neutral first, as in mean_charge_from_charge_state_densities. An element of density $n_I$ contributes $n_I\langle Z^2\rangle$ to $Z_\mathrm{eff} n_e$ and $n_I\langle Z\rangle$ to quasi-neutrality; $\langle Z^2\rangle - \langle Z\rangle^2$ is the charge-state variance that collapsing onto the mean charge would drop.

Raises

  • ValueError A non-finite or negative density, or a slice whose densities sum to zero, which has no charge distribution to average.
See Also · References

See Also

mean_charge_from_charge_state_densities fractional_abundances z_eff_from_n_s_Z_s

References

  1. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Sec. 4.25 (impurity charge states).

transient_fractional_abundances

source
transient_fractional_abundances(ne_m3, te_eV, acd, scd, tau_s)
Show source vaft/formula/atomic.py, lines 348–425
def transient_fractional_abundances(ne_m3, te_eV, acd: ADF11Source, scd: ADF11Source, tau_s):
    r"""Fractional abundances a time tau after neutral atoms enter a plasma of fixed n_e, T_e.

    $$\frac{d\mathbf f}{dt} = \mathsf M(n_e, T_e)\,\mathbf f,\qquad
      \mathbf f(\tau) = e^{\tau\mathsf M}\,\mathbf e_0$$

    with $\mathsf M$ tridiagonal: state $z$ is ionised at $n_e S_z$ and
    recombines at $n_e\alpha_z$, and $\mathbf e_0$ is all neutral.

    Parameters
    ----------
    ne_m3 : array-like
        Electron density, finite and positive [m^-3].
    te_eV : array-like
        Electron temperature, finite and positive [eV].
    acd : ADF11Data or path-like
        Effective recombination table [n/a].
    scd : ADF11Data or path-like
        Effective ionisation table [n/a].
    tau_s : float or array-like
        Time since the atoms entered, broadcastable against the profiles,
        non-negative [s].

    Returns
    -------
    np.ndarray
        Fractions with charge states (neutral first) on a new last axis,
        summing to one [-].

    Raises
    ------
    ValueError
        Non-finite or non-positive profiles, a negative time, or tables of
        incompatible shape.

    Assumptions
    -----------
    Constant $n_e$, $T_e$ over $\tau$, no transport and no charge exchange:
    the ionisation age of a parcel that entered as neutrals.  As
    $n_e\tau\to\infty$ it tends to :func:`fractional_abundances`.

    Limitations
    -----------
    An age, not a transport solution: an impurity that recycles keeps a
    population of low charge states that no single age reproduces.

    References
    ----------
    .. [1] H. P. Summers, *The ADAS User Manual*, version 2.6 (2004), Sec. on
           ADF11 (ionisation balance).
    .. [2] R. J. Hawryluk et al., Nucl. Fusion 19 (1979) 607 (transient
           ionisation in ohmic plasmas).

    See Also
    --------
    fractional_abundances
    coronal_relaxation_time
    """
    from scipy.linalg import expm

    matrix = _rate_matrix(ne_m3, te_eV, acd, scd)
    tau = np.asarray(tau_s, dtype=float)
    if not np.all(np.isfinite(tau)) or np.any(tau < 0.0):
        raise ValueError("tau_s must be finite and non-negative")
    shape = np.broadcast_shapes(matrix.shape[:-2], tau.shape)
    matrix = np.broadcast_to(matrix, shape + matrix.shape[-2:])
    tau = np.broadcast_to(tau, shape)
    n = matrix.shape[-1]
    start = np.zeros(n)
    start[0] = 1.0
    flat_m = matrix.reshape(-1, n, n)
    flat_t = tau.reshape(-1)
    out = np.empty((flat_m.shape[0], n))
    for k in range(flat_m.shape[0]):
        out[k] = expm(flat_m[k] * flat_t[k]) @ start
    out = np.clip(out, 0.0, None)
    out /= np.sum(out, axis=-1, keepdims=True)
    return out.reshape(shape + (n,))

Fractional abundances a time tau after neutral atoms enter a plasma of fixed n_e, T_e.

\[\frac{d\mathbf f}{dt} = \mathsf M(n_e, T_e)\,\mathbf f,\qquad \mathbf f(\tau) = e^{\tau\mathsf M}\,\mathbf e_0\]

with $\mathsf M$ tridiagonal: state $z$ is ionised at $n_e S_z$ and recombines at $n_e\alpha_z$, and $\mathbf e_0$ is all neutral.

NameTypeUnitDescription
ne_m3array-likem^-3

Electron density, finite and positive.

te_eVarray-likeeV

Electron temperature, finite and positive.

acdADF11Data or path-liken/a

Effective recombination table.

scdADF11Data or path-liken/a

Effective ionisation table.

tau_sfloat or array-likes

Time since the atoms entered, broadcastable against the profiles, non-negative.

Returns
—np.ndarray-

Fractions with charge states (neutral first) on a new last axis, summing to one.

Raises

  • ValueError Non-finite or non-positive profiles, a negative time, or tables of incompatible shape.
Assumptions · Limitations · See Also · References

Assumptions

Constant $n_e$, $T_e$ over $\tau$, no transport and no charge exchange: the ionisation age of a parcel that entered as neutrals. As $n_e\tau\to\infty$ it tends to fractional_abundances.

Limitations

An age, not a transport solution: an impurity that recycles keeps a population of low charge states that no single age reproduces.

See Also

fractional_abundances coronal_relaxation_time

References

  1. H. P. Summers, The ADAS User Manual, version 2.6 (2004), Sec. on ADF11 (ionisation balance).
  2. R. J. Hawryluk et al., Nucl. Fusion 19 (1979) 607 (transient ionisation in ohmic plasmas).

z_eff_from_n_s_Z_s

Convention-sensitive source
z_eff_from_n_s_Z_s(n_s, Z_s, n_e=None)
Show source vaft/formula/atomic.py, lines 614–686
def z_eff_from_n_s_Z_s(n_s, Z_s, n_e=None):
    r"""Effective charge of a mixture of ion species.

    $$Z_{\mathrm{eff}} = \frac{\sum_s n_s Z_s^2}{n_e}, \qquad
      n_e = \sum_s n_s Z_s\ \text{when not given}$$

    Parameters
    ----------
    n_s : array-like
        Density of each ion species or charge state, finite and non-negative;
        the last axis runs over species [m^-3].
    Z_s : array-like
        Charge of each, broadcastable against ``n_s``, finite and non-negative
        [-].
    n_e : float or array-like, optional
        Electron density, finite and positive; default the quasi-neutral
        $\sum_s n_s Z_s$ [m^-3].

    Returns
    -------
    float or np.ndarray
        Effective charge, with the species axis removed [-].

    Raises
    ------
    ValueError
        A non-finite or negative density or charge, a non-positive electron
        density, or a quasi-neutral electron density of zero.

    Convention
    ----------
    **Pass the electron density only when it is measured independently.**  The
    default makes the plasma quasi-neutral by construction, and then a pure
    hydrogenic plasma is exactly 1 and every impurity raises it.  A measured
    $n_e$ that disagrees with $\sum_s n_s Z_s$ is taken as given and not
    reconciled, so a density error lands directly in $Z_{\mathrm{eff}}$.

    A charge-resolved impurity is several species here, one per charge state:
    $Z_{\mathrm{eff}}$ weights $Z^2$, so collapsing an element of density $n_I$
    onto its mean charge first underestimates it by exactly
    $n_I\,\mathrm{Var}(Z)/n_e$ -- the quasi-neutral $n_e$ is unchanged, since
    it weights $Z$ only linearly.

    References
    ----------
    .. [1] J. Wesson, *Tokamaks*, 4th ed., Oxford University Press (2011),
           Sec. 4.25.

    See Also
    --------
    mean_charge_from_charge_state_densities
    vaft.formula.equilibrium.spitzer_resistivity_from_T_e_Z_eff_ln_Lambda
    """
    density = np.asarray(n_s, dtype=float)
    charge = np.asarray(Z_s, dtype=float)
    if not np.all(np.isfinite(density)) or np.any(density < 0.0):
        raise ValueError("n_s must be finite and non-negative")
    if not np.all(np.isfinite(charge)) or np.any(charge < 0.0):
        raise ValueError("Z_s must be finite and non-negative")
    density, charge = np.broadcast_arrays(density, charge)
    weighted = np.sum(density * charge**2, axis=-1)
    if n_e is None:
        electrons = np.sum(density * charge, axis=-1)
        if np.any(electrons <= 0.0):
            raise ValueError(
                "the quasi-neutral electron density is zero; pass n_e or a charged species"
            )
    else:
        electrons = np.asarray(n_e, dtype=float)
        if not np.all(np.isfinite(electrons)) or np.any(electrons <= 0.0):
            raise ValueError("n_e must be finite and positive")
    z_eff = weighted / electrons
    return float(z_eff) if np.ndim(z_eff) == 0 else z_eff

Effective charge of a mixture of ion species.

\[Z_{\mathrm{eff}} = \frac{\sum_s n_s Z_s^2}{n_e}, \qquad n_e = \sum_s n_s Z_s\ \text{when not given}\]
NameTypeUnitDescription
n_sarray-likem^-3

Density of each ion species or charge state, finite and non-negative; the last axis runs over species.

Z_sarray-like-

Charge of each, broadcastable against n_s, finite and non-negative

n_efloat or array-like, optionalm^-3

Electron density, finite and positive; default the quasi-neutral $\sum_s n_s Z_s$.

Returns
—float or np.ndarray-

Effective charge, with the species axis removed.

Convention

Pass the electron density only when it is measured independently. The default makes the plasma quasi-neutral by construction, and then a pure hydrogenic plasma is exactly 1 and every impurity raises it. A measured $n_e$ that disagrees with $\sum_s n_s Z_s$ is taken as given and not reconciled, so a density error lands directly in $Z_{\mathrm{eff}}$.

A charge-resolved impurity is several species here, one per charge state: $Z_{\mathrm{eff}}$ weights $Z^2$, so collapsing an element of density $n_I$ onto its mean charge first underestimates it by exactly $n_I\,\mathrm{Var}(Z)/n_e$ – the quasi-neutral $n_e$ is unchanged, since it weights $Z$ only linearly.

Raises

  • ValueError A non-finite or negative density or charge, a non-positive electron density, or a quasi-neutral electron density of zero.
See Also · References

See Also

mean_charge_from_charge_state_densities vaft.formula.equilibrium.spitzer_resistivity_from_T_e_Z_eff_ln_Lambda

References

  1. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Sec. 4.25.

results matching ""

    No results matching ""