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 

31 

32import lsst.utils 

33import lsst.utils.tests 

34import lsst.geom 

35import lsst.afw.image as afwImage 

36from lsst.afw.image.utils import defineFilter 

37from lsst.afw.coord import Weather 

38import lsst.afw.geom as afwGeom 

39import lsst.afw.table as afwTable 

40import lsst.pex.exceptions as pexExcept 

41from lsst.afw.fits import readMetadata, FitsError 

42from lsst.afw.cameraGeom.testUtils import DetectorWrapper 

43from lsst.log import Log 

44from testTableArchivesLib import DummyPsf 

45 

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

47 

48try: 

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

50except pexExcept.NotFoundError: 

51 dataDir = None 

52else: 

53 InputMaskedImageName = "871034p_1_MI.fits" 

54 InputMaskedImageNameSmall = "small_MI.fits" 

55 InputImageNameSmall = "small" 

56 OutputMaskedImageName = "871034p_1_MInew.fits" 

57 

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

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

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

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

62 

63 

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

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

66 """ 

67 A test case for the Exposure Class 

68 """ 

69 

70 def setUp(self): 

71 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

72 maskedImageMD = readMetadata(inFilePathSmall) 

73 

74 self.smallExposure = afwImage.ExposureF(inFilePathSmall) 

75 self.width = maskedImage.getWidth() 

76 self.height = maskedImage.getHeight() 

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

78 self.md = maskedImageMD 

79 self.psf = DummyPsf(2.0) 

80 self.detector = DetectorWrapper().detector 

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

82 

83 self.exposureBlank = afwImage.ExposureF() 

84 self.exposureMiOnly = afwImage.makeExposure(maskedImage) 

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

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

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

88 # test with ExtentI(100, 100) too 

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

90 

91 afwImage.Filter.reset() 

92 afwImage.FilterProperty.reset() 

93 

94 defineFilter("g", 470.0) 

95 

96 def tearDown(self): 

97 del self.smallExposure 

98 del self.wcs 

99 del self.psf 

100 del self.detector 

101 del self.extras 

102 

103 del self.exposureBlank 

104 del self.exposureMiOnly 

105 del self.exposureMiWcs 

106 del self.exposureCrWcs 

107 del self.exposureCrOnly 

108 

109 def testGetMaskedImage(self): 

110 """ 

111 Test to ensure a MaskedImage can be obtained from each 

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

113 therefore each of the Exposures should return a MaskedImage. 

114 

115 MaskedImage class should throw appropriate 

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

117 obtained. 

118 """ 

119 maskedImageBlank = self.exposureBlank.getMaskedImage() 

120 blankWidth = maskedImageBlank.getWidth() 

121 blankHeight = maskedImageBlank.getHeight() 

122 if blankWidth != blankHeight != 0: 

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

124 

125 maskedImageMiOnly = self.exposureMiOnly.getMaskedImage() 

126 miOnlyWidth = maskedImageMiOnly.getWidth() 

127 miOnlyHeight = maskedImageMiOnly.getHeight() 

128 self.assertAlmostEqual(miOnlyWidth, self.width) 

129 self.assertAlmostEqual(miOnlyHeight, self.height) 

130 

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

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

133 # the WCS being copied/created. 

134 

135 maskedImageMiWcs = self.exposureMiWcs.getMaskedImage() 

136 miWcsWidth = maskedImageMiWcs.getWidth() 

137 miWcsHeight = maskedImageMiWcs.getHeight() 

138 self.assertAlmostEqual(miWcsWidth, self.width) 

139 self.assertAlmostEqual(miWcsHeight, self.height) 

140 

141 maskedImageCrWcs = self.exposureCrWcs.getMaskedImage() 

142 crWcsWidth = maskedImageCrWcs.getWidth() 

143 crWcsHeight = maskedImageCrWcs.getHeight() 

144 if crWcsWidth != crWcsHeight != 0: 

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

146 

