Coverage for python / lsst / analysis / tools / atools / coaddInputCount.py: 22%

85 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-22 09:08 +0000

1# This file is part of analysis_tools. 

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

21from __future__ import annotations 

22 

23__all__ = ("CoaddInputCount", "CoaddQualityCheck", "CoaddQualityPlot") 

24 

25from lsst.pex.config import ListField 

26 

27from ..actions.plot.calculateRange import MinMax 

28from ..actions.plot.coaddDepthPlot import CoaddDepthPlot 

29from ..actions.plot.skyPlot import SkyPlot 

30from ..actions.scalar.scalarActions import MeanAction, MedianAction, SigmaMadAction, StdevAction 

31from ..actions.vector import BandSelector, CoaddPlotFlagSelector, DownselectVector, LoadVector, SnSelector 

32from ..interfaces import AnalysisTool 

33 

34 

35class CoaddInputCount(AnalysisTool): 

36 """Tract-wide metrics pertaining to how many exposures have gone into 

37 a deep coadd, per band. 

38 

39 This AnalysisTool is designed to run on an object table, which is only 

40 created for deep coadds, not template coadds. 

41 """ 

42 

43 def setDefaults(self): 

44 super().setDefaults() 

45 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

46 # Set this to an empty list to look at the band 

47 # the plot is being made in. 

48 self.prep.selectors.flagSelector.bands = [] 

49 

50 self.prep.selectors.snSelector = SnSelector() 

51 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux" 

52 self.prep.selectors.snSelector.threshold = 5 

53 

54 self.process.buildActions.x = LoadVector() 

55 self.process.buildActions.x.vectorKey = "coord_ra" 

56 self.process.buildActions.y = LoadVector() 

57 self.process.buildActions.y.vectorKey = "coord_dec" 

58 self.process.buildActions.statMask = SnSelector() 

59 self.process.buildActions.statMask.fluxType = "{band}_psfFlux" 

60 self.process.buildActions.statMask.threshold = 5 

61 

62 self.process.buildActions.z = LoadVector() 

63 self.process.buildActions.z.vectorKey = "{band}_inputCount" 

64 

65 self.process.buildActions.patch = LoadVector() 

66 self.process.buildActions.patch.vectorKey = "patch" 

67 

68 self.process.calculateActions.median = MedianAction() 

69 self.process.calculateActions.median.vectorKey = "z" 

70 

71 self.process.calculateActions.mean = MeanAction() 

72 self.process.calculateActions.mean.vectorKey = "z" 

73 

74 self.process.calculateActions.sigmaMad = SigmaMadAction() 

75 self.process.calculateActions.sigmaMad.vectorKey = "z" 

76 

77 # SkyPlot of number of contributing exposures in coad, per tract/band: 

78 self.produce.plot = SkyPlot() 

79 self.produce.plot.plotTypes = ["any"] 

80 self.produce.plot.plotName = "{band}_inputCount" 

81 self.produce.plot.xAxisLabel = "R.A. (deg)" 

82 self.produce.plot.yAxisLabel = "Dec. (deg)" 

83 self.produce.plot.zAxisLabel = "Input Count" 

84 self.produce.plot.plotOutlines = True 

85 self.produce.plot.showExtremeOutliers = False 

86 self.produce.plot.colorbarRange = MinMax() 

87 

88 # Summary metrics for the whole coadd, per tract/band. 

89 self.produce.metric.units = {"median": "ct", "sigmaMad": "ct", "mean": "ct"} 

90 self.produce.metric.newNames = { 

91 "median": "{band}_inputCount_median", 

92 "mean": "{band}_inputCount_mean", 

93 "sigmaMad": "{band}_inputCount_sigmaMad", 

94 } 

95 

96 

97class CoaddQualityCheck(AnalysisTool): 

98 """Compute the percentage of each coadd that has a number of input 

99 exposures exceeding a threshold. 

100 

101 This AnalysisTool is designed to run on any coadd, provided a 

102 coadd_depth_table is created first (via CoaddDepthSummaryAnalysisTask). 

103 

104 For example, if exactly half of a coadd patch contains 15 overlapping 

105 constituent visits and half contains fewer, the value computed for 

106 `depth_above_threshold_12` would be 50. 

107 

108 These values come from the n_image data product, which is an image 

109 identical to the coadd but with pixel values of the number of input 

110 images instead of flux or counts. n_images are persisted during 

111 coadd assembly. 

112 """ 

