예제 #1
0
def test_ionization_state_ion_input_error():
    """
    Test that `~plasmapy.particles.IonizationState` raises the appropriate
    exception when an ion is the base particle and ionic fractions are
    specified
    """

    ion = "He 1+"
    unnecessary_ionic_fractions = [0.0, 0.0, 1.0]

    with pytest.raises(ParticleError):
        IonizationState(ion, ionic_fractions=unnecessary_ionic_fractions)
예제 #2
0
 def setup_class(self):
     self.element = "H"
     self.valid_number_densities = u.Quantity([0.1, 0.2], unit=u.m**-3)
     self.expected_n_elem = np.sum(self.valid_number_densities)
     self.expected_ionic_fractions = (self.valid_number_densities /
                                      self.expected_n_elem)
     try:
         self.instance = IonizationState(self.element)
     except Exception:
         pytest.fail(
             "Unable to instantiate IonizationState with no ionic fractions."
         )
예제 #3
0
def test_nans():
    """
    Test that when no ionic fractions or temperature are inputted,
    the result is an array full of `~numpy.nan` of the right size.
    """
    element = "He"
    nstates = atomic_number(element) + 1
    instance = IonizationState(element)
    assert (len(instance.ionic_fractions) == nstates
            ), f"Incorrect number of ionization states for {element}"
    assert np.all([
        np.isnan(instance.ionic_fractions)
    ]), ("The ionic fractions for IonizationState are not defaulting "
         "to numpy.nan when not set by user.")
예제 #4
0
def test_IonizationState_ionfracs_from_ion_input(ion):

    ionization_state = IonizationState(ion)
    ion_particle = Particle(ion)
    actual_ionic_fractions = ionization_state.ionic_fractions

    expected_ionic_fractions = np.zeros(ion_particle.atomic_number + 1)
    expected_ionic_fractions[ion_particle.integer_charge] = 1.0

    if not np.allclose(expected_ionic_fractions, actual_ionic_fractions, atol=1e-16):
        pytest.fail(
            f"The returned ionic fraction for IonizationState({repr(ion)}) "
            f"should have entirely been in the Z = {ion_particle.integer_charge} "
            f"level, but was instead: {ionization_state.ionic_fractions}."
        )
 def __next__(self):
     if self._element_index < len(self.base_particles):
         particle = self.base_particles[self._element_index]
         result = IonizationState(
             particle,
             self.ionic_fractions[particle],
             T_e=self.T_e,
             n_elem=np.sum(self.number_densities[particle]),
             tol=self.tol,
         )
         self._element_index += 1
         return result
     else:
         del self._element_index
         raise StopIteration
예제 #6
0
def test_IonizationState_base_particles_from_ion_input(ion):
    """
    Test that supplying an ion to IonizationState will result in the
    base particle being the corresponding isotope or ion and that the
    ionic fraction of the corresponding charge level is 100%.
    """

    ionization_state = IonizationState(ion)
    ion_particle = Particle(ion)

    expected_base_particle = ion_particle.isotope or ion_particle.element
    if expected_base_particle != ionization_state.base_particle:
        pytest.fail(
            f"The expected base particle was {expected_base_particle}, "
            f"but the returned base particle was {ionization_state.base_particle}. "
        )
예제 #7
0
def test_IonizationState_ionfracs_from_ion_input(ion):

    ionization_state = IonizationState(ion)
    ion_particle = Particle(ion)
    actual_ionic_fractions = ionization_state.ionic_fractions

    expected_ionic_fractions = np.zeros(ion_particle.atomic_number + 1)
    expected_ionic_fractions[ion_particle.charge_number] = 1.0

    np.testing.assert_allclose(
        expected_ionic_fractions,
        actual_ionic_fractions,
        atol=1e-16,
        err_msg=f"The returned ionic fraction for IonizationState({repr(ion)}) "
        f"should have entirely been in the Z = {ion_particle.integer_charge} "
        f"level.",
    )
