Coverage for python / lsst / meas / extensions / multiprofit / pipetasks_match.py: 0%

97 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-21 10:56 +0000

1# This file is part of meas_extensions_multiprofit. 

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

21 

22__all__ = ( 

23 "MultiProFitMatchTractCatalogConfig", 

24 "MultiProFitMatchTractCatalogDC2Config", 

25 "MultiProFitMatchTractCatalogDC2Task", 

26) 

27 

28from lsst.pipe.tasks.diff_matched_tract_catalog import ( 

29 DiffMatchedTractCatalogConfig, 

30 DiffMatchedTractCatalogConnections, 

31 DiffMatchedTractCatalogTask, 

32) 

33from lsst.pipe.tasks.match_tract_catalog import ( 

34 MatchTractCatalogConfig, 

35 MatchTractCatalogConnections, 

36 MatchTractCatalogTask, 

37) 

38from lsst.pipe.tasks.match_tract_catalog_probabilistic import MatchTractCatalogProbabilisticTask 

39 

40 

41class MultiProFitMatchTractCatalogConfig( 

42 MatchTractCatalogConfig, 

43 pipelineConnections=MatchTractCatalogConnections, 

44): 

45 """Generic MultiProFit reference source match task config.""" 

46 

47 def setDefaults(self): 

48 self.connections.name_input_cat_target = "objectTable_tract_multiprofit" 

49 self.match_tract_catalog.retarget(MatchTractCatalogProbabilisticTask) 

50 

51 self.match_tract_catalog.columns_ref_copy = ["id", "truth_type"] 

52 self.match_tract_catalog.columns_target_copy = ["objectId"] 

53 # Must be set since there's no default - subclasses should add to this 

54 self.match_tract_catalog.columns_ref_meas = ["ra", "dec"] 

55 # Subclasses must format these 

56 columns_meas = ["{model_prefix}_cen_ra", "{model_prefix}_cen_dec"] 

57 self.match_tract_catalog.columns_target_meas = columns_meas 

58 self.match_tract_catalog.columns_target_err = [f"{col}_err" for col in columns_meas] 

59 # Override detect_isPrimary default because MultiProFit doesn't fit 

60 # non-primary rows anyway 

61 self.match_tract_catalog.columns_target_select_true = [] 

62 

63 

64class MultiProFitMatchTractCatalogDC2Config( 

65 MultiProFitMatchTractCatalogConfig, 

66 pipelineConnections=MatchTractCatalogConnections, 

67): 

68 """PipelineTaskConfig for MultiProFitMatchDC2CatalogTask.""" 

69 

70 def finalize( 

71 self, 

72 model_prefix: str, 

73 bands_match: list[str] | None = None, 

74 ): 

75 """Finalize configuration for a given model. 

76 

77 Parameters 

78 ---------- 

79 model_prefix 

80 The model column prefix, e.g. mpf_Sersic. 

81 bands_match 

82 List of bands to match fluxes on. 

83 """ 

84 if bands_match is None: 

85 bands_match = ["u", "g", "r", "i", "z", "y"] 

86 fluxes_ref = [f"flux_{band}" for band in bands_match] 

87 self.match_tract_catalog.columns_ref_flux = fluxes_ref 

88 self.match_tract_catalog.columns_ref_meas += fluxes_ref 

89 fluxes_meas = [f"{model_prefix}_{band}_flux" for band in bands_match] 

90 self.match_tract_catalog.columns_target_meas = [ 

91 col.format(model_prefix=model_prefix) for col in self.match_tract_catalog.columns_target_meas 

92 ] + fluxes_meas 

93 self.match_tract_catalog.columns_target_err = [ 

94 f"{col}_err" for col in self.match_tract_catalog.columns_target_meas 

95 ] 

96 self.match_tract_catalog.coord_format.column_target_coord1 = f"{model_prefix}_cen_ra" 

97 self.match_tract_catalog.coord_format.column_target_coord2 = f"{model_prefix}_cen_dec" 

98 self.match_tract_catalog.columns_target_select_false = [ 

99 f"{model_prefix}_not_primary_flag", 

100 ] 

101 

102 def setDefaults(self): 

103 super().setDefaults() 

104 self.match_tract_catalog.mag_faintest_ref = 27.0 

105 self.match_tract_catalog.columns_ref_select_true = ["is_unique_truth_entry"] 

106 

107 

108class MultiProFitMatchTractCatalogDC2Task(MatchTractCatalogTask): 

109 """Match DC2 truth_summary to a single model from an 

110 objectTable_tract_multiprofit. 

111 """ 

112 

113 _DefaultName = "multiProFitMatchTractCatalogDC2" 

114 ConfigClass = MultiProFitMatchTractCatalogDC2Config 

115 

116 

117class MultiProFitDiffMatchedTractCatalogConfig( 

118 DiffMatchedTractCatalogConfig, 

119 pipelineConnections=DiffMatchedTractCatalogConnections, 

120): 

121 """Generic MultiProFit reference matched catalog writing task config.""" 

122 

123 def _finalize_models( 

124 self, 

125 model_prefixes: str | list[str], 

126 bands: list[str] | None = None, 

127 fluxes_include: dict[str, list[str]] | None = None, 

128 sizes_include: dict[str, list[str]] | None = None, 

129 sersics_include: dict[str, list[str]] | None = None, 

130 is_v2: bool = False, 

131 ): 

