Skip to content

Commit a5a21cf

Browse files
committed
Added tests/test_telescope.py
1 parent 330aa2e commit a5a21cf

File tree

4 files changed

+236
-3
lines changed

4 files changed

+236
-3
lines changed

astroplan/exceptions.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
__all__ = ["TargetAlwaysUpWarning", "TargetNeverUpWarning",
88
"OldEarthOrientationDataWarning", "PlotWarning",
99
"PlotBelowHorizonWarning", "AstroplanWarning",
10-
"SkyCalcError"]
10+
"SkyCalcError", "UserInputError"]
1111

1212

1313
class AstroplanWarning(AstropyWarning):
@@ -42,9 +42,16 @@ class PlotBelowHorizonWarning(PlotWarning):
4242
pass
4343

4444

45-
class SkyCalcError(AstropyWarning):
45+
class SkyCalcError(AstroplanWarning):
4646
"""
4747
Raises an error when one of the parameters isn't accepted by
4848
the SkyCalc Sky Model Calculator.
4949
"""
5050
pass
51+
52+
53+
class UserInputError(AstroplanWarning):
54+
"""
55+
Raises an error when the user gives an array of the wrong shape
56+
"""
57+
pass

astroplan/telescope.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Third-party
66
import numpy as np
77
import astropy.units as u
8+
from astroplan.exceptions import UserInputError
89

910

1011
__all__ = ["Telescope"]
@@ -56,6 +57,24 @@ def _default_ccd_response():
5657
return np.array(wl) * u.nm, np.array(response) * u.Unit('') / 100
5758

5859

