Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of afw. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

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

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

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

12# (at your option) any later version. 

13# 

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

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

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

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22""" 

23Test lsst.afw.image.Exposure 

24""" 

25 

26import os.path 

27import unittest 

28 

29import numpy as np 

30from numpy.testing import assert_allclose 

31import yaml 

32 

33import lsst.utils 

34import lsst.utils.tests 

35import lsst.geom 

36import lsst.afw.image as afwImage 

37from lsst.afw.image.utils import defineFilter 

38from lsst.afw.coord import Weather 

39import lsst.afw.geom as afwGeom 

40import lsst.afw.table as afwTable 

41import lsst.pex.exceptions as pexExcept 

42from lsst.afw.fits import readMetadata, FitsError 

43from lsst.afw.cameraGeom.testUtils import DetectorWrapper 

44from lsst.log import Log 

45from testTableArchivesLib import DummyPsf 

46 

47Log.getLogger("afw.image.Mask").setLevel(Log.INFO) 

48 

49try: 

50 dataDir = os.path.join(lsst.utils.getPackageDir("afwdata"), "data") 

51except LookupError: 

52 dataDir = None 

53else: 

54 InputMaskedImageName = "871034p_1_MI.fits" 

55 InputMaskedImageNameSmall = "small_MI.fits" 

56 InputImageNameSmall = "small" 

57 OutputMaskedImageName = "871034p_1_MInew.fits" 

58 

59 currDir = os.path.abspath(os.path.dirname(__file__)) 

60 inFilePath = os.path.join(dataDir, InputMaskedImageName) 

61 inFilePathSmall = os.path.join(dataDir, InputMaskedImageNameSmall) 

62 inFilePathSmallImage = os.path.join(dataDir, InputImageNameSmall) 

63 

64 

65@unittest.skipIf(dataDir is None, "afwdata not setup") 

66class ExposureTestCase(lsst.utils.tests.TestCase): 

67 """ 

68 A test case for the Exposure Class 

69 """ 

70 

71 def setUp(self): 

72 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

73 maskedImageMD = readMetadata(inFilePathSmall) 

74 

75 self.smallExposure = afwImage.ExposureF(inFilePathSmall) 

76 self.width = maskedImage.getWidth() 

77 self.height = maskedImage.getHeight() 

78 self.wcs = afwGeom.makeSkyWcs(maskedImageMD, False) 

79 self.md = maskedImageMD 

80 self.psf = DummyPsf(2.0) 

81 self.detector = DetectorWrapper().detector 

82 self.id = 42 

83 self.extras = {"MISC": DummyPsf(3.5)} 

84 

85 self.exposureBlank = afwImage.ExposureF() 

86 self.exposureMiOnly = afwImage.makeExposure(maskedImage) 

87 self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) 

88 # n.b. the (100, 100, ...) form 

89 self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) 

90 # test with ExtentI(100, 100) too 

91 self.exposureCrOnly = afwImage.ExposureF(lsst.geom.ExtentI(100, 100)) 

92 

93 afwImage.Filter.reset() 

94 afwImage.FilterProperty.reset() 

95 

96 defineFilter("g", 470.0) 

97 

98 def tearDown(self): 

99 del self.smallExposure 

100 del self.wcs 

101 del self.psf 

102 del self.detector 

103 del self.extras 

104 

105 del self.exposureBlank 

106 del self.exposureMiOnly 

107 del self.exposureMiWcs 

108 del self.exposureCrWcs 

109 del self.exposureCrOnly 

110 

111 def testGetMaskedImage(self): 

112 """ 

113 Test to ensure a MaskedImage can be obtained from each 

114 Exposure. An Exposure is required to have a MaskedImage, 

115 therefore each of the Exposures should return a MaskedImage. 

116 

117 MaskedImage class should throw appropriate 

118 lsst::pex::exceptions::NotFound if the MaskedImage can not be 

119 obtained. 

120 """ 

121 maskedImageBlank = self.exposureBlank.getMaskedImage() 

122 blankWidth = maskedImageBlank.getWidth() 

123 blankHeight = maskedImageBlank.getHeight() 

124 if blankWidth != blankHeight != 0: 

125 self.fail(f"{blankWidth} = {blankHeight} != 0") 

126 

127 maskedImageMiOnly = self.exposureMiOnly.getMaskedImage() 

128 miOnlyWidth = maskedImageMiOnly.getWidth() 

129 miOnlyHeight = maskedImageMiOnly.getHeight() 

130 self.assertAlmostEqual(miOnlyWidth, self.width) 

131 self.assertAlmostEqual(miOnlyHeight, self.height) 

132 

133 # NOTE: Unittests for Exposures created from a MaskedImage and 

134 # a WCS object are incomplete. No way to test the validity of 

135 # the WCS being copied/created. 

136 

137 maskedImageMiWcs = self.exposureMiWcs.getMaskedImage() 

138 miWcsWidth = maskedImageMiWcs.getWidth() 

139 miWcsHeight = maskedImageMiWcs.getHeight() 

140 self.assertAlmostEqual(miWcsWidth, self.width) 

141 self.assertAlmostEqual(miWcsHeight, self.height) 

142 

143 maskedImageCrWcs = self.exposureCrWcs.getMaskedImage() 

144 crWcsWidth = maskedImageCrWcs.getWidth() 

145 crWcsHeight = maskedImageCrWcs.getHeight() 

146 if crWcsWidth != crWcsHeight != 0: 

147 self.fail(f"{crWcsWidth} != {crWcsHeight} != 0") 

148 

149 maskedImageCrOnly = self.exposureCrOnly.getMaskedImage() 

150 crOnlyWidth = maskedImageCrOnly.getWidth() 

151 crOnlyHeight = maskedImageCrOnly.getHeight() 

152 if crOnlyWidth != crOnlyHeight != 0: 

153 self.fail(f"{crOnlyWidth} != {crOnlyHeight} != 0") 

154 

155 # Check Exposure.getWidth() returns the MaskedImage's width 

156 self.assertEqual(crOnlyWidth, self.exposureCrOnly.getWidth()) 

157 self.assertEqual(crOnlyHeight, self.exposureCrOnly.getHeight()) 

158 # check width/height properties 

159 self.assertEqual(crOnlyWidth, self.exposureCrOnly.width) 

160 self.assertEqual(crOnlyHeight, self.exposureCrOnly.height) 

161 

162 def testProperties(self): 

163 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, 

