Coverage for tests/test_visitInfo.py: 10%

417 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-20 02:20 -0700

1# 

2# LSST Data Management System 

3# Copyright 2016 LSST Corporation. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

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

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

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

11# (at your option) any later version. 

12# 

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

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

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

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22import math 

23import os 

24import unittest 

25import collections 

26import numpy as np 

27 

28import lsst.utils.tests 

29import lsst.pex.exceptions 

30from lsst.daf.base import DateTime, PropertySet, PropertyList 

31from lsst.geom import Angle, degrees, SpherePoint 

32from lsst.afw.coord import Observatory, Weather 

33import lsst.afw.image as afwImage 

34 

35RotTypeEnumNameDict = { 

36 afwImage.RotType.UNKNOWN: "UNKNOWN", 

37 afwImage.RotType.SKY: "SKY", 

38 afwImage.RotType.HORIZON: "HORIZON", 

39 afwImage.RotType.MOUNT: "MOUNT", 

40} 

41 

42 

43def propertySetFromDict(keyValDict): 

44 """Make an lsst.daf.base.PropertySet from a dict of key: value""" 

45 metadata = PropertySet() 

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

47 metadata.set(key, val) 

48 return metadata 

49 

50 

51def makeVisitInfo(data): 

52 """Return a VisitInfo constructed from a VisitInfoData namedtuple.""" 

53 return afwImage.VisitInfo(data.exposureId, 

54 data.exposureTime, 

55 data.darkTime, 

56 data.date, 

57 data.ut1, 

58 data.era, 

59 data.boresightRaDec, 

60 data.boresightAzAlt, 

61 data.boresightAirmass, 

62 data.boresightRotAngle, 

63 data.rotType, 

64 data.observatory, 

65 data.weather, 

66 data.instrumentLabel, 

67 data.id, 

68 data.focusZ, 

69 data.observationType, 

70 data.scienceProgram, 

71 data.observationReason, 

72 data.object, 

73 data.hasSimulatedContent, 

74 ) 

75 

76 

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

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

79 

80 def setUp(self): 

81 self.testDir = os.path.dirname(__file__) 

82 

83 def computeLstHA(data): 

84 """Return LST, Hour Angle, computed from VisitInfoData.""" 

85 localEra = data.era + data.observatory.getLongitude() 

86 hourAngle = localEra - data.boresightRaDec[0] 

87 return localEra, hourAngle 

88 

89 fields = ['exposureId', 

90 'exposureTime', 

91 'darkTime', 

92 'date', 

93 'ut1', 

94 'era', 

95 'boresightRaDec', 

96 'boresightAzAlt', 

97 'boresightAirmass', 

98 'boresightRotAngle', 

99 'rotType', 

100 'observatory', 

101 'weather', 

102 'instrumentLabel', 

103 'id', 

104 'focusZ', 

105 'observationType', 

106 "scienceProgram", 

107 "observationReason", 

108 "object", 

109 "hasSimulatedContent", 

110 ] 

111 VisitInfoData = collections.namedtuple("VisitInfoData", fields) 

112 data1 = VisitInfoData(exposureId=10313423, 

113 exposureTime=10.01, 

114 darkTime=11.02, 

115 date=DateTime( 

116 65321.1, DateTime.MJD, DateTime.TAI), 

117 ut1=12345.1, 

118 era=45.1*degrees, 

119 boresightRaDec=SpherePoint( 

120 23.1*degrees, 73.2*degrees), 

121 boresightAzAlt=SpherePoint( 

122 134.5*degrees, 33.3*degrees), 

123 boresightAirmass=1.73, 

124 boresightRotAngle=73.2*degrees, 

125 rotType=afwImage.RotType.SKY, 

126 observatory=Observatory( 

127 11.1*degrees, 22.2*degrees, 0.333), 

128 weather=Weather(1.1, 2.2, 34.5), 

129 instrumentLabel="TestCameraOne", 

130 id=987654, 

131 focusZ=1.5, 

132 observationType="flat", 

133 scienceProgram="test program", 

134 observationReason="test reason", 

135 object="test object", 

136 hasSimulatedContent=False, 

137 ) 

138 self.data1 = data1 

139 self.localEra1, self.hourAngle1 = computeLstHA(data1) 

