Coverage for tests/test_exposure.py: 13%
Shortcuts 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
Shortcuts 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/>.
22"""
23Test lsst.afw.image.Exposure
24"""
26import os.path
27import unittest
29import numpy as np
30from numpy.testing import assert_allclose
31import yaml
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
47Log.getLogger("lsst.afw.image.Mask").setLevel(Log.INFO)
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"
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)
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 """
71 def setUp(self):
72 maskedImage = afwImage.MaskedImageF(inFilePathSmall)
73 maskedImageMD = readMetadata(inFilePathSmall)
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)}
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))
93 afwImage.Filter.reset()
94 afwImage.FilterProperty.reset()
96 defineFilter("g", 470.0)
98 def tearDown(self):
99 del self.smallExposure
100 del self.wcs
101 del self.psf
102 del self.detector
103 del self.extras
105 del self.exposureBlank
106 del self.exposureMiOnly
107 del self.exposureMiWcs
108 del self.exposureCrWcs
109 del self.exposureCrOnly
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.
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")
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)
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.
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)
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")
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")
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)
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)
174 image3 = afwImage.ImageF(self.exposureMiOnly.getDimensions())
175 image3.array[:] = 3.0
176 self.exposureMiOnly.image = image3
177 self.assertImagesEqual(self.exposureMiOnly.image, image3)
179 mask3 = afwImage.MaskX(self.exposureMiOnly.getDimensions())
180 mask3.array[:] = 0x2
181 self.exposureMiOnly.mask = mask3
182 self.assertMasksEqual(self.exposureMiOnly.mask, mask3)
184 var3 = afwImage.ImageF(self.exposureMiOnly.getDimensions())
185 var3.array[:] = 2.0
186 self.exposureMiOnly.variance = var3
187 self.assertImagesEqual(self.exposureMiOnly.variance, var3)
189 # Test the property getter for a null VisitInfo.
190 self.assertIsNone(self.exposureMiOnly.visitInfo)
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())
201 # These exposures should contain a WCS
202 self.assertEqual(self.wcs, self.exposureMiWcs.getWcs())
203 self.assertEqual(self.wcs, self.exposureCrWcs.getWcs())
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)
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)
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)
239 def testNullWcs(self):
240 """Test that an Exposure constructed with second argument None is usable
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())
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)
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())
276 exposure.setInfo(exposureInfo)
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)
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)
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())
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)
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)
340 def testSetMembers(self):
341 """
342 Test that the MaskedImage and the WCS of an Exposure can be set.
343 """
344 exposure = afwImage.ExposureF()
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"))
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)
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())
365 photoCalib = afwImage.PhotoCalib(511.1, 44.4)
366 exposure.setPhotoCalib(photoCalib)
367 self.assertEqual(exposure.getPhotoCalib(), photoCalib)
369 # Psfs next
370 self.assertFalse(exposure.hasPsf())
371 exposure.setPsf(self.psf)
372 self.assertTrue(exposure.hasPsf())
374 exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf
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))
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)
392 def testHasWcs(self):
393 """
394 Test if an Exposure has a WCS or not.
395 """
396 self.assertFalse(self.exposureBlank.hasWcs())
398 self.assertFalse(self.exposureMiOnly.hasWcs())
399 self.assertTrue(self.exposureMiWcs.hasWcs())
400 self.assertTrue(self.exposureCrWcs.hasWcs())
401 self.assertFalse(self.exposureCrOnly.hasWcs())
403 def testGetSubExposure(self):
404 """
405 Test that a subExposure of the original Exposure can be obtained.
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.
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)
421 self.checkWcs(self.exposureCrWcs, subExposure)
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.
427 subRegion3 = lsst.geom.Box2I(lsst.geom.Point2I(100, 100),
428 lsst.geom.Extent2I(10, 10))
430 def getSubRegion():
431 self.exposureCrWcs.Factory(
432 self.exposureCrWcs, subRegion3, afwImage.LOCAL)
434 self.assertRaises(pexExcept.LengthError, getSubRegion)
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)
440 subRegion4 = lsst.geom.Box2I(lsst.geom.Point2I(250, 250),
441 lsst.geom.Extent2I(10, 10))
443 def getSubRegion():
444 self.exposureCrWcs.Factory(
445 self.exposureCrWcs, subRegion4, afwImage.LOCAL)
447 self.assertRaises(pexExcept.LengthError, getSubRegion)
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)
457 subExpSkyPos = subExposure.getWcs().pixelToSky(0, 0)
459 self.assertSpherePointsAlmostEqual(parentSkyPos, subExpSkyPos, msg="Wcs in sub image has changed")
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)
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)
477 subExposure = afwImage.ExposureF(
478 inFilePathSmall, subBBox, afwImage.LOCAL)
480 self.checkWcs(mainExposure, subExposure)
482 # This should throw an exception
483 def getExposure():
484 afwImage.ExposureF(inFilePathSmallImage)
486 self.assertRaises(FitsError, getExposure)
488 mainExposure.setPsf(self.psf)
490 # Make sure we can write without an exception
491 photoCalib = afwImage.PhotoCalib(1e-10, 1e-12)
492 mainExposure.setPhotoCalib(photoCalib)
494 mainInfo = mainExposure.getInfo()
495 for key, value in self.extras.items():
496 mainInfo.setComponent(key, value)
498 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
499 mainExposure.writeFits(tmpFile)
501 readExposure = type(mainExposure)(tmpFile)
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())
512 self.assertEqual(photoCalib, readExposure.getPhotoCalib())
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))
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)
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()
534 # Note: pixel positions must be computed relative to XY0 when working
535 # with WCS
536 mainWcs = parentExposure.getWcs()
537 subWcs = subExposure.getWcs()
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 ))
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))
575 def testCopyExposure(self):
576 """Copy an Exposure (maybe changing type)"""
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)
588 exposureF = exposureU.convertF()
589 self.cmpExposure(exposureF, exposureU)
591 nexp = exposureF.Factory(exposureF, False)
592 self.cmpExposure(exposureF, nexp)
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)
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)
612 expCopy = exp.clone()
613 miCopy = expCopy.getMaskedImage()
614 miCopy.getImage().set(-50)
615 miCopy.getMask().set(2)
616 miCopy.getVariance().set(175)
618 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50)
619 self.assertTrue(np.all(miCopy.getMask().getArray() == 2))
620 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175)
622 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100)
623 self.assertTrue(np.all(mi.getMask().getArray() == 5))
624 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200)
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)
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)
642 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50)
643 self.assertTrue(np.all(miCopy.getMask().getArray() == 2))
644 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175)
646 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100)
647 self.assertTrue(np.all(mi.getMask().getArray() == 5))
648 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200)
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)
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)
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))))
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])
698 def testConversionToScalar(self):
699 """Test that even 1-pixel Exposures can't be converted to scalars"""
700 im = afwImage.ExposureF(10, 20)
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])
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)
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"))
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())
748 def testGetCutout(self):
749 wcs = self.smallExposure.getWcs()
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)
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)
780 def _checkCutoutProperties(self, cutout, size, center, precision, msg):
781 """Test whether a cutout has the desired size and position.
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)
802 def _checkCutoutPixels(self, cutout, validCorners, msg):
803 """Test whether a cutout has valid/empty pixels where expected.
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")
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)
824 def _getExposureCenter(self, exposure):
825 """Return the sky coordinates of an Exposure's center.
827 Parameters
828 ----------
829 exposure : `lsst.afw.image.Exposure`
830 The image whose center is desired.
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())
839 def _getValidCorners(self, imageBox, cutoutBox):
840 """Return the corners of a cutout that are constrained by the original image.
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.
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]
857class ExposureInfoTestCase(lsst.utils.tests.TestCase):
858 def setUp(self):
859 super().setUp()
861 afwImage.Filter.reset()
862 afwImage.FilterProperty.reset()
863 defineFilter("g", 470.0)
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()
879 self.exposureInfo = afwImage.ExposureInfo()
880 self.gFilterLabel = afwImage.FilterLabel(band="g")
881 self.exposureId = 42
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))
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)
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))
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)
926 def testId(self):
927 self.exposureInfo.setVisitInfo(afwImage.VisitInfo())
929 self.assertFalse(self.exposureInfo.hasId())
930 self.assertIsNone(self.exposureInfo.getId())
931 with self.assertWarns(FutureWarning):
932 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), 0)
933 self.assertIsNone(self.exposureInfo.id)
935 self.exposureInfo.setId(self.exposureId)
936 self.assertTrue(self.exposureInfo.hasId())
937 self.assertIsNotNone(self.exposureInfo.getId())
938 self.assertIsNotNone(self.exposureInfo.id)
939 self.assertEqual(self.exposureInfo.getId(), self.exposureId)
940 with self.assertWarns(FutureWarning):
941 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), self.exposureId)
942 self.assertEqual(self.exposureInfo.id, self.exposureId)
944 self.exposureInfo.id = 99899
945 self.assertEqual(self.exposureInfo.getId(), 99899)
947 self.exposureInfo.setVisitInfo(afwImage.VisitInfo(exposureId=12321))
948 self.assertEqual(self.exposureInfo.id, 12321)
950 self.exposureInfo.id = None
951 self.assertFalse(self.exposureInfo.hasId())
952 self.assertIsNone(self.exposureInfo.getId())
953 self.assertIsNone(self.exposureInfo.id)
955 def testCopy(self):
956 # Test that ExposureInfos have independently settable state
957 copy = afwImage.ExposureInfo(self.exposureInfo, True)
958 self.assertEqual(self.exposureInfo.getWcs(), copy.getWcs())
960 newWcs = afwGeom.makeSkyWcs(lsst.geom.Point2D(-23.0, 8.0),
961 lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees),
962 np.identity(2),
963 )
964 copy.setWcs(newWcs)
965 self.assertEqual(copy.getWcs(), newWcs)
966 self.assertNotEqual(self.exposureInfo.getWcs(), copy.getWcs())
968 def testMissingProperties(self):
969 # Test that invalid properties return None instead of raising
970 exposureInfo = afwImage.ExposureInfo()
972 self.assertIsNone(exposureInfo.id)
975class ExposureNoAfwdataTestCase(lsst.utils.tests.TestCase):
976 """Tests of Exposure that don't require afwdata.
978 These tests use the trivial exposures written to ``afw/tests/data``.
979 """
980 def setUp(self):
981 self.dataDir = os.path.join(os.path.split(__file__)[0], "data")
983 # Check the values below against what was written by comparing with
984 # the code in `afw/tests/data/makeTestExposure.py`
985 nx = ny = 10
986 image = afwImage.ImageF(np.arange(nx*ny, dtype='f').reshape(nx, ny))
987 variance = afwImage.ImageF(np.ones((nx, ny), dtype='f'))
988 mask = afwImage.MaskX(nx, ny)
989 mask.array[5, 5] = 5
990 self.maskedImage = afwImage.MaskedImageF(image, mask, variance)
991 self.exposureId = 12345
993 self.v0PhotoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(1e6, 2e4)
994 self.v1PhotoCalib = afwImage.PhotoCalib(1e6, 2e4)
995 self.v1FilterLabel = afwImage.FilterLabel(physical="ha")
996 self.v2FilterLabel = afwImage.FilterLabel(band="N656", physical="ha")
998 def testReadUnversioned(self):
999 """Test that we can read an unversioned (implicit verison 0) file.
1000 """
1001 filename = os.path.join(self.dataDir, "exposure-noversion.fits")
1002 exposure = afwImage.ExposureF.readFits(filename)
1004 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1006 self.assertEqual(exposure.info.id, self.exposureId)
1007 with self.assertWarns(FutureWarning):
1008 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1009 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib)
1010 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1012 def testReadVersion0(self):
1013 """Test that we can read a version 0 file.
1014 This file should be identical to the unversioned one, except that it
1015 is marked as ExposureInfo version 0 in the header.
1016 """
1017 filename = os.path.join(self.dataDir, "exposure-version-0.fits")
1018 exposure = afwImage.ExposureF.readFits(filename)
1020 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1022 self.assertEqual(exposure.info.id, self.exposureId)
1023 with self.assertWarns(FutureWarning):
1024 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1025 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib)
1026 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1028 # Check that the metadata reader parses the file correctly
1029 reader = afwImage.ExposureFitsReader(filename)
1030 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v0PhotoCalib)
1031 self.assertEqual(reader.readPhotoCalib(), self.v0PhotoCalib)
1033 def testReadVersion1(self):
1034 """Test that we can read a version 1 file.
1035 Version 1 replaced Calib with PhotoCalib.
1036 """
1037 filename = os.path.join(self.dataDir, "exposure-version-1.fits")
1038 exposure = afwImage.ExposureF.readFits(filename)
1040 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1042 self.assertEqual(exposure.info.id, self.exposureId)
1043 with self.assertWarns(FutureWarning):
1044 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1045 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib)
1046 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1048 # Check that the metadata reader parses the file correctly
1049 reader = afwImage.ExposureFitsReader(filename)
1050 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib)
1051 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib)
1053 def testReadVersion2(self):
1054 """Test that we can read a version 2 file.
1055 Version 2 replaced Filter with FilterLabel.
1056 """
1057 filename = os.path.join(self.dataDir, "exposure-version-2.fits")
1058 exposure = afwImage.ExposureF.readFits(filename)
1060 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1062 self.assertEqual(exposure.info.id, self.exposureId)
1063 with self.assertWarns(FutureWarning):
1064 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1065 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib)
1066 self.assertEqual(exposure.getFilterLabel(), self.v2FilterLabel)
1068 # Check that the metadata reader parses the file correctly
1069 reader = afwImage.ExposureFitsReader(filename)
1070 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib)
1071 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib)
1073 def testExposureSummaryExtraComponents(self):
1074 """Test that we can read an exposure summary with extra components.
1075 """
1076 testDict = {'ra': 0.0,
1077 'decl': 0.0,
1078 'nonsense': 1.0}
1079 bytes = yaml.dump(testDict, encoding='utf-8')
1080 with self.assertWarns(FutureWarning):
1081 summaryStats = lsst.afw.image.ExposureSummaryStats._read(bytes)
1083 self.assertEqual(summaryStats.ra, testDict['ra'])
1084 self.assertEqual(summaryStats.decl, testDict['decl'])
1087class MemoryTester(lsst.utils.tests.MemoryTestCase):
1088 pass
1091def setup_module(module):
1092 lsst.utils.tests.init()
1095if __name__ == "__main__": 1095 ↛ 1096line 1095 didn't jump to line 1096, because the condition on line 1095 was never true
1096 lsst.utils.tests.init()
1097 unittest.main()