Coverage for tests/test_exposure.py: 11%
677 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-06 12:52 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-06 12:52 -0800
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
32import astropy.units as units
34import lsst.utils
35import lsst.utils.tests
36import lsst.geom
37import lsst.afw.image as afwImage
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 def tearDown(self):
94 del self.smallExposure
95 del self.wcs
96 del self.psf
97 del self.detector
98 del self.extras
100 del self.exposureBlank
101 del self.exposureMiOnly
102 del self.exposureMiWcs
103 del self.exposureCrWcs
104 del self.exposureCrOnly
106 def testGetMaskedImage(self):
107 """
108 Test to ensure a MaskedImage can be obtained from each
109 Exposure. An Exposure is required to have a MaskedImage,
110 therefore each of the Exposures should return a MaskedImage.
112 MaskedImage class should throw appropriate
113 lsst::pex::exceptions::NotFound if the MaskedImage can not be
114 obtained.
115 """
116 maskedImageBlank = self.exposureBlank.getMaskedImage()
117 blankWidth = maskedImageBlank.getWidth()
118 blankHeight = maskedImageBlank.getHeight()
119 if blankWidth != blankHeight != 0:
120 self.fail(f"{blankWidth} = {blankHeight} != 0")
122 maskedImageMiOnly = self.exposureMiOnly.getMaskedImage()
123 miOnlyWidth = maskedImageMiOnly.getWidth()
124 miOnlyHeight = maskedImageMiOnly.getHeight()
125 self.assertAlmostEqual(miOnlyWidth, self.width)
126 self.assertAlmostEqual(miOnlyHeight, self.height)
128 # NOTE: Unittests for Exposures created from a MaskedImage and
129 # a WCS object are incomplete. No way to test the validity of
130 # the WCS being copied/created.
132 maskedImageMiWcs = self.exposureMiWcs.getMaskedImage()
133 miWcsWidth = maskedImageMiWcs.getWidth()
134 miWcsHeight = maskedImageMiWcs.getHeight()
135 self.assertAlmostEqual(miWcsWidth, self.width)
136 self.assertAlmostEqual(miWcsHeight, self.height)
138 maskedImageCrWcs = self.exposureCrWcs.getMaskedImage()
139 crWcsWidth = maskedImageCrWcs.getWidth()
140 crWcsHeight = maskedImageCrWcs.getHeight()
141 if crWcsWidth != crWcsHeight != 0:
142 self.fail(f"{crWcsWidth} != {crWcsHeight} != 0")
144 maskedImageCrOnly = self.exposureCrOnly.getMaskedImage()
145 crOnlyWidth = maskedImageCrOnly.getWidth()
146 crOnlyHeight = maskedImageCrOnly.getHeight()
147 if crOnlyWidth != crOnlyHeight != 0:
148 self.fail(f"{crOnlyWidth} != {crOnlyHeight} != 0")
150 # Check Exposure.getWidth() returns the MaskedImage's width
151 self.assertEqual(crOnlyWidth, self.exposureCrOnly.getWidth())
152 self.assertEqual(crOnlyHeight, self.exposureCrOnly.getHeight())
153 # check width/height properties
154 self.assertEqual(crOnlyWidth, self.exposureCrOnly.width)
155 self.assertEqual(crOnlyHeight, self.exposureCrOnly.height)
157 def testProperties(self):
158 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage,
159 self.exposureMiOnly.getMaskedImage())
160 mi2 = afwImage.MaskedImageF(self.exposureMiOnly.getDimensions())
161 mi2.image.array[:] = 5.0
162 mi2.variance.array[:] = 3.0
163 mi2.mask.array[:] = 0x1
164 self.exposureMiOnly.maskedImage = mi2
165 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, mi2)
166 self.assertImagesEqual(self.exposureMiOnly.image,
167 self.exposureMiOnly.maskedImage.image)
169 image3 = afwImage.ImageF(self.exposureMiOnly.getDimensions())
170 image3.array[:] = 3.0
171 self.exposureMiOnly.image = image3
172 self.assertImagesEqual(self.exposureMiOnly.image, image3)
174 mask3 = afwImage.MaskX(self.exposureMiOnly.getDimensions())
175 mask3.array[:] = 0x2
176 self.exposureMiOnly.mask = mask3
177 self.assertMasksEqual(self.exposureMiOnly.mask, mask3)
179 var3 = afwImage.ImageF(self.exposureMiOnly.getDimensions())
180 var3.array[:] = 2.0
181 self.exposureMiOnly.variance = var3
182 self.assertImagesEqual(self.exposureMiOnly.variance, var3)
184 # Test the property getter for a null VisitInfo.
185 self.assertIsNone(self.exposureMiOnly.visitInfo)
187 def testGetWcs(self):
188 """Test that a WCS can be obtained from each Exposure created with
189 a WCS, and that an Exposure lacking a WCS returns None.
190 """
191 # These exposures don't contain a WCS
192 self.assertIsNone(self.exposureBlank.getWcs())
193 self.assertIsNone(self.exposureMiOnly.getWcs())
194 self.assertIsNone(self.exposureCrOnly.getWcs())
196 # These exposures should contain a WCS
197 self.assertEqual(self.wcs, self.exposureMiWcs.getWcs())
198 self.assertEqual(self.wcs, self.exposureCrWcs.getWcs())
200 def testExposureInfoConstructor(self):
201 """Test the Exposure(maskedImage, exposureInfo) constructor"""
202 exposureInfo = afwImage.ExposureInfo()
203 exposureInfo.setWcs(self.wcs)
204 exposureInfo.setDetector(self.detector)
205 gFilterLabel = afwImage.FilterLabel(band="g")
206 exposureInfo.setFilter(gFilterLabel)
207 maskedImage = afwImage.MaskedImageF(inFilePathSmall)
208 exposure = afwImage.ExposureF(maskedImage, exposureInfo)
210 self.assertTrue(exposure.hasWcs())
211 self.assertEqual(exposure.getWcs().getPixelOrigin(),
212 self.wcs.getPixelOrigin())
213 self.assertEqual(exposure.getDetector().getName(),
214 self.detector.getName())
215 self.assertEqual(exposure.getDetector().getSerial(),
216 self.detector.getSerial())
217 self.assertEqual(exposure.getFilter(), gFilterLabel)
218 with self.assertWarns(FutureWarning):
219 self.assertEqual(exposure.getFilterLabel(), gFilterLabel)
221 self.assertTrue(exposure.getInfo().hasWcs())
222 # check the ExposureInfo property
223 self.assertTrue(exposure.info.hasWcs())
224 self.assertEqual(exposure.getInfo().getWcs().getPixelOrigin(),
225 self.wcs.getPixelOrigin())
226 self.assertEqual(exposure.getInfo().getDetector().getName(),
227 self.detector.getName())
228 self.assertEqual(exposure.getInfo().getDetector().getSerial(),
229 self.detector.getSerial())
230 self.assertEqual(exposure.getInfo().getFilter(), gFilterLabel)
231 with self.assertWarns(FutureWarning):
232 self.assertEqual(exposure.getInfo().getFilterLabel(), gFilterLabel)
234 def testNullWcs(self):
235 """Test that an Exposure constructed with second argument None is usable
237 When the exposureInfo constructor was first added, trying to get a WCS
238 or other info caused a segfault because the ExposureInfo did not exist.
239 """
240 maskedImage = self.exposureMiOnly.getMaskedImage()
241 exposure = afwImage.ExposureF(maskedImage, None)
242 self.assertFalse(exposure.hasWcs())
243 self.assertFalse(exposure.hasPsf())
245 def testExposureInfoSetNone(self):
246 exposureInfo = afwImage.ExposureInfo()
247 exposureInfo.setDetector(None)
248 exposureInfo.setValidPolygon(None)
249 exposureInfo.setPsf(None)
250 exposureInfo.setWcs(None)
251 exposureInfo.setPhotoCalib(None)
252 exposureInfo.setCoaddInputs(None)
253 exposureInfo.setVisitInfo(None)
254 exposureInfo.setApCorrMap(None)
255 for key in self.extras:
256 exposureInfo.setComponent(key, None)
258 def testSetExposureInfo(self):
259 exposureInfo = afwImage.ExposureInfo()
260 exposureInfo.setWcs(self.wcs)
261 exposureInfo.setDetector(self.detector)
262 gFilterLabel = afwImage.FilterLabel(band="g")
263 exposureInfo.setFilter(gFilterLabel)
264 exposureInfo.setId(self.id)
265 maskedImage = afwImage.MaskedImageF(inFilePathSmall)
266 exposure = afwImage.ExposureF(maskedImage)
267 self.assertFalse(exposure.hasWcs())
269 exposure.setInfo(exposureInfo)
271 self.assertTrue(exposure.hasWcs())
272 self.assertEqual(exposure.getWcs().getPixelOrigin(),
273 self.wcs.getPixelOrigin())
274 self.assertEqual(exposure.getDetector().getName(),
275 self.detector.getName())
276 self.assertEqual(exposure.getDetector().getSerial(),
277 self.detector.getSerial())
278 self.assertEqual(exposure.getFilter(), gFilterLabel)
279 with self.assertWarns(FutureWarning):
280 self.assertEqual(exposure.getFilterLabel(), gFilterLabel)
282 # test properties
283 self.assertEqual(exposure.detector.getName(), self.detector.getName())
284 self.assertEqual(exposure.filter, gFilterLabel)
285 self.assertEqual(exposure.wcs, self.wcs)
287 def testVisitInfoFitsPersistence(self):
288 """Test saving an exposure to FITS and reading it back in preserves (some) VisitInfo fields"""
289 exposureId = 5
290 exposureTime = 12.3
291 boresightRotAngle = 45.6 * lsst.geom.degrees
292 weather = Weather(1.1, 2.2, 0.3)
293 visitInfo = afwImage.VisitInfo(
294 exposureId=exposureId,
295 exposureTime=exposureTime,
296 boresightRotAngle=boresightRotAngle,
297 weather=weather,
298 )
299 photoCalib = afwImage.PhotoCalib(3.4, 5.6)
300 exposureInfo = afwImage.ExposureInfo()
301 exposureInfo.setVisitInfo(visitInfo)
302 exposureInfo.setPhotoCalib(photoCalib)
303 exposureInfo.setDetector(self.detector)
304 gFilterLabel = afwImage.FilterLabel(band="g")
305 exposureInfo.setFilter(gFilterLabel)
306 maskedImage = afwImage.MaskedImageF(inFilePathSmall)
307 exposure = afwImage.ExposureF(maskedImage, exposureInfo)
308 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
309 exposure.writeFits(tmpFile)
310 rtExposure = afwImage.ExposureF(tmpFile)
311 rtVisitInfo = rtExposure.getInfo().getVisitInfo()
312 self.assertEqual(rtVisitInfo.getWeather(), weather)
313 self.assertEqual(rtExposure.getPhotoCalib(), photoCalib)
314 self.assertEqual(rtExposure.getFilter(), gFilterLabel)
315 with self.assertWarns(FutureWarning):
316 self.assertEqual(rtExposure.getFilterLabel(), gFilterLabel)
318 # Test property getters.
319 self.assertEqual(rtExposure.photoCalib, photoCalib)
320 self.assertEqual(rtExposure.filter, gFilterLabel)
321 # NOTE: we can't test visitInfo equality, because most fields are NaN.
322 self.assertIsNotNone(rtExposure.visitInfo)
324 def testSetMembers(self):
325 """
326 Test that the MaskedImage and the WCS of an Exposure can be set.
327 """
328 exposure = afwImage.ExposureF()
330 maskedImage = afwImage.MaskedImageF(inFilePathSmall)
331 exposure.setMaskedImage(maskedImage)
332 exposure.setWcs(self.wcs)
333 exposure.setDetector(self.detector)
334 exposure.setFilter(afwImage.FilterLabel(band="g"))
336 self.assertEqual(exposure.getDetector().getName(),
337 self.detector.getName())
338 self.assertEqual(exposure.getDetector().getSerial(),
339 self.detector.getSerial())
340 self.assertEqual(exposure.getFilter().bandLabel, "g")
341 with self.assertWarns(FutureWarning):
342 self.assertEqual(exposure.getFilterLabel().bandLabel, "g")
343 self.assertEqual(exposure.getWcs(), self.wcs)
345 # The PhotoCalib tests are in test_photoCalib.py;
346 # here we just check that it's gettable and settable.
347 self.assertIsNone(exposure.getPhotoCalib())
349 photoCalib = afwImage.PhotoCalib(511.1, 44.4)
350 exposure.setPhotoCalib(photoCalib)
351 self.assertEqual(exposure.getPhotoCalib(), photoCalib)
353 # Psfs next
354 self.assertFalse(exposure.hasPsf())
355 exposure.setPsf(self.psf)
356 self.assertTrue(exposure.hasPsf())
358 exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf
360 # extras next
361 info = exposure.getInfo()
362 for key, value in self.extras.items():
363 self.assertFalse(info.hasComponent(key))
364 self.assertIsNone(info.getComponent(key))
365 info.setComponent(key, value)
366 self.assertTrue(info.hasComponent(key))
367 self.assertEqual(info.getComponent(key), value)
368 info.removeComponent(key)
369 self.assertFalse(info.hasComponent(key))
371 # Test that we can set the MaskedImage and WCS of an Exposure
372 # that already has both
373 self.exposureMiWcs.setMaskedImage(maskedImage)
374 exposure.setWcs(self.wcs)
376 def testHasWcs(self):
377 """
378 Test if an Exposure has a WCS or not.
379 """
380 self.assertFalse(self.exposureBlank.hasWcs())
382 self.assertFalse(self.exposureMiOnly.hasWcs())
383 self.assertTrue(self.exposureMiWcs.hasWcs())
384 self.assertTrue(self.exposureCrWcs.hasWcs())
385 self.assertFalse(self.exposureCrOnly.hasWcs())
387 def testGetSubExposure(self):
388 """
389 Test that a subExposure of the original Exposure can be obtained.
391 The MaskedImage class should throw a
392 lsst::pex::exceptions::InvalidParameter if the requested
393 subRegion is not fully contained within the original
394 MaskedImage.
396 """
397 #
398 # This subExposure is valid
399 #
400 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50),
401 lsst.geom.Extent2I(10, 10))
402 subExposure = self.exposureCrWcs.Factory(
403 self.exposureCrWcs, subBBox, afwImage.LOCAL)
405 self.checkWcs(self.exposureCrWcs, subExposure)
407 # this subRegion is not valid and should trigger an exception
408 # from the MaskedImage class and should trigger an exception
409 # from the WCS class for the MaskedImage 871034p_1_MI.
411 subRegion3 = lsst.geom.Box2I(lsst.geom.Point2I(100, 100),
412 lsst.geom.Extent2I(10, 10))
414 def getSubRegion():
415 self.exposureCrWcs.Factory(
416 self.exposureCrWcs, subRegion3, afwImage.LOCAL)
418 self.assertRaises(pexExcept.LengthError, getSubRegion)
420 # this subRegion is not valid and should trigger an exception
421 # from the MaskedImage class only for the MaskedImage small_MI.
422 # small_MI (cols, rows) = (256, 256)
424 subRegion4 = lsst.geom.Box2I(lsst.geom.Point2I(250, 250),
425 lsst.geom.Extent2I(10, 10))
427 def getSubRegion():
428 self.exposureCrWcs.Factory(
429 self.exposureCrWcs, subRegion4, afwImage.LOCAL)
431 self.assertRaises(pexExcept.LengthError, getSubRegion)
433 # check the sub- and parent- exposures are using the same Wcs
434 # transformation
435 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50),
436 lsst.geom.Extent2I(10, 10))
437 subExposure = self.exposureCrWcs.Factory(
438 self.exposureCrWcs, subBBox, afwImage.LOCAL)
439 parentSkyPos = self.exposureCrWcs.getWcs().pixelToSky(0, 0)
441 subExpSkyPos = subExposure.getWcs().pixelToSky(0, 0)
443 self.assertSpherePointsAlmostEqual(parentSkyPos, subExpSkyPos, msg="Wcs in sub image has changed")
445 def testReadWriteFits(self):
446 """Test readFits and writeFits.
447 """
448 # This should pass without an exception
449 mainExposure = afwImage.ExposureF(inFilePathSmall)
450 mainExposure.info.setId(self.id)
451 mainExposure.setDetector(self.detector)
453 subBBox = lsst.geom.Box2I(lsst.geom.Point2I(10, 10),
454 lsst.geom.Extent2I(40, 50))
455 subExposure = mainExposure.Factory(
456 mainExposure, subBBox, afwImage.LOCAL)
457 self.checkWcs(mainExposure, subExposure)
458 det = subExposure.getDetector()
459 self.assertTrue(det)
461 subExposure = afwImage.ExposureF(
462 inFilePathSmall, subBBox, afwImage.LOCAL)
464 self.checkWcs(mainExposure, subExposure)
466 # This should throw an exception
467 def getExposure():
468 afwImage.ExposureF(inFilePathSmallImage)
470 self.assertRaises(FitsError, getExposure)
472 mainExposure.setPsf(self.psf)
474 # Make sure we can write without an exception
475 photoCalib = afwImage.PhotoCalib(1e-10, 1e-12)
476 mainExposure.setPhotoCalib(photoCalib)
478 mainInfo = mainExposure.getInfo()
479 for key, value in self.extras.items():
480 mainInfo.setComponent(key, value)
482 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
483 mainExposure.writeFits(tmpFile)
485 readExposure = type(mainExposure)(tmpFile)
487 #
488 # Check the round-tripping
489 #
490 self.assertIsNotNone(mainExposure.getFilter())
491 self.assertEqual(mainExposure.getFilter(),
492 readExposure.getFilter())
493 with self.assertWarns(FutureWarning):
494 self.assertIsNotNone(mainExposure.getFilterLabel())
495 self.assertEqual(mainExposure.getFilterLabel(),
496 readExposure.getFilterLabel())
498 self.assertEqual(photoCalib, readExposure.getPhotoCalib())
500 readInfo = readExposure.getInfo()
501 self.assertEqual(mainExposure.info.getId(), readInfo.id)
502 for key, value in self.extras.items():
503 self.assertEqual(value, readInfo.getComponent(key))
505 psf = readExposure.getPsf()
506 self.assertIsNotNone(psf)
507 self.assertEqual(psf, self.psf)
508 # check psf property getter
509 self.assertEqual(readExposure.psf, self.psf)
511 def checkWcs(self, parentExposure, subExposure):
512 """Compare WCS at corner points of a sub-exposure and its parent exposure
513 By using the function indexToPosition, we should be able to convert the indices
514 (of the four corners (of the sub-exposure)) to positions and use the wcs
515 to get the same sky coordinates for each.
516 """
517 subMI = subExposure.getMaskedImage()
518 subDim = subMI.getDimensions()
520 # Note: pixel positions must be computed relative to XY0 when working
521 # with WCS
522 mainWcs = parentExposure.getWcs()
523 subWcs = subExposure.getWcs()
525 for xSubInd in (0, subDim.getX()-1):
526 for ySubInd in (0, subDim.getY()-1):
527 self.assertSpherePointsAlmostEqual(
528 mainWcs.pixelToSky(
529 afwImage.indexToPosition(xSubInd),
530 afwImage.indexToPosition(ySubInd),
531 ),
532 subWcs.pixelToSky(
533 afwImage.indexToPosition(xSubInd),
534 afwImage.indexToPosition(ySubInd),
535 ))
537 def cmpExposure(self, e1, e2):
538 self.assertEqual(e1.getDetector().getName(),
539 e2.getDetector().getName())
540 self.assertEqual(e1.getDetector().getSerial(),
541 e2.getDetector().getSerial())
542 self.assertEqual(e1.getFilter(), e2.getFilter())
543 with self.assertWarns(FutureWarning):
544 self.assertEqual(e1.getFilterLabel(), e2.getFilterLabel())
545 xy = lsst.geom.Point2D(0, 0)
546 self.assertEqual(e1.getWcs().pixelToSky(xy)[0],
547 e2.getWcs().pixelToSky(xy)[0])
548 self.assertEqual(e1.getPhotoCalib(), e2.getPhotoCalib())
549 # check PSF identity
550 if not e1.getPsf():
551 self.assertFalse(e2.getPsf())
552 else:
553 self.assertEqual(e1.getPsf(), e2.getPsf())
554 # Check extra components
555 i1 = e1.getInfo()
556 i2 = e2.getInfo()
557 for key in self.extras:
558 self.assertEqual(i1.hasComponent(key), i2.hasComponent(key))
559 if i1.hasComponent(key):
560 self.assertEqual(i1.getComponent(key), i2.getComponent(key))
562 def testCopyExposure(self):
563 """Copy an Exposure (maybe changing type)"""
565 exposureU = afwImage.ExposureU(inFilePathSmall, allowUnsafe=True)
566 exposureU.setWcs(self.wcs)
567 exposureU.setDetector(self.detector)
568 exposureU.setFilter(afwImage.FilterLabel(band="g"))
569 exposureU.setPsf(DummyPsf(4.0))
570 infoU = exposureU.getInfo()
571 for key, value in self.extras.items():
572 infoU.setComponent(key, value)
574 exposureF = exposureU.convertF()
575 self.cmpExposure(exposureF, exposureU)
577 nexp = exposureF.Factory(exposureF, False)
578 self.cmpExposure(exposureF, nexp)
580 # Ensure that the copy was deep.
581 # (actually this test is invalid since getDetector() returns a shared_ptr)
582 # cen0 = exposureU.getDetector().getCenterPixel()
583 # x0,y0 = cen0
584 # det = exposureF.getDetector()
585 # det.setCenterPixel(lsst.geom.Point2D(999.0, 437.8))
586 # self.assertEqual(exposureU.getDetector().getCenterPixel()[0], x0)
587 # self.assertEqual(exposureU.getDetector().getCenterPixel()[1], y0)
589 def testDeepCopyData(self):
590 """Make sure a deep copy of an Exposure has its own data (ticket #2625)
591 """
592 exp = afwImage.ExposureF(6, 7)
593 mi = exp.getMaskedImage()
594 mi.getImage().set(100)
595 mi.getMask().set(5)
596 mi.getVariance().set(200)
598 expCopy = exp.clone()
599 miCopy = expCopy.getMaskedImage()
600 miCopy.getImage().set(-50)
601 miCopy.getMask().set(2)
602 miCopy.getVariance().set(175)
604 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50)
605 self.assertTrue(np.all(miCopy.getMask().getArray() == 2))
606 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175)
608 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100)
609 self.assertTrue(np.all(mi.getMask().getArray() == 5))
610 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200)
612 def testDeepCopySubData(self):
613 """Make sure a deep copy of a subregion of an Exposure has its own data (ticket #2625)
614 """
615 exp = afwImage.ExposureF(6, 7)
616 mi = exp.getMaskedImage()
617 mi.getImage().set(100)
618 mi.getMask().set(5)
619 mi.getVariance().set(200)
621 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 4))
622 expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True)
623 miCopy = expCopy.getMaskedImage()
624 miCopy.getImage().set(-50)
625 miCopy.getMask().set(2)
626 miCopy.getVariance().set(175)
628 self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50)
629 self.assertTrue(np.all(miCopy.getMask().getArray() == 2))
630 self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175)
632 self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100)
633 self.assertTrue(np.all(mi.getMask().getArray() == 5))
634 self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200)
636 def testDeepCopyMetadata(self):
637 """Make sure a deep copy of an Exposure has a deep copy of metadata (ticket #2568)
638 """
639 exp = afwImage.ExposureF(10, 10)
640 expMeta = exp.getMetadata()
641 expMeta.set("foo", 5)
642 expCopy = exp.clone()
643 expCopyMeta = expCopy.getMetadata()
644 expCopyMeta.set("foo", 6)
645 self.assertEqual(expCopyMeta.getScalar("foo"), 6)
646 # this will fail if the bug is present
647 self.assertEqual(expMeta.getScalar("foo"), 5)
649 def testDeepCopySubMetadata(self):
650 """Make sure a deep copy of a subregion of an Exposure has a deep copy of metadata (ticket #2568)
651 """
652 exp = afwImage.ExposureF(10, 10)
653 expMeta = exp.getMetadata()
654 expMeta.set("foo", 5)
655 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 5))
656 expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True)
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 testMakeExposureLeaks(self):
664 """Test for memory leaks in makeExposure (the test is in lsst.utils.tests.MemoryTestCase)"""
665 afwImage.makeMaskedImage(afwImage.ImageU(lsst.geom.Extent2I(10, 20)))
666 afwImage.makeExposure(afwImage.makeMaskedImage(
667 afwImage.ImageU(lsst.geom.Extent2I(10, 20))))
669 def testImageSlices(self):
670 """Test image slicing, which generate sub-images using Box2I under the covers"""
671 exp = afwImage.ExposureF(10, 20)
672 mi = exp.getMaskedImage()
673 mi.image[9, 19] = 10
674 # N.b. Exposures don't support setting/getting the pixels so can't
675 # replicate e.g. Image's slice tests
676 sexp = exp[1:4, 6:10]
677 self.assertEqual(sexp.getDimensions(), lsst.geom.ExtentI(3, 4))
678 sexp = exp[:, -3:, afwImage.LOCAL]
679 self.assertEqual(sexp.getDimensions(),
680 lsst.geom.ExtentI(exp.getWidth(), 3))
681 self.assertEqual(sexp.maskedImage[-1, -1, afwImage.LOCAL],
682 exp.maskedImage[-1, -1, afwImage.LOCAL])
684 def testConversionToScalar(self):
685 """Test that even 1-pixel Exposures can't be converted to scalars"""
686 im = afwImage.ExposureF(10, 20)
688 # only single pixel images may be converted
689 self.assertRaises(TypeError, float, im)
690 # actually, can't convert (img, msk, var) to scalar
691 self.assertRaises(TypeError, float, im[0, 0])
693 def testReadMetadata(self):
694 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
695 self.exposureCrWcs.getMetadata().set("FRAZZLE", True)
696 # This will write the main metadata (inc. FRAZZLE) to the primary HDU, and the
697 # WCS to subsequent HDUs, along with INHERIT=T.
698 self.exposureCrWcs.writeFits(tmpFile)
699 # This should read the first non-empty HDU (i.e. it skips the primary), but
700 # goes back and reads it if it finds INHERIT=T. That should let us read
701 # frazzle and the Wcs from the PropertySet returned by
702 # testReadMetadata.
703 md = readMetadata(tmpFile)
704 wcs = afwGeom.makeSkyWcs(md, False)
705 self.assertPairsAlmostEqual(wcs.getPixelOrigin(), self.wcs.getPixelOrigin())
706 self.assertSpherePointsAlmostEqual(wcs.getSkyOrigin(), self.wcs.getSkyOrigin())
707 assert_allclose(wcs.getCdMatrix(), self.wcs.getCdMatrix(), atol=1e-10)
708 frazzle = md.getScalar("FRAZZLE")
709 self.assertTrue(frazzle)
711 def testArchiveKeys(self):
712 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
713 exposure1 = afwImage.ExposureF(100, 100, self.wcs)
714 exposure1.setPsf(self.psf)
715 exposure1.writeFits(tmpFile)
716 exposure2 = afwImage.ExposureF(tmpFile)
717 self.assertFalse(exposure2.getMetadata().exists("AR_ID"))
718 self.assertFalse(exposure2.getMetadata().exists("PSF_ID"))
719 self.assertFalse(exposure2.getMetadata().exists("WCS_ID"))
721 def testTicket2861(self):
722 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
723 exposure1 = afwImage.ExposureF(100, 100, self.wcs)
724 exposure1.setPsf(self.psf)
725 schema = afwTable.ExposureTable.makeMinimalSchema()
726 coaddInputs = afwImage.CoaddInputs(schema, schema)
727 exposure1.getInfo().setCoaddInputs(coaddInputs)
728 exposure2 = afwImage.ExposureF(exposure1, True)
729 self.assertIsNotNone(exposure2.getInfo().getCoaddInputs())
730 exposure2.writeFits(tmpFile)
731 exposure3 = afwImage.ExposureF(tmpFile)
732 self.assertIsNotNone(exposure3.getInfo().getCoaddInputs())
734 def testGetCutout(self):
735 wcs = self.smallExposure.getWcs()
737 dimensions = [lsst.geom.Extent2I(100, 50), lsst.geom.Extent2I(15, 15), lsst.geom.Extent2I(0, 10),
738 lsst.geom.Extent2I(25, 30), lsst.geom.Extent2I(15, -5),
739 2*self.smallExposure.getDimensions()]
740 locations = [("center", self._getExposureCenter(self.smallExposure)),
741 ("edge", wcs.pixelToSky(lsst.geom.Point2D(0, 0))),
742 ("rounding test", wcs.pixelToSky(lsst.geom.Point2D(0.2, 0.7))),
743 ("just inside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 + 1e-4, -0.5 + 1e-4))),
744 ("just outside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 - 1e-4, -0.5 - 1e-4))),
745 ("outside", wcs.pixelToSky(lsst.geom.Point2D(-1000, -1000)))]
746 for cutoutSize in dimensions:
747 for label, cutoutCenter in locations:
748 msg = 'Cutout size = %s, location = %s' % (cutoutSize, label)
749 if "outside" not in label and all(cutoutSize.gt(0)):
750 cutout = self.smallExposure.getCutout(cutoutCenter, cutoutSize)
751 centerInPixels = wcs.skyToPixel(cutoutCenter)
752 precision = (1 + 1e-4)*np.sqrt(0.5)*wcs.getPixelScale(centerInPixels)
753 self._checkCutoutProperties(cutout, cutoutSize, cutoutCenter, precision, msg)
754 self._checkCutoutPixels(
755 cutout,
756 self._getValidCorners(self.smallExposure.getBBox(), cutout.getBBox()),
757 msg)
759 # Need a valid WCS
760 with self.assertRaises(pexExcept.LogicError, msg=msg):
761 self.exposureMiOnly.getCutout(cutoutCenter, cutoutSize)
762 else:
763 with self.assertRaises(pexExcept.InvalidParameterError, msg=msg):
764 self.smallExposure.getCutout(cutoutCenter, cutoutSize)
766 def testGetConvexPolygon(self):
767 """Test the convex polygon."""
768 # Check that we do not have a convex polygon for the plain exposure.
769 self.assertIsNone(self.exposureMiOnly.convex_polygon)
771 # Check that all the points in the padded bounding box are in the polygon
772 bbox = self.exposureMiWcs.getBBox()
773 # Grow by the default padding.
774 bbox.grow(10)
775 x, y = np.meshgrid(np.arange(bbox.getBeginX(), bbox.getEndX(), dtype=np.float64),
776 np.arange(bbox.getBeginY(), bbox.getEndY(), dtype=np.float64))
777 wcs = self.exposureMiWcs.wcs
778 ra, dec = wcs.pixelToSkyArray(x.ravel(),
779 y.ravel())
781 poly = self.exposureMiWcs.convex_polygon
782 contains = poly.contains(ra, dec)
783 np.testing.assert_array_equal(contains, np.ones(len(contains), dtype=bool))
785 # Check that points one pixel outside of the bounding box are not in the polygon
786 bbox.grow(1)
788 ra, dec = wcs.pixelToSkyArray(
789 np.linspace(bbox.getBeginX(), bbox.getEndX(), 100),
790 np.full(100, bbox.getBeginY()))
791 contains = poly.contains(ra, dec)
792 np.testing.assert_array_equal(contains, np.zeros(len(contains), dtype=bool))
794 ra, dec = wcs.pixelToSkyArray(
795 np.linspace(bbox.getBeginX(), bbox.getEndX(), 100),
796 np.full(100, bbox.getEndY()))
797 contains = poly.contains(ra, dec)
798 np.testing.assert_array_equal(contains, np.zeros(len(contains), dtype=bool))
800 ra, dec = wcs.pixelToSkyArray(
801 np.full(100, bbox.getBeginX()),
802 np.linspace(bbox.getBeginY(), bbox.getEndY(), 100))
803 contains = poly.contains(ra, dec)
804 np.testing.assert_array_equal(contains, np.zeros(len(contains), dtype=bool))
806 ra, dec = wcs.pixelToSkyArray(
807 np.full(100, bbox.getEndX()),
808 np.linspace(bbox.getBeginY(), bbox.getEndY(), 100))
809 contains = poly.contains(ra, dec)
810 np.testing.assert_array_equal(contains, np.zeros(len(contains), dtype=bool))
812 def testContainsSkyCoords(self):
813 """Test the sky coord containment code."""
814 self.assertRaisesRegex(ValueError,
815 "Exposure does not have a valid WCS",
816 self.exposureMiOnly.containsSkyCoords,
817 0.0,
818 0.0)
820 # Check that all the points within the bounding box are contained
821 bbox = self.exposureMiWcs.getBBox()
822 x, y = np.meshgrid(np.arange(bbox.getBeginX() + 1, bbox.getEndX() - 1),
823 np.arange(bbox.getBeginY() + 1, bbox.getEndY() - 1))
824 wcs = self.exposureMiWcs.wcs
825 ra, dec = wcs.pixelToSkyArray(x.ravel().astype(np.float64),
826 y.ravel().astype(np.float64))
828 contains = self.exposureMiWcs.containsSkyCoords(ra*units.radian,
829 dec*units.radian)
830 np.testing.assert_array_equal(contains, np.ones(len(contains), dtype=bool))
832 # Same test, everything in degrees.
833 ra, dec = wcs.pixelToSkyArray(x.ravel().astype(np.float64),
834 y.ravel().astype(np.float64),
835 degrees=True)
837 contains = self.exposureMiWcs.containsSkyCoords(ra*units.degree,
838 dec*units.degree)
839 np.testing.assert_array_equal(contains, np.ones(len(contains), dtype=bool))
841 # Prepend and append some positions out of the box.
842 ra = np.concatenate(([300.0], ra, [180.]))
843 dec = np.concatenate(([50.0], dec, [50.0]))
845 contains = self.exposureMiWcs.containsSkyCoords(ra*units.degree,
846 dec*units.degree)
847 compare = np.ones(len(contains), dtype=bool)
848 compare[0] = False
849 compare[-1] = False
850 np.testing.assert_array_equal(contains, compare)
852 def _checkCutoutProperties(self, cutout, size, center, precision, msg):
853 """Test whether a cutout has the desired size and position.
855 Parameters
856 ----------
857 cutout : `lsst.afw.image.Exposure`
858 The cutout to test.
859 size : `lsst.geom.Extent2I`
860 The expected dimensions of ``cutout``.
861 center : `lsst.geom.SpherePoint`
862 The expected center of ``cutout``.
863 precision : `lsst.geom.Angle`
864 The precision to which ``center`` must match.
865 msg : `str`
866 An error message suffix describing test parameters.
867 """
868 newCenter = self._getExposureCenter(cutout)
869 self.assertIsNotNone(cutout, msg=msg)
870 self.assertSpherePointsAlmostEqual(newCenter, center, maxSep=precision, msg=msg)
871 self.assertEqual(cutout.getWidth(), size[0], msg=msg)
872 self.assertEqual(cutout.getHeight(), size[1], msg=msg)
874 def _checkCutoutPixels(self, cutout, validCorners, msg):
875 """Test whether a cutout has valid/empty pixels where expected.
877 Parameters
878 ----------
879 cutout : `lsst.afw.image.Exposure`
880 The cutout to test.
881 validCorners : iterable of `lsst.geom.Point2I`
882 The corners of ``cutout`` that should be drawn from the original image.
883 msg : `str`
884 An error message suffix describing test parameters.
885 """
886 mask = cutout.getMaskedImage().getMask()
887 edgeMask = mask.getPlaneBitMask("NO_DATA")
889 for corner in cutout.getBBox().getCorners():
890 maskBitsSet = mask[corner] & edgeMask
891 if corner in validCorners:
892 self.assertEqual(maskBitsSet, 0, msg=msg)
893 else:
894 self.assertEqual(maskBitsSet, edgeMask, msg=msg)
896 def _getExposureCenter(self, exposure):
897 """Return the sky coordinates of an Exposure's center.
899 Parameters
900 ----------
901 exposure : `lsst.afw.image.Exposure`
902 The image whose center is desired.
904 Returns
905 -------
906 center : `lsst.geom.SpherePoint`
907 The position at the center of ``exposure``.
908 """
909 return exposure.getWcs().pixelToSky(lsst.geom.Box2D(exposure.getBBox()).getCenter())
911 def _getValidCorners(self, imageBox, cutoutBox):
912 """Return the corners of a cutout that are constrained by the original image.
914 Parameters
915 ----------
916 imageBox: `lsst.geom.Extent2I`
917 The bounding box of the original image.
918 cutoutBox : `lsst.geom.Box2I`
919 The bounding box of the cutout.
921 Returns
922 -------
923 corners : iterable of `lsst.geom.Point2I`
924 The corners that are drawn from the original image.
925 """
926 return [corner for corner in cutoutBox.getCorners() if corner in imageBox]
929class ExposureInfoTestCase(lsst.utils.tests.TestCase):
930 def setUp(self):
931 super().setUp()
933 self.wcs = afwGeom.makeSkyWcs(lsst.geom.Point2D(0.0, 0.0),
934 lsst.geom.SpherePoint(2.0, 34.0, lsst.geom.degrees),
935 np.identity(2),
936 )
937 self.photoCalib = afwImage.PhotoCalib(1.5)
938 self.psf = DummyPsf(2.0)
939 self.detector = DetectorWrapper().detector
940 self.summaryStats = afwImage.ExposureSummaryStats(ra=100.0)
941 self.polygon = afwGeom.Polygon(lsst.geom.Box2D(lsst.geom.Point2D(0.0, 0.0),
942 lsst.geom.Point2D(25.0, 20.0)))
943 self.coaddInputs = afwImage.CoaddInputs()
944 self.apCorrMap = afwImage.ApCorrMap()
945 self.transmissionCurve = afwImage.TransmissionCurve.makeIdentity()
947 self.exposureInfo = afwImage.ExposureInfo()
948 self.gFilterLabel = afwImage.FilterLabel(band="g")
949 self.exposureId = 42
951 def _checkAlias(self, exposureInfo, key, value, has, get):
952 self.assertFalse(has())
953 self.assertFalse(exposureInfo.hasComponent(key))
954 self.assertIsNone(get())
955 self.assertIsNone(exposureInfo.getComponent(key))
957 self.exposureInfo.setComponent(key, value)
958 self.assertTrue(has())
959 self.assertTrue(exposureInfo.hasComponent(key))
960 self.assertIsNotNone(get())
961 self.assertIsNotNone(exposureInfo.getComponent(key))
962 self.assertEqual(get(), value)
963 self.assertEqual(exposureInfo.getComponent(key), value)
965 self.exposureInfo.removeComponent(key)
966 self.assertFalse(has())
967 self.assertFalse(exposureInfo.hasComponent(key))
968 self.assertIsNone(get())
969 self.assertIsNone(exposureInfo.getComponent(key))
971 def testAliases(self):
972 cls = type(self.exposureInfo)
973 self._checkAlias(self.exposureInfo, cls.KEY_WCS, self.wcs,
974 self.exposureInfo.hasWcs, self.exposureInfo.getWcs)
975 self._checkAlias(self.exposureInfo, cls.KEY_PSF, self.psf,
976 self.exposureInfo.hasPsf, self.exposureInfo.getPsf)
977 self._checkAlias(self.exposureInfo, cls.KEY_PHOTO_CALIB, self.photoCalib,
978 self.exposureInfo.hasPhotoCalib, self.exposureInfo.getPhotoCalib)
979 self._checkAlias(self.exposureInfo, cls.KEY_DETECTOR, self.detector,
980 self.exposureInfo.hasDetector, self.exposureInfo.getDetector)
981 self._checkAlias(self.exposureInfo, cls.KEY_VALID_POLYGON, self.polygon,
982 self.exposureInfo.hasValidPolygon, self.exposureInfo.getValidPolygon)
983 self._checkAlias(self.exposureInfo, cls.KEY_COADD_INPUTS, self.coaddInputs,
984 self.exposureInfo.hasCoaddInputs, self.exposureInfo.getCoaddInputs)
985 self._checkAlias(self.exposureInfo, cls.KEY_AP_CORR_MAP, self.apCorrMap,
986 self.exposureInfo.hasApCorrMap, self.exposureInfo.getApCorrMap)
987 self._checkAlias(self.exposureInfo, cls.KEY_TRANSMISSION_CURVE, self.transmissionCurve,
988 self.exposureInfo.hasTransmissionCurve, self.exposureInfo.getTransmissionCurve)
989 self._checkAlias(self.exposureInfo, cls.KEY_SUMMARY_STATS, self.summaryStats,
990 self.exposureInfo.hasSummaryStats, self.exposureInfo.getSummaryStats)
991 self._checkAlias(self.exposureInfo, cls.KEY_FILTER, self.gFilterLabel,
992 self.exposureInfo.hasFilter, self.exposureInfo.getFilter)
993 with self.assertWarns(FutureWarning):
994 self._checkAlias(self.exposureInfo, cls.KEY_FILTER, self.gFilterLabel,
995 self.exposureInfo.hasFilterLabel, self.exposureInfo.getFilterLabel)
997 def testId(self):
998 self.exposureInfo.setVisitInfo(afwImage.VisitInfo())
1000 self.assertFalse(self.exposureInfo.hasId())
1001 self.assertIsNone(self.exposureInfo.getId())
1002 with self.assertWarns(FutureWarning):
1003 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), 0)
1004 self.assertIsNone(self.exposureInfo.id)
1006 self.exposureInfo.setId(self.exposureId)
1007 self.assertTrue(self.exposureInfo.hasId())
1008 self.assertIsNotNone(self.exposureInfo.getId())
1009 self.assertIsNotNone(self.exposureInfo.id)
1010 self.assertEqual(self.exposureInfo.getId(), self.exposureId)
1011 with self.assertWarns(FutureWarning):
1012 self.assertEqual(self.exposureInfo.getVisitInfo().getExposureId(), self.exposureId)
1013 self.assertEqual(self.exposureInfo.id, self.exposureId)
1015 self.exposureInfo.id = 99899
1016 self.assertEqual(self.exposureInfo.getId(), 99899)
1018 self.exposureInfo.setVisitInfo(afwImage.VisitInfo(exposureId=12321))
1019 self.assertEqual(self.exposureInfo.id, 12321)
1021 self.exposureInfo.id = None
1022 self.assertFalse(self.exposureInfo.hasId())
1023 self.assertIsNone(self.exposureInfo.getId())
1024 self.assertIsNone(self.exposureInfo.id)
1026 def testCopy(self):
1027 # Test that ExposureInfos have independently settable state
1028 copy = afwImage.ExposureInfo(self.exposureInfo, True)
1029 self.assertEqual(self.exposureInfo.getWcs(), copy.getWcs())
1031 newWcs = afwGeom.makeSkyWcs(lsst.geom.Point2D(-23.0, 8.0),
1032 lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees),
1033 np.identity(2),
1034 )
1035 copy.setWcs(newWcs)
1036 self.assertEqual(copy.getWcs(), newWcs)
1037 self.assertNotEqual(self.exposureInfo.getWcs(), copy.getWcs())
1039 def testMissingProperties(self):
1040 # Test that invalid properties return None instead of raising
1041 exposureInfo = afwImage.ExposureInfo()
1043 self.assertIsNone(exposureInfo.id)
1046class ExposureNoAfwdataTestCase(lsst.utils.tests.TestCase):
1047 """Tests of Exposure that don't require afwdata.
1049 These tests use the trivial exposures written to ``afw/tests/data``.
1050 """
1051 def setUp(self):
1052 self.dataDir = os.path.join(os.path.split(__file__)[0], "data")
1054 # Check the values below against what was written by comparing with
1055 # the code in `afw/tests/data/makeTestExposure.py`
1056 nx = ny = 10
1057 image = afwImage.ImageF(np.arange(nx*ny, dtype='f').reshape(nx, ny))
1058 variance = afwImage.ImageF(np.ones((nx, ny), dtype='f'))
1059 mask = afwImage.MaskX(nx, ny)
1060 mask.array[5, 5] = 5
1061 self.maskedImage = afwImage.MaskedImageF(image, mask, variance)
1062 self.exposureId = 12345
1064 self.v0PhotoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(1e6, 2e4)
1065 self.v1PhotoCalib = afwImage.PhotoCalib(1e6, 2e4)
1066 self.v1FilterLabel = afwImage.FilterLabel(physical="ha")
1067 self.v2FilterLabel = afwImage.FilterLabel(band="N656", physical="ha")
1069 def testReadUnversioned(self):
1070 """Test that we can read an unversioned (implicit verison 0) file.
1071 """
1072 filename = os.path.join(self.dataDir, "exposure-noversion.fits")
1073 exposure = afwImage.ExposureF.readFits(filename)
1075 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1077 self.assertEqual(exposure.info.id, self.exposureId)
1078 with self.assertWarns(FutureWarning):
1079 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1080 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib)
1081 self.assertEqual(exposure.getFilter(), self.v1FilterLabel)
1082 with self.assertWarns(FutureWarning):
1083 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1085 def testReadVersion0(self):
1086 """Test that we can read a version 0 file.
1087 This file should be identical to the unversioned one, except that it
1088 is marked as ExposureInfo version 0 in the header.
1089 """
1090 filename = os.path.join(self.dataDir, "exposure-version-0.fits")
1091 exposure = afwImage.ExposureF.readFits(filename)
1093 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1095 self.assertEqual(exposure.info.id, self.exposureId)
1096 with self.assertWarns(FutureWarning):
1097 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1098 self.assertEqual(exposure.getPhotoCalib(), self.v0PhotoCalib)
1099 self.assertEqual(exposure.getFilter(), self.v1FilterLabel)
1100 with self.assertWarns(FutureWarning):
1101 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1103 # Check that the metadata reader parses the file correctly
1104 reader = afwImage.ExposureFitsReader(filename)
1105 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v0PhotoCalib)
1106 self.assertEqual(reader.readPhotoCalib(), self.v0PhotoCalib)
1108 def testReadVersion1(self):
1109 """Test that we can read a version 1 file.
1110 Version 1 replaced Calib with PhotoCalib.
1111 """
1112 filename = os.path.join(self.dataDir, "exposure-version-1.fits")
1113 exposure = afwImage.ExposureF.readFits(filename)
1115 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1117 self.assertEqual(exposure.info.id, self.exposureId)
1118 with self.assertWarns(FutureWarning):
1119 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1120 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib)
1121 self.assertEqual(exposure.getFilter(), self.v1FilterLabel)
1122 with self.assertWarns(FutureWarning):
1123 self.assertEqual(exposure.getFilterLabel(), self.v1FilterLabel)
1125 # Check that the metadata reader parses the file correctly
1126 reader = afwImage.ExposureFitsReader(filename)
1127 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib)
1128 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib)
1130 def testReadVersion2(self):
1131 """Test that we can read a version 2 file.
1132 Version 2 replaced Filter with FilterLabel.
1133 """
1134 filename = os.path.join(self.dataDir, "exposure-version-2.fits")
1135 exposure = afwImage.ExposureF.readFits(filename)
1137 self.assertMaskedImagesEqual(exposure.maskedImage, self.maskedImage)
1139 self.assertEqual(exposure.info.id, self.exposureId)
1140 with self.assertWarns(FutureWarning):
1141 self.assertEqual(exposure.info.getVisitInfo().getExposureId(), self.exposureId)
1142 self.assertEqual(exposure.getPhotoCalib(), self.v1PhotoCalib)
1143 self.assertEqual(exposure.getFilter(), self.v2FilterLabel)
1144 with self.assertWarns(FutureWarning):
1145 self.assertEqual(exposure.getFilterLabel(), self.v2FilterLabel)
1147 # Check that the metadata reader parses the file correctly
1148 reader = afwImage.ExposureFitsReader(filename)
1149 self.assertEqual(reader.readExposureInfo().getPhotoCalib(), self.v1PhotoCalib)
1150 self.assertEqual(reader.readPhotoCalib(), self.v1PhotoCalib)
1152 def testExposureSummaryExtraComponents(self):
1153 """Test that we can read an exposure summary with extra components.
1154 """
1155 testDict = {'ra': 0.0,
1156 'decl': 0.0,
1157 'nonsense': 1.0}
1158 bytes = yaml.dump(testDict, encoding='utf-8')
1159 with self.assertWarns(FutureWarning):
1160 summaryStats = lsst.afw.image.ExposureSummaryStats._read(bytes)
1162 self.assertEqual(summaryStats.ra, testDict['ra'])
1163 self.assertEqual(summaryStats.decl, testDict['decl'])
1166class MemoryTester(lsst.utils.tests.MemoryTestCase):
1167 pass
1170def setup_module(module):
1171 lsst.utils.tests.init()
1174if __name__ == "__main__": 1174 ↛ 1175line 1174 didn't jump to line 1175, because the condition on line 1174 was never true
1175 lsst.utils.tests.init()
1176 unittest.main()