140 data2 = VisitInfoData(exposureId=1, 

141 exposureTime=15.5, 

142 darkTime=17.8, 

143 date=DateTime( 

144 55321.2, DateTime.MJD, DateTime.TAI), 

145 ut1=312345.1, 

146 era=25.1*degrees, 

147 boresightRaDec=SpherePoint( 

148 2.1*degrees, 33.2*degrees), 

149 boresightAzAlt=SpherePoint(13.5*degrees, 83.3*degrees), 

150 boresightAirmass=2.05, 

151 boresightRotAngle=-53.2*degrees, 

152 rotType=afwImage.RotType.HORIZON, 

153 observatory=Observatory( 

154 22.2*degrees, 33.3*degrees, 0.444), 

155 weather=Weather(2.2, 3.3, 44.4), 

156 instrumentLabel="TestCameraTwo", 

157 id=123456, 

158 focusZ=-0.7, 

159 observationType="science", 

160 scienceProgram="test program 2", 

161 observationReason="test reason 2", 

162 object="test object 2", 

163 hasSimulatedContent=True, 

164 ) 

165 self.data2 = data2 

166 self.localEra2, self.hourAngle2 = computeLstHA(data2) 

167 

168 def _testValueConstructor(self, data, localEra, hourAngle): 

169 visitInfo = makeVisitInfo(data) 

170 with self.assertWarns(FutureWarning): 

171 self.assertEqual(visitInfo.getExposureId(), data.exposureId) 

172 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime) 

173 self.assertEqual(visitInfo.getDarkTime(), data.darkTime) 

174 self.assertEqual(visitInfo.getDate(), data.date) 

175 self.assertEqual(visitInfo.getUt1(), data.ut1) 

176 self.assertEqual(visitInfo.getEra(), data.era) 

177 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec) 

178 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt) 

179 self.assertEqual(visitInfo.getBoresightAirmass(), 

180 data.boresightAirmass) 

181 self.assertEqual(visitInfo.getBoresightRotAngle(), 

182 data.boresightRotAngle) 

183 self.assertEqual(visitInfo.getRotType(), data.rotType) 

184 self.assertEqual(visitInfo.getObservatory(), data.observatory) 

185 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel) 

186 self.assertEqual(visitInfo.getWeather(), data.weather) 

187 self.assertEqual(visitInfo.getLocalEra(), localEra) 

188 self.assertEqual(visitInfo.getBoresightHourAngle(), hourAngle) 

189 self.assertEqual(visitInfo.getId(), data.id) 

190 self.assertEqual(visitInfo.getFocusZ(), data.focusZ) 

191 self.assertEqual(visitInfo.getObservationType(), data.observationType) 

192 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram) 

193 self.assertEqual(visitInfo.getObservationReason(), data.observationReason) 

194 self.assertEqual(visitInfo.getObject(), data.object) 

195 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent) 

196 

197 def _testProperties(self, data, localEra, hourAngle): 

198 """Test property attribute accessors.""" 

199 visitInfo = makeVisitInfo(data) 

200 self.assertEqual(visitInfo.exposureTime, data.exposureTime) 

201 self.assertEqual(visitInfo.darkTime, data.darkTime) 

202 self.assertEqual(visitInfo.date, data.date) 

203 self.assertEqual(visitInfo.ut1, data.ut1) 

204 self.assertEqual(visitInfo.era, data.era) 

205 self.assertEqual(visitInfo.boresightRaDec, data.boresightRaDec) 

206 self.assertEqual(visitInfo.boresightAzAlt, data.boresightAzAlt) 

207 self.assertEqual(visitInfo.boresightAirmass, data.boresightAirmass) 

208 self.assertEqual(visitInfo.boresightRotAngle, data.boresightRotAngle) 

209 self.assertEqual(visitInfo.rotType, data.rotType) 

210 self.assertEqual(visitInfo.observatory, data.observatory) 

211 self.assertEqual(visitInfo.instrumentLabel, data.instrumentLabel) 

212 self.assertEqual(visitInfo.weather, data.weather) 

213 self.assertEqual(visitInfo.localEra, localEra) 

214 self.assertEqual(visitInfo.boresightHourAngle, hourAngle) 

215 self.assertEqual(visitInfo.id, data.id) 

216 self.assertEqual(visitInfo.focusZ, data.focusZ) 

217 self.assertEqual(visitInfo.observationType, data.observationType) 

218 self.assertEqual(visitInfo.scienceProgram, data.scienceProgram) 

219 self.assertEqual(visitInfo.observationReason, data.observationReason) 

220 self.assertEqual(visitInfo.object, data.object) 

221 self.assertEqual(visitInfo.hasSimulatedContent, data.hasSimulatedContent) 

222 

223 def testValueConstructor_data1(self): 

224 self._testValueConstructor(self.data1, self.localEra1, self.hourAngle1) 

225 self._testProperties(self.data1, self.localEra1, self.hourAngle1) 

226 

227 def testValueConstructor_data2(self): 

228 self._testValueConstructor(self.data2, self.localEra2, self.hourAngle2) 

229 self._testProperties(self.data2, self.localEra2, self.hourAngle2) 

230 

231 def testTablePersistence(self): 

