Coverage for tests/test_footprint.py: 15%

161 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2023-02-05 17:50 -0800

1# 

2# Copyright 2008-2017 AURA/LSST. 

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 <https://www.lsstcorp.org/LegalNotices/>. 

20# 

21 

22import os 

23import unittest 

24 

25import lsst.utils.tests 

26import lsst.geom 

27import lsst.afw.geom as afwGeom 

28import lsst.afw.detection as afwDet 

29import lsst.afw.table as afwTable 

30 

31 

32class FootprintTestCase(unittest.TestCase): 

33 def setUp(self): 

34 self.spanRad = 4 

35 self.regionRad = 10 

36 self.spans = afwGeom.SpanSet.fromShape(self.spanRad, afwGeom.Stencil.BOX) 

37 minPoint = lsst.geom.Point2I(-self.regionRad, -self.regionRad) 

38 maxPoint = lsst.geom.Point2I(self.regionRad, self.regionRad) 

39 self.region = lsst.geom.Box2I(minPoint, maxPoint) 

40 self.schema = afwDet.PeakTable.makeMinimalSchema() 

41 # Run the the constructors test to ensure the Footprints are setUp 

42 self.testConstructors() 

43 

44 def tearDown(self): 

45 del self.spans 

46 del self.region 

47 del self.schema 

48 del self.footprint 

49 del self.footprintWithRegion 

50 del self.footprintWithSchema 

51 del self.footprintWithSchemaRegion 

52 del self.emptyFootprint 

53 

54 def testConstructors(self): 

55 ''' 

56 Test that each of the constructors constructs a valid Footprint, 

57 if any of these fails, an exception will be raised and the test 

58 will fail. 

59 ''' 

60 self.footprint = afwDet.Footprint(self.spans) 

61 self.footprintWithRegion = afwDet.Footprint(self.spans, self.region) 

62 self.footprintWithSchema = afwDet.Footprint(self.spans, self.schema) 

63 self.footprintWithSchemaRegion = afwDet.Footprint(self.spans, 

64 self.schema, 

65 self.region) 

66 self.emptyFootprint = afwDet.Footprint() 

67 self.assertEqual(len(self.emptyFootprint.spans), 0) 

68 self.assertEqual(len(self.emptyFootprint.peaks), 0) 

69 

70 def testIsHeavy(self): 

71 self.assertFalse(self.footprint.isHeavy()) 

72 

73 def testGetSetSpans(self): 

74 ''' 

75 Test getting and setting the SpanSet member of the Footprint with both 

76 the getters and setters and the python property accessor 

77 ''' 

78 self.assertEqual(self.footprint.getSpans(), self.spans) 

79 self.assertEqual(self.footprint.spans, self.spans) 

80 tempSpanSet = afwGeom.SpanSet.fromShape(2, afwGeom.Stencil.BOX) 

81 self.footprint.setSpans(tempSpanSet) 

82 self.assertEqual(self.footprint.spans, tempSpanSet) 

83 # reset back to original with property 

84 self.footprint.spans = self.spans 

85 self.assertEqual(self.footprint.spans, self.spans) 

86 

87 def testPeakFunctionality(self): 

88 newSchema = afwDet.PeakTable.makeMinimalSchema() 

89 newField = afwTable.FieldI("extra", "doc", "na") 

90 newSchema.addField(newField) 

91 self.footprint.setPeakSchema(newSchema) 

92 names = self.footprint.getPeaks().getSchema().getNames() 

93 self.assertIn("extra", names) 

94 # reset the schema back 

95 self.footprint.setPeakSchema(self.schema) 

96 peakData = [[2, 2, 10], [0, 3, 21], [1, 9, 17]] 

97 for peak in peakData: 

98 self.footprint.addPeak(*peak) 

99 # Sort the peaks by value (use the property peaks to test that method 

100 # of access) 

101 sortKey = self.footprint.peaks.getSchema()['peakValue'].asKey() 

102 self.footprint.sortPeaks(sortKey) 

103 for i, peak in enumerate(self.footprint.peaks): 

104 self.assertEqual(peak['i_x'], i) 

