Repository: skypyproject/skypy
Pull request #415 (2021-01-26 16:50:11)

magnitude/luminosity functions to utils.photometry
## Description

Move the magnitude and luminosity conversion functions to the new `skypy.utils.photometry` module. Removes the incorrect apparent and absolute magnitude conversion functions.


Patch:
diff --git a/docs/pipeline/examples/config.yml b/docs/pipeline/examples/config.yml
index cca8591..37cfce3 100644
--- a/docs/pipeline/examples/config.yml
+++ b/docs/pipeline/examples/config.yml
@@ -4,7 +4,7 @@ parameters:
 cosmology: !astropy.cosmology.FlatLambdaCDM
   H0: $hubble_constant
   Om0: $omega_matter
-n_galaxies: 100
+n_galaxies: 1000
 tables:
   galaxies:
     redshift: !skypy.galaxies.redshift.smail
@@ -12,4 +12,3 @@ tables:
       alpha: 1.5
       beta: 2.0
       size: $n_galaxies
-    distance_modulus: !skypy.galaxies.luminosity.distance_modulus [$galaxies.redshift]
diff --git a/docs/pipeline/index.rst b/docs/pipeline/index.rst
index e017dd2..51c65df 100644
--- a/docs/pipeline/index.rst
+++ b/docs/pipeline/index.rst
@@ -51,12 +51,10 @@ with a dollar sign ``$``. For example:
     pipeline.execute()
 
     z = pipeline['galaxies']['redshift']
-    dm = pipeline['galaxies']['distance_modulus']
 
-    plt.scatter(z, dm, marker='+', color='k', label='galaxies')
+    plt.hist(z, histtype='step', density=True, label='redshifts')
     plt.legend()
     plt.xlabel('redshift')
-    plt.ylabel('distance_modulus')
 
 When executing a pipeline, all dependencies are tracked and resolved in order
 using a Directed Acylic Graph implemented in networkx_.
diff --git a/docs/utils/index.rst b/docs/utils/index.rst
index d1747b8..a99ca10 100644
--- a/docs/utils/index.rst
+++ b/docs/utils/index.rst
@@ -130,6 +130,9 @@ calculate photometric properties.
 .. autosummary::
    :nosignatures:
 
+   absolute_magnitude_from_luminosity
+   luminosity_from_absolute_magnitude
+   luminosity_in_band
    mag_ab
    SpectrumTemplates
 
diff --git a/skypy/galaxies/luminosity.py b/skypy/galaxies/luminosity.py
index 6c8773c..97717ef 100644
--- a/skypy/galaxies/luminosity.py
+++ b/skypy/galaxies/luminosity.py
@@ -9,151 +9,10 @@ from ..utils import dependent_argument
 
 
 __all__ = [
-    'absolute_to_apparent_magnitude',
-    'apparent_to_absolute_magnitude',
-    'distance_modulus',
-    'luminosity_in_band',
-    'luminosity_from_absolute_magnitude',
-    'absolute_magnitude_from_luminosity',
     'schechter_lf_magnitude',
 ]
 
 