232 """Test that VisitInfo can be round-tripped with current code. 

233 """ 

234 for item in (self.data1, self.data2): 

235 tablePath = os.path.join( 

236 self.testDir, "testVisitInfo_testTablePersistence.fits") 

237 v1 = afwImage.VisitInfo(*item) 

238 v1.writeFits(tablePath) 

239 v2 = afwImage.VisitInfo.readFits(tablePath) 

240 self.assertEqual(v1, v2) 

241 os.unlink(tablePath) 

242 

243 def _testFitsRead(self, data, filePath, version): 

244 """Test that old VersionInfo files are read correctly. 

245 

246 Parameters 

247 ---------- 

248 data : `VisitInfoData` 

249 The values expected to be stored in the file, or a 

250 superset thereof. 

251 filePath : `str` 

252 The file to test. 

253 version : `int` 

254 The VersionInfo persistence format used in ``filePath``. 

255 """ 

256 visitInfo = afwImage.VisitInfo.readFits(filePath) 

257 

258 if version >= 0: 

259 with self.assertWarns(FutureWarning): 

260 self.assertEqual(visitInfo.getExposureId(), data.exposureId) 

261 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime) 

262 self.assertEqual(visitInfo.getDarkTime(), data.darkTime) 

263 self.assertEqual(visitInfo.getDate(), data.date) 

264 self.assertEqual(visitInfo.getUt1(), data.ut1) 

265 self.assertEqual(visitInfo.getEra(), data.era) 

266 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec) 

267 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt) 

268 self.assertEqual(visitInfo.getBoresightAirmass(), 

269 data.boresightAirmass) 

270 self.assertEqual(visitInfo.getBoresightRotAngle(), 

271 data.boresightRotAngle) 

272 self.assertEqual(visitInfo.getRotType(), data.rotType) 

273 self.assertEqual(visitInfo.getObservatory(), data.observatory) 

274 self.assertEqual(visitInfo.getWeather(), data.weather) 

275 if version >= 1: 

276 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel) 

277 else: 

278 self.assertEqual(visitInfo.getInstrumentLabel(), "") 

279 if version >= 2: 

280 self.assertEqual(visitInfo.getId(), data.id) 

281 else: 

282 self.assertEqual(visitInfo.getId(), 0) 

283 if version >= 3: 

284 self.assertEqual(visitInfo.getFocusZ(), data.focusZ) 

285 else: 

286 self.assertTrue(math.isnan(visitInfo.getFocusZ())) 

287 if version >= 4: 

288 self.assertEqual(visitInfo.getObservationType(), data.observationType) 

289 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram) 

290 self.assertEqual(visitInfo.getObservationReason(), data.observationReason) 

291 self.assertEqual(visitInfo.getObject(), data.object) 

292 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent) 

293 else: 

294 self.assertEqual(visitInfo.getObservationType(), "") 

295 self.assertEqual(visitInfo.getScienceProgram(), "") 

296 self.assertEqual(visitInfo.getObservationReason(), "") 

297 self.assertEqual(visitInfo.getObject(), "") 

298 self.assertEqual(visitInfo.getHasSimulatedContent(), False) 

299 

300 def testPersistenceVersions(self): 

301 """Test that older versions are handled appropriately. 

302 """ 

303 dataDir = os.path.join(os.path.dirname(__file__), "data") 

304 

305 # All files created by makeVisitInfo(self.data1).writeFits() 

306 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-noversion.fits"), 0) 

307 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-1.fits"), 1) 

308 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-2.fits"), 2) 

309 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-3.fits"), 3) 

310 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-4.fits"), 4) 

311 

312 def testSetVisitInfoMetadata(self): 

313 for item in (self.data1, self.data2): 

314 visitInfo = makeVisitInfo(item) 

315 metadata = PropertyList() 

316 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

317 self.assertEqual(metadata.nameCount(), 28) 

318 self.assertEqual(metadata.getScalar("EXPID"), item.exposureId) 

319 self.assertEqual(metadata.getScalar("EXPTIME"), item.exposureTime) 

320 self.assertEqual(metadata.getScalar("DARKTIME"), item.darkTime) 

321 self.assertEqual(metadata.getScalar("DATE-AVG"), 

322 item.date.toString(DateTime.TAI)) 

323 self.assertEqual(metadata.getScalar("TIMESYS"), "TAI") 

324 self.assertEqual(metadata.getScalar("MJD-AVG-UT1"), item.ut1) 

325 self.assertEqual(metadata.getScalar("AVG-ERA"), item.era.asDegrees()) 

326 self.assertEqual(metadata.getScalar("BORE-RA"), 

327 item.boresightRaDec[0].asDegrees()) 

328 self.assertEqual(metadata.getScalar("BORE-DEC"), 

329 item.boresightRaDec[1].asDegrees()) 

