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