147 maskedImageCrOnly = self.exposureCrOnly.getMaskedImage() 

148 crOnlyWidth = maskedImageCrOnly.getWidth() 

149 crOnlyHeight = maskedImageCrOnly.getHeight() 

150 if crOnlyWidth != crOnlyHeight != 0: 

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

152 

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

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

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

156 # check width/height properties 

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

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

159 

160 def testProperties(self): 

161 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, 

162 self.exposureMiOnly.getMaskedImage()) 

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

164 mi2.image.array[:] = 5.0 

165 mi2.variance.array[:] = 3.0 

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

167 self.exposureMiOnly.maskedImage = mi2 

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

169 self.assertImagesEqual(self.exposureMiOnly.image, 

170 self.exposureMiOnly.maskedImage.image) 

171 

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

173 image3.array[:] = 3.0 

174 self.exposureMiOnly.image = image3 

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

176 

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

178 mask3.array[:] = 0x2 

179 self.exposureMiOnly.mask = mask3 

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

181 

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

183 var3.array[:] = 2.0 

184 self.exposureMiOnly.variance = var3 

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

186 

187 # Test the property getter for a null VisitInfo. 

188 self.assertIsNone(self.exposureMiOnly.visitInfo) 

189 

190 def testGetWcs(self): 

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

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

193 """ 

194 # These exposures don't contain a WCS 

195 self.assertIsNone(self.exposureBlank.getWcs()) 

196 self.assertIsNone(self.exposureMiOnly.getWcs()) 

197 self.assertIsNone(self.exposureCrOnly.getWcs()) 

198 

199 # These exposures should contain a WCS 

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

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

202 

203 def testExposureInfoConstructor(self): 

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

205 exposureInfo = afwImage.ExposureInfo() 

206 exposureInfo.setWcs(self.wcs) 

207 exposureInfo.setDetector(self.detector) 

208 gFilter = afwImage.Filter("g") 

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

210 exposureInfo.setFilter(gFilter) 

211 exposureInfo.setFilterLabel(gFilterLabel) 

212 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

213 exposure = afwImage.ExposureF(maskedImage, exposureInfo) 

214 

215 self.assertTrue(exposure.hasWcs()) 

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

217 self.wcs.getPixelOrigin()) 

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

219 self.detector.getName()) 

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

221 self.detector.getSerial()) 

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

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

224 

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

226 # check the ExposureInfo property 

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

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

229 self.wcs.getPixelOrigin()) 

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

231 self.detector.getName()) 

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

233 self.detector.getSerial()) 

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

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

236 

237 def testNullWcs(self): 

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

239 

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

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

242 """ 

243 maskedImage = self.exposureMiOnly.getMaskedImage() 

244 exposure = afwImage.ExposureF(maskedImage, None) 

245 self.assertFalse(exposure.hasWcs()) 

246 self.assertFalse(exposure.hasPsf()) 

247 

248 def testExposureInfoSetNone(self): 

249 exposureInfo = afwImage.ExposureInfo() 

250 exposureInfo.setDetector(None) 

251 exposureInfo.setValidPolygon(None) 

252 exposureInfo.setPsf(None) 

253 exposureInfo.setWcs(None) 

254 exposureInfo.setPhotoCalib(None) 

255 exposureInfo.setCoaddInputs(None) 

256 exposureInfo.setVisitInfo(None) 

257 exposureInfo.setApCorrMap(None) 

258 for key in self.extras: 

259 exposureInfo.setComponent(key, None) 

260 

261 def testSetExposureInfo(self): 

262 exposureInfo = afwImage.ExposureInfo() 

263 exposureInfo.setWcs(self.wcs) 

264 exposureInfo.setDetector(self.detector) 

265 gFilter = afwImage.Filter("g") 

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

267 exposureInfo.setFilter(gFilter) 

268 exposureInfo.setFilterLabel(gFilterLabel) 

269 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

270 exposure = afwImage.ExposureF(maskedImage) 

