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-26 09:37 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-26 09:37 +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/>.
22__all__ = (
23 "MultiProFitMatchTractCatalogConfig",
24 "MultiProFitMatchTractCatalogDC2Config",
25 "MultiProFitMatchTractCatalogDC2Task",
26)
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
41class MultiProFitMatchTractCatalogConfig(
42 MatchTractCatalogConfig,
43 pipelineConnections=MatchTractCatalogConnections,
44):
45 """Generic MultiProFit reference source match task config."""
47 def setDefaults(self):
48 self.connections.name_input_cat_target = "objectTable_tract_multiprofit"
49 self.match_tract_catalog.retarget(MatchTractCatalogProbabilisticTask)
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 = []
64class MultiProFitMatchTractCatalogDC2Config(
65 MultiProFitMatchTractCatalogConfig,
66 pipelineConnections=MatchTractCatalogConnections,
67):
68 """PipelineTaskConfig for MultiProFitMatchDC2CatalogTask."""
70 def finalize(
71 self,
72 model_prefix: str,
73 bands_match: list[str] | None = None,
74 ):
75 """Finalize configuration for a given model.
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 ]
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"]
108class MultiProFitMatchTractCatalogDC2Task(MatchTractCatalogTask):
109 """Match DC2 truth_summary to a single model from an
110 objectTable_tract_multiprofit.
111 """
113 _DefaultName = "multiProFitMatchTractCatalogDC2"
114 ConfigClass = MultiProFitMatchTractCatalogDC2Config
117class MultiProFitDiffMatchedTractCatalogConfig(
118 DiffMatchedTractCatalogConfig,
119 pipelineConnections=DiffMatchedTractCatalogConnections,
120):
121 """Generic MultiProFit reference matched catalog writing task config."""
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.
134 Total source fluxes are included for all bands. Individual component
135 fluxes are optional and must be specified.
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 = []
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 )
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 ]
251class MultiProFitDiffMatchedTractCatalogTask(DiffMatchedTractCatalogTask):
253 _DefaultName = "multiProFitDiffMatchedTractCatalogTask"
254 ConfigClass = MultiProFitDiffMatchedTractCatalogConfig