25 from .multiBandUtils
import (MergeSourcesRunner, _makeGetSchemaCatalogs, makeMergeArgumentParser,
26 getInputSchema, getShortFilterName, readCatalog)
36 @anchor MergeMeasurementsConfig_ 38 @brief Configuration parameters for the MergeMeasurementsTask 40 pseudoFilterList = ListField(dtype=str, default=[
"sky"],
41 doc=
"Names of filters which may have no associated detection\n" 42 "(N.b. should include MergeDetectionsConfig.skyFilterName)")
43 snName = Field(dtype=str, default=
"base_PsfFlux",
44 doc=
"Name of flux measurement for calculating the S/N when choosing the reference band.")
45 minSN = Field(dtype=float, default=10.,
46 doc=
"If the S/N from the priority band is below this value (and the S/N " 47 "is larger than minSNDiff compared to the priority band), use the band with " 48 "the largest S/N as the reference band.")
49 minSNDiff = Field(dtype=float, default=3.,
50 doc=
"If the difference in S/N between another band and the priority band is larger " 51 "than this value (and the S/N in the priority band is less than minSN) " 52 "use the band with the largest S/N as the reference band")
53 flags = ListField(dtype=str, doc=
"Require that these flags, if available, are not set",
54 default=[
"base_PixelFlags_flag_interpolatedCenter",
"base_PsfFlux_flag",
55 "ext_photometryKron_KronFlux_flag",
"modelfit_CModel_flag", ])
56 priorityList = ListField(dtype=str, default=[],
57 doc=
"Priority-ordered list of bands for the merge.")
58 coaddName = Field(dtype=str, default=
"deep", doc=
"Name of coadd")
63 raise RuntimeError(
"No priority list provided")
76 @anchor MergeMeasurementsTask_ 78 @brief Merge measurements from multiple bands 80 @section pipe_tasks_multiBand_Contents Contents 82 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Purpose 83 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Initialize 84 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Run 85 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Config 86 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Debug 87 - @ref pipe_tasks_multiband_MergeMeasurementsTask_Example 89 @section pipe_tasks_multiBand_MergeMeasurementsTask_Purpose Description 91 Command-line task that merges measurements from multiple bands. 93 Combines consistent (i.e. with the same peaks and footprints) catalogs of sources from multiple filter 94 bands to construct a unified catalog that is suitable for driving forced photometry. Every source is 95 required to have centroid, shape and flux measurements in each band. 98 deepCoadd_meas{tract,patch,filter}: SourceCatalog 100 deepCoadd_ref{tract,patch}: SourceCatalog 104 MergeMeasurementsTask subclasses @ref CmdLineTask_ "CmdLineTask". 106 @section pipe_tasks_multiBand_MergeMeasurementsTask_Initialize Task initialization 108 @copydoc \_\_init\_\_ 110 @section pipe_tasks_multiBand_MergeMeasurementsTask_Run Invoking the Task 114 @section pipe_tasks_multiBand_MergeMeasurementsTask_Config Configuration parameters 116 See @ref MergeMeasurementsConfig_ 118 @section pipe_tasks_multiBand_MergeMeasurementsTask_Debug Debug variables 120 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 121 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py 124 MergeMeasurementsTask has no debug variables. 126 @section pipe_tasks_multiband_MergeMeasurementsTask_Example A complete example 127 of using MergeMeasurementsTask 129 MergeMeasurementsTask is meant to be run after deblending & measuring sources in every band. 130 The purpose of the task is to generate a catalog of sources suitable for driving forced photometry in 131 coadds and individual exposures. 132 Command-line usage of MergeMeasurementsTask expects a data reference to the coadds to be processed. A list 133 of the available optional arguments can be obtained by calling mergeCoaddMeasurements.py with the `--help` 134 command line argument: 136 mergeCoaddMeasurements.py --help 139 To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we 140 will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished 141 step 7 at @ref pipeTasks_multiBand, one may merge the catalogs generated after deblending and measuring 144 mergeCoaddMeasurements.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I^HSC-R 146 This will merge the HSC-I & HSC-R band catalogs. The results are written in 147 `$CI_HSC_DIR/DATA/deepCoadd-results/`. 149 _DefaultName =
"mergeCoaddMeasurements" 150 ConfigClass = MergeMeasurementsConfig
151 RunnerClass = MergeSourcesRunner
152 inputDataset =
"meas" 153 outputDataset =
"ref" 154 getSchemaCatalogs = _makeGetSchemaCatalogs(
"ref")
157 def _makeArgumentParser(cls):
163 def __init__(self, butler=None, schema=None, **kwargs):
167 @param[in] schema: the schema of the detection catalogs used as input to this one 168 @param[in] butler: a butler used to read the input schema from disk, if schema is None 170 The task will set its own self.schema attribute to the schema of the output merged catalog. 172 CmdLineTask.__init__(self, **kwargs)
176 self.
instFluxKey = inputSchema.find(self.config.snName +
"_instFlux").getKey()
177 self.
instFluxErrKey = inputSchema.find(self.config.snName +
"_instFluxErr").getKey()
178 self.
fluxFlagKey = inputSchema.find(self.config.snName +
"_flag").getKey()
181 for band
in self.config.priorityList:
183 outputKey = self.
schemaMapper.editOutputSchema().addField(
184 "merge_measurement_%s" % short,
186 doc=
"Flag field set if the measurements here are from the %s filter" % band
188 peakKey = inputSchema.find(
"merge_peak_%s" % short).key
189 footprintKey = inputSchema.find(
"merge_footprint_%s" % short).key
190 self.
flagKeys[band] = Struct(peak=peakKey, footprint=footprintKey, output=outputKey)
194 for filt
in self.config.pseudoFilterList:
197 except Exception
as e:
198 self.log.warn(
"merge_peak is not set for pseudo-filter %s: %s" % (filt, e))
201 for flag
in self.config.flags:
204 except KeyError
as exc:
205 self.log.warn(
"Can't find flag %s in schema: %s" % (flag, exc,))
209 @brief Merge coadd sources from multiple bands. Calls @ref `run`. 210 @param[in] patchRefList list of data references for each filter 212 catalogs = dict(
readCatalog(self, patchRef)
for patchRef
in patchRefList)
213 mergedCatalog = self.
run(catalogs)
214 self.
write(patchRefList[0], mergedCatalog)
218 Merge measurement catalogs to create a single reference catalog for forced photometry 220 @param[in] catalogs: the catalogs to be merged 222 For parent sources, we choose the first band in config.priorityList for which the 223 merge_footprint flag for that band is is True. 225 For child sources, the logic is the same, except that we use the merge_peak flags. 228 orderedCatalogs = [catalogs[band]
for band
in self.config.priorityList
if band
in catalogs.keys()]
229 orderedKeys = [self.
flagKeys[band]
for band
in self.config.priorityList
if band
in catalogs.keys()]
231 mergedCatalog = afwTable.SourceCatalog(self.
schema)
232 mergedCatalog.reserve(len(orderedCatalogs[0]))
234 idKey = orderedCatalogs[0].table.getIdKey()
235 for catalog
in orderedCatalogs[1:]:
236 if numpy.any(orderedCatalogs[0].get(idKey) != catalog.get(idKey)):
237 raise ValueError(
"Error in inputs to MergeCoaddMeasurements: source IDs do not match")
241 for orderedRecords
in zip(*orderedCatalogs):
246 priorityRecord =
None 247 priorityFlagKeys =
None 249 hasPseudoFilter =
False 253 for inputRecord, flagKeys
in zip(orderedRecords, orderedKeys):
254 parent = (inputRecord.getParent() == 0
and inputRecord.get(flagKeys.footprint))
255 child = (inputRecord.getParent() != 0
and inputRecord.get(flagKeys.peak))
257 if not (parent
or child):
259 if inputRecord.get(pseudoFilterKey):
260 hasPseudoFilter =
True 261 priorityRecord = inputRecord
262 priorityFlagKeys = flagKeys
267 isBad = any(inputRecord.get(flag)
for flag
in self.
badFlags)
272 if numpy.isnan(sn)
or sn < 0.:
274 if (parent
or child)
and priorityRecord
is None:
275 priorityRecord = inputRecord
276 priorityFlagKeys = flagKeys
279 maxSNRecord = inputRecord
280 maxSNFlagKeys = flagKeys
293 bestRecord = priorityRecord
294 bestFlagKeys = priorityFlagKeys
295 elif (prioritySN < self.config.minSN
and (maxSN - prioritySN) > self.config.minSNDiff
and 296 maxSNRecord
is not None):
297 bestRecord = maxSNRecord
298 bestFlagKeys = maxSNFlagKeys
299 elif priorityRecord
is not None:
300 bestRecord = priorityRecord
301 bestFlagKeys = priorityFlagKeys
303 if bestRecord
is not None and bestFlagKeys
is not None:
304 outputRecord = mergedCatalog.addNew()
306 outputRecord.set(bestFlagKeys.output,
True)
308 raise ValueError(
"Error in inputs to MergeCoaddMeasurements: no valid reference for %s" %
312 for inputCatalog
in orderedCatalogs:
313 if len(mergedCatalog) != len(inputCatalog):
314 raise ValueError(
"Mismatch between catalog sizes: %s != %s" %
315 (len(mergedCatalog), len(orderedCatalogs)))
321 @brief Write the output. 323 @param[in] patchRef data reference for patch 324 @param[in] catalog catalog 326 We write as the dataset provided by the 'outputDataset' 329 patchRef.put(catalog, self.config.coaddName +
"Coadd_" + self.
outputDataset)
332 mergeDataId = patchRef.dataId.copy()
333 del mergeDataId[
"filter"]
334 self.log.info(
"Wrote merged catalog: %s" % (mergeDataId,))
def runDataRef(self, patchRefList)
Merge coadd sources from multiple bands.
def makeMergeArgumentParser(name, dataset)
Create a suitable ArgumentParser.
def readCatalog(task, patchRef)
Read input catalog.
Merge measurements from multiple bands.
def run(self, catalogs)
Merge measurement catalogs to create a single reference catalog for forced photometry.
def __init__(self, butler=None, schema=None, kwargs)
Initialize the task.
Configuration parameters for the MergeMeasurementsTask.
def getInputSchema(self, butler=None, schema=None)
def write(self, patchRef, catalog)
Write the output.
def getShortFilterName(name)