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
« 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#
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 testIsHeavy(self):
71 self.assertFalse(self.footprint.isHeavy())
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)
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)
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)
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)
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)
132 # Shift the footprint back
133 self.footprint.shift(lsst.geom.ExtentI(-offsetX, -offsetY))
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)
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)
146 nonMemberPoint = lsst.geom.Point2I(100, 100)
147 self.assertFalse(self.footprint.contains(nonMemberPoint))
148 self.assertNotIn(nonMemberPoint, self.footprint)
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())
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)
171 # Set the footprint back to what it was
172 self.footprint = afwDet.Footprint(self.spans)
174 # Test erode
175 kernelRad = 1
176 kernel = afwGeom.SpanSet.fromShape(kernelRad, afwGeom.Stencil.BOX)
177 self.footprint.erode(kernel)
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)
186 # Dilate the footprint back to the origional
187 self.footprint.dilate(kernel)
188 self.assertEqual(self.footprint.spans, self.spans)
190 # erode using the alternate call syntax
191 self.footprint.erode(1, afwGeom.Stencil.BOX)
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)
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)
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)]
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)
216 records = [multiFoot.addPeak(3, 1, 100),
217 multiFoot.addPeak(5, 11, 100)]
219 # Verify that the footprint is multi-component
220 self.assertFalse(multiFoot.isContiguous())
222 footprintList = multiFoot.split()
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)
230 # check that the peaks are split properly
231 self.assertEqual(len(fp.peaks), 1)
232 self.assertEqual(fp.peaks[0], records[i])
234 def testPersistence(self):
235 # populate the peaks for the peak tests
236 self.testPeakFunctionality()
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)
243 # Check that the Footprint before and after saving are the same
244 self.assertEqual(self.footprint, footprintFromFile)
246 # Clean up after ourselves
247 del footprintFromFile
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)
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)
265 del legacyFootprint
268class TestMemory(lsst.utils.tests.MemoryTestCase):
269 pass
272def setup_module(module):
273 lsst.utils.tests.init()
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()