Coverage for python/lsst/ap/pipe/metrics.py: 46%

53 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-26 17:25 +0000

1# This file is part of ap_pipe. 

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

21# 

22 

23"""Metrics for ap_pipe tasks. 

24""" 

25 

26__all__ = [ 

27 "ApFakesCompletenessMetricTask", "ApFakesCompletenessMetricConfig", 

28 "ApFakesCountMetricTask", "ApFakesCountMetricConfig" 

29] 

30 

31import astropy.units as u 

32import numpy as np 

33 

34import lsst.pex.config as pexConfig 

35from lsst.pipe.base import Struct 

36import lsst.pipe.base.connectionTypes as connTypes 

37from lsst.pipe.tasks.insertFakes import InsertFakesConfig 

38from lsst.verify import Measurement 

39from lsst.verify.tasks import MetricTask, MetricComputationError 

40 

41 

42class ApFakesCompletenessMetricConnections( 

43 MetricTask.ConfigClass.ConnectionsClass, 

44 dimensions={"instrument", "visit", "detector", "band"}, 

45 defaultTemplates={"coaddName": "deep", 

46 "fakesType": "fakes_", 

47 "package": "ap_pipe", 

48 "metric": "apFakesCompleteness"}): 

49 """ApFakesCompleteness connections. 

50 """ 

51 matchedFakes = connTypes.Input( 

52 doc="Fakes matched to their detections in the difference image.", 

53 name="{fakesType}{coaddName}Diff_matchDiaSrc", 

54 storageClass="DataFrame", 

55 dimensions=("instrument", "visit", "detector"), 

56 ) 

57 

58 

59# Inherits from InsertFakesConfig to preserve column names in the fakes 

60# catalog. 

61class ApFakesCompletenessMetricConfig( 

62 MetricTask.ConfigClass, 

63 InsertFakesConfig, 

64 pipelineConnections=ApFakesCompletenessMetricConnections): 

65 """ApFakesCompleteness config. 

66 """ 

67 magMin = pexConfig.RangeField( 

68 doc="Minimum of cut on magnitude range used to compute completeness " 

69 "in.", 

70 dtype=float, 

71 default=20, 

72 min=1, 

73 max=40, 

74 ) 

75 magMax = pexConfig.RangeField( 

76 doc="Maximum of cut on magnitude range used to compute completeness " 

77 "in.", 

78 dtype=int, 

79 default=30, 

80 min=1, 

81 max=40, 

82 ) 

83 

84 

85class ApFakesCompletenessMetricTask(MetricTask): 

86 """Metric task for summarizing the completeness of fakes inserted into the 

87 AP pipeline. 

88 """ 

89 _DefaultName = "apFakesCompleteness" 

90 ConfigClass = ApFakesCompletenessMetricConfig 

91 

92 def runQuantum(self, butlerQC, inputRefs, outputRefs): 

93 try: 

94 inputs = butlerQC.get(inputRefs) 

95 inputs["band"] = butlerQC.quantum.dataId["band"] 

96 outputs = self.run(**inputs) 

97 if outputs.measurement is not None: 

98 butlerQC.put(outputs, outputRefs) 

99 else: 

100 self.log.debug("Skipping measurement of %r on %s " 

101 "as not applicable.", self, inputRefs) 

102 except MetricComputationError: 

103 # Apparently lsst.log doesn't have built-in exception support? 

104 self.log.error( 

105 "Measurement of %r failed on %s->%s", 

106 self, inputRefs, outputRefs, exc_info=True) 

107 

108 def run(self, matchedFakes, band): 

109 """Compute the completeness of recovered fakes within a magnitude 

110 range. 

111 

112 Parameters 

113 ---------- 

114 matchedFakes : `lsst.afw.table.SourceCatalog` or `None` 

115 Catalog of fakes that were inserted into the ccdExposure matched 

116 to their detected counterparts. 

117 band : `str` 

118 Single character name of the observed band for this quanta. 

119 

120 Returns 

121 ------- 

122 result : `lsst.pipe.base.Struct` 

123 A `~lsst.pipe.base.Struct` containing the following component: 

124 ``measurement`` 

125 the ratio (`lsst.verify.Measurement` or `None`) 

126 """ 

127 if matchedFakes is not None: 

128 magnitudes = np.fabs(matchedFakes[f"{self.config.mag_col}" % band]) 

129 magCutFakes = matchedFakes[np.logical_and(magnitudes > self.config.magMin, 

130 magnitudes < self.config.magMax)] 

131 if len(magCutFakes) <= 0.0: 

132 raise MetricComputationError( 

133 "No matched fakes catalog sources found; Completeness is " 

134 "ill defined.") 

135 else: 

136 meas = Measurement( 

137 self.config.metricName, 

138 ((magCutFakes["diaSourceId"] > 0).sum() / len(magCutFakes)) 

139 * u.dimensionless_unscaled) 

140 else: 

141 self.log.info("Nothing to do: no matched catalog found.") 

142 meas = None 

143 return Struct(measurement=meas) 

144 

145 

146class ApFakesCountMetricConnections( 

147 ApFakesCompletenessMetricConnections, 

148 dimensions={"instrument", "visit", "detector", "band"}, 

149 defaultTemplates={"coaddName": "deep", 

150 "fakesType": "fakes_", 

151 "package": "ap_pipe", 

152 "metric": "apFakesCompleteness"}): 

153 pass 

154 

155 

156class ApFakesCountMetricConfig( 

157 ApFakesCompletenessMetricConfig, 

158 pipelineConnections=ApFakesCountMetricConnections): 

159 """ApFakesCompleteness config. 

160 """ 

161 pass 

162 

163 

164class ApFakesCountMetricTask(ApFakesCompletenessMetricTask): 

165 """Metric task for summarizing the completeness of fakes inserted into the 

166 AP pipeline. 

167 """ 

168 _DefaultName = "apFakesCount" 

169 ConfigClass = ApFakesCountMetricConfig 

170 

171 def run(self, matchedFakes, band): 

172 """Compute the number of fakes inserted within a magnitude 

173 range. 

174 

175 Parameters 

176 ---------- 

177 matchedFakes : `lsst.afw.table.SourceCatalog` or `None` 

178 Catalog of fakes that were inserted into the ccdExposure matched 

179 to their detected counterparts. 

180 band : `str` 

181 Single character name of the observed band for this quanta. 

182 

183 Returns 

184 ------- 

185 result : `lsst.pipe.base.Struct` 

186 A `~lsst.pipe.base.Struct` containing the following component: 

187 ``measurement`` 

188 the ratio (`lsst.verify.Measurement` or `None`) 

189 """ 

190 if matchedFakes is not None: 

191 magnitudes = np.fabs(matchedFakes[f"{self.config.mag_col}" % band]) 

192 magCutFakes = matchedFakes[np.logical_and(magnitudes > self.config.magMin, 

193 magnitudes < self.config.magMax)] 

194 meas = Measurement(self.config.metricName, 

195 len(magCutFakes) * u.count) 

196 else: 

197 self.log.info("Nothing to do: no matched catalog supplied.") 

198 meas = None 

199 return Struct(measurement=meas)