Coverage for tests/test_defects.py: 18%
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of meas_algorithms.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import os
23import unittest
25import lsst.geom
26import lsst.afw.image as afwImage
27import lsst.meas.algorithms as algorithms
28import lsst.utils.tests
29from lsst.daf.base import PropertyList
30from lsst.ip.isr import Defects
32try:
33 type(display)
34except NameError:
35 display = False
36else:
37 import lsst.afw.display as afwDisplay
38 afwDisplay.setDefaultMaskTransparency(75)
40# Determine if we have afwdata
41try:
42 afwdataDir = lsst.utils.getPackageDir('afwdata')
43except Exception:
44 afwdataDir = None
46TESTDIR = os.path.abspath(os.path.dirname(__file__))
49class DefectsTestCase(lsst.utils.tests.TestCase):
50 """Tests for collections of Defect."""
52 def assertMetadata(self, first, second):
53 """Compare the metadata associated with Defects"""
55 # Must strip out DATE metadata before comparison
56 meta1 = first.getMetadata()
57 meta2 = second.getMetadata()
58 for d in (meta1, meta2):
59 for k in ("DATE", "CALIB_CREATION_DATE", "CALIB_CREATION_TIME"):
60 if k in d:
61 del d[k]
63 self.assertEqual(meta1, meta2)
64 meta1["NEW"] = "additional header"
65 self.assertNotEqual(first.getMetadata(), second.getMetadata())
66 del meta1["NEW"]
68 def test_defects(self):
69 defects = Defects()
71 defects.append(algorithms.Defect(lsst.geom.Box2I(lsst.geom.Point2I(5, 6),
72 lsst.geom.Point2I(41, 50))))
74 defects.append(lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
75 lsst.geom.Point2I(4, 5)))
76 defects.append(lsst.geom.Point2I(50, 50))
77 defects.append(afwImage.DefectBase(lsst.geom.Box2I(lsst.geom.Point2I(100, 200),
78 lsst.geom.Extent2I(5, 5))))
79 self.assertEqual(len(defects), 4)
81 for d in defects:
82 self.assertIsInstance(d, algorithms.Defect)
84 # Transposition
85 transposed = defects.transpose()
86 self.assertEqual(len(transposed), len(defects))
88 # Check that an individual defect is found properly transposed within
89 # the outputs.
90 found = False
91 for defect in transposed:
92 if defect.getBBox() == lsst.geom.Box2I(lsst.geom.Point2I(6, 5), lsst.geom.Extent2I(45, 37)):
93 found = True
94 break
95 self.assertTrue(found)
97 # Serialization round trip
98 meta = PropertyList()
99 meta["TESTHDR"] = "testing"
100 defects.setMetadata(meta)
102 table = defects.toFitsRegionTable()
104 defects2 = Defects.fromTable([table])
106 self.assertEqual(defects2, defects)
108 # via FITS
109 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
110 defects.writeFits(tmpFile)
111 defects2 = Defects.readFits(tmpFile)
113 # Equality tests the bounding boxes so metadata is tested separately.
114 self.assertEqual(defects2, defects)
115 self.assertMetadata(defects2, defects)
117 # via text file
118 with lsst.utils.tests.getTempFilePath(".ecsv") as tmpFile:
119 defects.writeText(tmpFile)
120 defects2 = Defects.readText(tmpFile)
122 # Equality tests the bounding boxes so metadata is tested separately.
123 self.assertEqual(defects2, defects)
124 self.assertMetadata(defects2, defects)
126 # Check bad values
127 with self.assertRaises(ValueError):
128 defects.append(lsst.geom.Box2D(lsst.geom.Point2D(0., 0.),
129 lsst.geom.Point2D(3.1, 3.1)))
130 with self.assertRaises(ValueError):
131 defects.append("defect")
133 def testAstropyRegion(self):
134 """Read a FITS region file created by Astropy regions."""
135 # The file contains three regions:
136 #
137 # - Point2I(340, 344)
138 # - Point2I(340, 344)
139 # - Box2I(minimum=Point2I(5, -5), dimensions=Extent2I(10, 20))
140 #
141 # The two coincident points are combined on read, so we end up with two defects.
143 with self.assertLogs():
144 defects = Defects.readFits(os.path.join(TESTDIR, "data", "fits_region.fits"),
145 normalize_on_init=True)
147 self.assertEqual(len(defects), 2)
149 def testLsstTextfile(self):
150 """Read legacy LSST text file format"""
151 with lsst.utils.tests.getTempFilePath(".txt") as tmpFile:
152 with open(tmpFile, "w") as fh:
153 print("""# X0 Y0 width height
154 996 0 56 24
155 0 4156 2048 20
156 0 0 17 4176
157 1998 4035 50 141
158 1023 0 2 4176
159 2027 0 21 4176
160 0 4047 37 129
161# Some rows without fixed column widths
16214 20 2000 50
16310 10 10 10
164""", file=fh)
166 defects = Defects.readLsstDefectsFile(tmpFile, normalize_on_init=True)
168 # Although there are 9 defects listed above, we record 11 after
169 # normalization. This is due to non-optimal behaviour in
170 # Defects.fromMask; see DM-24781.
171 self.assertEqual(len(defects), 11)
173 def test_normalize_defects(self):
174 """A test for the lsst.meas.algorithms.Defect.normalize() method.
175 """
176 defects = Defects()
178 # First series of 1-pixel contiguous defects
179 for yPix in range(1, 6):
180 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(15, yPix),
181 dimensions=lsst.geom.Extent2I(1, 1)))
183 # Defects are normalized as they are added; check that the above have
184 # been merged into a single bounding box.
185 self.assertEqual(len(defects), 1)
187 # Second series of 1-pixel contiguous defects in bulk mode
188 with defects.bulk_update():
189 for yPix in range(11, 16):
190 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(20, yPix),
191 dimensions=lsst.geom.Extent2I(1, 1)))
192 # In bulk mode, defects are not normalized.
193 self.assertEqual(len(defects), 6)
195 # Normalization applied on exiting bulk mode.
196 self.assertEqual(len(defects), 2)
198 boxesMeasured = []
199 for defect in defects:
200 boxesMeasured.append(defect.getBBox())
202 # The normalizing function should have created the following two boxes out
203 # of the individual 1-pixel defects from above
204 expectedDefects = [lsst.geom.Box2I(corner=lsst.geom.Point2I(15, 1),
205 dimensions=lsst.geom.Extent2I(1, 5)),
206 lsst.geom.Box2I(corner=lsst.geom.Point2I(20, 11),
207 dimensions=lsst.geom.Extent2I(1, 5))]
209 self.assertEqual(len(expectedDefects), len(boxesMeasured))
210 for expDef, measDef in zip(expectedDefects, boxesMeasured):
211 self.assertEqual(expDef, measDef)
213 # Normalize two distinct sets of Defects and ensure they compare to the same thing
214 defects = Defects()
215 # Set 1
216 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 1), dimensions=lsst.geom.Extent2I(1, 1)))
217 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 2), dimensions=lsst.geom.Extent2I(1, 1)))
218 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 3), dimensions=lsst.geom.Extent2I(1, 1)))
219 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 4), dimensions=lsst.geom.Extent2I(1, 1)))
220 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 5), dimensions=lsst.geom.Extent2I(1, 1)))
221 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 6), dimensions=lsst.geom.Extent2I(1, 1)))
222 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 7), dimensions=lsst.geom.Extent2I(1, 1)))
223 defects.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 8), dimensions=lsst.geom.Extent2I(1, 1)))
225 # Set 2
226 defects2 = Defects()
227 defects2.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 1), dimensions=lsst.geom.Extent2I(1, 5)))
228 defects2.append(lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 5), dimensions=lsst.geom.Extent2I(1, 4)))
230 self.assertEqual(defects, defects2)
232 boxesMeasured, boxesMeasured2 = [], []
233 for defect, defect2 in zip(defects, defects2):
234 boxesMeasured.append(defect.getBBox())
235 boxesMeasured2.append(defect2.getBBox())
237 expectedDefects = [lsst.geom.Box2I(corner=lsst.geom.Point2I(25, 1),
238 dimensions=lsst.geom.Extent2I(1, 8))]
240 self.assertEqual(len(expectedDefects), len(boxesMeasured))
241 for expDef, measDef in zip(expectedDefects, boxesMeasured):
242 self.assertEqual(expDef, measDef)
244 self.assertEqual(len(expectedDefects), len(boxesMeasured2))
245 for expDef, measDef in zip(expectedDefects, boxesMeasured2):
246 self.assertEqual(expDef, measDef)
249class TestMemory(lsst.utils.tests.MemoryTestCase):
250 pass
253def setup_module(module):
254 lsst.utils.tests.init()
257if __name__ == "__main__": 257 ↛ 258line 257 didn't jump to line 258, because the condition on line 257 was never true
258 lsst.utils.tests.init()
259 unittest.main()