330 self.assertEqual(metadata.getScalar("BORE-AZ"), 

331 item.boresightAzAlt[0].asDegrees()) 

332 self.assertEqual(metadata.getScalar("BORE-ALT"), 

333 item.boresightAzAlt[1].asDegrees()) 

334 self.assertEqual(metadata.getScalar("BORE-AIRMASS"), 

335 item.boresightAirmass) 

336 self.assertEqual(metadata.getScalar("BORE-ROTANG"), 

337 item.boresightRotAngle.asDegrees()) 

338 self.assertEqual(metadata.getScalar("ROTTYPE"), 

339 RotTypeEnumNameDict[item.rotType]) 

340 self.assertEqual(metadata.getScalar("OBS-LONG"), 

341 item.observatory.getLongitude().asDegrees()) 

342 self.assertEqual(metadata.getScalar("OBS-LAT"), 

343 item.observatory.getLatitude().asDegrees()) 

344 self.assertEqual(metadata.getScalar("OBS-ELEV"), 

345 item.observatory.getElevation()) 

346 self.assertEqual(metadata.getScalar("AIRTEMP"), 

347 item.weather.getAirTemperature()) 

348 self.assertEqual(metadata.getScalar("AIRPRESS"), 

349 item.weather.getAirPressure()) 

350 self.assertEqual(metadata.getScalar("HUMIDITY"), 

351 item.weather.getHumidity()) 

352 self.assertEqual(metadata.getScalar("INSTRUMENT"), 

353 item.instrumentLabel) 

354 self.assertEqual(metadata.getScalar("IDNUM"), 

355 item.id) 

356 self.assertEqual(metadata.getScalar("FOCUSZ"), 

357 item.focusZ) 

358 self.assertEqual(metadata.getScalar("OBSTYPE"), 

359 item.observationType) 

360 self.assertEqual(metadata.getScalar("PROGRAM"), 

361 item.scienceProgram) 

362 self.assertEqual(metadata.getScalar("REASON"), 

363 item.observationReason) 

364 self.assertEqual(metadata.getScalar("OBJECT"), 

365 item.object) 

366 self.assertEqual(metadata.getScalar("HAS-SIMULATED-CONTENT"), 

367 item.hasSimulatedContent) 

368 

369 def testSetVisitInfoMetadataMissingValues(self): 

370 """If a value is unknown then it should not be written to the metadata""" 

371 # Only rot type and hasSimulatedContent are "known" when default- 

372 # constructed, by virtue of having no "null" state. 

373 visitInfo = afwImage.VisitInfo() 

374 metadata = PropertyList() 

375 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

376 self.assertEqual(metadata.getScalar("ROTTYPE"), 

377 RotTypeEnumNameDict[afwImage.RotType.UNKNOWN]) 

378 self.assertEqual(metadata.getScalar("HAS-SIMULATED-CONTENT"), False) 

379 self.assertEqual(metadata.nameCount(), 2) 

380 

381 def testStripVisitInfoKeywords(self): 

382 for argList in (self.data1, self.data2): 

383 visitInfo = afwImage.VisitInfo(*argList) 

384 metadata = PropertyList() 

385 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

386 # add an extra keyword that will not be stripped 

387 metadata.set("EXTRA", 5) 

388 self.assertEqual(metadata.nameCount(), 29) 

389 afwImage.stripVisitInfoKeywords(metadata) 

390 self.assertEqual(metadata.nameCount(), 1) 

391 

392 def _testIsEmpty(self, visitInfo): 

393 """Test that visitInfo is all NaN, 0, or empty string, as appropriate. 

394 """ 

395 with self.assertWarns(FutureWarning): 

396 self.assertEqual(visitInfo.getExposureId(), 0) 

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

398 self.assertTrue(math.isnan(visitInfo.getDarkTime())) 

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

400 self.assertTrue(math.isnan(visitInfo.getUt1())) 

401 self.assertTrue(math.isnan(visitInfo.getEra().asDegrees())) 

402 for i in range(2): 

403 self.assertTrue(math.isnan( 

404 visitInfo.getBoresightRaDec()[i].asDegrees())) 

405 self.assertTrue(math.isnan( 

406 visitInfo.getBoresightAzAlt()[i].asDegrees())) 

407 self.assertTrue(math.isnan(visitInfo.getBoresightAirmass())) 

408 self.assertTrue(math.isnan( 

409 visitInfo.getBoresightRotAngle().asDegrees())) 

410 self.assertEqual(visitInfo.getRotType(), afwImage.RotType.UNKNOWN) 

411 self.assertTrue(math.isnan( 

412 visitInfo.getObservatory().getLongitude().asDegrees())) 

