Repository: PlasmaPy/PlasmaPy

Issue:
Migrate `quantum_theta` and write tests
The `quantum_theta` function should be moved from `plasmapy.formulary.dimensionless` to `plasmapy.formulary.quantum`.  I would have no problem still keeping it exposed in the `dimensionless` namespace.

Additionally, the one test written for `quantum_theta` is not a real test, so a full set of tests need to be written.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1671?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) Report
> Merging [#1671](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1671?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) (177591c) into [main](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/5dbaf3ab83296636e77d4aac749abbd30ee04d1e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) (5dbaf3a) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

> :exclamation: Current head 177591c differs from pull request most recent head 353fd61. Consider uploading reports for the commit 353fd61 to get more accurate results

```diff
@@           Coverage Diff           @@
##             main    #1671   +/-   ##
=======================================
  Coverage   97.22%   97.22%           
=======================================
  Files          85       85           
  Lines        8012     8013    +1     
=======================================
+ Hits         7790     7791    +1     
  Misses        222      222           
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1671?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) | Coverage Δ | |
|---|---|---|
| [plasmapy/formulary/dimensionless.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1671/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy#diff-cGxhc21hcHkvZm9ybXVsYXJ5L2RpbWVuc2lvbmxlc3MucHk=) | `100.00% <100.00%> (ø)` | |
| [plasmapy/formulary/quantum.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1671/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy#diff-cGxhc21hcHkvZm9ybXVsYXJ5L3F1YW50dW0ucHk=) | `70.45% <100.00%> (+1.77%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy)

JaydenR2305: What should I do about the invalid reference? @StanczakDominik 
StanczakDominik: Oh dear, it's in the changelog for 0.6 and looking for the previous location of this function. Perhaps just change it from
```rst

- Adds formulas (which were missing) to the docstrings of
  `~plasmapy.formulary.dimensionless.quantum_theta` and
  `~plasmapy.formulary.dimensionless.beta`. (`#1041 <https://github.com/plasmapy/plasmapy/pull/1041>`__)
```
to
```rst

- Adds formulas (which were missing) to the docstrings of
  ``~plasmapy.formulary.dimensionless.quantum_theta`` and
  `~plasmapy.formulary.dimensionless.beta`. (`#1041 <https://github.com/plasmapy/plasmapy/pull/1041>`__)
```

because I don't think we want to spend too much time maintaining out-of-date changelogs!

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index b980bd46..3057d301 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -927,7 +927,7 @@ Improved Documentation
 - Put the docstring for `plasmapy.particles.Particle.is_category` into
   `numpydoc` format. (`#1039 <https://github.com/plasmapy/plasmapy/pull/1039>`__)
 - Adds formulas (which were missing) to the docstrings of
-  `~plasmapy.formulary.dimensionless.quantum_theta` and
+  ``plasmapy.formulary.dimensionless.quantum_theta`` and
   `~plasmapy.formulary.dimensionless.beta`. (`#1041 <https://github.com/plasmapy/plasmapy/pull/1041>`__)
 - Add live rendering of changelog entries on documentation builds, based on
   `sphinx-changelog <https://github.com/OpenAstronomy/sphinx-changelog>`_. (`#1052 <https://github.com/plasmapy/plasmapy/pull/1052>`__)
diff --git a/changelog/1671.trivial.rst b/changelog/1671.trivial.rst
new file mode 100644
index 00000000..f2f0ffe1
--- /dev/null
+++ b/changelog/1671.trivial.rst
@@ -0,0 +1,1 @@
+Move the ``plasmapy.formulary.dimensionless.quantum_theta`` function to the `~plasmapy.formulary.quantum` module. Note, this function can still be called from the `plasmapy.formulary.dimensionless` module without issue.
diff --git a/changelog/1673.doc.rst b/changelog/1673.doc.rst
new file mode 100644
index 00000000..91840706
--- /dev/null
+++ b/changelog/1673.doc.rst
@@ -0,0 +1,2 @@
+Added a guideline to the coding guide specifying how |nan| values should
+be treated in functions that accept |array_like| or |Quantity| inputs.
diff --git a/changelog/1674.doc.rst b/changelog/1674.doc.rst
new file mode 100644
index 00000000..62eee604
--- /dev/null
+++ b/changelog/1674.doc.rst
@@ -0,0 +1,3 @@
+Added an admonition to the |changelog guide| that describes how to
+change reST_ links for removed code objects into inline literals in old
+changelog entries.
diff --git a/changelog/README.rst b/changelog/README.rst
index 5f563842..98c6db9c 100644
--- a/changelog/README.rst
+++ b/changelog/README.rst
@@ -125,6 +125,29 @@ Changelog guidelines
   superseded or reverted and include a link to the appropriate pull
   request.
 
+.. _fixing-obsolete-rest-links:
+
+.. tip::
+
+   When removing or moving an object, reST_ links that follow the
+   original namespace will break, causing the documentation build to
+   fail.
+
+   Text in single back ticks is used to link to code objects, while text
+   in double back ticks is treated as an `inline literal`_. To remedy
+   this problem in old changelog entries, change the broken link into an
+   inline literal by surrounding it with double back ticks instead.
+   Remove the tilde if present. For example,
+   ```~plasmapy.subpackage.module.function``` should be changed
+   to:
+
+   .. code-block:: rst
+
+      ``plasmapy.subpackage.module.function``
+
+   Outside of the changelog, the namespace should be corrected rather
+   than changed into an inline literal.
+
 Building the changelog
 ======================
 
@@ -168,3 +191,5 @@ steps to update the changelog are described in the :ref:`Release Guide`.
    Here, ``⟨number⟩`` is replaced with the pull request number and
    ``⟨type⟩`` is replaced with the one of the changelog types as
    described above.
+
+.. _inline literal: https://docutils.sourceforge.io/docs/user/rst/quickref.html#inline-markup
diff --git a/docs/common_links.rst b/docs/common_links.rst
index d008cf5a..5b5e36ac 100644
--- a/docs/common_links.rst
+++ b/docs/common_links.rst
@@ -90,6 +90,7 @@
    used just before a period.
 
 .. |bibliography| replace:: :ref:`bibliography`\
+.. |changelog guide| replace:: :ref:`changelog guide`\
 .. |coding guide| replace:: :ref:`coding guide`\
 .. |contributor guide| replace:: :ref:`contributor guide`\
 .. |documentation guide| replace:: :ref:`documentation guide`\
diff --git a/docs/contributing/coding_guide.rst b/docs/contributing/coding_guide.rst
index 25b845a5..f0a0c422 100644
--- a/docs/contributing/coding_guide.rst
+++ b/docs/contributing/coding_guide.rst
@@ -119,6 +119,18 @@ Coding guidelines
   >>> print(f"{package_name!r}")  # shortcut for f"{repr(package_name)}"
   'PlasmaPy'
 
+* Functions that accept |array_like| or |Quantity| inputs should accept
+  and return |nan| (`not a number`_) values. This guideline applies when
+  |nan| is the input as well as when |nan| values are included in an
+  array.
+
+  .. tip::
+
+     Normally, ``numpy.nan == numpy.nan`` evaluates to `False`, which
+     complicates testing |nan| behavior. The ``equal_nan`` keyword of
+     functions like `numpy.allclose` and `numpy.testing.assert_allclose`
+     makes it so that |nan| is considered equal to itself.
+
 * Do not use :term:`mutable` objects as default values in the function
   or method declaration. This can lead to unexpected behavior.
 
@@ -787,6 +799,7 @@ the README file of `benchmarks-repo`_.
 .. _example notebook on particles: ../notebooks/getting_started/particles.ipynb
 .. _example notebook on units: ../notebooks/getting_started/units.ipynb
 .. _extract function refactoring pattern: https://refactoring.guru/extract-method
+.. _not a number: https://en.wikipedia.org/wiki/NaN
 .. _NumPy Enhancement Proposal 29: https://numpy.org/neps/nep-0029-deprecation_policy.html
 .. _pyupgrade: https://github.com/asottile/pyupgrade
 .. _rename refactoring in PyCharm: https://www.jetbrains.com/help/pycharm/rename-refactorings.html
diff --git a/docs/whatsnew/0.6.0.rst b/docs/whatsnew/0.6.0.rst
index f6b487b8..23abddc5 100644
--- a/docs/whatsnew/0.6.0.rst
+++ b/docs/whatsnew/0.6.0.rst
@@ -184,7 +184,7 @@ Improved Documentation
 - Put the docstring for `plasmapy.particles.particle_class.Particle.is_category` into
   ``numpydoc`` format. (`#1039 <https://github.com/plasmapy/plasmapy/pull/1039>`__)
 - Adds formulas (which were missing) to the docstrings of
-  `~plasmapy.formulary.dimensionless.quantum_theta` and
+  ``plasmapy.formulary.dimensionless.quantum_theta`` and
   `~plasmapy.formulary.dimensionless.beta`. (`#1041 <https://github.com/plasmapy/plasmapy/pull/1041>`__)
 - Add live rendering of changelog entries on documentation builds, based on
   `sphinx-changelog <https://github.com/OpenAstronomy/sphinx-changelog>`_. (`#1052 <https://github.com/plasmapy/plasmapy/pull/1052>`__)
diff --git a/plasmapy/formulary/dimensionless.py b/plasmapy/formulary/dimensionless.py
index d19e5cfe..b3813232 100644
--- a/plasmapy/formulary/dimensionless.py
+++ b/plasmapy/formulary/dimensionless.py
@@ -23,7 +23,8 @@
 
 from astropy.constants.si import k_B, mu0
 
-from plasmapy.formulary import frequencies, lengths, misc, quantum
+from plasmapy.formulary import frequencies, lengths, misc
+from plasmapy.formulary.quantum import quantum_theta
 from plasmapy.particles import Particle
 from plasmapy.utils.decorators import validate_quantities
 
@@ -225,66 +226,6 @@ def Hall_parameter(
 """Alias to `~plasmapy.formulary.dimensionless.Hall_parameter`."""
 
 
-@validate_quantities(
-    T={"can_be_negative": False, "equivalencies": u.temperature_energy()},
-    n_e={"can_be_negative": False},
-)
-def quantum_theta(T: u.K, n_e: u.m**-3) -> u.dimensionless_unscaled:
-    r"""
-    Compare Fermi energy to thermal kinetic energy to check if quantum
-    effects are important.
-
-    The quantum theta (:math:`θ`) of a plasma is defined by
-
-    .. math::
-        θ = \frac{E_T}{E_F}
-
-    where :math:`E_T` is the thermal energy of the plasma
-    and :math:`E_F` is the Fermi energy of the plasma.
-
-    Parameters
-    ----------
-    T : `~astropy.units.Quantity`
-        The temperature of the plasma.
-
-    n_e : `~astropy.units.Quantity`
-          The electron number density of the plasma.
-
-    Examples
-    --------
-    >>> import astropy.units as u
-    >>> quantum_theta(1*u.eV, 1e20*u.m**-3)
-    <Quantity 127290.619...>
-    >>> quantum_theta(1*u.eV, 1e16*u.m**-3)
-    <Quantity 59083071...>
-    >>> quantum_theta(1*u.eV, 1e26*u.m**-3)
-    <Quantity 12.72906...>
-    >>> quantum_theta(1*u.K, 1e26*u.m**-3)
-    <Quantity 0.00109...>
-
-    Returns
-    -------
-    theta : `~astropy.units.Quantity`
-
-    Notes
-    -----
-    The thermal energy of the plasma (:math:`E_T`) is defined by
-
-    .. math::
-        E_T = k_B T
-
-    where :math:`k_B` is the Boltzmann constant
-    and :math:`T` is the temperature of the plasma.
-
-    See Also
-    --------
-    ~plasmapy.formulary.quantum.Fermi_energy
-    """
-    fermi_energy = quantum.Fermi_energy(n_e)
-    thermal_energy = k_B * T
-    return thermal_energy / fermi_energy
-
-
 @validate_quantities(
     T={"can_be_negative": False, "equivalencies": u.temperature_energy()},
     n={"can_be_negative": False},
diff --git a/plasmapy/formulary/quantum.py b/plasmapy/formulary/quantum.py
index 96520817..c12782ed 100644
--- a/plasmapy/formulary/quantum.py
+++ b/plasmapy/formulary/quantum.py
@@ -7,6 +7,7 @@
     "chemical_potential",
     "deBroglie_wavelength",
     "Fermi_energy",
+    "quantum_theta",
     "Thomas_Fermi_length",
     "thermal_deBroglie_wavelength",
     "Wigner_Seitz_radius",
@@ -595,3 +596,63 @@ def _chemical_potential_interp(n_e, T):
     term3 = term3num / term3den
     beta_mu = term1 + term2 + term3
     return beta_mu.to(u.dimensionless_unscaled)
+
+
+@validate_quantities(
+    T={"can_be_negative": False, "equivalencies": u.temperature_energy()},
+    n_e={"can_be_negative": False},
+)
+def quantum_theta(T: u.K, n_e: u.m**-3) -> u.dimensionless_unscaled:
+    r"""
+    Compare Fermi energy to thermal kinetic energy to check if quantum
+    effects are important.
+
+    The quantum theta (:math:`θ`) of a plasma is defined by
+
+    .. math::
+        θ = \frac{E_T}{E_F}
+
+    where :math:`E_T` is the thermal energy of the plasma
+    and :math:`E_F` is the Fermi energy of the plasma.
+
+    Parameters
+    ----------
+    T : `~astropy.units.Quantity`
+        The temperature of the plasma.
+
+    n_e : `~astropy.units.Quantity`
+          The electron number density of the plasma.
+
+    Examples
+    --------
+    >>> import astropy.units as u
+    >>> quantum_theta(1*u.eV, 1e20*u.m**-3)
+    <Quantity 127290.619...>
+    >>> quantum_theta(1*u.eV, 1e16*u.m**-3)
+    <Quantity 59083071...>
+    >>> quantum_theta(1*u.eV, 1e26*u.m**-3)
+    <Quantity 12.72906...>
+    >>> quantum_theta(1*u.K, 1e26*u.m**-3)
+    <Quantity 0.00109...>
+
+    Returns
+    -------
+    theta : `~astropy.units.Quantity`
+
+    Notes
+    -----
+    The thermal energy of the plasma (:math:`E_T`) is defined by
+
+    .. math::
+        E_T = k_B T
+
+    where :math:`k_B` is the Boltzmann constant
+    and :math:`T` is the temperature of the plasma.
+
+    See Also
+    --------
+    ~plasmapy.formulary.quantum.Fermi_energy
+    """
+    fermi_energy = Fermi_energy(n_e)
+    thermal_energy = k_B * T
+    return thermal_energy / fermi_energy


Test patch:
diff --git a/plasmapy/formulary/tests/test_dimensionless.py b/plasmapy/formulary/tests/test_dimensionless.py
index cab35cbe..33ff8f83 100644
--- a/plasmapy/formulary/tests/test_dimensionless.py
+++ b/plasmapy/formulary/tests/test_dimensionless.py
@@ -11,7 +11,6 @@
     Hall_parameter,
     Mag_Reynolds,
     nD_,
-    quantum_theta,
     Re_,
     Reynolds_number,
     Rm_,
@@ -48,11 +47,6 @@ def test_beta_dimensionless():
     float(beta(T, n, B))
 
 
-def test_quantum_theta_dimensionless():
-    # Check that quantum theta is dimensionless
-    float(quantum_theta(T, n))
-
-
 def test_beta_nan():
     # Check that nans are passed through properly
     B = np.array([1, np.nan]) * u.T
diff --git a/plasmapy/formulary/tests/test_quantum.py b/plasmapy/formulary/tests/test_quantum.py
index 033a3fdb..733b8d2a 100644
--- a/plasmapy/formulary/tests/test_quantum.py
+++ b/plasmapy/formulary/tests/test_quantum.py
@@ -12,6 +12,7 @@
     Fermi_energy,
     lambdaDB_,
     lambdaDB_th_,
+    quantum_theta,
     thermal_deBroglie_wavelength,
     Thomas_Fermi_length,
     Wigner_Seitz_radius,
@@ -231,3 +232,30 @@ def test_quantum_aliases():
     assert Ef_ is Fermi_energy
     assert lambdaDB_ is deBroglie_wavelength
     assert lambdaDB_th_ is thermal_deBroglie_wavelength
+
+
+class TestQuantumTheta:
+    """Test the quantum_theta function in quantum.py."""
+
+    def test_units(self):
+        """Test the return units"""
+
+        theta = quantum_theta(1 * u.eV, 1e26 * u.m**-3)
+
+        assert theta.unit.is_equivalent(u.dimensionless_unscaled)
+
+    @pytest.mark.parametrize(
+        "T, n_e, expected_theta",
+        [
+            (1 * u.eV, 1e26 * u.m**-3, 12.72906),  # Both regimes are present
+            (2 / 3 * u.eV, 1e40 * u.m**-3, 3.93887e-9),  # Fermi regime
+            (8.61e2 * u.eV, 1e12 * u.m**-3, 2.36120e13),  # Thermal regime
+            (1 * u.K, 1e26 * u.m**-3, 1.09690e-3),  # Specify temperature in Kelvin
+        ],
+    )
+    def test_value(self, T, n_e, expected_theta):
+        """Compare the calculated theta with the expected value."""
+
+        theta = quantum_theta(T, n_e)
+
+        assert np.isclose(theta.value, expected_theta)