Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/pr/385'
Browse files Browse the repository at this point in the history
  • Loading branch information
StanczakDominik committed Oct 5, 2018
2 parents 3988303 + f414b8c commit 07eb8d8
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 62 deletions.
2 changes: 0 additions & 2 deletions plasmapy/atomic/atomic.py
@@ -1,6 +1,5 @@
"""Functions that retrieve or are related to elemental or isotopic data."""

import warnings
from typing import (
Union,
Optional,
Expand All @@ -21,7 +20,6 @@
InvalidParticleError,
InvalidElementError,
InvalidIsotopeError,
InvalidIonError,
MissingAtomicDataError,
)

Expand Down
68 changes: 56 additions & 12 deletions plasmapy/atomic/nuclear.py
@@ -1,6 +1,6 @@
"""Functions that are related to nuclear reactions."""

from astropy import units as u, constants
from astropy import units as u
from typing import List, Union
import re

Expand All @@ -15,6 +15,7 @@
__all__ = [
"nuclear_binding_energy",
"nuclear_reaction_energy",
"mass_energy",
]


Expand All @@ -37,7 +38,7 @@ def nuclear_binding_energy(particle: Particle, mass_numb: int = None) -> u.Quant
Returns
-------
binding_energy: `~astropy.units.Quantity`
The binding energy of the nucleus in units of Joules.
The binding energy of the nucleus in units of joules.
Raises
------
Expand All @@ -52,9 +53,12 @@ def nuclear_binding_energy(particle: Particle, mass_numb: int = None) -> u.Quant
See Also
--------
`~plasmapy.atomic.nuclear_reaction_energy` : Returns the change in
`~plasmapy.atomic.nuclear_reaction_energy` : Return the change in
binding energy during nuclear fusion or fission reactions.
`~plasmapy.atomic.mass_energy` : Return the mass energy of a
nucleon or particle.
Examples
--------
>>> from astropy import units as u
Expand All @@ -74,6 +78,46 @@ def nuclear_binding_energy(particle: Particle, mass_numb: int = None) -> u.Quant
return particle.binding_energy.to(u.J)


@particle_input
def mass_energy(particle: Particle, mass_numb: int = None) -> u.Quantity:
"""
Return a particle's mass energy. If the particle is an isotope or
nuclide, return the nuclear mass energy only.
Parameters
----------
particle: `str`, `int`, or `~plasmapy.atomic.Particle`
A Particle object, a string representing an element or isotope,
or an integer representing the atomic number of an element.
mass_numb: `int` (optional)
The mass number of an isotope, which is required if and only
if the first argument can only be used to determine the
element and not the isotope.
Returns
-------
mass_energy: `~astropy.units.Quantity`
The mass energy of the particle (or in the case of ) in units of joules.
Raises
------
`~plasmapy.utils.InvalidParticleError`
If the inputs do not correspond to a valid particle.
`~plasmapy.utils.AtomicError`
If the inputs do not correspond to a valid isotope or nucleon.
`TypeError`
If the inputs are not of the correct types.
>>> mass_energy('He-4')
<Quantity 5.97191997e-10 J>
"""
return particle.mass_energy


def nuclear_reaction_energy(*args, **kwargs):
"""
Return the released energy from a nuclear reaction.
Expand Down Expand Up @@ -129,16 +173,19 @@ def nuclear_reaction_energy(*args, **kwargs):
Examples
--------
>>> from astropy import units as u
>>> nuclear_reaction_energy("D + T --> alpha + n")
<Quantity 2.81812097e-12 J>
>>> triple_alpha1 = '2*He-4 --> Be-8'
>>> triple_alpha2 = 'Be-8 + alpha --> carbon-12'
>>> energy_triplealpha1 = nuclear_reaction_energy(triple_alpha1)
>>> energy_triplealpha2 = nuclear_reaction_energy(triple_alpha2)
>>> print(energy_triplealpha1, energy_triplealpha2)
-1.4714307834388437e-14 J 1.18025735267267e-12 J
-1.4714307834388437e-14 J 1.1802573526724632e-12 J
>>> energy_triplealpha2.to(u.MeV)
<Quantity 7.36658704 MeV>
>>> nuclear_reaction_energy(reactants=['n'], products=['p+', 'e-'])
<Quantity 1.25343511e-13 J>
Expand Down Expand Up @@ -229,13 +276,10 @@ def add_mass_energy(particles: List[Particle]) -> u.Quantity:
Find the total mass energy from a list of particles, while
taking the masses of the fully ionized isotopes.
"""
total_mass = 0.0 * u.kg
total_mass_energy = 0.0 * u.J
for particle in particles:
if particle.isotope:
total_mass += particle.nuclide_mass
else:
total_mass += particle.mass
return (total_mass * constants.c ** 2).to(u.J)
total_mass_energy += particle.mass_energy
return total_mass_energy.to(u.J)