413 self.assertTrue(math.isnan( 

414 visitInfo.getObservatory().getLatitude().asDegrees())) 

415 self.assertTrue(math.isnan(visitInfo.getObservatory().getElevation())) 

416 self.assertTrue(math.isnan(visitInfo.getWeather().getAirTemperature())) 

417 self.assertTrue(math.isnan(visitInfo.getWeather().getAirPressure())) 

418 self.assertTrue(math.isnan(visitInfo.getWeather().getHumidity())) 

419 self.assertTrue(math.isnan(visitInfo.getBoresightHourAngle())) 

420 self.assertEqual(visitInfo.getInstrumentLabel(), "") 

421 self.assertEqual(visitInfo.getId(), 0) 

422 self.assertTrue(math.isnan(visitInfo.getFocusZ())) 

423 self.assertEqual(visitInfo.getObservationType(), "") 

424 self.assertEqual(visitInfo.getScienceProgram(), "") 

425 self.assertEqual(visitInfo.getObservationReason(), "") 

426 self.assertEqual(visitInfo.getObject(), "") 

427 self.assertEqual(visitInfo.getHasSimulatedContent(), False) 

428 

429 def testEquals(self): 

430 """Test that identical VisitInfo objects compare equal, even if some fields are NaN. 

431 """ 

432 # objects with "equal state" should be equal 

433 self.assertEqual(makeVisitInfo(self.data1), makeVisitInfo(self.data1)) 

434 self.assertEqual(makeVisitInfo(self.data2), makeVisitInfo(self.data2)) 

435 self.assertNotEqual(makeVisitInfo(self.data1), makeVisitInfo(self.data2)) 

436 self.assertEqual(afwImage.VisitInfo(), afwImage.VisitInfo()) 

437 

438 # equality must be reflexive 

439 info = makeVisitInfo(self.data1) 

440 self.assertEqual(info, info) 

441 info = makeVisitInfo(self.data2) 

442 self.assertEqual(info, info) 

443 info = afwImage.VisitInfo() 

444 self.assertEqual(info, info) 

445 

446 # commutativity and transitivity difficult to test with this setup 

447 

448 def testMetadataConstructor(self): 

449 """Test the metadata constructor 

450 

451 This constructor allows missing values 

452 """ 

453 data = self.data1 

454 

455 metadata = propertySetFromDict({}) 

456 visitInfo = afwImage.VisitInfo(metadata) 

457 self._testIsEmpty(visitInfo) 

458 

459 metadata = propertySetFromDict({"EXPID": data.exposureId}) 

460 visitInfo = afwImage.VisitInfo(metadata) 

461 with self.assertWarns(FutureWarning): 

462 self.assertEqual(visitInfo.getExposureId(), data.exposureId) 

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

464 

465 metadata = propertySetFromDict({"EXPTIME": data.exposureTime}) 

466 visitInfo = afwImage.VisitInfo(metadata) 

467 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime) 

468 

469 metadata = propertySetFromDict({"DARKTIME": data.darkTime}) 

470 visitInfo = afwImage.VisitInfo(metadata) 

471 self.assertEqual(visitInfo.getDarkTime(), data.darkTime) 

472 

473 metadata = propertySetFromDict( 

474 {"DATE-AVG": data.date.toString(DateTime.TAI), "TIMESYS": "TAI"}) 

475 visitInfo = afwImage.VisitInfo(metadata) 

476 self.assertEqual(visitInfo.getDate(), data.date) 

477 

478 # TIME-MID in UTC is an acceptable alternative to DATE-AVG 

479 metadata = propertySetFromDict( 

480 {"TIME-MID": data.date.toString(DateTime.UTC)}) 

481 visitInfo = afwImage.VisitInfo(metadata) 

482 self.assertEqual(visitInfo.getDate(), data.date) 

483 

484 # TIME-MID must be in UTC and TIMESYS is ignored 

485 metadata = propertySetFromDict({ 

486 "TIME-MID": data.date.toString(DateTime.TAI) + "Z", 

487 "TIMESYS": "TAI", 

488 }) 

489 visitInfo = afwImage.VisitInfo(metadata) 

490 self.assertNotEqual(visitInfo.getDate(), data.date) 

491 

492 # if both DATE-AVG and TIME-MID provided then use DATE-AVG 

493 # use the wrong time system for TIME-MID so if it is used, an error 

494 # will result 

495 metadata = propertySetFromDict({ 

496 "DATE-AVG": data.date.toString(DateTime.TAI), 

497 "TIMESYS": "TAI", 

498 "TIME-MID": data.date.toString(DateTime.TAI) + "Z", 

499 }) 

500 visitInfo = afwImage.VisitInfo(metadata) 

501 self.assertEqual(visitInfo.getDate(), data.date) 

502 

