Repository: PlasmaPy/PlasmaPy
Pull request #805 (2020-05-10 00:50:28)

Add `relativistic_energy` to the Formulary
<!--
Thank you for contributing to PlasmaPy! Here's a bunch of pointers to
make things easier for all of us:

* If this PR will solve an issue tracked by GitHub, please add a phrase like
  "Closes #404." to automatically close the issue once the pull request is
  merged.  If your PR will not completely solve the issue, please still
  reference the issue. For an overview of this functionality, see
  https://help.github.com/articles/closing-issues-using-keywords/

* Remember to add some description of your changes in this text box.

* Tests and docstrings are required for new or changed functionality.
  Please make sure tests are passing before requesting a review - they
  will pop up at the bottom, in the Checks box. If you're unsure why
  they're failing, ask!
  
* If your pull request is not yet ready for review, submit it as a draft.
  Remember to change its' status once it's ready.

* If this is your first contribution, please add your name to the author
  list in `docs/about/credits.rst`.
  
* Feel free to chat with other developers on our Matrix channel at:
   https://riot.im/app/#/room/#plasmapy:openastronomy.org
  
* We have a developer's guide, where some answers to your questions may
  possibly be found, at
  http://docs.plasmapy.org/en/master/development/index.html

Many thanks in advance for following these pointers and for being willing to contribute!

When submitting a pull request, please ensure that you can (eventually,
sometime before it is merged) check the following basic requirements:

-->

- [x] I have added a changelog entry for this pull request (please see
  `changelog/README.rst` for instructions, and if you need help with picking the PR type, ask!)
- [x] If adding new functionality, I have added (passing) tests and
      docstrings. (Tests pop up at the bottom, in the checks box).
