LSST Applications g02d81e74bb+86cf3d8bc9,g180d380827+7a4e862ed4,g2079a07aa2+86d27d4dc4,g2305ad1205+e1ca1c66fa,g29320951ab+012e1474a1,g295015adf3+341ea1ce94,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+c429d67c83,g48712c4677+f88676dd22,g487adcacf7+27e1e21933,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+b41db86c35,g5a732f18d5+53520f316c,g64a986408d+86cf3d8bc9,g858d7b2824+86cf3d8bc9,g8a8a8dda67+585e252eca,g99cad8db69+84912a7fdc,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+a2b54eae19,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+6681f309db,gc120e1dc64+f0fcc2f6d8,gc28159a63d+0e5473021a,gcf0d15dbbd+c429d67c83,gdaeeff99f8+f9a426f77a,ge6526c86ff+0433e6603d,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+86cf3d8bc9,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
Classes | Functions | Variables
lsst.pipe.tasks.mergeDetections Namespace Reference

Classes

class  MergeDetectionsConnections
 

Functions

 matchCatalogsExact (catalog1, catalog2, patch1=None, patch2=None)
 

Variables

 schema : `lsst.afw.table.Schema`, optional
 
 initInputs : `dict`, optional
 
 catalogs : `lsst.afw.table.SourceCatalog`
 
 mergedList : `lsst.afw.table.SourceCatalog`
 
 result : `lsst.pipe.base.Struct`
 
 catalog : `lsst.afw.table.SourceCatalog`
 
 mergeKey = schema.find("merge_peak_%s" % self.config.skyFilterName).key
 
list converted = []
 
 peak = oldFoot.getPeaks()[0]
 
 newFoot = afwDetect.Footprint(oldFoot.spans, schema)
 

Function Documentation

◆ matchCatalogsExact()

lsst.pipe.tasks.mergeDetections.matchCatalogsExact ( catalog1,
catalog2,
patch1 = None,
patch2 = None )
Match two catalogs derived from the same mergeDet catalog.

When testing downstream features, like deblending methods/parameters
and measurement algorithms/parameters, it is useful to to compare
the same sources in two catalogs. In most cases this must be done
by matching on either RA/DEC or XY positions, which occassionally
will mismatch one source with another.

For a more robust solution, as long as the downstream catalog is
derived from the same mergeDet catalog, exact source matching
can be done via the unique ``(parent, deblend_peakID)``
combination. So this function performs this exact matching for
all sources both catalogs.

Parameters
----------
catalog1, catalog2 : `lsst.afw.table.SourceCatalog`
    The two catalogs to merge
patch1, patch2 : `array` of `int`
    Patch for each row, converted into an integer.

Returns
-------
result : `list` of `lsst.afw.table.SourceMatch`
    List of matches for each source (using an inner join).

Definition at line 42 of file mergeDetections.py.

