Repository: PlasmaPy/PlasmaPy

Issue:
`plasmapy.formulary.quantum.chemical_potential` bug with powers
The current doctest error for `plasmapy.formulary.quantum.chemical_formula()` is a result of a floating point arithmetic error...

<img width="805" alt="image" src="https://user-images.githubusercontent.com/29869348/69690641-5d474980-1081-11ea-95fc-86d0d29e34fa.png">

There is a large difference in `n_e` when we convert from `cm ** -3` to `m ** -3`...

```python
>>> (1.e27*u.m**-3) - (1.e21*u.cm**-3).to(u.m**-3)
<Quantity 1.37438953e+11 1 / m3>
```

Thus, even though the inputs are essentially identical, the following yields...

```python
>>> chemical_potential(1.e27 ** u.m ** -3, 11000 * u.K)
<Quantity 2.00039985e-12>

>>> chemical_potential(1.e21 ** u.cm ** -3, 11000 * u.K)
<Quantity 5.1487703e-12>
```

@namurphy @StanczakDominik Thoughts???  If we can't figure out a quick fix, then I feel like we should exclude this code from the source until we determine a solution.

_Originally posted by @rocco8773 in https://github.com/PlasmaPy/PlasmaPy/pull/722#issuecomment-558917491_


Discussion:
This issue has been raised on AstroPy ([#9721](https://github.com/astropy/astropy/issues/9721)).
@StanczakDominik I think this is working now, I get identical outputs for your given example case
Huh! Can you try removing `@pytest.mark.xfail` from the related tests in `quantum` to trigger CI runs for this?
I'm getting an assertion error for the known test case... Was the test case itself calculated incorrectly?
Could be! Can you post that as a PR?

Resolving patch:
diff --git a/plasmapy/formulary/collisions.py b/plasmapy/formulary/collisions.py
--- a/plasmapy/formulary/collisions.py
+++ b/plasmapy/formulary/collisions.py
@@ -2019,7 +2019,7 @@ def coupling_parameter(
         fermi_integral = Fermi_integral(chem_potential.si.value, 1.5)
         denominator = (n_e * lambda_deBroglie**3) * fermi_integral
         kinetic_energy = 2 * k_B * T / denominator
-        if np.all(np.imag(kinetic_energy) == 0):
+        if np.all(np.imag(kinetic_energy) < 1e-15 * u.J):
             kinetic_energy = np.real(kinetic_energy)
         else:  # coverage: ignore
             raise ValueError(
diff --git a/plasmapy/formulary/quantum.py b/plasmapy/formulary/quantum.py
--- a/plasmapy/formulary/quantum.py
+++ b/plasmapy/formulary/quantum.py
@@ -397,9 +397,6 @@ def Wigner_Seitz_radius(n: u.m**-3) -> u.m:
     return (3 / (4 * np.pi * n)) ** (1 / 3)
 
 
-# TODO: remove NotImplementedError and 'doctest: +SKIP' when the following issues are addressed...
-#       https://github.com/PlasmaPy/PlasmaPy/issues/726
-#       https://github.com/astropy/astropy/issues/9721
 @validate_quantities(
     n_e={"can_be_negative": False},
     T={"can_be_negative": False, "equivalencies": u.temperature_energy()},
@@ -461,25 +458,13 @@ def chemical_potential(n_e: u.m**-3, T: u.K) -> u.dimensionless_unscaled:
     This function returns :math:`β μ^{ideal}` the dimensionless
     ideal chemical potential.
 
-    Warnings
-    --------
-    At present this function is limited to relatively small arguments
-    due to limitations in the ``mpmath.polylog``, which PlasmaPy uses in
-    calculating the Fermi integral.
-
     Examples
     --------
     >>> from astropy import units as u
-    >>> chemical_potential(n_e=1e21*u.cm**-3,T=11000*u.K)  # doctest: +SKIP
-    <Quantity 2.00039985e-12>
+    >>> chemical_potential(n_e=1e21*u.cm**-3,T=11000*u.K)
+    <Quantity 9.28146e-14>
     """
 
-    raise NotImplementedError(
-        "This function has been temporarily disabled due to a bug.\n"
-        "Please refer to https://github.com/PlasmaPy/PlasmaPy/issues/726 \n"
-        "and https://github.com/astropy/astropy/issues/9721 "
-        "for progress in fixing it."
-    )
     # deBroglie wavelength
     lambdaDB = thermal_deBroglie_wavelength(T)
     # degeneracy parameter
@@ -491,7 +476,7 @@ def residual(params, data, eps_data):
         # note that alpha = mu / (k_B * T)
         model = mathematics.Fermi_integral(alpha, 0.5)
         complexResidue = (data - model) / eps_data
-        return complexResidue.view(np.float)
+        return complexResidue.view(np.float64)
 
     # setting parameters for fitting along with bounds
     alphaGuess = 1 * u.dimensionless_unscaled
@@ -505,10 +490,6 @@ def residual(params, data, eps_data):
     return beta_mu
 
 
-# TODO: decorate with validate_quantities
-# TODO: remove NotImplementedError and 'doctest: +SKIP' when the following issues are addressed...
-#       https://github.com/PlasmaPy/PlasmaPy/issues/726
-#       https://github.com/astropy/astropy/issues/9721
 def _chemical_potential_interp(n_e, T):
     r"""
     Fitting formula for interpolating chemical potential between classical
@@ -575,16 +556,10 @@ def _chemical_potential_interp(n_e, T):
     Examples
     --------
     >>> from astropy import units as u
-    >>> _chemical_potential_interp(n_e=1e23*u.cm**-3, T=11000*u.K)  # doctest: +SKIP
+    >>> _chemical_potential_interp(n_e=1e23*u.cm**-3, T=11000*u.K)
     <Quantity 8.17649>
 
     """
-    raise NotImplementedError(
-        "This function has been temporarily disabled due to a bug.\n"
-        "Please refer to https://github.com/PlasmaPy/PlasmaPy/issues/726 \n"
-        "and https://github.com/astropy/astropy/issues/9721 "
-        "for progress in fixing it."
-    )
     A = 0.25945
     B = 0.072
     b = 0.858


Test patch:
diff --git a/plasmapy/formulary/tests/test_collisions.py b/plasmapy/formulary/tests/test_collisions.py
--- a/plasmapy/formulary/tests/test_collisions.py
+++ b/plasmapy/formulary/tests/test_collisions.py
@@ -1670,17 +1670,19 @@ def test_zmean(self):
     # TODO vector z_mean
     @pytest.mark.parametrize("insert_some_nans", [[], ["V"]])
     @pytest.mark.parametrize("insert_all_nans", [[], ["V"]])
-    # @pytest.mark.parametrize("kwargs", [{"method": "classical"},
-    #                                     {"method": "quantum"},])   # TODO quantum issues
-    def test_handle_nparrays(self, insert_some_nans, insert_all_nans):
+    @pytest.mark.parametrize(
+        "kwargs",
+        [
+            {"method": "classical"},
+            {"method": "quantum"},
+        ],
+    )
+    def test_handle_nparrays(self, insert_some_nans, insert_all_nans, kwargs):
         """Test for ability to handle numpy array quantities"""
         assert_can_handle_nparray(
-            coupling_parameter, insert_some_nans, insert_all_nans, {}
+            coupling_parameter, insert_some_nans, insert_all_nans, kwargs
         )
 
-    @pytest.mark.xfail(
-        reason="see issue https://github.com/PlasmaPy/PlasmaPy/issues/726"
-    )
     def test_quantum(self):
         """
         Testing quantum method for coupling parameter.
diff --git a/plasmapy/formulary/tests/test_quantum.py b/plasmapy/formulary/tests/test_quantum.py
--- a/plasmapy/formulary/tests/test_quantum.py
+++ b/plasmapy/formulary/tests/test_quantum.py
@@ -156,11 +156,8 @@ def setup_class(self):
         self.n_e = 1e20 * u.cm**-3
         self.n_e_fail = 1e23 * u.cm**-3
         self.T = 11604 * u.K
-        self.True1 = 1.234345958778249e-11
+        self.True1 = 6.133671348607095e-11
 
-    @pytest.mark.xfail(
-        reason="see issue https://github.com/PlasmaPy/PlasmaPy/issues/726"
-    )
     def test_known1(self):
         """
         Tests Fermi_integral for expected value.
@@ -170,9 +167,6 @@ def test_known1(self):
         errStr = f"Chemical potential value should be {self.True1} and not {methodVal}."
         assert testTrue, errStr
 
-    @pytest.mark.xfail(
-        reason="see issue https://github.com/PlasmaPy/PlasmaPy/issues/726"
-    )
     def test_fail1(self):
         """
         Tests if test_known1() would fail if we slightly adjusted the
@@ -194,11 +188,8 @@ def setup_class(self):
         """initializing parameters for tests"""
         self.n_e = 1e23 * u.cm**-3
         self.T = 11604 * u.K
-        self.True1 = 7.741256653579105
+        self.True1 = 7.741254037813922
 
-    @pytest.mark.xfail(
-        reason="see issue https://github.com/PlasmaPy/PlasmaPy/issues/726"
-    )
     def test_known1(self):
         """
         Tests Fermi_integral for expected value.
@@ -208,9 +199,6 @@ def test_known1(self):
         errStr = f"Chemical potential value should be {self.True1} and not {methodVal}."
         assert testTrue, errStr
 
-    @pytest.mark.xfail(
-        reason="see issue https://github.com/PlasmaPy/PlasmaPy/issues/726"
-    )
     def test_fail1(self):
         """
         Tests if test_known1() would fail if we slightly adjusted the