132 """Finalize matched catalog configuration for given models. 

133 

134 Total source fluxes are included for all bands. Individual component 

135 fluxes are optional and must be specified. 

136 

137 Parameters 

138 ---------- 

139 model_prefixes 

140 One or more model column prefixes, e.g. mpf_Sersic. Only the first 

141 model will have its centroid parameters copied. 

142 bands 

143 The bands to add fluxes for. 

144 fluxes_include 

145 Short column names of components whose sizes (reff) should be 

146 included in the matched catalog. 

147 sizes_include 

148 Short column names of components whose sizes (reff) should be 

149 included in the matched catalog. 

150 sersics_include 

151 Short column names of components whose Sersic index should be 

152 included in the matched catalog. 

153 is_v2 

154 Whether the matched catalog is a truth_summary_v2 with moment and 

155 bulge fraction columns. 

156 """ 

157 if isinstance(model_prefixes, str): 

158 model_prefixes = [model_prefixes] 

159 elif not len(model_prefixes) > 0: 

160 raise ValueError(f"{model_prefixes} must have len > 0") 

161 if bands is None: 

162 bands = ["u", "g", "r", "i", "z", "y"] 

163 if fluxes_include is None: 

164 fluxes_include = {} 

165 if sizes_include is None: 

166 sizes_include = {} 

167 if sersics_include is None: 

168 sersics_include = {} 

169 columns_target_add = [] 

170 for model_prefix in model_prefixes: 

171 self.columns_target_copy += [ 

172 f"{model_prefix}_cen_x", 

173 f"{model_prefix}_cen_y", 

174 f"{model_prefix}_cen_x_err", 

175 f"{model_prefix}_cen_y_err", 

176 ] 

177 for band in bands: 

178 columns_target_add.append(f"{model_prefix}_{band}_flux") 

179 for component in fluxes_include.get(model_prefix, []): 

180 columns_target_add.append(f"{model_prefix}_{component}_{band}_flux") 

181 for size_include in sizes_include.get(model_prefix, []): 

182 for ax in ("x", "y"): 

183 columns_target_add.append(f"{model_prefix}_{size_include}_reff_{ax}") 

184 columns_target_add.append(f"{model_prefix}_{size_include}_rho") 

185 for sersic_include in sersics_include.get(model_prefix, []): 

186 columns_target_add.append(f"{model_prefix}_{sersic_include}_sersicindex") 

187 self.coord_format.column_target_coord1 = f"{model_prefixes[0]}_cen_ra" 

188 self.coord_format.column_target_coord2 = f"{model_prefixes[0]}_cen_dec" 

189 self.columns_ref_copy.extend([f"flux_{band}" for band in bands]) 

190 if is_v2: 

191 self.columns_ref_copy.extend( 

192 [ 

193 "positionAngle", 

194 "diskMajorAxisArcsec", 

195 "diskAxisRatio", 

196 "spheroidMajorAxisArcsec", 

197 "spheroidAxisRatio", 

198 ] 

199 ) 

200 self.columns_ref_copy.extend([f"bulge_to_total_{band}" for band in bands]) 

201 self.columns_target_copy.extend(columns_target_add) 

202 self.columns_target_copy.extend([f"{col}_err" for col in columns_target_add]) 

203 self.columns_target_coord_err = [ 

204 col.format(model_prefix=model_prefixes[0]) for col in self.columns_target_coord_err 

205 ] 

206 self.columns_target_select_false = [f"{model_prefixes[0]}_not_primary_flag"] 

207 self.columns_target_select_true = [] 

208 

209 def finalize( 

210 self, 

211 prefix_Sersic: str | None = None, 

212 prefix_ExpDeV: str | None = None, 

213 is_v2: bool = False, 

214 ): 

215 model_prefixes = [] 

216 fluxes_include = {} 

217 sizes_include = {} 

218 sersics_include = {} 

219 if prefix_Sersic: 

220 model_prefixes.append(prefix_Sersic) 

221 # TODO: get component prefix 

222 components = ["sersic"] 

223 sizes_include[prefix_Sersic] = components 

224 sersics_include[prefix_Sersic] = components 

225 if prefix_ExpDeV: 

226 model_prefixes.append(prefix_ExpDeV) 

227 components = ["exp", "deV"] 

228 fluxes_include[prefix_ExpDeV] = components 

229 sizes_include[prefix_ExpDeV] = components 

230 self._finalize_models( 

231 model_prefixes=model_prefixes, 

232 fluxes_include=fluxes_include, 

233 sizes_include=sizes_include, 

234 sersics_include=sersics_include, 

235 is_v2=is_v2, 

236 ) 

237 

238 def setDefaults(self): 

239 self.connections.name_input_cat_target = "objectTable_tract_multiprofit" 

240 self.columns_ref_copy = ["is_pointsource"] 

241 self.columns_target_copy = [ 

242 "objectId", 

243 "patch", 

244 ] 

245 self.columns_target_coord_err = [ 

246 "{model_prefix}_cen_ra_err", 

247 "{model_prefix}_cen_dec_err", 

248 ] 

249 

250 

251class MultiProFitDiffMatchedTractCatalogTask(DiffMatchedTractCatalogTask): 

252 

253 _DefaultName = "multiProFitDiffMatchedTractCatalogTask" 

254 ConfigClass = MultiProFitDiffMatchedTractCatalogConfig