LSST Applications g04e9c324dd+8c5ae1fdc5,g134cb467dc+b203dec576,g18429d2f64+358861cd2c,g199a45376c+0ba108daf9,g1fd858c14a+dd066899e3,g262e1987ae+ebfced1d55,g29ae962dfc+72fd90588e,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+b668f15bc5,g4595892280+3897dae354,g47891489e3+abcf9c3559,g4d44eb3520+fb4ddce128,g53246c7159+8c5ae1fdc5,g67b6fd64d1+abcf9c3559,g67fd3c3899+1f72b5a9f7,g74acd417e5+cb6b47f07b,g786e29fd12+668abc6043,g87389fa792+8856018cbb,g89139ef638+abcf9c3559,g8d7436a09f+bcf525d20c,g8ea07a8fe4+9f5ccc88ac,g90f42f885a+6054cc57f1,g97be763408+06f794da49,g9dd6db0277+1f72b5a9f7,ga681d05dcb+7e36ad54cd,gabf8522325+735880ea63,gac2eed3f23+abcf9c3559,gb89ab40317+abcf9c3559,gbf99507273+8c5ae1fdc5,gd8ff7fe66e+1f72b5a9f7,gdab6d2f7ff+cb6b47f07b,gdc713202bf+1f72b5a9f7,gdfd2d52018+8225f2b331,ge365c994fd+375fc21c71,ge410e46f29+abcf9c3559,geaed405ab2+562b3308c0,gf9a733ac38+8c5ae1fdc5,w.2025.35
LSST Data Management Base Package
Loading...
Searching...
No Matches
match_probabilistic_task.py
Go to the documentation of this file.
1# This file is part of meas_astrom.
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
22from typing import Dict, List, Optional, Set, Tuple
23import warnings
24
25import astropy.table
26import logging
27import lsst.afw.geom as afwGeom
28import lsst.geom as geom
29import lsst.pipe.base as pipeBase
30import lsst.utils as utils
31import numpy as np
32
33from .matcher_probabilistic import MatchProbabilisticConfig, MatcherProbabilistic
34
35
36__all__ = ["MatchProbabilisticTask", "radec_to_xy"]
37
38
39def radec_to_xy(ra_vec, dec_vec, factor, wcs: afwGeom.SkyWcs):
40 radec_true = [
41 geom.SpherePoint(ra*factor, dec*factor, geom.degrees)
42 for ra, dec in zip(ra_vec, dec_vec)
43 ]
44 return wcs.skyToPixel(radec_true)
45
46
47class MatchProbabilisticTask(pipeBase.Task):
48 """Run MatchProbabilistic on a reference and target catalog covering the same tract."""
49
50 ConfigClass = MatchProbabilisticConfig
51 _DefaultName = "matchProbabilistic"
52
53 @staticmethod
55 catalog: astropy.table.Table,
56 columns_true: List[str],
57 columns_false: List[str],
58 selection: Optional[np.array],
59 ) -> np.array:
60 """Apply additional boolean selection columns.
61
62 catalog : `astropy.table.Table`
63 The catalog to select from.
64 columns_true : `list` [`str`]
65 Columns that must be True for selection.
66 columns_false : `list` [`str`]
67 Columns that must be False for selection.
68 selection : `numpy.array`
69 A prior selection array. Default all true.
70
71 Returns
72 -------
73 selection : `numpy.array`
74 The final selection array.
75
76 """
77 select_additional = (len(columns_true) + len(columns_false)) > 0
78 if select_additional:
79 if selection is None:
80 selection = np.ones(len(catalog), dtype=bool)
81 for column in columns_true:
82 # This is intended for boolean columns, so the behaviour for non-boolean is not obvious
83 # More config options and/or using a ConfigurableActionField might be best
84 values = catalog[column]
85 selection &= (np.isfinite(values) & (values != 0))
86 for column in columns_false:
87 values = catalog[column]
88 selection &= (values == 0)
89 return selection
90
91 @property
92 def columns_in_ref(self) -> Set[str]:
93 return self.config.columns_in_ref
94
95 @property
96 def columns_in_target(self) -> Set[str]:
97 return self.config.columns_in_target
98
99 def match(
100 self,
101 catalog_ref: astropy.table.Table,
102 catalog_target: astropy.table.Table,
103 select_ref: np.array = None,
104 select_target: np.array = None,
105 wcs: afwGeom.SkyWcs = None,
106 logger: logging.Logger = None,
107 logging_n_rows: int = None,
108 ) -> Tuple[astropy.table.Table, astropy.table.Table, Dict[int, str]]:
109 """Match sources in a reference tract catalog with a target catalog.
110
111 Parameters
112 ----------
113 catalog_ref : `astropy.table.Table`
114 A reference catalog to match objects/sources from.
115 catalog_target : `astropy.table.Table`
116 A target catalog to match reference objects/sources to.
117 select_ref : `numpy.array`
118 A boolean array of the same length as `catalog_ref` selecting the sources that can be matched.
119 select_target : `numpy.array`
120 A boolean array of the same length as `catalog_target` selecting the sources that can be matched.
121 wcs : `lsst.afw.image.SkyWcs`
122 A coordinate system to convert catalog positions to sky coordinates. Only used if
123 `self.config.coords_ref_to_convert` is set.
124 logger : `logging.Logger`
125 A Logger for logging.
126 logging_n_rows : `int`
127 Number of matches to make before outputting incremental log message.
128
129 Returns
130 -------
131 catalog_out_ref : `astropy.table.Table`
132 Reference matched catalog with indices of target matches.
133 catalog_out_target : `astropy.table.Table`
134 Reference matched catalog with indices of target matches.
135 """
136 if logger is None:
137 logger = self.log
138
139 config = self.config
140
141 if config.column_ref_order is None:
142 fluxes = [catalog_ref[key] for key in config.columns_ref_flux]
143 flux_tot = np.nansum(fluxes, axis=0)
144 catalog_ref["flux_total"] = flux_tot
145 if config.mag_brightest_ref != -np.inf or config.mag_faintest_ref != np.inf:
146 mag_tot = (
147 -2.5 * np.log10(flux_tot) + config.coord_format.mag_zeropoint_ref
148 )
149 select_mag = (mag_tot >= config.mag_brightest_ref) & (
150 mag_tot <= config.mag_faintest_ref
151 )
152 else:
153 select_mag = np.isfinite(flux_tot)
154 if select_ref is None:
155 select_ref = select_mag
156 else:
157 select_ref &= select_mag
158
159 with warnings.catch_warnings():
160 # We already issued a deprecation warning; no need to repeat it.
161 warnings.filterwarnings(action="ignore", category=FutureWarning)
162 select_ref = self._apply_select_bool(
163 catalog=catalog_ref,
164 columns_true=config.columns_ref_select_true,
165 columns_false=config.columns_ref_select_false,
166 selection=select_ref,
167 )
168 select_target = self._apply_select_bool(
169 catalog=catalog_target,
170 columns_true=config.columns_target_select_true,
171 columns_false=config.columns_target_select_false,
172 selection=select_target,
173 )
174
175 logger.info(
176 "Beginning MatcherProbabilistic.match with %d/%d ref sources selected vs %d/%d target",
177 np.sum(select_ref),
178 len(select_ref),
179 np.sum(select_target),
180 len(select_target),
181 )
182
183 catalog_out_ref, catalog_out_target, exceptions = self.matcher.match(
184 catalog_ref,
185 catalog_target,
186 select_ref=select_ref,
187 select_target=select_target,
188 logger=logger,
189 logging_n_rows=logging_n_rows,
190 wcs=wcs,
191 radec_to_xy_func=radec_to_xy,
192 )
193
194 return catalog_out_ref, catalog_out_target, exceptions
195
196 @utils.timer.timeMethod
197 def run(
198 self,
199 catalog_ref: astropy.table.Table,
200 catalog_target: astropy.table.Table,
201 wcs: afwGeom.SkyWcs = None,
202 **kwargs,
203 ) -> pipeBase.Struct:
204 """Match sources in a reference tract catalog with a target catalog.
205
206 Parameters
207 ----------
208 catalog_ref : `astropy.table.Table`
209 A reference catalog to match objects/sources from.
210 catalog_target : `astropy.table.Table`
211 A target catalog to match reference objects/sources to.
212 wcs : `lsst.afw.image.SkyWcs`
213 A coordinate system to convert catalog positions to sky coordinates.
214 Only needed if `config.coords_ref_to_convert` is used to convert
215 reference catalog sky coordinates to pixel positions.
216 kwargs : Additional keyword arguments to pass to `match`.
217
218 Returns
219 -------
220 retStruct : `lsst.pipe.base.Struct`
221 A struct with output_ref and output_target attribute containing the
222 output matched catalogs, as well as a dict
223 """
224 with warnings.catch_warnings():
225 # We already issued a deprecation warning; no need to repeat it.
226 warnings.filterwarnings(action="ignore", category=FutureWarning)
227 catalog_ref, catalog_target, exceptions = self.match(
228 catalog_ref, catalog_target, wcs=wcs, **kwargs
229 )
230
231 return pipeBase.Struct(
232 cat_output_ref=catalog_ref,
233 cat_output_target=catalog_target,
234 exceptions=exceptions,
235 )
236
237 def __init__(self, **kwargs):
238 super().__init__(**kwargs)
239 self.matcher = MatcherProbabilistic(self.config)
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Definition SkyWcs.h:118
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57
pipeBase.Struct run(self, astropy.table.Table catalog_ref, astropy.table.Table catalog_target, afwGeom.SkyWcs wcs=None, **kwargs)
np.array _apply_select_bool(astropy.table.Table catalog, List[str] columns_true, List[str] columns_false, Optional[np.array] selection)
Tuple[astropy.table.Table, astropy.table.Table, Dict[int, str]] match(self, astropy.table.Table catalog_ref, astropy.table.Table catalog_target, np.array select_ref=None, np.array select_target=None, afwGeom.SkyWcs wcs=None, logging.Logger logger=None, int logging_n_rows=None)
radec_to_xy(ra_vec, dec_vec, factor, afwGeom.SkyWcs wcs)