Coverage for tests/test_setMatchDistance.py: 26%
85 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-06-07 12:21 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-06-07 12:21 +0000
1# LSST Data Management System
2# Copyright 2008, 2009, 2010 LSST Corporation.
3#
4# This product includes software developed by the
5# LSST Project (http://www.lsst.org/).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the LSST License Statement and
18# the GNU General Public License along with this program. If not,
19# see <http://www.lsstcorp.org/LegalNotices/>.
20#
21#
22# The classes in this test are a little non-standard to reduce code
23# duplication and support automated unittest discovery.
24# A base class includes all the code that implements the testing and
25# itself inherits from unittest.TestCase. unittest automated discovery
26# will scan all classes that inherit from unittest.TestCase and invoke
27# any test methods found. To prevent this base class from being executed
28# the test methods are placed in a different class that does not inherit
29# from unittest.TestCase. The actual test classes then inherit from
30# both the testing class and the implementation class allowing test
31# discovery to only run tests found in the subclasses.
33import unittest
35import numpy as np
37import lsst.utils.tests
38import lsst.geom
39import lsst.afw.geom as afwGeom
40import lsst.afw.table as afwTable
41from lsst.meas.algorithms import convertReferenceCatalog
42from lsst.meas.base import SingleFrameMeasurementTask
43from lsst.meas.astrom import setMatchDistance
46class BaseTestCase(unittest.TestCase):
48 """A test case for setMatchDistance
50 Use involves setting one class attribute:
51 * MatchClass: match class, e.g. ReferenceMatch or SourceMatch
53 This test is a bit messy because it exercises two templates of MatchClass
55 The test creates source and reference object catalogs that intentionally have
56 some separation in on-sky coordinates. The reference catalog is set using
57 a uniform grid of pixel positions and a simple WCS to compute on-sky coordinates.
58 The source catalog is created by using a distorted version of the same grid
59 of pixel positions, which is converted to on-sky coordinates using the same WCS.
60 """
61 MatchClass = None
63 def setUp(self):
64 crval = lsst.geom.SpherePoint(44, 45, lsst.geom.degrees)
65 crpix = lsst.geom.PointD(0, 0)
67 scale = 1 * lsst.geom.arcseconds
68 self.tanWcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval,
69 cdMatrix=afwGeom.makeCdMatrix(scale=scale))
71 S = 300
72 N = 5
74 if self.MatchClass == afwTable.ReferenceMatch:
75 refSchema = convertReferenceCatalog._makeSchema(
76 filterNameList=["r"], addIsPhotometric=True)
77 self.refCat = afwTable.SimpleCatalog(refSchema)
78 elif self.MatchClass == afwTable.SourceMatch:
79 refSchema = afwTable.SourceTable.makeMinimalSchema()
80 self.refCat = afwTable.SourceCatalog(refSchema)
81 else:
82 raise RuntimeError("Unsupported MatchClass=%r" % (self.MatchClass,))
83 srcSchema = afwTable.SourceTable.makeMinimalSchema()
84 SingleFrameMeasurementTask(schema=srcSchema)
85 self.refCoordKey = afwTable.CoordKey(refSchema["coord"])
86 self.srcCoordKey = afwTable.CoordKey(srcSchema["coord"])
87 self.srcCentroidKey = afwTable.Point2DKey(srcSchema["slot_Centroid"])
88 self.sourceCat = afwTable.SourceCatalog(srcSchema)
89 self.origSourceCat = afwTable.SourceCatalog(srcSchema) # undistorted copy
90 self.matches = []
92 for i in np.linspace(0., S, N):
93 for j in np.linspace(0., S, N):
94 src = self.sourceCat.addNew()
95 refObj = self.refCat.addNew()
97 src.set(self.srcCentroidKey, lsst.geom.Point2D(i, j))
99 c = self.tanWcs.pixelToSky(lsst.geom.Point2D(i, j))
100 refObj.setCoord(c)
102 self.matches.append(self.MatchClass(refObj, src, 0.0))
104 def tearDown(self):
105 del self.refCat
106 del self.origSourceCat
107 del self.sourceCat
108 del self.matches
109 del self.tanWcs
111 def doTest(self, name, func):
112 """Apply func(x, y) to each source in self.sourceCat, then set coord, compute and check dist
113 """
114 for refObj, src, d in self.matches:
115 origPos = src.get(self.srcCentroidKey)
116 x, y = func(*origPos)
117 distortedPos = lsst.geom.Point2D(*func(*origPos))
118 src.set(self.srcCentroidKey, distortedPos)
119 src.set(self.srcCoordKey, self.tanWcs.pixelToSky(distortedPos))
121 setMatchDistance(self.matches)
122 maxDistErr = 0*lsst.geom.radians
123 for refObj, source, distRad in self.matches:
124 sourceCoord = source.get(self.srcCoordKey)
125 refCoord = refObj.get(self.refCoordKey)
126 predDist = sourceCoord.separation(refCoord)
127 distErr = abs(predDist - distRad*lsst.geom.radians)
128 maxDistErr = max(distErr, maxDistErr)
130 self.assertLess(maxDistErr.asArcseconds(), 1e-7)
133class SideLoadTestCases:
135 """Base class implementations of testing methods.
137 Explicitly does not inherit from unittest.TestCase"""
139 def testTrivial(self):
140 """Add no distortion"""
141 self.doTest("testTrivial", lambda x, y: (x, y))
143 def testQuadraticX(self):
144 """Add quadratic distortion in x"""
145 self.doTest("testQuadraticX", lambda x, y: (x + 1e-4*x**2, y))
147 def testRadial(self):
148 """Add radial distortion"""
149 radialTransform = afwGeom.makeRadialTransform([0, 1.02, 1e-6])
151 def radialDistortion(x, y):
152 x, y = radialTransform.applyForward(lsst.geom.Point2D(x, y))
153 return (x, y)
154 self.doTest("testRadial", radialDistortion)
156# The test classes inherit from two base classes and differ in the match
157# class being used.
160class SetMatchDistanceTestCaseReferenceMatch(BaseTestCase, SideLoadTestCases):
161 MatchClass = afwTable.ReferenceMatch
164class SetMatchDistanceTestCaseSourceMatch(BaseTestCase, SideLoadTestCases):
165 MatchClass = afwTable.SourceMatch
168class MemoryTester(lsst.utils.tests.MemoryTestCase):
169 pass
172def setup_module(module):
173 lsst.utils.tests.init()
176if __name__ == "__main__": 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true
177 lsst.utils.tests.init()
178 unittest.main()