164 self.exposureMiOnly.getMaskedImage()) 

165 mi2 = afwImage.MaskedImageF(self.exposureMiOnly.getDimensions()) 

166 mi2.image.array[:] = 5.0 

167 mi2.variance.array[:] = 3.0 

168 mi2.mask.array[:] = 0x1 

169 self.exposureMiOnly.maskedImage = mi2 

170 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, mi2) 

171 self.assertImagesEqual(self.exposureMiOnly.image, 

172 self.exposureMiOnly.maskedImage.image) 

173 

174 image3 = afwImage.ImageF(self.exposureMiOnly.getDimensions()) 

175 image3.array[:] = 3.0 

176 self.exposureMiOnly.image = image3 

177 self.assertImagesEqual(self.exposureMiOnly.image, image3) 

178 

179 mask3 = afwImage.MaskX(self.exposureMiOnly.getDimensions()) 

180 mask3.array[:] = 0x2 

181 self.exposureMiOnly.mask = mask3 

182 self.assertMasksEqual(self.exposureMiOnly.mask, mask3) 

183 

184 var3 = afwImage.ImageF(self.exposureMiOnly.getDimensions()) 

185 var3.array[:] = 2.0 

186 self.exposureMiOnly.variance = var3 

187 self.assertImagesEqual(self.exposureMiOnly.variance, var3) 

188 

189 # Test the property getter for a null VisitInfo. 

190 self.assertIsNone(self.exposureMiOnly.visitInfo) 

191 

192 def testGetWcs(self): 

193 """Test that a WCS can be obtained from each Exposure created with 

194 a WCS, and that an Exposure lacking a WCS returns None. 

195 """ 

196 # These exposures don't contain a WCS 

197 self.assertIsNone(self.exposureBlank.getWcs()) 

198 self.assertIsNone(self.exposureMiOnly.getWcs()) 

199 self.assertIsNone(self.exposureCrOnly.getWcs()) 

200 

201 # These exposures should contain a WCS 

202 self.assertEqual(self.wcs, self.exposureMiWcs.getWcs()) 

203 self.assertEqual(self.wcs, self.exposureCrWcs.getWcs()) 

204 

205 def testExposureInfoConstructor(self): 

206 """Test the Exposure(maskedImage, exposureInfo) constructor""" 

207 exposureInfo = afwImage.ExposureInfo() 

208 exposureInfo.setWcs(self.wcs) 

209 exposureInfo.setDetector(self.detector) 

210 gFilter = afwImage.Filter("g") 

211 gFilterLabel = afwImage.FilterLabel(band="g") 

212 exposureInfo.setFilter(gFilter) 

213 exposureInfo.setFilterLabel(gFilterLabel) 

214 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

215 exposure = afwImage.ExposureF(maskedImage, exposureInfo) 

216 

217 self.assertTrue(exposure.hasWcs()) 

218 self.assertEqual(exposure.getWcs().getPixelOrigin(), 

219 self.wcs.getPixelOrigin()) 

220 self.assertEqual(exposure.getDetector().getName(), 

221 self.detector.getName()) 

222 self.assertEqual(exposure.getDetector().getSerial(), 

223 self.detector.getSerial()) 

224 self.assertEqual(exposure.getFilter(), gFilter) 

225 self.assertEqual(exposure.getFilterLabel(), gFilterLabel) 

226 

227 self.assertTrue(exposure.getInfo().hasWcs()) 

228 # check the ExposureInfo property 

229 self.assertTrue(exposure.info.hasWcs()) 

230 self.assertEqual(exposure.getInfo().getWcs().getPixelOrigin(), 

231 self.wcs.getPixelOrigin()) 

232 self.assertEqual(exposure.getInfo().getDetector().getName(), 

233 self.detector.getName()) 

234 self.assertEqual(exposure.getInfo().getDetector().getSerial(), 

235 self.detector.getSerial()) 

236 self.assertEqual(exposure.getInfo().getFilter(), gFilter) 

237 self.assertEqual(exposure.getInfo().getFilterLabel(), gFilterLabel) 

238 

239 def testNullWcs(self): 

240 """Test that an Exposure constructed with second argument None is usable 

241 

242 When the exposureInfo constructor was first added, trying to get a WCS 

243 or other info caused a segfault because the ExposureInfo did not exist. 

244 """ 

245 maskedImage = self.exposureMiOnly.getMaskedImage() 

246 exposure = afwImage.ExposureF(maskedImage, None) 

247 self.assertFalse(exposure.hasWcs()) 

248 self.assertFalse(exposure.hasPsf()) 

249 

250 def testExposureInfoSetNone(self): 

251 exposureInfo = afwImage.ExposureInfo() 

252 exposureInfo.setDetector(None) 

253 exposureInfo.setValidPolygon(None) 

254 exposureInfo.setPsf(None) 

255 exposureInfo.setWcs(None) 

256 exposureInfo.setPhotoCalib(None) 

257 exposureInfo.setCoaddInputs(None) 

258 exposureInfo.setVisitInfo(None) 

259 exposureInfo.setApCorrMap(None) 

260 for key in self.extras: 

261 exposureInfo.setComponent(key, None) 

262 

263 def testSetExposureInfo(self): 

264 exposureInfo = afwImage.ExposureInfo() 

265 exposureInfo.setWcs(self.wcs) 

266 exposureInfo.setDetector(self.detector) 

267 gFilter = afwImage.Filter("g") 

268 gFilterLabel = afwImage.FilterLabel(band="g") 

269 exposureInfo.setFilter(gFilter) 

270 exposureInfo.setFilterLabel(gFilterLabel) 

271 exposureInfo.setId(self.id) 

272 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

273 exposure = afwImage.ExposureF(maskedImage) 

274 self.assertFalse(exposure.hasWcs()) 

275 

276 exposure.setInfo(exposureInfo) 

277 

278 self.assertTrue(exposure.hasWcs()) 

279 self.assertEqual(exposure.getWcs().getPixelOrigin(), 

280 self.wcs.getPixelOrigin()) 

281 self.assertEqual(exposure.getDetector().getName(), 

282 self.detector.getName()) 

283 self.assertEqual(exposure.getDetector().getSerial(), 

284 self.detector.getSerial()) 

285 self.assertEqual(exposure.getFilter(), gFilter) 

286 self.assertEqual(exposure.getFilterLabel(), gFilterLabel) 

287 

288 # test properties 

