Coverage for tests/test_trailedEdgeSources.py: 25%
133 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-24 11:25 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-24 11:25 +0000
1#
2# This file is part of meas_extensions_trailedSources.
3#
4# Developed for the LSST Data Management System.
5# This product includes software developed by the LSST Project
6# (http://www.lsst.org).
7# See the COPYRIGHT file at the top-level directory of this distribution
8# for details of code ownership.
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
24import numpy as np
25import unittest
26import lsst.utils.tests
27import lsst.meas.extensions.trailedSources
28from lsst.meas.base.tests import AlgorithmTestCase
29from lsst.utils.tests import classParameters
30from lsst.geom import Point2I, Point2D, Box2I, Extent2I
33# Trailed-source length, angle, and centroid coordinates.
34trail_lengths = np.array([5, 5, 10])
35trail_angles = np.array([100, 0, 5])
36trail_x_coords = np.array([100, 20, -20])
37trail_y_coords = np.array([100, 20, -30])
40class TrailedEdgeSource:
41 """Holds a set of true trail parameters.
42 """
44 def __init__(self, instFlux, length, angle, xc, yc):
45 self.instFlux = instFlux
46 self.length = length
47 self.angle = angle
48 self.center = Point2D(xc, yc)
49 self.x0 = xc - length / 2 * np.cos(angle)
50 self.y0 = yc - length / 2 * np.sin(angle)
51 self.x1 = xc + length / 2 * np.cos(angle)
52 self.y1 = yc + length / 2 * np.sin(angle)
55class TrailedTaskSetup:
57 def makeTrailedSourceMeasurementTask(self, plugin=None, dependencies=(),
58 config=None, schema=None,
59 algMetadata=None):
60 """Set up a measurement task for a trailed source plugin.
61 """
62 config = self.makeSingleFrameMeasurementConfig(plugin=plugin,
63 dependencies=dependencies)
65 # Make sure the shape slot is base_SdssShape
66 config.slots.shape = "base_SdssShape"
67 return self.makeSingleFrameMeasurementTask(plugin=plugin,
68 dependencies=dependencies,
69 config=config,
70 schema=schema,
71 algMetadata=algMetadata)
74# "Extend" meas.base.tests.TestDataset
75class TrailedTestDataset(lsst.meas.base.tests.TestDataset):
76 """A dataset for testing trailed source measurements.
77 Given a `TrailedSource`, construct a record of the true values and an
78 Exposure.
79 """
81 def __init__(self, bbox, threshold=10.0, exposure=None, **kwds):
83 super().__init__(bbox, threshold, exposure, **kwds)
85 def addTrailedSource(self, trail, edge=True):
86 """Add a trailed source to the simulation.
88 Re-implemented version of
89 `lsst.meas.base.tests.TestDataset.addSource`. Numerically integrates a
90 Gaussian PSF over a line to obtain an image of a trailed source and
91 adds edge flags to the image.
92 """
93 record = self.catalog.addNew()
94 record.set(self.keys["centroid"], trail.center)
95 rng = np.random.default_rng(32)
96 covariance = rng.normal(0, 0.1, 4).reshape(2, 2)
97 covariance[0, 1] = covariance[1, 0]
98 record.set(self.keys["centroid_sigma"], covariance.astype(np.float32))
99 record.set(self.keys["shape"], self.psfShape)
100 record.set(self.keys["isStar"], False)
102 # Sum the psf at each
103 numIter = int(2 * trail.length)
104 xp = np.linspace(trail.x0, trail.x1, num=numIter)
105 yp = np.linspace(trail.y0, trail.y1, num=numIter)
106 for (x, y) in zip(xp, yp):
107 pt = Point2D(x, y)
108 im = self.drawGaussian(self.exposure.getBBox(), trail.instFlux,
109 lsst.afw.geom.Ellipse(self.psfShape, pt))
110 self.exposure.getMaskedImage().getImage().getArray()[:, :] += im.getArray()
112 planes = self.exposure.mask.getMaskPlaneDict()
113 dim = self.exposure.getBBox().getDimensions()
115 # Add edge flags to the first and last 20 columns and rows.
116 if edge:
117 for y in range(20):
118 self.exposure.mask.setMaskPlaneValues(planes['EDGE'], 0, dim[0] - 1, y)
119 self.exposure.mask.setMaskPlaneValues(planes['EDGE'], 0, dim[0] - 1, y + dim[1] - 20)
121 for y in range(dim[1]):
122 self.exposure.mask.setMaskPlaneValues(planes['EDGE'], 0, 20, y)
123 self.exposure.mask.setMaskPlaneValues(planes['EDGE'], dim[0] - 20, dim[0] - 1, y)
125 totFlux = self.exposure.image.array.sum()
126 self.exposure.image.array /= totFlux
127 self.exposure.image.array *= trail.instFlux
129 record.set(self.keys["instFlux"], trail.instFlux)
130 self._installFootprint(record, self.exposure.getImage())
132 return record, self.exposure.getImage()
135# Following from test_trailedSources
136@classParameters(length=trail_lengths, theta=trail_angles, xc=trail_x_coords, yc=trail_y_coords)
137class TrailedEdgeSourcesTestCase(AlgorithmTestCase, lsst.utils.tests.TestCase):
138 """ Test if ext_trailedSources_Naive_flag_edge is set correctly.
140 Given a `TrailedSource`, test if the edge flag is set correctly in the
141 source catalog after the
142 `lsst.meas.extensions.trailedSources.Naive.Plugin.makeTrailedSourceMeasurementTask`
143 has been run on the source catalog.
144 """
146 def setUp(self):
147 self.center = Point2D(50.1, 49.8)
148 self.bbox = Box2I(lsst.geom.Point2I(-20, -30), Extent2I(140, 160))
149 self.dataset = TrailedTestDataset(self.bbox)
151 # Trail which extends into edge pixels
152 self.trail = TrailedEdgeSource(100000.0, self.length, self.theta, self.xc, self.yc)
153 self.dataset.addTrailedSource(self.trail)
155 def tearDown(self):
156 del self.center
157 del self.bbox
158 del self.trail
159 del self.dataset
161 def testEdgeFlag(self):
162 """Test if edge flags are correctly set in NaivePlugin.py
164 Given a `TrailedTestDataset`, run the NaivePlugin measurement and
165 check that the trailed sources have the edge flag set. [100,100] does
166 not contain any edge pixels and should not have a flag set, [20,20]
167 crosses into the edge region on onle one side and should have the edge
168 flag set, and [-20,-30] extends off the chip and should have the edge
169 flag set.
170 """
171 # Set up and run Naive measurement.
172 task = TrailedTaskSetup.makeTrailedSourceMeasurementTask(self,
173 plugin="ext_trailedSources_Naive",
174 dependencies=("base_SdssCentroid",
175 "base_SdssShape")
176 )
177 exposure, catalog = self.dataset.realize(5.0, task.schema, randomSeed=0)
178 task.run(catalog, exposure)
179 record = catalog[0]
181 # Check that x0, y0 or x1, y1 is flagged as an edge pixel
182 x1 = int(record['ext_trailedSources_Naive_x1'])
183 y1 = int(record['ext_trailedSources_Naive_y1'])
184 x0 = int(record['ext_trailedSources_Naive_x0'])
185 y0 = int(record['ext_trailedSources_Naive_y0'])
187 # Test Case with no edge pixels
188 if record['truth_x'] == 100:
189 # These are used to ensure the mask pixels the trailed sources are
190 # compared with have the correct flags set
191 begin_edge_pixel_set = (exposure.mask[Point2I(x0, y0)] & exposure.mask.getPlaneBitMask(
192 'EDGE') != 0)
193 end_edge_pixel_set = (exposure.mask[Point2I(x1, y1)] & exposure.mask.getPlaneBitMask(
194 'EDGE') != 0)
196 self.assertFalse(begin_edge_pixel_set)
197 self.assertTrue(end_edge_pixel_set)
199 # Make sure measurement edge flag is set, but Naive_flag is not.
200 # A failed trailed source measurement with the edge flag
201 # set means the edge flag was set despite the measurement
202 # failing.
203 self.assertTrue(record.get("ext_trailedSources_Naive_flag_edge"))
204 self.assertFalse(record.get("ext_trailedSources_Naive_flag"))
206 x1 = int(record['ext_trailedSources_Naive_x1'])
207 y1 = int(record['ext_trailedSources_Naive_y1'])
209 self.assertFalse(exposure.mask[Point2I(x0, y0)] & exposure.mask.getPlaneBitMask('EDGE') != 0)
210 self.assertTrue(exposure.mask[Point2I(x1, y1)] & exposure.mask.getPlaneBitMask('EDGE') != 0)
212 # Test case with one end of trail containing edge pixels
213 elif record['truth_x'] == 20:
214 begin_edge_pixel_set = (exposure.mask[Point2I(x0, y0)] & exposure.mask.getPlaneBitMask(
215 'EDGE') != 0)
216 end_edge_pixel_set = (exposure.mask[Point2I(x1, y1)] & exposure.mask.getPlaneBitMask(
217 'EDGE') != 0)
219 self.assertFalse(begin_edge_pixel_set)
220 self.assertFalse(end_edge_pixel_set)
222 # Make sure measurement Naive_flag_edge and Naive_flag not set
223 self.assertFalse(record.get("ext_trailedSources_Naive_flag_edge"))
224 self.assertFalse(record.get("ext_trailedSources_Naive_flag"))
226 x1 = int(record['ext_trailedSources_Naive_x1'])
227 y1 = int(record['ext_trailedSources_Naive_y1'])
229 self.assertFalse(exposure.mask[Point2I(x0, y0)] & exposure.mask.getPlaneBitMask('EDGE') != 0)
230 self.assertFalse(exposure.mask[Point2I(x1, y1)] & exposure.mask.getPlaneBitMask('EDGE') != 0)
232 # Test case with trailed source extending off chip.
233 else:
234 self.assertTrue(record.get("ext_trailedSources_Naive_flag_edge"))
235 self.assertFalse(record.get("ext_trailedSources_Naive_flag"))
238@classParameters(length=[10], theta=[5], xc=[-20], yc=[-30])
239class TrailedEdgeSourcesOffImageTest(AlgorithmTestCase, lsst.utils.tests.TestCase):
240 """ Test if ext_trailedSources_Naive_flag_edge is set correctly.
242 Given a `TrailedSource`, test if the edge flag is set correctly in the
243 source catalog after the
244 'lsst.meas.extensions.trailedSources.Naive.Plugin.makeTrailedSourceMeasurementTask'
245 has been run on the source catalog.
246 """
248 def setUp(self):
249 self.center = Point2D(50.1, 49.8)
250 self.bbox = Box2I(lsst.geom.Point2I(-20, -30), Extent2I(140, 160))
251 self.dataset = TrailedTestDataset(self.bbox)
253 # Trail which extends into edge pixels
254 self.trail = TrailedEdgeSource(100000.0, self.length, self.theta,
255 self.xc, self.yc)
256 self.dataset.addTrailedSource(self.trail, edge=False)
258 def tearDown(self):
259 del self.center
260 del self.bbox
261 del self.trail
262 del self.dataset
264 def testOffImageEdgeFlag(self):
265 """Test if edge flags are correctly set in NaivePlugin.py when source
266 extends off the the image.
268 Given a `TrailedTestDataset`, run the NaivePlugin measurement and
269 check that the edge flag set when a source extends off the chip.
270 Edge pixels are not set in this test.
271 """
272 # Set up and run Naive measurement.
273 task = TrailedTaskSetup.makeTrailedSourceMeasurementTask(self,
274 plugin="ext_trailedSources_Naive",
275 dependencies=("base_SdssCentroid",
276 "base_SdssShape")
277 )
278 exposure, catalog = self.dataset.realize(5.0, task.schema, randomSeed=0)
279 task.run(catalog, exposure)
280 record = catalog[0]
282 self.assertTrue(record.get("ext_trailedSources_Naive_flag_edge"))
283 self.assertFalse(record.get("ext_trailedSources_Naive_flag"))
286class TestMemory(lsst.utils.tests.MemoryTestCase):
287 pass
290def setup_module(module):
291 lsst.utils.tests.init()
294if __name__ == "__main__": 294 ↛ 295line 294 didn't jump to line 295, because the condition on line 294 was never true
295 lsst.utils.tests.init()
296 unittest.main()