503 metadata = propertySetFromDict({"MJD-AVG-UT1": data.ut1}) 

504 visitInfo = afwImage.VisitInfo(metadata) 

505 self.assertEqual(visitInfo.getUt1(), data.ut1) 

506 

507 metadata = propertySetFromDict({"AVG-ERA": data.era.asDegrees()}) 

508 visitInfo = afwImage.VisitInfo(metadata) 

509 self.assertEqual(visitInfo.getEra(), data.era) 

510 

511 for i, key in enumerate(("BORE-RA", "BORE-DEC")): 

512 metadata = propertySetFromDict( 

513 {key: data.boresightRaDec[i].asDegrees()}) 

514 visitInfo = afwImage.VisitInfo(metadata) 

515 self.assertEqual(visitInfo.getBoresightRaDec() 

516 [i], data.boresightRaDec[i]) 

517 

518 for i, key in enumerate(("BORE-AZ", "BORE-ALT")): 

519 metadata = propertySetFromDict( 

520 {key: data.boresightAzAlt[i].asDegrees()}) 

521 visitInfo = afwImage.VisitInfo(metadata) 

522 self.assertEqual(visitInfo.getBoresightAzAlt() 

523 [i], data.boresightAzAlt[i]) 

524 

525 metadata = propertySetFromDict({"BORE-AIRMASS": data.boresightAirmass}) 

526 visitInfo = afwImage.VisitInfo(metadata) 

527 self.assertEqual(visitInfo.getBoresightAirmass(), 

528 data.boresightAirmass) 

529 

530 metadata = propertySetFromDict( 

531 {"BORE-ROTANG": data.boresightRotAngle.asDegrees()}) 

532 visitInfo = afwImage.VisitInfo(metadata) 

533 self.assertEqual(visitInfo.getBoresightRotAngle(), 

534 data.boresightRotAngle) 

535 

536 metadata = propertySetFromDict( 

537 {"ROTTYPE": RotTypeEnumNameDict[data.rotType]}) 

538 visitInfo = afwImage.VisitInfo(metadata) 

539 self.assertEqual(visitInfo.getRotType(), data.rotType) 

540 

541 metadata = propertySetFromDict( 

542 {"OBS-LONG": data.observatory.getLongitude().asDegrees()}) 

543 visitInfo = afwImage.VisitInfo(metadata) 

544 self.assertEqual(visitInfo.getObservatory().getLongitude(), 

545 data.observatory.getLongitude()) 

546 

547 metadata = propertySetFromDict( 

548 {"OBS-LAT": data.observatory.getLatitude().asDegrees()}) 

549 visitInfo = afwImage.VisitInfo(metadata) 

550 self.assertEqual(visitInfo.getObservatory().getLatitude(), 

551 data.observatory.getLatitude()) 

552 

553 metadata = propertySetFromDict( 

554 {"OBS-ELEV": data.observatory.getElevation()}) 

555 visitInfo = afwImage.VisitInfo(metadata) 

556 self.assertEqual(visitInfo.getObservatory().getElevation(), 

557 data.observatory.getElevation()) 

558 

559 metadata = propertySetFromDict( 

560 {"AIRTEMP": data.weather.getAirTemperature()}) 

561 visitInfo = afwImage.VisitInfo(metadata) 

562 self.assertEqual(visitInfo.getWeather().getAirTemperature(), 

563 data.weather.getAirTemperature()) 

564 

565 metadata = propertySetFromDict( 

566 {"AIRPRESS": data.weather.getAirPressure()}) 

567 visitInfo = afwImage.VisitInfo(metadata) 

568 self.assertEqual(visitInfo.getWeather().getAirPressure(), 

569 data.weather.getAirPressure()) 

570 

571 metadata = propertySetFromDict( 

572 {"HUMIDITY": data.weather.getHumidity()}) 

573 visitInfo = afwImage.VisitInfo(metadata) 

574 self.assertEqual(visitInfo.getWeather().getHumidity(), 

575 data.weather.getHumidity()) 

576 

577 metadata = propertySetFromDict({"INSTRUMENT": data.instrumentLabel}) 

578 visitInfo = afwImage.VisitInfo(metadata) 

579 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel) 

580 

581 metadata = propertySetFromDict({"IDNUM": data.id}) 

582 visitInfo = afwImage.VisitInfo(metadata) 

583 self.assertEqual(visitInfo.getId(), data.id) 

584 

585 metadata = propertySetFromDict({"FOCUSZ": data.focusZ}) 

586 visitInfo = afwImage.VisitInfo(metadata) 

587 self.assertEqual(visitInfo.getFocusZ(), data.focusZ) 

588 

589 metadata = propertySetFromDict({"OBSTYPE": data.observationType}) 

590 visitInfo = afwImage.VisitInfo(metadata) 

