Coverage for tests/test_visitInfo.py: 11%

355 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-19 12:16 -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 ) 

70 

71 

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

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

74 

75 def setUp(self): 

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

77 

78 def computeLstHA(data): 

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

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

81 hourAngle = localEra - data.boresightRaDec[0] 

82 return localEra, hourAngle 

83 

84 fields = ['exposureId', 

85 'exposureTime', 

86 'darkTime', 

87 'date', 

88 'ut1', 

89 'era', 

90 'boresightRaDec', 

91 'boresightAzAlt', 

92 'boresightAirmass', 

93 'boresightRotAngle', 

94 'rotType', 

95 'observatory', 

96 'weather', 

97 'instrumentLabel', 

98 'id', 

99 'focusZ', 

100 ] 

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

102 data1 = VisitInfoData(exposureId=10313423, 

103 exposureTime=10.01, 

104 darkTime=11.02, 

105 date=DateTime( 

106 65321.1, DateTime.MJD, DateTime.TAI), 

107 ut1=12345.1, 

108 era=45.1*degrees, 

109 boresightRaDec=SpherePoint( 

110 23.1*degrees, 73.2*degrees), 

111 boresightAzAlt=SpherePoint( 

112 134.5*degrees, 33.3*degrees), 

113 boresightAirmass=1.73, 

114 boresightRotAngle=73.2*degrees, 

115 rotType=afwImage.RotType.SKY, 

116 observatory=Observatory( 

117 11.1*degrees, 22.2*degrees, 0.333), 

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

119 instrumentLabel="TestCameraOne", 

120 id=987654, 

121 focusZ=1.5, 

122 ) 

123 self.data1 = data1 

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

125 data2 = VisitInfoData(exposureId=1, 

126 exposureTime=15.5, 

127 darkTime=17.8, 

128 date=DateTime( 

129 55321.2, DateTime.MJD, DateTime.TAI), 

130 ut1=312345.1, 

131 era=25.1*degrees, 

132 boresightRaDec=SpherePoint( 

133 2.1*degrees, 33.2*degrees), 

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

135 boresightAirmass=2.05, 

136 boresightRotAngle=-53.2*degrees, 

137 rotType=afwImage.RotType.HORIZON, 

138 observatory=Observatory( 

139 22.2*degrees, 33.3*degrees, 0.444), 

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

141 instrumentLabel="TestCameraTwo", 

142 id=123456, 

143 focusZ=-0.7, 

144 ) 

145 self.data2 = data2 

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

147 

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

149 visitInfo = makeVisitInfo(data) 

150 with self.assertWarns(FutureWarning): 

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

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

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

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

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

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

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

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

159 self.assertEqual(visitInfo.getBoresightAirmass(), 

160 data.boresightAirmass) 

161 self.assertEqual(visitInfo.getBoresightRotAngle(), 

162 data.boresightRotAngle) 

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

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

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

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

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

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

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

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

171 

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

173 """Test property attribute accessors.""" 

174 visitInfo = makeVisitInfo(data) 

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

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

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

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

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

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

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

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

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

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

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

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

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

188 self.assertEqual(visitInfo.localEra, localEra) 

189 self.assertEqual(visitInfo.boresightHourAngle, hourAngle) 

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

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

192 

193 def testValueConstructor_data1(self): 

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

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

196 

197 def testValueConstructor_data2(self): 

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

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

200 

201 def testTablePersistence(self): 

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

203 """ 

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

205 tablePath = os.path.join( 

206 self.testDir, "testVisitInfo_testTablePersistence.fits") 

207 v1 = afwImage.VisitInfo(*item) 

208 v1.writeFits(tablePath) 

209 v2 = afwImage.VisitInfo.readFits(tablePath) 

210 self.assertEqual(v1, v2) 

211 os.unlink(tablePath) 

212 

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

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

215 

216 Parameters 

217 ---------- 

218 data : `VisitInfoData` 

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

220 superset thereof. 

221 filePath : `str` 

222 The file to test. 

223 version : `int` 

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

225 """ 

226 visitInfo = afwImage.VisitInfo.readFits(filePath) 

227 

228 if version >= 0: 

229 with self.assertWarns(FutureWarning): 

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

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

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

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

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

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

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

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

238 self.assertEqual(visitInfo.getBoresightAirmass(), 

239 data.boresightAirmass) 

240 self.assertEqual(visitInfo.getBoresightRotAngle(), 

241 data.boresightRotAngle) 

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

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

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

245 if version >= 1: 

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

247 else: 

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

249 if version >= 2: 

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

251 else: 

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

253 if version >= 3: 

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

255 else: 

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

257 

258 def testPersistenceVersions(self): 

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