289 self.assertEqual(exposure.detector.getName(), self.detector.getName()) 

290 self.assertEqual(exposure.filterLabel, gFilterLabel) 

291 self.assertEqual(exposure.wcs, self.wcs) 

292 

293 def testDefaultFilter(self): 

294 """Test that old convention of having a "default" filter replaced with `None`. 

295 """ 

296 exposureInfo = afwImage.ExposureInfo() 

297 noFilter = afwImage.Filter() 

298 exposureInfo.setFilter(noFilter) 

299 self.assertFalse(exposureInfo.hasFilterLabel()) 

300 self.assertIsNone(exposureInfo.getFilterLabel()) 

301 

302 def testVisitInfoFitsPersistence(self): 

303 """Test saving an exposure to FITS and reading it back in preserves (some) VisitInfo fields""" 

304 exposureId = 5 

305 exposureTime = 12.3 

306 boresightRotAngle = 45.6 * lsst.geom.degrees 

307 weather = Weather(1.1, 2.2, 0.3) 

308 visitInfo = afwImage.VisitInfo( 

309 exposureId=exposureId, 

310 exposureTime=exposureTime, 

311 boresightRotAngle=boresightRotAngle, 

312 weather=weather, 

313 ) 

314 photoCalib = afwImage.PhotoCalib(3.4, 5.6) 

315 exposureInfo = afwImage.ExposureInfo() 

316 exposureInfo.setVisitInfo(visitInfo) 

317 exposureInfo.setPhotoCalib(photoCalib) 

318 exposureInfo.setDetector(self.detector) 

319 gFilter = afwImage.Filter("g") 

320 gFilterLabel = afwImage.FilterLabel(band="g") 

321 exposureInfo.setFilter(gFilter) 

322 exposureInfo.setFilterLabel(gFilterLabel) 

323 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

324 exposure = afwImage.ExposureF(maskedImage, exposureInfo) 

325 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

326 exposure.writeFits(tmpFile) 

327 rtExposure = afwImage.ExposureF(tmpFile) 

328 rtVisitInfo = rtExposure.getInfo().getVisitInfo() 

329 self.assertEqual(rtVisitInfo.getWeather(), weather) 

330 self.assertEqual(rtExposure.getPhotoCalib(), photoCalib) 

331 self.assertEqual(rtExposure.getFilter(), gFilter) 

332 self.assertEqual(rtExposure.getFilterLabel(), gFilterLabel) 

333 

334 # Test property getters. 

335 self.assertEqual(rtExposure.photoCalib, photoCalib) 

336 self.assertEqual(rtExposure.filterLabel, gFilterLabel) 

337 # NOTE: we can't test visitInfo equality, because most fields are NaN. 

338 self.assertIsNotNone(rtExposure.visitInfo) 

339 

340 def testSetMembers(self): 

341 """ 

342 Test that the MaskedImage and the WCS of an Exposure can be set. 

343 """ 

344 exposure = afwImage.ExposureF() 

345 

346 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

347 exposure.setMaskedImage(maskedImage) 

348 exposure.setWcs(self.wcs) 

349 exposure.setDetector(self.detector) 

350 exposure.setFilter(afwImage.Filter("g")) 

351 exposure.setFilterLabel(afwImage.FilterLabel(band="g")) 

352 

353 self.assertEqual(exposure.getDetector().getName(), 

354 self.detector.getName()) 

355 self.assertEqual(exposure.getDetector().getSerial(), 

356 self.detector.getSerial()) 

357 self.assertEqual(exposure.getFilter().getName(), "g") 

358 self.assertEqual(exposure.getFilterLabel().bandLabel, "g") 

359 self.assertEqual(exposure.getWcs(), self.wcs) 

360 

361 # The PhotoCalib tests are in test_photoCalib.py; 

362 # here we just check that it's gettable and settable. 

363 self.assertIsNone(exposure.getPhotoCalib()) 

364 

365 photoCalib = afwImage.PhotoCalib(511.1, 44.4) 

366 exposure.setPhotoCalib(photoCalib) 

367 self.assertEqual(exposure.getPhotoCalib(), photoCalib) 

368 

369 # Psfs next 

370 self.assertFalse(exposure.hasPsf()) 

371 exposure.setPsf(self.psf) 

372 self.assertTrue(exposure.hasPsf()) 

373 

374 exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf 

375 

376 # extras next 

377 info = exposure.getInfo() 

378 for key, value in self.extras.items(): 

379 self.assertFalse(info.hasComponent(key)) 

380 self.assertIsNone(info.getComponent(key)) 

381 info.setComponent(key, value) 

382 self.assertTrue(info.hasComponent(key)) 

383 self.assertEqual(info.getComponent(key), value) 

384 info.removeComponent(key) 

385 self.assertFalse(info.hasComponent(key)) 

386 

387 # Test that we can set the MaskedImage and WCS of an Exposure 

388 # that already has both 

389 self.exposureMiWcs.setMaskedImage(maskedImage) 

390 exposure.setWcs(self.wcs) 

391 

392 def testHasWcs(self): 

393 """ 

394 Test if an Exposure has a WCS or not. 

395 """ 

396 self.assertFalse(self.exposureBlank.hasWcs()) 

397 

398 self.assertFalse(self.exposureMiOnly.hasWcs()) 

399 self.assertTrue(self.exposureMiWcs.hasWcs()) 

400 self.assertTrue(self.exposureCrWcs.hasWcs()) 

401 self.assertFalse(self.exposureCrOnly.hasWcs()) 

402 

403 def testGetSubExposure(self): 

404 """ 

405 Test that a subExposure of the original Exposure can be obtained. 

406 

407 The MaskedImage class should throw a 

408 lsst::pex::exceptions::InvalidParameter if the requested 

409 subRegion is not fully contained within the original 

410 MaskedImage. 

411 

412 """ 

413 # 

414 # This subExposure is valid 

415 # 

416 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50), 

417 lsst.geom.Extent2I(10, 10)) 

418 subExposure = self.exposureCrWcs.Factory( 

419 self.exposureCrWcs, subBBox, afwImage.LOCAL) 

420 

421 self.checkWcs(self.exposureCrWcs, subExposure) 

422 

423 # this subRegion is not valid and should trigger an exception 

424 # from the MaskedImage class and should trigger an exception 

425 # from the WCS class for the MaskedImage 871034p_1_MI. 

426 