271 self.assertFalse(exposure.hasWcs()) 

272 

273 exposure.setInfo(exposureInfo) 

274 

275 self.assertTrue(exposure.hasWcs()) 

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

277 self.wcs.getPixelOrigin()) 

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

279 self.detector.getName()) 

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

281 self.detector.getSerial()) 

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

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

284 

285 # test properties 

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

287 self.assertEqual(exposure.filterLabel, gFilterLabel) 

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

289 

290 def testDefaultFilter(self): 

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

292 """ 

293 exposureInfo = afwImage.ExposureInfo() 

294 noFilter = afwImage.Filter() 

295 exposureInfo.setFilter(noFilter) 

296 self.assertFalse(exposureInfo.hasFilterLabel()) 

297 self.assertIsNone(exposureInfo.getFilterLabel()) 

298 

299 def testVisitInfoFitsPersistence(self): 

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

301 exposureId = 5 

302 exposureTime = 12.3 

303 boresightRotAngle = 45.6 * lsst.geom.degrees 

304 weather = Weather(1.1, 2.2, 0.3) 

305 visitInfo = afwImage.VisitInfo( 

306 exposureId=exposureId, 

307 exposureTime=exposureTime, 

308 boresightRotAngle=boresightRotAngle, 

309 weather=weather, 

310 ) 

311 photoCalib = afwImage.PhotoCalib(3.4, 5.6) 

312 exposureInfo = afwImage.ExposureInfo() 

313 exposureInfo.setVisitInfo(visitInfo) 

314 exposureInfo.setPhotoCalib(photoCalib) 

315 exposureInfo.setDetector(self.detector) 

316 gFilter = afwImage.Filter("g") 

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

318 exposureInfo.setFilter(gFilter) 

319 exposureInfo.setFilterLabel(gFilterLabel) 

320 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

321 exposure = afwImage.ExposureF(maskedImage, exposureInfo) 

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

323 exposure.writeFits(tmpFile) 

324 rtExposure = afwImage.ExposureF(tmpFile) 

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

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

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

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

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

330 

331 # Test property getters. 

332 self.assertEqual(rtExposure.photoCalib, photoCalib) 

333 self.assertEqual(rtExposure.filterLabel, gFilterLabel) 

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

335 self.assertIsNotNone(rtExposure.visitInfo) 

336 

337 def testSetMembers(self): 

338 """ 

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

340 """ 

341 exposure = afwImage.ExposureF() 

342 

343 maskedImage = afwImage.MaskedImageF(inFilePathSmall) 

344 exposure.setMaskedImage(maskedImage) 

345 exposure.setWcs(self.wcs) 

346 exposure.setDetector(self.detector) 

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

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

349 

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

351 self.detector.getName()) 

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

353 self.detector.getSerial()) 

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

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

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

357 

358 # The PhotoCalib tests are in test_photoCalib.py; 

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

360 self.assertIsNone(exposure.getPhotoCalib()) 

361 

362 photoCalib = afwImage.PhotoCalib(511.1, 44.4) 

363 exposure.setPhotoCalib(photoCalib) 

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

365 

366 # Psfs next 

367 self.assertFalse(exposure.hasPsf()) 

368 exposure.setPsf(self.psf) 

369 self.assertTrue(exposure.hasPsf()) 

370 

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

372 

373 # extras next 

374 info = exposure.getInfo() 

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

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

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

378 info.setComponent(key, value) 

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

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

381 info.removeComponent(key) 

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

383 

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

385 # that already has both 

386 self.exposureMiWcs.setMaskedImage(maskedImage) 

387 exposure.setWcs(self.wcs) 

388 

389 def testHasWcs(self): 

390 """ 

391 Test if an Exposure has a WCS or not. 

392 """ 

393 self.assertFalse(self.exposureBlank.hasWcs()) 

394 

395 self.assertFalse(self.exposureMiOnly.hasWcs()) 

396 self.assertTrue(self.exposureMiWcs.hasWcs()) 

397 self.assertTrue(self.exposureCrWcs.hasWcs()) 

398 self.assertFalse(self.exposureCrOnly.hasWcs()) 

399 

400 def testGetSubExposure(self): 

401 """ 

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

