116 def run(self, coadd_object_cat, ccd_inputs,
117 source_table_handle_dict=None, finalized_source_table_handle_dict=None,
118 visit_summary_handle_dict=None):
119 """Propagate flags from single-frame sources to coadd objects.
121 Flags are only propagated if a configurable percentage of the sources
122 are matched to the coadd objects. This task will match both "plain"
123 source flags and "finalized" source flags.
127 coadd_object_cat : `lsst.afw.table.SourceCatalog`
128 Table of coadd objects.
129 ccd_inputs : `lsst.afw.table.ExposureCatalog`
130 Table of single-frame inputs to coadd.
131 source_table_handle_dict : `dict` [`int`: `lsst.daf.butler.DeferredDatasetHandle`], optional
132 Dict for sourceTable_visit handles (key is visit). May be None if
133 ``config.source_flags`` has no entries.
134 finalized_source_table_handle_dict : `dict` [`int`:
135 `lsst.daf.butler.DeferredDatasetHandle`], optional
136 Dict for finalized_src_table handles (key is visit). May be None if
137 ``config.finalized_source_flags`` has no entries.
138 visit_summary_handle_dict : `dict` [`int`: `lsst.daf.butler.DeferredDatasetHandle`], optional
139 Dict for visitSummary handles (key is visit). If None, using WCS
140 from the ccd_inputs will be attempted.
142 if len(self.config.source_flags) == 0
and len(self.config.finalized_source_flags) == 0:
146 self.config.x_column,
147 self.config.y_column,
148 self.config.source_flags.keys()
151 self.config.finalized_x_column,
152 self.config.finalized_y_column,
153 self.config.finalized_source_flags.keys(),
159 num_overlaps = np.zeros(len(coadd_object_cat), dtype=np.int32)
160 if isinstance(ccd_inputs, ExposureCatalog):
161 for i, obj
in enumerate(coadd_object_cat):
162 num_overlaps[i] = len(ccd_inputs.subsetContaining(obj.getCoord(),
True))
164 visits = np.unique(ccd_inputs[
"visit"])
166 for i, obj
in enumerate(coadd_object_cat):
169 num_overlaps[i] = len(ccd_inputs.subsetContaining(obj.getCentroid()))
171 visits = np.unique([ccd_input.visit
for ccd_input
in ccd_inputs])
173 matcher = Matcher(np.rad2deg(coadd_object_cat[
"coord_ra"]),
174 np.rad2deg(coadd_object_cat[
"coord_dec"]))
176 source_flag_counts = {f: np.zeros(len(coadd_object_cat), dtype=np.int32)
177 for f
in self.config.source_flags}
178 finalized_source_flag_counts = {f: np.zeros(len(coadd_object_cat), dtype=np.int32)
179 for f
in self.config.finalized_source_flags}
181 handles_list = [source_table_handle_dict, finalized_source_table_handle_dict]
182 columns_list = [source_columns, finalized_columns]
183 counts_list = [source_flag_counts, finalized_source_flag_counts]
184 x_column_list = [self.config.x_column, self.config.finalized_x_column]
185 y_column_list = [self.config.y_column, self.config.finalized_y_column]
186 name_list = [
"sources",
"finalized_sources"]
188 for handle_dict, columns, flag_counts, x_col, y_col, name
in zip(handles_list,
194 if handle_dict
is not None and len(columns) > 0:
196 if visit
not in handle_dict:
197 self.log.info(
"Visit %d not in input handle dict for %s", visit, name)
199 handle = handle_dict[visit]
200 tbl = handle.get(parameters={
"columns": columns})
201 if visit_summary_handle_dict
is not None:
202 visit_summary = visit_summary_handle_dict[visit].get()
205 for row
in ccd_inputs:
206 if row[
"visit"] != visit:
208 detector = row[
"ccd"]
209 if visit_summary_handle_dict
is None:
212 wcs = visit_summary.find(detector).getWcs()
214 self.log.info(
"No WCS for visit %d detector %d, so can't match sources to "
215 "propagate flags. Skipping...", visit, detector)
218 tbl_det = tbl[tbl[
"detector"] == detector]
220 if len(tbl_det) == 0:
223 ra, dec = wcs.pixelToSkyArray(np.asarray(tbl_det[x_col]),
224 np.asarray(tbl_det[y_col]),
231 idx, i1, i2, d = matcher.query_radius(
234 self.config.match_radius/3600.,
239 self.log.info(
"Visit %d has no overlapping objects", visit)
244 self.log.info(
"Visit %d has no overlapping objects", visit)
247 for flag
in flag_counts:
248 flag_values = np.asarray(tbl_det[flag])
249 flag_counts[flag][i1] += flag_values[i2].astype(np.int32)
251 for flag
in source_flag_counts:
252 thresh = num_overlaps*self.config.source_flags[flag]
253 object_flag = (source_flag_counts[flag] > thresh)
254 coadd_object_cat[flag] = object_flag
255 self.log.info(
"Propagated %d sources with flag %s", object_flag.sum(), flag)
257 for flag
in finalized_source_flag_counts:
258 thresh = num_overlaps*self.config.finalized_source_flags[flag]
259 object_flag = (finalized_source_flag_counts[flag] > thresh)
260 coadd_object_cat[flag] = object_flag
261 self.log.info(
"Propagated %d finalized sources with flag %s", object_flag.sum(), flag)