1 from __future__
import absolute_import, division, print_function
23 """Utilities that should be imported into the lsst.afw.geom namespace when lsst.afw.geom is used 25 In the case of the assert functions, importing them makes them available in lsst.utils.tests.TestCase 27 __all__ = [
"wcsAlmostEqualOverBBox"]
29 from builtins
import range
37 from .angle
import arcseconds
38 from .box
import Box2D
39 from .coordinates
import Point2D
40 from .endpoint
import GenericEndpoint, Point2Endpoint, SpherePointEndpoint
44 """Format extra error message, if any 51 @lsst.utils.tests.inTestCase
53 ignoreWrap=True, msg="Angles differ"):
54 r"""Assert that two `~lsst.afw.geom.Angle`\ s are almost equal, ignoring wrap differences by default 58 testCase : `unittest.TestCase` 59 test case the test is part of; an object supporting one method: fail(self, msgStr) 60 ang0 : `lsst.afw.geom.Angle` 62 ang1 : `an lsst.afw.geom.Angle` 64 maxDiff : `an lsst.afw.geom.Angle` 65 maximum difference between the two angles 67 ignore wrap when comparing the angles? 68 - if True then wrap is ignored, e.g. 0 and 360 degrees are considered equal 69 - if False then wrap matters, e.g. 0 and 360 degrees are considered different 71 exception message prefix; details of the error are appended after ": " 76 Raised if the difference is greater than ``maxDiff`` 78 measDiff = ang1 - ang0
80 measDiff = measDiff.wrapCtr()
81 if abs(measDiff) > maxDiff:
82 testCase.fail(
"%s: measured difference %s arcsec > max allowed %s arcsec" %
83 (msg, measDiff.asArcseconds(), maxDiff.asArcseconds()))
86 @lsst.utils.tests.inTestCase
88 """Assert that two Cartesian points are almost equal. 90 Each point can be any indexable pair of two floats, including 91 Point2D or Extent2D, a list or a tuple. 95 testCase : `unittest.TestCase` 96 test case the test is part of; an object supporting one method: fail(self, msgStr) 97 pair0 : pair of `float` 99 pair1 : pair of `floats` 102 maximum radial separation between the two points 104 exception message prefix; details of the error are appended after ": " 109 Raised if the radial difference is greater than ``maxDiff`` 115 Does not compare types, just compares values. 118 raise RuntimeError(
"len(pair0)=%s != 2" % (len(pair0),))
120 raise RuntimeError(
"len(pair1)=%s != 2" % (len(pair1),))
122 pairDiff = [float(pair1[i] - pair0[i])
for i
in range(2)]
123 measDiff = math.hypot(*pairDiff)
124 if measDiff > maxDiff:
125 testCase.fail(
"%s: measured radial distance = %s > maxDiff = %s, pair0=(%r, %r), pair1=(%r, %r)" %
126 (msg, measDiff, maxDiff, pair0[0], pair0[1], pair1[0], pair1[1]))
129 @lsst.utils.tests.inTestCase
131 """Assert that two lists of Cartesian points are almost equal 133 Each point can be any indexable pair of two floats, including 134 Point2D or Extent2D, a list or a tuple. 138 testCase : `unittest.TestCase` 139 test case the test is part of; an object supporting one method: fail(self, msgStr) 140 list0 : `list` of pairs of `float` 142 list1 : `list` of pairs of `float` 145 maximum radial separation between the two points 147 additional information for the error message; appended after ": " 152 Raised if the radial difference is greater than ``maxDiff`` 158 Does not compare types, just values. 160 testCase.assertEqual(len(list0), len(list1))
161 lenList1 = np.array([len(val)
for val
in list0])
162 lenList2 = np.array([len(val)
for val
in list1])
163 testCase.assertTrue(np.all(lenList1 == 2))
164 testCase.assertTrue(np.all(lenList2 == 2))
166 diffArr = np.array([(val0[0] - val1[0], val0[1] - val1[1])
167 for val0, val1
in zip(list0, list1)], dtype=float)
168 sepArr = np.hypot(diffArr[:, 0], diffArr[:, 1])
169 badArr = sepArr > maxDiff
171 maxInd = np.argmax(sepArr)
172 testCase.fail(
"PairLists differ in %s places; max separation is at %s: %s > %s%s" %
173 (np.sum(badArr), maxInd, sepArr[maxInd], maxDiff,
extraMsg(msg)))
176 @lsst.utils.tests.inTestCase
178 r"""Assert that two `~lsst.afw.geom.SpherePoint`\ s are almost equal 182 testCase : `unittest.TestCase` 183 test case the test is part of; an object supporting one method: fail(self, msgStr) 184 sp0 : `lsst.afw.geom.SpherePoint` 186 sp1 : `lsst.afw.geom.SpherePoint` 188 maxSep : `lsst.afw.geom.Angle` 191 extra information to be printed with any error message 193 if sp0.separation(sp1) > maxSep:
194 testCase.fail(
"Angular separation between %s and %s = %s\" > maxSep = %s\"%s" %
195 (sp0, sp1, sp0.separation(sp1).asArcseconds(), maxSep.asArcseconds(),
extraMsg(msg)))
198 @lsst.utils.tests.inTestCase
200 r"""Assert that two lists of `~lsst.afw.geom.SpherePoint`\ s are almost equal 204 testCase : `unittest.TestCase` 205 test case the test is part of; an object supporting one method: fail(self, msgStr) 206 splist0 : `list` of `lsst.afw.geom.SpherePoint` 207 list of SpherePoints 0 208 splist1 : `list` of `lsst.afw.geom.SpherePoint` 209 list of SpherePoints 1 210 maxSep : `lsst.afw.geom.Angle` 213 exception message prefix; details of the error are appended after ": " 215 testCase.assertEqual(len(splist0), len(splist1), msg=msg)
216 sepArr = np.array([sp0.separation(sp1)
217 for sp0, sp1
in zip(splist0, splist1)])
218 badArr = sepArr > maxSep
220 maxInd = np.argmax(sepArr)
221 testCase.fail(
"SpherePointLists differ in %s places; max separation is at %s: %s\" > %s\"%s" %
222 (np.sum(badArr), maxInd, sepArr[maxInd].asArcseconds(),
223 maxSep.asArcseconds(),
extraMsg(msg)))
226 @lsst.utils.tests.inTestCase
228 """Assert that two boxes (`~lsst.afw.geom.Box2D` or `~lsst.afw.geom.Box2I`) are almost equal 232 testCase : `unittest.TestCase` 233 test case the test is part of; an object supporting one method: fail(self, msgStr) 234 box0 : `lsst.afw.geom.Box2D` or `lsst.afw.geom.Box2I` 236 box1 : `lsst.afw.geom.Box2D` or `lsst.afw.geom.Box2I` 239 maximum radial separation between the min points and max points 241 exception message prefix; details of the error are appended after ": " 246 Raised if the radial difference of the min points or max points is greater than maxDiff 252 Does not compare types, just compares values. 255 box1.getMin(), maxDiff=maxDiff, msg=msg +
": min")
257 box1.getMax(), maxDiff=maxDiff, msg=msg +
": max")
260 def _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01*arcseconds,
261 maxDiffPix=0.01, nx=5, ny=5, doShortCircuit=True):
262 """Compare two :py:class:`WCS <lsst.afw.geom.SkyWcs>` over a rectangular grid of pixel positions 266 wcs0 : `lsst.afw.geom.SkyWcs` 268 wcs1 : `lsst.afw.geom.SkyWcs` 270 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 271 boundaries of pixel grid over which to compare the WCSs 272 maxDiffSky : `lsst.afw.geom.Angle` 273 maximum separation between sky positions computed using Wcs.pixelToSky 275 maximum separation between pixel positions computed using Wcs.skyToPixel 277 number of points in x for the grid of pixel positions 279 number of points in y for the grid of pixel positions 280 doShortCircuit : `bool` 281 if True then stop at the first error, else test all values in the grid 282 and return information about the worst violations found 287 an empty string if the WCS are sufficiently close; else return a string describing 288 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 289 and sky coordinates (if pixel to sky error was excessive). If doShortCircuit is true 290 then the reported error is likely to be much less than the maximum error across the 295 "nx = %s and ny = %s must both be positive" % (nx, ny))
296 if maxDiffSky <= 0*arcseconds:
297 raise RuntimeError(
"maxDiffSky = %s must be positive" % (maxDiffSky,))
299 raise RuntimeError(
"maxDiffPix = %s must be positive" % (maxDiffPix,))
302 xList = np.linspace(bboxd.getMinX(), bboxd.getMaxX(), nx)
303 yList = np.linspace(bboxd.getMinY(), bboxd.getMaxY(), ny)
306 measDiffSky = (maxDiffSky,
"?")
307 measDiffPix = (maxDiffPix,
"?")
308 for x, y
in itertools.product(xList, yList):
310 sky0 = wcs0.pixelToSky(fromPixPos)
311 sky1 = wcs1.pixelToSky(fromPixPos)
312 diffSky = sky0.separation(sky1)
313 if diffSky > measDiffSky[0]:
314 measDiffSky = (diffSky, fromPixPos)
318 toPixPos0 = wcs0.skyToPixel(sky0)
319 toPixPos1 = wcs1.skyToPixel(sky0)
320 diffPix = math.hypot(*(toPixPos0 - toPixPos1))
321 if diffPix > measDiffPix[0]:
322 measDiffPix = (diffPix, sky0)
327 if measDiffSky[0] > maxDiffSky:
328 msgList.append(
"%s arcsec max measured sky error > %s arcsec max allowed sky error at pix pos=%s" %
329 (measDiffSky[0].asArcseconds(), maxDiffSky.asArcseconds(), measDiffSky[1]))
330 if measDiffPix[0] > maxDiffPix:
331 msgList.append(
"%s max measured pix error > %s max allowed pix error at sky pos=%s" %
332 (measDiffPix[0], maxDiffPix, measDiffPix[1]))
334 return "; ".join(msgList)
338 maxDiffPix=0.01, nx=5, ny=5):
339 """Test if two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions. 343 wcs0 : `lsst.afw.geom.SkyWcs` 345 wcs1 : `lsst.afw.geom.SkyWcs` 347 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 348 boundaries of pixel grid over which to compare the WCSs 349 maxDiffSky : `lsst.afw.geom.Angle` 350 maximum separation between sky positions computed using Wcs.pixelToSky 352 maximum separation between pixel positions computed using Wcs.skyToPixel 354 number of points in x for the grid of pixel positions 356 number of points in y for the grid of pixel positions 361 `True` if two WCS are almost equal over a grid of pixel positions, else `False` 363 return not bool(_compareWcsOverBBox(
367 maxDiffSky=maxDiffSky,
368 maxDiffPix=maxDiffPix,
375 @lsst.utils.tests.inTestCase
377 maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ"):
378 """Assert that two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions 380 Compare pixelToSky and skyToPixel for two WCS over a rectangular grid of pixel positions. 381 If the WCS are too divergent at any point, call testCase.fail; the message describes 382 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 383 and sky coordinates (if pixel to sky error was excessive) across the entire pixel grid. 387 testCase : `unittest.TestCase` 388 test case the test is part of; an object supporting one method: fail(self, msgStr) 389 wcs0 : `lsst.afw.geom.SkyWcs` 391 wcs1 : `lsst.afw.geom.SkyWcs` 393 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 394 boundaries of pixel grid over which to compare the WCSs 395 maxDiffSky : `lsst.afw.geom.Angle` 396 maximum separation between sky positions computed using Wcs.pixelToSky 398 maximum separation between pixel positions computed using Wcs.skyToPixel 400 number of points in x for the grid of pixel positions 402 number of points in y for the grid of pixel positions 404 exception message prefix; details of the error are appended after ": " 406 errMsg = _compareWcsOverBBox(
410 maxDiffSky=maxDiffSky,
411 maxDiffPix=maxDiffPix,
414 doShortCircuit=
False,
417 testCase.fail(
"%s: %s" % (msg, errMsg))
420 @lsst.utils.tests.inTestCase
422 warnings.warn(
"Deprecated. Use assertWcsAlmostEqualOverBBox",
423 DeprecationWarning, 2)
427 @lsst.utils.tests.inTestCase
429 """Generate a representative sample of ``Endpoints``. 433 testCase : `unittest.TestCase` 434 test case the test is part of; an object supporting one method: fail(self, msgStr) 439 List of endpoints with enough diversity to exercise ``Endpoint``-related 440 code. Each invocation of this method shall return independent objects. 442 return [GenericEndpoint(n)
for n
in range(1, 6)] + \
443 [Point2Endpoint(), SpherePointEndpoint()]
446 @lsst.utils.tests.inTestCase
448 warnings.warn(
"Deprecated. Use assertAnglesAlmostEqual",
449 DeprecationWarning, 2)
453 @lsst.utils.tests.inTestCase
455 warnings.warn(
"Deprecated. Use assertPairsAlmostEqual", DeprecationWarning, 2)
459 @lsst.utils.tests.inTestCase
461 warnings.warn(
"Deprecated. Use assertBoxesAlmostEqual", DeprecationWarning, 2)
def assertSpherePointsAlmostEqual(testCase, sp0, sp1, maxSep=0.001 *arcseconds, msg="")
def makeEndpoints(testCase)
def assertBoxesNearlyEqual(args, kwargs)
def assertAnglesNearlyEqual(args, kwargs)
def assertWcsNearlyEqualOverBBox(args, kwargs)
def assertPairsAlmostEqual(testCase, pair0, pair1, maxDiff=1e-7, msg="Pairs differ")
def assertWcsAlmostEqualOverBBox(testCase, wcs0, wcs1, bbox, maxDiffSky=0.01 *arcseconds, maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ")
Point< double, 2 > Point2D
def wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01 *arcseconds, maxDiffPix=0.01, nx=5, ny=5)
def assertPairsNearlyEqual(args, kwargs)
def assertPairListsAlmostEqual(testCase, list0, list1, maxDiff=1e-7, msg=None)
def assertBoxesAlmostEqual(testCase, box0, box1, maxDiff=1e-7, msg="Boxes differ")
def assertAnglesAlmostEqual(testCase, ang0, ang1, maxDiff=0.001 *arcseconds, ignoreWrap=True, msg="Angles differ")
def assertSpherePointListsAlmostEqual(testCase, splist0, splist1, maxSep=0.001 *arcseconds, msg=None)