- [x] I have fixed any new failing tests (if you're unsure why
  they're failing, ask!).


codecov[bot]: # [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=h1) Report
> Merging [#805](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/860efdd92f766f2cbafde4b0b136bf698c9bd3d7&el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/graphs/tree.svg?width=650&height=150&src=pr&token=LzZ5mnXVad)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #805      +/-   ##
==========================================
- Coverage   95.86%   95.84%   -0.03%     
==========================================
  Files          56       56              
  Lines        5108     5075      -33     
==========================================
- Hits         4897     4864      -33     
  Misses        211      211              
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/formulary/relativity.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvZm9ybXVsYXJ5L3JlbGF0aXZpdHkucHk=) | `100.00% <100.00%> (ø)` | |
| [plasmapy/classes/plasma\_base.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvY2xhc3Nlcy9wbGFzbWFfYmFzZS5weQ==) | `67.74% <0.00%> (-4.49%)` | :arrow_down: |
| [plasmapy/simulation/abstractions.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvc2ltdWxhdGlvbi9hYnN0cmFjdGlvbnMucHk=) | `75.00% <0.00%> (-2.78%)` | :arrow_down: |
| [plasmapy/classes/sources/openpmd\_hdf5.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvY2xhc3Nlcy9zb3VyY2VzL29wZW5wbWRfaGRmNS5weQ==) | `78.40% <0.00%> (-1.17%)` | :arrow_down: |
| [plasmapy/simulation/particletracker.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvc2ltdWxhdGlvbi9wYXJ0aWNsZXRyYWNrZXIucHk=) | `98.27% <0.00%> (-0.03%)` | :arrow_down: |
| [plasmapy/particles/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvcGFydGljbGVzL2lvbml6YXRpb25fc3RhdGUucHk=) | `92.91% <0.00%> (-0.03%)` | :arrow_down: |
| [plasmapy/utils/pytest\_helpers/pytest\_helpers.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvdXRpbHMvcHl0ZXN0X2hlbHBlcnMvcHl0ZXN0X2hlbHBlcnMucHk=) | `93.38% <0.00%> (-0.03%)` | :arrow_down: |
| [plasmapy/particles/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvcGFydGljbGVzL3BhcnRpY2xlX2NsYXNzLnB5) | `95.73% <0.00%> (-0.01%)` | :arrow_down: |
| [plasmapy/formulary/braginskii.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvZm9ybXVsYXJ5L2JyYWdpbnNraWkucHk=) | `99.72% <0.00%> (-0.01%)` | :arrow_down: |
| [plasmapy/utils/decorators/checks.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree#diff-cGxhc21hcHkvdXRpbHMvZGVjb3JhdG9ycy9jaGVja3MucHk=) | `100.00% <0.00%> (ø)` | |
| ... and [5 more](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=footer). Last update [860efdd...ad6a469](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/805?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

pep8speaks: Hello @KhalilBryant! Thanks for updating your pull request.

* In the file [`plasmapy/formulary/relativity.py`](https://github.com/PlasmaPy/PlasmaPy/blob/d8935db179f237ebc50fdc0380428423996b6947/plasmapy/formulary/relativity.py):

> [Line 92:1](https://github.com/PlasmaPy/PlasmaPy/blob/d8935db179f237ebc50fdc0380428423996b6947/plasmapy/formulary/relativity.py#L92): [E302](https://duckduckgo.com/?q=pep8%20E302) expected 2 blank lines, found 1



Patch:
diff --git a/changelog/805.feature.rst b/changelog/805.feature.rst
new file mode 100644
index 00000000..cc4e5642
--- /dev/null
+++ b/changelog/805.feature.rst
@@ -0,0 +1,1 @@
+Create :func:`~plasmapy.formulary.relativity.relativistic_energy` function, which uses the established :func:`~plamsapy.formulary.relativity.Lorentz_factor` function to aid in the calculation of the relativistic energy of an object.
diff --git a/plasmapy/formulary/relativity.py b/plasmapy/formulary/relativity.py
index 1219db1e..1bc83527 100644
--- a/plasmapy/formulary/relativity.py
+++ b/plasmapy/formulary/relativity.py
@@ -1,8 +1,5 @@
-r"""This module currently provides ample room for the Lorentz factor,
-as it turned out we didn't really have much else of the relativistic
-variety to add just yet! This is expected to change in the future.
-"""
-__all__ = ["Lorentz_factor"]
+r"""Functionality for calculating relativistic quantities (:math:`v \to c`)."""
+__all__ = ["Lorentz_factor", "relativistic_energy"]
 
 import numpy as np
 
@@ -88,3 +85,71 @@ def Lorentz_factor(V: u.m / u.s):
             gamma = ((1 - (V / c) ** 2) ** -0.5).value
 
     return gamma
+
+
+@validate_quantities(m={"can_be_negative": False}, 
+                     validations_on_return={"can_be_negative": False})
+def relativistic_energy(m: u.kg, v: u.m / u.s) -> u.Joule:
+    """
+    Calculate the relativistic energy (in Joules) of an object of mass 
+    `m` and velocity `v`.
+    
+    .. math::
+
+        E = \\gamma m c^{2}
+    
+    where :math:`\\gamma` is the `Lorentz_factor`.
+
+    Parameters
+    ----------
+    m : `~astropy.units.Quantity`
+        The mass in units convertible to kilograms.
+
+    v : `~astropy.units.Quantity`
+        The velocity in units convertible to meters per second.
+
+    Returns
+    -------
+    `~astropy.Quantity`
+        The relativistic energy (in Joules) of an object of mass `m` moving at velocity `v`.
+
+    Raises
+    ------
+    TypeError
+        If input arguments are not instances `~astropy.units.Quantity` or
+        convertible to a `~astropy.units.Quantity`.
+
+    ~astropy.units.UnitConversionError
+        If the `v` is not in appropriate units.
+
+    ValueError
+        If the magnitude of `m` is negative or arguments are complex.
+
+    :exc:`~plasmapy.utils.exceptions.RelativityError`
+        If the velocity `v` is greater than the speed of light.
+
+    Warns
+    -----
+    : `~astropy.units.UnitsWarning`
+        If units are not provided, SI units are assumed.
+
+    Examples
+    --------
+    >>> from astropy import units as u
+    >>> velocity = 1.4e8 * u.m / u.s
+    >>> mass = 1 * u.kg
+    >>> relativistic_energy(mass, velocity)
+    <Quantity 1.01638929e+17 J>
+    >>> relativistic_energy(mass, 299792458*u.m / u.s)
+    <Quantity inf J>
+    >>> relativistic_energy(1 * u.mg, 1.4e8 * u.m / u.s)
+    <Quantity 1.01638929e+11 J>
+    >>> relativistic_energy(-mass, velocity)
+    Traceback (most recent call last):
+        ...
+    ValueError: The argument 'm' to function relativistic_energy() can not contain negative numbers.
+    """
+
+    gamma = Lorentz_factor(v)
+    E = gamma * m * c ** 2
+    return E


Test patch:
diff --git a/plasmapy/formulary/tests/test_relativity.py b/plasmapy/formulary/tests/test_relativity.py
index 8894cf61..074ff574 100644
--- a/plasmapy/formulary/tests/test_relativity.py
+++ b/plasmapy/formulary/tests/test_relativity.py
@@ -2,9 +2,10 @@
 
 import pytest
 import numpy as np
+
 from astropy import units as u
 from astropy.constants import c
-from plasmapy.formulary.relativity import Lorentz_factor
+from plasmapy.formulary.relativity import Lorentz_factor, relativistic_energy
 from plasmapy.utils.exceptions import RelativityError
 
 
@@ -38,3 +39,37 @@ def test_Lorentz_factor():
 
     with pytest.raises(u.UnitTypeError):
         Lorentz_factor(4 * u.kg)
+
+
+def test_relativistic_energy():
+    r"""Test relativistic_energy in relativity.py"""
+
+    v = 123456789 * u.m / u.s
+    m = 1 * u.kg
+    assert np.isclose(relativistic_energy(m, v).value, ((1 / np.sqrt(1 - v ** 2 / c ** 2)) * m * c ** 2).value)
+    assert relativistic_energy(m, -v) == relativistic_energy(m, v)
+
+    assert np.isclose(relativistic_energy(m, 0 * u.m / u.s).value, (m * c ** 2).value)
+    assert relativistic_energy(m, c) == np.inf
+
+    V_arr = np.array([987532.0, 299792458]) * u.m / u.s
+    Energy_arr = relativistic_energy(m, V_arr)
+    assert np.isclose(Energy_arr[0].value, ((1 / np.sqrt(1 - V_arr[0] ** 2 / c ** 2)) * m * c ** 2).value)
+    assert Energy_arr[1] == np.inf
+
+    assert relativistic_energy(2 * u.kg, 3 * u.m / u.s).unit == u.J
+
+    with pytest.raises(RelativityError):
+        relativistic_energy(m, 1.0000000001 * c)
+
+    with pytest.raises(RelativityError), pytest.warns(u.UnitsWarning):
+        relativistic_energy(1, 299792459)
+
+    with pytest.warns(u.UnitsWarning):
+        relativistic_energy(m, 2.2)
+
+    with pytest.raises(u.UnitTypeError):
+        relativistic_energy(m, 4 * u.kg)
+
+    with pytest.raises(ValueError):
+        relativistic_energy(-m, v)