*********************
Utils (`skypy.utils`)
*********************

.. currentmodule:: skypy.utils


Decorators
==========

SkyPy provides a number of convenient decorators to perform common tasks:

- :ref:`broadcast_arguments`
- :ref:`dependent_argument`


.. _broadcast_arguments:

Broadcast arguments to same shape
---------------------------------

The `broadcast_arguments` decorator takes a list of argument names that will
be broadcast to a common shape (using `numpy.broadcast_arrays`) before being
passed to the function.

.. code-block:: python

    import numpy as np

    from skypy.utils import broadcast_arguments

    @broadcast_arguments('a', 'b')
    def a_function_of_arrays(a, b):
        print(np.block([a, b]))

    a = [[1, 2, 3]]      # row vector
    b = [[4], [5], [6]]  # column vector

    a_function_of_arrays(a, b)
    # output: [[1 2 3 4 4 4]
    #          [1 2 3 5 5 5]
    #          [1 2 3 6 6 6]]

Since `broadcast_arguments` requires the final shapes of its arguments, it
should be placed below decorators which modify arguments.


.. _dependent_argument:

Evaluate dependent arguments
----------------------------

Sometimes, the value of one argument (the dependent argument) will be a
function other arguments (the independent arguments). Consider the following
example to plot a parametric surface:

.. code-block:: python

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    def plot(x, y, z):
        '''plot the surface given by `z = f(x, y)`'''
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')
        ax.plot_surface(x, y, z)
        plt.show()

    def f(x, y):
        '''the surface function `z = f(x, y)`'''
        return np.sin(np.hypot(x, y))

    # x and y over a [-5, 5]x[-5, 5] grid
    x, y = np.mgrid[-5.0:5.0:0.1, -5.0:5.0:0.1]

    # compute surface
    z = f(x, y)

    # plot surface
    plot(x, y, z)

The function `plot(x, y, z)` takes three coordinates, where `z` is generated by
a function `f(x, y)`. In this situation, it is often more convenient to pass
the function `f` directly instead of the `z` coordinate, which would require
the receiving function to distinguish whether it is given values or a function.
The `dependent_argument` decorator handles this situation transparently by
taking the name of one dependent argument and the names of one or more
independent arguments, and computing values if a function is provided for the
dependent argument:

.. code-block:: python

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    from skypy.utils import dependent_argument

    @dependent_argument('z', 'x', 'y')
    def plot(x, y, z):
        '''plot the surface given by `z = f(x, y)`'''
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')
        ax.plot_surface(x, y, z)
        plt.show()

    def f(x, y):
        '''the surface function `z = f(x, y)`'''
        return np.sin(np.hypot(x, y))

    # x and y over a [-5, 5]x[-5, 5] grid
    x, y = np.mgrid[-5.0:5.0:0.1, -5.0:5.0:0.1]

    # plot surface
    plot(x, y, f)

Since `dependent_argument` requires the values of all independent arguments, it
should be placed below decorators which modify any of the independent
arguments.


Photometry (`skypy.utils.photometry`)
=====================================

This module contains methods that model spectral energy distributions and
calculate photometric properties.

SkyPy uses the `speclite <https://speclite.readthedocs.io/>`_ package for
photometric calculations. Some of the following functions take the names of
photometric filters as an input parameter. Users can choose from the available
`Speclite Filters <https://speclite.readthedocs.io/en/latest/filters.html>`_
following the naming syntax described in `speclite.filters.load_filters`, or
create their own named `speclite.filters.FilterResponse`.


.. currentmodule:: skypy.utils.photometry
.. autosummary::
   :nosignatures:

   absolute_magnitude_from_luminosity
   luminosity_from_absolute_magnitude
   luminosity_in_band
   mag_ab
   SpectrumTemplates


Random sampling (`skypy.utils.random`)
======================================

.. automodule:: skypy.utils.random


Special functions (`skypy.utils.special`)
=========================================

.. automodule:: skypy.utils.special


Reference/API
=============

.. automodapi:: skypy.utils
.. automodapi:: skypy.utils.photometry
