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 builtins import zip 

2from builtins import range 

3import os 

4import numpy as np 

5import unittest 

6import lsst.utils 

7import lsst.utils.tests 

8from lsst.sims.utils import ObservationMetaData 

9import lsst.sims.photUtils.SignalToNoise as snr 

10from lsst.sims.photUtils import Sed, Bandpass, PhotometricParameters, LSSTdefaults 

11from lsst.sims.photUtils.utils import setM5 

12 

13 

14def setup_module(module): 

15 lsst.utils.tests.init() 

16 

17 

18class TestSNRmethods(unittest.TestCase): 

19 

20 def setUp(self): 

21 

22 starName = os.path.join(lsst.utils.getPackageDir('sims_photUtils'), 

23 'tests/cartoonSedTestData/starSed/') 

24 starName = os.path.join(starName, 'kurucz', 'km20_5750.fits_g40_5790.gz') 

25 self.starSED = Sed() 

26 self.starSED.readSED_flambda(starName) 

27 imsimband = Bandpass() 

28 imsimband.imsimBandpass() 

29 fNorm = self.starSED.calcFluxNorm(22.0, imsimband) 

30 self.starSED.multiplyFluxNorm(fNorm) 

31 

32 hardwareDir = os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline') 

33 componentList = ['detector.dat', 'm1.dat', 'm2.dat', 'm3.dat', 

34 'lens1.dat', 'lens2.dat', 'lens3.dat'] 

35 self.skySed = Sed() 

36 self.skySed.readSED_flambda(os.path.join(hardwareDir, 'darksky.dat')) 

37 

38 totalNameList = ['total_u.dat', 'total_g.dat', 'total_r.dat', 'total_i.dat', 

39 'total_z.dat', 'total_y.dat'] 

40 

41 self.bpList = [] 

42 self.hardwareList = [] 

43 for name in totalNameList: 

44 dummy = Bandpass() 

45 dummy.readThroughput(os.path.join(hardwareDir, name)) 

46 self.bpList.append(dummy) 

47 

48 dummy = Bandpass() 

49 hardwareNameList = [os.path.join(hardwareDir, name)] 

50 for component in componentList: 

51 hardwareNameList.append(os.path.join(hardwareDir, component)) 

52 dummy.readThroughputList(hardwareNameList) 

53 self.hardwareList.append(dummy) 

54 

55 self.filterNameList = ['u', 'g', 'r', 'i', 'z', 'y'] 

56 

57 def testMagError(self): 

58 """ 

59 Make sure that calcMagError_sed and calcMagError_m5 

60 agree to within 0.001 

61 """ 

62 defaults = LSSTdefaults() 

63 photParams = PhotometricParameters() 

64 

65 # create a cartoon spectrum to test on 

66 spectrum = Sed() 

67 spectrum.setFlatSED() 

68 spectrum.multiplyFluxNorm(1.0e-9) 

69 

70 # find the magnitudes of that spectrum in our bandpasses 

71 magList = [] 

72 for total in self.bpList: 

73 magList.append(spectrum.calcMag(total)) 

74 magList = np.array(magList) 

75 

76 # try for different normalizations of the skySED 

77 for fNorm in np.arange(1.0, 5.0, 1.0): 

78 self.skySed.multiplyFluxNorm(fNorm) 

79 

80 for total, hardware, filterName, mm in \ 

81 zip(self.bpList, self.hardwareList, self.filterNameList, magList): 

82 

83 FWHMeff = defaults.FWHMeff(filterName) 

84 

85 m5 = snr.calcM5(self.skySed, total, hardware, photParams, FWHMeff=FWHMeff) 

86 

87 sigma_sed = snr.calcMagError_sed(spectrum, total, self.skySed, 

88 hardware, photParams, FWHMeff=FWHMeff) 

89 

90 sigma_m5, gamma = snr.calcMagError_m5(mm, total, m5, photParams) 

91 

92 self.assertAlmostEqual(sigma_m5, sigma_sed, 3) 

93 

94 def testVerboseSNR(self): 

95 """ 

96 Make sure that calcSNR_sed has everything it needs to run in verbose mode 

97 """ 

98 photParams = PhotometricParameters() 

99 

100 # create a cartoon spectrum to test on 

101 spectrum = Sed() 

102 spectrum.setFlatSED() 

103 spectrum.multiplyFluxNorm(1.0e-9) 

104 

105 snr.calcSNR_sed(spectrum, self.bpList[0], self.skySed, 

106 self.hardwareList[0], photParams, FWHMeff=0.7, verbose=True) 

107 

108 def testSignalToNoise(self): 

109 """ 

110 Test that calcSNR_m5 and calcSNR_sed give similar results 

111 """ 

