Coverage for tests/test_verifyStats.py: 18%
156 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-04 03:35 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-04 03:35 -0700
1# This file is part of cp_verify.
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 numpy as np
23import unittest
25import lsst.utils.tests
26import lsst.ip.isr.isrMock as isrMock
27import lsst.cp.verify as cpVerify
28import lsst.ip.isr.isrFunctions as isrFunctions
30from lsst.pipe.base import TaskMetadata
33def updateMockExp(exposure, addCR=True):
34 """Update an exposure with a mask and variance plane.
36 Parameters
37 ----------
38 exposure : `lsst.afw.image.Exposure`
39 Exposure to be modified in place.
40 addCR : `bool`
41 Whether a known cosmic ray should be added to ``exposure``.
42 """
43 if addCR:
44 # Add a cosmic ray
45 image = exposure.getImage()
46 image.getArray()[50, 50] = 10000.0
48 # Set the mask and variance planes:
49 mask = exposure.getMask()
50 mask.getArray()[:, 10] = 1
51 isrFunctions.updateVariance(exposure.getMaskedImage(), 1.0, 5.0)
54class ToySubClass(cpVerify.CpVerifyStatsTask):
55 """The CpVerifyStatsTask requires an implentation of verify.
56 """
58 def verify(self, inputExp, outputStats):
59 # Docstring inherited from CpVerifyStatsTask.verify()
60 verifiedStats = {'A REAL TEST': True, 'A BAD TEST': False}
61 successValue = True
63 return verifiedStats, successValue
66class VerifyStatsTestCase(lsst.utils.tests.TestCase):
67 """Unit test for stats code.
68 """
70 def setUp(self):
71 """Generate a mock exposure/camera to test."""
72 self.inputExp = isrMock.CalibratedRawMock().run()
73 self.camera = isrMock.IsrMock().getCamera()
75 updateMockExp(self.inputExp)
77 def test_failures(self):
78 """Test that all the NotImplementedError methods fail correctly."""
79 results = None
80 with self.assertRaises(NotImplementedError):
81 # We have not implemented a verify method
82 config = cpVerify.CpVerifyStatsConfig()
83 config.numSigmaClip = 3.0
84 task = cpVerify.CpVerifyStatsTask(config=config)
85 results = task.run(self.inputExp, self.camera)
87 # Or the catalog stats
88 config.catalogStatKeywords = {'CAT_MEAN', 'MEDIAN'}
89 task = cpVerify.CpVerifyStatsTask(config=config)
90 results = task.run(self.inputExp, self.camera)
92 # Or the detector stats
93 config.catalogStatKeywords = {}
94 config.detectorStatKeywords = {'DET_SIGMA', 'STDEV'}
95 task = cpVerify.CpVerifyStatsTask(config=config)
96 results = task.run(self.inputExp, self.camera)
97 self.assertIsNone(results)
99 def test_generic(self):
100 """Test a subset of the output values to identify that the
101 image stat methods haven't changed.
102 """
103 config = cpVerify.CpVerifyStatsConfig()
104 config.imageStatKeywords = {'MEAN': 'MEAN', 'MEDIAN': 'MEDIAN', 'CLIPPED': 'MEANCLIP',
105 'SIGMA': 'STDEV'}
106 config.unmaskedImageStatKeywords = {'un_MEAN': 'MEAN', 'un_MEDIAN': 'MEDIAN',
107 'un_CLIPPED': 'MEANCLIP',
108 'un_SIGMA': 'STDEV'}
109 config.crImageStatKeywords = {'cr_MEAN': 'MEAN', 'cr_MEDIAN': 'MEDIAN', 'cr_CLIPPED': 'MEANCLIP',
110 'cr_SIGMA': 'STDEV'}
111 config.normImageStatKeywords = {'norm_MEAN': 'MEAN', 'norm_MEDIAN': 'MEDIAN',
112 'norm_CLIPPED': 'MEANCLIP',
113 'norm_SIGMA': 'STDEV'}
114 config.numSigmaClip = 3.0
115 task = ToySubClass(config=config)
117 results = task.run(self.inputExp, self.camera)
118 resultStats = results.outputStats
120 self.assertAlmostEqual(resultStats['AMP']['C:0,0']['MEAN'], 1506.06976, 4)
121 self.assertAlmostEqual(resultStats['AMP']['C:0,0']['un_MEAN'], 1501.0299, 4)
122 self.assertAlmostEqual(resultStats['AMP']['C:0,0']['norm_MEAN'], 301.213957, 4)
123 self.assertAlmostEqual(resultStats['AMP']['C:0,0']['cr_MEAN'], 1504.2776, 4)
125 self.assertTrue(resultStats['VERIFY']['A REAL TEST'])
126 self.assertFalse(resultStats['VERIFY']['A BAD TEST'])
128 self.assertTrue(resultStats['SUCCESS'])
131class VerifyBiasTestCase(lsst.utils.tests.TestCase):
132 """Unit test for stats code - bias cases."""
134 def setUp(self):
135 """Generate a mock exposure/camera to test."""
136 config = isrMock.IsrMockConfig()
137 config.isTrimmed = True
138 config.rngSeed = 12345
139 biasExposure = isrMock.BiasMock(config=config).run()
141 config.rngSeed = 54321
142 fakeBias = isrMock.BiasMock(config=config).run()
144 self.inputExp = biasExposure.clone()
145 mi = self.inputExp.getMaskedImage()
146 mi.scaledMinus(1.0, fakeBias.getMaskedImage())
147 updateMockExp(self.inputExp)
149 self.camera = isrMock.IsrMock().getCamera()
151 def test_bias(self):
152 """Test a subset of the output values to identify that the
153 image stat methods haven't changed.
154 """
155 config = cpVerify.CpVerifyBiasConfig()
156 config.numSigmaClip = 3.0
157 task = cpVerify.CpVerifyBiasTask(config=config)
158 results = task.run(self.inputExp, self.camera)
159 biasStats = results.outputStats
161 self.assertAlmostEqual(biasStats['AMP']['C:0,0']['MEAN'], 2.08672, 4)
162 self.assertAlmostEqual(biasStats['AMP']['C:0,0']['NOISE'], 13.99547, 4)
163 self.assertAlmostEqual(biasStats['AMP']['C:0,0']['CR_NOISE'], 14.11526, 4)
165 self.assertIn(biasStats['SUCCESS'], [True, False])
168class VerifyDarkTestCase(lsst.utils.tests.TestCase):
169 """Unit test for stats code - dark cases.
170 """
172 def setUp(self):
173 """Generate a mock exposure/camera to test."""
174 config = isrMock.IsrMockConfig()
175 config.isTrimmed = True
176 config.rngSeed = 12345
177 darkExposure = isrMock.DarkMock(config=config).run()
179 config.rngSeed = 54321
180 fakeDark = isrMock.DarkMock(config=config).run()
182 self.inputExp = darkExposure.clone()
183 mi = self.inputExp.getMaskedImage()
184 mi.scaledMinus(1.0, fakeDark.getMaskedImage())
185 updateMockExp(self.inputExp)
187 # Use this to test the metadataStats code, as this is the case
188 # it's designed to fix.
189 metadataContents = TaskMetadata()
190 metadataContents["RESIDUAL STDEV C:0,0"] = 12.0
191 metadataContents["RESIDUAL STDEV"] = 24.0
192 self.metadata = TaskMetadata()
193 self.metadata["subGroup"] = metadataContents
195 self.camera = isrMock.IsrMock().getCamera()
197 def test_dark(self):
198 """Test a subset of the output values to identify that the
199 image stat methods haven't changed.
200 """
201 config = cpVerify.CpVerifyDarkConfig()
202 config.numSigmaClip = 3.0
203 task = cpVerify.CpVerifyDarkTask(config=config)
204 results = task.run(self.inputExp, self.camera, taskMetadata=self.metadata)
205 darkStats = results.outputStats
207 self.assertAlmostEqual(darkStats['AMP']['C:0,0']['MEAN'], 2.0043, 4)
208 self.assertAlmostEqual(darkStats['AMP']['C:0,0']['NOISE'], 3.12948, 4)
209 self.assertAlmostEqual(darkStats['AMP']['C:0,0']['CR_NOISE'], 3.15946, 4)
211 self.assertIn(darkStats['SUCCESS'], [True, False])
214class VerifyDefectsTestCase(lsst.utils.tests.TestCase):
215 """Unit test for stats code - defect cases."""
217 defectFlux = 100000 # Flux to use for simulated defect.
219 def setUp(self):
220 """Generate a mock exposure/camera to test."""
221 config = isrMock.IsrMockConfig()
222 config.isTrimmed = True
223 config.doGenerateImage = True
224 config.doAddFringe = False
225 config.doAddSource = False
226 config.doAddSky = True
227 config.doAddOverscan = False
228 config.doAddCrosstalk = False
229 config.doAddBias = False
230 config.doAddDark = False
231 config.doAddFlat = False
232 config.doAddFringe = False
234 config.skyLevel = 1000
235 config.rngSeed = 12345
236 self.inputExp = isrMock.IsrMock(config=config).run()
238 # These are simulated defects
239 self.inputExp.getImage().getArray()[0, 0] = -1.0 * self.defectFlux
240 self.inputExp.getImage().getArray()[40, 50] = self.defectFlux
241 self.inputExp.getImage().getArray()[75, 50] = np.nan
243 updateMockExp(self.inputExp, addCR=False)
245 self.inputExp.getMask().getArray()[0, 0] = 1
246 self.inputExp.getMask().getArray()[40, 50] = 1
247 self.inputExp.getMask().getArray()[75, 50] = 1
249 self.camera = isrMock.IsrMock().getCamera()
251 def test_defects(self):
252 """Test a subset of the output values to identify that the
253 image stat methods haven't changed.
254 """
255 config = cpVerify.CpVerifyDefectsConfig()
256 config.numSigmaClip = 3.0
257 task = cpVerify.CpVerifyDefectsTask(config=config)
258 results = task.run(self.inputExp, self.camera)
259 defectStats = results.outputStats
261 self.assertEqual(defectStats['AMP']['C:0,0']['DEFECT_PIXELS'], 53)
262 self.assertEqual(defectStats['AMP']['C:0,0']['OUTLIERS'], 17)
263 self.assertEqual(defectStats['AMP']['C:0,0']['STAT_OUTLIERS'], 3)
264 self.assertAlmostEqual(defectStats['AMP']['C:0,0']['MEDIAN'], 999.466, 4)
265 self.assertAlmostEqual(defectStats['AMP']['C:0,0']['STDEV'], 30.96303, 4)
266 self.assertAlmostEqual(defectStats['AMP']['C:0,0']['MIN'], 881.56146, 4)
267 self.assertAlmostEqual(defectStats['AMP']['C:0,0']['MAX'], 1124.19934, 4)
269 self.assertEqual(defectStats['AMP']['C:0,0']['UNMASKED_MIN'], -1.0 * self.defectFlux, 4)
270 self.assertEqual(defectStats['AMP']['C:0,0']['UNMASKED_MAX'], self.defectFlux, 4)
272 self.assertIn(defectStats['SUCCESS'], [True, False])
275class MemoryTester(lsst.utils.tests.MemoryTestCase):
276 pass
279def setup_module(module):
280 lsst.utils.tests.init()
283if __name__ == "__main__": 283 ↛ 284line 283 didn't jump to line 284, because the condition on line 283 was never true
284 lsst.utils.tests.init()
285 unittest.main()