403 

404 The MaskedImage class should throw a 

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

406 subRegion is not fully contained within the original 

407 MaskedImage. 

408 

409 """ 

410 # 

411 # This subExposure is valid 

412 # 

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

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

415 subExposure = self.exposureCrWcs.Factory( 

416 self.exposureCrWcs, subBBox, afwImage.LOCAL) 

417 

418 self.checkWcs(self.exposureCrWcs, subExposure) 

419 

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

421 # from the MaskedImage class and should trigger an exception 

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

423 

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

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

426 

427 def getSubRegion(): 

428 self.exposureCrWcs.Factory( 

429 self.exposureCrWcs, subRegion3, afwImage.LOCAL) 

430 

431 self.assertRaises(pexExcept.LengthError, getSubRegion) 

432 

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

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

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

436 

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

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

439 

440 def getSubRegion(): 

441 self.exposureCrWcs.Factory( 

442 self.exposureCrWcs, subRegion4, afwImage.LOCAL) 

443 

444 self.assertRaises(pexExcept.LengthError, getSubRegion) 

445 

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

447 # transformation 

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

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

450 subExposure = self.exposureCrWcs.Factory( 

451 self.exposureCrWcs, subBBox, afwImage.LOCAL) 

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

453 

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

455 

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

457 

458 def testReadWriteFits(self): 

459 """Test readFits and writeFits. 

460 """ 

461 # This should pass without an exception 

462 mainExposure = afwImage.ExposureF(inFilePathSmall) 

463 mainExposure.setDetector(self.detector) 

464 

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

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

467 subExposure = mainExposure.Factory( 

468 mainExposure, subBBox, afwImage.LOCAL) 

469 self.checkWcs(mainExposure, subExposure) 

470 det = subExposure.getDetector() 

471 self.assertTrue(det) 

472 

473 subExposure = afwImage.ExposureF( 

474 inFilePathSmall, subBBox, afwImage.LOCAL) 

475 

476 self.checkWcs(mainExposure, subExposure) 

477 

478 # This should throw an exception 

479 def getExposure(): 

480 afwImage.ExposureF(inFilePathSmallImage) 

481 

482 self.assertRaises(FitsError, getExposure) 

483 

484 mainExposure.setPsf(self.psf) 

485 

486 # Make sure we can write without an exception 

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

488 mainExposure.setPhotoCalib(photoCalib) 

489 

490 mainInfo = mainExposure.getInfo() 

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

492 mainInfo.setComponent(key, value) 

493 

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

495 mainExposure.writeFits(tmpFile) 

496 

497 readExposure = type(mainExposure)(tmpFile) 

498 

499 # 

500 # Check the round-tripping 

501 # 

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

503 readExposure.getFilter().getName()) 

504 self.assertIsNotNone(mainExposure.getFilterLabel()) 

505 self.assertEqual(mainExposure.getFilterLabel(), 

506 readExposure.getFilterLabel()) 

507 

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

509 

510 readInfo = readExposure.getInfo() 

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

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

513 

514 psf = readExposure.getPsf() 

515 self.assertIsNotNone(psf) 

516 self.assertEqual(psf, self.psf) 

517 # check psf property getter 

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

519 

520 def checkWcs(self, parentExposure, subExposure): 

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

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

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

524 to get the same sky coordinates for each. 

525 """ 

526 subMI = subExposure.getMaskedImage() 

527 subDim = subMI.getDimensions() 

528 

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

530 # with WCS 

531 mainWcs = parentExposure.getWcs() 

532 subWcs = subExposure.getWcs() 

533 

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

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

