23 """Simple association algorithm for DRP.
24 Adapted from http://github.com/LSSTDESC/dia_pipe
36 from .associationUtils
import query_disc, eq2xyz, toIndex
40 """Configuration parameters for the SimpleAssociationTask
42 tolerance = pexConfig.Field(
44 doc=
'maximum distance to match sources together in arcsec',
47 nside = pexConfig.Field(
49 doc=
'Healpix nside value used for indexing',
55 """Construct DiaObjects from a DataFrame of DIASources by spatially
56 associating the sources.
58 Represents a simple, brute force algorithm, 2-way matching of DiaSources
59 into. DiaObjects. Algorithm picks the nearest, first match within the
60 matching radius of a DiaObject to associate a source to for simplicity.
62 ConfigClass = SimpleAssociationConfig
63 _DefaultName =
"simpleAssociation"
65 def run(self, diaSources, tractPatchId, skymapBits):
66 """Associate DiaSources into a collection of DiaObjects using a
67 brute force matching algorithm.
69 Reproducible is for the same input data is assured by ordering the
70 DiaSource data by ccdVisit ordering.
74 diaSources : `pandas.DataFrame`
75 DiaSources grouped by CcdVisitId to spatially associate into
78 Unique identifier for the tract patch.
80 Maximum number of bits used the ``tractPatchId`` integer
85 results : `lsst.pipe.base.Struct`
86 Results struct with attributes:
89 Table of DiaSources with updated values for the DiaObjects
90 they are spatially associated to (`pandas.DataFrame`).
92 Table of DiaObjects from matching DiaSources
98 diaSources.reset_index(inplace=
True)
99 diaSources.set_index([
"ccdVisitId",
"diaSourceId"], inplace=
True)
107 exposureIdInfo = ExposureIdInfo(tractPatchId, skymapBits)
108 idFactory = exposureIdInfo.makeSourceIdFactory()
110 afwTable.SourceTable.make(afwTable.SourceTable.makeMinimalSchema(),
113 for ccdVisit
in diaSources.index.levels[0]:
116 ccdVisitSources = diaSources.loc[ccdVisit]
117 if len(diaObjectCat) == 0:
118 for diaSourceId, diaSrc
in ccdVisitSources.iterrows():
129 usedMatchIndicies = []
131 for diaSourceId, diaSrc
in ccdVisitSources.iterrows():
133 matchResult = self.
findMatchesfindMatches(diaSrc[
"ra"],
135 2*self.config.tolerance,
138 dists = matchResult.dists
139 matches = matchResult.matches
152 if np.min(dists) < np.deg2rad(self.config.tolerance/3600):
153 matchDistArg = np.argmin(dists)
154 matchIndex = matches[matchDistArg]
156 if np.isin([matchIndex], usedMatchIndicies).sum() < 1:
165 usedMatchIndicies.append(matchIndex)
190 diaSources.reset_index(inplace=
True)
191 diaSources.set_index(
"diaSourceId", inplace=
True, verify_integrity=
True)
193 diaObjects = pd.DataFrame(data=diaObjectCat)
194 diaSources.reset_index(inplace=
True)
195 if "diaObjectId" in diaObjects.columns:
196 diaObjects.set_index(
"diaObjectId", inplace=
True, verify_integrity=
True)
198 return pipeBase.Struct(
199 assocDiaSources=diaSources,
200 diaObjects=diaObjects)
211 """Create a new DiaObject and append its data.
215 diaSrc : `pandas.Series`
216 Full unassociated DiaSource to create a DiaObject from.
217 diaSources : `pandas.DataFrame`
218 DiaSource catalog to update information in. The catalog is
221 Unique identifier of the ccdVisit where ``diaSrc`` was observed.
223 Unique identifier of the DiaSource.
224 diaObjectCat : `list` of `dict`s
225 Catalog of diaObjects to append the new object o.
226 idCat : `lsst.afw.table.SourceCatalog`
227 Catalog with the IdFactory used to generate unique DiaObject
229 diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s
230 Set of coordinates of DiaSource locations that make up the
231 DiaObject average coordinate.
232 healPixIndices : `list` of `int`s
233 HealPix indices representing the locations of each currently
236 hpIndex =
toIndex(self.config.nside,
239 healPixIndices.append(hpIndex)
244 diaObjCoords.append([sphPoint])
246 diaObjId = idCat.addNew().get(
"id")
250 diaSources.loc[(ccdVisit, diaSourceId),
"diaObjectId"] = diaObjId
261 """Update DiaObject and DiaSource values after an association.
266 Array index location of the DiaObject that ``diaSrc`` was
268 diaSrc : `pandas.Series`
269 Full unassociated DiaSource to create a DiaObject from.
270 diaSources : `pandas.DataFrame`
271 DiaSource catalog to update information in. The catalog is
274 Unique identifier of the ccdVisit where ``diaSrc`` was observed.
276 Unique identifier of the DiaSource.
277 diaObjectCat : `list` of `dict`s
278 Catalog of diaObjects to append the new object o.
279 diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s
280 Set of coordinates of DiaSource locations that make up the
281 DiaObject average coordinate.
282 healPixIndices : `list` of `int`s
283 HealPix indices representing the locations of each currently
290 diaObjCoords[matchIndex].
append(sphPoint)
292 diaObjCat[matchIndex][
"ra"] = aveCoord.getRa().asDegrees()
293 diaObjCat[matchIndex][
"decl"] = aveCoord.getDec().asDegrees()
294 nSources = diaObjCat[matchIndex][
"nDiaSources"]
295 diaObjCat[matchIndex][
"nDiaSources"] = nSources + 1
296 healPixIndices[matchIndex] =
toIndex(self.config.nside,
297 diaObjCat[matchIndex][
"ra"],
298 diaObjCat[matchIndex][
"decl"])
300 diaSources.loc[(ccdVisit, diaSourceId),
"diaObjectId"] = \
301 diaObjCat[matchIndex][
"diaObjectId"]
304 """Search healPixels around DiaSource locations for DiaObjects.
309 DiaSource RA location.
311 DiaSource Dec location.
313 Size of annulus to convert to covering healPixels and search for
315 hpIndices : `list` of `int`s
316 List of heal pix indices containing the DiaObjects in ``diaObjs``.
317 diaObjs : `list` of `dict`s
318 Catalog diaObjects to with full location information for comparing
323 results : `lsst.pipe.base.Struct`
324 Results struct containing
327 Array of distances between the current DiaSource diaObjects.
328 (`numpy.ndarray` or `None`)
330 Array of array indices of diaObjects this DiaSource matches to.
331 (`numpy.ndarray` or `None`)
336 np.deg2rad(tol/3600.))
337 matchIndices = np.argwhere(np.isin(hpIndices, match_indices)).flatten()
339 if len(matchIndices) < 1:
340 return pipeBase.Struct(dists=
None, matches=
None)
343 [np.sqrt(np.sum((
eq2xyz(src_ra, src_dec)
344 -
eq2xyz(diaObjs[match][
"ra"],
345 diaObjs[match][
"decl"]))**2))
346 for match
in matchIndices])
347 return pipeBase.Struct(
349 matches=matchIndices)
352 """Create a simple empty DiaObject with location and id information.
357 Unique ID for this new DiaObject.
359 RA location of this DiaObject.
361 Dec location of this DiaObject
366 Dictionary of values representing a DiaObject.
368 new_dia_object = {
"diaObjectId": objId,
372 return new_dia_object
Point in an unspecified spherical coordinate system.
def updateCatalogs(self, matchIndex, diaSrc, diaSources, ccdVisit, diaSourceId, diaObjCat, diaObjCoords, healPixIndices)
def addNewDiaObject(self, diaSrc, diaSources, ccdVisit, diaSourceId, diaObjCat, idCat, diaObjCoords, healPixIndices)
def createDiaObject(self, objId, ra, decl)
def findMatches(self, src_ra, src_dec, tol, hpIndices, diaObjs)
def run(self, diaSources, tractPatchId, skymapBits)
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
SpherePoint averageSpherePoint(std::vector< SpherePoint > const &coords)
Return the average of a list of coordinates.
def query_disc(nside, ra, dec, max_rad, min_rad=0)
def toIndex(nside, ra, dec)