Coverage for python/lsst/pipe/tasks/multiBand.py : 76%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/env python # # LSST Data Management System # Copyright 2008-2015 AURA/LSST. # # This product includes software developed by the # LSST Project (http://www.lsst.org/). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the LSST License Statement and # the GNU General Public License along with this program. If not, # see <https://www.lsstcorp.org/LegalNotices/>. #
PipelineTask, InitOutputDatasetField, InputDatasetField, OutputDatasetField, QuantumConfig)
""" New dataset types: * deepCoadd_det: detections from what used to be processCoadd (tract, patch, filter) * deepCoadd_mergeDet: merged detections (tract, patch) * deepCoadd_meas: measurements of merged detections (tract, patch, filter) * deepCoadd_ref: reference sources (tract, patch) All of these have associated *_schema catalogs that require no data ID and hold no records.
In addition, we have a schema-only dataset, which saves the schema for the PeakRecords in the mergeDet, meas, and ref dataset Footprints: * deepCoadd_peak_schema """
"""Construct a getSchemaCatalogs instance method
These are identical for most of the classes here, so we'll consolidate the code.
datasetSuffix: Suffix of dataset name, e.g., "src" for "deepCoadd_src" """
"""Return a dict of empty catalogs for each catalog dataset produced by this task."""
"""Construct a makeIdFactory instance method
These are identical for all the classes here, so this consolidates the code.
datasetName: Dataset name without the coadd name prefix, e.g., "CoaddId" for "deepCoaddId" """
"""Return an IdFactory for setting the detection identifiers
The actual parameters used in the IdFactory are provided by the butler (through the provided data reference. """
"""Given a longer, camera-specific filter name (e.g. "HSC-I") return its shorthand name ("i"). """ # I'm not sure if this is the way this is supposed to be implemented, but it seems to work, # and its the only way I could get it to work.
##############################################################################################################
"""! @anchor DetectCoaddSourcesConfig_
@brief Configuration parameters for the DetectCoaddSourcesTask """ doc="Run fake sources injection task") doc="Injection of fake sources for testing " "purposes (must be retargeted)") doc="Schema of the detection catalog", name="{}Coadd_det_schema", storageClass="SourceCatalog", ) doc="Exposure on which detections are to be performed", name="deepCoadd", scalar=True, storageClass="Exposure", units=("Tract", "Patch", "AbstractFilter", "SkyMap") ) doc="Output Backgrounds used in detection", name="{}Coadd_calexp_background", scalar=True, storageClass="Background", units=("Tract", "Patch", "AbstractFilter", "SkyMap") ) doc="Detected sources catalog", name="{}Coadd_det", scalar=True, storageClass="SourceCatalog", units=("Tract", "Patch", "AbstractFilter", "SkyMap") ) doc="Exposure post detection", name="{}Coadd_calexp", scalar=True, storageClass="Exposure", units=("Tract", "Patch", "AbstractFilter", "SkyMap") ) units=("Tract", "Patch", "AbstractFilter", "SkyMap") )
# Coadds are made from background-subtracted CCDs, so any background subtraction should be very basic
## @addtogroup LSST_task_documentation ## @{ ## @page DetectCoaddSourcesTask ## @ref DetectCoaddSourcesTask_ "DetectCoaddSourcesTask" ## @copybrief DetectCoaddSourcesTask ## @}
"""! @anchor DetectCoaddSourcesTask_
@brief Detect sources on a coadd
@section pipe_tasks_multiBand_Contents Contents
- @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Purpose - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Initialize - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Run - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Config - @ref pipe_tasks_multiBand_DetectCoaddSourcesTask_Debug - @ref pipe_tasks_multiband_DetectCoaddSourcesTask_Example
@section pipe_tasks_multiBand_DetectCoaddSourcesTask_Purpose Description
Command-line task that detects sources on a coadd of exposures obtained with a single filter.
Coadding individual visits requires each exposure to be warped. This introduces covariance in the noise properties across pixels. Before detection, we correct the coadd variance by scaling the variance plane in the coadd to match the observed variance. This is an approximate approach -- strictly, we should propagate the full covariance matrix -- but it is simple and works well in practice.
After scaling the variance plane, we detect sources and generate footprints by delegating to the @ref SourceDetectionTask_ "detection" subtask.
@par Inputs: deepCoadd{tract,patch,filter}: ExposureF @par Outputs: deepCoadd_det{tract,patch,filter}: SourceCatalog (only parent Footprints) @n deepCoadd_calexp{tract,patch,filter}: Variance scaled, background-subtracted input exposure (ExposureF) @n deepCoadd_calexp_background{tract,patch,filter}: BackgroundList @par Data Unit: tract, patch, filter
DetectCoaddSourcesTask delegates most of its work to the @ref SourceDetectionTask_ "detection" subtask. You can retarget this subtask if you wish.
@section pipe_tasks_multiBand_DetectCoaddSourcesTask_Initialize Task initialization
@copydoc \_\_init\_\_
@section pipe_tasks_multiBand_DetectCoaddSourcesTask_Run Invoking the Task
@copydoc run
@section pipe_tasks_multiBand_DetectCoaddSourcesTask_Config Configuration parameters
See @ref DetectCoaddSourcesConfig_ "DetectSourcesConfig"
@section pipe_tasks_multiBand_DetectCoaddSourcesTask_Debug Debug variables
The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files.
DetectCoaddSourcesTask has no debug variables of its own because it relegates all the work to @ref SourceDetectionTask_ "SourceDetectionTask"; see the documetation for @ref SourceDetectionTask_ "SourceDetectionTask" for further information.
@section pipe_tasks_multiband_DetectCoaddSourcesTask_Example A complete example of using DetectCoaddSourcesTask
DetectCoaddSourcesTask is meant to be run after assembling a coadded image in a given band. The purpose of the task is to update the background, detect all sources in a single band and generate a set of parent footprints. Subsequent tasks in the multi-band processing procedure will merge sources across bands and, eventually, perform forced photometry. Command-line usage of DetectCoaddSourcesTask expects a data reference to the coadd to be processed. A list of the available optional arguments can be obtained by calling detectCoaddSources.py with the `--help` command line argument: @code detectCoaddSources.py --help @endcode
To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has followed steps 1 - 4 at @ref pipeTasks_multiBand, one may detect all the sources in each coadd as follows: @code detectCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I @endcode that will process the HSC-I band data. The results are written to `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I`.
It is also necessary to run: @code detectCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R @endcode to generate the sources catalogs for the HSC-R band required by the next step in the multi-band processing procedure: @ref MergeDetectionsTask_ "MergeDetectionsTask". """
def _makeArgumentParser(cls): parser = ArgumentParser(name=cls._DefaultName) parser.add_id_argument("--id", "deepCoadd", help="data ID, e.g. --id tract=12345 patch=1,2 filter=r", ContainerClass=ExistingCoaddDataIdContainer) return parser
def getOutputDatasetTypes(cls, config): coaddName = config.coaddName for name in ("outputBackgrounds", "outputSources", "outputExposure"): attr = getattr(config, name) setattr(attr, "name", attr.name.format(coaddName)) outputTypeDict = super().getOutputDatasetTypes(config) return outputTypeDict
def getInitOutputDatasetTypes(cls, config): coaddName = config.coaddName attr = config.detectionSchema setattr(attr, "name", attr.name.format(coaddName)) output = super().getInitOutputDatasetTypes(config) print(output) return output
"""! @brief Initialize the task. Create the @ref SourceDetectionTask_ "detection" subtask.
Keyword arguments (in addition to those forwarded to CmdLineTask.__init__):
@param[in] schema: initial schema for the output catalog, modified-in place to include all fields set by this task. If None, the source minimal schema will be used. @param[in] **kwargs: keyword arguments to be passed to lsst.pipe.base.task.Task.__init__ """ # N.B. Super is used here to handle the multiple inheritance of PipelineTasks, the init tree # call structure has been reviewed carefully to be sure super will work as intended. self.makeSubtask("insertFakes")
return {"detectionSchema": afwTable.SourceCatalog(self.schema)}
"""! @brief Run detection on a coadd.
Invokes @ref run and then uses @ref write to output the results.
@param[in] patchRef: data reference for patch """
# FINDME: DM-15843 needs to come back and address these next two lines with a final solution inputData["idFactory"] = afwTable.IdFactory.makeSimple() inputData["expId"] = 0 return self.run(**inputData)
"""! @brief Run detection on an exposure.
First scale the variance plane to match the observed variance using @ref ScaleVarianceTask. Then invoke the @ref SourceDetectionTask_ "detection" subtask to detect sources.
@param[in,out] exposure: Exposure on which to detect (may be backround-subtracted and scaled, depending on configuration). @param[in] idFactory: IdFactory to set source identifiers @param[in] expId: Exposure identifier (integer) for RNG seed
@return a pipe.base.Struct with fields - sources: catalog of detections - backgrounds: list of backgrounds """ self.insertFakes.run(exposure, background=backgrounds)
"""! @brief Write out results from runDetection.
@param[in] exposure: Exposure to write out @param[in] results: Struct returned from runDetection @param[in] patchRef: data reference for patch """
##############################################################################################################
"""Task runner for the `MergeSourcesTask`
Required because the run method requires a list of dataRefs rather than a single dataRef. """ """Provide a butler to the Task constructor.
Parameters ---------- parsedCmd: The parsed command args: tuple Tuple of a list of data references and kwargs (un-used)
Raises ------ RuntimeError Thrown if both `parsedCmd` & `args` are `None` """ if parsedCmd is not None: butler = parsedCmd.butler elif args is not None: dataRefList, kwargs = args butler = dataRefList[0].getButler() else: raise RuntimeError("Neither parsedCmd or args specified") return self.TaskClass(config=self.config, log=self.log, butler=butler)
def buildRefDict(parsedCmd): """Build a hierarchical dictionary of patch references
Parameters ---------- parsedCmd: The parsed command
Returns ------- refDict: dict A reference dictionary of the form {patch: {tract: {filter: dataRef}}}
Raises ------ RuntimeError Thrown when multiple references are provided for the same combination of tract, patch and filter """ refDict = {} # Will index this as refDict[tract][patch][filter] = ref for ref in parsedCmd.id.refList: tract = ref.dataId["tract"] patch = ref.dataId["patch"] filter = ref.dataId["filter"] if tract not in refDict: refDict[tract] = {} if patch not in refDict[tract]: refDict[tract][patch] = {} if filter in refDict[tract][patch]: raise RuntimeError("Multiple versions of %s" % (ref.dataId,)) refDict[tract][patch][filter] = ref return refDict
def getTargetList(parsedCmd, **kwargs): """Provide a list of patch references for each patch, tract, filter combo.
Parameters ---------- parsedCmd: The parsed command kwargs: Keyword arguments passed to the task
Returns ------- targetList: list List of tuples, where each tuple is a (dataRef, kwargs) pair. """ refDict = MergeSourcesRunner.buildRefDict(parsedCmd) return [(list(p.values()), kwargs) for t in refDict.values() for p in t.values()]
"""! @anchor MergeSourcesConfig_
@brief Configuration for merging sources. """ doc="Priority-ordered list of bands for the merge.")
Config.validate(self) if len(self.priorityList) == 0: raise RuntimeError("No priority list provided")
"""! @anchor MergeSourcesTask_
@brief A base class for merging source catalogs.
Merging detections (MergeDetectionsTask) and merging measurements (MergeMeasurementsTask) are so similar that it makes sense to re-use the code, in the form of this abstract base class.
NB: Do not use this class directly. Instead use one of the child classes that inherit from MergeSourcesTask such as @ref MergeDetectionsTask_ "MergeDetectionsTask" or @ref MergeMeasurementsTask_ "MergeMeasurementsTask"
Sub-classes should set the following class variables: * `_DefaultName`: name of Task * `inputDataset`: name of dataset to read * `outputDataset`: name of dataset to write * `getSchemaCatalogs` to the result of `_makeGetSchemaCatalogs(outputDataset)`
In addition, sub-classes must implement the run method. """
def _makeArgumentParser(cls): """! @brief Create a suitable ArgumentParser.
We will use the ArgumentParser to get a provide a list of data references for patches; the RunnerClass will sort them into lists of data references for the same patch """ parser = ArgumentParser(name=cls._DefaultName) parser.add_id_argument("--id", "deepCoadd_" + cls.inputDataset, ContainerClass=ExistingCoaddDataIdContainer, help="data ID, e.g. --id tract=12345 patch=1,2 filter=g^r^i") return parser
"""! @brief Obtain the input schema either directly or froma butler reference.
@param[in] butler butler reference to obtain the input schema from @param[in] schema the input schema """ immediate=True).schema
"""! @brief Initialize the task.
Keyword arguments (in addition to those forwarded to CmdLineTask.__init__): @param[in] schema the schema of the detection catalogs used as input to this one @param[in] butler a butler used to read the input schema from disk, if schema is None
Derived classes should use the getInputSchema() method to handle the additional arguments and retreive the actual input schema. """
"""! @brief Merge coadd sources from multiple bands. Calls @ref `run` which must be defined in subclasses that inherit from MergeSourcesTask.
@param[in] patchRefList list of data references for each filter """
"""! @brief Read input catalog.
We read the input dataset provided by the 'inputDataset' class variable.
@param[in] patchRef data reference for patch @return tuple consisting of the filter name and the catalog """
"""! @brief Merge multiple catalogs. This function must be defined in all subclasses that inherit from MergeSourcesTask.
@param[in] catalogs dict mapping filter name to source catalog
@return merged catalog """ raise NotImplementedError()
"""! @brief Write the output.
@param[in] patchRef data reference for patch @param[in] catalog catalog
We write as the dataset provided by the 'outputDataset' class variable. """ # since the filter isn't actually part of the data ID for the dataset we're saving, # it's confusing to see it in the log message, even if the butler simply ignores it.
"""! @brief No metadata to write, and not sure how to write it for a list of dataRefs. """ pass
"""! @anchor CullPeaksConfig_
@brief Configuration for culling garbage peaks after merging footprints.
Peaks may also be culled after detection or during deblending; this configuration object only deals with culling after merging Footprints.
These cuts are based on three quantities: - nBands: the number of bands in which the peak was detected - peakRank: the position of the peak within its family, sorted from brightest to faintest. - peakRankNormalized: the peak rank divided by the total number of peaks in the family.
The formula that identifie peaks to cull is:
nBands < nBandsSufficient AND (rank >= rankSufficient) AND (rank >= rankConsider OR rank >= rankNormalizedConsider)
To disable peak culling, simply set nBandsSufficient=1. """
doc="Always keep peaks detected in this many bands") doc="Always keep this many peaks in each family") doc=("Keep peaks with less than this rank that also match the " "rankNormalizedConsidered condition.")) doc=("Keep peaks with less than this normalized rank that" " also match the rankConsidered condition."))
"""! @anchor MergeDetectionsConfig_
@brief Configuration parameters for the MergeDetectionsTask. """ doc="Minimum distance from closest peak to create a new one (in arcsec).")
doc="When adding new catalogs to the merge, all peaks less than this distance " " (in arcsec) to an existing peak will be flagged as detected in that catalog.")
doc="Name of `filter' used to label sky objects (e.g. flag merge_peak_sky is set)\n" "(N.b. should be in MergeMeasurementsConfig.pseudoFilterList)")
## @addtogroup LSST_task_documentation ## @{ ## @page MergeDetectionsTask ## @ref MergeDetectionsTask_ "MergeDetectionsTask" ## @copybrief MergeDetectionsTask ## @}
"""! @anchor MergeDetectionsTask_
@brief Merge coadd detections from multiple bands.
@section pipe_tasks_multiBand_Contents Contents
- @ref pipe_tasks_multiBand_MergeDetectionsTask_Purpose - @ref pipe_tasks_multiBand_MergeDetectionsTask_Init - @ref pipe_tasks_multiBand_MergeDetectionsTask_Run - @ref pipe_tasks_multiBand_MergeDetectionsTask_Config - @ref pipe_tasks_multiBand_MergeDetectionsTask_Debug - @ref pipe_tasks_multiband_MergeDetectionsTask_Example
@section pipe_tasks_multiBand_MergeDetectionsTask_Purpose Description
Command-line task that merges sources detected in coadds of exposures obtained with different filters.
To perform photometry consistently across coadds in multiple filter bands, we create a master catalog of sources from all bands by merging the sources (peaks & footprints) detected in each coadd, while keeping track of which band each source originates in.
The catalog merge is performed by @ref getMergedSourceCatalog. Spurious peaks detected around bright objects are culled as described in @ref CullPeaksConfig_.
@par Inputs: deepCoadd_det{tract,patch,filter}: SourceCatalog (only parent Footprints) @par Outputs: deepCoadd_mergeDet{tract,patch}: SourceCatalog (only parent Footprints) @par Data Unit: tract, patch
MergeDetectionsTask subclasses @ref MergeSourcesTask_ "MergeSourcesTask".
@section pipe_tasks_multiBand_MergeDetectionsTask_Init Task initialisation
@copydoc \_\_init\_\_
@section pipe_tasks_multiBand_MergeDetectionsTask_Run Invoking the Task
@copydoc run
@section pipe_tasks_multiBand_MergeDetectionsTask_Config Configuration parameters
See @ref MergeDetectionsConfig_
@section pipe_tasks_multiBand_MergeDetectionsTask_Debug Debug variables
The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files.
MergeDetectionsTask has no debug variables.
@section pipe_tasks_multiband_MergeDetectionsTask_Example A complete example of using MergeDetectionsTask
MergeDetectionsTask is meant to be run after detecting sources in coadds generated for the chosen subset of the available bands. The purpose of the task is to merge sources (peaks & footprints) detected in the coadds generated from the chosen subset of filters. Subsequent tasks in the multi-band processing procedure will deblend the generated master list of sources and, eventually, perform forced photometry. Command-line usage of MergeDetectionsTask expects data references for all the coadds to be processed. A list of the available optional arguments can be obtained by calling mergeCoaddDetections.py with the `--help` command line argument: @code mergeCoaddDetections.py --help @endcode
To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished step 5 at @ref pipeTasks_multiBand, one may merge the catalogs of sources from each coadd as follows: @code mergeCoaddDetections.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I^HSC-R @endcode This will merge the HSC-I & -R band parent source catalogs and write the results to `$CI_HSC_DIR/DATA/deepCoadd-results/merged/0/5,4/mergeDet-0-5,4.fits`.
The next step in the multi-band processing procedure is @ref MeasureMergedCoaddSourcesTask_ "MeasureMergedCoaddSourcesTask" """
"""! @brief Initialize the merge detections task.
A @ref FootprintMergeList_ "FootprintMergeList" will be used to merge the source catalogs.
Additional keyword arguments (forwarded to MergeSourcesTask.__init__): @param[in] schema the schema of the detection catalogs used as input to this one @param[in] butler a butler used to read the input schema from disk, if schema is None @param[in] **kwargs keyword arguments to be passed to MergeSourcesTask.__init__
The task will set its own self.schema attribute to the schema of the output merged catalog. """
"""! @brief Merge multiple catalogs.
After ordering the catalogs and filters in priority order, @ref getMergedSourceCatalog of the @ref FootprintMergeList_ "FootprintMergeList" created by @ref \_\_init\_\_ is used to perform the actual merging. Finally, @ref cullPeaks is used to remove garbage peaks detected around bright objects.
@param[in] catalogs @param[in] patchRef @param[out] mergedList """
# Convert distance to tract coordinate
# Put catalogs, filters in priority order if band in catalogs.keys()]
self.schema, self.makeIdFactory(patchRef), samePeakDistance)
# # Add extra sources that correspond to blank sky #
# Sort Peaks from brightest to faintest # Attempt to remove garbage peaks
"""! @brief Attempt to remove garbage peaks (mostly on the outskirts of large blends).
@param[in] catalog Source catalog """ # Make a list copy so we can clear the attached PeakCatalog and append the ones we're keeping # to it (which is easier than deleting as we iterate). (sum([peak.get(k) for k in keys]) >= self.config.cullPeaks.nBandsSufficient) or (rank < self.config.cullPeaks.rankConsidered and rank < self.config.cullPeaks.rankNormalizedConsidered * familySize)): else:
"""! Return a dict of empty catalogs for each catalog dataset produced by this task.
@param[out] dictionary of empty catalogs """ self.config.coaddName + "Coadd_peak": peak}
"""! @brief Return a list of Footprints of sky objects which don't overlap with anything in mergedList
@param mergedList The merged Footprints from all the input bands @param skyInfo A description of the patch @param seed Seed for the random number generator """
return footprints
# Need to convert the peak catalog's schema so we can set the "merge_peak_<skyFilterName>" flags
"""DeblendCoaddSourcesConfig
Configuration parameters for the `DeblendCoaddSourcesTask`. """ doc="Deblend sources separately in each band") doc="Deblend sources simultaneously across bands")
"""Task runner for the `MergeSourcesTask`
Required because the run method requires a list of dataRefs rather than a single dataRef. """ def getTargetList(parsedCmd, **kwargs): """Provide a list of patch references for each patch, tract, filter combo.
Parameters ---------- parsedCmd: The parsed command kwargs: Keyword arguments passed to the task
Returns ------- targetList: list List of tuples, where each tuple is a (dataRef, kwargs) pair. """ refDict = MergeSourcesRunner.buildRefDict(parsedCmd) kwargs["psfCache"] = parsedCmd.psfCache return [(list(p.values()), kwargs) for t in refDict.values() for p in t.values()]
"""Deblend the sources in a merged catalog
Deblend sources from master catalog in each coadd. This can either be done separately in each band using the HSC-SDSS deblender (`DeblendCoaddSourcesTask.config.simultaneous==False`) or use SCARLET to simultaneously fit the blend in all bands (`DeblendCoaddSourcesTask.config.simultaneous==True`). The task will set its own `self.schema` atribute to the `Schema` of the output deblended catalog. This will include all fields from the input `Schema`, as well as additional fields from the deblender.
`pipe.tasks.multiband.DeblendCoaddSourcesTask Description --------------------------------------------------------- `
Parameters ---------- butler: `Butler` Butler used to read the input schemas from disk or construct the reference catalog loader, if `schema` or `peakSchema` or schema: `Schema` The schema of the merged detection catalog as an input to this task. peakSchema: `Schema` The schema of the `PeakRecord`s in the `Footprint`s in the merged detection catalog """
def _makeArgumentParser(cls): parser = ArgumentParser(name=cls._DefaultName) parser.add_id_argument("--id", "deepCoadd_calexp", help="data ID, e.g. --id tract=12345 patch=1,2 filter=g^r^i", ContainerClass=ExistingCoaddDataIdContainer) parser.add_argument("--psfCache", type=int, default=100, help="Size of CoaddPsf cache") return parser
self.makeSubtask("multiBandDeblend", schema=self.schema, peakSchema=peakSchema) else:
"""Return a dict of empty catalogs for each catalog dataset produced by this task.
Returns ------- result: dict Dictionary of empty catalogs, with catalog names as keys. """ self.config.coaddName + "Coadd_deblendedModel": catalog}
"""Deblend the patch
Deblend each source simultaneously or separately (depending on `DeblendCoaddSourcesTask.config.simultaneous`). Set `is-primary` and related flags. Propagate flags from individual visits. Write the deblended sources out.
Parameters ---------- patchRefList: list List of data references for each filter """ # Use SCARLET to simultaneously deblend across filters filters = [] exposures = [] for patchRef in patchRefList: exposure = patchRef.get(self.config.coaddName + "Coadd_calexp", immediate=True) filters.append(patchRef.dataId["filter"]) exposures.append(exposure) # The input sources are the same for all bands, since it is a merged catalog sources = self.readSources(patchRef) exposure = afwImage.MultibandExposure.fromExposures(filters, exposures) fluxCatalogs, templateCatalogs = self.multiBandDeblend.run(exposure, sources) for n in range(len(patchRefList)): self.write(patchRefList[n], fluxCatalogs[filters[n]], templateCatalogs[filters[n]]) else: # Use the singeband deblender to deblend each band separately
"""Read merged catalog
Read the catalog of merged detections and create a catalog in a single band.
Parameters ---------- dataRef: data reference Data reference for catalog of merged detections
Returns ------- sources: `SourceCatalog` List of sources in merged catalog
We also need to add columns to hold the measurements we're about to make so we can measure in-place. """
"""Write the source catalog(s)
Parameters ---------- dataRef: Data Reference Reference to the output catalog. flux_sources: `SourceCatalog` Flux conserved sources to write to file. If using the single band deblender, this is the catalog generated. template_sources: `SourceCatalog` Source catalog using the multiband template models as footprints. """ # The multiband deblender does not have to conserve flux, # so only write the flux conserved catalog if it exists # Only the multiband deblender has the option to output the # template model catalog, which can optionally be used # in MeasureMergedCoaddSources assert self.config.multiBandDeblend.saveTemplates dataRef.put(template_sources, self.config.coaddName + "Coadd_deblendedModel")
"""Write the metadata produced from processing the data. Parameters ---------- dataRefList List of Butler data references used to write the metadata. The metadata is written to dataset type `CmdLineTask._getMetadataName`. """ for dataRef in dataRefList: try: metadataName = self._getMetadataName() if metadataName is not None: dataRef.put(self.getFullMetadata(), metadataName) except Exception as e: self.log.warn("Could not persist metadata for dataId=%s: %s", dataRef.dataId, e)
"""Get the ExposureId from a data reference """ return int(dataRef.get(self.config.coaddName + "CoaddId"))
"""! @anchor MeasureMergedCoaddSourcesConfig_
@brief Configuration parameters for the MeasureMergedCoaddSourcesTask """ doc=("Name of the input catalog to use." "If the single band deblender was used this should be 'deblendedFlux." "If the multi-band deblender was used this should be 'deblendedModel." "If no deblending was performed this should be 'mergeDet'")) dtype=bool, default=True, doc="Whether to match sources to CCD catalogs to propagate flags (to e.g. identify PSF stars)" ) dtype=bool, default=False, doc=("Write reference matches in denormalized format? " "This format uses more disk space, but is more convenient to read."), ) doc="Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'", dtype=str, default="raise", ) dtype=bool, default=True, doc="Apply aperture corrections" ) target=ApplyApCorrTask, doc="Subtask to apply aperture corrections" ) dtype=bool, default=True, doc='Run catalogCalculation task' ) target=CatalogCalculationTask, doc="Subtask to run catalogCalculation plugins on catalog" )
'INEXACT_PSF'] 'INEXACT_PSF']
## @addtogroup LSST_task_documentation ## @{ ## @page MeasureMergedCoaddSourcesTask ## @ref MeasureMergedCoaddSourcesTask_ "MeasureMergedCoaddSourcesTask" ## @copybrief MeasureMergedCoaddSourcesTask ## @}
"""Get the psfCache setting into MeasureMergedCoaddSourcesTask""" def getTargetList(parsedCmd, **kwargs): return ButlerInitializedTaskRunner.getTargetList(parsedCmd, psfCache=parsedCmd.psfCache)
"""! @anchor MeasureMergedCoaddSourcesTask_
@brief Deblend sources from master catalog in each coadd seperately and measure.
@section pipe_tasks_multiBand_Contents Contents
- @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Purpose - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Initialize - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Run - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Config - @ref pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Debug - @ref pipe_tasks_multiband_MeasureMergedCoaddSourcesTask_Example
@section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Purpose Description
Command-line task that uses peaks and footprints from a master catalog to perform deblending and measurement in each coadd.
Given a master input catalog of sources (peaks and footprints) or deblender outputs (including a HeavyFootprint in each band), measure each source on the coadd. Repeating this procedure with the same master catalog across multiple coadds will generate a consistent set of child sources.
The deblender retains all peaks and deblends any missing peaks (dropouts in that band) as PSFs. Source properties are measured and the @c is-primary flag (indicating sources with no children) is set. Visit flags are propagated to the coadd sources.
Optionally, we can match the coadd sources to an external reference catalog.
@par Inputs: deepCoadd_mergeDet{tract,patch} or deepCoadd_deblend{tract,patch}: SourceCatalog @n deepCoadd_calexp{tract,patch,filter}: ExposureF @par Outputs: deepCoadd_meas{tract,patch,filter}: SourceCatalog @par Data Unit: tract, patch, filter
MeasureMergedCoaddSourcesTask delegates most of its work to a set of sub-tasks:
<DL> <DT> @ref SingleFrameMeasurementTask_ "measurement" <DD> Measure source properties of deblended sources.</DD> <DT> @ref SetPrimaryFlagsTask_ "setPrimaryFlags" <DD> Set flag 'is-primary' as well as related flags on sources. 'is-primary' is set for sources that are not at the edge of the field and that have either not been deblended or are the children of deblended sources</DD> <DT> @ref PropagateVisitFlagsTask_ "propagateFlags" <DD> Propagate flags set in individual visits to the coadd.</DD> <DT> @ref DirectMatchTask_ "match" <DD> Match input sources to a reference catalog (optional). </DD> </DL> These subtasks may be retargeted as required.
@section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Initialize Task initialization
@copydoc \_\_init\_\_
@section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Run Invoking the Task
@copydoc run
@section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Config Configuration parameters
See @ref MeasureMergedCoaddSourcesConfig_
@section pipe_tasks_multiBand_MeasureMergedCoaddSourcesTask_Debug Debug variables
The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files.
MeasureMergedCoaddSourcesTask has no debug variables of its own because it delegates all the work to the various sub-tasks. See the documetation for individual sub-tasks for more information.
@section pipe_tasks_multiband_MeasureMergedCoaddSourcesTask_Example A complete example of using MeasureMergedCoaddSourcesTask
After MeasureMergedCoaddSourcesTask has been run on multiple coadds, we have a set of per-band catalogs. The next stage in the multi-band processing procedure will merge these measurements into a suitable catalog for driving forced photometry.
Command-line usage of MeasureMergedCoaddSourcesTask expects a data reference to the coadds to be processed. A list of the available optional arguments can be obtained by calling measureCoaddSources.py with the `--help` command line argument: @code measureCoaddSources.py --help @endcode
To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished step 6 at @ref pipeTasks_multiBand, one may perform deblending and measure sources in the HSC-I band coadd as follows: @code measureCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I @endcode This will process the HSC-I band data. The results are written in `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I/0/5,4/meas-HSC-I-0-5,4.fits
It is also necessary to run @code measureCoaddSources.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R @endcode to generate the sources catalogs for the HSC-R band required by the next step in the multi-band procedure: @ref MergeMeasurementsTask_ "MergeMeasurementsTask". """
def _makeArgumentParser(cls): parser = ArgumentParser(name=cls._DefaultName) parser.add_id_argument("--id", "deepCoadd_calexp", help="data ID, e.g. --id tract=12345 patch=1,2 filter=r", ContainerClass=ExistingCoaddDataIdContainer) parser.add_argument("--psfCache", type=int, default=100, help="Size of CoaddPsf cache") return parser
"""! @brief Initialize the task.
Keyword arguments (in addition to those forwarded to CmdLineTask.__init__): @param[in] schema: the schema of the merged detection catalog used as input to this one @param[in] peakSchema: the schema of the PeakRecords in the Footprints in the merged detection catalog @param[in] refObjLoader: an instance of LoadReferenceObjectsTasks that supplies an external reference catalog. May be None if the loader can be constructed from the butler argument or all steps requiring a reference catalog are disabled. @param[in] butler: a butler used to read the input schemas from disk or construct the reference catalog loader, if schema or peakSchema or refObjLoader is None
The task will set its own self.schema attribute to the schema of the output measurement catalog. This will include all fields from the input schema, as well as additional fields for all the measurements. """ if refObjLoader is None: assert butler is not None, "Neither butler nor refObjLoader is defined" self.makeSubtask("match", butler=butler, refObjLoader=refObjLoader)
"""! @brief Deblend and measure.
@param[in] patchRef: Patch reference.
Set 'is-primary' and related flags. Propagate flags from individual visits. Optionally match the sources to a reference catalog and write the matches. Finally, write the deblended sources and measurements out. """
catalog=sources, apCorrMap=exposure.getInfo().getApCorrMap() )
# TODO DM-11568: this contiguous check-and-copy could go away if we # reserve enough space during SourceDetection and/or SourceDeblend. # NOTE: sourceSelectors require contiguous catalogs, so ensure # contiguity now, so views are preserved from here on. sources = sources.copy(deep=True)
includeDeblend=self.deblended) exposure.getWcs()) self.writeMatches(patchRef, exposure, sources)
"""! @brief Read input sources.
@param[in] dataRef: Data reference for catalog of merged detections @return List of sources in merged catalog
We also need to add columns to hold the measurements we're about to make so we can measure in-place. """
"""! @brief Write matches of the sources to the astrometric reference catalog.
We use the Wcs in the exposure to match sources.
@param[in] dataRef: data reference @param[in] exposure: exposure with Wcs @param[in] sources: source catalog """ result = self.match.run(sources, exposure.getInfo().getFilter().getName()) if result.matches: matches = afwTable.packMatches(result.matches) matches.table.setMetadata(result.matchMeta) dataRef.put(matches, self.config.coaddName + "Coadd_measMatch") if self.config.doWriteMatchesDenormalized: denormMatches = denormalizeMatches(result.matches, result.matchMeta) dataRef.put(denormMatches, self.config.coaddName + "Coadd_measMatchFull")
"""! @brief Write the source catalog.
@param[in] dataRef: data reference @param[in] sources: source catalog """
"""! @anchor MergeMeasurementsConfig_
@brief Configuration parameters for the MergeMeasurementsTask """ doc="Names of filters which may have no associated detection\n" "(N.b. should include MergeDetectionsConfig.skyFilterName)") doc="Name of flux measurement for calculating the S/N when choosing the reference band.") doc="If the S/N from the priority band is below this value (and the S/N " "is larger than minSNDiff compared to the priority band), use the band with " "the largest S/N as the reference band.") doc="If the difference in S/N between another band and the priority band is larger " "than this value (and the S/N in the priority band is less than minSN) " "use the band with the largest S/N as the reference band") default=["base_PixelFlags_flag_interpolatedCenter", "base_PsfFlux_flag", "ext_photometryKron_KronFlux_flag", "modelfit_CModel_flag", ])
## @addtogroup LSST_task_documentation ## @{ ## @page MergeMeasurementsTask ## @ref MergeMeasurementsTask_ "MergeMeasurementsTask" ## @copybrief MergeMeasurementsTask ## @}
"""! @anchor MergeMeasurementsTask_
@brief Merge measurements from multiple bands
@section pipe_tasks_multiBand_Contents Contents
- @ref pipe_tasks_multiBand_MergeMeasurementsTask_Purpose - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Initialize - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Run - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Config - @ref pipe_tasks_multiBand_MergeMeasurementsTask_Debug - @ref pipe_tasks_multiband_MergeMeasurementsTask_Example
@section pipe_tasks_multiBand_MergeMeasurementsTask_Purpose Description
Command-line task that merges measurements from multiple bands.
Combines consistent (i.e. with the same peaks and footprints) catalogs of sources from multiple filter bands to construct a unified catalog that is suitable for driving forced photometry. Every source is required to have centroid, shape and flux measurements in each band.
@par Inputs: deepCoadd_meas{tract,patch,filter}: SourceCatalog @par Outputs: deepCoadd_ref{tract,patch}: SourceCatalog @par Data Unit: tract, patch
MergeMeasurementsTask subclasses @ref MergeSourcesTask_ "MergeSourcesTask".
@section pipe_tasks_multiBand_MergeMeasurementsTask_Initialize Task initialization
@copydoc \_\_init\_\_
@section pipe_tasks_multiBand_MergeMeasurementsTask_Run Invoking the Task
@copydoc run
@section pipe_tasks_multiBand_MergeMeasurementsTask_Config Configuration parameters
See @ref MergeMeasurementsConfig_
@section pipe_tasks_multiBand_MergeMeasurementsTask_Debug Debug variables
The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files.
MergeMeasurementsTask has no debug variables.
@section pipe_tasks_multiband_MergeMeasurementsTask_Example A complete example of using MergeMeasurementsTask
MergeMeasurementsTask is meant to be run after deblending & measuring sources in every band. The purpose of the task is to generate a catalog of sources suitable for driving forced photometry in coadds and individual exposures. Command-line usage of MergeMeasurementsTask expects a data reference to the coadds to be processed. A list of the available optional arguments can be obtained by calling mergeCoaddMeasurements.py with the `--help` command line argument: @code mergeCoaddMeasurements.py --help @endcode
To demonstrate usage of the DetectCoaddSourcesTask in the larger context of multi-band processing, we will process HSC data in the [ci_hsc](https://github.com/lsst/ci_hsc) package. Assuming one has finished step 7 at @ref pipeTasks_multiBand, one may merge the catalogs generated after deblending and measuring as follows: @code mergeCoaddMeasurements.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I^HSC-R @endcode This will merge the HSC-I & HSC-R band catalogs. The results are written in `$CI_HSC_DIR/DATA/deepCoadd-results/`. """
"""! Initialize the task.
Additional keyword arguments (forwarded to MergeSourcesTask.__init__): @param[in] schema: the schema of the detection catalogs used as input to this one @param[in] butler: a butler used to read the input schema from disk, if schema is None
The task will set its own self.schema attribute to the schema of the output merged catalog. """
"merge_measurement_%s" % short, type="Flag", doc="Flag field set if the measurements here are from the %s filter" % band )
except Exception as e: self.log.warn("merge_peak is not set for pseudo-filter %s: %s" % (filt, e))
"""! Merge measurement catalogs to create a single reference catalog for forced photometry
@param[in] catalogs: the catalogs to be merged @param[in] patchRef: patch reference for data
For parent sources, we choose the first band in config.priorityList for which the merge_footprint flag for that band is is True.
For child sources, the logic is the same, except that we use the merge_peak flags. """ # Put catalogs, filters in priority order
if numpy.any(orderedCatalogs[0].get(idKey) != catalog.get(idKey)): raise ValueError("Error in inputs to MergeCoaddMeasurements: source IDs do not match")
# This first zip iterates over all the catalogs simultaneously, yielding a sequence of one # record for each band, in priority order.
# Now we iterate over those record-band pairs, keeping track of the priority and the # largest S/N band.
else: sn = 0.
# If the priority band has a low S/N we would like to choose the band with the highest S/N as # the reference band instead. However, we only want to choose the highest S/N band if it is # significantly better than the priority band. Therefore, to choose a band other than the # priority, we require that the priority S/N is below the minimum threshold and that the # difference between the priority and highest S/N is larger than the difference threshold. # # For pseudo code objects we always choose the first band in the priority list. maxSNRecord is not None): bestRecord = maxSNRecord bestFlagKeys = maxSNFlagKeys
else: # if we didn't find any records raise ValueError("Error in inputs to MergeCoaddMeasurements: no valid reference for %s" % inputRecord.getId())
# more checking for sane inputs, since zip silently iterates over the smallest sequence raise ValueError("Mismatch between catalog sizes: %s != %s" % (len(mergedCatalog), len(orderedCatalogs)))
|