427 subRegion3 = lsst.geom.Box2I(lsst.geom.Point2I(100, 100), 

428 lsst.geom.Extent2I(10, 10)) 

429 

430 def getSubRegion(): 

431 self.exposureCrWcs.Factory( 

432 self.exposureCrWcs, subRegion3, afwImage.LOCAL) 

433 

434 self.assertRaises(pexExcept.LengthError, getSubRegion) 

435 

436 # this subRegion is not valid and should trigger an exception 

437 # from the MaskedImage class only for the MaskedImage small_MI. 

438 # small_MI (cols, rows) = (256, 256) 

439 

440 subRegion4 = lsst.geom.Box2I(lsst.geom.Point2I(250, 250), 

441 lsst.geom.Extent2I(10, 10)) 

442 

443 def getSubRegion(): 

444 self.exposureCrWcs.Factory( 

445 self.exposureCrWcs, subRegion4, afwImage.LOCAL) 

446 

447 self.assertRaises(pexExcept.LengthError, getSubRegion) 

448 

449 # check the sub- and parent- exposures are using the same Wcs 

450 # transformation 

451 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50), 

452 lsst.geom.Extent2I(10, 10)) 

453 subExposure = self.exposureCrWcs.Factory( 

454 self.exposureCrWcs, subBBox, afwImage.LOCAL) 

455 parentSkyPos = self.exposureCrWcs.getWcs().pixelToSky(0, 0) 

456 

457 subExpSkyPos = subExposure.getWcs().pixelToSky(0, 0) 

458 

459 self.assertSpherePointsAlmostEqual(parentSkyPos, subExpSkyPos, msg="Wcs in sub image has changed") 

460 

461 def testReadWriteFits(self): 

462 """Test readFits and writeFits. 

463 """ 

464 # This should pass without an exception 

465 mainExposure = afwImage.ExposureF(inFilePathSmall) 

466 mainExposure.info.setId(self.id) 

467 mainExposure.setDetector(self.detector) 

468 

469 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(10, 10), 

470 lsst.geom.Extent2I(40, 50)) 

471 subExposure = mainExposure.Factory( 

472 mainExposure, subBBox, afwImage.LOCAL) 

473 self.checkWcs(mainExposure, subExposure) 

474 det = subExposure.getDetector() 

475 self.assertTrue(det) 

476 

477 subExposure = afwImage.ExposureF( 

478 inFilePathSmall, subBBox, afwImage.LOCAL) 

479 

480 self.checkWcs(mainExposure, subExposure) 

481 

482 # This should throw an exception 

483 def getExposure(): 

484 afwImage.ExposureF(inFilePathSmallImage) 

485 

486 self.assertRaises(FitsError, getExposure) 

487 

488 mainExposure.setPsf(self.psf) 

489 

490 # Make sure we can write without an exception 

491 photoCalib = afwImage.PhotoCalib(1e-10, 1e-12) 

492 mainExposure.setPhotoCalib(photoCalib) 

493 

494 mainInfo = mainExposure.getInfo() 

495 for key, value in self.extras.items(): 

496 mainInfo.setComponent(key, value) 

497 

498 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

499 mainExposure.writeFits(tmpFile) 

500 

501 readExposure = type(mainExposure)(tmpFile) 

502 

503 # 

504 # Check the round-tripping 

505 # 

506 self.assertEqual(mainExposure.getFilter().getName(), 

507 readExposure.getFilter().getName()) 

508 self.assertIsNotNone(mainExposure.getFilterLabel()) 

509 self.assertEqual(mainExposure.getFilterLabel(), 

510 readExposure.getFilterLabel()) 

511 

512 self.assertEqual(photoCalib, readExposure.getPhotoCalib()) 

513 

514 readInfo = readExposure.getInfo() 

515 self.assertEqual(mainExposure.info.getId(), readInfo.id) 

516 for key, value in self.extras.items(): 

517 self.assertEqual(value, readInfo.getComponent(key)) 

518 

519 psf = readExposure.getPsf() 

520 self.assertIsNotNone(psf) 

521 self.assertEqual(psf, self.psf) 

522 # check psf property getter 

523 self.assertEqual(readExposure.psf, self.psf) 

524 

525 def checkWcs(self, parentExposure, subExposure): 

526 """Compare WCS at corner points of a sub-exposure and its parent exposure 

527 By using the function indexToPosition, we should be able to convert the indices 

528 (of the four corners (of the sub-exposure)) to positions and use the wcs 

529 to get the same sky coordinates for each. 

530 """ 

531 subMI = subExposure.getMaskedImage() 

532 subDim = subMI.getDimensions() 

533 

534 # Note: pixel positions must be computed relative to XY0 when working 

535 # with WCS 

536 mainWcs = parentExposure.getWcs() 

537 subWcs = subExposure.getWcs() 

538 

539 for xSubInd in (0, subDim.getX()-1): 

540 for ySubInd in (0, subDim.getY()-1): 

541 self.assertSpherePointsAlmostEqual( 

542 mainWcs.pixelToSky( 

543 afwImage.indexToPosition(xSubInd), 

544 afwImage.indexToPosition(ySubInd), 

545 ), 

546 subWcs.pixelToSky( 

547 afwImage.indexToPosition(xSubInd), 

548 afwImage.indexToPosition(ySubInd), 

549 )) 

550 

551 def cmpExposure(self, e1, e2): 

552 self.assertEqual(e1.getDetector().getName(), 

553 e2.getDetector().getName()) 

554 self.assertEqual(e1.getDetector().getSerial(), 

555 e2.getDetector().getSerial()) 

556 self.assertEqual(e1.getFilter().getName(), e2.getFilter().getName()) 

557 self.assertEqual(e1.getFilterLabel(), e2.getFilterLabel()) 

558 xy = lsst.geom.Point2D(0, 0) 

559 self.assertEqual(e1.getWcs().pixelToSky(xy)[0], 

560 e2.getWcs().pixelToSky(xy)[0]) 

561 self.assertEqual(e1.getPhotoCalib(), e2.getPhotoCalib()) 

562 # check PSF identity 

563 if not e1.getPsf(): 

564 self.assertFalse(e2.getPsf()) 

565 else: 

566 self.assertEqual(e1.getPsf(), e2.getPsf()) 

567 # Check extra components 

568 i1 = e1.getInfo() 

569 i2 = e2.getInfo() 

570 for key in self.extras: 

571 self.assertEqual(i1.hasComponent(key), i2.hasComponent(key)) 

