Coverage for tests/testSed.py : 16%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import with_statement
2from __future__ import print_function
3from builtins import zip
4from builtins import str
5from builtins import range
6import numpy as np
7import warnings
8import unittest
9import gzip
10import os
11import tempfile
12import shutil
14import lsst.utils.tests
15from lsst.utils import getPackageDir
16import lsst.sims.photUtils.Sed as Sed
17import lsst.sims.photUtils.Bandpass as Bandpass
18from lsst.sims.photUtils import PhotometricParameters
21ROOT = os.path.abspath(os.path.dirname(__file__))
24def setup_module(module):
25 lsst.utils.tests.init()
28class TestSedWavelenLimits(unittest.TestCase):
29 def setUp(self):
30 warnings.simplefilter('always')
31 self.wmin = 500
32 self.wmax = 1500
33 self.bandpasswavelen = np.arange(self.wmin, self.wmax+.5, 1)
34 self.bandpasssb = np.ones(len(self.bandpasswavelen))
35 self.testbandpass = Bandpass(wavelen=self.bandpasswavelen, sb=self.bandpasssb)
37 def tearDown(self):
38 del self.bandpasswavelen
39 del self.bandpasssb
40 del self.testbandpass
41 del self.wmin
42 del self.wmax
44 def testSedWavelenRange(self):
45 """Test setting sed with wavelength range different from standard values works properly."""
46 sedwavelen = self.bandpasswavelen * 1.0
47 sedflambda = np.ones(len(sedwavelen))
48 testsed = Sed(wavelen=sedwavelen, flambda=sedflambda, name='TestSed')
49 np.testing.assert_equal(testsed.wavelen, sedwavelen)
50 np.testing.assert_equal(testsed.flambda, sedflambda)
51 self.assertEqual(testsed.name, 'TestSed')
53 def testSedBandpassMatch(self):
54 """Test errors when bandpass and sed do not completely overlap in wavelength range."""
55 # Test case where they do match (no error message)
56 sedwavelen = np.arange(self.wmin, self.wmax+.5, 1)
57 sedflambda = np.ones(len(sedwavelen))
58 testsed = Sed(wavelen=sedwavelen, flambda=sedflambda)
59 print('')
60 # Test that no warning is made.
61 with warnings.catch_warnings(record=True) as wa:
62 w, f = testsed.resampleSED(wavelen_match=self.testbandpass.wavelen,
63 wavelen=testsed.wavelen, flux=testsed.flambda)
64 self.assertEqual(len(wa), 0)
65 np.testing.assert_equal(w, testsed.wavelen)
66 np.testing.assert_equal(f, testsed.flambda)
67 # Test that warning is given for non-overlap at either top or bottom end of wavelength range.
68 sedwavelen = np.arange(self.wmin, self.wmax - 50, 1)
69 sedflambda = np.ones(len(sedwavelen))
70 testsed = Sed(wavelen=sedwavelen, flambda=sedflambda)
71 with warnings.catch_warnings(record=True) as wa:
72 testsed.resampleSED(wavelen_match=self.testbandpass.wavelen)
73 self.assertEqual(len(wa), 1)
74 self.assertIn('non-overlap', str(wa[-1].message))
75 np.testing.assert_equal(testsed.flambda[-1:], np.NaN)
76 sedwavelen = np.arange(self.wmin+50, self.wmax, 1)
77 sedflambda = np.ones(len(sedwavelen))
78 testsed = Sed(wavelen=sedwavelen, flambda=sedflambda)
79 with warnings.catch_warnings(record=True) as wa:
80 testsed.resampleSED(wavelen_match=self.testbandpass.wavelen)
81 self.assertEqual(len(wa), 1)
82 self.assertIn('non-overlap', str(wa[-1].message))
83 np.testing.assert_equal(testsed.flambda[0], np.NaN)
84 np.testing.assert_equal(testsed.flambda[49], np.NaN)
86 def testSedMagErrors(self):
87 """Test error handling at mag and adu calculation levels of sed."""
88 sedwavelen = np.arange(self.wmin+50, self.wmax, 1)
89 sedflambda = np.ones(len(sedwavelen))
90 testsed = Sed(wavelen=sedwavelen, flambda=sedflambda)
91 # Test handling in calcMag
92 with warnings.catch_warnings(record=True) as w:
93 mag = testsed.calcMag(self.testbandpass)
94 self.assertEqual(len(w), 1)
95 self.assertIn("non-overlap", str(w[-1].message))
96 np.testing.assert_equal(mag, np.NaN)
97 # Test handling in calcADU
98 with warnings.catch_warnings(record=True) as w:
99 adu = testsed.calcADU(self.testbandpass,
100 photParams=PhotometricParameters())
101 self.assertEqual(len(w), 1)
102 self.assertIn("non-overlap", str(w[-1].message))
103 np.testing.assert_equal(adu, np.NaN)
104 # Test handling in calcFlux
105 with warnings.catch_warnings(record=True) as w:
106 flux = testsed.calcFlux(self.testbandpass)
107 self.assertEqual(len(w), 1)
108 self.assertIn("non-overlap", str(w[-1].message))
109 np.testing.assert_equal(flux, np.NaN)
112class TestSedName(unittest.TestCase):
113 def setUp(self):
114 self.wmin = 500
115 self.wmax = 1500
116 self.wavelen = np.arange(self.wmin, self.wmax+.5, 1)
117 self.flambda = np.ones(len(self.wavelen))
118 self.name = 'TestSed'
119 self.testsed = Sed(self.wavelen, self.flambda, name=self.name)
121 def tearDown(self):
122 del self.wmin, self.wmax, self.wavelen, self.flambda
123 del self.name
124 del self.testsed
126 def testSetName(self):
127 self.assertEqual(self.testsed.name, self.name)
129 def testRedshiftName(self):
130 testsed = Sed(self.testsed.wavelen, self.testsed.flambda, name=self.testsed.name)
131 redshift = .2
132 testsed.redshiftSED(redshift=redshift)
133 newname = testsed.name + '_Z' + '%.2f' % (redshift)
134 testsed.name = newname
135 self.assertEqual(testsed.name, newname)
138class SedBasicFunctionsTestCase(unittest.TestCase):
140 longMessage = True
142 def test_read_sed_flambda(self):
143 """
144 Test how readSED_flambda handles the reading of SED filenames
145 when we fail to correctly specify their gzipped state.
146 """
148 scratch_dir = tempfile.mkdtemp(prefix='test_read_sed_flambda',
149 dir=ROOT)
151 rng = np.random.RandomState(88)
152 zipped_name = os.path.join(scratch_dir, "zipped_sed.txt.gz")
153 unzipped_name = os.path.join(scratch_dir, "unzipped_sed.txt")
154 if os.path.exists(zipped_name):
155 os.unlink(zipped_name)
156 if os.path.exists(unzipped_name):
157 os.unlink(unzipped_name)
158 wv = np.arange(100.0, 1000.0, 10.0)
159 flux = rng.random_sample(len(wv))
160 with gzip.open(zipped_name, "wt") as output_file:
161 for ww, ff in zip(wv, flux):
162 output_file.write("%e %e\n" % (ww, ff))
163 with open(unzipped_name, "wt") as output_file:
164 for ww, ff in zip(wv, flux):
165 output_file.write("%e %e\n" % (ww, ff))
167 ss = Sed()
168 ss.readSED_flambda(zipped_name)
169 ss.readSED_flambda(zipped_name[:-3])
170 ss.readSED_flambda(unzipped_name)
171 ss.readSED_flambda(unzipped_name+'.gz')
173 # make sure an error is raised when you try to read
174 # a file that does not exist
175 with self.assertRaises(IOError) as context:
176 ss.readSED_flambda(os.path.join(scratch_dir, "nonsense.txt"))
177 self.assertIn("sed file", context.exception.args[0])
179 if os.path.exists(scratch_dir):
180 shutil.rmtree(scratch_dir)
182 def test_eq(self):
183 """
184 Test that __eq__ in Sed works correctly
185 """
186 sed_dir = os.path.join(getPackageDir('sims_photUtils'), 'tests',
187 'cartoonSedTestData', 'starSed', 'kurucz')
188 list_of_seds = os.listdir(sed_dir)
189 sedname1 = os.path.join(sed_dir, list_of_seds[0])
190 sedname2 = os.path.join(sed_dir, list_of_seds[1])
191 ss1 = Sed()
192 ss1.readSED_flambda(sedname1)
193 ss2 = Sed()
194 ss2.readSED_flambda(sedname2)
195 ss3 = Sed()
196 ss3.readSED_flambda(sedname1)
198 self.assertFalse(ss1 == ss2)
199 self.assertTrue(ss1 != ss2)
200 self.assertTrue(ss1 == ss3)
201 self.assertFalse(ss1 != ss3)
203 ss3.flambdaTofnu()
205 self.assertFalse(ss1 == ss3)
206 self.assertTrue(ss1 != ss3)
208 def test_cache(self):
209 """
210 Verify that loading an SED from the cache gives identical
211 results to loading the same SED from ASCII (since we are
212 not calling cache_LSST_seds(), as soon as we load an SED
213 with readSED_flambda, it should get stored in the
214 _global_misc_sed_cache)
215 """
216 sed_dir = os.path.join(getPackageDir('sims_photUtils'), 'tests',
217 'cartoonSedTestData', 'starSed', 'kurucz')
219 sed_name_list = os.listdir(sed_dir)
220 msg = ('An SED loaded from the cache is not '
221 'identical to the same SED loaded from disk')
222 for ix in range(5):
223 full_name = os.path.join(sed_dir, sed_name_list[ix])
224 ss_uncache = Sed()
225 ss_uncache.readSED_flambda(full_name)
226 ss_cache = Sed()
227 ss_cache.readSED_flambda(full_name)
229 self.assertEqual(ss_cache, ss_uncache, msg=msg)
231 # test that modifications to an SED don't get pushed
232 # to the cache
233 full_name = os.path.join(sed_dir, sed_name_list[0])
234 ss1 = Sed()
235 ss1.readSED_flambda(full_name)
236 ss2 = Sed()
237 ss2.readSED_flambda(full_name)
238 ss2.flambda *= 2.0
239 ss3 = Sed()
240 ss3.readSED_flambda(full_name)
241 msg = "Changes to SED made it into the cache"
242 self.assertEqual(ss1, ss3, msg=msg)
243 self.assertNotEqual(ss1, ss2, msg=msg)
244 self.assertNotEqual(ss2, ss3, msg=msg)
246 def test_calcErgs(self):
247 """
248 Test that calcErgs actually calculates the flux of a source in
249 ergs/s/cm^2 by running it on black bodies with flat bandpasses
250 and comparing to the Stefan-Boltzmann law.
251 """
253 boltzmann_k = 1.3807e-16 # in ergs/Kelvin
254 planck_h = 6.6261e-27 # in cm^2*g/s
255 speed_of_light = 2.9979e10 # in cm/s
256 stefan_boltzmann_sigma = 5.6705e-5 # in ergs/cm^2/s/Kelvin
258 wavelen_arr = np.arange(10.0, 200000.0, 10.0) # in nm
259 bp = Bandpass(wavelen=wavelen_arr, sb=np.ones(len(wavelen_arr)))
261 log10_bb_factor = np.log10(2.0) + np.log10(planck_h)
262 log10_bb_factor += 2.0*np.log10(speed_of_light)
263 log10_bb_factor -= 5.0*(np.log10(wavelen_arr) - 7.0) # convert wavelen to cm
265 for temp in np.arange(5000.0, 7000.0, 250.0):
266 log10_exp_arg = np.log10(planck_h) + np.log10(speed_of_light)
267 log10_exp_arg -= (np.log10(wavelen_arr) - 7.0)
268 log10_exp_arg -= (np.log10(boltzmann_k) + np.log10(temp))
270 exp_arg = np.power(10.0, log10_exp_arg)
271 log10_bose_factor = -1.0*np.log10(np.exp(exp_arg)-1.0)
273 # the -7.0 below is because, otherwise, flambda will be in
274 # ergs/s/cm^2/cm and we want ergs/s/cm^2/nm
275 #
276 # the np.pi comes from the integral in the 'Stefan-Boltzmann'
277 # section of
278 # https://en.wikipedia.org/wiki/Planck%27s_law#Stefan.E2.80.93Boltzmann_law
279 #
280 bb_flambda = np.pi*np.power(10.0, log10_bb_factor+log10_bose_factor-7.0)
282 sed = Sed(wavelen=wavelen_arr, flambda=bb_flambda)
283 ergs = sed.calcErgs(bp)
285 log10_ergs = np.log10(stefan_boltzmann_sigma) + 4.0*np.log10(temp)
286 ergs_truth = np.power(10.0, log10_ergs)
288 msg = '\ntemp:%e\nergs: %e\nergs_truth: %e' % (temp, ergs, ergs_truth)
289 self.assertAlmostEqual(ergs/ergs_truth, 1.0, 3, msg=msg)
291 # Now test it on a bandpass with throughput=0.25 and an wavelength
292 # array that is not the same as the SED
294 wavelen_arr = np.arange(10.0, 100000.0, 146.0) # in nm
295 bp = Bandpass(wavelen=wavelen_arr, sb=0.25*np.ones(len(wavelen_arr)))
297 wavelen_arr = np.arange(5.0, 200000.0, 17.0)
299 log10_bb_factor = np.log10(2.0) + np.log10(planck_h)
300 log10_bb_factor += 2.0*np.log10(speed_of_light)
301 log10_bb_factor -= 5.0*(np.log10(wavelen_arr) - 7.0) # convert wavelen to cm
303 for temp in np.arange(5000.0, 7000.0, 250.0):
304 log10_exp_arg = np.log10(planck_h) + np.log10(speed_of_light)
305 log10_exp_arg -= (np.log10(wavelen_arr) - 7.0)
306 log10_exp_arg -= (np.log10(boltzmann_k) + np.log10(temp))
308 exp_arg = np.power(10.0, log10_exp_arg)
309 log10_bose_factor = -1.0*np.log10(np.exp(exp_arg)-1.0)
311 # the -7.0 below is because, otherwise, flambda will be in
312 # ergs/s/cm^2/cm and we want ergs/s/cm^2/nm
313 #
314 # the np.pi comes from the integral in the 'Stefan-Boltzmann'
315 # section of
316 # https://en.wikipedia.org/wiki/Planck%27s_law#Stefan.E2.80.93Boltzmann_law
317 #
318 bb_flambda = np.pi*np.power(10.0, log10_bb_factor+log10_bose_factor-7.0)
320 sed = Sed(wavelen=wavelen_arr, flambda=bb_flambda)
321 ergs = sed.calcErgs(bp)
323 log10_ergs = np.log10(stefan_boltzmann_sigma) + 4.0*np.log10(temp)
324 ergs_truth = np.power(10.0, log10_ergs)
326 msg = '\ntemp: %e\nergs: %e\nergs_truth: %e' % (temp,ergs, ergs_truth)
327 self.assertAlmostEqual(ergs/ergs_truth, 0.25, 3, msg=msg)
329 def test_mags_vs_flux(self):
330 """
331 Verify that the relationship between Sed.calcMag() and Sed.calcFlux()
332 is as expected
333 """
334 wavelen = np.arange(100.0, 1500.0, 1.0)
335 flambda = np.exp(-0.5*np.power((wavelen-500.0)/100.0,2))
336 sb = (wavelen-100.0)/1400.0
338 ss = Sed(wavelen=wavelen, flambda=flambda)
339 bp = Bandpass(wavelen=wavelen, sb=sb)
341 mag = ss.calcMag(bp)
342 flux = ss.calcFlux(bp)
344 self.assertAlmostEqual(ss.magFromFlux(flux)/mag, 1.0, 10)
345 self.assertAlmostEqual(ss.fluxFromMag(mag)/flux, 1.0, 10)
348class MemoryTestClass(lsst.utils.tests.MemoryTestCase):
349 pass
351if __name__ == "__main__": 351 ↛ 352line 351 didn't jump to line 352, because the condition on line 351 was never true
352 lsst.utils.tests.init()
353 unittest.main()