22 """Utilities that should be imported into the lsst.afw.geom namespace when lsst.afw.geom is used 24 In the case of the assert functions, importing them makes them available in lsst.utils.tests.TestCase 26 __all__ = [
"wcsAlmostEqualOverBBox"]
35 from .angle
import arcseconds
36 from .box
import Box2D
37 from .coordinates
import Point2D
38 from .endpoint
import GenericEndpoint, Point2Endpoint, SpherePointEndpoint
42 """Format extra error message, if any 49 @lsst.utils.tests.inTestCase
51 ignoreWrap=True, msg="Angles differ"):
52 r"""Assert that two `~lsst.afw.geom.Angle`\ s are almost equal, ignoring wrap differences by default 56 testCase : `unittest.TestCase` 57 test case the test is part of; an object supporting one method: fail(self, msgStr) 58 ang0 : `lsst.afw.geom.Angle` 60 ang1 : `an lsst.afw.geom.Angle` 62 maxDiff : `an lsst.afw.geom.Angle` 63 maximum difference between the two angles 65 ignore wrap when comparing the angles? 66 - if True then wrap is ignored, e.g. 0 and 360 degrees are considered equal 67 - if False then wrap matters, e.g. 0 and 360 degrees are considered different 69 exception message prefix; details of the error are appended after ": " 74 Raised if the difference is greater than ``maxDiff`` 76 measDiff = ang1 - ang0
78 measDiff = measDiff.wrapCtr()
79 if abs(measDiff) > maxDiff:
80 testCase.fail(
"%s: measured difference %s arcsec > max allowed %s arcsec" %
81 (msg, measDiff.asArcseconds(), maxDiff.asArcseconds()))
84 @lsst.utils.tests.inTestCase
86 """Assert that two Cartesian points are almost equal. 88 Each point can be any indexable pair of two floats, including 89 Point2D or Extent2D, a list or a tuple. 93 testCase : `unittest.TestCase` 94 test case the test is part of; an object supporting one method: fail(self, msgStr) 95 pair0 : pair of `float` 97 pair1 : pair of `floats` 100 maximum radial separation between the two points 102 exception message prefix; details of the error are appended after ": " 107 Raised if the radial difference is greater than ``maxDiff`` 113 Does not compare types, just compares values. 116 raise RuntimeError(
"len(pair0)=%s != 2" % (len(pair0),))
118 raise RuntimeError(
"len(pair1)=%s != 2" % (len(pair1),))
120 pairDiff = [
float(pair1[i] - pair0[i])
for i
in range(2)]
121 measDiff = math.hypot(*pairDiff)
122 if measDiff > maxDiff:
123 testCase.fail(
"%s: measured radial distance = %s > maxDiff = %s, pair0=(%r, %r), pair1=(%r, %r)" %
124 (msg, measDiff, maxDiff, pair0[0], pair0[1], pair1[0], pair1[1]))
127 @lsst.utils.tests.inTestCase
129 """Assert that two lists of Cartesian points are almost equal 131 Each point can be any indexable pair of two floats, including 132 Point2D or Extent2D, a list or a tuple. 136 testCase : `unittest.TestCase` 137 test case the test is part of; an object supporting one method: fail(self, msgStr) 138 list0 : `list` of pairs of `float` 140 list1 : `list` of pairs of `float` 143 maximum radial separation between the two points 145 additional information for the error message; appended after ": " 150 Raised if the radial difference is greater than ``maxDiff`` 156 Does not compare types, just values. 158 testCase.assertEqual(len(list0), len(list1))
159 lenList1 = np.array([len(val)
for val
in list0])
160 lenList2 = np.array([len(val)
for val
in list1])
161 testCase.assertTrue(np.all(lenList1 == 2))
162 testCase.assertTrue(np.all(lenList2 == 2))
164 diffArr = np.array([(val0[0] - val1[0], val0[1] - val1[1])
165 for val0, val1
in zip(list0, list1)], dtype=float)
166 sepArr = np.hypot(diffArr[:, 0], diffArr[:, 1])
167 badArr = sepArr > maxDiff
169 maxInd = np.argmax(sepArr)
170 testCase.fail(
"PairLists differ in %s places; max separation is at %s: %s > %s%s" %
171 (np.sum(badArr), maxInd, sepArr[maxInd], maxDiff,
extraMsg(msg)))
174 @lsst.utils.tests.inTestCase
176 r"""Assert that two `~lsst.afw.geom.SpherePoint`\ s are almost equal 180 testCase : `unittest.TestCase` 181 test case the test is part of; an object supporting one method: fail(self, msgStr) 182 sp0 : `lsst.afw.geom.SpherePoint` 184 sp1 : `lsst.afw.geom.SpherePoint` 186 maxSep : `lsst.afw.geom.Angle` 189 extra information to be printed with any error message 191 if sp0.separation(sp1) > maxSep:
192 testCase.fail(
"Angular separation between %s and %s = %s\" > maxSep = %s\"%s" %
193 (sp0, sp1, sp0.separation(sp1).asArcseconds(), maxSep.asArcseconds(),
extraMsg(msg)))
196 @lsst.utils.tests.inTestCase
198 r"""Assert that two lists of `~lsst.afw.geom.SpherePoint`\ s are almost equal 202 testCase : `unittest.TestCase` 203 test case the test is part of; an object supporting one method: fail(self, msgStr) 204 splist0 : `list` of `lsst.afw.geom.SpherePoint` 205 list of SpherePoints 0 206 splist1 : `list` of `lsst.afw.geom.SpherePoint` 207 list of SpherePoints 1 208 maxSep : `lsst.afw.geom.Angle` 211 exception message prefix; details of the error are appended after ": " 213 testCase.assertEqual(len(splist0), len(splist1), msg=msg)
214 sepArr = np.array([sp0.separation(sp1)
215 for sp0, sp1
in zip(splist0, splist1)])
216 badArr = sepArr > maxSep
218 maxInd = np.argmax(sepArr)
219 testCase.fail(
"SpherePointLists differ in %s places; max separation is at %s: %s\" > %s\"%s" %
220 (np.sum(badArr), maxInd, sepArr[maxInd].asArcseconds(),
221 maxSep.asArcseconds(),
extraMsg(msg)))
224 @lsst.utils.tests.inTestCase
226 """Assert that two boxes (`~lsst.afw.geom.Box2D` or `~lsst.afw.geom.Box2I`) are almost equal 230 testCase : `unittest.TestCase` 231 test case the test is part of; an object supporting one method: fail(self, msgStr) 232 box0 : `lsst.afw.geom.Box2D` or `lsst.afw.geom.Box2I` 234 box1 : `lsst.afw.geom.Box2D` or `lsst.afw.geom.Box2I` 237 maximum radial separation between the min points and max points 239 exception message prefix; details of the error are appended after ": " 244 Raised if the radial difference of the min points or max points is greater than maxDiff 250 Does not compare types, just compares values. 253 box1.getMin(), maxDiff=maxDiff, msg=msg +
": min")
255 box1.getMax(), maxDiff=maxDiff, msg=msg +
": max")
258 def _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01*arcseconds,
259 maxDiffPix=0.01, nx=5, ny=5, doShortCircuit=True):
260 """Compare two :py:class:`WCS <lsst.afw.geom.SkyWcs>` over a rectangular grid of pixel positions 264 wcs0 : `lsst.afw.geom.SkyWcs` 266 wcs1 : `lsst.afw.geom.SkyWcs` 268 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 269 boundaries of pixel grid over which to compare the WCSs 270 maxDiffSky : `lsst.afw.geom.Angle` 271 maximum separation between sky positions computed using Wcs.pixelToSky 273 maximum separation between pixel positions computed using Wcs.skyToPixel 275 number of points in x for the grid of pixel positions 277 number of points in y for the grid of pixel positions 278 doShortCircuit : `bool` 279 if True then stop at the first error, else test all values in the grid 280 and return information about the worst violations found 285 an empty string if the WCS are sufficiently close; else return a string describing 286 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 287 and sky coordinates (if pixel to sky error was excessive). If doShortCircuit is true 288 then the reported error is likely to be much less than the maximum error across the 293 "nx = %s and ny = %s must both be positive" % (nx, ny))
294 if maxDiffSky <= 0*arcseconds:
295 raise RuntimeError(
"maxDiffSky = %s must be positive" % (maxDiffSky,))
297 raise RuntimeError(
"maxDiffPix = %s must be positive" % (maxDiffPix,))
300 xList = np.linspace(bboxd.getMinX(), bboxd.getMaxX(), nx)
301 yList = np.linspace(bboxd.getMinY(), bboxd.getMaxY(), ny)
304 measDiffSky = (maxDiffSky,
"?")
305 measDiffPix = (maxDiffPix,
"?")
306 for x, y
in itertools.product(xList, yList):
308 sky0 = wcs0.pixelToSky(fromPixPos)
309 sky1 = wcs1.pixelToSky(fromPixPos)
310 diffSky = sky0.separation(sky1)
311 if diffSky > measDiffSky[0]:
312 measDiffSky = (diffSky, fromPixPos)
316 toPixPos0 = wcs0.skyToPixel(sky0)
317 toPixPos1 = wcs1.skyToPixel(sky0)
318 diffPix = math.hypot(*(toPixPos0 - toPixPos1))
319 if diffPix > measDiffPix[0]:
320 measDiffPix = (diffPix, sky0)
325 if measDiffSky[0] > maxDiffSky:
326 msgList.append(
"%s arcsec max measured sky error > %s arcsec max allowed sky error at pix pos=%s" %
327 (measDiffSky[0].asArcseconds(), maxDiffSky.asArcseconds(), measDiffSky[1]))
328 if measDiffPix[0] > maxDiffPix:
329 msgList.append(
"%s max measured pix error > %s max allowed pix error at sky pos=%s" %
330 (measDiffPix[0], maxDiffPix, measDiffPix[1]))
332 return "; ".join(msgList)
336 maxDiffPix=0.01, nx=5, ny=5):
337 """Test if two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions. 341 wcs0 : `lsst.afw.geom.SkyWcs` 343 wcs1 : `lsst.afw.geom.SkyWcs` 345 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 346 boundaries of pixel grid over which to compare the WCSs 347 maxDiffSky : `lsst.afw.geom.Angle` 348 maximum separation between sky positions computed using Wcs.pixelToSky 350 maximum separation between pixel positions computed using Wcs.skyToPixel 352 number of points in x for the grid of pixel positions 354 number of points in y for the grid of pixel positions 359 `True` if two WCS are almost equal over a grid of pixel positions, else `False` 361 return not bool(_compareWcsOverBBox(
365 maxDiffSky=maxDiffSky,
366 maxDiffPix=maxDiffPix,
373 @lsst.utils.tests.inTestCase
375 maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ"):
376 """Assert that two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions 378 Compare pixelToSky and skyToPixel for two WCS over a rectangular grid of pixel positions. 379 If the WCS are too divergent at any point, call testCase.fail; the message describes 380 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 381 and sky coordinates (if pixel to sky error was excessive) across the entire pixel grid. 385 testCase : `unittest.TestCase` 386 test case the test is part of; an object supporting one method: fail(self, msgStr) 387 wcs0 : `lsst.afw.geom.SkyWcs` 389 wcs1 : `lsst.afw.geom.SkyWcs` 391 bbox : `lsst.afw.geom.Box2I` or `lsst.afw.geom.Box2D` 392 boundaries of pixel grid over which to compare the WCSs 393 maxDiffSky : `lsst.afw.geom.Angle` 394 maximum separation between sky positions computed using Wcs.pixelToSky 396 maximum separation between pixel positions computed using Wcs.skyToPixel 398 number of points in x for the grid of pixel positions 400 number of points in y for the grid of pixel positions 402 exception message prefix; details of the error are appended after ": " 404 errMsg = _compareWcsOverBBox(
408 maxDiffSky=maxDiffSky,
409 maxDiffPix=maxDiffPix,
412 doShortCircuit=
False,
415 testCase.fail(
"%s: %s" % (msg, errMsg))
418 @lsst.utils.tests.inTestCase
420 warnings.warn(
"Deprecated. Use assertWcsAlmostEqualOverBBox",
421 DeprecationWarning, 2)
425 @lsst.utils.tests.inTestCase
427 """Generate a representative sample of ``Endpoints``. 431 testCase : `unittest.TestCase` 432 test case the test is part of; an object supporting one method: fail(self, msgStr) 437 List of endpoints with enough diversity to exercise ``Endpoint``-related 438 code. Each invocation of this method shall return independent objects. 440 return [GenericEndpoint(n)
for n
in range(1, 6)] + \
441 [Point2Endpoint(), SpherePointEndpoint()]
444 @lsst.utils.tests.inTestCase
446 warnings.warn(
"Deprecated. Use assertAnglesAlmostEqual",
447 DeprecationWarning, 2)
451 @lsst.utils.tests.inTestCase
453 warnings.warn(
"Deprecated. Use assertPairsAlmostEqual", DeprecationWarning, 2)
457 @lsst.utils.tests.inTestCase
459 warnings.warn(
"Deprecated. Use assertBoxesAlmostEqual", DeprecationWarning, 2)
def assertSpherePointsAlmostEqual(testCase, sp0, sp1, maxSep=0.001 *arcseconds, msg="")
Angle abs(Angle const &a)
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)