Coverage for tests/test_overscanCorrection.py: 12%
177 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-14 16:32 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-14 16:32 -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#
23import unittest
24import numpy as np
26import lsst.utils.tests
27import lsst.geom
28import lsst.afw.image as afwImage
29import lsst.ip.isr as ipIsr
32class IsrTestCases(lsst.utils.tests.TestCase):
34 def setUp(self):
35 self.overscanKeyword = "BIASSEC"
37 def tearDown(self):
38 del self.overscanKeyword
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
47 order = kwargs.get('order', None)
48 if order:
49 config.overscan.order = order
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)
57 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10))
58 dataImage = afwImage.MaskedImageF(maskedImage, dataBox)
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)
70 config = ipIsr.IsrTask.ConfigClass()
71 self.updateConfigFromKwargs(config, **kwargs)
73 if kwargs['fitType'] == "MEDIAN_PER_ROW":
74 # Add a bad point to test outlier rejection.
75 overscan.getImage().getArray()[0, 0] = 12345
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
81 isrTask = ipIsr.IsrTask(config=config)
82 isrTask.overscan.run(dataImage.getImage(), overscan.getImage())
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)
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)
101 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10))
102 dataImage = afwImage.MaskedImageF(maskedImage, dataBox)
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)
111 exposure = afwImage.ExposureF(maskedImage, None)
112 metadata = exposure.getMetadata()
113 metadata.setString(self.overscanKeyword, biassec)
115 config = ipIsr.IsrTask.ConfigClass()
116 self.updateConfigFromKwargs(config, **kwargs)
118 isrTask = ipIsr.IsrTask(config=config)
119 isrTask.overscan.run(dataImage, overscan.getImage())
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)
130 def checkOverscanCorrectionSineWave(self, **kwargs):
131 """vertical sine wave along long direction"""
133 # Full image: (500,100)
134 longAxis = 500
135 shortAxis = 100
136 overscanWidth = 30
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)
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)
149 fullImage = np.repeat(sineWave, shortAxis).reshape((longAxis, shortAxis))
150 maskedImage.image.array += fullImage
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
163 exposure = afwImage.ExposureF(maskedImage, None)
164 metadata = exposure.getMetadata()
165 metadata.setString(self.overscanKeyword, biassec)
167 ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs)
169 height = maskedImage.getHeight()
170 width = maskedImage.getWidth()
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)
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")
184 def test_MedianOverscanCorrection(self):
185 self.checkOverscanCorrectionY(fitType="MEDIAN")
186 self.checkOverscanCorrectionX(fitType="MEDIAN")
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)
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
205 config = ipIsr.IsrTask.ConfigClass()
206 self.updateConfigFromKwargs(config, **kwargs)
208 isrTask = ipIsr.IsrTask(config=config)
209 isrTask.overscan.run(dataImage, overscan.getImage())
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)
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)
230 dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10))
231 dataImage = afwImage.MaskedImageF(maskedImage, dataBox)
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
242 config = ipIsr.IsrTask.ConfigClass()
243 self.updateConfigFromKwargs(config, **kwargs)
245 isrTask = ipIsr.IsrTask(config=config)
246 isrTask.overscan.run(dataImage, overscan.getImage())
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)
261 def testPolyOverscanCorrection(self):
262 for fitType in ("POLY", "CHEB", "LEG"):
263 self.checkPolyOverscanCorrectionX(fitType=fitType)
264 self.checkPolyOverscanCorrectionY(fitType=fitType)
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)
272class MemoryTester(lsst.utils.tests.MemoryTestCase):
273 pass
276def setup_module(module):
277 lsst.utils.tests.init()
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()