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 """!Assert that two angles are almost equal, ignoring wrap differences by default 56 @param[in] testCase unittest.TestCase instance the test is part of; 57 an object supporting one method: fail(self, msgStr) 58 @param[in] ang0 angle 0 (an lsst.afw.geom.Angle) 59 @param[in] ang1 angle 1 (an lsst.afw.geom.Angle) 60 @param[in] maxDiff maximum difference between the two angles (an lsst.afw.geom.Angle) 61 @param[in] ignoreWrap ignore wrap when comparing the angles? 62 - if True then wrap is ignored, e.g. 0 and 360 degrees are considered equal 63 - if False then wrap matters, e.g. 0 and 360 degrees are considered different 64 @param[in] msg exception message prefix; details of the error are appended after ": " 66 @throw AssertionError if the difference is greater than maxDiff 68 measDiff = ang1 - ang0
70 measDiff = measDiff.wrapCtr()
71 if abs(measDiff) > maxDiff:
72 testCase.fail(
"%s: measured difference %s arcsec > max allowed %s arcsec" %
73 (msg, measDiff.asArcseconds(), maxDiff.asArcseconds()))
76 @lsst.utils.tests.inTestCase
78 """!Assert that two Cartesian points are almost equal. 80 Each point can be any indexable pair of two floats, including 81 Point2D or Extent2D, a list or a tuple. 83 @warning Does not compare types, just compares values. 85 @param[in] testCase unittest.TestCase instance the test is part of; 86 an object supporting one method: fail(self, msgStr) 87 @param[in] pair0 pair 0 (a pair of floats) 88 @param[in] pair1 pair 1 (a pair of floats) 89 @param[in] maxDiff maximum radial separation between the two points 90 @param[in] msg exception message prefix; details of the error are appended after ": " 92 @throw AssertionError if the radial difference is greater than maxDiff 95 raise RuntimeError(
"len(pair0)=%s != 2" % (len(pair0),))
97 raise RuntimeError(
"len(pair1)=%s != 2" % (len(pair1),))
99 pairDiff = [float(pair1[i] - pair0[i])
for i
in range(2)]
100 measDiff = math.hypot(*pairDiff)
101 if measDiff > maxDiff:
102 testCase.fail(
"%s: measured radial distance = %s > maxDiff = %s" % (
103 msg, measDiff, maxDiff))
106 @lsst.utils.tests.inTestCase
108 """!Assert that two lists of Cartesian points are almost equal 110 Each point can be any indexable pair of two floats, including 111 Point2D or Extent2D, a list or a tuple. 113 @warning Does not compare types, just values. 115 @param[in] testCase unittest.TestCase instance the test is part of; 116 an object supporting one method: fail(self, msgStr) 117 @param[in] list0 list of pairs 0 (each element a pair of floats) 118 @param[in] list1 list of pairs 1 119 @param[in] maxDiff maximum radial separation between the two points 120 @param[in] msg additional information for the error message; appended after ": " 122 @throw AssertionError if the radial difference is greater than maxDiff 124 testCase.assertEqual(len(list0), len(list1))
125 lenList1 = np.array([len(val)
for val
in list0])
126 lenList2 = np.array([len(val)
for val
in list1])
127 testCase.assertTrue(np.all(lenList1 == 2))
128 testCase.assertTrue(np.all(lenList2 == 2))
130 diffArr = np.array([(val0[0] - val1[0], val0[1] - val1[1])
131 for val0, val1
in zip(list0, list1)], dtype=float)
132 sepArr = np.hypot(diffArr[:, 0], diffArr[:, 1])
133 badArr = sepArr > maxDiff
135 maxInd = np.argmax(sepArr)
136 testCase.fail(
"PairLists differ in %s places; max separation is at %s: %s > %s%s" %
137 (np.sum(badArr), maxInd, sepArr[maxInd], maxDiff,
extraMsg(msg)))
140 @lsst.utils.tests.inTestCase
142 """!Assert that two SpherePoints are almost equal 144 @param[in] testCase unittest.TestCase instance the test is part of; 145 an object supporting one method: fail(self, msgStr) 146 @param[in] sp0 SpherePoint 0 147 @param[in] sp1 SpherePoint 1 148 @param[in] maxSep maximum separation, an lsst.afw.geom.Angle 149 @param[in] msg extra information to be printed with any error message 151 if sp0.separation(sp1) > maxSep:
152 testCase.fail(
"Angular separation between %s and %s = %s\" > maxSep = %s\"%s" %
153 (sp0, sp1, sp0.separation(sp1).asArcseconds(), maxSep.asArcseconds(),
extraMsg(msg)))
156 @lsst.utils.tests.inTestCase
158 """!Assert that two lists of SpherePoints are almost equal 160 @param[in] testCase unittest.TestCase instance the test is part of; 161 an object supporting one method: fail(self, msgStr) 162 @param[in] splist0 list of SpherePoints 0 163 @param[in] splist1 list of SpherePoints 1 164 @param[in] maxSep maximum separation, an lsst.afw.geom.Angle 165 @param[in] msg exception message prefix; details of the error are appended after ": " 167 testCase.assertEqual(len(splist0), len(splist1), msg=msg)
168 sepArr = np.array([sp0.separation(sp1)
169 for sp0, sp1
in zip(splist0, splist1)])
170 badArr = sepArr > maxSep
172 maxInd = np.argmax(sepArr)
173 testCase.fail(
"SpherePointLists differ in %s places; max separation is at %s: %s\" > %s\"%s" %
174 (np.sum(badArr), maxInd, sepArr[maxInd].asArcseconds(),
175 maxSep.asArcseconds(),
extraMsg(msg)))
178 @lsst.utils.tests.inTestCase
180 """!Assert that two boxes (Box2D or Box2I) are almost equal 182 @warning Does not compare types, just compares values. 184 @param[in] testCase unittest.TestCase instance the test is part of; 185 an object supporting one method: fail(self, msgStr) 186 @param[in] box0 box 0 187 @param[in] box1 box 1 188 @param[in] maxDiff maximum radial separation between the min points and max points 189 @param[in] msg exception message prefix; details of the error are appended after ": " 191 @throw AssertionError if the radial difference of the min points or max points is greater than maxDiff 194 box1.getMin(), maxDiff=maxDiff, msg=msg +
": min")
196 box1.getMax(), maxDiff=maxDiff, msg=msg +
": max")
199 def _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01*arcseconds,
200 maxDiffPix=0.01, nx=5, ny=5, doShortCircuit=True):
201 """!Compare two WCS over a rectangular grid of pixel positions 203 @param[in] wcs0 WCS 0 (an lsst.afw.geom.SkyWcs) 204 @param[in] wcs1 WCS 1 (an lsst.afw.geom.SkyWcs) 205 @param[in] bbox boundaries of pixel grid over which to compare the WCSs (an lsst.afw.geom.Box2I or Box2D) 206 @param[in] maxDiffSky maximum separation between sky positions computed using Wcs.pixelToSky 207 (an lsst.afw.geom.Angle) 208 @param[in] maxDiffPix maximum separation between pixel positions computed using Wcs.skyToPixel 209 @param[in] nx number of points in x for the grid of pixel positions 210 @param[in] ny number of points in y for the grid of pixel positions 211 @param[in] doShortCircuit if True then stop at the first error, else test all values in the grid 212 and return information about the worst violations found 214 @return return an empty string if the WCS are sufficiently close; else return a string describing 215 the largest error measured in pixel coordinates (if sky to pixel error was excessive) and sky coordinates 216 (if pixel to sky error was excessive). If doShortCircuit is true then the reported error is likely to be 217 much less than the maximum error across the whole pixel grid. 221 "nx = %s and ny = %s must both be positive" % (nx, ny))
222 if maxDiffSky <= 0*arcseconds:
223 raise RuntimeError(
"maxDiffSky = %s must be positive" % (maxDiffSky,))
225 raise RuntimeError(
"maxDiffPix = %s must be positive" % (maxDiffPix,))
228 xList = np.linspace(bboxd.getMinX(), bboxd.getMaxX(), nx)
229 yList = np.linspace(bboxd.getMinY(), bboxd.getMaxY(), ny)
232 measDiffSky = (maxDiffSky,
"?")
233 measDiffPix = (maxDiffPix,
"?")
234 for x, y
in itertools.product(xList, yList):
236 sky0 = wcs0.pixelToSky(fromPixPos)
237 sky1 = wcs1.pixelToSky(fromPixPos)
238 diffSky = sky0.separation(sky1)
239 if diffSky > measDiffSky[0]:
240 measDiffSky = (diffSky, fromPixPos)
244 toPixPos0 = wcs0.skyToPixel(sky0)
245 toPixPos1 = wcs1.skyToPixel(sky0)
246 diffPix = math.hypot(*(toPixPos0 - toPixPos1))
247 if diffPix > measDiffPix[0]:
248 measDiffPix = (diffPix, sky0)
253 if measDiffSky[0] > maxDiffSky:
254 msgList.append(
"%s arcsec max measured sky error > %s arcsec max allowed sky error at pix pos=%s" %
255 (measDiffSky[0].asArcseconds(), maxDiffSky.asArcseconds(), measDiffSky[1]))
256 if measDiffPix[0] > maxDiffPix:
257 msgList.append(
"%s max measured pix error > %s max allowed pix error at sky pos=%s" %
258 (measDiffPix[0], maxDiffPix, measDiffPix[1]))
260 return "; ".join(msgList)
264 maxDiffPix=0.01, nx=5, ny=5):
265 """!Return True if two WCS are almost equal over a grid of pixel positions, else False 267 @param[in] wcs0 WCS 0 (an lsst.afw.geom.SkyWcs) 268 @param[in] wcs1 WCS 1 (an lsst.afw.geom.SkyWcs) 269 @param[in] bbox boundaries of pixel grid over which to compare the WCSs (an lsst.afw.geom.Box2I or Box2D) 270 @param[in] maxDiffSky maximum separation between sky positions computed using Wcs.pixelToSky 271 (an lsst.afw.geom.Angle) 272 @param[in] maxDiffPix maximum separation between pixel positions computed using Wcs.skyToPixel 273 @param[in] nx number of points in x for the grid of pixel positions 274 @param[in] ny number of points in y for the grid of pixel positions 276 return not bool(_compareWcsOverBBox(
280 maxDiffSky=maxDiffSky,
281 maxDiffPix=maxDiffPix,
288 @lsst.utils.tests.inTestCase
290 maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ"):
291 """!Assert that two WCS are almost equal over a grid of pixel positions 293 Compare pixelToSky and skyToPixel for two WCS over a rectangular grid of pixel positions. 294 If the WCS are too divergent at any point, call testCase.fail; the message describes 295 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 296 and sky coordinates (if pixel to sky error was excessive) across the entire pixel grid. 298 @param[in] testCase unittest.TestCase instance the test is part of; 299 an object supporting one method: fail(self, msgStr) 300 @param[in] wcs0 WCS 0 (an lsst.afw.geom.SkyWcs) 301 @param[in] wcs1 WCS 1 (an lsst.afw.geom.SkyWcs) 302 @param[in] bbox boundaries of pixel grid over which to compare the WCSs (an lsst.afw.geom.Box2I or Box2D) 303 @param[in] maxDiffSky maximum separation between sky positions computed using Wcs.pixelToSky 304 (an lsst.afw.geom.Angle) 305 @param[in] maxDiffPix maximum separation between pixel positions computed using Wcs.skyToPixel 306 @param[in] nx number of points in x for the grid of pixel positions 307 @param[in] ny number of points in y for the grid of pixel positions 308 @param[in] msg exception message prefix; details of the error are appended after ": " 310 errMsg = _compareWcsOverBBox(
314 maxDiffSky=maxDiffSky,
315 maxDiffPix=maxDiffPix,
318 doShortCircuit=
False,
321 testCase.fail(
"%s: %s" % (msg, errMsg))
324 @lsst.utils.tests.inTestCase
326 warnings.warn(
"Deprecated. Use assertWcsAlmostEqualOverBBox",
327 DeprecationWarning, 2)
331 @lsst.utils.tests.inTestCase
333 """Generate a representative sample of Endpoints. 338 List of endpoints with enough diversity to exercise Endpoint-related 339 code. Each invocation of this method shall return independent objects. 341 return [GenericEndpoint(n)
for n
in range(1, 6)] + \
342 [Point2Endpoint(), SpherePointEndpoint()]
345 @lsst.utils.tests.inTestCase
347 warnings.warn(
"Deprecated. Use assertAnglesAlmostEqual",
348 DeprecationWarning, 2)
352 @lsst.utils.tests.inTestCase
354 warnings.warn(
"Deprecated. Use assertPairsAlmostEqual", DeprecationWarning, 2)
358 @lsst.utils.tests.inTestCase
360 warnings.warn(
"Deprecated. Use assertBoxesAlmostEqual", DeprecationWarning, 2)
def assertSpherePointsAlmostEqual(testCase, sp0, sp1, maxSep=0.001 *arcseconds, msg="")
Assert that two SpherePoints are almost equal.
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")
Assert that two Cartesian points are almost equal.
def assertWcsAlmostEqualOverBBox(testCase, wcs0, wcs1, bbox, maxDiffSky=0.01 *arcseconds, maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ")
Assert that two WCS are almost equal over a grid of pixel positions.
Point< double, 2 > Point2D
def wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01 *arcseconds, maxDiffPix=0.01, nx=5, ny=5)
Return True if two WCS are almost equal over a grid of pixel positions, else False.
def assertPairsNearlyEqual(args, kwargs)
def assertPairListsAlmostEqual(testCase, list0, list1, maxDiff=1e-7, msg=None)
Assert that two lists of Cartesian points are almost equal.
def assertBoxesAlmostEqual(testCase, box0, box1, maxDiff=1e-7, msg="Boxes differ")
Assert that two boxes (Box2D or Box2I) are almost equal.
def assertAnglesAlmostEqual(testCase, ang0, ang1, maxDiff=0.001 *arcseconds, ignoreWrap=True, msg="Angles differ")
Assert that two angles are almost equal, ignoring wrap differences by default.
def assertSpherePointListsAlmostEqual(testCase, splist0, splist1, maxSep=0.001 *arcseconds, msg=None)
Assert that two lists of SpherePoints are almost equal.