Coverage for tests/test_makeRawVisitInfo.py: 16%

Shortcuts 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

182 statements  

1# This file is part of obs_base. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22import math 

23import unittest 

24 

25import astropy.coordinates 

26import astropy.units 

27 

28import lsst.utils.tests 

29import lsst.pex.exceptions 

30from lsst.daf.base import DateTime, PropertySet 

31from lsst.obs.base import MakeRawVisitInfo 

32from lsst.geom import degrees 

33 

34 

35class SimpleMakeRawVisitInfo(MakeRawVisitInfo): 

36 

37 def getDateAvg(self, md, exposureTime): 

38 """Return date at the middle of the exposure""" 

39 dateObs = self.popIsoDate(md, "DATE-OBS") 

40 return self.offsetDate(dateObs, 0.5*exposureTime) 

41 

42 

43def getMetadata(keyValDict): 

44 md = PropertySet() 

45 for key, val in keyValDict.items(): 

46 md.set(key, val) 

47 return md 

48 

49 

50class VisitInfoTestCase(lsst.utils.tests.TestCase): 

51 """Test lsst.afw.image.VisitInfo, a simple struct-like class""" 

52 

53 def setUp(self): 

54 self.makeRawVisitInfo = SimpleMakeRawVisitInfo() 

55 

56 def testMakeRawVisitInfo(self): 

57 """Test base class functor MakeRawVisitInfo 

58 

59 The base class only sets date and exposureTime fields, 

60 reads DATE-OBS, TIMESYS and EXPTIME, 

61 and deletes DATE-OBS and EXPTIME, but not TIMESYS. 

62 """ 

63 exposureTime = 6.2 # arbitrary value in seconds 

64 date = DateTime("2001-01-02T03:04:05.123456789", DateTime.TAI) 

65 dateNsec = date.nsecs(DateTime.TAI) 

66 startDate = DateTime(dateNsec - int(exposureTime*1e9/2), DateTime.TAI) 

67 

68 exposureId = 54321 # an arbitrary value 

69 md = getMetadata({ 

70 "DATE-OBS": startDate.toString(DateTime.UTC), 

71 "TIMESYS": "UTC", 

72 "EXPTIME": exposureTime, 

73 "EXTRA1": "an abitrary key and value", 

74 "EXTRA2": 5, 

75 }) 

76 length = len(md) 

77 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId) 

78 self.assertEqual(visitInfo.getExposureId(), exposureId) 

79 self.assertEqual(md.nameCount(), length) # No stripping 

80 self.assertEqual(visitInfo.getExposureTime(), exposureTime) 

81 self.assertEqual(visitInfo.getDate(), date) 

82 

83 # Test stripping keywords 

84 visitInfo = SimpleMakeRawVisitInfo(doStripHeader=True)(md=md, exposureId=exposureId) 

85 self.assertEqual(md.nameCount(), 3) # TIMESYS and two EXTRAn keywords 

86 

87 # try TIMESYS=TAI 

88 md = getMetadata({ 

89 "DATE-OBS": startDate.toString(DateTime.TAI), 

90 "TIMESYS": "TAI", 

91 "EXPTIME": exposureTime, 

92 }) 

93 length = len(md) 

94 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId) 

95 self.assertEqual(md.nameCount(), length) 

96 self.assertEqual(visitInfo.getExposureTime(), exposureTime) 

97 self.assertEqual(visitInfo.getDate(), date) 

98 

99 # try omitting TIMESYS, which defaults to UTC 

100 md = getMetadata({ 

101 "DATE-OBS": startDate.toString(DateTime.UTC), 

102 "EXPTIME": exposureTime, 

103 }) 

104 length = len(md) 

105 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId) 

106 self.assertEqual(md.nameCount(), length) 

107 self.assertEqual(visitInfo.getExposureTime(), exposureTime) 

108 self.assertEqual(visitInfo.getDate(), date) 

109 

110 # omit DATE-OBS; date should be default-constructed 

111 md = getMetadata({ 

112 "EXPTIME": exposureTime, 

113 }) 

114 length = len(md) 

115 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId) 

116 self.assertEqual(md.nameCount(), length) 

117 self.assertEqual(visitInfo.getExposureTime(), exposureTime) 

118 self.assertEqual(visitInfo.getDate(), DateTime()) 

119 

120 # omit EXPTIME; date should be start date, not avg date, and 

121 # exposureTime should be nan 

122 md = getMetadata({ 

123 "DATE-OBS": startDate.toString(DateTime.UTC), 

124 }) 

125 length = len(md) 