591 self.assertEqual(visitInfo.getObservationType(), data.observationType) 

592 

593 metadata = propertySetFromDict({"PROGRAM": data.scienceProgram}) 

594 visitInfo = afwImage.VisitInfo(metadata) 

595 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram) 

596 

597 metadata = propertySetFromDict({"REASON": data.observationReason}) 

598 visitInfo = afwImage.VisitInfo(metadata) 

599 self.assertEqual(visitInfo.getObservationReason(), data.observationReason) 

600 

601 metadata = propertySetFromDict({"OBJECT": data.object}) 

602 visitInfo = afwImage.VisitInfo(metadata) 

603 self.assertEqual(visitInfo.getObject(), data.object) 

604 

605 metadata = propertySetFromDict({"HAS-SIMULATED-CONTENT": data.hasSimulatedContent}) 

606 visitInfo = afwImage.VisitInfo(metadata) 

607 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent) 

608 

609 def testMetadataConstructorUndefined(self): 

610 """Test that we can create VisitInfo using None in metadata.""" 

611 

612 metadata = propertySetFromDict({ 

613 # These are examples of generic reader code. 

614 "PROGRAM": None, # A string should convert to "". 

615 "DARKTIME": None, # A missing float should convert to NaN. 

616 # These headers have special logic in the reader. 

617 "EXPTIME": None, 

618 "IDNUM": None, 

619 "DATE-AVG": None, 

620 "ROTTYPE": None, 

621 "HAS-SIMULATED-CONTENT": None, 

622 }) 

623 visitInfo = afwImage.VisitInfo(metadata) 

624 self.assertEqual(visitInfo.getScienceProgram(), "") 

625 self.assertTrue(math.isnan(visitInfo.getDarkTime())) 

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

627 self.assertEqual(visitInfo.getId(), 0) 

628 self.assertFalse(visitInfo.getDate().isValid()) 

629 

630 def testConstructorKeywordArguments(self): 

631 """Test VisitInfo with named arguments""" 

632 data = self.data1 

633 

634 visitInfo = afwImage.VisitInfo() 

635 self._testIsEmpty(visitInfo) 

636 

637 visitInfo = afwImage.VisitInfo(exposureId=data.exposureId) 

638 with self.assertWarns(FutureWarning): 

639 self.assertEqual(visitInfo.getExposureId(), data.exposureId) 

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

641 

642 visitInfo = afwImage.VisitInfo(exposureTime=data.exposureTime) 

643 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime) 

644 

645 visitInfo = afwImage.VisitInfo(darkTime=data.darkTime) 

646 self.assertEqual(visitInfo.getDarkTime(), data.darkTime) 

647 

648 visitInfo = afwImage.VisitInfo(date=data.date) 

649 self.assertEqual(visitInfo.getDate(), data.date) 

650 

651 visitInfo = afwImage.VisitInfo(ut1=data.ut1) 

652 self.assertEqual(visitInfo.getUt1(), data.ut1) 

653 

654 visitInfo = afwImage.VisitInfo(era=data.era) 

655 self.assertEqual(visitInfo.getEra(), data.era) 

656 

657 visitInfo = afwImage.VisitInfo(boresightRaDec=data.boresightRaDec) 

658 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec) 

659 

660 visitInfo = afwImage.VisitInfo(boresightAzAlt=data.boresightAzAlt) 

661 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt) 

662 

663 visitInfo = afwImage.VisitInfo(boresightAirmass=data.boresightAirmass) 

664 self.assertEqual(visitInfo.getBoresightAirmass(), 

665 data.boresightAirmass) 

666 

667 visitInfo = afwImage.VisitInfo( 

668 boresightRotAngle=data.boresightRotAngle) 

669 self.assertEqual(visitInfo.getBoresightRotAngle(), 

670 data.boresightRotAngle) 

671 

672 visitInfo = afwImage.VisitInfo(rotType=data.rotType) 

673 self.assertEqual(visitInfo.getRotType(), data.rotType) 

674 

675 visitInfo = afwImage.VisitInfo(observatory=data.observatory) 

676 self.assertEqual(visitInfo.getObservatory(), data.observatory) 

677 

678 visitInfo = afwImage.VisitInfo(weather=data.weather) 

679 self.assertEqual(visitInfo.getWeather(), data.weather) 

680 

681 visitInfo = afwImage.VisitInfo(instrumentLabel=data.instrumentLabel) 

682 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel) 

683 

684 visitInfo = afwImage.VisitInfo(id=data.id) 

685 self.assertEqual(visitInfo.getId(), data.id) 

686 

687 visitInfo = afwImage.VisitInfo(focusZ=data.focusZ) 

688 self.assertEqual(visitInfo.getFocusZ(), data.focusZ) 

