Coverage for tests/test_overscanCorrection.py: 12%

177 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-23 03:04 -0700

1# 

2# LSST Data Management System 

3# Copyright 2008, 2009, 2010 LSST Corporation. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import unittest 

24import numpy as np 

25 

26import lsst.utils.tests 

27import lsst.geom 

28import lsst.afw.image as afwImage 

29import lsst.ip.isr as ipIsr 

30 

31 

32class IsrTestCases(lsst.utils.tests.TestCase): 

33 

34 def setUp(self): 

35 self.overscanKeyword = "BIASSEC" 

36 

37 def tearDown(self): 

38 del self.overscanKeyword 

39 

40 def updateConfigFromKwargs(self, config, **kwargs): 

41 """Common config from keywords. 

42 """ 

43 fitType = kwargs.get('fitType', None) 

44 if fitType: 

45 config.overscan.fitType = fitType 

46 

47 order = kwargs.get('order', None) 

48 if order: 

49 config.overscan.order = order 

50 

51 def checkOverscanCorrectionY(self, **kwargs): 

52 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

53 lsst.geom.Point2I(9, 12)) 

54 maskedImage = afwImage.MaskedImageF(bbox) 

55 maskedImage.set(10, 0x0, 1) 

56 

57 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10)) 

58 dataImage = afwImage.MaskedImageF(maskedImage, dataBox) 

59 

60 # these should be functionally equivalent 

61 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 10), 

62 lsst.geom.Point2I(9, 12)) 

63 biassec = '[1:10,11:13]' 

64 overscan = afwImage.MaskedImageF(maskedImage, bbox) 

65 overscan.set(2, 0x0, 1) 

66 exposure = afwImage.ExposureF(maskedImage, None) 

67 metadata = exposure.getMetadata() 

68 metadata.setString(self.overscanKeyword, biassec) 

69 

70 config = ipIsr.IsrTask.ConfigClass() 

71 self.updateConfigFromKwargs(config, **kwargs) 

72 

73 if kwargs['fitType'] == "MEDIAN_PER_ROW": 

74 # Add a bad point to test outlier rejection. 

75 overscan.getImage().getArray()[0, 0] = 12345 

76 

77 # Shrink the sigma clipping limit to handle the fact that the 

78 # bad point is not be rejected at higher thresholds (2/0.74). 

79 config.overscan.numSigmaClip = 2.7 

80 

81 isrTask = ipIsr.IsrTask(config=config) 

82 isrTask.overscan.run(dataImage.getImage(), overscan.getImage()) 

83 

84 height = maskedImage.getHeight() 

85 width = maskedImage.getWidth() 

86 for j in range(height): 

87 for i in range(width): 

88 if j == 10 and i == 0 and kwargs['fitType'] == "MEDIAN_PER_ROW": 

89 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 12343) 

90 elif j >= 10: 

91 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0) 

92 else: 

93 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 8) 

94 

95 def checkOverscanCorrectionX(self, **kwargs): 

96 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

97 lsst.geom.Point2I(12, 9)) 

98 maskedImage = afwImage.MaskedImageF(bbox) 

99 maskedImage.set(10, 0x0, 1) 

100 

101 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10)) 

102 dataImage = afwImage.MaskedImageF(maskedImage, dataBox) 

103 

104 # these should be functionally equivalent 

105 bbox = lsst.geom.Box2I(lsst.geom.Point2I(10, 0), 

106 lsst.geom.Point2I(12, 9)) 

107 biassec = '[11:13,1:10]' 

108 overscan = afwImage.MaskedImageF(maskedImage, bbox) 

109 overscan.set(2, 0x0, 1) 

110 

111 exposure = afwImage.ExposureF(maskedImage, None) 

112 metadata = exposure.getMetadata() 

113 metadata.setString(self.overscanKeyword, biassec) 

114 

115 config = ipIsr.IsrTask.ConfigClass() 

116 self.updateConfigFromKwargs(config, **kwargs) 

117 

118 isrTask = ipIsr.IsrTask(config=config) 

119 isrTask.overscan.run(dataImage, overscan.getImage()) 

120 

121 height = maskedImage.getHeight() 

122 width = maskedImage.getWidth() 

123 for j in range(height): 

124 for i in range(width): 

125 if i >= 10: 

126 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0) 

127 else: 

128 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 8) 

129 

130 def checkOverscanCorrectionSineWave(self, **kwargs): 

131 """vertical sine wave along long direction""" 

132 

133 # Full image: (500,100) 

134 longAxis = 500 

135 shortAxis = 100 

136 overscanWidth = 30 

137 

138 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

139 lsst.geom.Point2I(shortAxis-1, longAxis-1)) 

140 maskedImage = afwImage.MaskedImageF(bbox) 

141 maskedImage.set(50.0, 0x0, 1) 

142 

143 # vertical sine wave along long direction 

144 x = np.linspace(0, 2*3.14159, longAxis) 

145 a, w = 15, 50*3.14159 

146 sineWave = 20 + a*np.sin(w*x) 

147 sineWave = sineWave.astype(int) 

148 

149 fullImage = np.repeat(sineWave, shortAxis).reshape((longAxis, shortAxis)) 

150 maskedImage.image.array += fullImage 

151 

152 # data part of the full image: (500,70) 

153 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(shortAxis-overscanWidth, 

154 longAxis)) 

155 dataImage = afwImage.MaskedImageF(maskedImage, dataBox) 

156 # these should be functionally equivalent 

