This page was generated by nbsphinx from docs/notebooks/particles/ace.ipynb.
Interactive online version: Binder badge.

Ionization states in an interplanetary coronal mass ejection

The ionization state distribution for an element refers to the fractions of that element at each ionic level. For example, the ionization state of helium in the solar wind might be 10% He\(^{0+}\), 70% He\(^{1+}\), and 20% He\(^{2+}\). This notebook introduces the data structures in plasmapy.particles for representing the ionization state of a plasma.

The ionization state of a single element

Let’s create an IonizationState object for helium using the ionic fractions described above. We’ll specify the total number density of helium via the n_elem keyword argument.

[2]:
He_states = IonizationState("He-4", [0.1, 0.7, 0.2], n_elem=1e13 * u.m**-3)

The ionization state distribution is stored in the ionic_fractions attribute of IonizationState.

[3]:
array([0.1, 0.7, 0.2])

We can get the symbols for each ionic level in He_states too.

[4]:
['He-4 0+', 'He-4 1+', 'He-4 2+']

Because we provided the number density of the element as a whole, we can get back the number density of each ionic level.

[5]:
$[1 \times 10^{12},~7 \times 10^{12},~2 \times 10^{12}] \; \mathrm{\frac{1}{m^{3}}}$

We can also get the electron number density required to balance the positive charges for ions of this element.

[6]:
$1.1 \times 10^{13} \; \mathrm{\frac{1}{m^{3}}}$

We can provide an IonizationState with a charge number as an index to get an IonicLevel object that contains most of these attributes, but for a single ionic level (like He\(^{1+}\)). This capability is useful if we wish to iterate over the ions of an element.

[7]:
for Z in range(3):
    print(He_states[Z])
IonicLevel('He-4 0+', ionic_fraction=0.1)
IonicLevel('He-4 1+', ionic_fraction=0.7)
IonicLevel('He-4 2+', ionic_fraction=0.2)

We can get information about the average charge state via Z_mean, Z_most_abundant, and Z_rms.

[8]:
np.float64(1.1)
[9]:
[1]
[10]:
np.float64(1.224744871391589)

We can calculate the properties of the average ionic level.

[11]:
CustomParticle(mass=6.645477039375987e-27 kg, charge=1.7623942974e-19 C)

We can use the summarize() method to get information about the ionization state.

IonizationState instance for He-4 with Z_mean = 1.10
----------------------------------------------------------------
He-4  0+: 0.100    n_i = 1.00e+12 m**-3
He-4  1+: 0.700    n_i = 7.00e+12 m**-3
He-4  2+: 0.200    n_i = 2.00e+12 m**-3
----------------------------------------------------------------
n_elem = 1.00e+13 m**-3
n_e = 1.10e+13 m**-3
----------------------------------------------------------------

Ionization states of multiple elements

Now let’s look at some actual average hourly densities for ions of C, O, and Fe during an interplanetary coronal mass ejection (ICME) observed by the Advanced Composition Explorer (ACE) near 1 AU. The data were estimated from Figure 4 in Gilbert et al. (2012). This data set is noteworthy because there is information from very low charge states to very high charge states for several elements.

The electron ionization and radiative recombination rates for a given temperature are proportional to \(n_i n_e\), where \(n_i\) is the ion number density and \(n_e\) is the electron number density. Ionization and recombination are fast at high densities and slow at low densities. High density plasma can reach ionization equilibrium (when the recombination and ionization rates balance each other out) more quickly than low density plasma. Plasma undergoing rapid heating or cooling will be in non-equilibrium ionization because ionization and recombination can’t keep up with the temperature changes.

Quiescent plasma near the sun is typically close to ionization equilibrium because the density is high. As plasma moves away from the sun, the ionization and recombination rates drop rapidly because of the decreasing number density. The ionization states freeze out at several solar radii as the ionization and recombination time scales begin to exceed the time it takes for plasma to move from the sun to 1 AU.

The ionization states of the solar wind are powerful diagnostics of the thermodynamic history of solar wind and ICME plasma. The ionization states observed by ACE at 1 AU are essentially the same as at ∼\(5R_☉\).

[13]:
number_densities = {
    "C": [0, 5.7e-7, 4.3e-5, 3.6e-6, 2.35e-6, 1e-6, 1.29e-6] * u.cm**-3,
    "O": [0, 1.2e-7, 2.2e-4, 7.8e-6, 8.8e-7, 1e-6, 4e-6, 1.3e-6, 1.2e-7] * u.cm**-3,
    "Fe": [
        0,
        0,
        1.4e-8,
        1.1e-7,
        2.5e-7,
        2.2e-7,
        1.4e-7,
        1.2e-7,
        2.1e-7,
        2.1e-7,
        1.6e-7,
        8e-8,
        6.3e-8,
        4.2e-8,
        2.5e-8,
        2.3e-8,
        1.5e-8,
        3.1e-8,
        6.1e-9,
        2.3e-9,
        5.3e-10,
        2.3e-10,
        0,
        0,
        0,
        0,
        0,
    ]
    * u.cm**-3,
}