105 

106 # Test that peaks outside the Footprint are removed 

107 self.footprint.removeOrphanPeaks() 

108 self.assertEqual(len(self.footprint.peaks), 2) 

109 for peak in self.footprint.peaks: 

110 self.assertNotEqual(peak['i_x'], 1) 

111 

112 def testGeometry(self): 

113 # Move the base footprint by 2 in x and 2 in y 

114 offsetX = 2 

115 offsetY = -3 

116 self.footprint.shift(offsetX, offsetY) 

117 # verify that this shifts the center from 0,0 as the default 

118 # constructed footprint has 

119 center = self.footprint.getCentroid() 

120 self.assertEqual(center.getX(), offsetX) 

121 self.assertEqual(center.getY(), offsetY) 

122 

123 shape = 6.66666 

124 covShape = 0 

125 places = 4 

126 self.assertAlmostEqual(self.footprint.getShape().getIxx(), 

127 shape, places) 

128 self.assertAlmostEqual(self.footprint.getShape().getIyy(), 

129 shape, places) 

130 self.assertEqual(self.footprint.getShape().getIxy(), covShape) 

131 

132 # Shift the footprint back 

133 self.footprint.shift(lsst.geom.ExtentI(-offsetX, -offsetY)) 

134 

135 bBox = self.footprint.getBBox() 

136 self.assertEqual(bBox.getMinX(), -self.spanRad) 

137 self.assertEqual(bBox.getMinY(), -self.spanRad) 

138 self.assertEqual(bBox.getMaxX(), self.spanRad) 

139 self.assertEqual(bBox.getMaxY(), self.spanRad) 

140 

141 # Test the point membership in a Footprint 

142 memberPoint = lsst.geom.Point2I(1, 1) 

143 self.assertTrue(self.footprint.contains(memberPoint)) 

144 self.assertIn(memberPoint, self.footprint) 

145 

146 nonMemberPoint = lsst.geom.Point2I(100, 100) 

147 self.assertFalse(self.footprint.contains(nonMemberPoint)) 

148 self.assertNotIn(nonMemberPoint, self.footprint) 

149 

150 def testRegion(self): 

151 self.assertEqual(self.footprintWithRegion.getRegion(), self.region) 

152 largeRad = 20 

153 testRegion = lsst.geom.Box2I(lsst.geom.Point2I(-largeRad, -largeRad), 

154 lsst.geom.Point2I(largeRad, largeRad)) 

155 self.footprintWithRegion.setRegion(testRegion) 

156 self.assertEqual(testRegion, self.footprintWithRegion.getRegion()) 

157 

158 def testMutationFunctionality(self): 

159 clipRad = 2 

160 clipBox = lsst.geom.Box2I(lsst.geom.Point2I(-clipRad, -clipRad), 

161 lsst.geom.Point2I(clipRad, clipRad)) 

162 self.footprint.clipTo(clipBox) 

163 # Fetch the bounding box using the property notation 

164 bBox = self.footprint.getBBox() 

165 # Check the bounding box is now at the bounds which were clipped to 

166 self.assertEqual(bBox.getMinX(), -clipRad) 

167 self.assertEqual(bBox.getMinY(), -clipRad) 

168 self.assertEqual(bBox.getMaxX(), clipRad) 

169 self.assertEqual(bBox.getMaxY(), clipRad) 

170 

171 # Set the footprint back to what it was 

172 self.footprint = afwDet.Footprint(self.spans) 

173 

174 # Test erode 

175 kernelRad = 1 

176 kernel = afwGeom.SpanSet.fromShape(kernelRad, afwGeom.Stencil.BOX) 

177 self.footprint.erode(kernel) 

178 

179 # Verify the eroded dimensions 

180 bBox = self.footprint.getBBox() 

181 self.assertEqual(bBox.getMinX(), -3) 

182 self.assertEqual(bBox.getMinY(), -3) 

183 self.assertEqual(bBox.getMaxX(), 3) 

184 self.assertEqual(bBox.getMaxY(), 3) 

185 

186 # Dilate the footprint back to the origional 

187 self.footprint.dilate(kernel) 

