Coverage for tests/test_visitInfo.py: 9%

420 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-01 03:31 -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.exposureTime, 

54 data.darkTime, 

55 data.date, 

56 data.ut1, 

57 data.era, 

58 data.boresightRaDec, 

59 data.boresightAzAlt, 

60 data.boresightAirmass, 

61 data.boresightRotAngle, 

62 data.rotType, 

63 data.observatory, 

64 data.weather, 

65 data.instrumentLabel, 

66 data.id, 

67 data.focusZ, 

68 data.observationType, 

69 data.scienceProgram, 

70 data.observationReason, 

71 data.object, 

72 data.hasSimulatedContent, 

73 ) 

74 

75 

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

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

78 

79 def setUp(self): 

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

81 

82 def computeLstHA(data): 

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

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

85 hourAngle = localEra - data.boresightRaDec[0] 

86 return localEra, hourAngle 

87 

88 fields = ['exposureTime', 

89 'darkTime', 

90 'date', 

91 'ut1', 

92 'era', 

93 'boresightRaDec', 

94 'boresightAzAlt', 

95 'boresightAirmass', 

96 'boresightRotAngle', 

97 'rotType', 

98 'observatory', 

99 'weather', 

100 'instrumentLabel', 

101 'id', 

102 'focusZ', 

103 'observationType', 

104 "scienceProgram", 

105 "observationReason", 

106 "object", 

107 "hasSimulatedContent", 

108 ] 

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

110 data1 = VisitInfoData(exposureTime=10.01, 

111 darkTime=11.02, 

112 date=DateTime( 

113 65321.1, DateTime.MJD, DateTime.TAI), 

114 ut1=12345.1, 

115 era=45.1*degrees, 

116 boresightRaDec=SpherePoint( 

117 23.1*degrees, 73.2*degrees), 

118 boresightAzAlt=SpherePoint( 

119 134.5*degrees, 33.3*degrees), 

120 boresightAirmass=1.73, 

121 boresightRotAngle=73.2*degrees, 

122 rotType=afwImage.RotType.SKY, 

123 observatory=Observatory( 

124 11.1*degrees, 22.2*degrees, 0.333), 

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

126 instrumentLabel="TestCameraOne", 

127 id=987654, 

128 focusZ=1.5, 

129 observationType="flat", 

130 scienceProgram="test program", 

131 observationReason="test reason", 

132 object="test object", 

133 hasSimulatedContent=False, 

134 ) 

135 self.data1 = data1 

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

137 data2 = VisitInfoData(exposureTime=15.5, 

138 darkTime=17.8, 

139 date=DateTime( 

140 55321.2, DateTime.MJD, DateTime.TAI), 

141 ut1=312345.1, 

142 era=25.1*degrees, 

143 boresightRaDec=SpherePoint( 

144 2.1*degrees, 33.2*degrees), 

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

146 boresightAirmass=2.05, 

147 boresightRotAngle=-53.2*degrees, 

148 rotType=afwImage.RotType.HORIZON, 

149 observatory=Observatory( 

150 22.2*degrees, 33.3*degrees, 0.444), 

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

152 instrumentLabel="TestCameraTwo", 

153 id=123456, 

154 focusZ=-0.7, 

155 observationType="science", 

156 scienceProgram="test program 2", 

157 observationReason="test reason 2", 

158 object="test object 2", 

159 hasSimulatedContent=True, 

160 ) 

161 self.data2 = data2 

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

163 

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

165 visitInfo = makeVisitInfo(data) 

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

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

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

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

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

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

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

173 self.assertEqual(visitInfo.getBoresightAirmass(), 

174 data.boresightAirmass) 

175 self.assertEqual(visitInfo.getBoresightRotAngle(), 

176 data.boresightRotAngle) 

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

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

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

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

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

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

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

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

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

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

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

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

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

190 

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

192 """Test property attribute accessors.""" 

193 visitInfo = makeVisitInfo(data) 

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

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

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

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

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

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

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

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

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

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

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

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

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

207 self.assertEqual(visitInfo.localEra, localEra) 

208 self.assertEqual(visitInfo.boresightHourAngle, hourAngle) 

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

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

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

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

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

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

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

216 

217 def testValueConstructor_data1(self): 

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

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

220 

221 def testValueConstructor_data2(self): 

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

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

224 

225 def testCopyWith(self): 

226 visitInfo1 = makeVisitInfo(self.data1) 

