Coverage for python/lsst/cp/verify/verifyDefects.py: 23%
42 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-18 03:25 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-18 03:25 -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# (http://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 <http://www.gnu.org/licenses/>.
21import numpy as np
22import scipy.stats
24from .verifyStats import CpVerifyStatsConfig, CpVerifyStatsTask, CpVerifyStatsConnections
27__all__ = ['CpVerifyDefectsConfig', 'CpVerifyDefectsTask']
30class CpVerifyDefectsConfig(CpVerifyStatsConfig,
31 pipelineConnections=CpVerifyStatsConnections):
32 """Inherits from base CpVerifyStatsConfig.
33 """
35 def setDefaults(self):
36 super().setDefaults()
37 self.maskNameList = ['BAD'] # noqa F821
39 self.imageStatKeywords = {'DEFECT_PIXELS': 'NMASKED', # noqa F821
40 'OUTLIERS': 'NCLIPPED',
41 'MEDIAN': 'MEDIAN',
42 'STDEV': 'STDEVCLIP',
43 'MIN': 'MIN',
44 'MAX': 'MAX', }
45 self.unmaskedImageStatKeywords = {'UNMASKED_MIN': 'MIN', # noqa F821
46 'UNMASKED_MAX': 'MAX',
47 'UNMASKED_STDEV': 'STDEVCLIP',
48 'UNMASKED_OUTLIERS': 'NCLIPPED', }
51class CpVerifyDefectsTask(CpVerifyStatsTask):
52 """Defects verification sub-class, implementing the verify method.
54 This also applies additional image processing statistics.
55 """
56 ConfigClass = CpVerifyDefectsConfig
57 _DefaultName = 'cpVerifyDefects'
59 def imageStatistics(self, exposure, statControl):
60 """Measure additional defect statistics.
62 This calls the parent class method first, then adds additional
63 measurements.
65 Parameters
66 ----------
67 exposure : `lsst.afw.image.Exposure`
68 Exposure containing the ISR processed data to measure.
69 statControl : `lsst.afw.math.StatControl`
70 Statistics control object with parameters defined by
71 the config.
73 Returns
74 -------
75 outputStatistics : `dict` [`str`, `dict` [`str`, scalar]]
76 A dictionary indexed by the amplifier name, containing
77 dictionaries of the statistics measured and their values.
78 """
79 outputStatistics = super().imageStatistics(exposure, statControl)
81 # Is this a useful test? It saves having to do chi^2 fits,
82 # which are going to be biased by the bulk of points.
83 for amp in exposure.getDetector():
84 ampName = amp.getName()
85 ampExp = exposure.Factory(exposure, amp.getBBox())
87 normImage = ampExp.getImage()
88 normArray = normImage.getArray()
90 normArray -= outputStatistics[ampName]['MEDIAN']
91 normArray /= outputStatistics[ampName]['STDEV']
93 probability = scipy.stats.norm.pdf(normArray)
94 outliers = np.where(probability < 1.0 / probability.size, 1.0, 0.0)
95 outputStatistics[ampName]['STAT_OUTLIERS'] = int(np.sum(outliers))
97 return outputStatistics
99 def verify(self, exposure, statisticsDict):
100 """Verify that the measured statistics meet the verification criteria.
102 Parameters
103 ----------
104 exposure : `lsst.afw.image.Exposure`
105 The exposure the statistics are from.
106 statisticsDictionary : `dict` [`str`, `dict` [`str`, scalar]],
107 Dictionary of measured statistics. The inner dictionary
108 should have keys that are statistic names (`str`) with
109 values that are some sort of scalar (`int` or `float` are
110 the mostly likely types).
112 Returns
113 -------
114 outputStatistics : `dict` [`str`, `dict` [`str`, `bool`]]
115 A dictionary indexed by the amplifier name, containing
116 dictionaries of the verification criteria.
117 success : `bool`
118 A boolean indicating if all tests have passed.
119 """
120 ampStats = statisticsDict['AMP']
121 verifyStats = {}
122 success = True
123 for ampName, stats in ampStats.items():
124 verify = {}
126 # These are not defined in DMTN-101 yet.
127 verify['OUTLIERS'] = bool(stats['UNMASKED_OUTLIERS'] >= stats['OUTLIERS'])
128 verify['STDEV'] = bool(stats['UNMASKED_STDEV'] >= stats['STDEV'])
129 verify['MIN'] = bool(stats['UNMASKED_MIN'] <= stats['MIN'])
130 verify['MAX'] = bool(stats['UNMASKED_MAX'] >= stats['MAX'])
132 # This test is bad, and should be made not bad.
133 verify['PROB_TEST'] = bool(stats['STAT_OUTLIERS'] == stats['DEFECT_PIXELS'])
135 verify['SUCCESS'] = bool(np.all(list(verify.values())))
136 if verify['SUCCESS'] is False:
137 success = False
139 verifyStats[ampName] = verify
141 return {'AMP': verifyStats}, bool(success)