188 self.assertEqual(self.footprint.spans, self.spans) 

189 

190 # erode using the alternate call syntax 

191 self.footprint.erode(1, afwGeom.Stencil.BOX) 

192 

193 # verify the eroded dimensions 

194 bBox = self.footprint.getBBox() 

195 self.assertEqual(bBox.getMinX(), -3) 

196 self.assertEqual(bBox.getMinY(), -3) 

197 self.assertEqual(bBox.getMaxX(), 3) 

198 self.assertEqual(bBox.getMaxY(), 3) 

199 

200 # Dilate the footprint back to the origional using alternate signature 

201 self.footprint.dilate(1, afwGeom.Stencil.BOX) 

202 self.assertEqual(self.footprint.spans, self.spans) 

203 

204 def testSplit(self): 

205 spanList = [afwGeom.Span(0, 2, 4), 

206 afwGeom.Span(1, 2, 4), 

207 afwGeom.Span(2, 2, 4), 

208 afwGeom.Span(10, 4, 7), 

209 afwGeom.Span(11, 4, 7), 

210 afwGeom.Span(12, 4, 7)] 

211 

212 spans = afwGeom.SpanSet(spanList) 

213 region = lsst.geom.Box2I(lsst.geom.PointI(-6, -6), lsst.geom.PointI(20, 20)) 

214 multiFoot = afwDet.Footprint(spans, region) 

215 

216 records = [multiFoot.addPeak(3, 1, 100), 

217 multiFoot.addPeak(5, 11, 100)] 

218 

219 # Verify that the footprint is multi-component 

220 self.assertFalse(multiFoot.isContiguous()) 

221 

222 footprintList = multiFoot.split() 

223 

224 self.assertEqual(len(footprintList), 2) 

225 for i, fp in enumerate(footprintList): 

226 # check that the correct Spans are populated for each 

227 tempSpan = afwGeom.SpanSet(spanList[i*3:i*3+3]) 

228 self.assertEqual(fp.spans, tempSpan) 

229 

230 # check that the peaks are split properly 

231 self.assertEqual(len(fp.peaks), 1) 

232 self.assertEqual(fp.peaks[0], records[i]) 

233 

234 def testPersistence(self): 

235 # populate the peaks for the peak tests 

236 self.testPeakFunctionality() 

237 

238 with lsst.utils.tests.getTempFilePath(".fits") as filepath: 

239 # Persist the Footprint to file and read it back 

240 self.footprint.writeFits(filepath) 

241 footprintFromFile = afwDet.Footprint.readFits(filepath) 

242 

243 # Check that the Footprint before and after saving are the same 

244 self.assertEqual(self.footprint, footprintFromFile) 

245 

246 # Clean up after ourselves 

247 del footprintFromFile 

248 

249 def testLegacyFootprints(self): 

250 testPath = os.path.abspath(os.path.dirname(__file__)) 

251 fileName = os.path.join(testPath, 'data', 'preSpanSetsFootprint.fits') 

252 legacyFootprint = afwDet.Footprint.readFits(fileName) 

253 

254 # Calculate some quantifying numbers from the legacy Footprint to ensure 

255 # it loaded properly 

256 self.assertEqual(len(legacyFootprint.spans), 303) 

257 self.assertEqual(len(legacyFootprint.peaks), 48) 

258 self.assertEqual(legacyFootprint.spans.getBBox(), 

259 lsst.geom.Box2I(lsst.geom.Point2I(32676, 27387), 

260 lsst.geom.Extent2I(175, 153))) 

261 legacyCenter = legacyFootprint.spans.computeCentroid() 

262 self.assertAlmostEqual(legacyCenter.getY(), 27456.70733, 5) 

263 self.assertAlmostEqual(legacyCenter.getX(), 32775.47611, 5) 

264 

265 del legacyFootprint 

266 

267 

268class TestMemory(lsst.utils.tests.MemoryTestCase): 

269 pass 

270 

271 

272def setup_module(module): 

273 lsst.utils.tests.init() 

274 

275 

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

277 lsst.utils.tests.init() 

278 unittest.main()