227 visitInfo2 = makeVisitInfo(self.data2) 

228 

229 updateFields1 = [ 

230 "exposureTime", 

231 "darkTime", 

232 "date", 

233 "ut1", 

234 "era", 

235 "boresightRaDec", 

236 "boresightAzAlt", 

237 "boresightAirmass", 

238 "boresightRotAngle", 

239 ] 

240 

241 updateFields2 = [ 

242 "rotType", 

243 "observatory", 

244 "weather", 

245 "instrumentLabel", 

246 "id", 

247 "focusZ", 

248 "observationType", 

249 "scienceProgram", 

250 "observationReason", 

251 "object", 

252 "hasSimulatedContent", 

253 ] 

254 

255 kwargs1 = {k: getattr(visitInfo2, k) for k in updateFields1} 

256 kwargs2 = {k: getattr(visitInfo2, k) for k in updateFields2} 

257 

258 newVisit1 = visitInfo1.copyWith(**kwargs1) 

259 newVisit2 = visitInfo1.copyWith(**kwargs2) 

260 

261 for field in updateFields1: 

262 self.assertEqual(getattr(newVisit1, field), getattr(visitInfo2, field)) 

263 self.assertEqual(getattr(newVisit2, field), getattr(visitInfo1, field)) 

264 

265 for field in updateFields2: 

266 self.assertEqual(getattr(newVisit1, field), getattr(visitInfo1, field)) 

267 self.assertEqual(getattr(newVisit2, field), getattr(visitInfo2, field)) 

268 

269 def testTablePersistence(self): 

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

271 """ 

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

273 tablePath = os.path.join( 

274 self.testDir, "testVisitInfo_testTablePersistence.fits") 

275 v1 = afwImage.VisitInfo(*item) 

276 v1.writeFits(tablePath) 

277 v2 = afwImage.VisitInfo.readFits(tablePath) 

278 self.assertEqual(v1, v2) 

279 os.unlink(tablePath) 

280 

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

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

283 

284 Parameters 

285 ---------- 

286 data : `VisitInfoData` 

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

288 superset thereof. 

289 filePath : `str` 

290 The file to test. 

291 version : `int` 

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

293 """ 

294 visitInfo = afwImage.VisitInfo.readFits(filePath) 

295 

296 if version >= 0: 

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

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

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

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

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

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

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

304 self.assertEqual(visitInfo.getBoresightAirmass(), 

305 data.boresightAirmass) 

306 self.assertEqual(visitInfo.getBoresightRotAngle(), 

307 data.boresightRotAngle) 

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

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

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

311 if version >= 1: 

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

313 else: 

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

315 if version >= 2: 

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

317 else: 

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

319 if version >= 3: 

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

321 else: 

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

323 if version >= 4: 

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

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

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

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

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

329 else: 

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

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

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

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

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

335 # version == 5 removed the exposureId field 

336 

337 def testPersistenceVersions(self): 

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

339 """ 

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

341 

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

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

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

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

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

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

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

349 

350 # Check that reading a newer file raises a useful exception. 

351 with self.assertRaisesRegex(TypeError, 

352 r"Cannot read VisitInfo FITS version > [0-9]+, found version 999999"): 

353 afwImage.VisitInfo.readFits(os.path.join(dataDir, "visitInfo-version-999999.fits")) 

354 

355 def testSetVisitInfoMetadata(self): 

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

357 visitInfo = makeVisitInfo(item) 

358 metadata = PropertyList() 

359 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

360 self.assertEqual(metadata.nameCount(), 27) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

377 item.boresightAirmass) 

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

379 item.boresightRotAngle.asDegrees()) 

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

381 RotTypeEnumNameDict[item.rotType]) 

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

383 item.observatory.getLongitude().asDegrees()) 

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

385 item.observatory.getLatitude().asDegrees()) 

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

387 item.observatory.getElevation()) 

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

389 item.weather.getAirTemperature()) 

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

391 item.weather.getAirPressure()) 

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

393 item.weather.getHumidity()) 

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

395 item.instrumentLabel) 

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

397 item.id) 

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

399 item.focusZ) 

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

401 item.observationType) 

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

403 item.scienceProgram) 

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

405 item.observationReason) 

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

407 item.object) 

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

409 item.hasSimulatedContent) 

410 

411 def testSetVisitInfoMetadataMissingValues(self): 

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

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

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

415 visitInfo = afwImage.VisitInfo() 

416 metadata = PropertyList() 

417 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

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

419 RotTypeEnumNameDict[afwImage.RotType.UNKNOWN]) 

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

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

422 

423 def testStripVisitInfoKeywords(self): 

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

425 visitInfo = afwImage.VisitInfo(*argList) 

426 metadata = PropertyList() 

427 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

428 # add an extra keyword that will not be stripped 

429 metadata.set("EXTRA", 5) 

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

431 afwImage.stripVisitInfoKeywords(metadata) 

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

433 

434 def _testIsEmpty(self, visitInfo): 

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

436 """ 

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

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

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

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

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

