Coverage for tests/test_visitInfo.py: 10%

409 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-15 02:49 -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 testConstructorKeywordArguments(self): 

610 """Test VisitInfo with named arguments""" 

611 data = self.data1 

612 

613 visitInfo = afwImage.VisitInfo() 

614 self._testIsEmpty(visitInfo) 

615 

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

617 with self.assertWarns(FutureWarning): 

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

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

620 

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

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

623 

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

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

626 

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

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

629 

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

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

632 

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

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

635 

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

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

638 

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

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

641 

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

643 self.assertEqual(visitInfo.getBoresightAirmass(), 

644 data.boresightAirmass) 

645 

646 visitInfo = afwImage.VisitInfo( 

647 boresightRotAngle=data.boresightRotAngle) 

648 self.assertEqual(visitInfo.getBoresightRotAngle(), 

649 data.boresightRotAngle) 

650 

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

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

653 

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

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

656 

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

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

659 

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

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

662 

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

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

665 

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

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

668 

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

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

671 

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

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

674 

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

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

677 

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

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

680 

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

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

683 

684 def testGoodRotTypes(self): 

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

686 for rotType in RotTypeEnumNameDict: 

687 metadata = propertySetFromDict( 

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

689 visitInfo = afwImage.VisitInfo(metadata) 

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

691 

692 def testBadRotTypes(self): 

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

694 for badRotTypeName in ( 

695 "unknown", # must be all uppercase 

696 "sky", # must be all uppercase 

697 "Sky", # must be all uppercase 

698 "SKY1", # extra chars 

699 "HORIZONTAL", # extra chars 

700 ): 

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

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

703 afwImage.VisitInfo(metadata) 

704 

705 def test_str(self): 

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

707 visitInfo = makeVisitInfo(self.data1) 

708 string = str(visitInfo) 

709 self.assertEqual(string, 

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

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

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

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

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

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

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

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

718 

719 def testParallacticAngle(self): 

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

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

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

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

724 boresightRaDec=item.boresightRaDec, 

725 observatory=item.observatory, 

726 ) 

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

728 

729 def testParallacticAngleNorthMeridian(self): 

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

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

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

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

734 boresightRaDec=SpherePoint(meridianBoresightRA, 

735 northBoresightDec), 

736 observatory=self.data1.observatory, 

737 ) 

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

739 

740 def testParallacticAngleSouthMeridian(self): 

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

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

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

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

745 boresightRaDec=SpherePoint(meridianBoresightRA, 

746 southBoresightDec), 

747 observatory=self.data1.observatory, 

748 ) 

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

750 

751 

752def setup_module(module): 

753 lsst.utils.tests.init() 

754 

755 

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

757 pass 

758 

759 

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

761 lsst.utils.tests.init() 

762 unittest.main()