572 if i1.hasComponent(key): 

573 self.assertEqual(i1.getComponent(key), i2.getComponent(key)) 

574 

575 def testCopyExposure(self): 

576 """Copy an Exposure (maybe changing type)""" 

577 

578 exposureU = afwImage.ExposureU(inFilePathSmall, allowUnsafe=True) 

579 exposureU.setWcs(self.wcs) 

580 exposureU.setDetector(self.detector) 

581 exposureU.setFilter(afwImage.Filter("g")) 

582 exposureU.setFilterLabel(afwImage.FilterLabel(band="g")) 

583 exposureU.setPsf(DummyPsf(4.0)) 

584 infoU = exposureU.getInfo() 

585 for key, value in self.extras.items(): 

586 infoU.setComponent(key, value) 

587 

588 exposureF = exposureU.convertF() 

589 self.cmpExposure(exposureF, exposureU) 

590 

591 nexp = exposureF.Factory(exposureF, False) 

592 self.cmpExposure(exposureF, nexp) 

593 

594 # Ensure that the copy was deep. 

595 # (actually this test is invalid since getDetector() returns a shared_ptr) 

596 # cen0 = exposureU.getDetector().getCenterPixel() 

597 # x0,y0 = cen0 

598 # det = exposureF.getDetector() 

599 # det.setCenterPixel(lsst.geom.Point2D(999.0, 437.8)) 

600 # self.assertEqual(exposureU.getDetector().getCenterPixel()[0], x0) 

601 # self.assertEqual(exposureU.getDetector().getCenterPixel()[1], y0) 

602 

603 def testDeepCopyData(self): 

604 """Make sure a deep copy of an Exposure has its own data (ticket #2625) 

605 """ 

606 exp = afwImage.ExposureF(6, 7) 

607 mi = exp.getMaskedImage() 

608 mi.getImage().set(100) 

609 mi.getMask().set(5) 

610 mi.getVariance().set(200) 

611 

612 expCopy = exp.clone() 

613 miCopy = expCopy.getMaskedImage() 

614 miCopy.getImage().set(-50) 

615 miCopy.getMask().set(2) 

616 miCopy.getVariance().set(175) 

617 

618 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50) 

619 self.assertTrue(np.all(miCopy.getMask().getArray() == 2)) 

620 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175) 

621 

622 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100) 

623 self.assertTrue(np.all(mi.getMask().getArray() == 5)) 

624 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200) 

625 

626 def testDeepCopySubData(self): 

627 """Make sure a deep copy of a subregion of an Exposure has its own data (ticket #2625) 

628 """ 

629 exp = afwImage.ExposureF(6, 7) 

630 mi = exp.getMaskedImage() 

631 mi.getImage().set(100) 

632 mi.getMask().set(5) 

633 mi.getVariance().set(200) 

634 

635 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 4)) 

636 expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) 

637 miCopy = expCopy.getMaskedImage() 

638 miCopy.getImage().set(-50) 

639 miCopy.getMask().set(2) 

640 miCopy.getVariance().set(175) 

641 

642 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50) 

643 self.assertTrue(np.all(miCopy.getMask().getArray() == 2)) 

644 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175) 

645 

646 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100) 

647 self.assertTrue(np.all(mi.getMask().getArray() == 5)) 

648 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200) 

649 

650 def testDeepCopyMetadata(self): 

651 """Make sure a deep copy of an Exposure has a deep copy of metadata (ticket #2568) 

652 """ 

653 exp = afwImage.ExposureF(10, 10) 

654 expMeta = exp.getMetadata() 

655 expMeta.set("foo", 5) 

656 expCopy = exp.clone() 

657 expCopyMeta = expCopy.getMetadata() 

658 expCopyMeta.set("foo", 6) 

659 self.assertEqual(expCopyMeta.getScalar("foo"), 6) 

660 # this will fail if the bug is present 

661 self.assertEqual(expMeta.getScalar("foo"), 5) 

662 

663 def testDeepCopySubMetadata(self): 

664 """Make sure a deep copy of a subregion of an Exposure has a deep copy of metadata (ticket #2568) 

665 """ 

666 exp = afwImage.ExposureF(10, 10) 

667 expMeta = exp.getMetadata() 

668 expMeta.set("foo", 5) 

669 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 5)) 

670 expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) 

671 expCopyMeta = expCopy.getMetadata() 

672 expCopyMeta.set("foo", 6) 

673 self.assertEqual(expCopyMeta.getScalar("foo"), 6) 

674 # this will fail if the bug is present 

675 self.assertEqual(expMeta.getScalar("foo"), 5) 

676 

677 def testMakeExposureLeaks(self): 

678 """Test for memory leaks in makeExposure (the test is in lsst.utils.tests.MemoryTestCase)""" 

679 afwImage.makeMaskedImage(afwImage.ImageU(lsst.geom.Extent2I(10, 20))) 

680 afwImage.makeExposure(afwImage.makeMaskedImage( 

681 afwImage.ImageU(lsst.geom.Extent2I(10, 20)))) 

682 

683 def testImageSlices(self): 

684 """Test image slicing, which generate sub-images using Box2I under the covers""" 

685 exp = afwImage.ExposureF(10, 20) 

686 mi = exp.getMaskedImage() 

687 mi.image[9, 19] = 10 

688 # N.b. Exposures don't support setting/getting the pixels so can't 

689 # replicate e.g. Image's slice tests 

690 sexp = exp[1:4, 6:10] 

691 self.assertEqual(sexp.getDimensions(), lsst.geom.ExtentI(3, 4)) 

692 sexp = exp[:, -3:, afwImage.LOCAL] 

693 self.assertEqual(sexp.getDimensions(), 

694 lsst.geom.ExtentI(exp.getWidth(), 3)) 

695 self.assertEqual(sexp.maskedImage[-1, -1, afwImage.LOCAL], 

696 exp.maskedImage[-1, -1, afwImage.LOCAL]) 

697 

698 def testConversionToScalar(self): 

699 """Test that even 1-pixel Exposures can't be converted to scalars""" 

700 im = afwImage.ExposureF(10, 20) 

701 

702 # only single pixel images may be converted 

703 self.assertRaises(TypeError, float, im) 

704 # actually, can't convert (img, msk, var) to scalar 

705 self.assertRaises(TypeError, float, im[0, 0]) 

706 

707 def testReadMetadata(self): 

708 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

