Skip to content

Commit

Permalink
Adding preliminary tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bmorris3 committed Dec 3, 2018
1 parent 52ead04 commit 2ccc9e9
Show file tree
Hide file tree
Showing 8 changed files with 2,483 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ env:

# List other runtime dependencies for the package that are available as
# pip packages here.
- PIP_DEPENDENCIES=''
- PIP_DEPENDENCIES='aesop'

# Conda packages for affiliated packages are hosted in channel
# "astropy" while builds for astropy LTS with recent numpy versions
Expand Down
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ stellar spectroscopy with the `ARC Echelle Spectrograph (ARCES)
`ARC 3.5 m Telescope <https://www.apo.nmsu.edu/arc35m/>`_ at
`Apache Point Observatory <https://www.apo.nmsu.edu>`_.

For more information, `read the docs <https://arcesetc.readthedocs.io/>`_.

License
-------

Expand Down
2,344 changes: 2,344 additions & 0 deletions arcesetc/data/HR3454.0016.wfrmcpc.fits

Large diffs are not rendered by default.

49 changes: 13 additions & 36 deletions arcesetc/plots.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import numpy as np
import astropy.units as u
import matplotlib.pyplot as plt
from .util import (closest_target, archive, scale_flux,
get_closest_order, matrix_row_to_spectrum,
sn_to_exp_time)
from .util import reconstruct_order

__all__ = ['plot_order_counts', 'plot_order_sn']

Expand Down Expand Up @@ -79,28 +77,17 @@ def plot_order_counts(sptype, wavelength, V, exp_time=None,
>>> plt.show() #doctest: +SKIP
"""
target, closest_spectral_type = closest_target(sptype)

matrix = archive[target][:]

closest_order = get_closest_order(matrix, wavelength)
wave, flux = matrix_row_to_spectrum(matrix, closest_order)
flux *= scale_flux(archive[target], V)
wave, flux, closest_sptype, exp_time = reconstruct_order(sptype,
wavelength,
V,
exp_time=exp_time,
signal_to_noise=signal_to_noise)

fig, ax = plt.subplots()

if exp_time is not None and signal_to_noise is None:
flux *= exp_time.to(u.s).value

elif exp_time is None and signal_to_noise is not None:
exp_time = sn_to_exp_time(wave, flux, wavelength, signal_to_noise)
flux *= exp_time.value
else:
raise ValueError("Supply either the `exp_time` or the "
"`signal_to_noise` keyword argument.")

ax.set_title('Sp. Type: {0}, Exposure time: {1:.1f}'
.format(closest_spectral_type, exp_time.to(u.min)))
.format(closest_sptype, exp_time.to(u.min)))
ax.plot(wave, flux, **kwargs)
ax.set_xlabel('Wavelength [Angstrom]')
ax.set_ylabel('Flux [DN]')
Expand Down Expand Up @@ -180,27 +167,17 @@ def plot_order_sn(sptype, wavelength, V, exp_time=None, signal_to_noise=None,
>>> fig, ax, exp_time = plot_order_sn(sptype, wavelength, V, signal_to_noise=signal_to_noise) #doctest: +SKIP
>>> plt.show() #doctest: +SKIP
"""
target, closest_spectral_type = closest_target(sptype)

matrix = archive[target][:]

closest_order = get_closest_order(matrix, wavelength)
wave, flux = matrix_row_to_spectrum(matrix, closest_order)
flux *= scale_flux(archive[target], V)

fig, ax = plt.subplots()

if exp_time is not None:
flux *= exp_time.to(u.s).value
elif exp_time is None and signal_to_noise is not None:
exp_time = sn_to_exp_time(wave, flux, wavelength, signal_to_noise)
flux *= exp_time.value
else:
raise ValueError("Supply either the `exp_time` or the "
"`signal_to_noise` keyword argument.")
wave, flux, closest_sptype, exp_time = reconstruct_order(sptype,
wavelength,
V,
exp_time=exp_time,
signal_to_noise=signal_to_noise)
sn = flux / np.sqrt(flux)
ax.set_title('Sp. Type: {0}, Exposure time: {1:.1f}'
.format(closest_spectral_type, exp_time.to(u.min)))
.format(closest_sptype, exp_time.to(u.min)))
ax.plot(wave, sn, **kwargs)
ax.set_xlabel('Wavelength [Angstrom]')
ax.set_ylabel('Signal/Noise')
Expand Down
54 changes: 54 additions & 0 deletions arcesetc/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import pytest
from aesop import EchelleSpectrum
import numpy as np
import astropy.units as u
from ..util import (reconstruct_order, closest_sptype, archive, scale_flux,
signal_to_noise_to_exp_time)

path = os.path.dirname(__file__)


@pytest.mark.parametrize("order", [25, 35, 41, 60, 84, 89])
def test_reconstruct_order(order):
"""
End-to-end functional test on several well-behaved orders of an early-type
star.
"""
b3v = EchelleSpectrum.from_fits(os.path.join(path, os.pardir, 'data',
'HR3454.0016.wfrmcpc.fits'))

wave, flux, sp_type, exp_time = reconstruct_order('B3V',
b3v[order].wavelength.mean(),
4.3,
exp_time=b3v.header['EXPTIME']*u.s)

interp_flux = np.interp(b3v[order].wavelength, wave, flux)
np.testing.assert_allclose(b3v[order].flux, interp_flux, atol=500, rtol=1e-1)
assert sp_type == 'B3V'


def test_closest_sptype():
"""Test that package finds closest available sptype"""
assert closest_sptype('G4V') == 'G5V'