689 

690 visitInfo = afwImage.VisitInfo(observationType=data.observationType) 

691 self.assertEqual(visitInfo.getObservationType(), data.observationType) 

692 

693 visitInfo = afwImage.VisitInfo(scienceProgram=data.scienceProgram) 

694 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram) 

695 

696 visitInfo = afwImage.VisitInfo(observationReason=data.observationReason) 

697 self.assertEqual(visitInfo.getObservationReason(), data.observationReason) 

698 

699 visitInfo = afwImage.VisitInfo(object=data.object) 

700 self.assertEqual(visitInfo.getObject(), data.object) 

701 

702 visitInfo = afwImage.VisitInfo(hasSimulatedContent=data.hasSimulatedContent) 

703 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent) 

704 

705 def testGoodRotTypes(self): 

706 """Test round trip of all valid rot types""" 

707 for rotType in RotTypeEnumNameDict: 

708 metadata = propertySetFromDict( 

709 {"ROTTYPE": RotTypeEnumNameDict[rotType]}) 

710 visitInfo = afwImage.VisitInfo(metadata) 

711 self.assertEqual(visitInfo.getRotType(), rotType) 

712 

713 def testBadRotTypes(self): 

714 """Test that invalid rot type names cannot be used to construct a VisitInfo""" 

715 for badRotTypeName in ( 

716 "unknown", # must be all uppercase 

717 "sky", # must be all uppercase 

718 "Sky", # must be all uppercase 

719 "SKY1", # extra chars 

720 "HORIZONTAL", # extra chars 

721 ): 

722 metadata = propertySetFromDict({"ROTTYPE": badRotTypeName}) 

723 with self.assertRaises(lsst.pex.exceptions.RuntimeError): 

724 afwImage.VisitInfo(metadata) 

725 

726 def test_str(self): 

727 """Check that we get something reasonable for str()""" 

728 visitInfo = makeVisitInfo(self.data1) 

729 string = str(visitInfo) 

730 self.assertEqual(string, 

731 "VisitInfo(exposureId=10313423, exposureTime=10.01, darkTime=11.02, " 

732 "date=2037-09-20T02:24:00.000000000, UT1=12345.1, ERA=0.787143 rad, " 

733 "boresightRaDec=(23.1000000000, +73.2000000000), " 

734 "boresightAzAlt=(134.5000000000, +33.3000000000), boresightAirmass=1.73, " 

735 "boresightRotAngle=1.27758 rad, rotType=1, observatory=22.2N, 11.1E 0.333, " 

736 "weather=Weather(1.1, 2.2, 34.5), instrumentLabel='TestCameraOne', " 

737 "id=987654, focusZ=1.5, observationType='flat', scienceProgram='test program', " 

738 "observationReason='test reason', object='test object', hasSimulatedContent=false)") 

739 

740 def testParallacticAngle(self): 

741 """Check that we get the same precomputed values for parallactic angle.""" 

742 parallacticAngle = [141.39684140703142*degrees, 76.99982166973487*degrees] 

743 for item, parAngle in zip((self.data1, self.data2), parallacticAngle): 

744 visitInfo = afwImage.VisitInfo(era=item.era, 

745 boresightRaDec=item.boresightRaDec, 

746 observatory=item.observatory, 

747 ) 

748 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), parAngle) 

749 

750 def testParallacticAngleNorthMeridian(self): 

751 """An observation on the Meridian that is North of zenith has a parallactic angle of pi radians.""" 

752 meridianBoresightRA = self.data1.era + self.data1.observatory.getLongitude() 

753 northBoresightDec = self.data1.observatory.getLatitude() + 10.*degrees 

754 visitInfo = afwImage.VisitInfo(era=self.data1.era, 

755 boresightRaDec=SpherePoint(meridianBoresightRA, 

756 northBoresightDec), 

757 observatory=self.data1.observatory, 

758 ) 

759 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), Angle(np.pi)) 

760 

761 def testParallacticAngleSouthMeridian(self): 

762 """An observation on the Meridian that is South of zenith has a parallactic angle of zero.""" 

763 meridianBoresightRA = self.data1.era + self.data1.observatory.getLongitude() 

764 southBoresightDec = self.data1.observatory.getLatitude() - 10.*degrees 

765 visitInfo = afwImage.VisitInfo(era=self.data1.era, 

766 boresightRaDec=SpherePoint(meridianBoresightRA, 

767 southBoresightDec), 

768 observatory=self.data1.observatory, 

769 ) 

770 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), Angle(0.)) 

771 

772 

773def setup_module(module): 

774 lsst.utils.tests.init() 

775 

776 

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

778 pass 

779 

780 

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

782 lsst.utils.tests.init() 

783 unittest.main()