157 bbox = lsst.geom.Box2I(lsst.geom.Point2I(shortAxis-overscanWidth, 0), 

158 lsst.geom.Point2I(shortAxis-1, longAxis-1)) 

159 biassec = '[1:500,71:100]' 

160 overscan = afwImage.MaskedImageF(maskedImage, bbox) 

161 overscan.image.array -= 50.0 # subtract initial pedestal 

162 

163 exposure = afwImage.ExposureF(maskedImage, None) 

164 metadata = exposure.getMetadata() 

165 metadata.setString(self.overscanKeyword, biassec) 

166 

167 ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs) 

168 

169 height = maskedImage.getHeight() 

170 width = maskedImage.getWidth() 

171 

172 for j in range(height): 

173 for i in range(width): 

174 if i >= 70: 

175 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0.0) 

176 else: 

177 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 50.0) 

178 

179 def test_MedianPerRowOverscanCorrection(self): 

180 self.checkOverscanCorrectionY(fitType="MEDIAN_PER_ROW") 

181 self.checkOverscanCorrectionY(fitType="MEDIAN_PER_ROW") 

182 self.checkOverscanCorrectionSineWave(fitType="MEDIAN_PER_ROW") 

183 

184 def test_MedianOverscanCorrection(self): 

185 self.checkOverscanCorrectionY(fitType="MEDIAN") 

186 self.checkOverscanCorrectionX(fitType="MEDIAN") 

187 

188 def checkPolyOverscanCorrectionX(self, **kwargs): 

189 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

190 lsst.geom.Point2I(12, 9)) 

191 maskedImage = afwImage.MaskedImageF(bbox) 

192 maskedImage.set(10, 0x0, 1) 

193 

194 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10)) 

195 dataImage = afwImage.MaskedImageF(maskedImage, dataBox) 

196 # these should be functionally equivalent 

197 bbox = lsst.geom.Box2I(lsst.geom.Point2I(10, 0), 

198 lsst.geom.Point2I(12, 9)) 

199 overscan = afwImage.MaskedImageF(maskedImage, bbox) 

200 overscan.set(2, 0x0, 1) 

201 for i in range(bbox.getDimensions()[1]): 

202 for j, off in enumerate([-0.5, 0.0, 0.5]): 

203 overscan.image[j, i, afwImage.LOCAL] = 2+i+off 

204 

205 config = ipIsr.IsrTask.ConfigClass() 

206 self.updateConfigFromKwargs(config, **kwargs) 

207 

208 isrTask = ipIsr.IsrTask(config=config) 

209 isrTask.overscan.run(dataImage, overscan.getImage()) 

210 

211 height = maskedImage.getHeight() 

212 width = maskedImage.getWidth() 

213 for j in range(height): 

214 for i in range(width): 

215 if i == 10: 

216 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], -0.5) 

217 elif i == 11: 

218 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0) 

219 elif i == 12: 

220 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0.5) 

221 else: 

222 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 10 - 2 - j) 

223 

224 def checkPolyOverscanCorrectionY(self, **kwargs): 

225 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

226 lsst.geom.Point2I(9, 12)) 

227 maskedImage = afwImage.MaskedImageF(bbox) 

228 maskedImage.set(10, 0x0, 1) 

229 

230 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10)) 

231 dataImage = afwImage.MaskedImageF(maskedImage, dataBox) 

232 

233 # these should be functionally equivalent 

234 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 10), 

235 lsst.geom.Point2I(9, 12)) 

236 overscan = afwImage.MaskedImageF(maskedImage, bbox) 

237 overscan.set(2, 0x0, 1) 

238 for i in range(bbox.getDimensions()[0]): 

239 for j, off in enumerate([-0.5, 0.0, 0.5]): 

240 overscan.image[i, j, afwImage.LOCAL] = 2+i+off 

241 

242 config = ipIsr.IsrTask.ConfigClass() 

243 self.updateConfigFromKwargs(config, **kwargs) 

244 

245 isrTask = ipIsr.IsrTask(config=config) 

246 isrTask.overscan.run(dataImage, overscan.getImage()) 

247 

248 height = maskedImage.getHeight() 

249 width = maskedImage.getWidth() 

250 for j in range(height): 

251 for i in range(width): 

252 if j == 10: 

253 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], -0.5) 

254 elif j == 11: 

255 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0) 

256 elif j == 12: 

257 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0.5) 

258 else: 

259 self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 10 - 2 - i) 

260 

261 def testPolyOverscanCorrection(self): 

262 for fitType in ("POLY", "CHEB", "LEG"): 

263 self.checkPolyOverscanCorrectionX(fitType=fitType) 

264 self.checkPolyOverscanCorrectionY(fitType=fitType) 

265 

266 def testSplineOverscanCorrection(self): 

267 for fitType in ("NATURAL_SPLINE", "CUBIC_SPLINE", "AKIMA_SPLINE"): 

268 self.checkPolyOverscanCorrectionX(fitType=fitType, order=5) 

269 self.checkPolyOverscanCorrectionY(fitType=fitType, order=5) 

270 

271 

272class MemoryTester(lsst.utils.tests.MemoryTestCase): 

273 pass 

274 

275 

276def setup_module(module): 

277 lsst.utils.tests.init() 

278 

279 

280if __name__ == "__main__": 280 ↛ 281line 280 didn't jump to line 281, because the condition on line 280 was never true

281 lsst.utils.tests.init() 

282 unittest.main()