예제 #8
0
def test_exclude_neutrals_from_average_ion():
    """
    Test that the `IonizationState.average_ion` method returns a
    |CustomParticle| that does not include neutrals in the averaging
    when the ``include_neutrals`` keyword is `False`.
    """
    base_particle = Particle("He-4")
    ionization_state_without_neutrals = IonizationState(base_particle, [0, 0.2, 0.8])
    expected_average_ion = ionization_state_without_neutrals.average_ion()
    ionization_state_with_neutrals = IonizationState(base_particle, [0.50, 0.1, 0.4])
    actual_average_ion = ionization_state_with_neutrals.average_ion(
        include_neutrals=False
    )
    assert actual_average_ion == expected_average_ion
예제 #9
0
    def __getitem__(self, *values) -> IonizationState:

        errmsg = f"Invalid indexing for IonizationStates instance: {values[0]}"

        one_input = not isinstance(values[0], tuple)
        two_inputs = len(values[0]) == 2

        if not one_input and not two_inputs:
            raise IndexError(errmsg)

        try:
            arg1 = values[0] if one_input else values[0][0]
            int_charge = None if one_input else values[0][1]
            particle = arg1 if arg1 in self.base_particles else particle_symbol(arg1)

            if int_charge is None:
                return IonizationState(
                    particle=particle,
                    ionic_fractions=self.ionic_fractions[particle],
                    T_e=self._pars["T_e"],
                    n_elem=np.sum(self.number_densities[particle]),
                    tol=self.tol,
                )
            else:
                if not isinstance(int_charge, Integral):
                    raise TypeError(
                        f"{int_charge} is not a valid charge for {particle}."
                    )
                elif not 0 <= int_charge <= atomic_number(particle):
                    raise ChargeError(
                        f"{int_charge} is not a valid charge for {particle}."
                    )
                return State(
                    integer_charge=int_charge,
                    ionic_fraction=self.ionic_fractions[particle][int_charge],
                    ionic_symbol=particle_symbol(particle, Z=int_charge),
                    number_density=self.number_densities[particle][int_charge],
                )
        except Exception as exc:
            raise IndexError(errmsg) from exc
예제 #10
0
 def test_instantiation(self, test_name):
     """
     Test that each IonizationState test case can be instantiated.
     """
     self.instances[test_name] = IonizationState(**test_cases[test_name])
예제 #11
0
    "element": "He",
    "atomic_number": 2,
    "Z_mean": 1.3,
    "Z_rms": 1.51657508881031,
    "n_e": 1.3e19 * u.m ** -3,
    "n_elem": 1e19 * u.m ** -3,
    "integer_charges": [0, 1, 2],
    "ionic_fractions": np.array([0.2, 0.3, 0.5]),
    "ionic_symbols": ["He-4 0+", "He-4 1+", "He-4 2+"],
    "_is_normalized()": True,
    "number_densities": np.array([2e18, 3e18, 5e18]) * u.m ** -3,
    "tol": 2e-14,
    "__str__()": "<IonizationState instance for He-4>",
}

instance = IonizationState(**kwargs)


@pytest.mark.parametrize("key", expected_properties.keys())
def test_IonizationState_attributes(key):
    """
    Test a specific case that the `IonizationState` attributes are
    working as expected.
    """
    expected = expected_properties[key]
    actual = eval(f"instance.{key}")

    if isinstance(expected, u.Quantity):
        assert expected.unit == actual.unit, f"Unit mismatch for IonizationState.{key}"
        assert np.allclose(
            expected, actual, atol=1e-15 * expected.unit
예제 #12
0
def test_ionization_state_inequality_and_identity():
    deuterium_states = IonizationState("D+", n_elem=1e20 * u.m**-3, T_e=10 * u.eV)
    tritium_states = IonizationState("T+", n_elem=1e20 * u.m**-3, T_e=10 * u.eV)
    assert deuterium_states != tritium_states
예제 #13
0
def test_setting_ionic_fractions():
    instance = IonizationState("He")
    new_ionic_fractions = [0.2, 0.5, 0.3]
    instance.ionic_fractions = new_ionic_fractions
    assert np.allclose(instance.ionic_fractions, new_ionic_fractions)