Coverage for python/lsst/cp/verify/verifyFlat.py: 25%

56 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 04:02 -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 lsst.afw.math as afwMath 

23from .verifyStats import CpVerifyStatsConfig, CpVerifyStatsTask, CpVerifyStatsConnections 

24from .mergeResults import CpVerifyExpMergeConfig, CpVerifyExpMergeTask 

25 

26__all__ = ['CpVerifyFlatConfig', 'CpVerifyFlatTask', 

27 'CpVerifyFlatExpMergeConfig', 'CpVerifyFlatExpMergeTask'] 

28# 'CpVerifyFlatRunMergeConfig', 'CpVerifyFlatRunMergeTask',] 

29 

30 

31class CpVerifyFlatConfig(CpVerifyStatsConfig, 

32 pipelineConnections=CpVerifyStatsConnections): 

33 """Inherits from base CpVerifyStatsConfig. 

34 """ 

35 

36 def setDefaults(self): 

37 super().setDefaults() 

38 self.imageStatKeywords = {'MEAN': 'MEAN', # noqa F841 

39 'NOISE': 'STDEVCLIP', } 

40 self.detectorStatKeywords = {'MEAN': 'MEAN', # noqa F841 

41 'SCATTER': 'STDEV', } 

42 

43 

44class CpVerifyFlatTask(CpVerifyStatsTask): 

45 """Flat verification sub-class, implementing the verify method. 

46 """ 

47 ConfigClass = CpVerifyFlatConfig 

48 _DefaultName = 'cpVerifyFlat' 

49 

50 def detectorStatistics(self, statisticsDict, statControl, exposure=None, uncorrectedExposure=None): 

51 """Calculate detector level statistics based on the existing 

52 per-amplifier measurements. 

53 

54 Parameters 

55 ---------- 

56 statisticsDict : `dict` [`str`, `dict` [`str`, scalar]], 

57 Dictionary of measured statistics. The inner dictionary 

58 should have keys that are statistic names (`str`) with 

59 values that are some sort of scalar (`int` or `float` are 

60 the mostly likely types). 

61 statControl : `lsst.afw.math.StatControl` 

62 Statistics control object with parameters defined by 

63 the config. 

64 exposure : `lsst.afw.image.Exposure`, optional 

65 Exposure containing the ISR-processed data to measure. 

66 uncorrectedExposure : `lsst.afw.image.Exposure`, optional 

67 uncorrected esposure (no defects) containing the 

68 ISR-processed data to measure. 

69 

70 Returns 

71 ------- 

72 outputStatistics : `dict` [`str`, scalar] 

73 A dictionary of the statistics measured and their values. 

74 

75 """ 

76 outputStatistics = {} 

77 

78 ampStats = statisticsDict['AMP'] 

79 amplifierMeans = [stats['MEAN'] for stats in ampStats.values()] 

80 

81 statisticToRun, statAccessor = self._configHelper(self.config.detectorStatKeywords) 

82 stats = afwMath.makeStatistics(amplifierMeans, statisticToRun, statControl) 

83 

84 for k, v in statAccessor.items(): 

85 outputStatistics[k] = stats.getValue(v) 

86 

87 return outputStatistics 

88 

89 def verify(self, exposure, statisticsDict): 

90 """Verify that the measured statistics meet the verification criteria. 

91 

92 Parameters 

93 ---------- 

94 exposure : `lsst.afw.image.Exposure` 

95 The exposure the statistics are from. 

96 statisticsDict : `dict` [`str`, `dict` [`str`, scalar]], 

97 Dictionary of measured statistics. The inner dictionary 

98 should have keys that are statistic names (`str`) with 

99 values that are some sort of scalar (`int` or `float` are 

100 the mostly likely types). 

101 

102 Returns 

103 ------- 

104 outputStatistics : `dict` [`str`, `dict` [`str`, `bool`]] 

105 A dictionary indexed by the amplifier name, containing 

106 dictionaries of the verification criteria. 

107 success : `bool` 

108 A boolean indicating if all tests have passed. 

109 """ 

