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

56 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-05 12:27 +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# (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): 

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 

62 Returns 

63 ------- 

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

65 A dictionary of the statistics measured and their values. 

66 

67 """ 

68 outputStatistics = {} 

69 

70 ampStats = statisticsDict['AMP'] 

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

72 

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

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

75 

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

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

78 

79 return outputStatistics 

80 

81 def verify(self, exposure, statisticsDict): 

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

83 

84 Parameters 

85 ---------- 

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

87 The exposure the statistics are from. 

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

89 Dictionary of measured statistics. The inner dictionary 

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

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

92 the mostly likely types). 

93 

94 Returns 

95 ------- 

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

97 A dictionary indexed by the amplifier name, containing 

98 dictionaries of the verification criteria. 

99 success : `bool` 

100 A boolean indicating if all tests have passed. 

101 """ 

102 ampStats = statisticsDict['AMP'] 

103 verifyStats = {} 

104 success = True 

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

106 verify = {} 

107 

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

109 # consistent with Poissonian 

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

111 

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

113 if verify['SUCCESS'] is False: 

114 success = False 

115 

116 verifyStats[ampName] = verify 

117 

118 verifyDet = {} 

119 detStats = statisticsDict['DET'] 

120 

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

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

123 

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

125 if verifyDet['SUCCESS'] is False: 

126 success = False 

127 

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

129 

130 

131class CpVerifyFlatExpMergeConfig(CpVerifyExpMergeConfig): 

132 """Inherits from base CpVerifyExpMergeConfig 

133 """ 

134 

135 def setDefaults(self): 

136 super().setDefaults() 

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

138 } 

139 

140 

141class CpVerifyFlatExpMergeTask(CpVerifyExpMergeTask): 

142 """Inherits from base CpVerifyExpMergeTask 

143 """ 

144 

145 def exposureStatistics(self, statisticsDictionary): 

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

147 per-amplifier and per-detector measurements. 

148 

149 Parameters 

150 ---------- 

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

152 Dictionary of measured statistics. The top level 

153 dictionary is keyed on the detector names, and contains 

154 the measured statistics from the per-detector 

155 measurements. 

156 

157 Returns 

158 ------- 

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

160 A dictionary of the statistics measured and their values. 

161 """ 

162 detectorMeans = [] 

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

164 # Get detector stats: 

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

166 

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

168 

169 def verify(self, detectorStatistics, statisticsDictionary): 

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

171 

172 Parameters 

173 ---------- 

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

175 Merged set of input detector level statistics. 

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

177 Dictionary of measured statistics. The inner dictionary 

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

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

180 the mostly likely types). 

181 

182 Returns 

183 ------- 

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

185 A dictionary indexed by the amplifier name, containing 

186 dictionaries of the verification criteria. 

187 success : `bool` 

188 A boolean indicating if all tests have passed. 

189 

190 """ 

191 verifyStats = {} 

192 success = True 

193 

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

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

196 

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

198 

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