Coverage for tests/test_tableUtils.py: 21%

98 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-30 02:30 -0700

1# LSST Data Management System 

2# Copyright 2016 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# The classes in this test are a little non-standard to reduce code 

22# duplication and support automated unittest discovery. 

23# A base class includes all the code that implements the testing and 

24# itself inherits from unittest.TestCase. unittest automated discovery 

25# will scan all classes that inherit from unittest.TestCase and invoke 

26# any test methods found. To prevent this base class from being executed 

27# the test methods are placed in a different class that does not inherit 

28# from unittest.TestCase. The actual test classes then inherit from 

29# both the testing class and the implementation class allowing test 

30# discovery to only run tests found in the subclasses. 

31 

32import math 

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 

41 

42 

43class UpdateTestCase(lsst.utils.tests.TestCase): 

44 """A test case for the lsst.afw.table.updateRefCentroids and updateSourceCoords 

45 """ 

46 

47 def setUp(self): 

48 self.crval = lsst.geom.SpherePoint(44.0, 45.0, lsst.geom.degrees) 

49 self.crpix = lsst.geom.Point2D(15000, 4000) 

50 

51 arcsecPerPixel = 1/3600.0 

52 cdMatrix = afwGeom.makeCdMatrix(arcsecPerPixel * lsst.geom.arcseconds) 

53 self.wcs = afwGeom.makeSkyWcs(crval=self.crval, crpix=self.crpix, cdMatrix=cdMatrix) 

54 

55 refSchema = afwTable.SimpleTable.makeMinimalSchema() 

56 self.refCentroidKey = afwTable.Point2DKey.addFields( 

57 refSchema, "centroid", "centroid", "pixels") 

58 self.refCoordKey = afwTable.CoordKey(refSchema["coord"]) 

59 self.refHasCentroidKey = refSchema.addField("hasCentroid", type="Flag") 

60 self.refCat = afwTable.SimpleCatalog(refSchema) 

61 

62 # an alias is required to make src.getCentroid() work; 

63 # simply defining a field named "slot_Centroid" doesn't suffice 

64 srcSchema = afwTable.SourceTable.makeMinimalSchema() 

65 self.srcCentroidKey = afwTable.Point2DKey.addFields(srcSchema, "base_SdssCentroid", 

66 "centroid", "pixels") 

67 srcAliases = srcSchema.getAliasMap() 

68 srcAliases.set("slot_Centroid", "base_SdssCentroid") 

69 self.srcCoordKey = afwTable.CoordKey(srcSchema["coord"]) 

70 self.sourceCat = afwTable.SourceCatalog(srcSchema) 

71 

72 def tearDown(self): 

73 del self.wcs 

74 del self.refCat 

75 del self.sourceCat 

76 

77 def testNull(self): 

78 """Check that an empty list causes no problems for either function""" 

79 afwTable.updateRefCentroids(self.wcs, []) 

80 afwTable.updateSourceCoords(self.wcs, []) 

81 

82 def testRefCenter(self): 

83 """Check that a ref obj at the center is handled as expected""" 

84 refObj = self.refCat.addNew() 

85 refObj.set(self.refCoordKey, self.crval) 

86 

87 # initial centroid should be nan and hasCentroid False 

88 nanRefCentroid = self.refCat[0].get(self.refCentroidKey) 

89 for val in nanRefCentroid: 

90 self.assertTrue(math.isnan(val)) 

91 self.assertFalse(self.refCat[0].get(self.refHasCentroidKey)) 

92 

93 # computed centroid should be crpix and hasCentroid True 

94 afwTable.updateRefCentroids(self.wcs, self.refCat) 

95 refCentroid = self.refCat[0].get(self.refCentroidKey) 

96 self.assertPairsAlmostEqual(refCentroid, self.crpix) 

97 self.assertTrue(self.refCat[0].get(self.refHasCentroidKey)) 

98 

99 # coord should not be changed 

100 self.assertEqual(self.refCat[0].get(self.refCoordKey), self.crval) 

101 

102 def testSourceCenter(self): 

103 """Check that a source at the center is handled as expected""" 

104 src = self.sourceCat.addNew() 

105 src.set(self.srcCentroidKey, self.crpix) 

106 

107 # initial coord should be nan; as a sanity-check 

