Coverage for tests/test_footprint.py: 15%
163 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-11 02:44 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-11 02:44 -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#
22import os
23import unittest
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
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()
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
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)
70 def test_str(self):
71 self.assertEqual(str(self.footprint), "0 peaks, area=81, centroid=(0, 0)")
73 def testIsHeavy(self):
74 self.assertFalse(self.footprint.isHeavy())
76 def testGetSetSpans(self):
77 '''
78 Test getting and setting the SpanSet member of the Footprint with both
79 the getters and setters and the python property accessor
80 '''
81 self.assertEqual(self.footprint.getSpans(), self.spans)
82 self.assertEqual(self.footprint.spans, self.spans)
83 tempSpanSet = afwGeom.SpanSet.fromShape(2, afwGeom.Stencil.BOX)
84 self.footprint.setSpans(tempSpanSet)
85 self.assertEqual(self.footprint.spans, tempSpanSet)
86 # reset back to original with property
87 self.footprint.spans = self.spans
88 self.assertEqual(self.footprint.spans, self.spans)
90 def testPeakFunctionality(self):
91 newSchema = afwDet.PeakTable.makeMinimalSchema()
92 newField = afwTable.FieldI("extra", "doc", "na")
93 newSchema.addField(newField)
94 self.footprint.setPeakSchema(newSchema)
95 names = self.footprint.getPeaks().getSchema().getNames()
96 self.assertIn("extra", names)
97 # reset the schema back
98 self.footprint.setPeakSchema(self.schema)
99 peakData = [[2, 2, 10], [0, 3, 21], [1, 9, 17]]
100 for peak in peakData:
101 self.footprint.addPeak(*peak)
102 # Sort the peaks by value (use the property peaks to test that method
103 # of access)
104 sortKey = self.footprint.peaks.getSchema()['peakValue'].asKey()
105 self.footprint.sortPeaks(sortKey)
106 for i, peak in enumerate(self.footprint.peaks):
107 self.assertEqual(peak['i_x'], i)
109 # Test that peaks outside the Footprint are removed
110 self.footprint.removeOrphanPeaks()
111 self.assertEqual(len(self.footprint.peaks), 2)
112 for peak in self.footprint.peaks:
113 self.assertNotEqual(peak['i_x'], 1)
115 def testGeometry(self):
116 # Move the base footprint by 2 in x and 2 in y
117 offsetX = 2
118 offsetY = -3
119 self.footprint.shift(offsetX, offsetY)
120 # verify that this shifts the center from 0,0 as the default
121 # constructed footprint has
122 center = self.footprint.getCentroid()
123 self.assertEqual(center.getX(), offsetX)
124 self.assertEqual(center.getY(), offsetY)
126 shape = 6.66666
127 covShape = 0
128 places = 4
129 self.assertAlmostEqual(self.footprint.getShape().getIxx(),
130 shape, places)
131 self.assertAlmostEqual(self.footprint.getShape().getIyy(),
132 shape, places)
133 self.assertEqual(self.footprint.getShape().getIxy(), covShape)
135 # Shift the footprint back
136 self.footprint.shift(lsst.geom.ExtentI(-offsetX, -offsetY))
138 bBox = self.footprint.getBBox()
139 self.assertEqual(bBox.getMinX(), -self.spanRad)
140 self.assertEqual(bBox.getMinY(), -self.spanRad)
141 self.assertEqual(bBox.getMaxX(), self.spanRad)
142 self.assertEqual(bBox.getMaxY(), self.spanRad)
144 # Test the point membership in a Footprint
145 memberPoint = lsst.geom.Point2I(1, 1)
146 self.assertTrue(self.footprint.contains(memberPoint))
147 self.assertIn(memberPoint, self.footprint)
149 nonMemberPoint = lsst.geom.Point2I(100, 100)
150 self.assertFalse(self.footprint.contains(nonMemberPoint))
151 self.assertNotIn(nonMemberPoint, self.footprint)
153 def testRegion(self):
154 self.assertEqual(self.footprintWithRegion.getRegion(), self.region)
155 largeRad = 20
156 testRegion = lsst.geom.Box2I(lsst.geom.Point2I(-largeRad, -largeRad),
157 lsst.geom.Point2I(largeRad, largeRad))
158 self.footprintWithRegion.setRegion(testRegion)
159 self.assertEqual(testRegion, self.footprintWithRegion.getRegion())
161 def testMutationFunctionality(self):
162 clipRad = 2
163 clipBox = lsst.geom.Box2I(lsst.geom.Point2I(-clipRad, -clipRad),
164 lsst.geom.Point2I(clipRad, clipRad))
165 self.footprint.clipTo(clipBox)
166 # Fetch the bounding box using the property notation
167 bBox = self.footprint.getBBox()
168 # Check the bounding box is now at the bounds which were clipped to
169 self.assertEqual(bBox.getMinX(), -clipRad)
170 self.assertEqual(bBox.getMinY(), -clipRad)
171 self.assertEqual(bBox.getMaxX(), clipRad)
172 self.assertEqual(bBox.getMaxY(), clipRad)
174 # Set the footprint back to what it was
175 self.footprint = afwDet.Footprint(self.spans)
177 # Test erode
178 kernelRad = 1
179 kernel = afwGeom.SpanSet.fromShape(kernelRad, afwGeom.Stencil.BOX)
180 self.footprint.erode(kernel)
182 # Verify the eroded dimensions
183 bBox = self.footprint.getBBox()
184 self.assertEqual(bBox.getMinX(), -3)
185 self.assertEqual(bBox.getMinY(), -3)
186 self.assertEqual(bBox.getMaxX(), 3)
187 self.assertEqual(bBox.getMaxY(), 3)
189 # Dilate the footprint back to the origional
190 self.footprint.dilate(kernel)
191 self.assertEqual(self.footprint.spans, self.spans)
193 # erode using the alternate call syntax
194 self.footprint.erode(1, afwGeom.Stencil.BOX)
196 # verify the eroded dimensions
197 bBox = self.footprint.getBBox()
198 self.assertEqual(bBox.getMinX(), -3)
199 self.assertEqual(bBox.getMinY(), -3)
200 self.assertEqual(bBox.getMaxX(), 3)
201 self.assertEqual(bBox.getMaxY(), 3)
203 # Dilate the footprint back to the origional using alternate signature
204 self.footprint.dilate(1, afwGeom.Stencil.BOX)
205 self.assertEqual(self.footprint.spans, self.spans)
207 def testSplit(self):
208 spanList = [afwGeom.Span(0, 2, 4),
209 afwGeom.Span(1, 2, 4),
210 afwGeom.Span(2, 2, 4),
211 afwGeom.Span(10, 4, 7),
212 afwGeom.Span(11, 4, 7),
213 afwGeom.Span(12, 4, 7)]
215 spans = afwGeom.SpanSet(spanList)
216 region = lsst.geom.Box2I(lsst.geom.PointI(-6, -6), lsst.geom.PointI(20, 20))
217 multiFoot = afwDet.Footprint(spans, region)
219 records = [multiFoot.addPeak(3, 1, 100),
220 multiFoot.addPeak(5, 11, 100)]
222 # Verify that the footprint is multi-component
223 self.assertFalse(multiFoot.isContiguous())
225 footprintList = multiFoot.split()
227 self.assertEqual(len(footprintList), 2)
228 for i, fp in enumerate(footprintList):
229 # check that the correct Spans are populated for each
230 tempSpan = afwGeom.SpanSet(spanList[i*3:i*3+3])
231 self.assertEqual(fp.spans, tempSpan)
233 # check that the peaks are split properly
234 self.assertEqual(len(fp.peaks), 1)
235 self.assertEqual(fp.peaks[0], records[i])
237 def testPersistence(self):
238 # populate the peaks for the peak tests
239 self.testPeakFunctionality()
241 with lsst.utils.tests.getTempFilePath(".fits") as filepath:
242 # Persist the Footprint to file and read it back
243 self.footprint.writeFits(filepath)
244 footprintFromFile = afwDet.Footprint.readFits(filepath)
246 # Check that the Footprint before and after saving are the same
247 self.assertEqual(self.footprint, footprintFromFile)
249 # Clean up after ourselves
250 del footprintFromFile
252 def testLegacyFootprints(self):
253 testPath = os.path.abspath(os.path.dirname(__file__))
254 fileName = os.path.join(testPath, 'data', 'preSpanSetsFootprint.fits')
255 legacyFootprint = afwDet.Footprint.readFits(fileName)
257 # Calculate some quantifying numbers from the legacy Footprint to ensure
258 # it loaded properly
259 self.assertEqual(len(legacyFootprint.spans), 303)
260 self.assertEqual(len(legacyFootprint.peaks), 48)
261 self.assertEqual(legacyFootprint.spans.getBBox(),
262 lsst.geom.Box2I(lsst.geom.Point2I(32676, 27387),
263 lsst.geom.Extent2I(175, 153)))
264 legacyCenter = legacyFootprint.spans.computeCentroid()
265 self.assertAlmostEqual(legacyCenter.getY(), 27456.70733, 5)
266 self.assertAlmostEqual(legacyCenter.getX(), 32775.47611, 5)
268 del legacyFootprint
271class TestMemory(lsst.utils.tests.MemoryTestCase):
272 pass
275def setup_module(module):
276 lsst.utils.tests.init()
279if __name__ == "__main__": 279 ↛ 280line 279 didn't jump to line 280, because the condition on line 279 was never true
280 lsst.utils.tests.init()
281 unittest.main()