Coverage for tests/test_warper.py : 33%

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#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22"""Basic test of Warp (the warping algorithm is thoroughly tested in lsst.afw.math)
23"""
24import os
25import unittest
27import lsst.utils
28import lsst.utils.tests
29import lsst.geom
30import lsst.afw.geom as afwGeom
31import lsst.afw.image as afwImage
32import lsst.afw.image.utils as imageUtils
33import lsst.afw.math as afwMath
34import lsst.pex.exceptions as pexExcept
35from lsst.log import Log
37# Change the level to Log.DEBUG to see debug messages
38Log.getLogger("afw.image.Mask").setLevel(Log.INFO)
39Log.getLogger("TRACE3.afw.math.warp").setLevel(Log.INFO)
40Log.getLogger("TRACE4.afw.math.warp").setLevel(Log.INFO)
42try:
43 afwdataDir = lsst.utils.getPackageDir("afwdata")
44except pexExcept.NotFoundError:
45 afwdataDir = None
46 dataDir = None
47else:
48 dataDir = os.path.join(afwdataDir, "data")
49 originalExposureName = "medexp.fits"
50 originalExposurePath = os.path.join(dataDir, originalExposureName)
51 subExposureName = "medsub.fits"
52 subExposurePath = os.path.join(dataDir, originalExposureName)
53 originalFullExposureName = os.path.join(
54 "CFHT", "D4", "cal-53535-i-797722_1.fits")
55 originalFullExposurePath = os.path.join(dataDir, originalFullExposureName)
58class WarpExposureTestCase(lsst.utils.tests.TestCase):
59 """Test case for Warp
60 """
62 def testMatchSwarpLanczos2Exposure(self):
63 """Test that warpExposure matches swarp using a lanczos2 warping kernel.
64 """
65 self.compareToSwarp("lanczos2")
67 def testMatchSwarpLanczos2SubExposure(self):
68 """Test that warpExposure matches swarp using a lanczos2 warping kernel with a subexposure
69 """
70 for useDeepCopy in (False, True):
71 self.compareToSwarp("lanczos2", useSubregion=True,
72 useDeepCopy=useDeepCopy)
74 @unittest.skipIf(dataDir is None, "afwdata not setup")
75 def testBBox(self):
76 """Test that the default bounding box includes all warped pixels
77 """
78 kernelName = "lanczos2"
79 warper = afwMath.Warper(kernelName)
80 originalExposure, swarpedImage, swarpedWcs = self.getSwarpedImage(
81 kernelName=kernelName, useSubregion=True, useDeepCopy=False)
83 imageUtils.defineFilter("i", 748.1)
85 originalFilter = afwImage.Filter("i")
86 originalPhotoCalib = afwImage.PhotoCalib(1.0e5, 1.0e3)
87 originalExposure.setFilter(originalFilter)
88 originalExposure.setPhotoCalib(originalPhotoCalib)
90 warpedExposure1 = warper.warpExposure(
91 destWcs=swarpedWcs, srcExposure=originalExposure)
92 # the default size must include all good pixels, so growing the bbox
93 # should not add any
94 warpedExposure2 = warper.warpExposure(
95 destWcs=swarpedWcs, srcExposure=originalExposure, border=1)
96 # a bit of excess border is allowed, but surely not as much as 10 (in
97 # fact it is approx. 5)
98 warpedExposure3 = warper.warpExposure(
99 destWcs=swarpedWcs, srcExposure=originalExposure, border=-10)
100 # assert that warpedExposure and warpedExposure2 have the same number of non-no_data pixels
101 # and that warpedExposure3 has fewer
102 noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA")
103 mask1Arr = warpedExposure1.getMaskedImage().getMask().getArray()
104 mask2Arr = warpedExposure2.getMaskedImage().getMask().getArray()
105 mask3Arr = warpedExposure3.getMaskedImage().getMask().getArray()
106 nGood1 = (mask1Arr & noDataBitMask == 0).sum()
107 nGood2 = (mask2Arr & noDataBitMask == 0).sum()
108 nGood3 = (mask3Arr & noDataBitMask == 0).sum()
109 self.assertEqual(nGood1, nGood2)
110 self.assertLess(nGood3, nGood1)
112 self.assertEqual(warpedExposure1.getFilter().getName(),
113 originalFilter.getName())
114 self.assertEqual(warpedExposure1.getPhotoCalib(), originalPhotoCalib)
116 @unittest.skipIf(dataDir is None, "afwdata not setup")
117 def testDestBBox(self):
118 """Test that the destBBox argument works
119 """
120 kernelName = "lanczos2"
121 warper = afwMath.Warper(kernelName)
122 originalExposure, swarpedImage, swarpedWcs = self.getSwarpedImage(
123 kernelName=kernelName, useSubregion=True, useDeepCopy=False)
125 bbox = lsst.geom.Box2I(lsst.geom.Point2I(100, 25), lsst.geom.Extent2I(3, 7))
126 warpedExposure = warper.warpExposure(
127 destWcs=swarpedWcs,
128 srcExposure=originalExposure,
129 destBBox=bbox,
130 # should be ignored
131 border=-2,
132 # should be ignored
133 maxBBox=lsst.geom.Box2I(lsst.geom.Point2I(1, 2),
134 lsst.geom.Extent2I(8, 9)),
135 )
136 self.assertEqual(bbox, warpedExposure.getBBox(afwImage.PARENT))
138 @unittest.skipIf(dataDir is None, "afwdata not setup")
139 def getSwarpedImage(self, kernelName, useSubregion=False, useDeepCopy=False):
140 """
141 Inputs:
142 - kernelName: name of kernel in the form used by afwImage.makeKernel
143 - useSubregion: if True then the original source exposure (from which the usual
144 test exposure was extracted) is read and the correct subregion extracted
145 - useDeepCopy: if True then the copy of the subimage is a deep copy,
146 else it is a shallow copy; ignored if useSubregion is False
148 Returns:
149 - originalExposure
150 - swarpedImage
151 - swarpedWcs
152 """
153 if useSubregion:
154 originalFullExposure = afwImage.ExposureF(originalExposurePath)
155 # "medsub" is a subregion of med starting at 0-indexed pixel (40, 150) of size 145 x 200
156 bbox = lsst.geom.Box2I(lsst.geom.Point2I(40, 150),
157 lsst.geom.Extent2I(145, 200))
158 originalExposure = afwImage.ExposureF(
159 originalFullExposure, bbox, afwImage.LOCAL, useDeepCopy)
160 swarpedImageName = f"medsubswarp1{kernelName}.fits"
161 else:
162 originalExposure = afwImage.ExposureF(originalExposurePath)
163 swarpedImageName = f"medswarp1{kernelName}.fits"
165 swarpedImagePath = os.path.join(dataDir, swarpedImageName)
166 swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath)
167 swarpedImage = swarpedDecoratedImage.getImage()
168 swarpedMetadata = swarpedDecoratedImage.getMetadata()
169 swarpedWcs = afwGeom.makeSkyWcs(swarpedMetadata)
170 return (originalExposure, swarpedImage, swarpedWcs)
172 @unittest.skipIf(dataDir is None, "afwdata not setup")
173 def compareToSwarp(self, kernelName,
174 useSubregion=False, useDeepCopy=False,
175 interpLength=10, cacheSize=100000,
176 rtol=4e-05, atol=1e-2):
177 """Compare warpExposure to swarp for given warping kernel.
179 Note that swarp only warps the image plane, so only test that plane.
181 Inputs:
182 - kernelName: name of kernel in the form used by afwImage.makeKernel
183 - useSubregion: if True then the original source exposure (from which the usual
184 test exposure was extracted) is read and the correct subregion extracted
185 - useDeepCopy: if True then the copy of the subimage is a deep copy,
186 else it is a shallow copy; ignored if useSubregion is False
187 - interpLength: interpLength argument for lsst.afw.math.warpExposure
188 - cacheSize: cacheSize argument for lsst.afw.math.SeparableKernel.computeCache;
189 0 disables the cache
190 10000 gives some speed improvement but less accurate results (atol must be increased)
191 100000 gives better accuracy but no speed improvement in this test
192 - rtol: relative tolerance as used by numpy.allclose
193 - atol: absolute tolerance as used by numpy.allclose
194 """
195 warper = afwMath.Warper(kernelName)
197 originalExposure, swarpedImage, swarpedWcs = self.getSwarpedImage(
198 kernelName=kernelName, useSubregion=useSubregion, useDeepCopy=useDeepCopy)
199 maxBBox = lsst.geom.Box2I(
200 lsst.geom.Point2I(swarpedImage.getX0(), swarpedImage.getY0()),
201 lsst.geom.Extent2I(swarpedImage.getWidth(), swarpedImage.getHeight()))
203 # warning: this test assumes that the swarped image is smaller than it needs to be
204 # to hold all of the warped pixels
205 afwWarpedExposure = warper.warpExposure(
206 destWcs=swarpedWcs,
207 srcExposure=originalExposure,
208 maxBBox=maxBBox,
209 )
210 afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage()
212 afwWarpedMask = afwWarpedMaskedImage.getMask()
213 noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA")
214 noDataMask = afwWarpedMask.getArray() & noDataBitMask
216 msg = "afw and swarp %s-warped %s (ignoring bad pixels)"
217 self.assertImagesAlmostEqual(afwWarpedMaskedImage.getImage(), swarpedImage,
218 skipMask=noDataMask, rtol=rtol, atol=atol, msg=msg)
221class MemoryTester(lsst.utils.tests.MemoryTestCase):
222 pass
225def setup_module(module):
226 lsst.utils.tests.init()
229if __name__ == "__main__": 229 ↛ 230line 229 didn't jump to line 230, because the condition on line 229 was never true
230 lsst.utils.tests.init()
231 unittest.main()