Coverage for tests/test_methods.py: 7%
229 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 04:03 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 04:03 -0700
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#
22import unittest
23import re
25import numpy as np
27import lsst.utils.tests
28import lsst.daf.base as dafBase
29import lsst.geom
30import lsst.afw.geom as afwGeom
31import lsst.afw.image as afwImage
32from lsst.afw.image.testUtils import imagesDiffer
33from lsst.afw.geom.utils import _compareWcsOverBBox
36class TestTestUtils(lsst.utils.tests.TestCase):
37 """Test test methods added to lsst.utils.tests.TestCase
38 """
39 def testAssertWcsAlmostEqualOverBBox(self):
40 """Test assertWcsAlmostEqualOverBBox and wcsAlmostEqualOverBBox"""
41 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
42 lsst.geom.Extent2I(3001, 3001))
43 ctrPix = lsst.geom.Point2I(1500, 1500)
44 metadata = dafBase.PropertySet()
45 metadata.set("RADESYS", "FK5")
46 metadata.set("EQUINOX", 2000.0)
47 metadata.set("CTYPE1", "RA---TAN")
48 metadata.set("CTYPE2", "DEC--TAN")
49 metadata.set("CUNIT1", "deg")
50 metadata.set("CUNIT2", "deg")
51 metadata.set("CRVAL1", 215.5)
52 metadata.set("CRVAL2", 53.0)
53 metadata.set("CRPIX1", ctrPix[0] + 1)
54 metadata.set("CRPIX2", ctrPix[1] + 1)
55 metadata.set("CD1_1", 5.1e-05)
56 metadata.set("CD1_2", 0.0)
57 metadata.set("CD2_2", -5.1e-05)
58 metadata.set("CD2_1", 0.0)
59 wcs0 = lsst.afw.geom.makeSkyWcs(metadata, strip=False)
60 metadata.set("CRVAL2", 53.000001) # tweak CRVAL2 for wcs1
61 wcs1 = lsst.afw.geom.makeSkyWcs(metadata)
63 self.assertWcsAlmostEqualOverBBox(wcs0, wcs0, bbox,
64 maxDiffSky=0*lsst.geom.arcseconds, maxDiffPix=0)
65 self.assertTrue(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs0, bbox,
66 maxDiffSky=0*lsst.geom.arcseconds, maxDiffPix=0))
68 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
69 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.02)
70 self.assertTrue(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
71 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.02))
73 with self.assertRaises(AssertionError):
74 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
75 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.02)
76 self.assertFalse(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
77 maxDiffSky=0.001*lsst.geom.arcseconds,
78 maxDiffPix=0.02))
80 with self.assertRaises(AssertionError):
81 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
82 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.001)
83 self.assertFalse(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox,
84 maxDiffSky=0.04*lsst.geom.arcseconds,
85 maxDiffPix=0.001))
87 # check that doShortCircuit works in the private implementation
88 errStr1 = _compareWcsOverBBox(wcs0, wcs1, bbox,
89 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.001,
90 doShortCircuit=False)
91 errStr2 = _compareWcsOverBBox(wcs0, wcs1, bbox,
92 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.001,
93 doShortCircuit=True)
94 self.assertNotEqual(errStr1, errStr2)
96 def checkMaskedImage(self, mi):
97 """Run assertImage-like function tests on a masked image
99 Compare the masked image to itself, then alter copies and check that the altered copy
100 is or is not nearly equal the original, depending on the amount of change, rtol and atol
101 """
102 epsilon = 1e-5 # margin to avoid roundoff error
104 mi0 = mi.Factory(mi, True) # deep copy
105 mi1 = mi.Factory(mi, True)
107 # a masked image should be exactly equal to itself
108 self.assertMaskedImagesEqual(mi0, mi1)
109 self.assertMaskedImagesEqual(mi1, mi0)
110 self.assertMaskedImagesAlmostEqual(mi0, mi1, atol=0, rtol=0)
111 self.assertMaskedImagesAlmostEqual(mi0, mi1, atol=0, rtol=0)
112 self.assertMaskedImagesAlmostEqual(
113 (mi0.image.array, mi0.mask.array, mi0.variance.array), mi1, atol=0, rtol=0)
114 self.assertMaskedImagesAlmostEqual(
115 mi0, (mi1.image.array, mi1.mask.array, mi1.variance.array), atol=0, rtol=0)
116 self.assertMaskedImagesAlmostEqual(
117 (mi0.image.array, mi0.mask.array, mi0.variance.array),
118 (mi1.image.array, mi1.mask.array, mi1.variance.array), atol=0, rtol=0)
119 for getName in ("getImage", "getVariance"):
120 plane0 = getattr(mi0, getName)()
121 plane1 = getattr(mi1, getName)()
122 self.assertImagesEqual(plane0, plane1)
123 self.assertImagesEqual(plane1, plane0)
124 self.assertImagesAlmostEqual(plane0, plane1, atol=0, rtol=0)
125 self.assertImagesAlmostEqual(plane1, plane0, atol=0, rtol=0)
126 self.assertImagesAlmostEqual(
127 plane0.getArray(), plane1, atol=0, rtol=0)
128 self.assertImagesAlmostEqual(
129 plane0, plane1.getArray(), atol=0, rtol=0)
130 self.assertImagesAlmostEqual(
131 plane0.getArray(), plane1.getArray(), atol=0, rtol=0)
132 self.assertMasksEqual(plane0, plane1)
133 self.assertMasksEqual(plane1, plane0)
134 self.assertMasksEqual(plane0.getArray(), plane1)
135 self.assertMasksEqual(plane0, plane1.getArray())
136 self.assertMasksEqual(plane0.getArray(), plane1.getArray())
137 self.assertMasksEqual(mi0.getMask(), mi1.getMask())
138 self.assertMasksEqual(mi1.getMask(), mi0.getMask())
140 # alter image and variance planes and check the results
141 for getName in ("getImage", "getVariance"):
142 isFloat = getattr(mi, getName)().getArray().dtype.kind == "f"
143 if isFloat:
144 for errVal in (np.nan, np.inf, -np.inf):
145 mi0 = mi.Factory(mi, True)
146 mi1 = mi.Factory(mi, True)
147 plane0 = getattr(mi0, getName)()
148 plane1 = getattr(mi1, getName)()
149 plane1[2, 2] = errVal
150 with self.assertRaises(Exception):
151 self.assertImagesAlmostEqual(plane0, plane1)
152 with self.assertRaises(Exception):
153 self.assertImagesAlmostEqual(plane0.getArray(), plane1)
154 with self.assertRaises(Exception):
155 self.assertImagesAlmostEqual(plane1, plane0)
156 with self.assertRaises(Exception):
157 self.assertMaskedImagesAlmostEqual(mi0, mi1)
158 with self.assertRaises(Exception):
159 self.assertMaskedImagesAlmostEqual(
160 mi0, (mi1.image.array, mi1.mask.array, mi1.variance.array))
161 with self.assertRaises(Exception):
162 self.assertMaskedImagesAlmostEqual(mi1, mi0)
164 skipMask = mi.getMask().Factory(mi.getMask(), True)
165 skipMaskArr = skipMask.getArray()
166 skipMaskArr[:] = 0
167 skipMaskArr[2, 2] = 1
168 self.assertImagesAlmostEqual(
169 plane0, plane1, skipMask=skipMaskArr, atol=0, rtol=0)
170 self.assertImagesAlmostEqual(
171 plane0, plane1, skipMask=skipMask, atol=0, rtol=0)
172 self.assertMaskedImagesAlmostEqual(
173 mi0, mi1, skipMask=skipMaskArr, atol=0, rtol=0)
174 self.assertMaskedImagesAlmostEqual(
175 mi0, mi1, skipMask=skipMask, atol=0, rtol=0)
177 for dval in (0.001, 0.03):
178 mi0 = mi.Factory(mi, True)
179 mi1 = mi.Factory(mi, True)
180 plane0 = getattr(mi0, getName)()
181 plane1 = getattr(mi1, getName)()
182 plane1[2, 2] += dval
183 val1 = plane1[2, 2, afwImage.LOCAL]
184 self.assertImagesAlmostEqual(
185 plane0, plane1, rtol=0, atol=dval + epsilon)
186 self.assertImagesAlmostEqual(
187 plane0, plane1, rtol=dval/val1 + epsilon, atol=0)
188 self.assertMaskedImagesAlmostEqual(
189 mi0, mi1, rtol=0, atol=dval + epsilon)
190 self.assertMaskedImagesAlmostEqual(
191 mi1, mi0, rtol=0, atol=dval + epsilon)
192 with self.assertRaises(Exception):
193 self.assertImagesAlmostEqual(
194 plane0, plane1, rtol=0, atol=dval - epsilon)
195 with self.assertRaises(Exception):
196 self.assertImagesAlmostEqual(
197 plane0, plane1, rtol=dval/val1 - epsilon, atol=0)
198 with self.assertRaises(Exception):
199 self.assertMaskedImagesAlmostEqual(
200 mi0, mi1, rtol=0, atol=dval - epsilon)
201 with self.assertRaises(Exception):
202 self.assertMaskedImagesAlmostEqual(
203 mi0, mi1, rtol=dval/val1 - epsilon, atol=0)
204 else:
205 # plane is an integer of some type
206 for dval in (1, 3):
207 mi0 = mi.Factory(mi, True)
208 mi1 = mi.Factory(mi, True)
209 plane0 = getattr(mi0, getName)()
210 plane1 = getattr(mi1, getName)()
211 plane1[2, 2] += dval
212 val1 = plane1[2, 2, afwImage.LOCAL]
213 # int value and test is <= so epsilon not required for atol
214 # but rtol is a fraction, so epsilon is still safest for
215 # the rtol test
216 self.assertImagesAlmostEqual(
217 plane0, plane1, rtol=0, atol=dval)
218 self.assertImagesAlmostEqual(
219 plane0, plane1, rtol=dval/val1 + epsilon, atol=0)
220 with self.assertRaises(Exception):
221 self.assertImagesAlmostEqual(
222 plane0, plane1, rtol=0, atol=dval - epsilon)
223 with self.assertRaises(Exception):
224 self.assertImagesAlmostEqual(
225 plane0, plane1, rtol=dval/val1 - epsilon, atol=0)
227 # alter mask and check the results
228 mi0 = mi.Factory(mi, True)
229 mi1 = mi.Factory(mi, True)
230 mask0 = mi0.getMask()
231 mask1 = mi1.getMask()
232 for dval in (1, 3):
233 # getArray avoids "unsupported operand type" failure
234 mask1.getArray()[2, 2] += 1
235 with self.assertRaises(Exception):
236 self.assertMasksEqual(mask0, mask1)
237 with self.assertRaises(Exception):
238 self.assertMasksEqual(mask1, mask0)
239 with self.assertRaises(Exception):
240 self.assertMaskedImagesEqual(mi0, mi1)
241 with self.assertRaises(Exception):
242 self.assertMaskedImagesEqual(mi1, mi0)
244 skipMask = mi.getMask().Factory(mi.getMask(), True)
245 skipMaskArr = skipMask.getArray()
246 skipMaskArr[:] = 0
247 skipMaskArr[2, 2] = 1
248 self.assertMasksEqual(mask0, mask1, skipMask=skipMaskArr)
249 self.assertMasksEqual(mask0, mask1, skipMask=skipMask)
250 self.assertMaskedImagesAlmostEqual(
251 mi0, mi1, skipMask=skipMaskArr, atol=0, rtol=0)
252 self.assertMaskedImagesAlmostEqual(
253 mi0, mi1, skipMask=skipMask, atol=0, rtol=0)
255 def testAssertImagesAlmostEqual(self):
256 """Test assertImagesAlmostEqual, assertMasksEqual and assertMaskedImagesAlmostEqual
257 """
258 width = 10
259 height = 9
261 for miType in (afwImage.MaskedImageF, afwImage.MaskedImageD, afwImage.MaskedImageI,
262 afwImage.MaskedImageU):
263 mi = makeRampMaskedImageWithNans(width, height, miType)
264 self.checkMaskedImage(mi)
266 for invalidType in (np.zeros([width+1, height]), str, self.assertRaises):
267 mi = makeRampMaskedImageWithNans(width, height, miType)
268 with self.assertRaises(TypeError):
269 self.assertMasksEqual(mi.getMask(), invalidType)
270 with self.assertRaises(TypeError):
271 self.assertMasksEqual(invalidType, mi.getMask())
272 with self.assertRaises(TypeError):
273 self.assertMasksEqual(
274 mi.getMask(), mi.getMask(), skipMask=invalidType)
276 with self.assertRaises(TypeError):
277 self.assertImagesAlmostEqual(mi.getImage(), invalidType)
278 with self.assertRaises(TypeError):
279 self.assertImagesAlmostEqual(invalidType, mi.getImage())
280 with self.assertRaises(TypeError):
281 self.assertImagesAlmostEqual(
282 mi.getImage(), mi.getImage(), skipMask=invalidType)
284 with self.assertRaises(TypeError):
285 self.assertMaskedImagesAlmostEqual(mi, invalidType)
286 with self.assertRaises(TypeError):
287 self.assertMaskedImagesAlmostEqual(invalidType, mi)
288 with self.assertRaises(TypeError):
289 self.assertMaskedImagesAlmostEqual(
290 mi, mi, skipMask=invalidType)
292 with self.assertRaises(TypeError):
293 self.assertMaskedImagesAlmostEqual(
294 mi.getImage(), mi.getImage())
296 def testUnsignedImages(self):
297 """Unsigned images can give incorrect differences unless the test code is careful
298 """
299 image0 = np.zeros([5, 5], dtype=np.uint8)
300 image1 = np.zeros([5, 5], dtype=np.uint8)
301 image0[0, 0] = 1
302 image1[0, 1] = 2
304 # arrays differ by a maximum of 2
305 errMsg1 = imagesDiffer(image0, image1)
306 match = re.match(r"maxDiff *= *(\d+)", errMsg1, re.IGNORECASE)
307 self.assertIsNotNone(match)
308 self.assertEqual(match.group(1), "2")
310 # arrays are equal to within 5
311 self.assertImagesAlmostEqual(image0, image1, atol=5)
314def makeRampMaskedImageWithNans(width, height, imgClass=afwImage.MaskedImageF):
315 """Make a masked image that is a ramp with additional non-finite values
317 Make a masked image with the following additional non-finite values
318 in the variance plane and (if image is of some floating type) image plane:
319 - nan at [0, 0]
320 - inf at [1, 0]
321 - -inf at [0, 1]
322 """
323 mi = makeRampMaskedImage(width, height, imgClass)
325 var = mi.getVariance()
326 var[0, 0] = np.nan
327 var[1, 0] = np.inf
328 var[0, 1] = -np.inf
330 im = mi.getImage()
331 try:
332 np.array([np.nan], dtype=im.getArray().dtype)
333 except Exception:
334 # image plane does not support nan, etc. (presumably an int of some
335 # variety)
336 pass
337 else:
338 # image plane does support nan, etc.
339 im[0, 0] = np.nan
340 im[1, 0] = np.inf
341 im[0, 1] = -np.inf
342 return mi
345def makeRampMaskedImage(width, height, imgClass=afwImage.MaskedImageF):
346 """Make a ramp image of the specified size and image class
348 Image values start from 0 at the lower left corner and increase by 1 along rows
349 Variance values equal image values + 100
350 Mask values equal image values modulo 8 bits (leaving plenty of unused values)
351 """
352 mi = imgClass(width, height)
353 image = mi.getImage()
354 mask = mi.getMask()
355 variance = mi.getVariance()
356 val = 0
357 for yInd in range(height):
358 for xInd in range(width):
359 image[xInd, yInd, afwImage.LOCAL] = val
360 variance[xInd, yInd, afwImage.LOCAL] = val + 100
361 mask[xInd, yInd, afwImage.LOCAL] = val % 0x100
362 val += 1
363 return mi
366class MemoryTester(lsst.utils.tests.MemoryTestCase):
367 pass
370def setup_module(module):
371 lsst.utils.tests.init()
374if __name__ == "__main__": 374 ↛ 375line 374 didn't jump to line 375, because the condition on line 374 was never true
375 lsst.utils.tests.init()
376 unittest.main()