def test_scale_flux():
"""
Check that the flux scaling is workign appropriately by inputting the actual
magnitude of a particular star, show that it returns flux scaling == 1
"""
assert np.abs(scale_flux(archive['HR 3454'], V=4.3) - 1) < 1e-6


def test_sn_to_exptime():
"""
Check that the plot-less function works appropriately.
"""
sptype = 'M0V'
wavelength = 6562 * u.Angstrom
signal_to_noise = 30
V = 12
exp_time = signal_to_noise_to_exp_time(sptype, wavelength, V,
signal_to_noise)
assert np.abs(exp_time.to(u.s).value - 642.11444) < 1e-2
66 changes: 64 additions & 2 deletions arcesetc/util.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import numpy as np
from json import load
import os
import numpy as np
import h5py
import astropy.units as u

__all__ = ['available_sptypes', 'signal_to_noise_to_exp_time']
__all__ = ['available_sptypes', 'signal_to_noise_to_exp_time',
'reconstruct_order']

directory = os.path.dirname(__file__)

Expand Down Expand Up @@ -156,6 +157,67 @@ def sn_to_exp_time(wave, flux, wavelength, signal_to_noise):
return exp_time * u.s


@u.quantity_input(exp_time=u.s, wavelength=u.Angstrom)
def reconstruct_order(sptype, wavelength, V, exp_time=None,
signal_to_noise=None):
"""
Return the counts as a function of wavelength for the spectral
order nearest to ``wavelength`` for a star of spectral type ``sptype`` and
V magnitude ``V``.
Either ``exp_time`` or ``signal_to_noise`` should be supplied to the
function (but not both).
.. warning ::
``arcesetc`` doesn't know anything about saturation. Ye be warned!
Parameters
----------
sptype : str
Spectral type of the star. If
wavelength : `~astropy.units.Quantity`
V : float
V magnitude of the target
exp_time : None or float
If ``exp_time`` is a float, show the counts curve for that exposure
time. Otherwise, use ``signal_to_noise`` to compute the appropriate
exposure time.
signal_to_noise : None or float
If ``signal_to_noise`` is a float, compute the appropriate exposure time
to generate the counts curve that has S/N = ``signal_to_noise`` at
wavelength ``wavelength``. Otherwise, generate counts curve for
exposure time ``exp_time``.
Returns
-------
wave : `~astropy.units.Quantity`
Wavelengths
flux : `~np.ndarray`
Flux at each wavelength
exp_time : `~astropy.units.Quantity`
Exposure time input; or required to reach S/N of ``signal_to_noise``
"""

target, closest_spectral_type = closest_target(sptype)

matrix = archive[target][:]

closest_order = get_closest_order(matrix, wavelength)
wave, flux = matrix_row_to_spectrum(matrix, closest_order)
flux *= scale_flux(archive[target], V)

if exp_time is not None and signal_to_noise is None:
flux *= exp_time.to(u.s).value

elif exp_time is None and signal_to_noise is not None:
exp_time = sn_to_exp_time(wave, flux, wavelength, signal_to_noise)
flux *= exp_time.value
else:
raise ValueError("Supply either the `exp_time` or the "
"`signal_to_noise` keyword argument.")
return wave, flux, closest_spectral_type, exp_time


@u.quantity_input(exp_time=u.s, wavelength=u.Angstrom)
def signal_to_noise_to_exp_time(sptype, wavelength, V, signal_to_noise):
"""
Expand Down
5 changes: 3 additions & 2 deletions docs/paper.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ the desired exposure time in order to determine the counts and signal-to-noise
ratio as a function of wavelength; or the desired signal-to-noise ratio at a
given wavelength to determine the required exposure time.

We estimates the count rates for stars as a function of wavelength by fitting
We estimate the count rates for stars as a function of wavelength by fitting
15th-order polynomials to each spectral order of real observations of a star of
each spectral type. These polynomial coefficients and some wavelength metadata
are stored in an HDF5 archive for compactness and easy of reconstruction. Then
upon calling ``arcesetc``, the archive is opened and the spectral order closest
to the wavelength of interest is reconstructed from the polynomial
coeffiecients.
coefficients, for a star of the closest available spectral type to the one
requested.

At present, the stellar spectral types included in the ``arcesetc`` library
span from late F to early M stars on the main sequence, and one each of an
Expand Down
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ exclude = extern,sphinx,*parsetab.py
[metadata]
package_name = arcesetc
description = Exposure time calculator for APO/ARCES
long_description = Calculate S/N and exposure times for stellar spectroscopy with the ARC Echelle Spectrograph (ARCES) on the 3.5 m Telescope at Apache Point Observatory
long_description = Calculate S/N and exposure times for stellar spectroscopy with the ARC Echelle Spectrograph (ARCES) on the ARC 3.5 m Telescope at Apache Point Observatory
author = Brett Morris & Trevor Dorn-Wallenstein
author_email = brettmorris21@gmail.com
license = MIT
url = https://github.com/bmorris3/arcesetc
edit_on_github = False
github_project = bmorris3/arcesetc
# install_requires should be formatted as a comma-separated list, e.g.:
install_requires = astropy, numpy, matplotlib
install_requires = astropy, numpy, matplotlib, h5py
# version should be PEP440 compatible (https://www.python.org/dev/peps/pep-0440/)
version = 0.0.dev
# Note: you will also need to change this in your package's __init__.py
Expand Down

0 comments on commit 2ccc9e9

Please sign in to comment.