Coverage for tests/test_setMatchDistance.py: 33%

85 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-14 03:12 -0700

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. 

32 

33import unittest 

34 

35import numpy as np 

36 

37import lsst.utils.tests 

38import lsst.geom 

39import lsst.afw.geom as afwGeom 

40import lsst.afw.table as afwTable 

41from lsst.meas.algorithms import LoadReferenceObjectsTask 

42from lsst.meas.base import SingleFrameMeasurementTask 

43from lsst.meas.astrom import setMatchDistance 

44 

45 

46class BaseTestCase(unittest.TestCase): 

47 

48 """A test case for setMatchDistance 

49 

50 Use involves setting one class attribute: 

51 * MatchClass: match class, e.g. ReferenceMatch or SourceMatch 

52 

53 This test is a bit messy because it exercises two templates of MatchClass 

54 

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 

62 

63 def setUp(self): 

64 crval = lsst.geom.SpherePoint(44, 45, lsst.geom.degrees) 

65 crpix = lsst.geom.PointD(0, 0) 

66 

67 scale = 1 * lsst.geom.arcseconds 

68 self.tanWcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, 

69 cdMatrix=afwGeom.makeCdMatrix(scale=scale)) 

70 

71 S = 300 

72 N = 5 

73 

74 if self.MatchClass == afwTable.ReferenceMatch: 

75 refSchema = LoadReferenceObjectsTask.makeMinimalSchema( 

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 = [] 

91 

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() 

96 

97 src.set(self.srcCentroidKey, lsst.geom.Point2D(i, j)) 

98 

99 c = self.tanWcs.pixelToSky(lsst.geom.Point2D(i, j)) 

100 refObj.setCoord(c) 

101 

102 self.matches.append(self.MatchClass(refObj, src, 0.0)) 

103 

104 def tearDown(self): 

105 del self.refCat 

106 del self.origSourceCat 

107 del self.sourceCat 

108 del self.matches 

109 del self.tanWcs 

110 

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)) 

120 

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) 

129 

130 self.assertLess(maxDistErr.asArcseconds(), 1e-7) 

131 

132 

133class SideLoadTestCases: 

134 

135 """Base class implementations of testing methods. 

136 

137 Explicitly does not inherit from unittest.TestCase""" 

138 

139 def testTrivial(self): 

140 """Add no distortion""" 

141 self.doTest("testTrivial", lambda x, y: (x, y)) 

142 

143 def testQuadraticX(self): 

144 """Add quadratic distortion in x""" 

145 self.doTest("testQuadraticX", lambda x, y: (x + 1e-4*x**2, y)) 

146 

147 def testRadial(self): 

148 """Add radial distortion""" 

149 radialTransform = afwGeom.makeRadialTransform([0, 1.02, 1e-6]) 

150 

151 def radialDistortion(x, y): 

152 x, y = radialTransform.applyForward(lsst.geom.Point2D(x, y)) 

153 return (x, y) 

154 self.doTest("testRadial", radialDistortion) 

155 

156# The test classes inherit from two base classes and differ in the match 

157# class being used. 

158 

159 

160class SetMatchDistanceTestCaseReferenceMatch(BaseTestCase, SideLoadTestCases): 

161 MatchClass = afwTable.ReferenceMatch 

162 

163 

164class SetMatchDistanceTestCaseSourceMatch(BaseTestCase, SideLoadTestCases): 

165 MatchClass = afwTable.SourceMatch 

166 

167 

168class MemoryTester(lsst.utils.tests.MemoryTestCase): 

169 pass 

170 

171 

172def setup_module(module): 

173 lsst.utils.tests.init() 

174 

175 

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()