input_err_msg = (
"The inputs to nuclear_reaction_energy should be either "
Expand Down Expand Up @@ -266,8 +310,8 @@ def add_mass_energy(particles: List[Particle]) -> u.Quantity:

try:
LHS_string, RHS_string = re.split('-+>', reaction)
LHS_list = re.split(' \+ ', LHS_string)
RHS_list = re.split(' \+ ', RHS_string)
LHS_list = re.split(r' \+ ', LHS_string)
RHS_list = re.split(r' \+ ', RHS_string)
reactants = process_particles_list(LHS_list)
products = process_particles_list(RHS_list)
except Exception as ex:
Expand Down
6 changes: 5 additions & 1 deletion plasmapy/atomic/parsing.py
Expand Up @@ -6,7 +6,11 @@
from typing import (Union, Dict)
import numbers

from plasmapy.atomic.elements import (_atomic_numbers_to_symbols, _element_names_to_symbols, _Elements)
from plasmapy.atomic.elements import (
_atomic_numbers_to_symbols,
_element_names_to_symbols,
_Elements)

from plasmapy.atomic.isotopes import _Isotopes
from plasmapy.atomic.special_particles import _Particles, ParticleZoo

Expand Down
164 changes: 124 additions & 40 deletions plasmapy/atomic/particle_class.py
Expand Up @@ -276,7 +276,7 @@ class Particle:
``'post-transition metal'``, ``'proton'``, ``'stable'``,
``'transition metal'``, ``'uncharged'``, and ``'unstable'``.
"""
"""

def __init__(
self,
Expand Down Expand Up @@ -906,6 +906,129 @@ def mass(self) -> u.Quantity:

raise MissingAtomicDataError(f"The mass of {self} is not available.")

@property
def nuclide_mass(self) -> u.Quantity:
"""
Return the mass of the bare nucleus of an isotope or a neutron.
This attribute will raise a
`~plasmapy.utils.InvalidIsotopeError` if the particle is not an
isotope or neutron, or a
`~plasmapy.utils.MissingAtomicDataError` if the isotope mass is
not available.
Examples
--------
>>> deuterium = Particle('D')
>>> deuterium.nuclide_mass
<Quantity 3.34358372e-27 kg>
"""

if self.isotope == 'H-1':
return const.m_p
elif self.isotope == 'D':
return _special_ion_masses['D 1+']
elif self.isotope == 'T':
return _special_ion_masses['T 1+']
elif self.particle == 'n':
return const.m_n

if not self.isotope:
raise InvalidIsotopeError(_category_errmsg(self, 'isotope'))

base_mass = self._attributes['isotope mass']

if base_mass is None: # coverage: ignore
raise MissingAtomicDataError(f"The mass of a {self.isotope} nuclide is not available.")

_nuclide_mass = self._attributes['isotope mass'] - self.atomic_number * const.m_e

return _nuclide_mass.to(u.kg)

@property
def mass_energy(self) -> u.Quantity:
"""
Return the mass energy of the particle in joules.
If the particle is an isotope or nuclide, return the mass energy
of the nucleus only.
If the mass of the particle is not known, then raise a
`~plasmapy.utils.MissingAtomicDataError`.
Examples
--------
>>> proton = Particle('p+')
>>> proton.mass_energy
<Quantity 1.50327759e-10 J>
>>> protium = Particle('H-1 0+')
>>> protium.mass_energy
<Quantity 1.50327759e-10 J>
>>> electron = Particle('electron')
>>> electron.mass_energy.to('MeV')
<Quantity 0.51099895 MeV>
"""
try:
mass = self.nuclide_mass if self.isotope else self.mass
energy = mass * const.c ** 2
return energy.to(u.J)
except MissingAtomicDataError:
raise MissingAtomicDataError(
f"The mass energy of {self.particle} is not available "
f"because the mass is unknown.") from None

@property
def binding_energy(self) -> u.Quantity:
"""
Return the nuclear binding energy in joules.
This attribute will raise an
`~plasmapy.utils.InvalidIsotopeError` if the particle is not a
nucleon or isotope.
Examples
--------
>>> alpha = Particle('alpha')
>>> alpha.binding_energy
<Quantity 4.53346938e-12 J>
>>> Particle('T').binding_energy.to('MeV')
<Quantity 8.48179621 MeV>
The binding energy of a nucleon equals 0 joules.
>>> neutron = Particle('n')
>>> proton = Particle('p+')
>>> neutron.binding_energy
<Quantity 0. J>
>>> proton.binding_energy
<Quantity 0. J>
"""

if self._attributes['baryon number'] == 1:
return 0 * u.J

if not self.isotope:
raise InvalidIsotopeError(
f"The nuclear binding energy may only be calculated for nucleons and isotopes.")

number_of_protons = self.atomic_number
number_of_neutrons = self.mass_number - self.atomic_number

mass_of_protons = number_of_protons * const.m_p
mass_of_neutrons = number_of_neutrons * const.m_n

mass_of_nucleons = mass_of_protons + mass_of_neutrons

mass_defect = mass_of_nucleons - self.nuclide_mass
nuclear_binding_energy = mass_defect * const.c ** 2

return nuclear_binding_energy.to(u.J)

@property
def atomic_number(self) -> numbers.Integral:
"""
Expand Down Expand Up @@ -1086,45 +1209,6 @@ def lepton_number(self) -> numbers.Integral:
f"The lepton number for {self.particle} is not available.")
return self._attributes['lepton number']

@property
def binding_energy(self) -> u.Quantity:
"""
Return the nuclear binding energy in joules.
This attribute will raise an
`~plasmapy.utils.InvalidIsotopeError` if the particle is not a
nucleon or isotope.
Examples
--------
>>> alpha = Particle('alpha')
>>> alpha.binding_energy
<Quantity 4.53346938e-12 J>
>>> Particle('T').binding_energy.to('MeV')
<Quantity 8.48179621 MeV>
"""

if self._attributes['baryon number'] == 1:
return 0 * u.J

if not self.isotope:
raise InvalidIsotopeError(
f"The nuclear binding energy may only be calculated for nucleons and isotopes.")

number_of_protons = self.atomic_number
number_of_neutrons = self.mass_number - self.atomic_number

mass_of_protons = number_of_protons * const.m_p
mass_of_neutrons = number_of_neutrons * const.m_n

mass_of_nucleons = mass_of_protons + mass_of_neutrons

mass_defect = mass_of_nucleons - self.nuclide_mass
nuclear_binding_energy = mass_defect * const.c ** 2

return nuclear_binding_energy.to(u.J)

@property
def half_life(self) -> Union[u.Quantity, str]:
"""
Expand Down
3 changes: 1 addition & 2 deletions plasmapy/atomic/special_particles.py
Expand Up @@ -3,13 +3,12 @@
information for special particles.
"""

from typing import Set, Dict, List, Optional, Union
from typing import Set, Dict
from astropy import units as u, constants as const
import numpy as np
from plasmapy.atomic.elements import _PeriodicTable



class _ParticleZooClass:
"""
Create an object with taxonomy information for special particles.
Expand Down
1 change: 1 addition & 0 deletions plasmapy/atomic/tests/test_atomic.py
Expand Up @@ -414,6 +414,7 @@ def test_periodic_table_group(self):
with pytest.raises(TypeError):
periodic_table_group(('B', 'Ti', 'Ge'))


# The tables above do not include the function to be tested in order to
# avoid cluttering up the code. The following block of code prepends
# the correct function to each list containing args, kwargs, and the
Expand Down
10 changes: 8 additions & 2 deletions plasmapy/atomic/tests/test_nuclear.py
@@ -1,8 +1,9 @@
from astropy import units as u
from astropy import units as u, constants as const
import numpy as np
from ..nuclear import nuclear_binding_energy, nuclear_reaction_energy
from ..nuclear import nuclear_binding_energy, nuclear_reaction_energy, mass_energy
from ...utils import (
InvalidParticleError,
InvalidIsotopeError,
AtomicError,
run_test,
run_test_equivalent_calls,
Expand All @@ -17,6 +18,11 @@
[nuclear_binding_energy, 'He-99', {}, InvalidParticleError],
[nuclear_binding_energy, "He", {"mass_numb": 99}, InvalidParticleError],
[nuclear_binding_energy, 3.1415926535j, {}, TypeError],
[mass_energy, 'e-', {}, (const.m_e * const.c ** 2).to(u.J)],
[mass_energy, 'p+', {}, (const.m_p * const.c ** 2).to(u.J)],
[mass_energy, 'H-1', {}, (const.m_p * const.c ** 2).to(u.J)],
[mass_energy, 'H-1 0+', {}, (const.m_p * const.c ** 2).to(u.J)],
[mass_energy, 'n', {}, (const.m_n * const.c ** 2).to(u.J)],
[nuclear_reaction_energy, (), {'reactants': ['n'], 'products': 3}, TypeError],
[nuclear_reaction_energy, (), {'reactants': ['n'], 'products': ['He-4']}, AtomicError],
[nuclear_reaction_energy, (), {'reactants': ['h'], 'products': ['H-1']}, AtomicError],
Expand Down

0 comments on commit 07eb8d8

Please sign in to comment.