Coverage for tests/test_trailedEdgeSources.py: 25%

133 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-03-22 02:46 -0700

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# 

23 

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 

31 

32 

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]) 

38 

39 

40class TrailedEdgeSource: 

41 """Holds a set of true trail parameters. 

42 """ 

43 

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) 

53 

54 

55class TrailedTaskSetup: 

56 

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) 

64 

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) 

72 

73 

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 """ 

80 

81 def __init__(self, bbox, threshold=10.0, exposure=None, **kwds): 

82 

83 super().__init__(bbox, threshold, exposure, **kwds) 

84 

85 def addTrailedSource(self, trail, edge=True): 

86 """Add a trailed source to the simulation. 

87 

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) 

101 

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() 

111 

112 planes = self.exposure.mask.getMaskPlaneDict() 

113 dim = self.exposure.getBBox().getDimensions() 

114 

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) 

120 

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) 

124 

125 totFlux = self.exposure.image.array.sum() 

126 self.exposure.image.array /= totFlux 

127 self.exposure.image.array *= trail.instFlux 

128 

129 record.set(self.keys["instFlux"], trail.instFlux) 

130 self._installFootprint(record, self.exposure.getImage()) 

131 

132 return record, self.exposure.getImage() 

133 

134 

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. 

139 

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 """ 

145 

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) 

150 

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) 

154 

155 def tearDown(self): 

156 del self.center 

157 del self.bbox 

158 del self.trail 

159 del self.dataset 

160 

161 def testEdgeFlag(self): 

162 """Test if edge flags are correctly set in NaivePlugin.py 

163 

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] 

180 

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']) 

186 

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) 

195 

196 self.assertFalse(begin_edge_pixel_set) 

197 self.assertTrue(end_edge_pixel_set) 

198 

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")) 

205 

206 x1 = int(record['ext_trailedSources_Naive_x1']) 

207 y1 = int(record['ext_trailedSources_Naive_y1']) 

208 

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) 

211 

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) 

218 

219 self.assertFalse(begin_edge_pixel_set) 

220 self.assertFalse(end_edge_pixel_set) 

221 

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")) 

225 

226 x1 = int(record['ext_trailedSources_Naive_x1']) 

227 y1 = int(record['ext_trailedSources_Naive_y1']) 

228 

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) 

231 

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")) 

236 

237 

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. 

241 

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 """ 

247 

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) 

252 

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) 

257 

258 def tearDown(self): 

259 del self.center 

260 del self.bbox 

261 del self.trail 

262 del self.dataset 

263 

264 def testOffImageEdgeFlag(self): 

265 """Test if edge flags are correctly set in NaivePlugin.py when source 

266 extends off the the image. 

267 

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] 

281 

282 self.assertTrue(record.get("ext_trailedSources_Naive_flag_edge")) 

283 self.assertFalse(record.get("ext_trailedSources_Naive_flag")) 

284 

285 

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

287 pass 

288 

289 

290def setup_module(module): 

291 lsst.utils.tests.init() 

292 

293 

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()