112 defaults = LSSTdefaults() 

113 photParams = PhotometricParameters() 

114 

115 m5 = [] 

116 for i in range(len(self.hardwareList)): 

117 m5.append(snr.calcM5(self.skySed, self.bpList[i], 

118 self.hardwareList[i], 

119 photParams, FWHMeff=defaults.FWHMeff(self.filterNameList[i]))) 

120 

121 sedDir = os.path.join(lsst.utils.getPackageDir('sims_photUtils'), 

122 'tests/cartoonSedTestData/starSed/') 

123 sedDir = os.path.join(sedDir, 'kurucz') 

124 fileNameList = os.listdir(sedDir) 

125 

126 rng = np.random.RandomState(42) 

127 offset = rng.random_sample(len(fileNameList))*2.0 

128 

129 for ix, name in enumerate(fileNameList): 

130 if ix > 100: 

131 break 

132 spectrum = Sed() 

133 spectrum.readSED_flambda(os.path.join(sedDir, name)) 

134 ff = spectrum.calcFluxNorm(m5[2]-offset[ix], self.bpList[2]) 

135 spectrum.multiplyFluxNorm(ff) 

136 for i in range(len(self.bpList)): 

137 control_snr = snr.calcSNR_sed(spectrum, self.bpList[i], 

138 self.skySed, 

139 self.hardwareList[i], 

140 photParams, defaults.FWHMeff(self.filterNameList[i])) 

141 

142 mag = spectrum.calcMag(self.bpList[i]) 

143 

144 test_snr, gamma = snr.calcSNR_m5(mag, self.bpList[i], m5[i], photParams) 

145 self.assertLess((test_snr-control_snr)/control_snr, 0.001) 

146 

147 def testSystematicUncertainty(self): 

148 """ 

149 Test that systematic uncertainty is added correctly. 

150 """ 

151 sigmaSys = 0.002 

152 m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] 

153 photParams = PhotometricParameters(sigmaSys=sigmaSys) 

154 

155 obs_metadata = ObservationMetaData(pointingRA=23.0, pointingDec=45.0, 

156 m5=m5_list, bandpassName=self.filterNameList) 

157 magnitude_list = [] 

158 for bp in self.bpList: 

159 mag = self.starSED.calcMag(bp) 

160 magnitude_list.append(mag) 

161 

162 for bp, hardware, filterName, mm, m5 in \ 

163 zip(self.bpList, self.hardwareList, self.filterNameList, magnitude_list, m5_list): 

164 

165 skyDummy = Sed() 

166 skyDummy.readSED_flambda(os.path.join(lsst.utils.getPackageDir('throughputs'), 

167 'baseline', 'darksky.dat')) 

168 

169 normalizedSkyDummy = setM5(obs_metadata.m5[filterName], skyDummy, 

170 bp, hardware, 

171 FWHMeff=LSSTdefaults().FWHMeff(filterName), 

172 photParams=photParams) 

173 

174 sigma, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) 

175 

176 snrat = snr.calcSNR_sed(self.starSED, bp, normalizedSkyDummy, hardware, 

177 FWHMeff=LSSTdefaults().FWHMeff(filterName), 

178 photParams=PhotometricParameters()) 

179 

180 testSNR, gamma = snr.calcSNR_m5(mm, bp, m5, photParams=PhotometricParameters(sigmaSys=0.0)) 

181 

182 self.assertAlmostEqual(snrat, testSNR, 10, 

183 msg = 'failed on calcSNR_m5 test %e != %e ' 

184 % (snrat, testSNR)) 

185 

186 control = np.sqrt(np.power(snr.magErrorFromSNR(testSNR), 2) + np.power(sigmaSys, 2)) 

187 

188 msg = '%e is not %e; failed' % (sigma, control) 

189 

190 self.assertAlmostEqual(sigma, control, 10, msg=msg) 

191 

192 def testNoSystematicUncertainty(self): 

193 """ 

194 Test that systematic uncertainty is handled correctly when set to None. 

195 """ 

196 m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] 

197 photParams = PhotometricParameters(sigmaSys=0.0) 

198 

199 obs_metadata = ObservationMetaData(pointingRA=23.0, pointingDec=45.0, 

200 m5=m5_list, bandpassName=self.filterNameList) 

201 

202 magnitude_list = [] 

203 for bp in self.bpList: 

204 mag = self.starSED.calcMag(bp) 

205 magnitude_list.append(mag) 

206 

207 for bp, hardware, filterName, mm, m5 in \ 

208 zip(self.bpList, self.hardwareList, self.filterNameList, magnitude_list, m5_list): 

209 

210 skyDummy = Sed() 

