115 def run(self, coadd_object_cat, ccd_inputs,
116 source_table_handle_dict=None, finalized_source_table_handle_dict=None):
117 """Propagate flags from single-frame sources to coadd objects.
119 Flags are only propagated if a configurable percentage of the sources
120 are matched to the coadd objects. This task will match both "plain"
121 source flags and "finalized" source flags.
125 coadd_object_cat : `lsst.afw.table.SourceCatalog`
126 Table of coadd objects.
127 ccd_inputs : `lsst.afw.table.ExposureCatalog`
128 Table of single-frame inputs to coadd.
129 source_table_handle_dict : `dict` [`int`: `lsst.daf.butler.DeferredDatasetHandle`]
130 Dict for sourceTable_visit handles (key is visit). May be None if
131 ``config.source_flags`` has no entries.
132 finalized_source_table_handle_dict : `dict` [`int`:
133 `lsst.daf.butler.DeferredDatasetHandle`]
134 Dict for finalized_src_table handles (key is visit). May be None if
135 ``config.finalized_source_flags`` has no entries.
137 if len(self.config.source_flags) == 0
and len(self.config.finalized_source_flags) == 0:
141 self.config.x_column,
142 self.config.y_column,
143 self.config.source_flags.keys()
146 self.config.finalized_x_column,
147 self.config.finalized_y_column,
148 self.config.finalized_source_flags.keys(),
154 num_overlaps = np.zeros(len(coadd_object_cat), dtype=np.int32)
155 for i, obj
in enumerate(coadd_object_cat):
156 num_overlaps[i] = len(ccd_inputs.subsetContaining(obj.getCoord(),
True))
158 visits = np.unique(ccd_inputs[
"visit"])
160 matcher = Matcher(np.rad2deg(coadd_object_cat[
"coord_ra"]),
161 np.rad2deg(coadd_object_cat[
"coord_dec"]))
163 source_flag_counts = {f: np.zeros(len(coadd_object_cat), dtype=np.int32)
164 for f
in self.config.source_flags}
165 finalized_source_flag_counts = {f: np.zeros(len(coadd_object_cat), dtype=np.int32)
166 for f
in self.config.finalized_source_flags}
168 handles_list = [source_table_handle_dict, finalized_source_table_handle_dict]
169 columns_list = [source_columns, finalized_columns]
170 counts_list = [source_flag_counts, finalized_source_flag_counts]
171 x_column_list = [self.config.x_column, self.config.finalized_x_column]
172 y_column_list = [self.config.y_column, self.config.finalized_y_column]
173 name_list = [
"sources",
"finalized_sources"]
175 for handle_dict, columns, flag_counts, x_col, y_col, name
in zip(handles_list,
181 if handle_dict
is not None and len(columns) > 0:
183 if visit
not in handle_dict:
184 self.log.info(
"Visit %d not in input handle dict for %s", visit, name)
186 handle = handle_dict[visit]
187 df = handle.get(parameters={
"columns": columns})
190 for row
in ccd_inputs[ccd_inputs[
"visit"] == visit]:
191 detector = row[
"ccd"]
194 self.log.info(
"No WCS for visit %d detector %d, so can't match sources to "
195 "propagate flags. Skipping...", visit, detector)
198 df_det = df[df[
"detector"] == detector]
203 ra, dec = wcs.pixelToSkyArray(df_det[x_col].values,
204 df_det[y_col].values,
211 idx, i1, i2, d = matcher.query_radius(
214 self.config.match_radius/3600.,
219 self.log.info(
"Visit %d has no overlapping objects", visit)
224 self.log.info(
"Visit %d has no overlapping objects", visit)
227 for flag
in flag_counts:
228 flag_values = df_det[flag].values
229 flag_counts[flag][i1] += flag_values[i2].astype(np.int32)
231 for flag
in source_flag_counts:
232 thresh = num_overlaps*self.config.source_flags[flag]
233 object_flag = (source_flag_counts[flag] > thresh)
234 coadd_object_cat[flag] = object_flag
235 self.log.info(
"Propagated %d sources with flag %s", object_flag.sum(), flag)
237 for flag
in finalized_source_flag_counts:
238 thresh = num_overlaps*self.config.finalized_source_flags[flag]
239 object_flag = (finalized_source_flag_counts[flag] > thresh)
240 coadd_object_cat[flag] = object_flag
241 self.log.info(
"Propagated %d finalized sources with flag %s", object_flag.sum(), flag)