Coverage for tests/test_visitInfo.py: 9%

436 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-03 02:47 -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 testCopyWith(self): 

232 visitInfo1 = makeVisitInfo(self.data1) 

233 visitInfo2 = makeVisitInfo(self.data2) 

234 

235 updateFields1 = [ 

236 "exposureTime", 

237 "darkTime", 

238 "date", 

239 "ut1", 

240 "era", 

241 "boresightRaDec", 

242 "boresightAzAlt", 

243 "boresightAirmass", 

244 "boresightRotAngle", 

245 ] 

246 

247 updateFields2 = [ 

248 "rotType", 

249 "observatory", 

250 "weather", 

251 "instrumentLabel", 

252 "id", 

253 "focusZ", 

254 "observationType", 

255 "scienceProgram", 

256 "observationReason", 

257 "object", 

258 "hasSimulatedContent", 

259 ] 

260 

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

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

263 

264 newVisit1 = visitInfo1.copyWith(**kwargs1) 

265 newVisit2 = visitInfo1.copyWith(**kwargs2) 

266 

267 for field in updateFields1: 

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

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

270 

271 for field in updateFields2: 

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

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

274 

275 # Test the deprecated exposureId. 

276 # This code can be removed with DM-32138. 

277 deprecatedVisit = visitInfo1.copyWith(exposureId=3) 

278 self.assertEqual(deprecatedVisit.getExposureId(), 3) 

279 deprecatedCopy = deprecatedVisit.copyWith(**kwargs1) 

280 self.assertEqual(deprecatedCopy.getExposureId(), 3) 

281 

282 def testTablePersistence(self): 

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

284 """ 

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

286 tablePath = os.path.join( 

287 self.testDir, "testVisitInfo_testTablePersistence.fits") 

288 v1 = afwImage.VisitInfo(*item) 

289 v1.writeFits(tablePath) 

290 v2 = afwImage.VisitInfo.readFits(tablePath) 

291 self.assertEqual(v1, v2) 

292 os.unlink(tablePath) 

293 

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

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

296 

297 Parameters 

298 ---------- 

299 data : `VisitInfoData` 

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

301 superset thereof. 

302 filePath : `str` 

303 The file to test. 

304 version : `int` 

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

306 """ 

307 visitInfo = afwImage.VisitInfo.readFits(filePath) 

308 

309 if version >= 0: 

310 with self.assertWarns(FutureWarning): 

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

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

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

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

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

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

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

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

319 self.assertEqual(visitInfo.getBoresightAirmass(), 

320 data.boresightAirmass) 

321 self.assertEqual(visitInfo.getBoresightRotAngle(), 

322 data.boresightRotAngle) 

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

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

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

326 if version >= 1: 

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

328 else: 

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

330 if version >= 2: 

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

332 else: 

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

334 if version >= 3: 

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

336 else: 

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

338 if version >= 4: 

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

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

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

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

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

344 else: 

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

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

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

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

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

350 

351 def testPersistenceVersions(self): 

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

353 """ 

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

355 

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

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

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

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

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

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

362 

363 def testSetVisitInfoMetadata(self): 

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

365 visitInfo = makeVisitInfo(item) 

366 metadata = PropertyList() 

367 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

386 item.boresightAirmass) 

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

388 item.boresightRotAngle.asDegrees()) 

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

390 RotTypeEnumNameDict[item.rotType]) 

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

392 item.observatory.getLongitude().asDegrees()) 

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

394 item.observatory.getLatitude().asDegrees()) 

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

396 item.observatory.getElevation()) 

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

398 item.weather.getAirTemperature()) 

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

400 item.weather.getAirPressure()) 

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

402 item.weather.getHumidity()) 

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

404 item.instrumentLabel) 

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

406 item.id) 

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

408 item.focusZ) 

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

410 item.observationType) 

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

412 item.scienceProgram) 

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

414 item.observationReason) 

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

416 item.object) 

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

418 item.hasSimulatedContent) 

419 

420 def testSetVisitInfoMetadataMissingValues(self): 

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

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

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

424 visitInfo = afwImage.VisitInfo() 

425 metadata = PropertyList() 

426 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

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

428 RotTypeEnumNameDict[afwImage.RotType.UNKNOWN]) 

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

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

431 

432 def testStripVisitInfoKeywords(self): 

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

434 visitInfo = afwImage.VisitInfo(*argList) 

435 metadata = PropertyList() 

436 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

437 # add an extra keyword that will not be stripped 

438 metadata.set("EXTRA", 5) 

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

440 afwImage.stripVisitInfoKeywords(metadata) 

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

442 

443 def _testIsEmpty(self, visitInfo): 

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

445 """ 