108 nanSourceCoord = self.sourceCat[0].get(self.srcCoordKey) 

109 for val in nanSourceCoord: 

110 self.assertTrue(math.isnan(val)) 

111 

112 # compute coord should be crval 

113 afwTable.updateSourceCoords(self.wcs, self.sourceCat) 

114 srcCoord = self.sourceCat[0].get(self.srcCoordKey) 

115 self.assertPairsAlmostEqual(srcCoord, self.crval) 

116 

117 # centroid should not be changed; also make sure that getCentroid words 

118 self.assertEqual(self.sourceCat[0].getCentroid(), self.crpix) 

119 

120 def testLists(self): 

121 """Check updating lists of reference objects and sources""" 

122 # arbitrary but reasonable values that are intentionally different than 

123 # testCatalogs 

124 maxPix = 1000 

125 numPoints = 10 

126 self.setCatalogs(maxPix=maxPix, numPoints=numPoints) 

127 

128 # update the catalogs as lists 

129 afwTable.updateSourceCoords(self.wcs, [s for s in self.sourceCat]) 

130 afwTable.updateRefCentroids(self.wcs, [r for r in self.refCat]) 

131 

132 self.checkCatalogs() 

133 

134 def testCatalogs(self): 

135 """Check updating catalogs of reference objects and sources""" 

136 # arbitrary but reasonable values that are intentionally different than 

137 # testLists 

138 maxPix = 2000 

139 numPoints = 9 

140 self.setCatalogs(maxPix=maxPix, numPoints=numPoints) 

141 

142 # update the catalogs 

143 afwTable.updateSourceCoords(self.wcs, self.sourceCat) 

144 afwTable.updateRefCentroids(self.wcs, self.refCat) 

145 

146 # check that centroids and coords match 

147 self.checkCatalogs() 

148 

149 def checkCatalogs(self, maxPixDiff=1e-5, maxSkyDiff=0.001*lsst.geom.arcseconds): 

150 """Check that the source and reference object catalogs have equal centroids and coords""" 

151 self.assertEqual(len(self.sourceCat), len(self.refCat)) 

152 

153 for src, refObj in zip(self.sourceCat, self.refCat): 

154 self.assertTrue(refObj.get(self.refHasCentroidKey)) 

155 srcCentroid = src.get(self.srcCentroidKey) 

156 refCentroid = refObj.get(self.refCentroidKey) 

157 self.assertPairsAlmostEqual( 

158 srcCentroid, refCentroid, maxDiff=maxPixDiff) 

159 

160 srcCoord = src.get(self.srcCoordKey) 

161 refCoord = refObj.get(self.refCoordKey) 

162 self.assertSpherePointsAlmostEqual( 

163 srcCoord, refCoord, maxSep=maxSkyDiff) 

164 

165 def setCatalogs(self, maxPix, numPoints): 

166 """Set the source centroids and reference object coords 

167 

168 Set self.sourceCat centroids to a square grid of points 

169 and set self.refCat coords to the corresponding sky positions 

170 

171 The catalogs must be empty to start 

172 

173 @param[in] maxPix maximum pixel position; used for both x and y; 

174 the min is the negative of maxPix 

175 @param[in] numPoints number of points in x or y; total points = numPoints*numPoints 

176 """ 

177 if len(self.sourceCat) != 0: 

178 raise RuntimeError("self.sourceCat must be empty") 

179 if len(self.refCat) != 0: 

180 raise RuntimeError("self.refCat must be empty") 

181 

182 for i in np.linspace(-maxPix, maxPix, numPoints): 

183 for j in np.linspace(-maxPix, maxPix, numPoints): 

184 centroid = lsst.geom.Point2D(i, j) 

185 src = self.sourceCat.addNew() 

186 src.set(self.srcCentroidKey, centroid) 

187 

188 refObj = self.refCat.addNew() 

189 coord = self.wcs.pixelToSky(centroid) 

190 refObj.set(self.refCoordKey, coord) 

191 

192 

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

194 pass 

195 

196 

197def setup_module(module): 

198 lsst.utils.tests.init() 

199 

200 

201if __name__ == "__main__": 201 ↛ 202line 201 didn't jump to line 202, because the condition on line 201 was never true

202 lsst.utils.tests.init() 

203 unittest.main()