709 self.exposureCrWcs.getMetadata().set("FRAZZLE", True) 

710 # This will write the main metadata (inc. FRAZZLE) to the primary HDU, and the 

711 # WCS to subsequent HDUs, along with INHERIT=T. 

712 self.exposureCrWcs.writeFits(tmpFile) 

713 # This should read the first non-empty HDU (i.e. it skips the primary), but 

714 # goes back and reads it if it finds INHERIT=T. That should let us read 

715 # frazzle and the Wcs from the PropertySet returned by 

716 # testReadMetadata. 

717 md = readMetadata(tmpFile) 

718 wcs = afwGeom.makeSkyWcs(md, False) 

719 self.assertPairsAlmostEqual(wcs.getPixelOrigin(), self.wcs.getPixelOrigin()) 

720 self.assertSpherePointsAlmostEqual(wcs.getSkyOrigin(), self.wcs.getSkyOrigin()) 

721 assert_allclose(wcs.getCdMatrix(), self.wcs.getCdMatrix(), atol=1e-10) 

722 frazzle = md.getScalar("FRAZZLE") 

723 self.assertTrue(frazzle) 

724 

725 def testArchiveKeys(self): 

726 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

727 exposure1 = afwImage.ExposureF(100, 100, self.wcs) 

728 exposure1.setPsf(self.psf) 

729 exposure1.writeFits(tmpFile) 

730 exposure2 = afwImage.ExposureF(tmpFile) 

731 self.assertFalse(exposure2.getMetadata().exists("AR_ID")) 

732 self.assertFalse(exposure2.getMetadata().exists("PSF_ID")) 

733 self.assertFalse(exposure2.getMetadata().exists("WCS_ID")) 

734 

735 def testTicket2861(self): 

736 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

737 exposure1 = afwImage.ExposureF(100, 100, self.wcs) 

738 exposure1.setPsf(self.psf) 

739 schema = afwTable.ExposureTable.makeMinimalSchema() 

740 coaddInputs = afwImage.CoaddInputs(schema, schema) 

741 exposure1.getInfo().setCoaddInputs(coaddInputs) 

742 exposure2 = afwImage.ExposureF(exposure1, True) 

743 self.assertIsNotNone(exposure2.getInfo().getCoaddInputs()) 

744 exposure2.writeFits(tmpFile) 

745 exposure3 = afwImage.ExposureF(tmpFile) 

746 self.assertIsNotNone(exposure3.getInfo().getCoaddInputs()) 

747 

748 def testGetCutout(self): 

749 wcs = self.smallExposure.getWcs() 

750 

751 dimensions = [lsst.geom.Extent2I(100, 50), lsst.geom.Extent2I(15, 15), lsst.geom.Extent2I(0, 10), 

752 lsst.geom.Extent2I(25, 30), lsst.geom.Extent2I(15, -5), 

753 2*self.smallExposure.getDimensions()] 