60+
def _user_input_test(user_input, user_input_str):
61+
"""
62+
Raise appropriate errors if the user doesn't input the
63+
correct array len or type.
64+
"""
65+
66+
if len(user_input) != 2:
67+
raise UserInputError(user_input_str +
68+
" ccd_response must be "
69+
"a numpy array of shape = (2, n)")
70+
71+
elif (type(user_input[0]) is not u.Quantity
72+
or type(user_input[1]) is not u.Quantity):
73+
raise TypeError(user_input_str +
74+
" must be a 2D-array of"
75+
"`~astropy.units.Quantity` objects")
76+
77+
5978
class Telescope(object):
6079
"""A class to store telescope specifications"""
6180
@u.quantity_input(diameter=u.m, gain=u.ct / u.adu,
@@ -77,7 +96,8 @@ def __init__(self, diameter, bandpass, gain, ccd_response=False,
7796
Gain of the CCD with units of counts/ADU. Default is
7897
1 * astropy.units.ct / astropy.units.adu such that the
7998
contribution to the error due to the gain is assumed to be small.
80-
ccd_response : 'default' or 2D-array
99+
ccd_response : 'default' or 2D-array of `~astropy.units.Quantity`
100+
objects
81101
Note: the zeroth index of the given array must be the
82102
waveset of the response function, while the other
83103
must contain the values of the function.
@@ -118,16 +138,26 @@ def area(self):
118138
def bandpass(self):
119139
"""Bandpass of the instrument"""
120140
from synphot.spectrum import SpectralElement
141+
121142
if isinstance(self._bandpass, SpectralElement):
122143
waves = self._bandpass.waveset
123144
return waves, self._bandpass(waves)
145+
146+
else:
147+
_user_input_test(self._bandpass, "bandpass")
148+
124149
return self._bandpass
125150

126151
@property
127152
def ccd_response(self):
128153
"""Response function of the CCD, i.e. the quantum efficiency"""
129154
if self._ccd_response == 'default':
130155
return _default_ccd_response()
156+
131157
elif self._ccd_response is False:
132158
return self._ccd_response
159+
160+
else:
161+
_user_input_test(self._ccd_response, "ccd_response")
162+
133163
return self._ccd_response[0], self._ccd_response[1]

astroplan/tests/test_telescope.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2+
from __future__ import (absolute_import, division, print_function,
3+
unicode_literals)
4+
import astropy.units as u
5+
from ..telescope import Telescope
6+
import pytest
7+
import sys
8+
import numpy as np
9+
import unittest
10+
from astroplan.exceptions import UserInputError
11+
from astropy.tests.helper import raises
12+
13+
14+
class TestTelescope(object):
15+
"""Tests for telescope.py"""
16+
@pytest.mark.skipif(reason="synphot not installed")
17+
def setup_class(self):
18+
19+
from synphot.spectrum import SpectralElement
20+
from astropy.utils.data import download_file
21+
22+
svo_link = ('http://svo2.cab.inta-csic.es/theory/fps3/fps.php?ID=')
23+
filt_path = download_file(svo_link + 'SLOAN/SDSS.rprime_filter')
24+
25+
self.diameter = 3.5 * u.m
26+
self.bandpass = SpectralElement.from_file(filt_path)
27+
self.gain = 1.9 * (u.ct / u.adu)
28+
self.default_readnoise = 0 * (u.ct / u.pixel)
29+
self.default_ad_err = np.sqrt(0.289) * (u.adu / u.pixel)
30+
self.telescope = Telescope(self.diameter, self.bandpass, self.gain)
31+
32+
def test_diameter(self):
33+
"""
34+
Tests that Telescope returns the correct diameter
35+
"""
36+
assert(self.telescope.diameter == self.diameter)
37+
38+
def test_bandpass(self):
39+
"""
40+
Tests that Telescope returns the correct bandpass
41+
"""
42+
waves = self.bandpass.waveset
43+
assert(all(self.telescope.bandpass[0] == waves) and
44+
all(self.telescope.bandpass[1] == self.bandpass(waves)))
45+
46+
def test_gain(self):
47+
"""
48+
Tests that Telescope returns the correct gain
49+
"""
50+
assert(self.telescope.gain == self.gain)
51+
52+
def test_ccd_response(self):
53+
"""
54+
Tests that Telescope.ccd_response is False if a ccd response
55+
function isn't given.
56+
"""
57+
assert(self.telescope.ccd_response is False)
58+
59+
def test_readnoise(self):
60+
"""Tests that Telescope returns the default readnoise"""
61+
assert(self.telescope.readnoise == self.default_readnoise)
62+
63+
def test_ad_err(self):
64+
"""Tests that Telescope returns the default ad_err"""
65+
assert(self.telescope.ad_err == self.default_ad_err)
66+
67+
@raises(TypeError)
68+
def test_diameter_type(self):
69+
"""
70+
Tests that Telescope raises an error if the user doesn't
71+
gives the bandpass as a unit quantity
72+
"""
73+
return Telescope(1, self.bandpass, self.gain).diameter
74+
75+
@raises(TypeError)
76+
def test_bandpass_type(self):
77+
"""
78+
Tests that Telescope raises an error if the user doesn't
79+
gives the bandpass as a unit quantity
80+
"""
81+
return Telescope(self.diameter, np.array([[],[]]), self.gain).bandpass
82+
83+
@raises(UserInputError)
84+
def test_bandpass_len(self):
85+
"""
86+
Tests that Telescope raises an error if the user doesn't
87+
give a bandpass of the correct shape
88+
"""
89+
return Telescope(self.diameter, np.array([]), self.gain).bandpass
90+
91+
@raises(TypeError)
92+
def test_gain_type(self):
93+
"""
94+
Tests that Telescope raises an error if gain isn't given
95+
as a `~astropy.units.quantity.Quantity`.
96+
"""
97+
return Telescope(self.diameter, self.bandpass, 1).gain
98+
99+
def test_default_ccd_response(self):
100+
"""
101+
Tests that Telescope.ccd_response returns the following array
102+
if set to 'default'.
103+
"""
104+
wl = np.array([100., 309.45600215, 319.53901519, 329.99173871,
105+
339.70504127, 349.78805431, 379.53294279, 390.00376402,
106+
399.57293121, 409.3114413, 419.5961146, 429.14136695,
107+
439.52687038, 449.9795939, 459.69289647, 469.60785929,
108+
479.85892255, 489.5638226, 499.59835962, 509.99161922,
109+
519.5607864, 529.30446727, 539.85285015, 549.59976275,
110+
559.51472558, 569.94676599, 579.68075166, 589.59571448,
111+
599.9631202, 609.56008031, 619.65269622, 630.09581687,
112+
639.67467926, 649.50561697, 659.84070534, 669.7685951,
113+
679.50258077, 689.9637068, 699.78494931, 709.53555533,
114+
719.83463294, 729.72858948, 739.88431656, 749.9673296,
115+
759.66253445, 769.59042422, 780.37854306, 789.59647942,
116+
799.60677842, 810.07759966, 819.65646205, 829.52341053,
117+
839.82248813, 849.68943661, 859.77244965, 870.07152726,
118+
879.71760973, 889.81096433, 899.94245339, 909.73137855,
119+
919.69435573, 930.06545485, 939.64431724, 949.72733028,
120+
959.95862293, 969.6772918, 979.76030484, 990.05938245,
121+
1100.]) * u.nm
122+
response = (np.array([0., 70.30747425, 73.11442327, 75.26541144, 76.58538173,
123+
74.70200949, 77.10351031, 81.79762371, 84.528972,
124+
87.18136276, 89.0405892, 91.16038906, 92.49142617,
125+
93.66048522, 94.87582372, 95.64295585, 96.56602958,
126+
97.20551595, 98.01709918, 98.32588679, 98.26189462,
127+
98.79719419, 99.10133838, 99.09379281, 99.35788748,
128+
99.30100555, 99.14661175, 98.81209184, 98.74843825,
129+
98.30855134, 98.04495971, 97.98459522, 97.24513015,
130+
96.85779131, 96.40002722, 96.03435769, 95.87183789,
131+
95.09275863, 94.89671913, 94.49854563, 94.12126754,
132+
93.52139537, 92.57268607, 91.77633908, 90.30410094,
133+
88.68846298, 86.74856762, 84.85909033, 82.85400237,
134+
80.76562301, 78.18504085, 75.90628116, 72.63150731,
135+
68.93418199, 65.34249453, 61.79608045, 58.13799205,
136+
54.49429826, 49.87975185, 45.18326838, 41.57397462,
137+
36.82027063, 32.80603172, 28.7917928, 25.09446748,
138+
21.39714216, 18.4392819, 14.89286782, 0.]) *
139+
u.Unit('') / 100)
140+
default_ccd_response = (wl, response)
141+
TELE = Telescope(self.diameter, self.bandpass, self.gain,
142+
ccd_response='default')
143+
assert(all(wl == TELE.ccd_response[0]) and
144+
all(response == TELE.ccd_response[1]))
145+
146+
def test_custom_ccd_response(self):
147+
"""
148+
Tests that Telescope.ccd_response gives back the user specified
149+
ccd response function.
150+
"""
151+
wl = np.arange(10) * u.angstrom
152+
response = np.arange(10) * u.Unit('')
153+
custom_ccd_response = (wl, response)
154+
155+
TELE = Telescope(self.diameter, self.bandpass, self.gain,
156+
ccd_response=custom_ccd_response)
157+
assert(TELE.ccd_response == custom_ccd_response)
158+
159+
@raises(TypeError)
160+
def test_custom_ccd_response_type(self):
161+
"""
162+
Tests that telescope raises an error if ccd_response isn't passed in
163+
as a `~astropy.units.quantity.Quantity`.
164+
"""
165+
wl = np.arange(10)
166+
response = np.arange(10)
167+
custom_ccd_response = (wl, response)
168+
return Telescope(self.diameter, self.bandpass, self.gain,
169+
ccd_response=custom_ccd_response).ccd_response
170+
171+
@raises(UserInputError)
172+
def test_custom_ccd_response_len(self):
173+
"""
174+
Tests that telescope raises an error if the given ccd_response isn't
175+
the right length
176+
"""
177+
return Telescope(self.diameter, self.bandpass, self.gain,
178+
ccd_response=np.array([])).ccd_response
179+
180+
@raises(TypeError)
181+
def test_readnoise_type(self):
182+
"""Tests that Telescope raises an error if readnoise isn't passed in
183+
as a `~astropy.units.quantity.Quantity`.
184+
"""
185+
return Telescope(self.diameter, self.bandpass, self.gain,
186+
readnoise=0)
187+
188+
@raises(TypeError)
189+
def test_ad_err_type(self):
190+
"""
191+
Tests that telescope raises an error if ad_err isn't given
192+
as a `~astropy.units.quantity.Quantity`.
193+
"""
194+
return Telescope(self.diameter, self.bandpass, self.gain,
195+
ad_err=1).ad_err

docs/tutorials/exptime.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ edu/arc35m/Instruments/ARCTIC/>`_ on APO's 3.5m telescope), and input:
200200
'theory/fps3/fps.php?ID=')
201201
>>> filt_path = download_file(svo_link + 'SLOAN/SDSS.rprime_filter')
202202
>>> bandpass = SpectralElement.from_file(filt_path)
203+
>>> bandpass.plot()
203204
204205
.. plot::
205206

0 commit comments

Comments
 (0)