110 ampStats = statisticsDict['AMP'] 

111 verifyStats = {} 

112 success = True 

113 for ampName, stats in ampStats.items(): 

114 verify = {} 

115 

116 # DMTN-101 Test 10.X: confirm that per-amplifier scatter is 

117 # consistent with Poissonian 

118 verify['NOISE'] = bool(stats['NOISE'] <= np.sqrt(stats['MEAN'])) 

119 

120 verify['SUCCESS'] = bool(np.all(list(verify.values()))) 

121 if verify['SUCCESS'] is False: 

122 success = False 

123 

124 verifyStats[ampName] = verify 

125 

126 verifyDet = {} 

127 detStats = statisticsDict['DET'] 

128 

129 # DMTN-101 Test 10.Y: confirm intra-chip scatter is small. 

130 verifyDet['SCATTER'] = bool(detStats['SCATTER']/detStats['MEAN'] <= 0.05) 

131 

132 verifyDet['SUCCESS'] = bool(np.all(list(verifyDet.values()))) 

133 if verifyDet['SUCCESS'] is False: 

134 success = False 

135 

136 return {'AMP': verifyStats, 'DET': verifyDet}, bool(success) 

137 

138 

139class CpVerifyFlatExpMergeConfig(CpVerifyExpMergeConfig): 

140 """Inherits from base CpVerifyExpMergeConfig 

141 """ 

142 

143 def setDefaults(self): 

144 super().setDefaults() 

145 self.exposureStatKeywords = {'EXPOSURE_SCATTER': 'STDEV', # noqa F841 

146 } 

147 

148 

149class CpVerifyFlatExpMergeTask(CpVerifyExpMergeTask): 

150 """Inherits from base CpVerifyExpMergeTask 

151 """ 

152 

153 def exposureStatistics(self, statisticsDictionary): 

154 """Calculate exposure level statistics based on the existing 

155 per-amplifier and per-detector measurements. 

156 

157 Parameters 

158 ---------- 

159 statisticsDictionary : `dict [`str`, `dict` [`str`, scalar]], 

160 Dictionary of measured statistics. The top level 

161 dictionary is keyed on the detector names, and contains 

162 the measured statistics from the per-detector 

163 measurements. 

164 

165 Returns 

166 ------- 

167 outputStatistics : `dict` [`str, scalar] 

168 A dictionary of the statistics measured and their values. 

169 """ 

170 detectorMeans = [] 

171 for detName, stats in statisticsDictionary.items(): 

172 # Get detector stats: 

173 detectorMeans.append(stats['DET']['MEAN']) 

174 

175 return {'SCATTER': np.stdev(detectorMeans)} 

176 

177 def verify(self, detectorStatistics, statisticsDictionary): 

178 """Verify if the measured statistics meet the verification criteria. 

179 

180 Parameters 

181 ---------- 

182 detectorStatistics : `dict` [`str`, `dict` [`str`, scalar]] 

183 Merged set of input detector level statistics. 

184 statisticsDictionary : `dict` [`str`, `dict` [`str`, scalar]], 

185 Dictionary of measured statistics. The inner dictionary 

186 should have keys that are statistic names (`str`) with 

187 values that are some sort of scalar (`int` or `float` are 

188 the mostly likely types). 

189 

190 Returns 

191 ------- 

192 outputStatistics : `dict` [`str`, `dict` [`str`, `bool`]] 

193 A dictionary indexed by the amplifier name, containing 

194 dictionaries of the verification criteria. 

195 success : `bool` 

196 A boolean indicating if all tests have passed. 

197 

198 """ 

199 verifyStats = {} 

200 success = True 

201 

202 # DMTN-101 Test 10.Z: confirm inter-chip scatter is small. 

203 verifyStats['SCATTER'] = bool(statisticsDictionary['EXP']['SCATTER'] <= 0.05) 

204 

205 success = bool(np.all(list(verifyStats.values()))) 

206 

207 return {'EXP': verifyStats}, bool(success)