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 .endpoint
import GenericEndpoint, Point2Endpoint, SpherePointEndpoint
38 def _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01*lsst.geom.arcseconds,
39 maxDiffPix=0.01, nx=5, ny=5, doShortCircuit=True):
40 """Compare two :py:class:`WCS <lsst.afw.geom.SkyWcs>` over a rectangular grid of pixel positions 44 wcs0 : `lsst.afw.geom.SkyWcs` 46 wcs1 : `lsst.afw.geom.SkyWcs` 48 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 49 boundaries of pixel grid over which to compare the WCSs 50 maxDiffSky : `lsst.geom.Angle` 51 maximum separation between sky positions computed using Wcs.pixelToSky 53 maximum separation between pixel positions computed using Wcs.skyToPixel 55 number of points in x for the grid of pixel positions 57 number of points in y for the grid of pixel positions 58 doShortCircuit : `bool` 59 if True then stop at the first error, else test all values in the grid 60 and return information about the worst violations found 65 an empty string if the WCS are sufficiently close; else return a string describing 66 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 67 and sky coordinates (if pixel to sky error was excessive). If doShortCircuit is true 68 then the reported error is likely to be much less than the maximum error across the 73 "nx = %s and ny = %s must both be positive" % (nx, ny))
74 if maxDiffSky < 0*lsst.geom.arcseconds:
75 raise RuntimeError(
"maxDiffSky = %s must not be negative" % (maxDiffSky,))
77 raise RuntimeError(
"maxDiffPix = %s must not be negative" % (maxDiffPix,))
80 xList = np.linspace(bboxd.getMinX(), bboxd.getMaxX(), nx)
81 yList = np.linspace(bboxd.getMinY(), bboxd.getMaxY(), ny)
84 measDiffSky = (maxDiffSky,
"?")
85 measDiffPix = (maxDiffPix,
"?")
86 for x, y
in itertools.product(xList, yList):
88 sky0 = wcs0.pixelToSky(fromPixPos)
89 sky1 = wcs1.pixelToSky(fromPixPos)
90 diffSky = sky0.separation(sky1)
91 if diffSky > measDiffSky[0]:
92 measDiffSky = (diffSky, fromPixPos)
96 toPixPos0 = wcs0.skyToPixel(sky0)
97 toPixPos1 = wcs1.skyToPixel(sky0)
98 diffPix = math.hypot(*(toPixPos0 - toPixPos1))
99 if diffPix > measDiffPix[0]:
100 measDiffPix = (diffPix, sky0)
105 if measDiffSky[0] > maxDiffSky:
106 msgList.append(
"%s arcsec max measured sky error > %s arcsec max allowed sky error at pix pos=%s" %
107 (measDiffSky[0].asArcseconds(), maxDiffSky.asArcseconds(), measDiffSky[1]))
108 if measDiffPix[0] > maxDiffPix:
109 msgList.append(
"%s max measured pix error > %s max allowed pix error at sky pos=%s" %
110 (measDiffPix[0], maxDiffPix, measDiffPix[1]))
112 return "; ".join(msgList)
116 maxDiffPix=0.01, nx=5, ny=5):
117 """Test if two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions. 121 wcs0 : `lsst.afw.geom.SkyWcs` 123 wcs1 : `lsst.afw.geom.SkyWcs` 125 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 126 boundaries of pixel grid over which to compare the WCSs 127 maxDiffSky : `lsst.geom.Angle` 128 maximum separation between sky positions computed using Wcs.pixelToSky 130 maximum separation between pixel positions computed using Wcs.skyToPixel 132 number of points in x for the grid of pixel positions 134 number of points in y for the grid of pixel positions 139 `True` if two WCS are almost equal over a grid of pixel positions, else `False` 141 return not bool(_compareWcsOverBBox(
145 maxDiffSky=maxDiffSky,
146 maxDiffPix=maxDiffPix,
153 @lsst.utils.tests.inTestCase
155 maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ"):
156 """Assert that two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions 158 Compare pixelToSky and skyToPixel for two WCS over a rectangular grid of pixel positions. 159 If the WCS are too divergent at any point, call testCase.fail; the message describes 160 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 161 and sky coordinates (if pixel to sky error was excessive) across the entire pixel grid. 165 testCase : `unittest.TestCase` 166 test case the test is part of; an object supporting one method: fail(self, msgStr) 167 wcs0 : `lsst.afw.geom.SkyWcs` 169 wcs1 : `lsst.afw.geom.SkyWcs` 171 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 172 boundaries of pixel grid over which to compare the WCSs 173 maxDiffSky : `lsst.geom.Angle` 174 maximum separation between sky positions computed using Wcs.pixelToSky 176 maximum separation between pixel positions computed using Wcs.skyToPixel 178 number of points in x for the grid of pixel positions 180 number of points in y for the grid of pixel positions 182 exception message prefix; details of the error are appended after ": " 184 errMsg = _compareWcsOverBBox(
188 maxDiffSky=maxDiffSky,
189 maxDiffPix=maxDiffPix,
192 doShortCircuit=
False,
195 testCase.fail(
"%s: %s" % (msg, errMsg))
198 @lsst.utils.tests.inTestCase
200 """Generate a representative sample of ``Endpoints``. 204 testCase : `unittest.TestCase` 205 test case the test is part of; an object supporting one method: fail(self, msgStr) 210 List of endpoints with enough diversity to exercise ``Endpoint``-related 211 code. Each invocation of this method shall return independent objects. 213 return [GenericEndpoint(n)
for n
in range(1, 6)] + \
214 [Point2Endpoint(), SpherePointEndpoint()]
def makeEndpoints(testCase)
A floating-point coordinate rectangle geometry.
def assertWcsAlmostEqualOverBBox(testCase, wcs0, wcs1, bbox, maxDiffSky=0.01 *lsst.geom.arcseconds, maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ")
def wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.01 *lsst.geom.arcseconds, maxDiffPix=0.01, nx=5, ny=5)