lsst.meas.astrom g3b20d027df+1b9c813971
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
22import lsst.afw.geom as afwGeom
23import lsst.geom as geom
24import lsst.pipe.base as pipeBase
25import lsst.utils as utils
26from .matcher_probabilistic import MatchProbabilisticConfig, MatcherProbabilistic
27
28import logging
29import numpy as np
30import pandas as pd
31from typing import Dict, Set, Tuple
32
33__all__ = ['MatchProbabilisticTask']
34
35
36class MatchProbabilisticTask(pipeBase.Task):
37 """Run MatchProbabilistic on a reference and target catalog covering the same tract.
38 """
39 ConfigClass = MatchProbabilisticConfig
40 _DefaultName = "matchProbabilistic"
41
42 @property
43 def columns_in_ref(self) -> Set[str]:
44 return self.config.columns_in_ref()
45
46 @property
47 def columns_in_target(self) -> Set[str]:
48 return self.config.columns_in_target()
49
50 def match(
51 self,
52 catalog_ref: pd.DataFrame,
53 catalog_target: pd.DataFrame,
54 select_ref: np.array = None,
55 select_target: np.array = None,
56 wcs: afwGeom.SkyWcs = None,
57 logger: logging.Logger = None,
58 logging_n_rows: int = None,
59 ) -> Tuple[pd.DataFrame, pd.DataFrame, Dict[int, str]]:
60 """Match sources in a reference tract catalog with a target catalog.
61
62 Parameters
63 ----------
64 catalog_ref : `pandas.DataFrame`
65 A reference catalog to match objects/sources from.
66 catalog_target : `pandas.DataFrame`
67 A target catalog to match reference objects/sources to.
68 select_ref : `numpy.array`
69 A boolean array of the same length as `catalog_ref` selecting the sources that can be matched.
70 select_target : `numpy.array`
71 A boolean array of the same length as `catalog_target` selecting the sources that can be matched.
72 wcs : `lsst.afw.image.SkyWcs`
73 A coordinate system to convert catalog positions to sky coordinates. Only used if
74 `self.config.coords_ref_to_convert` is set.
75 logger : `logging.Logger`
76 A Logger for logging.
77 logging_n_rows : `int`
78 Number of matches to make before outputting incremental log message.
79
80 Returns
81 -------
82 catalog_out_ref : `pandas.DataFrame`
83 Reference matched catalog with indices of target matches.
84 catalog_out_target : `pandas.DataFrame`
85 Reference matched catalog with indices of target matches.
86 """
87 if logger is None:
88 logger = self.log
89
90 config = self.config
91
92 if config.column_order is None:
93 flux_tot = np.nansum(catalog_ref.loc[:, config.columns_ref_flux].values, axis=1)
94 catalog_ref['flux_total'] = flux_tot
95 if config.mag_brightest_ref != -np.inf or config.mag_faintest_ref != np.inf:
96 mag_tot = -2.5 * np.log10(flux_tot) + config.mag_zeropoint_ref
97 select_mag = (mag_tot >= config.mag_brightest_ref) & (
98 mag_tot <= config.mag_faintest_ref)
99 else:
100 select_mag = np.isfinite(flux_tot)
101 if select_ref is None:
102 select_ref = select_mag
103 else:
104 select_ref &= select_mag
105
106 if config.coords_ref_to_convert:
107 ra_ref, dec_ref = [catalog_ref[column] for column in config.coords_ref_to_convert.keys()]
108 factor = config.coords_ref_factor
109 radec_true = [geom.SpherePoint(ra*factor, dec*factor, geom.degrees)
110 for ra, dec in zip(ra_ref, dec_ref)]
111 xy_true = wcs.skyToPixel(radec_true)
112
113 for idx_coord, column_out in enumerate(config.coords_ref_to_convert.values()):
114 catalog_ref[column_out] = np.array([xy[idx_coord] for xy in xy_true])
115
116 select_additional = (len(config.columns_target_select_true)
117 + len(config.columns_target_select_false)) > 0
118 if select_additional:
119 if select_target is None:
120 select_target = np.ones(len(catalog_target), dtype=bool)
121 for column in config.columns_target_select_true:
122 select_target &= catalog_target[column].values
123 for column in config.columns_target_select_false:
124 select_target &= ~catalog_target[column].values
125
126 logger.info('Beginning MatcherProbabilistic.match with %d/%d ref sources selected vs %d/%d target',
127 np.sum(select_ref), len(select_ref), np.sum(select_target), len(select_target))
128
129 catalog_out_ref, catalog_out_target, exceptions = self.matchermatcher.match(
130 catalog_ref,
131 catalog_target,
132 select_ref=select_ref,
133 select_target=select_target,
134 logger=logger,
135 logging_n_rows=logging_n_rows,
136 )
137
138 return catalog_out_ref, catalog_out_target, exceptions
139
140 @utils.timer.timeMethod
141 def run(
142 self,
143 catalog_ref: pd.DataFrame,
144 catalog_target: pd.DataFrame,
145 wcs: afwGeom.SkyWcs = None,
146 **kwargs,
147 ) -> pipeBase.Struct:
148 """Match sources in a reference tract catalog with a target catalog.
149
150 Parameters
151 ----------
152 catalog_ref : `pandas.DataFrame`
153 A reference catalog to match objects/sources from.
154 catalog_target : `pandas.DataFrame`
155 A target catalog to match reference objects/sources to.
156 wcs : `lsst.afw.image.SkyWcs`
157 A coordinate system to convert catalog positions to sky coordinates.
158 Only needed if `config.coords_ref_to_convert` is used to convert
159 reference catalog sky coordinates to pixel positions.
160 kwargs : Additional keyword arguments to pass to `match`.
161
162 Returns
163 -------
164 retStruct : `lsst.pipe.base.Struct`
165 A struct with output_ref and output_target attribute containing the
166 output matched catalogs, as well as a dict
167 """
168 catalog_ref, catalog_target, exceptions = self.matchmatch(catalog_ref, catalog_target, wcs=wcs, **kwargs)
169 return pipeBase.Struct(cat_output_ref=catalog_ref, cat_output_target=catalog_target,
170 exceptions=exceptions)
171
172 def __init__(self, **kwargs):
173 super().__init__(**kwargs)
174 self.matchermatcher = MatcherProbabilistic(self.config)
pipeBase.Struct run(self, pd.DataFrame catalog_ref, pd.DataFrame catalog_target, afwGeom.SkyWcs wcs=None, **kwargs)
Tuple[pd.DataFrame, pd.DataFrame, Dict[int, str]] match(self, pd.DataFrame catalog_ref, pd.DataFrame 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)