126 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId) 

127 self.assertEqual(md.nameCount(), length) 

128 self.assertTrue(math.isnan(visitInfo.getExposureTime())) 

129 self.assertEqual(visitInfo.getDate(), startDate) 

130 

131 def testPopItem(self): 

132 md = getMetadata({ 

133 "TIMESYS": "UTC", 

134 "OTHER": 5, 

135 }) 

136 names = set(md.names()) 

137 

138 timesys = self.makeRawVisitInfo.popItem(md, "TIMESYS") 

139 self.assertEqual(timesys, "UTC") 

140 self.assertEqual(set(md.names()), names) 

141 

142 defVal = self.makeRawVisitInfo.popItem(md, "BADKEY", default=7) 

143 self.assertEqual(set(md.names()), names) 

144 self.assertEqual(defVal, 7) 

145 missingItem = self.makeRawVisitInfo.popItem(md, "BADKEY") 

146 self.assertIsNone(missingItem) 

147 

148 # Repeat, with stripping 

149 timesys = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "TIMESYS") 

150 self.assertEqual(timesys, "UTC") 

151 self.assertEqual(set(md.names()), set(["OTHER"])) 

152 

153 defVal = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "BADKEY", default=7) 

154 self.assertEqual(set(md.names()), set(["OTHER"])) 

155 self.assertEqual(defVal, 7) 

156 missingItem = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "BADKEY") 

157 self.assertIsNone(missingItem) 

158 

159 def testPopFloat(self): 

160 dataDict = { 

161 "FLOAT": 5.5, 

162 "INT": 5, 

163 "FLOATSTR": "6.1", 

164 "INTSTR": "6", 

165 "STR": "FOO", 

166 } 

167 length = len(dataDict) 

168 

169 for key, desValue in dataDict.items(): 

170 if key == "STR": 

171 continue 

172 md = getMetadata(dataDict) 

173 value = self.makeRawVisitInfo.popFloat(md, key) 

174 self.assertAlmostEqual(value, float(desValue)) 

175 self.assertEqual(len(md.names()), length) 

176 

177 badFloat = self.makeRawVisitInfo.popFloat(md, "STR") 

178 self.assertTrue(math.isnan(badFloat)) 

179 

180 missingValue = self.makeRawVisitInfo.popFloat(md, "BADKEY") 

181 self.assertTrue(math.isnan(missingValue)) 

182 

183 def testPopAngle(self): 

184 dataDict = { 

185 "DEG1": 270.5, 

186 "DEG2": "45:30", 

187 "DEG3": "-310:12:32", 

188 "HR_1": -23.5, 

189 "HR_2": "23:30", 

190 "HR_3": "-13:15:16.7", 

191 "STR": "FOO", 

192 } 

193 

194 for key, desValue in dataDict.items(): 

195 if key == "STR": 

196 continue 

197 elif key.startswith("DEG"): 

198 units = astropy.units.deg 

199 else: 

200 units = astropy.units.h 

201 

202 desAngleDeg = astropy.coordinates.Angle(desValue, unit=units).deg 

203 md = getMetadata(dataDict) 

204 angle = self.makeRawVisitInfo.popAngle(md, key, units=units) 

205 self.assertAnglesAlmostEqual(angle, desAngleDeg*degrees) 

206 

207 badAngle = self.makeRawVisitInfo.popAngle(md, "STR") 

208 self.assertTrue(math.isnan(badAngle.asDegrees())) 

209 

210 missingAngle = self.makeRawVisitInfo.popAngle(md, "BADKEY") 

211 self.assertTrue(math.isnan(missingAngle.asDegrees())) 

212 

213 def testPopIsoDate(self): 

214 for timesys in (None, "UTC", "TAI"): 

215 dataDict = { 

216 "DATE1": "2001-02-03T04:05:06.123456789", 

217 "DATE2": "2001-02-03T04:05:06.123456789Z", # Z should be ignored 

218 "DATE3": "1980-03-04T01:02:03.999999999", 

219 "BADISODATE": "51234.354", 

220 } 

221 if timesys is not None: 

222 dataDict["TIMESYS"] = timesys 

223 length = len(dataDict) 

224 

225 for key, dateStr in dataDict.items(): 

226 if not key.startswith("DATE"): 

227 continue 

228 

229 lsstSys = dict( 

230 UTC=DateTime.UTC, 

231 TAI=DateTime.TAI, 

232 ).get(timesys, DateTime.UTC) 

233 

234 # lsstDateStr = dateStr with trailing Z if UTC, else no 

235 # trailing Z, because lsst.daf.base.DateTime is very picky 

