Coverage for python/lsst/analysis/tools/analysisMetrics/diffMatchedMetrics.py: 29%

77 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-16 01:27 -0800

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__ = ("MatchedRefCoaddMetric", "MatchedRefCoaddCModelFluxMetric", "MatchedRefCoaddPositionMetric") 

24 

25from typing import Optional 

26 

27import lsst.pex.config as pexConfig 

28 

29from ..actions.vector.calcBinnedStats import CalcBinnedStatsAction 

30from ..actions.vector.selectors import RangeSelector 

31from ..analysisParts.diffMatched import ( 

32 MatchedRefCoaddDiffMagTool, 

33 MatchedRefCoaddDiffPositionTool, 

34 MatchedRefCoaddTool, 

35) 

36from ..interfaces import AnalysisMetric, KeyedData 

37 

38 

39class MatchedRefCoaddMetric(MatchedRefCoaddTool, AnalysisMetric): 

40 """Base tool for matched-to-reference metrics on coadds.""" 

41 

42 mag_low_min: int = 15 

43 mag_low_max: int = 27 

44 mag_interval: int = 1 

45 

46 name_prefix = pexConfig.Field[str](default=None, doc="Prefix for metric key") 

47 

48 names = ("stars", "galaxies", "all") 

49 types = ("unresolved", "resolved", "all") 

50 

51 unit = pexConfig.Field[str](default=None, doc="Astropy unit of y-axis values") 

52 

53 def _validate(self): 

54 if self.name_prefix is None or self.unit is None: 

55 raise ValueError( 

56 f"{self.name_prefix=} and {self.unit=} must not be None;" 

57 f" did you forget to set a valid context?" 

58 ) 

59 

60 def configureMetrics( 

61 self, 

62 unit: Optional[str] = None, 

63 name_prefix: Optional[str] = None, 

64 name_suffix: str = "_mad_ref_mag{minimum}", 

65 unit_select: str = "mag", 

66 ): 

67 """Configure metric actions and return units. 

68 

69 Parameters 

70 ---------- 

71 unit : `str` 

72 The (astropy) unit of the summary statistic metrics. 

73 name_prefix : `str` 

74 The prefix for the action (column) name. 

75 name_suffix : `str` 

76 The sufffix for the action (column) name. 

77 unit_select : `str` 

78 The (astropy) unit of the selection (x-axis) column. Default "mag". 

79 

80 Returns 

81 ------- 

82 units : `dict` [`str`, `str`] 

83 A dict of the unit (value) for each metric name (key) 

84 """ 

85 unit_is_none = unit is None 

86 name_prefix_is_none = name_prefix is None 

87 

88 if unit_is_none or name_prefix_is_none: 

89 if unit_is_none: 

90 unit = self.unit 

91 if name_prefix_is_none: 

92 name_prefix = self.name_prefix 

93 self._validate() 

94 if unit_select is None: 

95 unit_select = "mag" 

96 

97 assert name_prefix is not None 

98 units = {} 

99 for name, name_class in zip(self.names, self.types): 

100 name_capital = name.capitalize() 

101 x_key = f"x{name_capital}" 

102 

103 for minimum in range(self.mag_low_min, self.mag_low_max + 1): 

104 action = getattr(self.process.calculateActions, f"{name}{minimum}") 

105 action.selector_range = RangeSelector( 

106 key=x_key, 

107 minimum=minimum, 

108 maximum=minimum + self.mag_interval, 

109 ) 

110 

111 action.name_prefix = name_prefix.format(name_class=name_class) 

112 action.name_suffix = name_suffix.format(minimum=minimum) 

113 

114 units.update( 

115 { 

116 action.name_median: unit, 

117 action.name_sigmaMad: unit, 

118 action.name_count: "count", 

119 action.name_select_minimum: unit_select, 

120 action.name_select_median: unit_select, 

121 action.name_select_maximum: unit_select, 

122 } 

123 ) 

124 return units 

125 

126 def setDefaults(self): 

127 super().setDefaults() 

128 

129 for name in self.names: 

130 name_capital = name.capitalize() 

131 for minimum in range(self.mag_low_min, self.mag_low_max + 1): 

132 setattr( 

133 self.process.calculateActions, 

134 f"{name}{minimum}", 

135 CalcBinnedStatsAction(key_vector=f"y{name_capital}"), 

136 ) 

137 

138 def __call__(self, data: KeyedData, **kwargs): 

139 self._validate() 

140 return super().__call__(data=data, **kwargs) 

141 

142 

143# The diamond inheritance on MatchedRefCoaddTool seems ok 

144class MatchedRefCoaddCModelFluxMetric(MatchedRefCoaddDiffMagTool, MatchedRefCoaddMetric): 

145 """Metric for diffs between reference and CModel coadd mags.""" 

146 

147 def matchedRefDiffContext(self): 

148 super().matchedRefDiffContext() 

149 self.unit = "mmag" 

150 self.name_prefix = "photom_mag_cModelFlux_{name_class}_diff_" 

151 self.produce.units = self.configureMetrics() 

152 

153 def matchedRefChiContext(self): 

154 super().matchedRefChiContext() 

155 self.unit = "" 

156 self.name_prefix = "photom_mag_cModelFlux_{name_class}_chi_" 

157 self.produce.units = self.configureMetrics() 

158 

159 def setDefaults(self): 

160 super().setDefaults() 

161 

162 

163class MatchedRefCoaddPositionMetric(MatchedRefCoaddDiffPositionTool, MatchedRefCoaddMetric): 

164 """Metric for diffs between reference and base coadd centroids.""" 

165 

166 def matchedRefDiffContext(self): 

167 super().matchedRefDiffContext() 

168 self.unit = "pix" 

169 self.name_prefix = f"astrom_{self.variable}_{{name_class}}_diff_" 

170 self.produce.units = self.configureMetrics() 

171 

172 def matchedRefChiContext(self): 

173 super().matchedRefChiContext() 

174 self.unit = "" 

175 self.name_prefix = f"astrom_{self.variable}_{{name_class}}_diff_" 

176 self.produce.units = self.configureMetrics() 

177 

178 def setDefaults(self): 

179 super().setDefaults()