113 

114 band_list = ListField( 

115 default=["u", "g", "r", "i", "z", "y"], 

116 dtype=str, 

117 doc="Bands for colors.", 

118 ) 

119 

120 threshold_list = ListField( 

121 default=[1, 3, 5, 12], 

122 dtype=int, 

123 doc="The n_image pixel value thresholds.", 

124 ) 

125 

126 quantile_list = ListField( 

127 default=[5, 10, 25, 50, 75, 90, 95], 

128 dtype=int, 

129 doc="The percentiles at which to compute n_image values, in ascending order.", 

130 ) 

131 

132 def setDefaults(self): 

133 super().setDefaults() 

134 

135 self.process.buildActions.patch = LoadVector(vectorKey="patch") 

136 self.process.buildActions.band = LoadVector(vectorKey="band") 

137 

138 def finalize(self): 

139 for threshold in self.threshold_list: 

140 # This gives a RuntimeWarning whenever the tract doesn't have 

141 # a particular band. Need to use a band list derived from the 

142 # bands found in the "band" column of a given tract. 

143 for band in self.band_list: 

144 name = f"depth_above_threshold_{threshold}" 

145 setattr(self.process.buildActions, name, LoadVector(vectorKey=name)) 

146 setattr( 

147 self.process.filterActions, 

148 f"{name}_{band}", 

149 DownselectVector(vectorKey=name, selector=BandSelector(bands=[band])), 

150 ) 

151 setattr( 

152 self.process.calculateActions, 

153 f"{name}_{band}_median", 

154 MedianAction(vectorKey=f"{name}_{band}"), 

155 ) 

156 setattr( 

157 self.process.calculateActions, 

158 f"{name}_{band}_mean", 

159 MeanAction(vectorKey=f"{name}_{band}"), 

160 ) 

161 setattr( 

162 self.process.calculateActions, 

163 f"{name}_{band}_stdev", 

164 StdevAction(vectorKey=f"{name}_{band}"), 

165 ) 

166 

167 # The units for the quantity are dimensionless (percentage) 

168 self.produce.metric.units[f"{name}_{band}_median"] = "" 

169 self.produce.metric.units[f"{name}_{band}_mean"] = "" 

170 self.produce.metric.units[f"{name}_{band}_stdev"] = "" 

171 

172 for quantile in self.quantile_list: 

173 for band in self.band_list: 

174 name = f"depth_{quantile}_percentile" 

175 setattr(self.process.buildActions, name, LoadVector(vectorKey=name)) 

176 setattr( 

177 self.process.filterActions, 

178 f"{name}_{band}", 

179 DownselectVector(vectorKey=name, selector=BandSelector(bands=[band])), 

180 ) 

181 setattr( 

182 self.process.calculateActions, 

183 f"{name}_{band}_median", 

184 MedianAction(vectorKey=f"{name}_{band}"), 

185 ) 

186 setattr( 

187 self.process.calculateActions, 

188 f"{name}_{band}_mean", 

189 MeanAction(vectorKey=f"{name}_{band}"), 

190 ) 

191 setattr( 

192 self.process.calculateActions, 

193 f"{name}_{band}_stdev", 

194 StdevAction(vectorKey=f"{name}_{band}"), 

195 ) 

196 

197 # The units for the quantity are dimensionless (percentage) 

198 self.produce.metric.units[f"{name}_{band}_median"] = "" 

199 self.produce.metric.units[f"{name}_{band}_mean"] = "" 

200 self.produce.metric.units[f"{name}_{band}_stdev"] = "" 

201 

202 

203class CoaddQualityPlot(AnalysisTool): 

204 """Make a plot of coadd depth.""" 

205 

206 parameterizedBand: bool = False 

207 

208 def setDefaults(self): 

209 super().setDefaults() 

210 self.process.buildActions.patch = LoadVector(vectorKey="patch") 

211 self.process.buildActions.band = LoadVector(vectorKey="band") 

212 self.process.buildActions.depth = LoadVector(vectorKey="depth") 

213 self.process.buildActions.pixels = LoadVector(vectorKey="pixels") 

214 

215 self.produce.plot = CoaddDepthPlot()