442 for i in range(2): 

443 self.assertTrue(math.isnan( 

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

445 self.assertTrue(math.isnan( 

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

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

448 self.assertTrue(math.isnan( 

449 visitInfo.getBoresightRotAngle().asDegrees())) 

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

451 self.assertTrue(math.isnan( 

452 visitInfo.getObservatory().getLongitude().asDegrees())) 

453 self.assertTrue(math.isnan( 

454 visitInfo.getObservatory().getLatitude().asDegrees())) 

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

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

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

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

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

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

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

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

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

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

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

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

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

468 

469 def testEquals(self): 

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

471 """ 

472 # objects with "equal state" should be equal 

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

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

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

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

477 

478 # equality must be reflexive 

479 info = makeVisitInfo(self.data1) 

480 self.assertEqual(info, info) 

481 info = makeVisitInfo(self.data2) 

482 self.assertEqual(info, info) 

483 info = afwImage.VisitInfo() 

484 self.assertEqual(info, info) 

485 

486 # commutativity and transitivity difficult to test with this setup 

487 

488 def testMetadataConstructor(self): 

489 """Test the metadata constructor 

490 

491 This constructor allows missing values 

492 """ 

493 data = self.data1 

494 

495 metadata = propertySetFromDict({}) 

496 visitInfo = afwImage.VisitInfo(metadata) 

497 self._testIsEmpty(visitInfo) 

498 

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

500 visitInfo = afwImage.VisitInfo(metadata) 

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

502 

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

504 visitInfo = afwImage.VisitInfo(metadata) 

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

506 

507 metadata = propertySetFromDict( 

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

509 visitInfo = afwImage.VisitInfo(metadata) 

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

511 

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

513 metadata = propertySetFromDict( 

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

515 visitInfo = afwImage.VisitInfo(metadata) 

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

517 

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

519 metadata = propertySetFromDict({ 

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

521 "TIMESYS": "TAI", 

522 }) 

523 visitInfo = afwImage.VisitInfo(metadata) 

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

525 

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

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

528 # will result 

529 metadata = propertySetFromDict({ 

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

531 "TIMESYS": "TAI", 

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

533 }) 

534 visitInfo = afwImage.VisitInfo(metadata) 

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

536 

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

538 visitInfo = afwImage.VisitInfo(metadata) 

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

540 

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

542 visitInfo = afwImage.VisitInfo(metadata) 

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

544 

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

546 metadata = propertySetFromDict( 

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

548 visitInfo = afwImage.VisitInfo(metadata) 

549 self.assertEqual(visitInfo.getBoresightRaDec() 

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

551 

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

553 metadata = propertySetFromDict( 

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

555 visitInfo = afwImage.VisitInfo(metadata) 

556 self.assertEqual(visitInfo.getBoresightAzAlt() 

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

558 

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

560 visitInfo = afwImage.VisitInfo(metadata) 

561 self.assertEqual(visitInfo.getBoresightAirmass(), 

562 data.boresightAirmass) 

563 

564 metadata = propertySetFromDict( 

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

566 visitInfo = afwImage.VisitInfo(metadata) 

567 self.assertEqual(visitInfo.getBoresightRotAngle(), 

568 data.boresightRotAngle) 

569 

570 metadata = propertySetFromDict( 

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

572 visitInfo = afwImage.VisitInfo(metadata) 

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

574 

575 metadata = propertySetFromDict( 

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

577 visitInfo = afwImage.VisitInfo(metadata) 

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

579 data.observatory.getLongitude()) 

580 

581 metadata = propertySetFromDict( 

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

583 visitInfo = afwImage.VisitInfo(metadata) 

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

585 data.observatory.getLatitude()) 

586 

587 metadata = propertySetFromDict( 

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

589 visitInfo = afwImage.VisitInfo(metadata) 

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

591 data.observatory.getElevation()) 

592 

593 metadata = propertySetFromDict( 

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

595 visitInfo = afwImage.VisitInfo(metadata) 

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

597 data.weather.getAirTemperature()) 

598 

599 metadata = propertySetFromDict( 

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

601 visitInfo = afwImage.VisitInfo(metadata) 

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

603 data.weather.getAirPressure()) 

604 

605 metadata = propertySetFromDict( 

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

607 visitInfo = afwImage.VisitInfo(metadata) 

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

609 data.weather.getHumidity()) 

610 

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

612 visitInfo = afwImage.VisitInfo(metadata) 

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

614 

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

616 visitInfo = afwImage.VisitInfo(metadata) 

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

618 

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

620 visitInfo = afwImage.VisitInfo(metadata) 

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

622 

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

624 visitInfo = afwImage.VisitInfo(metadata) 

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

626 

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

628 visitInfo = afwImage.VisitInfo(metadata) 

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

630 

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

632 visitInfo = afwImage.VisitInfo(metadata) 

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

634 

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

636 visitInfo = afwImage.VisitInfo(metadata) 

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

638 

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

640 visitInfo = afwImage.VisitInfo(metadata) 

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

642 

643 def testMetadataConstructorUndefined(self): 

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

645 

646 metadata = propertySetFromDict({ 

647 # These are examples of generic reader code. 

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

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

650 # These headers have special logic in the reader. 

651 "EXPTIME": None, 

652 "IDNUM": None, 

653 "DATE-AVG": None, 

654 "ROTTYPE": None, 

655 "HAS-SIMULATED-CONTENT": None, 

656 }) 

657 visitInfo = afwImage.VisitInfo(metadata) 

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

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

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

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

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

663 

664 def testConstructorKeywordArguments(self): 

665 """Test VisitInfo with named arguments""" 

666 data = self.data1 

667 

668 visitInfo = afwImage.VisitInfo() 

669 self._testIsEmpty(visitInfo) 

670 

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

672 

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

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

675 

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

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

678 

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

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

681 

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

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

684 

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

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

687 

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

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

690 

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

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

693 

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

695 self.assertEqual(visitInfo.getBoresightAirmass(), 

696 data.boresightAirmass) 

697 

698 visitInfo = afwImage.VisitInfo( 

699 boresightRotAngle=data.boresightRotAngle) 

700 self.assertEqual(visitInfo.getBoresightRotAngle(), 

701 data.boresightRotAngle) 

702 

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

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

705 

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

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

708 

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

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

711 

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

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

714 

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

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

717 

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

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

720 

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

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

723 

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

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

726 

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

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

729 

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

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

732 

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

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

735 

736 def testGoodRotTypes(self): 

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

738 for rotType in RotTypeEnumNameDict: 

739 metadata = propertySetFromDict( 

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

741 visitInfo = afwImage.VisitInfo(metadata) 

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

743 

744 def testBadRotTypes(self): 

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

746 for badRotTypeName in ( 

747 "unknown", # must be all uppercase 

748 "sky", # must be all uppercase 

749 "Sky", # must be all uppercase 

750 "SKY1", # extra chars 

751 "HORIZONTAL", # extra chars 

752 ): 

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

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

755 afwImage.VisitInfo(metadata) 

756 

757 def test_str(self): 

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

759 visitInfo = makeVisitInfo(self.data1) 

760 string = str(visitInfo) 

761 self.assertEqual(string, 

762 "VisitInfo(exposureTime=10.01, darkTime=11.02, " 

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

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

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

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

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

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

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

770 

771 def testParallacticAngle(self): 

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

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

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

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

776 boresightRaDec=item.boresightRaDec, 

777 observatory=item.observatory, 

778 ) 

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

780 

781 def testParallacticAngleNorthMeridian(self): 

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

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

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

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

786 boresightRaDec=SpherePoint(meridianBoresightRA, 

787 northBoresightDec), 

788 observatory=self.data1.observatory, 

789 ) 

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

791 

792 def testParallacticAngleSouthMeridian(self): 

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

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

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

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

797 boresightRaDec=SpherePoint(meridianBoresightRA, 

798 southBoresightDec), 

799 observatory=self.data1.observatory, 

800 ) 

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

802 

803 

804def setup_module(module): 

805 lsst.utils.tests.init() 

806 

807 

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

809 pass 

810 

811 

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

813 lsst.utils.tests.init() 

814 unittest.main()