536 self.assertSpherePointsAlmostEqual( 

537 mainWcs.pixelToSky( 

538 afwImage.indexToPosition(xSubInd), 

539 afwImage.indexToPosition(ySubInd), 

540 ), 

541 subWcs.pixelToSky( 

542 afwImage.indexToPosition(xSubInd), 

543 afwImage.indexToPosition(ySubInd), 

544 )) 

545 

546 def cmpExposure(self, e1, e2): 

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

548 e2.getDetector().getName()) 

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

550 e2.getDetector().getSerial()) 

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

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

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

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

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

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

557 # check PSF identity 

558 if not e1.getPsf(): 

559 self.assertFalse(e2.getPsf()) 

560 else: 

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

562 # Check extra components 

563 i1 = e1.getInfo() 

564 i2 = e2.getInfo() 

565 for key in self.extras: 

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

567 if i1.hasComponent(key): 

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

569 

570 def testCopyExposure(self): 

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

572 

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

574 exposureU.setWcs(self.wcs) 

575 exposureU.setDetector(self.detector) 

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

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

578 exposureU.setPsf(DummyPsf(4.0)) 

579 infoU = exposureU.getInfo() 

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

581 infoU.setComponent(key, value) 

582 

583 exposureF = exposureU.convertF() 

584 self.cmpExposure(exposureF, exposureU) 

585 

586 nexp = exposureF.Factory(exposureF, False) 

587 self.cmpExposure(exposureF, nexp) 

588 

589 # Ensure that the copy was deep. 

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

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

592 # x0,y0 = cen0 

593 # det = exposureF.getDetector() 

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

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

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

597 

598 def testDeepCopyData(self): 

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

600 """ 

601 exp = afwImage.ExposureF(6, 7) 

602 mi = exp.getMaskedImage() 

603 mi.getImage().set(100) 

604 mi.getMask().set(5) 

605 mi.getVariance().set(200) 

606 

607 expCopy = exp.clone() 

608 miCopy = expCopy.getMaskedImage() 

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

610 miCopy.getMask().set(2) 

611 miCopy.getVariance().set(175) 

612 

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

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

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

616 

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

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

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

620 

621 def testDeepCopySubData(self): 

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

623 """ 

624 exp = afwImage.ExposureF(6, 7) 

625 mi = exp.getMaskedImage() 

626 mi.getImage().set(100) 

627 mi.getMask().set(5) 

628 mi.getVariance().set(200) 

629 

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

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

632 miCopy = expCopy.getMaskedImage() 

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

634 miCopy.getMask().set(2) 

635 miCopy.getVariance().set(175) 

636 

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

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

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

640 

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

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

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

644 

645 def testDeepCopyMetadata(self): 

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

647 """ 

648 exp = afwImage.ExposureF(10, 10) 

649 expMeta = exp.getMetadata() 

650 expMeta.set("foo", 5) 

651 expCopy = exp.clone() 

652 expCopyMeta = expCopy.getMetadata() 

653 expCopyMeta.set("foo", 6) 

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

655 # this will fail if the bug is present 

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

657 

658 def testDeepCopySubMetadata(self): 

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

660 """ 

661 exp = afwImage.ExposureF(10, 10) 

662 expMeta = exp.getMetadata() 

663 expMeta.set("foo", 5) 

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

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

666 expCopyMeta = expCopy.getMetadata() 

667 expCopyMeta.set("foo", 6) 

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

669 # this will fail if the bug is present 

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

671 

672 def testMakeExposureLeaks(self): 

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

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