446 with self.assertWarns(FutureWarning): 

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

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

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

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

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

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

453 for i in range(2): 

454 self.assertTrue(math.isnan( 

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

456 self.assertTrue(math.isnan( 

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

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

459 self.assertTrue(math.isnan( 

460 visitInfo.getBoresightRotAngle().asDegrees())) 

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

462 self.assertTrue(math.isnan( 

463 visitInfo.getObservatory().getLongitude().asDegrees())) 

464 self.assertTrue(math.isnan( 

465 visitInfo.getObservatory().getLatitude().asDegrees())) 

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

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

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

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

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

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

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

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

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

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

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

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

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

479 

480 def testEquals(self): 

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

482 """ 

483 # objects with "equal state" should be equal 

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

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

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

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

488 

489 # equality must be reflexive 

490 info = makeVisitInfo(self.data1) 

491 self.assertEqual(info, info) 

492 info = makeVisitInfo(self.data2) 

493 self.assertEqual(info, info) 

494 info = afwImage.VisitInfo() 

495 self.assertEqual(info, info) 

496 

497 # commutativity and transitivity difficult to test with this setup 

498 

499 def testMetadataConstructor(self): 

500 """Test the metadata constructor 

501 

502 This constructor allows missing values 

503 """ 

504 data = self.data1 

505 

506 metadata = propertySetFromDict({}) 

507 visitInfo = afwImage.VisitInfo(metadata) 

508 self._testIsEmpty(visitInfo) 

509 

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

511 visitInfo = afwImage.VisitInfo(metadata) 

512 with self.assertWarns(FutureWarning): 

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

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

515 

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

517 visitInfo = afwImage.VisitInfo(metadata) 

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

519 

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

521 visitInfo = afwImage.VisitInfo(metadata) 

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

523 

524 metadata = propertySetFromDict( 

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

526 visitInfo = afwImage.VisitInfo(metadata) 

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

528 

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

530 metadata = propertySetFromDict( 

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

532 visitInfo = afwImage.VisitInfo(metadata) 

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

534 

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

536 metadata = propertySetFromDict({ 

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

538 "TIMESYS": "TAI", 

539 }) 

540 visitInfo = afwImage.VisitInfo(metadata) 

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

542 

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

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

545 # will result 

546 metadata = propertySetFromDict({ 

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

548 "TIMESYS": "TAI", 

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

550 }) 

551 visitInfo = afwImage.VisitInfo(metadata) 

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

553 

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

555 visitInfo = afwImage.VisitInfo(metadata) 

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

557 

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

559 visitInfo = afwImage.VisitInfo(metadata) 

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

561 

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

563 metadata = propertySetFromDict( 

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

565 visitInfo = afwImage.VisitInfo(metadata) 

566 self.assertEqual(visitInfo.getBoresightRaDec() 

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

568 

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

570 metadata = propertySetFromDict( 

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

572 visitInfo = afwImage.VisitInfo(metadata) 

573 self.assertEqual(visitInfo.getBoresightAzAlt() 

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

575 

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

577 visitInfo = afwImage.VisitInfo(metadata) 

578 self.assertEqual(visitInfo.getBoresightAirmass(), 

579 data.boresightAirmass) 

580 

581 metadata = propertySetFromDict( 

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

583 visitInfo = afwImage.VisitInfo(metadata) 

584 self.assertEqual(visitInfo.getBoresightRotAngle(), 

585 data.boresightRotAngle) 

586 

587 metadata = propertySetFromDict( 

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

589 visitInfo = afwImage.VisitInfo(metadata) 

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

591 

592 metadata = propertySetFromDict( 

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

594 visitInfo = afwImage.VisitInfo(metadata) 

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

596 data.observatory.getLongitude()) 

597 

598 metadata = propertySetFromDict( 

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

600 visitInfo = afwImage.VisitInfo(metadata) 

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

602 data.observatory.getLatitude()) 

603 

604 metadata = propertySetFromDict( 

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

606 visitInfo = afwImage.VisitInfo(metadata) 

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

608 data.observatory.getElevation()) 

609 

610 metadata = propertySetFromDict( 

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

612 visitInfo = afwImage.VisitInfo(metadata) 

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

614 data.weather.getAirTemperature()) 

615 

616 metadata = propertySetFromDict( 

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

618 visitInfo = afwImage.VisitInfo(metadata) 

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

620 data.weather.getAirPressure()) 

621 

622 metadata = propertySetFromDict( 

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

624 visitInfo = afwImage.VisitInfo(metadata) 

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

626 data.weather.getHumidity()) 

627 

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

629 visitInfo = afwImage.VisitInfo(metadata) 

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

631 

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

633 visitInfo = afwImage.VisitInfo(metadata) 

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

635 

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

637 visitInfo = afwImage.VisitInfo(metadata) 

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

639 

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

641 visitInfo = afwImage.VisitInfo(metadata) 

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

643 

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

645 visitInfo = afwImage.VisitInfo(metadata) 

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

647 

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

649 visitInfo = afwImage.VisitInfo(metadata) 

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

651 

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

653 visitInfo = afwImage.VisitInfo(metadata) 

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

655 

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

657 visitInfo = afwImage.VisitInfo(metadata) 

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

659 

660 def testMetadataConstructorUndefined(self): 

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

662 

663 metadata = propertySetFromDict({ 

664 # These are examples of generic reader code. 

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

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

667 # These headers have special logic in the reader. 

668 "EXPTIME": None, 

669 "IDNUM": None, 

670 "DATE-AVG": None, 

671 "ROTTYPE": None, 

672 "HAS-SIMULATED-CONTENT": None, 

673 }) 

674 visitInfo = afwImage.VisitInfo(metadata) 

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

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

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

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

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

680 

681 def testConstructorKeywordArguments(self): 

682 """Test VisitInfo with named arguments""" 

683 data = self.data1 

684 

685 visitInfo = afwImage.VisitInfo() 

686 self._testIsEmpty(visitInfo) 

687 

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

689 with self.assertWarns(FutureWarning): 

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

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

692 

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

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

695 

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

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

698 

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

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

701 

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

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

704 

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

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

707 

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

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

710 

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

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

713 

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

715 self.assertEqual(visitInfo.getBoresightAirmass(), 

716 data.boresightAirmass) 

717 

718 visitInfo = afwImage.VisitInfo( 

719 boresightRotAngle=data.boresightRotAngle) 

720 self.assertEqual(visitInfo.getBoresightRotAngle(), 

721 data.boresightRotAngle) 

722 

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

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

725 

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

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

728 

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

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

731 

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

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

734 

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

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

737 

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

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

740 

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

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

743 

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

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

746 

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

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

749 

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

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

752 

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

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

755 

756 def testGoodRotTypes(self): 

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

758 for rotType in RotTypeEnumNameDict: 

759 metadata = propertySetFromDict( 

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

761 visitInfo = afwImage.VisitInfo(metadata) 

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

763 

764 def testBadRotTypes(self): 

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

766 for badRotTypeName in ( 

767 "unknown", # must be all uppercase 

768 "sky", # must be all uppercase 

769 "Sky", # must be all uppercase 

770 "SKY1", # extra chars 

771 "HORIZONTAL", # extra chars 

772 ): 

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

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

775 afwImage.VisitInfo(metadata) 

776 

777 def test_str(self): 

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

779 visitInfo = makeVisitInfo(self.data1) 

780 string = str(visitInfo) 

781 self.assertEqual(string, 

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

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

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

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

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

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

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

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

790 

791 def testParallacticAngle(self): 

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

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

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

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

796 boresightRaDec=item.boresightRaDec, 

797 observatory=item.observatory, 

798 ) 

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

800 

801 def testParallacticAngleNorthMeridian(self): 

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

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

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

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

806 boresightRaDec=SpherePoint(meridianBoresightRA, 

807 northBoresightDec), 

808 observatory=self.data1.observatory, 

809 ) 

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

811 

812 def testParallacticAngleSouthMeridian(self): 

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

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

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

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

817 boresightRaDec=SpherePoint(meridianBoresightRA, 

818 southBoresightDec), 

819 observatory=self.data1.observatory, 

820 ) 

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

822 

823 

824def setup_module(module): 

825 lsst.utils.tests.init() 

826 

827 

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

829 pass 

830 

831 

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

833 lsst.utils.tests.init() 

834 unittest.main()