260 """ 

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

262 

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

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

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

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

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

268 

269 def testSetVisitInfoMetadata(self): 

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

271 visitInfo = makeVisitInfo(item) 

272 metadata = PropertyList() 

273 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

274 self.assertEqual(metadata.nameCount(), 23) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

292 item.boresightAirmass) 

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

294 item.boresightRotAngle.asDegrees()) 

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

296 RotTypeEnumNameDict[item.rotType]) 

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

298 item.observatory.getLongitude().asDegrees()) 

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

300 item.observatory.getLatitude().asDegrees()) 

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

302 item.observatory.getElevation()) 

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

304 item.weather.getAirTemperature()) 

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

306 item.weather.getAirPressure()) 

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

308 item.weather.getHumidity()) 

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

310 item.instrumentLabel) 

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

312 item.id) 

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

314 item.focusZ) 

315 

316 def testSetVisitInfoMetadataMissingValues(self): 

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

318 visitInfo = afwImage.VisitInfo() # only rot type is known 

319 metadata = PropertyList() 

320 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

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

322 RotTypeEnumNameDict[afwImage.RotType.UNKNOWN]) 

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

324 

325 def testStripVisitInfoKeywords(self): 

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

327 visitInfo = afwImage.VisitInfo(*argList) 

328 metadata = PropertyList() 

329 afwImage.setVisitInfoMetadata(metadata, visitInfo) 

330 # add an extra keyword that will not be stripped 

331 metadata.set("EXTRA", 5) 

332 self.assertEqual(metadata.nameCount(), 24) 

333 afwImage.stripVisitInfoKeywords(metadata) 

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

335 

336 def _testIsEmpty(self, visitInfo): 

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

338 """ 

339 with self.assertWarns(FutureWarning): 

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

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

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

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

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

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

346 for i in range(2): 

