26 from lsst.pipe.base import CmdLineTask, Struct, TaskRunner, ArgumentParser, ButlerInitializedTaskRunner
27 from lsst.pex.config import Config, Field, ListField, ConfigurableField, RangeField, ConfigField
29 from lsst.meas.base import SingleFrameMeasurementTask, ApplyApCorrTask, CatalogCalculationTask
45 * deepCoadd_det: detections from what used to be processCoadd (tract, patch, filter) 46 * deepCoadd_mergeDet: merged detections (tract, patch) 47 * deepCoadd_meas: measurements of merged detections (tract, patch, filter) 48 * deepCoadd_ref: reference sources (tract, patch) 49 All of these have associated *_schema catalogs that require no data ID and hold no records. 51 In addition, we have a schema-only dataset, which saves the schema for the PeakRecords in 52 the mergeDet, meas, and ref dataset Footprints: 53 * deepCoadd_peak_schema 57 def _makeGetSchemaCatalogs(datasetSuffix):
58 """Construct a getSchemaCatalogs instance method 60 These are identical for most of the classes here, so we'll consolidate 63 datasetSuffix: Suffix of dataset name, e.g., "src" for "deepCoadd_src" 66 def getSchemaCatalogs(self):
67 """Return a dict of empty catalogs for each catalog dataset produced by this task.""" 68 src = afwTable.SourceCatalog(self.schema)
69 if hasattr(self,
"algMetadata"):
70 src.getTable().setMetadata(self.algMetadata)
71 return {self.config.coaddName +
"Coadd_" + datasetSuffix: src}
72 return getSchemaCatalogs
75 def _makeMakeIdFactory(datasetName):
76 """Construct a makeIdFactory instance method 78 These are identical for all the classes here, so this consolidates 81 datasetName: Dataset name without the coadd name prefix, e.g., "CoaddId" for "deepCoaddId" 84 def makeIdFactory(self, dataRef):
85 """Return an IdFactory for setting the detection identifiers 87 The actual parameters used in the IdFactory are provided by 88 the butler (through the provided data reference. 90 expBits = dataRef.get(self.config.coaddName + datasetName +
"_bits")
91 expId = int(dataRef.get(self.config.coaddName + datasetName))
92 return afwTable.IdFactory.makeSource(expId, 64 - expBits)
97 """Given a longer, camera-specific filter name (e.g. "HSC-I") return its shorthand name ("i"). 101 return afwImage.Filter(name).getFilterProperty().getName()
108 @anchor DetectCoaddSourcesConfig_ 110 @brief Configuration parameters for the DetectCoaddSourcesTask 112 doScaleVariance = Field(dtype=bool, default=
True, doc=
"Scale variance plane using empirical noise?")
113 scaleVariance = ConfigurableField(target=ScaleVarianceTask, doc=
"Variance rescaling")
114 detection = ConfigurableField(target=DynamicDetectionTask, doc=
"Source detection")
115 coaddName = Field(dtype=str, default=
"deep", doc=
"Name of coadd")
116 doInsertFakes = Field(dtype=bool, default=
False,
117 doc=
"Run fake sources injection task")
118 insertFakes = ConfigurableField(target=BaseFakeSourcesTask,
119 doc=
"Injection of fake sources for testing " 120 "purposes (must be retargeted)")
123 Config.setDefaults(self)
124 self.
detection.thresholdType =
"pixel_stdev" 127 self.
detection.reEstimateBackground =
False 128 self.
detection.background.useApprox =
False 130 self.
detection.background.undersampleStyle =
'REDUCE_INTERP_ORDER' 131 self.
detection.doTempWideBackground =
True 143 @anchor DetectCoaddSourcesTask_ 145 @brief Detect sources on a coadd 147 @section pipe_tasks_multiBand_Contents Contents 149 - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Purpose 150 - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Initialize 151 - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Run 152 - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Config 153 - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Debug 154 - @ref pipe_tasks_multiband_DetectCoaddSourcesTask_Example 156 @section pipe_tasks_multiBand_DetectCoaddSourcesTask_Purpose Description 158 Command-line task that detects sources on a coadd of exposures obtained with a single filter. 160 Coadding individual visits requires each exposure to be warped. This introduces covariance in the noise 161 properties across pixels. Before detection, we correct the coadd variance by scaling the variance plane 162 in the coadd to match the observed variance. This is an approximate approach -- strictly, we should 163 propagate the full covariance matrix -- but it is simple and works well in practice. 165 After scaling the variance plane, we detect sources and generate footprints by delegating to the @ref 166 SourceDetectionTask_ "detection" subtask. 169 deepCoadd{tract,patch,filter}: ExposureF 171 deepCoadd_det{tract,patch,filter}: SourceCatalog (only parent Footprints) 172 @n deepCoadd_calexp{tract,patch,filter}: Variance scaled, background-subtracted input 174 @n deepCoadd_calexp_background{tract,patch,filter}: BackgroundList 178 DetectCoaddSourcesTask delegates most of its work to the @ref SourceDetectionTask_ "detection" subtask. 179 You can retarget this subtask if you wish. 181 @section pipe_tasks_multiBand_DetectCoaddSourcesTask_Initialize Task initialization 183 @copydoc \_\_init\_\_ 185 @section pipe_tasks_multiBand_DetectCoaddSourcesTask_Run Invoking the Task 189 @section pipe_tasks_multiBand_DetectCoaddSourcesTask_Config Configuration parameters 191 See @ref DetectCoaddSourcesConfig_ "DetectSourcesConfig" 193 @section pipe_tasks_multiBand_DetectCoaddSourcesTask_Debug Debug variables 195 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 196 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py 199 DetectCoaddSourcesTask has no debug variables of its own because it relegates all the work to 200 @ref SourceDetectionTask_ "SourceDetectionTask"; see the documetation for 201 @ref SourceDetectionTask_ "SourceDetectionTask" for further information. 203 @section pipe_tasks_multiband_DetectCoaddSourcesTask_Example A complete example 204 of using DetectCoaddSourcesTask 206 DetectCoaddSourcesTask is meant to be run after assembling a coadded image in a given band. The purpose of 207 the task is to update the background, detect all sources in a single band and generate a set of parent 208 footprints. Subsequent tasks in the multi-band processing procedure will merge sources across bands and, 209 eventually, perform forced photometry. Command-line usage of DetectCoaddSourcesTask expects a data 210 reference to the coadd to be processed. A list of the available optional arguments can be obtained by 211 calling detectCoaddSources.py with the `--help` command line argument: 213 detectCoaddSources.py --help 216 To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we 217 will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has followed 218 steps 1 - 4 at @ref pipeTasks_multiBand, one may detect all the sources in each coadd as follows: 220 detectCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I 222 that will process the HSC-I band data. The results are written to 223 `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I`. 225 It is also necessary to run: 227 detectCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R 229 to generate the sources catalogs for the HSC-R band required by the next step in the multi-band 230 processing procedure: @ref MergeDetectionsTask_ "MergeDetectionsTask". 232 _DefaultName =
"detectCoaddSources" 233 ConfigClass = DetectCoaddSourcesConfig
234 getSchemaCatalogs = _makeGetSchemaCatalogs(
"det")
235 makeIdFactory = _makeMakeIdFactory(
"CoaddId")
238 def _makeArgumentParser(cls):
240 parser.add_id_argument(
"--id",
"deepCoadd", help=
"data ID, e.g. --id tract=12345 patch=1,2 filter=r",
241 ContainerClass=ExistingCoaddDataIdContainer)
246 @brief Initialize the task. Create the @ref SourceDetectionTask_ "detection" subtask. 248 Keyword arguments (in addition to those forwarded to CmdLineTask.__init__): 250 @param[in] schema: initial schema for the output catalog, modified-in place to include all 251 fields set by this task. If None, the source minimal schema will be used. 252 @param[in] **kwargs: keyword arguments to be passed to lsst.pipe.base.task.Task.__init__ 254 CmdLineTask.__init__(self, **kwargs)
256 schema = afwTable.SourceTable.makeMinimalSchema()
257 if self.config.doInsertFakes:
258 self.makeSubtask(
"insertFakes")
260 self.makeSubtask(
"detection", schema=self.
schema)
261 if self.config.doScaleVariance:
262 self.makeSubtask(
"scaleVariance")
266 @brief Run detection on a coadd. 268 Invokes @ref run and then uses @ref write to output the 271 @param[in] patchRef: data reference for patch 273 exposure = patchRef.get(self.config.coaddName +
"Coadd", immediate=
True)
274 expId = int(patchRef.get(self.config.coaddName +
"CoaddId"))
276 self.
write(exposure, results, patchRef)
279 def run(self, exposure, idFactory, expId):
281 @brief Run detection on an exposure. 283 First scale the variance plane to match the observed variance 284 using @ref ScaleVarianceTask. Then invoke the @ref SourceDetectionTask_ "detection" subtask to 287 @param[in,out] exposure: Exposure on which to detect (may be backround-subtracted and scaled, 288 depending on configuration). 289 @param[in] idFactory: IdFactory to set source identifiers 290 @param[in] expId: Exposure identifier (integer) for RNG seed 292 @return a pipe.base.Struct with fields 293 - sources: catalog of detections 294 - backgrounds: list of backgrounds 296 if self.config.doScaleVariance:
297 varScale = self.scaleVariance.
run(exposure.maskedImage)
298 exposure.getMetadata().add(
"variance_scale", varScale)
299 backgrounds = afwMath.BackgroundList()
300 if self.config.doInsertFakes:
301 self.insertFakes.
run(exposure, background=backgrounds)
302 table = afwTable.SourceTable.make(self.
schema, idFactory)
303 detections = self.detection.makeSourceCatalog(table, exposure, expId=expId)
304 sources = detections.sources
305 fpSets = detections.fpSets
306 if hasattr(fpSets,
"background")
and fpSets.background:
307 for bg
in fpSets.background:
308 backgrounds.append(bg)
309 return Struct(sources=sources, backgrounds=backgrounds)
311 def write(self, exposure, results, patchRef):
313 @brief Write out results from runDetection. 315 @param[in] exposure: Exposure to write out 316 @param[in] results: Struct returned from runDetection 317 @param[in] patchRef: data reference for patch 319 coaddName = self.config.coaddName +
"Coadd" 320 patchRef.put(results.backgrounds, coaddName +
"_calexp_background")
321 patchRef.put(results.sources, coaddName +
"_det")
322 patchRef.put(exposure, coaddName +
"_calexp")
329 @anchor MergeSourcesRunner_ 331 @brief Task runner for the @ref MergeSourcesTask_ "MergeSourcesTask". Required because the run method 332 requires a list of dataRefs rather than a single dataRef. 337 @brief Provide a butler to the Task constructor. 339 @param[in] parsedCmd the parsed command 340 @param[in] args tuple of a list of data references and kwargs (un-used) 341 @throws RuntimeError if both parsedCmd & args are None 343 if parsedCmd
is not None:
344 butler = parsedCmd.butler
345 elif args
is not None:
346 dataRefList, kwargs = args
347 butler = dataRefList[0].getButler()
349 raise RuntimeError(
"Neither parsedCmd or args specified")
350 return self.TaskClass(config=self.config, log=self.log, butler=butler)
355 @brief Provide a list of patch references for each patch. 357 The patch references within the list will have different filters. 359 @param[in] parsedCmd the parsed command 360 @param **kwargs key word arguments (unused) 361 @throws RuntimeError if multiple references are provided for the same combination of tract, patch and 365 for ref
in parsedCmd.id.refList:
366 tract = ref.dataId[
"tract"]
367 patch = ref.dataId[
"patch"]
368 filter = ref.dataId[
"filter"]
369 if tract
not in refList:
371 if patch
not in refList[tract]:
372 refList[tract][patch] = {}
373 if filter
in refList[tract][patch]:
374 raise RuntimeError(
"Multiple versions of %s" % (ref.dataId,))
375 refList[tract][patch][filter] = ref
376 return [(list(p.values()), kwargs)
for t
in refList.values()
for p
in t.values()]
381 @anchor MergeSourcesConfig_ 383 @brief Configuration for merging sources. 385 priorityList = ListField(dtype=str, default=[],
386 doc=
"Priority-ordered list of bands for the merge.")
387 coaddName = Field(dtype=str, default=
"deep", doc=
"Name of coadd")
390 Config.validate(self)
392 raise RuntimeError(
"No priority list provided")
397 @anchor MergeSourcesTask_ 399 @brief A base class for merging source catalogs. 401 Merging detections (MergeDetectionsTask) and merging measurements (MergeMeasurementsTask) are 402 so similar that it makes sense to re-use the code, in the form of this abstract base class. 404 NB: Do not use this class directly. Instead use one of the child classes that inherit from 405 MergeSourcesTask such as @ref MergeDetectionsTask_ "MergeDetectionsTask" or @ref MergeMeasurementsTask_ 406 "MergeMeasurementsTask" 408 Sub-classes should set the following class variables: 409 * `_DefaultName`: name of Task 410 * `inputDataset`: name of dataset to read 411 * `outputDataset`: name of dataset to write 412 * `getSchemaCatalogs` to the result of `_makeGetSchemaCatalogs(outputDataset)` 414 In addition, sub-classes must implement the run method. 417 ConfigClass = MergeSourcesConfig
418 RunnerClass = MergeSourcesRunner
421 getSchemaCatalogs =
None 424 def _makeArgumentParser(cls):
426 @brief Create a suitable ArgumentParser. 428 We will use the ArgumentParser to get a provide a list of data 429 references for patches; the RunnerClass will sort them into lists 430 of data references for the same patch 433 parser.add_id_argument(
"--id",
"deepCoadd_" + cls.
inputDataset,
434 ContainerClass=ExistingCoaddDataIdContainer,
435 help=
"data ID, e.g. --id tract=12345 patch=1,2 filter=g^r^i")
440 @brief Obtain the input schema either directly or froma butler reference. 442 @param[in] butler butler reference to obtain the input schema from 443 @param[in] schema the input schema 446 assert butler
is not None,
"Neither butler nor schema specified" 447 schema = butler.get(self.config.coaddName +
"Coadd_" + self.
inputDataset +
"_schema",
448 immediate=
True).schema
451 def __init__(self, butler=None, schema=None, **kwargs):
453 @brief Initialize the task. 455 Keyword arguments (in addition to those forwarded to CmdLineTask.__init__): 456 @param[in] schema the schema of the detection catalogs used as input to this one 457 @param[in] butler a butler used to read the input schema from disk, if schema is None 459 Derived classes should use the getInputSchema() method to handle the additional 460 arguments and retreive the actual input schema. 462 CmdLineTask.__init__(self, **kwargs)
466 @brief Merge coadd sources from multiple bands. Calls @ref `run` which must be defined in 467 subclasses that inherit from MergeSourcesTask. 469 @param[in] patchRefList list of data references for each filter 471 catalogs = dict(self.
readCatalog(patchRef)
for patchRef
in patchRefList)
472 mergedCatalog = self.
run(catalogs, patchRefList[0])
473 self.
write(patchRefList[0], mergedCatalog)
477 @brief Read input catalog. 479 We read the input dataset provided by the 'inputDataset' 482 @param[in] patchRef data reference for patch 483 @return tuple consisting of the filter name and the catalog 485 filterName = patchRef.dataId[
"filter"]
486 catalog = patchRef.get(self.config.coaddName +
"Coadd_" + self.
inputDataset, immediate=
True)
487 self.log.info(
"Read %d sources for filter %s: %s" % (len(catalog), filterName, patchRef.dataId))
488 return filterName, catalog
490 def run(self, catalogs, patchRef):
492 @brief Merge multiple catalogs. This function must be defined in all subclasses that inherit from 495 @param[in] catalogs dict mapping filter name to source catalog 497 @return merged catalog 499 raise NotImplementedError()
503 @brief Write the output. 505 @param[in] patchRef data reference for patch 506 @param[in] catalog catalog 508 We write as the dataset provided by the 'outputDataset' 511 patchRef.put(catalog, self.config.coaddName +
"Coadd_" + self.
outputDataset)
514 mergeDataId = patchRef.dataId.copy()
515 del mergeDataId[
"filter"]
516 self.log.info(
"Wrote merged catalog: %s" % (mergeDataId,))
520 @brief No metadata to write, and not sure how to write it for a list of dataRefs. 525 class CullPeaksConfig(Config):
527 @anchor CullPeaksConfig_ 529 @brief Configuration for culling garbage peaks after merging footprints. 531 Peaks may also be culled after detection or during deblending; this configuration object 532 only deals with culling after merging Footprints. 534 These cuts are based on three quantities: 535 - nBands: the number of bands in which the peak was detected 536 - peakRank: the position of the peak within its family, sorted from brightest to faintest. 537 - peakRankNormalized: the peak rank divided by the total number of peaks in the family. 539 The formula that identifie peaks to cull is: 541 nBands < nBandsSufficient 542 AND (rank >= rankSufficient) 543 AND (rank >= rankConsider OR rank >= rankNormalizedConsider) 545 To disable peak culling, simply set nBandsSufficient=1. 548 nBandsSufficient = RangeField(dtype=int, default=2, min=1,
549 doc=
"Always keep peaks detected in this many bands")
550 rankSufficient = RangeField(dtype=int, default=20, min=1,
551 doc=
"Always keep this many peaks in each family")
552 rankConsidered = RangeField(dtype=int, default=30, min=1,
553 doc=(
"Keep peaks with less than this rank that also match the " 554 "rankNormalizedConsidered condition."))
555 rankNormalizedConsidered = RangeField(dtype=float, default=0.7, min=0.0,
556 doc=(
"Keep peaks with less than this normalized rank that" 557 " also match the rankConsidered condition."))
562 @anchor MergeDetectionsConfig_ 564 @brief Configuration parameters for the MergeDetectionsTask. 566 minNewPeak = Field(dtype=float, default=1,
567 doc=
"Minimum distance from closest peak to create a new one (in arcsec).")
569 maxSamePeak = Field(dtype=float, default=0.3,
570 doc=
"When adding new catalogs to the merge, all peaks less than this distance " 571 " (in arcsec) to an existing peak will be flagged as detected in that catalog.")
572 cullPeaks = ConfigField(dtype=CullPeaksConfig, doc=
"Configuration for how to cull peaks.")
574 skyFilterName = Field(dtype=str, default=
"sky",
575 doc=
"Name of `filter' used to label sky objects (e.g. flag merge_peak_sky is set)\n" 576 "(N.b. should be in MergeMeasurementsConfig.pseudoFilterList)")
577 skyObjects = ConfigurableField(target=SkyObjectsTask, doc=
"Generate sky objects")
580 MergeSourcesConfig.setDefaults(self)
594 @anchor MergeDetectionsTask_ 596 @brief Merge coadd detections from multiple bands. 598 @section pipe_tasks_multiBand_Contents Contents 600 - @ref pipe_tasks_multiBand_MergeDetectionsTask_Purpose 601 - @ref pipe_tasks_multiBand_MergeDetectionsTask_Init 602 - @ref pipe_tasks_multiBand_MergeDetectionsTask_Run 603 - @ref pipe_tasks_multiBand_MergeDetectionsTask_Config 604 - @ref pipe_tasks_multiBand_MergeDetectionsTask_Debug 605 - @ref pipe_tasks_multiband_MergeDetectionsTask_Example 607 @section pipe_tasks_multiBand_MergeDetectionsTask_Purpose Description 609 Command-line task that merges sources detected in coadds of exposures obtained with different filters. 611 To perform photometry consistently across coadds in multiple filter bands, we create a master catalog of 612 sources from all bands by merging the sources (peaks & footprints) detected in each coadd, while keeping 613 track of which band each source originates in. 615 The catalog merge is performed by @ref getMergedSourceCatalog. Spurious peaks detected around bright 616 objects are culled as described in @ref CullPeaksConfig_. 619 deepCoadd_det{tract,patch,filter}: SourceCatalog (only parent Footprints) 621 deepCoadd_mergeDet{tract,patch}: SourceCatalog (only parent Footprints) 625 MergeDetectionsTask subclasses @ref MergeSourcesTask_ "MergeSourcesTask". 627 @section pipe_tasks_multiBand_MergeDetectionsTask_Init Task initialisation 629 @copydoc \_\_init\_\_ 631 @section pipe_tasks_multiBand_MergeDetectionsTask_Run Invoking the Task 635 @section pipe_tasks_multiBand_MergeDetectionsTask_Config Configuration parameters 637 See @ref MergeDetectionsConfig_ 639 @section pipe_tasks_multiBand_MergeDetectionsTask_Debug Debug variables 641 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag @c -d 642 to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files. 644 MergeDetectionsTask has no debug variables. 646 @section pipe_tasks_multiband_MergeDetectionsTask_Example A complete example of using MergeDetectionsTask 648 MergeDetectionsTask is meant to be run after detecting sources in coadds generated for the chosen subset 649 of the available bands. 650 The purpose of the task is to merge sources (peaks & footprints) detected in the coadds generated from the 651 chosen subset of filters. 652 Subsequent tasks in the multi-band processing procedure will deblend the generated master list of sources 653 and, eventually, perform forced photometry. 654 Command-line usage of MergeDetectionsTask expects data references for all the coadds to be processed. 655 A list of the available optional arguments can be obtained by calling mergeCoaddDetections.py with the 656 `--help` command line argument: 658 mergeCoaddDetections.py --help 661 To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we 662 will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished 663 step 5 at @ref pipeTasks_multiBand, one may merge the catalogs of sources from each coadd as follows: 665 mergeCoaddDetections.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I^HSC-R 667 This will merge the HSC-I & -R band parent source catalogs and write the results to 668 `$CI_HSC_DIR/DATA/deepCoadd-results/merged/0/5,4/mergeDet-0-5,4.fits`. 670 The next step in the multi-band processing procedure is 671 @ref MeasureMergedCoaddSourcesTask_ "MeasureMergedCoaddSourcesTask" 673 ConfigClass = MergeDetectionsConfig
674 _DefaultName =
"mergeCoaddDetections" 676 outputDataset =
"mergeDet" 677 makeIdFactory = _makeMakeIdFactory(
"MergedCoaddId")
679 def __init__(self, butler=None, schema=None, **kwargs):
681 @brief Initialize the merge detections task. 683 A @ref FootprintMergeList_ "FootprintMergeList" will be used to 684 merge the source catalogs. 686 Additional keyword arguments (forwarded to MergeSourcesTask.__init__): 687 @param[in] schema the schema of the detection catalogs used as input to this one 688 @param[in] butler a butler used to read the input schema from disk, if schema is None 689 @param[in] **kwargs keyword arguments to be passed to MergeSourcesTask.__init__ 691 The task will set its own self.schema attribute to the schema of the output merged catalog. 693 MergeSourcesTask.__init__(self, butler=butler, schema=schema, **kwargs)
694 self.makeSubtask(
"skyObjects")
698 filterNames += [self.config.skyFilterName]
701 def run(self, catalogs, patchRef):
703 @brief Merge multiple catalogs. 705 After ordering the catalogs and filters in priority order, 706 @ref getMergedSourceCatalog of the @ref FootprintMergeList_ "FootprintMergeList" created by 707 @ref \_\_init\_\_ is used to perform the actual merging. Finally, @ref cullPeaks is used to remove 708 garbage peaks detected around bright objects. 712 @param[out] mergedList 716 skyInfo =
getSkyInfo(coaddName=self.config.coaddName, patchRef=patchRef)
717 tractWcs = skyInfo.wcs
718 peakDistance = self.config.minNewPeak / tractWcs.getPixelScale().asArcseconds()
719 samePeakDistance = self.config.maxSamePeak / tractWcs.getPixelScale().asArcseconds()
722 orderedCatalogs = [catalogs[band]
for band
in self.config.priorityList
if band
in catalogs.keys()]
724 if band
in catalogs.keys()]
726 mergedList = self.
merged.getMergedSourceCatalog(orderedCatalogs, orderedBands, peakDistance,
733 skySeed = patchRef.get(self.config.coaddName +
"MergedCoaddId")
735 if skySourceFootprints:
736 key = mergedList.schema.find(
"merge_footprint_%s" % self.config.skyFilterName).key
737 for foot
in skySourceFootprints:
738 s = mergedList.addNew()
743 for record
in mergedList:
744 record.getFootprint().sortPeaks()
745 self.log.info(
"Merged to %d sources" % len(mergedList))
752 @brief Attempt to remove garbage peaks (mostly on the outskirts of large blends). 754 @param[in] catalog Source catalog 756 keys = [item.key
for item
in self.
merged.getPeakSchema().extract(
"merge_peak_*").values()]
757 assert len(keys) > 0,
"Error finding flags that associate peaks with their detection bands." 760 for parentSource
in catalog:
763 keptPeaks = parentSource.getFootprint().getPeaks()
764 oldPeaks = list(keptPeaks)
766 familySize = len(oldPeaks)
767 totalPeaks += familySize
768 for rank, peak
in enumerate(oldPeaks):
769 if ((rank < self.config.cullPeaks.rankSufficient)
or 770 (sum([peak.get(k)
for k
in keys]) >= self.config.cullPeaks.nBandsSufficient)
or 771 (rank < self.config.cullPeaks.rankConsidered
and 772 rank < self.config.cullPeaks.rankNormalizedConsidered * familySize)):
773 keptPeaks.append(peak)
776 self.log.info(
"Culled %d of %d peaks" % (culledPeaks, totalPeaks))
780 Return a dict of empty catalogs for each catalog dataset produced by this task. 782 @param[out] dictionary of empty catalogs 784 mergeDet = afwTable.SourceCatalog(self.
schema)
785 peak = afwDetect.PeakCatalog(self.
merged.getPeakSchema())
786 return {self.config.coaddName +
"Coadd_mergeDet": mergeDet,
787 self.config.coaddName +
"Coadd_peak": peak}
791 @brief Return a list of Footprints of sky objects which don't overlap with anything in mergedList 793 @param mergedList The merged Footprints from all the input bands 794 @param skyInfo A description of the patch 795 @param seed Seed for the random number generator 797 mask = afwImage.Mask(skyInfo.patchInfo.getOuterBBox())
798 detected = mask.getPlaneBitMask(
"DETECTED")
800 s.getFootprint().spans.setMask(mask, detected)
802 footprints = self.skyObjects.
run(mask, seed)
807 schema = self.
merged.getPeakSchema()
808 mergeKey = schema.find(
"merge_peak_%s" % self.config.skyFilterName).key
810 for oldFoot
in footprints:
811 assert len(oldFoot.getPeaks()) == 1,
"Should be a single peak only" 812 peak = oldFoot.getPeaks()[0]
813 newFoot = afwDetect.Footprint(oldFoot.spans, schema)
814 newFoot.addPeak(peak.getFx(), peak.getFy(), peak.getPeakValue())
815 newFoot.getPeaks()[0].set(mergeKey,
True)
816 converted.append(newFoot)
823 @anchor MeasureMergedCoaddSourcesConfig_ 825 @brief Configuration parameters for the MeasureMergedCoaddSourcesTask 827 doDeblend = Field(dtype=bool, default=
True, doc=
"Deblend sources?")
828 deblend = ConfigurableField(target=SourceDeblendTask, doc=
"Deblend sources")
829 measurement = ConfigurableField(target=SingleFrameMeasurementTask, doc=
"Source measurement")
830 setPrimaryFlags = ConfigurableField(target=SetPrimaryFlagsTask, doc=
"Set flags for primary tract/patch")
831 doPropagateFlags = Field(
832 dtype=bool, default=
True,
833 doc=
"Whether to match sources to CCD catalogs to propagate flags (to e.g. identify PSF stars)" 835 propagateFlags = ConfigurableField(target=PropagateVisitFlagsTask, doc=
"Propagate visit flags to coadd")
836 doMatchSources = Field(dtype=bool, default=
True, doc=
"Match sources to reference catalog?")
837 match = ConfigurableField(target=DirectMatchTask, doc=
"Matching to reference catalog")
838 doWriteMatchesDenormalized = Field(
841 doc=(
"Write reference matches in denormalized format? " 842 "This format uses more disk space, but is more convenient to read."),
844 coaddName = Field(dtype=str, default=
"deep", doc=
"Name of coadd")
845 checkUnitsParseStrict = Field(
846 doc=
"Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'",
853 doc=
"Apply aperture corrections" 855 applyApCorr = ConfigurableField(
856 target=ApplyApCorrTask,
857 doc=
"Subtask to apply aperture corrections" 859 doRunCatalogCalculation = Field(
862 doc=
'Run catalogCalculation task' 864 catalogCalculation = ConfigurableField(
865 target=CatalogCalculationTask,
866 doc=
"Subtask to run catalogCalculation plugins on catalog" 870 Config.setDefaults(self)
871 self.
deblend.propagateAllPeaks =
True 872 self.
measurement.plugins.names |= [
'base_InputCount',
'base_Variance']
873 self.
measurement.plugins[
'base_PixelFlags'].masksFpAnywhere = [
'CLIPPED',
'SENSOR_EDGE',
875 self.
measurement.plugins[
'base_PixelFlags'].masksFpCenter = [
'CLIPPED',
'SENSOR_EDGE',
887 """Get the psfCache setting into MeasureMergedCoaddSourcesTask""" 890 return ButlerInitializedTaskRunner.getTargetList(parsedCmd, psfCache=parsedCmd.psfCache)
895 @anchor MeasureMergedCoaddSourcesTask_ 897 @brief Deblend sources from master catalog in each coadd seperately and measure. 899 @section pipe_tasks_multiBand_Contents Contents 901 - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Purpose 902 - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Initialize 903 - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Run 904 - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Config 905 - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Debug 906 - @ref pipe_tasks_multiband_MeasureMergedCoaddSourcesTask_Example 908 @section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Purpose Description 910 Command-line task that uses peaks and footprints from a master catalog to perform deblending and 911 measurement in each coadd. 913 Given a master input catalog of sources (peaks and footprints), deblend and measure each source on the 914 coadd. Repeating this procedure with the same master catalog across multiple coadds will generate a 915 consistent set of child sources. 917 The deblender retains all peaks and deblends any missing peaks (dropouts in that band) as PSFs. Source 918 properties are measured and the @c is-primary flag (indicating sources with no children) is set. Visit 919 flags are propagated to the coadd sources. 921 Optionally, we can match the coadd sources to an external reference catalog. 924 deepCoadd_mergeDet{tract,patch}: SourceCatalog 925 @n deepCoadd_calexp{tract,patch,filter}: ExposureF 927 deepCoadd_meas{tract,patch,filter}: SourceCatalog 931 MeasureMergedCoaddSourcesTask delegates most of its work to a set of sub-tasks: 934 <DT> @ref SourceDeblendTask_ "deblend" 935 <DD> Deblend all the sources from the master catalog.</DD> 936 <DT> @ref SingleFrameMeasurementTask_ "measurement" 937 <DD> Measure source properties of deblended sources.</DD> 938 <DT> @ref SetPrimaryFlagsTask_ "setPrimaryFlags" 939 <DD> Set flag 'is-primary' as well as related flags on sources. 'is-primary' is set for sources that are 940 not at the edge of the field and that have either not been deblended or are the children of deblended 942 <DT> @ref PropagateVisitFlagsTask_ "propagateFlags" 943 <DD> Propagate flags set in individual visits to the coadd.</DD> 944 <DT> @ref DirectMatchTask_ "match" 945 <DD> Match input sources to a reference catalog (optional). 948 These subtasks may be retargeted as required. 950 @section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Initialize Task initialization 952 @copydoc \_\_init\_\_ 954 @section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Run Invoking the Task 958 @section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Config Configuration parameters 960 See @ref MeasureMergedCoaddSourcesConfig_ 962 @section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Debug Debug variables 964 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 965 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py 968 MeasureMergedCoaddSourcesTask has no debug variables of its own because it delegates all the work to 969 the various sub-tasks. See the documetation for individual sub-tasks for more information. 971 @section pipe_tasks_multiband_MeasureMergedCoaddSourcesTask_Example A complete example of using 972 MeasureMergedCoaddSourcesTask 974 After MeasureMergedCoaddSourcesTask has been run on multiple coadds, we have a set of per-band catalogs. 975 The next stage in the multi-band processing procedure will merge these measurements into a suitable 976 catalog for driving forced photometry. 978 Command-line usage of MeasureMergedCoaddSourcesTask expects a data reference to the coadds 980 A list of the available optional arguments can be obtained by calling measureCoaddSources.py with the 981 `--help` command line argument: 983 measureCoaddSources.py --help 986 To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we 987 will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished 988 step 6 at @ref pipeTasks_multiBand, one may perform deblending and measure sources in the HSC-I band 991 measureCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I 993 This will process the HSC-I band data. The results are written in 994 `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I/0/5,4/meas-HSC-I-0-5,4.fits 996 It is also necessary to run 998 measureCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R 1000 to generate the sources catalogs for the HSC-R band required by the next step in the multi-band 1001 procedure: @ref MergeMeasurementsTask_ "MergeMeasurementsTask". 1003 _DefaultName =
"measureCoaddSources" 1004 ConfigClass = MeasureMergedCoaddSourcesConfig
1005 RunnerClass = MeasureMergedCoaddSourcesRunner
1006 getSchemaCatalogs = _makeGetSchemaCatalogs(
"meas")
1007 makeIdFactory = _makeMakeIdFactory(
"MergedCoaddId")
1010 def _makeArgumentParser(cls):
1012 parser.add_id_argument(
"--id",
"deepCoadd_calexp",
1013 help=
"data ID, e.g. --id tract=12345 patch=1,2 filter=r",
1014 ContainerClass=ExistingCoaddDataIdContainer)
1015 parser.add_argument(
"--psfCache", type=int, default=100, help=
"Size of CoaddPsf cache")
1018 def __init__(self, butler=None, schema=None, peakSchema=None, refObjLoader=None, **kwargs):
1020 @brief Initialize the task. 1022 Keyword arguments (in addition to those forwarded to CmdLineTask.__init__): 1023 @param[in] schema: the schema of the merged detection catalog used as input to this one 1024 @param[in] peakSchema: the schema of the PeakRecords in the Footprints in the merged detection catalog 1025 @param[in] refObjLoader: an instance of LoadReferenceObjectsTasks that supplies an external reference 1026 catalog. May be None if the loader can be constructed from the butler argument or all steps 1027 requiring a reference catalog are disabled. 1028 @param[in] butler: a butler used to read the input schemas from disk or construct the reference 1029 catalog loader, if schema or peakSchema or refObjLoader is None 1031 The task will set its own self.schema attribute to the schema of the output measurement catalog. 1032 This will include all fields from the input schema, as well as additional fields for all the 1035 CmdLineTask.__init__(self, **kwargs)
1037 assert butler
is not None,
"Neither butler nor schema is defined" 1038 schema = butler.get(self.config.coaddName +
"Coadd_mergeDet_schema", immediate=
True).schema
1043 if self.config.doDeblend:
1044 if peakSchema
is None:
1045 assert butler
is not None,
"Neither butler nor peakSchema is defined" 1046 peakSchema = butler.get(self.config.coaddName +
"Coadd_peak_schema", immediate=
True).schema
1047 self.makeSubtask(
"deblend", schema=self.
schema, peakSchema=peakSchema)
1048 self.makeSubtask(
"measurement", schema=self.
schema, algMetadata=self.
algMetadata)
1049 self.makeSubtask(
"setPrimaryFlags", schema=self.
schema)
1050 if self.config.doMatchSources:
1051 if refObjLoader
is None:
1052 assert butler
is not None,
"Neither butler nor refObjLoader is defined" 1053 self.makeSubtask(
"match", butler=butler, refObjLoader=refObjLoader)
1054 if self.config.doPropagateFlags:
1055 self.makeSubtask(
"propagateFlags", schema=self.
schema)
1056 self.
schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
1057 if self.config.doApCorr:
1058 self.makeSubtask(
"applyApCorr", schema=self.
schema)
1059 if self.config.doRunCatalogCalculation:
1060 self.makeSubtask(
"catalogCalculation", schema=self.
schema)
1064 @brief Deblend and measure. 1066 @param[in] patchRef: Patch reference. 1068 Deblend each source in every coadd and measure. Set 'is-primary' and related flags. Propagate flags 1069 from individual visits. Optionally match the sources to a reference catalog and write the matches. 1070 Finally, write the deblended sources and measurements out. 1072 exposure = patchRef.get(self.config.coaddName +
"Coadd_calexp", immediate=
True)
1073 exposure.getPsf().setCacheCapacity(psfCache)
1075 if self.config.doDeblend:
1076 self.deblend.run(exposure, sources)
1078 bigKey = sources.schema[
"deblend_parentTooBig"].asKey()
1080 numBig = sum((s.get(bigKey)
for s
in sources))
1082 self.log.warn(
"Patch %s contains %d large footprints that were not deblended" %
1083 (patchRef.dataId, numBig))
1085 table = sources.getTable()
1088 self.measurement.run(sources, exposure, exposureId=self.
getExposureId(patchRef))
1090 if self.config.doApCorr:
1091 self.applyApCorr.run(
1093 apCorrMap=exposure.getInfo().getApCorrMap()
1100 if not sources.isContiguous():
1101 sources = sources.copy(deep=
True)
1103 if self.config.doRunCatalogCalculation:
1104 self.catalogCalculation.run(sources)
1106 skyInfo =
getSkyInfo(coaddName=self.config.coaddName, patchRef=patchRef)
1107 self.setPrimaryFlags.run(sources, skyInfo.skyMap, skyInfo.tractInfo, skyInfo.patchInfo,
1108 includeDeblend=self.config.doDeblend)
1109 if self.config.doPropagateFlags:
1110 self.propagateFlags.run(patchRef.getButler(), sources, self.propagateFlags.getCcdInputs(exposure),
1112 if self.config.doMatchSources:
1114 self.
write(patchRef, sources)
1118 @brief Read input sources. 1120 @param[in] dataRef: Data reference for catalog of merged detections 1121 @return List of sources in merged catalog 1123 We also need to add columns to hold the measurements we're about to make 1124 so we can measure in-place. 1126 merged = dataRef.get(self.config.coaddName +
"Coadd_mergeDet", immediate=
True)
1127 self.log.info(
"Read %d detections: %s" % (len(merged), dataRef.dataId))
1130 idFactory.notify(s.getId())
1131 table = afwTable.SourceTable.make(self.
schema, idFactory)
1132 sources = afwTable.SourceCatalog(table)
1138 @brief Write matches of the sources to the astrometric reference catalog. 1140 We use the Wcs in the exposure to match sources. 1142 @param[in] dataRef: data reference 1143 @param[in] exposure: exposure with Wcs 1144 @param[in] sources: source catalog 1146 result = self.match.run(sources, exposure.getInfo().getFilter().getName())
1148 matches = afwTable.packMatches(result.matches)
1149 matches.table.setMetadata(result.matchMeta)
1150 dataRef.put(matches, self.config.coaddName +
"Coadd_measMatch")
1151 if self.config.doWriteMatchesDenormalized:
1152 denormMatches = denormalizeMatches(result.matches, result.matchMeta)
1153 dataRef.put(denormMatches, self.config.coaddName +
"Coadd_measMatchFull")
1157 @brief Write the source catalog. 1159 @param[in] dataRef: data reference 1160 @param[in] sources: source catalog 1162 dataRef.put(sources, self.config.coaddName +
"Coadd_meas")
1163 self.log.info(
"Wrote %d sources: %s" % (len(sources), dataRef.dataId))
1166 return int(dataRef.get(self.config.coaddName +
"CoaddId"))
1171 @anchor MergeMeasurementsConfig_ 1173 @brief Configuration parameters for the MergeMeasurementsTask 1175 pseudoFilterList = ListField(dtype=str, default=[
"sky"],
1176 doc=
"Names of filters which may have no associated detection\n" 1177 "(N.b. should include MergeDetectionsConfig.skyFilterName)")
1178 snName = Field(dtype=str, default=
"base_PsfFlux",
1179 doc=
"Name of flux measurement for calculating the S/N when choosing the reference band.")
1180 minSN = Field(dtype=float, default=10.,
1181 doc=
"If the S/N from the priority band is below this value (and the S/N " 1182 "is larger than minSNDiff compared to the priority band), use the band with " 1183 "the largest S/N as the reference band.")
1184 minSNDiff = Field(dtype=float, default=3.,
1185 doc=
"If the difference in S/N between another band and the priority band is larger " 1186 "than this value (and the S/N in the priority band is less than minSN) " 1187 "use the band with the largest S/N as the reference band")
1188 flags = ListField(dtype=str, doc=
"Require that these flags, if available, are not set",
1189 default=[
"base_PixelFlags_flag_interpolatedCenter",
"base_PsfFlux_flag",
1190 "ext_photometryKron_KronFlux_flag",
"modelfit_CModel_flag", ])
1202 @anchor MergeMeasurementsTask_ 1204 @brief Merge measurements from multiple bands 1206 @section pipe_tasks_multiBand_Contents Contents 1208 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Purpose 1209 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Initialize 1210 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Run 1211 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Config 1212 - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Debug 1213 - @ref pipe_tasks_multiband_MergeMeasurementsTask_Example 1215 @section pipe_tasks_multiBand_MergeMeasurementsTask_Purpose Description 1217 Command-line task that merges measurements from multiple bands. 1219 Combines consistent (i.e. with the same peaks and footprints) catalogs of sources from multiple filter 1220 bands to construct a unified catalog that is suitable for driving forced photometry. Every source is 1221 required to have centroid, shape and flux measurements in each band. 1224 deepCoadd_meas{tract,patch,filter}: SourceCatalog 1226 deepCoadd_ref{tract,patch}: SourceCatalog 1230 MergeMeasurementsTask subclasses @ref MergeSourcesTask_ "MergeSourcesTask". 1232 @section pipe_tasks_multiBand_MergeMeasurementsTask_Initialize Task initialization 1234 @copydoc \_\_init\_\_ 1236 @section pipe_tasks_multiBand_MergeMeasurementsTask_Run Invoking the Task 1240 @section pipe_tasks_multiBand_MergeMeasurementsTask_Config Configuration parameters 1242 See @ref MergeMeasurementsConfig_ 1244 @section pipe_tasks_multiBand_MergeMeasurementsTask_Debug Debug variables 1246 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 1247 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py 1250 MergeMeasurementsTask has no debug variables. 1252 @section pipe_tasks_multiband_MergeMeasurementsTask_Example A complete example 1253 of using MergeMeasurementsTask 1255 MergeMeasurementsTask is meant to be run after deblending & measuring sources in every band. 1256 The purpose of the task is to generate a catalog of sources suitable for driving forced photometry in 1257 coadds and individual exposures. 1258 Command-line usage of MergeMeasurementsTask expects a data reference to the coadds to be processed. A list 1259 of the available optional arguments can be obtained by calling mergeCoaddMeasurements.py with the `--help` 1260 command line argument: 1262 mergeCoaddMeasurements.py --help 1265 To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we 1266 will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished 1267 step 7 at @ref pipeTasks_multiBand, one may merge the catalogs generated after deblending and measuring 1270 mergeCoaddMeasurements.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I^HSC-R 1272 This will merge the HSC-I & HSC-R band catalogs. The results are written in 1273 `$CI_HSC_DIR/DATA/deepCoadd-results/`. 1275 _DefaultName =
"mergeCoaddMeasurements" 1276 ConfigClass = MergeMeasurementsConfig
1277 inputDataset =
"meas" 1278 outputDataset =
"ref" 1279 getSchemaCatalogs = _makeGetSchemaCatalogs(
"ref")
1281 def __init__(self, butler=None, schema=None, **kwargs):
1283 Initialize the task. 1285 Additional keyword arguments (forwarded to MergeSourcesTask.__init__): 1286 @param[in] schema: the schema of the detection catalogs used as input to this one 1287 @param[in] butler: a butler used to read the input schema from disk, if schema is None 1289 The task will set its own self.schema attribute to the schema of the output merged catalog. 1291 MergeSourcesTask.__init__(self, butler=butler, schema=schema, **kwargs)
1295 self.
fluxKey = inputSchema.find(self.config.snName +
"_flux").getKey()
1296 self.
fluxErrKey = inputSchema.find(self.config.snName +
"_fluxErr").getKey()
1297 self.
fluxFlagKey = inputSchema.find(self.config.snName +
"_flag").getKey()
1300 for band
in self.config.priorityList:
1302 outputKey = self.
schemaMapper.editOutputSchema().addField(
1303 "merge_measurement_%s" % short,
1305 doc=
"Flag field set if the measurements here are from the %s filter" % band
1307 peakKey = inputSchema.find(
"merge_peak_%s" % short).key
1308 footprintKey = inputSchema.find(
"merge_footprint_%s" % short).key
1309 self.
flagKeys[band] = Struct(peak=peakKey, footprint=footprintKey, output=outputKey)
1313 for filt
in self.config.pseudoFilterList:
1316 except Exception
as e:
1317 self.log.warn(
"merge_peak is not set for pseudo-filter %s: %s" % (filt, e))
1320 for flag
in self.config.flags:
1323 except KeyError
as exc:
1324 self.log.warn(
"Can't find flag %s in schema: %s" % (flag, exc,))
1326 def run(self, catalogs, patchRef):
1328 Merge measurement catalogs to create a single reference catalog for forced photometry 1330 @param[in] catalogs: the catalogs to be merged 1331 @param[in] patchRef: patch reference for data 1333 For parent sources, we choose the first band in config.priorityList for which the 1334 merge_footprint flag for that band is is True. 1336 For child sources, the logic is the same, except that we use the merge_peak flags. 1339 orderedCatalogs = [catalogs[band]
for band
in self.config.priorityList
if band
in catalogs.keys()]
1340 orderedKeys = [self.
flagKeys[band]
for band
in self.config.priorityList
if band
in catalogs.keys()]
1342 mergedCatalog = afwTable.SourceCatalog(self.
schema)
1343 mergedCatalog.reserve(len(orderedCatalogs[0]))
1345 idKey = orderedCatalogs[0].table.getIdKey()
1346 for catalog
in orderedCatalogs[1:]:
1347 if numpy.any(orderedCatalogs[0].get(idKey) != catalog.get(idKey)):
1348 raise ValueError(
"Error in inputs to MergeCoaddMeasurements: source IDs do not match")
1352 for orderedRecords
in zip(*orderedCatalogs):
1355 maxSNFlagKeys =
None 1357 priorityRecord =
None 1358 priorityFlagKeys =
None 1360 hasPseudoFilter =
False 1364 for inputRecord, flagKeys
in zip(orderedRecords, orderedKeys):
1365 parent = (inputRecord.getParent() == 0
and inputRecord.get(flagKeys.footprint))
1366 child = (inputRecord.getParent() != 0
and inputRecord.get(flagKeys.peak))
1368 if not (parent
or child):
1370 if inputRecord.get(pseudoFilterKey):
1371 hasPseudoFilter =
True 1372 priorityRecord = inputRecord
1373 priorityFlagKeys = flagKeys
1378 isBad = any(inputRecord.get(flag)
for flag
in self.
badFlags)
1383 if numpy.isnan(sn)
or sn < 0.:
1385 if (parent
or child)
and priorityRecord
is None:
1386 priorityRecord = inputRecord
1387 priorityFlagKeys = flagKeys
1390 maxSNRecord = inputRecord
1391 maxSNFlagKeys = flagKeys
1404 bestRecord = priorityRecord
1405 bestFlagKeys = priorityFlagKeys
1406 elif (prioritySN < self.config.minSN
and (maxSN - prioritySN) > self.config.minSNDiff
and 1407 maxSNRecord
is not None):
1408 bestRecord = maxSNRecord
1409 bestFlagKeys = maxSNFlagKeys
1410 elif priorityRecord
is not None:
1411 bestRecord = priorityRecord
1412 bestFlagKeys = priorityFlagKeys
1414 if bestRecord
is not None and bestFlagKeys
is not None:
1415 outputRecord = mergedCatalog.addNew()
1417 outputRecord.set(bestFlagKeys.output,
True)
1419 raise ValueError(
"Error in inputs to MergeCoaddMeasurements: no valid reference for %s" %
1420 inputRecord.getId())
1423 for inputCatalog
in orderedCatalogs:
1424 if len(mergedCatalog) != len(inputCatalog):
1425 raise ValueError(
"Mismatch between catalog sizes: %s != %s" %
1426 (len(mergedCatalog), len(orderedCatalogs)))
1428 return mergedCatalog
def getSkySourceFootprints(self, mergedList, skyInfo, seed)
Return a list of Footprints of sky objects which don't overlap with anything in mergedList.
Merge coadd detections from multiple bands.
def makeTask(self, parsedCmd=None, args=None)
Provide a butler to the Task constructor.
def getInputSchema(self, butler=None, schema=None)
Obtain the input schema either directly or froma butler reference.
def getSchemaCatalogs(self)
Return a dict of empty catalogs for each catalog dataset produced by this task.
def runDataRef(self, patchRefList)
Merge coadd sources from multiple bands.
def runDataRef(self, patchRef)
Run detection on a coadd.
def cullPeaks(self, catalog)
Attempt to remove garbage peaks (mostly on the outskirts of large blends).
Task runner for the MergeSourcesTask. Required because the run method requires a list of dataRefs rat...
def write(self, exposure, results, patchRef)
Write out results from runDetection.
def __init__(self, butler=None, schema=None, kwargs)
Initialize the task.
def __init__(self, butler=None, schema=None, kwargs)
Initialize the task.
Configuration parameters for the DetectCoaddSourcesTask.
def __init__(self, schema=None, kwargs)
Initialize the task.
Merge measurements from multiple bands.
Deblend sources from master catalog in each coadd seperately and measure.
def writeMatches(self, dataRef, exposure, sources)
Write matches of the sources to the astrometric reference catalog.
def getShortFilterName(name)
Configuration parameters for the MergeMeasurementsTask.
def readSources(self, dataRef)
Read input sources.
def getExposureId(self, dataRef)
Configuration parameters for the MergeDetectionsTask.
Configuration for merging sources.
def run(self, catalogs, patchRef)
Merge measurement catalogs to create a single reference catalog for forced photometry.
def run(self, catalogs, patchRef)
Merge multiple catalogs.
def write(self, patchRef, catalog)
Write the output.
A base class for merging source catalogs.
def write(self, dataRef, sources)
Write the source catalog.
def readCatalog(self, patchRef)
Read input catalog.
def getTargetList(parsedCmd, kwargs)
Configuration parameters for the MeasureMergedCoaddSourcesTask.
def getSkyInfo(coaddName, patchRef)
Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded...
def writeMetadata(self, dataRefList)
No metadata to write, and not sure how to write it for a list of dataRefs.
def __init__(self, butler=None, schema=None, peakSchema=None, refObjLoader=None, kwargs)
Initialize the task.
def run(self, exposure, idFactory, expId)
Run detection on an exposure.
Detect sources on a coadd.
def runDataRef(self, patchRef, psfCache=100)
Deblend and measure.
def __init__(self, butler=None, schema=None, kwargs)
Initialize the merge detections task.
def run(self, catalogs, patchRef)
Merge multiple catalogs.
def getTargetList(parsedCmd, kwargs)
Provide a list of patch references for each patch.