675 afwImage.makeExposure(afwImage.makeMaskedImage( 

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

677 

678 def testImageSlices(self): 

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

680 exp = afwImage.ExposureF(10, 20) 

681 mi = exp.getMaskedImage() 

682 mi.image[9, 19] = 10 

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

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

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

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

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

688 self.assertEqual(sexp.getDimensions(), 

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

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

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

692 

693 def testConversionToScalar(self): 

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

695 im = afwImage.ExposureF(10, 20) 

696 

697 # only single pixel images may be converted 

698 self.assertRaises(TypeError, float, im) 

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

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

701 

702 def testReadMetadata(self): 

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

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

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

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

707 self.exposureCrWcs.writeFits(tmpFile) 

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

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

710 # frazzle and the Wcs from the PropertySet returned by 

711 # testReadMetadata. 

712 md = readMetadata(tmpFile) 

713 wcs = afwGeom.makeSkyWcs(md, False) 

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

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

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

717 frazzle = md.getScalar("FRAZZLE") 

718 self.assertTrue(frazzle) 

719 

720 def testArchiveKeys(self): 

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

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

723 exposure1.setPsf(self.psf) 

724 exposure1.writeFits(tmpFile) 

725 exposure2 = afwImage.ExposureF(tmpFile) 

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

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

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

729 

730 def testTicket2861(self): 

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

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

733 exposure1.setPsf(self.psf) 

734 schema = afwTable.ExposureTable.makeMinimalSchema() 

735 coaddInputs = afwImage.CoaddInputs(schema, schema) 

736 exposure1.getInfo().setCoaddInputs(coaddInputs) 

737 exposure2 = afwImage.ExposureF(exposure1, True) 

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

739 exposure2.writeFits(tmpFile) 

740 exposure3 = afwImage.ExposureF(tmpFile) 

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

742 

743 def testGetCutout(self): 

744 wcs = self.smallExposure.getWcs() 

745 

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

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

748 2*self.smallExposure.getDimensions()] 

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

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

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

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

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

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

755 for cutoutSize in dimensions: 

756 for label, cutoutCenter in locations: 

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

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

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

760 centerInPixels = wcs.skyToPixel(cutoutCenter) 

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

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

763 self._checkCutoutPixels( 

764 cutout, 

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

766 msg) 

767 

768 # Need a valid WCS 

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

770 self.exposureMiOnly.getCutout(cutoutCenter, cutoutSize) 

771 else: 

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

773 self.smallExposure.getCutout(cutoutCenter, cutoutSize) 

774 

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

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

777 

778 Parameters 

779 ---------- 

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

781 The cutout to test. 

782 size : `lsst.geom.Extent2I` 

783 The expected dimensions of ``cutout``. 

784 center : `lsst.geom.SpherePoint` 

785 The expected center of ``cutout``. 

786 precision : `lsst.geom.Angle` 

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

788 msg : `str` 

789 An error message suffix describing test parameters. 

790 """ 

791 newCenter = self._getExposureCenter(cutout) 

792 self.assertIsNotNone(cutout, msg=msg) 

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

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

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

796 

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

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

799 

800 Parameters 

801 ---------- 

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

803 The cutout to test. 

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

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

806 msg : `str` 

807 An error message suffix describing test parameters. 

808 """ 

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

810 edgeMask = mask.getPlaneBitMask("NO_DATA") 

811 

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

813 maskBitsSet = mask[corner] & edgeMask 

814 if corner in validCorners: 

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

816 else: 

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

818 

819 def _getExposureCenter(self, exposure): 

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

821 

822 Parameters 

823 ---------- 

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

825 The image whose center is desired. 

826 

827 Returns 

828 ------- 

829 center : `lsst.geom.SpherePoint` 

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

831 """ 

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

833 

834 def _getValidCorners(self, imageBox, cutoutBox): 

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

836 

837 Parameters 

838 ---------- 

839 imageBox: `lsst.geom.Extent2I` 

840 The bounding box of the original image. 

841 cutoutBox : `lsst.geom.Box2I` 

842 The bounding box of the cutout. 

843 

844 Returns 

845 ------- 

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

847 The corners that are drawn from the original image. 

848 """ 

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

850 

851 

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

853 def setUp(self): 

854 super().setUp() 

855 

856 afwImage.Filter.reset() 

857 afwImage.FilterProperty.reset() 

858 defineFilter("g", 470.0) 

859 

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

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

862 np.identity(2), 

863 ) 

864 self.photoCalib = afwImage.PhotoCalib(1.5) 

865 self.psf = DummyPsf(2.0) 

866 self.detector = DetectorWrapper().detector 

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

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

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

870 self.coaddInputs = afwImage.CoaddInputs() 

871 self.apCorrMap = afwImage.ApCorrMap() 

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

873 

874 self.exposureInfo = afwImage.ExposureInfo() 

875 gFilter = afwImage.Filter("g") 

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

877 self.exposureInfo.setFilter(gFilter) 

878 self.exposureInfo.setFilterLabel(gFilterLabel) 

879 

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

881 self.assertFalse(has()) 

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

883 self.assertIsNone(get()) 

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

885 

886 self.exposureInfo.setComponent(key, value) 

887 self.assertTrue(has()) 

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

889 self.assertIsNotNone(get()) 

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

891 self.assertEqual(get(), value) 

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

893 

894 self.exposureInfo.removeComponent(key) 

895 self.assertFalse(has()) 

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

897 self.assertIsNone(get()) 

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

899 

900 def testAliases(self): 

901 cls = type(self.exposureInfo) 

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

903 self.exposureInfo.hasWcs, self.exposureInfo.getWcs) 

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