Let’s use this information as an input for IonizationStateCollection: a data structure for the ionization states of multiple elements.

[14]:
states = IonizationStateCollection(number_densities)

We can index this to get an IonizationState for one of the elements.

[15]:
states["C"]
[15]:
<IonizationState instance for C>

We can get the relative abundances of each of the elements.

[16]:
{'C': 0.17942722921968796, 'O': 0.8146086249190311, 'Fe': 0.005964145861281176}
[17]:
{'C': np.float64(-0.7461116493492604),
 'O': np.float64(-0.08905099599945356),
 'Fe': np.float64(-2.224451743828212)}

We can get the number densities as a dict (like what we provided) and the electron number density (assuming quasineutrality, but only for the elements contained in the data structure).

[18]:
{'C': <Quantity [ 0.  ,  0.57, 43.  ,  3.6 ,  2.35,  1.  ,  1.29] 1 / m3>,
 'O': <Quantity [0.0e+00, 1.2e-01, 2.2e+02, 7.8e+00, 8.8e-01, 1.0e+00, 4.0e+00,
            1.3e+00, 1.2e-01] 1 / m3>,
 'Fe': <Quantity [0.0e+00, 0.0e+00, 1.4e-02, 1.1e-01, 2.5e-01, 2.2e-01, 1.4e-01,
            1.2e-01, 2.1e-01, 2.1e-01, 1.6e-01, 8.0e-02, 6.3e-02, 4.2e-02,
            2.5e-02, 2.3e-02, 1.5e-02, 3.1e-02, 6.1e-03, 2.3e-03, 5.3e-04,
            2.3e-04, 0.0e+00, 0.0e+00, 0.0e+00, 0.0e+00, 0.0e+00] 1 / m3>}
[19]:
[19]:
$638.73093 \; \mathrm{\frac{1}{m^{3}}}$

We can summarize this information too, but let’s specify the minimum ionic fraction to print.

[20]:
states.summarize(minimum_ionic_fraction=0.02)
IonizationStateCollection instance for: C, O, Fe
----------------------------------------------------------------
C  2+: 0.830    n_i = 4.30e+01 m**-3
C  3+: 0.069    n_i = 3.60e+00 m**-3
C  4+: 0.045    n_i = 2.35e+00 m**-3
C  6+: 0.025    n_i = 1.29e+00 m**-3
----------------------------------------------------------------
O  2+: 0.935    n_i = 2.20e+02 m**-3
O  3+: 0.033    n_i = 7.80e+00 m**-3
----------------------------------------------------------------
Fe  3+: 0.064    n_i = 1.10e-01 m**-3
Fe  4+: 0.145    n_i = 2.50e-01 m**-3
Fe  5+: 0.128    n_i = 2.20e-01 m**-3
Fe  6+: 0.081    n_i = 1.40e-01 m**-3
Fe  7+: 0.070    n_i = 1.20e-01 m**-3
Fe  8+: 0.122    n_i = 2.10e-01 m**-3
Fe  9+: 0.122    n_i = 2.10e-01 m**-3
Fe 10+: 0.093    n_i = 1.60e-01 m**-3
Fe 11+: 0.046    n_i = 8.00e-02 m**-3
Fe 12+: 0.037    n_i = 6.30e-02 m**-3
Fe 13+: 0.024    n_i = 4.20e-02 m**-3
----------------------------------------------------------------
n_e = 6.39e+02 m**-3
----------------------------------------------------------------
[21]:
fig, axes = plt.subplots(1, 3, figsize=(10, 3), tight_layout=True)

for state, ax in zip(states, axes, strict=False):
    ax.bar(state.charge_numbers, state.ionic_fractions)
    ax.set_title(f"Ionization state for {state.base_particle}")
    ax.set_xlabel("ionic level")
    ax.set_ylabel("log$_{10}$ of ionic fraction")
    ax.set_yscale("log")
../../_images/notebooks_particles_ace_40_0.png

The wide range of average ionic levels for each element is strong evidence that the plasma observed by ACE originated from a wide range of temperatures. The lowest charge states are evidence of cool filament plasma while the high charge states are evidence of rapidly heated plasma.