754 locations = [("center", self._getExposureCenter(self.smallExposure)), 

755 ("edge", wcs.pixelToSky(lsst.geom.Point2D(0, 0))), 

756 ("rounding test", wcs.pixelToSky(lsst.geom.Point2D(0.2, 0.7))), 

757 ("just inside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 + 1e-4, -0.5 + 1e-4))), 

758 ("just outside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 - 1e-4, -0.5 - 1e-4))), 

759 ("outside", wcs.pixelToSky(lsst.geom.Point2D(-1000, -1000)))] 

760 for cutoutSize in dimensions: 

761 for label, cutoutCenter in locations: 

762 msg = 'Cutout size = %s, location = %s' % (cutoutSize, label) 

763 if "outside" not in label and all(cutoutSize.gt(0)): 

764 cutout = self.smallExposure.getCutout(cutoutCenter, cutoutSize) 

765 centerInPixels = wcs.skyToPixel(cutoutCenter) 

766 precision = (1 + 1e-4)*np.sqrt(0.5)*wcs.getPixelScale(centerInPixels) 

767 self._checkCutoutProperties(cutout, cutoutSize, cutoutCenter, precision, msg) 

768 self._checkCutoutPixels( 

769 cutout, 

770 self._getValidCorners(self.smallExposure.getBBox(), cutout.getBBox()), 

771 msg) 

772 

773 # Need a valid WCS 

774 with self.assertRaises(pexExcept.LogicError, msg=msg): 

775 self.exposureMiOnly.getCutout(cutoutCenter, cutoutSize) 

776 else: 

777 with self.assertRaises(pexExcept.InvalidParameterError, msg=msg): 

778 self.smallExposure.getCutout(cutoutCenter, cutoutSize) 

779 

780 def _checkCutoutProperties(self, cutout, size, center, precision, msg): 

781 """Test whether a cutout has the desired size and position. 

782 

783 Parameters 

784 ---------- 

785 cutout : `lsst.afw.image.Exposure` 

786 The cutout to test. 

787 size : `lsst.geom.Extent2I` 

788 The expected dimensions of ``cutout``. 

789 center : `lsst.geom.SpherePoint` 

790 The expected center of ``cutout``. 

791 precision : `lsst.geom.Angle` 

792 The precision to which ``center`` must match. 

793 msg : `str` 

794 An error message suffix describing test parameters. 

795 """ 

796 newCenter = self._getExposureCenter(cutout) 

797 self.assertIsNotNone(cutout, msg=msg) 

798 self.assertSpherePointsAlmostEqual(newCenter, center, maxSep=precision, msg=msg) 

799 self.assertEqual(cutout.getWidth(), size[0], msg=msg) 

800 self.assertEqual(cutout.getHeight(), size[1], msg=msg) 

801 

802 def _checkCutoutPixels(self, cutout, validCorners, msg): 

803 """Test whether a cutout has valid/empty pixels where expected. 

804 

805 Parameters 

806 ---------- 

807 cutout : `lsst.afw.image.Exposure` 

808 The cutout to test. 

809 validCorners : iterable of `lsst.geom.Point2I` 

810 The corners of ``cutout`` that should be drawn from the original image. 

811 msg : `str` 

812 An error message suffix describing test parameters. 

813 """ 

814 mask = cutout.getMaskedImage().getMask() 

815 edgeMask = mask.getPlaneBitMask("NO_DATA") 

816 

817 for corner in cutout.getBBox().getCorners(): 

818 maskBitsSet = mask[corner] & edgeMask 

819 if corner in validCorners: 

820 self.assertEqual(maskBitsSet, 0, msg=msg) 

821 else: 

822 self.assertEqual(maskBitsSet, edgeMask, msg=msg) 

823 

824 def _getExposureCenter(self, exposure): 

825 """Return the sky coordinates of an Exposure's center. 

826 

827 Parameters 

828 ---------- 

829 exposure : `lsst.afw.image.Exposure` 

830 The image whose center is desired. 

831 

832 Returns 

833 ------- 

834 center : `lsst.geom.SpherePoint` 

835 The position at the center of ``exposure``. 

836 """ 

837 return exposure.getWcs().pixelToSky(lsst.geom.Box2D(exposure.getBBox()).getCenter()) 

838 

839 def _getValidCorners(self, imageBox, cutoutBox): 

840 """Return the corners of a cutout that are constrained by the original image. 

841 

842 Parameters 

843 ---------- 

844 imageBox: `lsst.geom.Extent2I` 

845 The bounding box of the original image. 

846 cutoutBox : `lsst.geom.Box2I` 

847 The bounding box of the cutout. 

848 

849 Returns 

850 ------- 

851 corners : iterable of `lsst.geom.Point2I` 

852 The corners that are drawn from the original image. 

853 """ 

854 return [corner for corner in cutoutBox.getCorners() if corner in imageBox] 

855 

856 

857class ExposureInfoTestCase(lsst.utils.tests.TestCase): 

858 def setUp(self): 

859 super().setUp() 

860 

861 afwImage.Filter.reset() 

862 afwImage.FilterProperty.reset() 

863 defineFilter("g", 470.0) 

864 

865 self.wcs = afwGeom.makeSkyWcs(lsst.geom.Point2D(0.0, 0.0), 

866 lsst.geom.SpherePoint(2.0, 34.0, lsst.geom.degrees), 

867 np.identity(2), 

868 ) 

869 self.photoCalib = afwImage.PhotoCalib(1.5) 

870 self.psf = DummyPsf(2.0) 

871 self.detector = DetectorWrapper().detector 

872 self.summaryStats = afwImage.ExposureSummaryStats(ra=100.0) 

873 self.polygon = afwGeom.Polygon(lsst.geom.Box2D(lsst.geom.Point2D(0.0, 0.0), 

874 lsst.geom.Point2D(25.0, 20.0))) 

875 self.coaddInputs = afwImage.CoaddInputs() 

876 self.apCorrMap = afwImage.ApCorrMap() 

877 self.transmissionCurve = afwImage.TransmissionCurve.makeIdentity() 

878 

879 self.exposureInfo = afwImage.ExposureInfo() 

880 self.gFilterLabel = afwImage.FilterLabel(band="g") 

881 self.exposureId = 42 

882 

883 def _checkAlias(self, exposureInfo, key, value, has, get): 

884 self.assertFalse(has()) 

885 self.assertFalse(exposureInfo.hasComponent(key)) 

886 self.assertIsNone(get()) 

887 self.assertIsNone(exposureInfo.getComponent(key)) 

888 

889 self.exposureInfo.setComponent(key, value) 

890 self.assertTrue(has()) 

891 self.assertTrue(exposureInfo.hasComponent(key)) 

892 self.assertIsNotNone(get()) 

893 self.assertIsNotNone(exposureInfo.getComponent(key)) 

894 self.assertEqual(get(), value) 

895 self.assertEqual(exposureInfo.getComponent(key), value) 

896 

897 self.exposureInfo.removeComponent(key) 

898 self.assertFalse(has()) 

899 self.assertFalse(exposureInfo.hasComponent(key)) 

900 self.assertIsNone(get()) 

901 self.assertIsNone(exposureInfo.getComponent(key)) 

902 

903 def testAliases(self): 

904 cls = type(self.exposureInfo) 

905 self._checkAlias(self.exposureInfo, cls.KEY_WCS, self.wcs, 

906 self.exposureInfo.hasWcs, self.exposureInfo.getWcs) 

907 self._checkAlias(self.exposureInfo, cls.KEY_PSF, self.psf, 

908 self.exposureInfo.hasPsf, self.exposureInfo.getPsf) 

909 self._checkAlias(self.exposureInfo, cls.KEY_PHOTO_CALIB, self.photoCalib, 

910 self.exposureInfo.hasPhotoCalib, self.exposureInfo.getPhotoCalib) 

911 self._checkAlias(self.exposureInfo, cls.KEY_DETECTOR, self.detector, 

912 self.exposureInfo.hasDetector, self.exposureInfo.getDetector) 

913 self._checkAlias(self.exposureInfo, cls.KEY_VALID_POLYGON, self.polygon, 

914 self.exposureInfo.hasValidPolygon, self.exposureInfo.getValidPolygon) 

915 self._checkAlias(self.exposureInfo, cls.KEY_COADD_INPUTS, self.coaddInputs, 

916 self.exposureInfo.hasCoaddInputs, self.exposureInfo.getCoaddInputs) 

917 self._checkAlias(self.exposureInfo, cls.KEY_AP_CORR_MAP, self.apCorrMap, 

918 self.exposureInfo.hasApCorrMap, self.exposureInfo.getApCorrMap) 

919 self._checkAlias(self.exposureInfo, cls.KEY_TRANSMISSION_CURVE, self.transmissionCurve, 

920 self.exposureInfo.hasTransmissionCurve, self.exposureInfo.getTransmissionCurve) 

921 self._checkAlias(self.exposureInfo, cls.KEY_SUMMARY_STATS, self.summaryStats, 

922 self.exposureInfo.hasSummaryStats, self.exposureInfo.getSummaryStats) 

923 self._checkAlias(self.exposureInfo, cls.KEY_FILTER, self.gFilterLabel, 

924 self.exposureInfo.hasFilterLabel, self.exposureInfo.getFilterLabel) 

925 

926 def testId(self): 

927 self.exposureInfo.setVisitInfo(afwImage.VisitInfo()) 

928 

929 self.assertFalse(self.exposureInfo.hasId()) 

930 self.assertIsNone(self.exposureInfo.getId()) 

931 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), 0) 

932 self.assertIsNone(self.exposureInfo.id) 

933 

934 self.exposureInfo.setId(self.exposureId) 

935 self.assertTrue(self.exposureInfo.hasId()) 

936 self.assertIsNotNone(self.exposureInfo.getId()) 

937 self.assertIsNotNone(self.exposureInfo.id) 