-def absolute_to_apparent_magnitude(absolute_magnitude, distance_modulus):
-    '''Convert absolute to apparent magnitude.
-
-    Parameters
-    ----------
-    absolute_magnitude : array_like
-        Absolute magnitude M.
-    distance_modulus : array_like
-        Distance modulus DM.
-
-    Returns
-    -------
-    apparent_magnitude : array_like
-        Apparent magnitude M + DM.
-
-    '''
-
-    return np.add(absolute_magnitude, distance_modulus)
-
-
-def apparent_to_absolute_magnitude(apparent_magnitude, distance_modulus):
-    '''Convert apparent to absolute magnitude.
-
-    Parameters
-    ----------
-    apparent_magnitude : array_like
-        Apparent magnitude m.
-    distance_modulus : array_like
-        Distance modulus DM.
-
-    Returns
-    -------
-    absolute_magnitude : array_like
-        Absolute magnitude m - DM.
-
-    '''
-
-    return np.subtract(apparent_magnitude, distance_modulus)
-
-
-def distance_modulus(redshift, cosmology):
-    '''Compute the distance modulus.
-
-    Parameters
-    ----------
-    redshift : array_like
-        Redshift of objects.
-    cosmology : Cosmology
-        The cosmology from which the luminosity distance is taken.
-
-    Returns
-    -------
-    distmod : array_like
-        The distance modulus m - M for each input redshift.
-    '''
-
-    return cosmology.distmod(redshift).value
-
-
-luminosity_in_band = {
-    'Lsun_U': 6.33,
-    'Lsun_B': 5.31,
-    'Lsun_V': 4.80,
-    'Lsun_R': 4.60,
-    'Lsun_I': 4.51,
-}
-'''Bandpass magnitude of reference luminosities.
-
-These values can be used for conversion in `absolute_magnitude_from_luminosity`
-and `luminosity_from_absolute_magnitude`. The `Lsun_{UBVRI}` values contain the
-absolute AB magnitude of the sun in Johnson/Cousins bands from [1]_.
-
-References
-----------
-.. [1] Christopher N. A. Willmer 2018 ApJS 236 47
-
-'''
-
-
-def luminosity_from_absolute_magnitude(absolute_magnitude, zeropoint=None):
-    """Converts absolute magnitudes to luminosities.
-
-    Parameters
-    ----------
-    absolute_magnitude : array_like
-        Input absolute magnitudes.
-    zeropoint : float or str, optional
-        Zeropoint for the conversion. If a string is given, uses the reference
-        luminosities from `luminosity_in_band`.
-
-    Returns
-    -------
-    luminosity : array_like
-        Luminosity values.
-
-    """
-
-    if zeropoint is None:
-        zeropoint = 0.
-    elif isinstance(zeropoint, str):
-        if zeropoint not in luminosity_in_band:
-            raise KeyError('unknown zeropoint `{}`'.format(zeropoint))
-        zeropoint = -luminosity_in_band[zeropoint]
-
-    return 10.**(-0.4*np.add(absolute_magnitude, zeropoint))
-
-
-def absolute_magnitude_from_luminosity(luminosity, zeropoint=None):
-    """Converts luminosities to absolute magnitudes.
-
-    Parameters
-    ----------
-    luminosity : array_like
-        Input luminosity.
-    zeropoint : float, optional
-        Zeropoint for the conversion. If a string is given, uses the reference
-        luminosities from `luminosity_in_band`.
-
-    Returns
-    -------
-    absolute_magnitude : array_like
-        Absolute magnitude values.
-
-    """
-
-    if zeropoint is None:
-        zeropoint = 0.
-    elif isinstance(zeropoint, str):
-        if zeropoint not in luminosity_in_band:
-            raise KeyError('unknown zeropoint `{}`'.format(zeropoint))
-        zeropoint = -luminosity_in_band[zeropoint]
-
-    return -2.5*np.log10(luminosity) - zeropoint
-
-
 @dependent_argument('M_star', 'redshift')
 @dependent_argument('alpha', 'redshift')
 def schechter_lf_magnitude(redshift, M_star, alpha, m_lim, cosmology, size=None,
diff --git a/skypy/utils/photometry.py b/skypy/utils/photometry.py
index 2f3e7dc..6efa272 100644
--- a/skypy/utils/photometry.py
+++ b/skypy/utils/photometry.py
@@ -8,6 +8,9 @@ import numpy as np
 
 
 __all__ = [
+    'absolute_magnitude_from_luminosity',
+    'luminosity_from_absolute_magnitude',
+    'luminosity_in_band',
     'mag_ab',
     'SpectrumTemplates',
 ]
@@ -224,3 +227,79 @@ class SpectrumTemplates(metaclass=ABCMeta):
         m = mag_ab(self.wavelength, self.templates, filters, redshift=redshift,
                    coefficients=coefficients, distmod=distmod, interpolate=resolution)
         return (m.T + mass_modulus).T
+
+
+luminosity_in_band = {
+    'Lsun_U': 6.33,
+    'Lsun_B': 5.31,
+    'Lsun_V': 4.80,
+    'Lsun_R': 4.60,
+    'Lsun_I': 4.51,
+}
+'''Bandpass magnitude of reference luminosities.
+
+These values can be used for conversion in `absolute_magnitude_from_luminosity`
+and `luminosity_from_absolute_magnitude`. The `Lsun_{UBVRI}` values contain the
+absolute AB magnitude of the sun in Johnson/Cousins bands from [1]_.
+
+References
+----------
+.. [1] Christopher N. A. Willmer 2018 ApJS 236 47
+
+'''
+
+
+def luminosity_from_absolute_magnitude(absolute_magnitude, zeropoint=None):
+    """Converts absolute magnitudes to luminosities.
+
+    Parameters
+    ----------
+    absolute_magnitude : array_like
+        Input absolute magnitudes.
+    zeropoint : float or str, optional
+        Zeropoint for the conversion. If a string is given, uses the reference
+        luminosities from `luminosity_in_band`.
+
+    Returns
+    -------
+    luminosity : array_like
+        Luminosity values.
+
+    """
+
+    if zeropoint is None:
+        zeropoint = 0.
+    elif isinstance(zeropoint, str):
+        if zeropoint not in luminosity_in_band:
+            raise KeyError('unknown zeropoint `{}`'.format(zeropoint))
+        zeropoint = -luminosity_in_band[zeropoint]
+
+    return 10.**(-0.4*np.add(absolute_magnitude, zeropoint))
+
+
+def absolute_magnitude_from_luminosity(luminosity, zeropoint=None):
+    """Converts luminosities to absolute magnitudes.
+
+    Parameters
+    ----------
+    luminosity : array_like
+        Input luminosity.
+    zeropoint : float, optional
+        Zeropoint for the conversion. If a string is given, uses the reference
+        luminosities from `luminosity_in_band`.
+
+    Returns
+    -------
+    absolute_magnitude : array_like
+        Absolute magnitude values.
+
+    """
+
+    if zeropoint is None:
+        zeropoint = 0.
+    elif isinstance(zeropoint, str):
+        if zeropoint not in luminosity_in_band:
+            raise KeyError('unknown zeropoint `{}`'.format(zeropoint))
+        zeropoint = -luminosity_in_band[zeropoint]
+
+    return -2.5*np.log10(luminosity) - zeropoint


Test patch:
diff --git a/skypy/galaxies/tests/test_luminosity.py b/skypy/galaxies/tests/test_luminosity.py
index 21da20e..acf6429 100644
--- a/skypy/galaxies/tests/test_luminosity.py
+++ b/skypy/galaxies/tests/test_luminosity.py
@@ -3,58 +3,6 @@ import pytest
 from scipy.stats import kstest
 
 
-def test_magnitude_functions():
-
-    from astropy.cosmology import default_cosmology
-
-    from skypy.galaxies.luminosity import (
-            absolute_to_apparent_magnitude, apparent_to_absolute_magnitude,
-            distance_modulus, luminosity_in_band,
-            luminosity_from_absolute_magnitude,
-            absolute_magnitude_from_luminosity)
-
-    cosmo = default_cosmology.get()
-
-    # sample some redshifts
-    z = np.random.uniform(0, 10, size=1000)
-
-    # sample some absolute magnitudes
-    M = np.random.uniform(15, 25, size=1000)
-
-    # sample distance moduli
-    DM = cosmo.distmod(z).value
-
-    # compare with function
-    np.testing.assert_allclose(distance_modulus(z, cosmo), DM)
-
-    # compute apparent magnitudes
-    m = absolute_to_apparent_magnitude(M, DM)
-
-    # compare with values
-    np.testing.assert_allclose(m, M+DM)
-
-    # go back to absolute magnitudes
-    M_ = apparent_to_absolute_magnitude(m, DM)
-
-    # compare with original values
-    np.testing.assert_allclose(M_, M)
-
-    # convert between absolute luminosity and magnitude
-    assert np.isclose(luminosity_from_absolute_magnitude(-22), 630957344.5)
-    assert np.isclose(absolute_magnitude_from_luminosity(630957344.5), -22)
-
-    # convert with standard luminosities
-    for ref, mag in luminosity_in_band.items():
-        assert np.isclose(luminosity_from_absolute_magnitude(mag, ref), 1.0)
-        assert np.isclose(absolute_magnitude_from_luminosity(1.0, ref), mag)
-
-    # error when unknown reference is used
-    with pytest.raises(KeyError):
-        luminosity_from_absolute_magnitude(0., 'unknown')
-    with pytest.raises(KeyError):
-        absolute_magnitude_from_luminosity(1., 'unknown')
-
-
 @pytest.mark.flaky
 def test_schechter_lf_magnitude():
     from skypy.galaxies.luminosity import schechter_lf_magnitude
diff --git a/skypy/utils/tests/test_photometry.py b/skypy/utils/tests/test_photometry.py
index 6f1d1ec..6e79434 100644
--- a/skypy/utils/tests/test_photometry.py
+++ b/skypy/utils/tests/test_photometry.py
@@ -3,6 +3,28 @@ import pytest
 from skypy.utils.photometry import HAS_SPECLITE
 
 
+def test_magnitude_functions():
+
+    from skypy.utils.photometry import (luminosity_in_band,
+            luminosity_from_absolute_magnitude,
+            absolute_magnitude_from_luminosity)
+
+    # convert between absolute luminosity and magnitude
+    assert np.isclose(luminosity_from_absolute_magnitude(-22), 630957344.5)
+    assert np.isclose(absolute_magnitude_from_luminosity(630957344.5), -22)
+
+    # convert with standard luminosities
+    for ref, mag in luminosity_in_band.items():
+        assert np.isclose(luminosity_from_absolute_magnitude(mag, ref), 1.0)
+        assert np.isclose(absolute_magnitude_from_luminosity(1.0, ref), mag)
+
+    # error when unknown reference is used
+    with pytest.raises(KeyError):
+        luminosity_from_absolute_magnitude(0., 'unknown')
+    with pytest.raises(KeyError):
+        absolute_magnitude_from_luminosity(1., 'unknown')
+
+
 @pytest.mark.skipif(not HAS_SPECLITE, reason='test requires speclite')
 def test_mag_ab_standard_source():