42def matchCatalogsExact(catalog1, catalog2, patch1=None, patch2=None):
43 """Match two catalogs derived from the same mergeDet catalog.
44
45 When testing downstream features, like deblending methods/parameters
46 and measurement algorithms/parameters, it is useful to to compare
47 the same sources in two catalogs. In most cases this must be done
48 by matching on either RA/DEC or XY positions, which occassionally
49 will mismatch one source with another.
50
51 For a more robust solution, as long as the downstream catalog is
52 derived from the same mergeDet catalog, exact source matching
53 can be done via the unique ``(parent, deblend_peakID)``
54 combination. So this function performs this exact matching for
55 all sources both catalogs.
56
57 Parameters
58 ----------
59 catalog1, catalog2 : `lsst.afw.table.SourceCatalog`
60 The two catalogs to merge
61 patch1, patch2 : `array` of `int`
62 Patch for each row, converted into an integer.
63
64 Returns
65 -------
66 result : `list` of `lsst.afw.table.SourceMatch`
67 List of matches for each source (using an inner join).
68 """
69 # Only match the individual sources, the parents will
70 # already be matched by the mergeDet catalog
71 sidx1 = catalog1["parent"] != 0
72 sidx2 = catalog2["parent"] != 0
73
74 # Create the keys used to merge the catalogs
75 parents1 = np.array(catalog1["parent"][sidx1])
76 peaks1 = np.array(catalog1["deblend_peakId"][sidx1])
77 index1 = np.arange(len(catalog1))[sidx1]
78 parents2 = np.array(catalog2["parent"][sidx2])
79 peaks2 = np.array(catalog2["deblend_peakId"][sidx2])
80 index2 = np.arange(len(catalog2))[sidx2]
81
82 if patch1 is not None:
83 if patch2 is None:
84 msg = ("If the catalogs are from different patches then patch1 and patch2 must be specified"
85 ", got {} and {}").format(patch1, patch2)
86 raise ValueError(msg)
87 patch1 = patch1[sidx1]
88 patch2 = patch2[sidx2]
89
90 key1 = np.rec.array((parents1, peaks1, patch1, index1),
91 dtype=[('parent', np.int64), ('peakId', np.int32),
92 ("patch", patch1.dtype), ("index", np.int32)])
93 key2 = np.rec.array((parents2, peaks2, patch2, index2),
94 dtype=[('parent', np.int64), ('peakId', np.int32),
95 ("patch", patch2.dtype), ("index", np.int32)])
96 matchColumns = ("parent", "peakId", "patch")
97 else:
98 key1 = np.rec.array((parents1, peaks1, index1),
99 dtype=[('parent', np.int64), ('peakId', np.int32), ("index", np.int32)])
100 key2 = np.rec.array((parents2, peaks2, index2),
101 dtype=[('parent', np.int64), ('peakId', np.int32), ("index", np.int32)])
102 matchColumns = ("parent", "peakId")
103 # Match the two keys.
104 # This line performs an inner join on the structured
105 # arrays `key1` and `key2`, which stores their indices
106 # as columns in a structured array.
107 matched = rec_join(matchColumns, key1, key2, jointype="inner")
108
109 # Create the full index for both catalogs
110 indices1 = matched["index1"]
111 indices2 = matched["index2"]
112
113 # Re-index the resulting catalogs
114 matches = [
115 afwTable.SourceMatch(catalog1[int(i1)], catalog2[int(i2)], 0.0)
116 for i1, i2 in zip(indices1, indices2)
117 ]
118
119 return matches
120
121
Tag types used to declare specialized field types.
Definition misc.h:31

Variable Documentation

◆ catalog

lsst.pipe.tasks.mergeDetections.catalog : `lsst.afw.table.SourceCatalog`
# Convert distance to tract coordinate
tractWcs = skyInfo.wcs
peakDistance = self.config.minNewPeak / tractWcs.getPixelScale().asArcseconds()
samePeakDistance = self.config.maxSamePeak / tractWcs.getPixelScale().asArcseconds()

# Put catalogs, filters in priority order
orderedCatalogs = [catalogs[band] for band in self.config.priorityList if band in catalogs.keys()]
orderedBands = [band for band in self.config.priorityList if band in catalogs.keys()]

mergedList = self.merged.getMergedSourceCatalog(orderedCatalogs, orderedBands, peakDistance,
                                                self.schema, idFactory,
                                                samePeakDistance)

#
# Add extra sources that correspond to blank sky
#
skySourceFootprints = self.getSkySourceFootprints(mergedList, skyInfo, skySeed)
if skySourceFootprints:
    key = mergedList.schema.find("merge_footprint_%s" % self.config.skyFilterName).key
    for foot in skySourceFootprints:
        s = mergedList.addNew()
        s.setFootprint(foot)
        s.set(key, True)

# Sort Peaks from brightest to faintest
for record in mergedList:
    record.getFootprint().sortPeaks()
self.log.info("Merged to %d sources", len(mergedList))
# Attempt to remove garbage peaks
self.cullPeaks(mergedList)
return Struct(outputCatalog=mergedList)

def cullPeaks(self, catalog):

Definition at line 334 of file mergeDetections.py.

◆ catalogs

lsst.pipe.tasks.mergeDetections.catalogs : `lsst.afw.table.SourceCatalog`
ConfigClass = MergeDetectionsConfig
_DefaultName = "mergeCoaddDetections"

