Hide keyboard shortcuts

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 

13 

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 

19 

20 

21ROOT = os.path.abspath(os.path.dirname(__file__)) 

22 

23 

24def setup_module(module): 

25 lsst.utils.tests.init() 

26 

27 

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) 

36 

37 def tearDown(self): 

38 del self.bandpasswavelen 

39 del self.bandpasssb 

40 del self.testbandpass 

41 del self.wmin 

42 del self.wmax 

43 

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') 

52 

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) 

85 

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) 

110 

111 

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) 

120 

121 def tearDown(self): 

122 del self.wmin, self.wmax, self.wavelen, self.flambda 

123 del self.name 

124 del self.testsed 

125 

126 def testSetName(self): 

127 self.assertEqual(self.testsed.name, self.name) 

128 

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) 

136 

137 

138class SedBasicFunctionsTestCase(unittest.TestCase): 

139 

140 longMessage = True 

141 

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 """ 

147 

148 scratch_dir = tempfile.mkdtemp(prefix='test_read_sed_flambda', 

149 dir=ROOT) 

150 

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)) 

166 

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') 

172 

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]) 

178 

179 if os.path.exists(scratch_dir): 

180 shutil.rmtree(scratch_dir) 

181 

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) 

197 

198 self.assertFalse(ss1 == ss2) 

199 self.assertTrue(ss1 != ss2) 

200 self.assertTrue(ss1 == ss3) 

201 self.assertFalse(ss1 != ss3) 

202 

203 ss3.flambdaTofnu() 

204 

205 self.assertFalse(ss1 == ss3) 

206 self.assertTrue(ss1 != ss3) 

207 

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') 

218 

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) 

228 

229 self.assertEqual(ss_cache, ss_uncache, msg=msg) 

230 

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) 

245 

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 """ 

252 

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 

257 

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))) 

260 

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 

264 

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)) 

269 

270 exp_arg = np.power(10.0, log10_exp_arg) 

271 log10_bose_factor = -1.0*np.log10(np.exp(exp_arg)-1.0) 

272 

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) 

281 

282 sed = Sed(wavelen=wavelen_arr, flambda=bb_flambda) 

283 ergs = sed.calcErgs(bp) 

284 

285 log10_ergs = np.log10(stefan_boltzmann_sigma) + 4.0*np.log10(temp) 

286 ergs_truth = np.power(10.0, log10_ergs) 

287 

288 msg = '\ntemp:%e\nergs: %e\nergs_truth: %e' % (temp, ergs, ergs_truth) 

289 self.assertAlmostEqual(ergs/ergs_truth, 1.0, 3, msg=msg) 

290 

291 # Now test it on a bandpass with throughput=0.25 and an wavelength 

292 # array that is not the same as the SED 

293 

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))) 

296 

297 wavelen_arr = np.arange(5.0, 200000.0, 17.0) 

298 

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 

302 

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)) 

307 

308 exp_arg = np.power(10.0, log10_exp_arg) 

309 log10_bose_factor = -1.0*np.log10(np.exp(exp_arg)-1.0) 

310 

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) 

319 

320 sed = Sed(wavelen=wavelen_arr, flambda=bb_flambda) 

321 ergs = sed.calcErgs(bp) 

322 

323 log10_ergs = np.log10(stefan_boltzmann_sigma) + 4.0*np.log10(temp) 

324 ergs_truth = np.power(10.0, log10_ergs) 

325 

326 msg = '\ntemp: %e\nergs: %e\nergs_truth: %e' % (temp,ergs, ergs_truth) 

327 self.assertAlmostEqual(ergs/ergs_truth, 0.25, 3, msg=msg) 

328 

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 

337 

338 ss = Sed(wavelen=wavelen, flambda=flambda) 

339 bp = Bandpass(wavelen=wavelen, sb=sb) 

340 

341 mag = ss.calcMag(bp) 

342 flux = ss.calcFlux(bp) 

343 

344 self.assertAlmostEqual(ss.magFromFlux(flux)/mag, 1.0, 10) 

345 self.assertAlmostEqual(ss.fluxFromMag(mag)/flux, 1.0, 10) 

346 

347 

348class MemoryTestClass(lsst.utils.tests.MemoryTestCase): 

349 pass 

350 

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()