236 lsstDateStr = dateStr 

237 if lsstSys == DateTime.UTC: 

238 if not lsstDateStr.endswith("Z"): 

239 lsstDateStr = lsstDateStr + "Z" 

240 elif dateStr.endswith("Z"): 

241 lsstDateStr = lsstDateStr[0:-1] 

242 desDate = DateTime(lsstDateStr, lsstSys) 

243 

244 md = getMetadata(dataDict) 

245 date = self.makeRawVisitInfo.popIsoDate(md, key, timesys=timesys) 

246 self.assertEqual(len(md.names()), length) 

247 self.assertEqual(date, desDate) 

248 

249 badDate = self.makeRawVisitInfo.popIsoDate(md, "BADISODATE") 

250 self.assertEqual(badDate, DateTime()) 

251 

252 missingDate = self.makeRawVisitInfo.popIsoDate(md, "BADKEY") 

253 self.assertEqual(missingDate, DateTime()) 

254 

255 def testPopMjdDate(self): 

256 for timesys in (None, "UTC", "TAI"): 

257 

258 dataDict = { 

259 "DATE1": 51943.1705801, 

260 "DATE2": 44302.0433218, 

261 "BADMJDDATE": "2001-02-03T04:05:06.123456789", 

262 } 

263 if timesys is not None: 

264 dataDict["TIMESYS"] = timesys 

265 length = len(dataDict) 

266 

267 for key, mjdDate in dataDict.items(): 

268 if not key.startswith("DATE"): 

269 continue 

270 

271 lsstSys = dict( 

272 UTC=DateTime.UTC, 

273 TAI=DateTime.TAI, 

274 ).get(timesys, DateTime.UTC) 

275 

276 desDate = DateTime(mjdDate, DateTime.MJD, lsstSys) 

277 

278 md = getMetadata(dataDict) 

279 date = self.makeRawVisitInfo.popMjdDate(md, key, timesys=timesys) 

280 self.assertEqual(len(md.names()), length) 

281 self.assertAlmostEqual(date.get(), desDate.get()) 

282 

283 badDate = self.makeRawVisitInfo.popMjdDate(md, "BADMJDDATE") 

284 self.assertEqual(badDate, DateTime()) 

285 

286 missingDate = self.makeRawVisitInfo.popMjdDate(md, "BADKEY") 

287 self.assertEqual(missingDate, DateTime()) 

288 

289 def testEraFromLstAndLongitude(self): 

290 LST = 90*degrees 

291 Longitude = 50*degrees 

292 era = self.makeRawVisitInfo.eraFromLstAndLongitude(LST, Longitude) 

293 self.assertAnglesAlmostEqual(era, LST-Longitude) 

294 

295 def testEraFromLstAndLongitude_float_vs_Angle_fails(self): 

296 val1 = 90*degrees 

297 val2 = 50.0 

298 with self.assertRaises(TypeError): 

299 self.makeRawVisitInfo.eraFromLstAndLongitude(val1, val2) 

300 with self.assertRaises(TypeError): 

301 self.makeRawVisitInfo.eraFromLstAndLongitude(val2, val1) 

302 

303 def testAltitudeFromZenithDistance(self): 

304 for zdDeg in (0, 35.6, 89.999, 90.0): 

305 desAltDeg = 90-zdDeg 

306 self.assertAnglesAlmostEqual( 

307 desAltDeg*degrees, 

308 self.makeRawVisitInfo.altitudeFromZenithDistance(zdDeg*degrees), 

309 ) 

310 

311 def testCentigradeFromKelvin(self): 

312 for tempK, desTempC in ( # a few values from http://www.convertunits.com/from/kelvin/to/centigrade 

313 (0, -273.15), 

314 (301.5, 28.35), 

315 ): 

316 self.assertAlmostEqual(desTempC, self.makeRawVisitInfo.centigradeFromKelvin(tempK)) 

317 

318 def testPascalFromMmHg(self): 

319 for mmHg, desPascal in ( # a few values from http://www.convertunits.com/from/mm+Hg/to/pascal 

320 (1, 133.32239), 

321 (0.062, 8.26598818), 

322 ): 

323 self.assertAlmostEqual(desPascal, self.makeRawVisitInfo.pascalFromMmHg(mmHg), places=5) 

324 

325 

326def setup_module(module): 

327 lsst.utils.tests.init() 

328 

329 

330class MemoryTester(lsst.utils.tests.MemoryTestCase): 

331 pass 

332 

333 

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

335 lsst.utils.tests.init() 

336 unittest.main()