def __init__(self, schema=None, initInputs=None, **kwargs):
    super().__init__(**kwargs)

    if initInputs is not None:
        schema = initInputs['schema'].schema

    if schema is None:
        raise ValueError("No input schema or initInputs['schema'] provided.")

    self.schema = schema

    self.makeSubtask("skyObjects")

    filterNames = list(self.config.priorityList)
    filterNames.append(self.config.skyFilterName)
    self.merged = afwDetect.FootprintMergeList(self.schema, filterNames)
    self.outputSchema = afwTable.SourceCatalog(self.schema)
    self.outputPeakSchema = afwDetect.PeakCatalog(self.merged.getPeakSchema())

def runQuantum(self, butlerQC, inputRefs, outputRefs):
    inputs = butlerQC.get(inputRefs)
    idGenerator = self.config.idGenerator.apply(butlerQC.quantum.dataId)
    inputs["skySeed"] = idGenerator.catalog_id
    inputs["idFactory"] = idGenerator.make_table_id_factory()
    catalogDict = {ref.dataId['band']: cat for ref, cat in zip(inputRefs.catalogs,
                   inputs['catalogs'])}
    inputs['catalogs'] = catalogDict
    skyMap = inputs.pop('skyMap')
    # Can use the first dataId to find the tract and patch being worked on
    tractNumber = inputRefs.catalogs[0].dataId['tract']
    tractInfo = skyMap[tractNumber]
    patchInfo = tractInfo.getPatchInfo(inputRefs.catalogs[0].dataId['patch'])
    skyInfo = Struct(
        skyMap=skyMap,
        tractInfo=tractInfo,
        patchInfo=patchInfo,
        wcs=tractInfo.getWcs(),
        bbox=patchInfo.getOuterBBox()
    )
    inputs['skyInfo'] = skyInfo

    outputs = self.run(**inputs)
    butlerQC.put(outputs, outputRefs)

def run(self, catalogs, skyInfo, idFactory, skySeed):

Definition at line 284 of file mergeDetections.py.

◆ converted

list lsst.pipe.tasks.mergeDetections.converted = []

Definition at line 383 of file mergeDetections.py.

◆ initInputs

lsst.pipe.tasks.mergeDetections.initInputs : `dict`, optional

Definition at line 220 of file mergeDetections.py.

◆ mergedList

lsst.pipe.tasks.mergeDetections.mergedList : `lsst.afw.table.SourceCatalog`

Definition at line 286 of file mergeDetections.py.

◆ mergeKey

lsst.pipe.tasks.mergeDetections.mergeKey = schema.find("merge_peak_%s" % self.config.skyFilterName).key

Definition at line 382 of file mergeDetections.py.

◆ newFoot

lsst.pipe.tasks.mergeDetections.newFoot = afwDetect.Footprint(oldFoot.spans, schema)

Definition at line 387 of file mergeDetections.py.

◆ peak

lsst.pipe.tasks.mergeDetections.peak = oldFoot.getPeaks()[0]

Definition at line 386 of file mergeDetections.py.

◆ result

lsst.pipe.tasks.mergeDetections.result : `lsst.pipe.base.Struct`

Definition at line 291 of file mergeDetections.py.

◆ schema

lsst.pipe.tasks.mergeDetections.schema : `lsst.afw.table.Schema`, optional
keys = [item.key for item in self.merged.getPeakSchema().extract("merge_peak_*").values()]
assert len(keys) > 0, "Error finding flags that associate peaks with their detection bands."
totalPeaks = 0
culledPeaks = 0
for parentSource in 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).
    keptPeaks = parentSource.getFootprint().getPeaks()
    oldPeaks = list(keptPeaks)
    keptPeaks.clear()
    familySize = len(oldPeaks)
    totalPeaks += familySize
    for rank, peak in enumerate(oldPeaks):
        if ((rank < self.config.cullPeaks.rankSufficient)
            or (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)):
            keptPeaks.append(peak)
        else:
            culledPeaks += 1
self.log.info("Culled %d of %d peaks", culledPeaks, totalPeaks)

def getSkySourceFootprints(self, mergedList, skyInfo, seed):

Definition at line 218 of file mergeDetections.py.