211 skyDummy.readSED_flambda(os.path.join(lsst.utils.getPackageDir('throughputs'), 

212 'baseline', 'darksky.dat')) 

213 

214 normalizedSkyDummy = setM5(obs_metadata.m5[filterName], skyDummy, 

215 bp, hardware, 

216 FWHMeff=LSSTdefaults().FWHMeff(filterName), 

217 photParams=photParams) 

218 

219 sigma, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) 

220 

221 snrat = snr.calcSNR_sed(self.starSED, bp, normalizedSkyDummy, hardware, 

222 FWHMeff=LSSTdefaults().FWHMeff(filterName), 

223 photParams=PhotometricParameters()) 

224 

225 testSNR, gamma = snr.calcSNR_m5(mm, bp, m5, photParams=PhotometricParameters(sigmaSys=0.0)) 

226 

227 self.assertAlmostEqual(snrat, testSNR, 10, 

228 msg = 'failed on calcSNR_m5 test %e != %e ' 

229 % (snrat, testSNR)) 

230 

231 control = snr.magErrorFromSNR(testSNR) 

232 

233 msg = '%e is not %e; failed' % (sigma, control) 

234 

235 self.assertAlmostEqual(sigma, control, 10, msg=msg) 

236 

237 def testFWHMconversions(self): 

238 FWHMeff = 0.8 

239 FWHMgeom = snr.FWHMeff2FWHMgeom(FWHMeff) 

240 self.assertEqual(FWHMgeom, (0.822*FWHMeff+0.052)) 

241 FWHMgeom = 0.8 

242 FWHMeff = snr.FWHMgeom2FWHMeff(FWHMgeom) 

243 self.assertEqual(FWHMeff, (FWHMgeom-0.052)/0.822) 

244 

245 def testAstrometricError(self): 

246 fwhmGeom = 0.7 

247 m5 = 24.5 

248 # For bright objects, error should be systematic floor 

249 mag = 10 

250 astrometricErr = snr.calcAstrometricError(mag, m5, fwhmGeom=fwhmGeom, nvisit=1, systematicFloor=10) 

251 self.assertAlmostEqual(astrometricErr, 10, 3) 

252 # Even if you increase the number of visits, the systemic floor doesn't change 

253 astrometricErr = snr.calcAstrometricError(mag, m5, fwhmGeom=fwhmGeom, nvisit=100) 

254 self.assertAlmostEqual(astrometricErr, 10, 3) 

255 # For a single visit, fainter source, larger error and nvisits matters 

256 mag = 24.5 

257 astrometricErr1 = snr.calcAstrometricError(mag, m5, fwhmGeom=fwhmGeom, nvisit=1, 

258 systematicFloor=10) 

259 astrometricErr100 = snr.calcAstrometricError(mag, m5, fwhmGeom=fwhmGeom, nvisit=100, 

260 systematicFloor=10) 

261 self.assertGreater(astrometricErr1, astrometricErr100) 

262 self.assertAlmostEqual(astrometricErr1, 140.357, 3) 

263 

264 def testSNR_arr(self): 

265 """ 

266 Test that calcSNR_m5 works on numpy arrays of magnitudes 

267 """ 

268 rng = np.random.RandomState(17) 

269 mag_list = rng.random_sample(100)*5.0 + 15.0 

270 

271 photParams = PhotometricParameters() 

272 bp = self.bpList[0] 

273 m5 = 24.0 

274 control_list = [] 

275 for mm in mag_list: 

276 ratio, gamma = snr.calcSNR_m5(mm, bp, m5, photParams) 

277 control_list.append(ratio) 

278 control_list = np.array(control_list) 

279 

280 test_list, gamma = snr.calcSNR_m5(mag_list, bp, m5, photParams) 

281 

282 np.testing.assert_array_equal(control_list, test_list) 

283 

284 def testError_arr(self): 

285 """ 

286 Test that calcMagError_m5 works on numpy arrays of magnitudes 

287 """ 

288 rng = np.random.RandomState(17) 

289 mag_list = rng.random_sample(100)*5.0 + 15.0 

290 

291 photParams = PhotometricParameters() 

292 bp = self.bpList[0] 

293 m5 = 24.0 

294 control_list = [] 

295 for mm in mag_list: 

296 sig, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) 

297 control_list.append(sig) 

298 control_list = np.array(control_list) 

299 

300 test_list, gamma = snr.calcMagError_m5(mag_list, bp, m5, photParams) 

301 

302 np.testing.assert_array_equal(control_list, test_list) 

303 

304 

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

306 pass 

307 

308if __name__ == "__main__": 308 ↛ 309line 308 didn't jump to line 309, because the condition on line 308 was never true

309 lsst.utils.tests.init() 

310 unittest.main()