347 self.assertTrue(math.isnan( 

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

349 self.assertTrue(math.isnan( 

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

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

352 self.assertTrue(math.isnan( 

353 visitInfo.getBoresightRotAngle().asDegrees())) 

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

355 self.assertTrue(math.isnan( 

356 visitInfo.getObservatory().getLongitude().asDegrees())) 

357 self.assertTrue(math.isnan( 

358 visitInfo.getObservatory().getLatitude().asDegrees())) 

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

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

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

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

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

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

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

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

367 

368 def testEquals(self): 

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

370 """ 

371 # objects with "equal state" should be equal 

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

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

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

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

376 

377 # equality must be reflexive 

378 info = makeVisitInfo(self.data1) 

379 self.assertEqual(info, info) 

380 info = makeVisitInfo(self.data2) 

381 self.assertEqual(info, info) 

382 info = afwImage.VisitInfo() 

383 self.assertEqual(info, info) 

384 

385 # commutativity and transitivity difficult to test with this setup 

386 

387 def testMetadataConstructor(self): 

388 """Test the metadata constructor 

389 

390 This constructor allows missing values 

391 """ 

392 data = self.data1 

393 

394 metadata = propertySetFromDict({}) 

395 visitInfo = afwImage.VisitInfo(metadata) 

396 self._testIsEmpty(visitInfo) 

397 

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

399 visitInfo = afwImage.VisitInfo(metadata) 

400 with self.assertWarns(FutureWarning): 

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

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

403 

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

405 visitInfo = afwImage.VisitInfo(metadata) 

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

407 

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

409 visitInfo = afwImage.VisitInfo(metadata) 

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

411 

412 metadata = propertySetFromDict( 

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

414 visitInfo = afwImage.VisitInfo(metadata) 

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

416 

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

418 metadata = propertySetFromDict( 

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

420 visitInfo = afwImage.VisitInfo(metadata) 

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

422 

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

424 metadata = propertySetFromDict({ 

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

426 "TIMESYS": "TAI", 

427 }) 

428 visitInfo = afwImage.VisitInfo(metadata) 

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

430 

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

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

433 # will result 

434 metadata = propertySetFromDict({ 

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

436 "TIMESYS": "TAI", 

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

438 }) 

439 visitInfo = afwImage.VisitInfo(metadata) 

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

441 

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

443 visitInfo = afwImage.VisitInfo(metadata) 

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

445 

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

447 visitInfo = afwImage.VisitInfo(metadata) 

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

449 

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

451 metadata = propertySetFromDict( 

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

453 visitInfo = afwImage.VisitInfo(metadata) 

454 self.assertEqual(visitInfo.getBoresightRaDec() 

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

456 

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

458 metadata = propertySetFromDict( 

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

460 visitInfo = afwImage.VisitInfo(metadata) 

461 self.assertEqual(visitInfo.getBoresightAzAlt() 

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

463 

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

465 visitInfo = afwImage.VisitInfo(metadata) 

466 self.assertEqual(visitInfo.getBoresightAirmass(), 

467 data.boresightAirmass) 

468 

469 metadata = propertySetFromDict( 

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

471 visitInfo = afwImage.VisitInfo(metadata) 

472 self.assertEqual(visitInfo.getBoresightRotAngle(), 

473 data.boresightRotAngle) 

474 

475 metadata = propertySetFromDict( 

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

477 visitInfo = afwImage.VisitInfo(metadata) 

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

479 

480 metadata = propertySetFromDict( 

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

482 visitInfo = afwImage.VisitInfo(metadata) 

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

484 data.observatory.getLongitude()) 

485 

486 metadata = propertySetFromDict( 

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

488 visitInfo = afwImage.VisitInfo(metadata) 

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

490 data.observatory.getLatitude()) 

491 

492 metadata = propertySetFromDict( 

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

494 visitInfo = afwImage.VisitInfo(metadata) 

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

496 data.observatory.getElevation()) 

497 

498 metadata = propertySetFromDict( 

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

500 visitInfo = afwImage.VisitInfo(metadata) 

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

502 data.weather.getAirTemperature()) 

503 

504 metadata = propertySetFromDict( 

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

506 visitInfo = afwImage.VisitInfo(metadata) 

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

508 data.weather.getAirPressure()) 

509 

510 metadata = propertySetFromDict( 

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

512 visitInfo = afwImage.VisitInfo(metadata) 

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

514 data.weather.getHumidity()) 

515 

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

517 visitInfo = afwImage.VisitInfo(metadata) 

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

519 

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

521 visitInfo = afwImage.VisitInfo(metadata) 

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

523 

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

525 visitInfo = afwImage.VisitInfo(metadata) 

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

527 

528 def testConstructorKeywordArguments(self): 

529 """Test VisitInfo with named arguments""" 

530 data = self.data1 

531 

532 visitInfo = afwImage.VisitInfo() 

533 self._testIsEmpty(visitInfo) 

534 

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

536 with self.assertWarns(FutureWarning): 

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

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

539 

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

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

542 

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

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

545 

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

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

548 

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

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

551 

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

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

554 

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

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

557 

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

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

560 

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

562 self.assertEqual(visitInfo.getBoresightAirmass(), 

563 data.boresightAirmass) 

564 

565 visitInfo = afwImage.VisitInfo( 

566 boresightRotAngle=data.boresightRotAngle) 

567 self.assertEqual(visitInfo.getBoresightRotAngle(), 

568 data.boresightRotAngle) 

569 

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

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

572 

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

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

575 

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

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

578 

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

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

581 

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

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

584 

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

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

587 

588 def testGoodRotTypes(self): 

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

590 for rotType in RotTypeEnumNameDict: 

591 metadata = propertySetFromDict( 

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

593 visitInfo = afwImage.VisitInfo(metadata) 

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

595 

596 def testBadRotTypes(self): 

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

598 for badRotTypeName in ( 

599 "unknown", # must be all uppercase 

600 "sky", # must be all uppercase 

601 "Sky", # must be all uppercase 

602 "SKY1", # extra chars 

603 "HORIZONTAL", # extra chars 

604 ): 

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

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

607 afwImage.VisitInfo(metadata) 

608 

609 def test_str(self): 

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

611 visitInfo = makeVisitInfo(self.data1) 

612 string = str(visitInfo) 

613 self.assertIn("exposureId=10313423", string) 

614 self.assertIn("exposureTime=10.01", string) 

615 self.assertIn("darkTime=11.02", string) 

616 self.assertIn("rotType=1", string) 

617 

618 # Check that it at least doesn't throw 

619 str(afwImage.VisitInfo()) 

620 

621 def testParallacticAngle(self): 

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

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

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

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

626 boresightRaDec=item.boresightRaDec, 

627 observatory=item.observatory, 

628 ) 

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

630 

631 def testParallacticAngleNorthMeridian(self): 

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

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

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

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

636 boresightRaDec=SpherePoint(meridianBoresightRA, 

637 northBoresightDec), 

638 observatory=self.data1.observatory, 

639 ) 

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

641 

642 def testParallacticAngleSouthMeridian(self): 

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

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

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

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

647 boresightRaDec=SpherePoint(meridianBoresightRA, 

648 southBoresightDec), 

649 observatory=self.data1.observatory, 

650 ) 

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

652 

653 

654def setup_module(module): 

655 lsst.utils.tests.init() 

656 

657 

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

659 pass 

660 

661 

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

663 lsst.utils.tests.init() 

664 unittest.main()