905 self.exposureInfo.hasPsf, self.exposureInfo.getPsf) 

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

907 self.exposureInfo.hasPhotoCalib, self.exposureInfo.getPhotoCalib) 

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

909 self.exposureInfo.hasDetector, self.exposureInfo.getDetector) 

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

911 self.exposureInfo.hasValidPolygon, self.exposureInfo.getValidPolygon) 

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

913 self.exposureInfo.hasCoaddInputs, self.exposureInfo.getCoaddInputs) 

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

915 self.exposureInfo.hasApCorrMap, self.exposureInfo.getApCorrMap) 

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

917 self.exposureInfo.hasTransmissionCurve, self.exposureInfo.getTransmissionCurve) 

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

919 self.exposureInfo.hasSummaryStats, self.exposureInfo.getSummaryStats) 

920 

921 def testCopy(self): 

922 # Test that ExposureInfos have independently settable state 

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

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

925 

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

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

928 np.identity(2), 

929 ) 

930 copy.setWcs(newWcs) 

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

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

933 

934 

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

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

937 

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

939 """ 

940 def setUp(self): 

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

942 

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

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

945 nx = ny = 10 

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

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

948 mask = afwImage.MaskX(nx, ny) 

949 mask.array[5, 5] = 5 

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

951 

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

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

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

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

956 

957 def testReadUnversioned(self): 

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

959 """ 

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

961 exposure = afwImage.ExposureF.readFits(filename) 

962 

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

964 

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

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

967 

968 def testReadVersion0(self): 

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

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

971 is marked as ExposureInfo version 0 in the header. 

972 """ 

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

974 exposure = afwImage.ExposureF.readFits(filename) 

975 

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

977 

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

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

980 

981 # Check that the metadata reader parses the file correctly 

982 reader = afwImage.ExposureFitsReader(filename) 

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

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

985 

986 def testReadVersion1(self): 

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

988 Version 1 replaced Calib with PhotoCalib. 

989 """ 

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

991 exposure = afwImage.ExposureF.readFits(filename) 

992 

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

994 

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

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

997 

998 # Check that the metadata reader parses the file correctly 

999 reader = afwImage.ExposureFitsReader(filename) 

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

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

1002 

1003 def testReadVersion2(self): 

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

1005 Version 2 replaced Filter with FilterLabel. 

1006 """ 

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

1008 exposure = afwImage.ExposureF.readFits(filename) 

1009 

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

1011 

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

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

1014 

1015 # Check that the metadata reader parses the file correctly 

1016 reader = afwImage.ExposureFitsReader(filename) 

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

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

1019 

1020 

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

1022 pass 

1023 

1024 

1025def setup_module(module): 

1026 lsst.utils.tests.init() 

1027 

1028 

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

1030 lsst.utils.tests.init() 

1031 unittest.main()