938 self.assertEqual(self.exposureInfo.getId(), self.exposureId) 

939 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), self.exposureId) 

940 self.assertEqual(self.exposureInfo.id, self.exposureId) 

941 

942 self.exposureInfo.id = 99899 

943 self.assertEqual(self.exposureInfo.getId(), 99899) 

944 

945 self.exposureInfo.setVisitInfo(afwImage.VisitInfo(exposureId=12321)) 

946 self.assertEqual(self.exposureInfo.id, 12321) 

947 

948 self.exposureInfo.id = None 

949 self.assertFalse(self.exposureInfo.hasId()) 

950 self.assertIsNone(self.exposureInfo.getId()) 

951 self.assertIsNone(self.exposureInfo.id) 

952 

953 def testCopy(self): 

954 # Test that ExposureInfos have independently settable state 

955 copy = afwImage.ExposureInfo(self.exposureInfo, True) 

956 self.assertEqual(self.exposureInfo.getWcs(), copy.getWcs()) 

957 

958 newWcs = afwGeom.makeSkyWcs(lsst.geom.Point2D(-23.0, 8.0), 

959 lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees), 

960 np.identity(2), 

961 ) 

962 copy.setWcs(newWcs) 

963 self.assertEqual(copy.getWcs(), newWcs) 

964 self.assertNotEqual(self.exposureInfo.getWcs(), copy.getWcs()) 

965 

966 def testMissingProperties(self): 

967 # Test that invalid properties return None instead of raising 

968 exposureInfo = afwImage.ExposureInfo() 

969 

970 self.assertIsNone(exposureInfo.id) 

971 

972 

973class ExposureNoAfwdataTestCase(lsst.utils.tests.TestCase): 

974 """Tests of Exposure that don't require afwdata. 

975 

976 These tests use the trivial exposures written to ``afw/tests/data``. 

977 """ 

978 def setUp(self): 

979 self.dataDir = os.path.join(os.path.split(__file__)[0], "data") 

980 

981 # Check the values below against what was written by comparing with 

982 # the code in `afw/tests/data/makeTestExposure.py` 

983 nx = ny = 10 

984 image = afwImage.ImageF(np.arange(nx*ny, dtype='f').reshape(nx, ny)) 

985 variance = afwImage.ImageF(np.ones((nx, ny), dtype='f')) 

986 mask = afwImage.MaskX(nx, ny) 

987 mask.array[5, 5] = 5 

988 self.maskedImage = afwImage.MaskedImageF(image, mask, variance) 

989 self.exposureId = 12345 

990 

991 self.v0PhotoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(1e6, 2e4) 

992 self.v1PhotoCalib = afwImage.PhotoCalib(1e6, 2e4) 

993 self.v1FilterLabel = afwImage.FilterLabel(physical="ha") 

994 self.v2FilterLabel = afwImage.FilterLabel(band="N656", physical="ha") 

995 

996 def testReadUnversioned(self): 

997 """Test that we can read an unversioned (implicit verison 0) file. 

998 """ 

999 filename = os.path.join(self.dataDir, "exposure-noversion.fits") 

1000 exposure = afwImage.ExposureF.readFits(filename) 

1001 

1002 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage) 

1003 

1004 self.assertEqual(exposure.info.id, self.exposureId) 

1005 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId) 

1006 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib) 

1007 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel) 

1008 

1009 def testReadVersion0(self): 

1010 """Test that we can read a version 0 file. 

1011 This file should be identical to the unversioned one, except that it 

1012 is marked as ExposureInfo version 0 in the header. 

1013 """ 

1014 filename = os.path.join(self.dataDir, "exposure-version-0.fits") 

1015 exposure = afwImage.ExposureF.readFits(filename) 

1016 

1017 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage) 

1018 

1019 self.assertEqual(exposure.info.id, self.exposureId) 

1020 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId) 

1021 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib) 

1022 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel) 

1023 

1024 # Check that the metadata reader parses the file correctly 

1025 reader = afwImage.ExposureFitsReader(filename) 

1026 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v0PhotoCalib) 

1027 self.assertEqual(reader.readPhotoCalib(), self.v0PhotoCalib) 

1028 

1029 def testReadVersion1(self): 

1030 """Test that we can read a version 1 file. 

1031 Version 1 replaced Calib with PhotoCalib. 

1032 """ 

1033 filename = os.path.join(self.dataDir, "exposure-version-1.fits") 

1034 exposure = afwImage.ExposureF.readFits(filename) 

1035 

1036 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage) 

1037 

1038 self.assertEqual(exposure.info.id, self.exposureId) 

1039 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId) 

1040 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib) 

1041 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel) 

1042 

1043 # Check that the metadata reader parses the file correctly 

1044 reader = afwImage.ExposureFitsReader(filename) 

1045 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib) 

1046 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib) 

1047 

1048 def testReadVersion2(self): 

1049 """Test that we can read a version 2 file. 

1050 Version 2 replaced Filter with FilterLabel. 

1051 """ 

1052 filename = os.path.join(self.dataDir, "exposure-version-2.fits") 

1053 exposure = afwImage.ExposureF.readFits(filename) 

1054 

1055 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage) 

1056 

1057 self.assertEqual(exposure.info.id, self.exposureId) 

1058 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId) 

1059 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib) 

1060 self.assertEqual(exposure.getFilterLabel(), self.v2FilterLabel) 

1061 

1062 # Check that the metadata reader parses the file correctly 

1063 reader = afwImage.ExposureFitsReader(filename) 

1064 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib) 

1065 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib) 

1066 

1067 def testExposureSummaryExtraComponents(self): 

1068 """Test that we can read an exposure summary with extra components. 

1069 """ 

1070 testDict = {'ra': 0.0, 

1071 'decl': 0.0, 

1072 'nonsense': 1.0} 

1073 bytes = yaml.dump(testDict, encoding='utf-8') 

1074 with self.assertWarns(FutureWarning): 

1075 summaryStats = lsst.afw.image.ExposureSummaryStats._read(bytes) 

1076 

1077 self.assertEqual(summaryStats.ra, testDict['ra']) 

1078 self.assertEqual(summaryStats.decl, testDict['decl']) 

1079 

1080 

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

1082 pass 

1083 

1084 

1085def setup_module(module): 

1086 lsst.utils.tests.init() 

1087 

1088 

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

1090 lsst.utils.tests.init() 

1091 unittest.main()