Coverage for tests/test_verifyStats.py: 18%

156 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-10-28 11:53 +0000

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/>. 

21 

22import numpy as np 

23import unittest 

24 

25import lsst.utils.tests 

26import lsst.ip.isr.isrMock as isrMock 

27import lsst.cp.verify as cpVerify 

28import lsst.ip.isr.isrFunctions as isrFunctions 

29 

30from lsst.pipe.base import TaskMetadata 

31 

32 

33def updateMockExp(exposure, addCR=True): 

34 """Update an exposure with a mask and variance plane. 

35 

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 

47 

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) 

52 

53 

54class ToySubClass(cpVerify.CpVerifyStatsTask): 

55 """The CpVerifyStatsTask requires an implentation of verify. 

56 """ 

57 

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 

62 

63 return verifiedStats, successValue 

64 

65 

66class VerifyStatsTestCase(lsst.utils.tests.TestCase): 

67 """Unit test for stats code. 

68 """ 

69 

70 def setUp(self): 

71 """Generate a mock exposure/camera to test.""" 

72 self.inputExp = isrMock.CalibratedRawMock().run() 

73 self.camera = isrMock.IsrMock().getCamera() 

74 

75 updateMockExp(self.inputExp) 

76 

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) 

86 

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) 

91 

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) 

98 

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) 

116 

117 results = task.run(self.inputExp, self.camera) 

118 resultStats = results.outputStats 

119 

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) 

124 

125 self.assertTrue(resultStats['VERIFY']['A REAL TEST']) 

126 self.assertFalse(resultStats['VERIFY']['A BAD TEST']) 

127 

128 self.assertTrue(resultStats['SUCCESS']) 

129 

130 

131class VerifyBiasTestCase(lsst.utils.tests.TestCase): 

132 """Unit test for stats code - bias cases.""" 

133 

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

140 

141 config.rngSeed = 54321 

142 fakeBias = isrMock.BiasMock(config=config).run() 

143 

144 self.inputExp = biasExposure.clone() 

145 mi = self.inputExp.getMaskedImage() 

146 mi.scaledMinus(1.0, fakeBias.getMaskedImage()) 

147 updateMockExp(self.inputExp) 

148 

149 self.camera = isrMock.IsrMock().getCamera() 

150 

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 

160 

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) 

164 

165 self.assertIn(biasStats['SUCCESS'], [True, False]) 

166 

167 

168class VerifyDarkTestCase(lsst.utils.tests.TestCase): 

169 """Unit test for stats code - dark cases. 

170 """ 

171 

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

178 

179 config.rngSeed = 54321 

180 fakeDark = isrMock.DarkMock(config=config).run() 

181 

182 self.inputExp = darkExposure.clone() 

183 mi = self.inputExp.getMaskedImage() 

184 mi.scaledMinus(1.0, fakeDark.getMaskedImage()) 

185 updateMockExp(self.inputExp) 

186 

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 

194 

195 self.camera = isrMock.IsrMock().getCamera() 

196 

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 

206 

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) 

210 

211 self.assertIn(darkStats['SUCCESS'], [True, False]) 

212 

213 

214class VerifyDefectsTestCase(lsst.utils.tests.TestCase): 

215 """Unit test for stats code - defect cases.""" 

216 

217 defectFlux = 100000 # Flux to use for simulated defect. 

218 

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 

233 

234 config.skyLevel = 1000 

235 config.rngSeed = 12345 

236 self.inputExp = isrMock.IsrMock(config=config).run() 

237 

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 

242 

243 updateMockExp(self.inputExp, addCR=False) 

244 

245 self.inputExp.getMask().getArray()[0, 0] = 1 

246 self.inputExp.getMask().getArray()[40, 50] = 1 

247 self.inputExp.getMask().getArray()[75, 50] = 1 

248 

249 self.camera = isrMock.IsrMock().getCamera() 

250 

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 

260 

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) 

268 

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) 

271 

272 self.assertIn(defectStats['SUCCESS'], [True, False]) 

273 

274 

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

276 pass 

277 

278 

279def setup_module(module): 

280 lsst.utils.tests.init() 

281 

282 

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