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 72 raise RuntimeError(f
"nx = {nx} and ny = {ny} must both be positive")
73 if maxDiffSky < 0*lsst.geom.arcseconds:
74 raise RuntimeError(f
"maxDiffSky = {maxDiffSky} must not be negative")
76 raise RuntimeError(f
"maxDiffPix = {maxDiffPix} must not be negative")
79 xList = np.linspace(bboxd.getMinX(), bboxd.getMaxX(), nx)
80 yList = np.linspace(bboxd.getMinY(), bboxd.getMaxY(), ny)
83 measDiffSky = (maxDiffSky,
"?")
84 measDiffPix = (maxDiffPix,
"?")
85 for x, y
in itertools.product(xList, yList):
87 sky0 = wcs0.pixelToSky(fromPixPos)
88 sky1 = wcs1.pixelToSky(fromPixPos)
89 diffSky = sky0.separation(sky1)
90 if diffSky > measDiffSky[0]:
91 measDiffSky = (diffSky, fromPixPos)
95 toPixPos0 = wcs0.skyToPixel(sky0)
96 toPixPos1 = wcs1.skyToPixel(sky0)
97 diffPix = math.hypot(*(toPixPos0 - toPixPos1))
98 if diffPix > measDiffPix[0]:
99 measDiffPix = (diffPix, sky0)
104 if measDiffSky[0] > maxDiffSky:
105 msgList.append(f
"{measDiffSky[0].asArcseconds()} arcsec max measured sky error " 106 f
"> {maxDiffSky.asArcseconds()} arcsec max allowed sky error " 107 f
"at pix pos=measDiffSky[1]")
108 if measDiffPix[0] > maxDiffPix:
109 msgList.append(f
"{measDiffPix[0]} max measured pix error " 110 f
"> {maxDiffPix} max allowed pix error " 111 f
"at sky pos={measDiffPix[1]}")
113 return "; ".join(msgList)
117 maxDiffPix=0.01, nx=5, ny=5):
118 """Test if two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions. 122 wcs0 : `lsst.afw.geom.SkyWcs` 124 wcs1 : `lsst.afw.geom.SkyWcs` 126 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 127 boundaries of pixel grid over which to compare the WCSs 128 maxDiffSky : `lsst.geom.Angle` 129 maximum separation between sky positions computed using Wcs.pixelToSky 131 maximum separation between pixel positions computed using Wcs.skyToPixel 133 number of points in x for the grid of pixel positions 135 number of points in y for the grid of pixel positions 140 `True` if two WCS are almost equal over a grid of pixel positions, else `False` 142 return not bool(_compareWcsOverBBox(
146 maxDiffSky=maxDiffSky,
147 maxDiffPix=maxDiffPix,
154 @lsst.utils.tests.inTestCase
156 maxDiffPix=0.01, nx=5, ny=5, msg="WCSs differ"):
157 """Assert that two :py:class:`WCS <lsst.afw.geom.SkyWcs>` are almost equal over a grid of pixel positions 159 Compare pixelToSky and skyToPixel for two WCS over a rectangular grid of pixel positions. 160 If the WCS are too divergent at any point, call testCase.fail; the message describes 161 the largest error measured in pixel coordinates (if sky to pixel error was excessive) 162 and sky coordinates (if pixel to sky error was excessive) across the entire pixel grid. 166 testCase : `unittest.TestCase` 167 test case the test is part of; an object supporting one method: fail(self, msgStr) 168 wcs0 : `lsst.afw.geom.SkyWcs` 170 wcs1 : `lsst.afw.geom.SkyWcs` 172 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 173 boundaries of pixel grid over which to compare the WCSs 174 maxDiffSky : `lsst.geom.Angle` 175 maximum separation between sky positions computed using Wcs.pixelToSky 177 maximum separation between pixel positions computed using Wcs.skyToPixel 179 number of points in x for the grid of pixel positions 181 number of points in y for the grid of pixel positions 183 exception message prefix; details of the error are appended after ": " 185 errMsg = _compareWcsOverBBox(
189 maxDiffSky=maxDiffSky,
190 maxDiffPix=maxDiffPix,
193 doShortCircuit=
False,
196 testCase.fail(f
"{msg}: {errMsg}")
199 @lsst.utils.tests.inTestCase
201 """Generate a representative sample of ``Endpoints``. 205 testCase : `unittest.TestCase` 206 test case the test is part of; an object supporting one method: fail(self, msgStr) 211 List of endpoints with enough diversity to exercise ``Endpoint``-related 212 code. Each invocation of this method shall return independent objects. 214 return [GenericEndpoint(n)
for n
in range(1, 6)] + \
215 [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)