65 def run(self, diaSources, idGenerator=None):
66 """Associate DiaSources into a collection of DiaObjects using a
67 brute force matching algorithm.
69 Reproducible for the same input data is assured by ordering the
70 DiaSource data by visit,detector.
74 diaSources : `pandas.DataFrame`
75 DiaSources in clusters of visit, detector to spatially associate
77 idGenerator : `lsst.meas.base.IdGenerator`, optional
78 Object that generates Object IDs and random number generator seeds.
82 results : `lsst.pipe.base.Struct`
83 Results struct with attributes:
86 Table of DiaSources with updated values for the DiaObjects
87 they are spatially associated to (`pandas.DataFrame`).
89 Table of DiaObjects from matching DiaSources
94 doDropIndex = diaSources.index.names[0]
is None
95 diaSources.reset_index(inplace=
True, drop=doDropIndex)
100 diaSources[(
"visit,detector")] = list(zip(diaSources[
"visit"], diaSources[
"detector"]))
101 diaSources.set_index([(
"visit,detector"),
"diaSourceId"], inplace=
True)
109 if idGenerator
is None:
110 idGenerator = IdGenerator()
111 idCat = idGenerator.make_source_catalog(afwTable.SourceTable.makeMinimalSchema())
113 for visit, detector
in diaSources.index.levels[0]:
116 orderedSources = diaSources.loc[(visit, detector)]
117 if len(diaObjectCat) == 0:
118 for diaSourceId, diaSrc
in orderedSources.iterrows():
130 usedMatchIndicies = []
132 for diaSourceId, diaSrc
in orderedSources.iterrows():
136 2*self.config.tolerance,
139 dists = matchResult.dists
140 matches = matchResult.matches
154 if np.min(dists) < np.deg2rad(self.config.tolerance/3600):
155 matchDistArg = np.argmin(dists)
156 matchIndex = matches[matchDistArg]
158 if np.isin([matchIndex], usedMatchIndicies).sum() < 1:
168 usedMatchIndicies.append(matchIndex)
195 diaSources.reset_index(inplace=
True)
196 del diaSources[
"visit,detector"]
197 diaSources.set_index(
"diaSourceId", inplace=
True, verify_integrity=
True)
199 objs = diaObjectCat
if diaObjectCat
else np.array([], dtype=[(
'diaObjectId',
'int64'),
202 (
'nDiaSources',
'int64')])
203 diaObjects = pd.DataFrame(data=objs)
205 if "diaObjectId" in diaObjects.columns:
206 diaObjects.set_index(
"diaObjectId", inplace=
True, verify_integrity=
True)
208 return pipeBase.Struct(
209 assocDiaSources=diaSources,
210 diaObjects=diaObjects)
222 """Create a new DiaObject and append its data.
226 diaSrc : `pandas.Series`
227 Full unassociated DiaSource to create a DiaObject from.
228 diaSources : `pandas.DataFrame`
229 DiaSource catalog to update information in. The catalog is
230 modified in place. Must be indexed on:
231 `(visit, detector), diaSourceId`.
232 visit, detector : `int`
233 Visit and detector ids where ``diaSrc`` was observed.
235 Unique identifier of the DiaSource.
236 diaObjectCat : `list` of `dict`s
237 Catalog of diaObjects to append the new object o.
238 idCat : `lsst.afw.table.SourceCatalog`
239 Catalog with the IdFactory used to generate unique DiaObject
241 diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s
242 Set of coordinates of DiaSource locations that make up the
243 DiaObject average coordinate.
244 healPixIndices : `list` of `int`s
245 HealPix indices representing the locations of each currently
248 hpIndex = toIndex(self.config.nside,
251 healPixIndices.append(hpIndex)
256 diaObjCoords.append([sphPoint])
258 diaObjId = idCat.addNew().get(
"id")
262 diaSources.loc[((visit, detector), diaSourceId),
"diaObjectId"] = diaObjId
274 """Update DiaObject and DiaSource values after an association.
279 Array index location of the DiaObject that ``diaSrc`` was
281 diaSrc : `pandas.Series`
282 Full unassociated DiaSource to create a DiaObject from.
283 diaSources : `pandas.DataFrame`
284 DiaSource catalog to update information in. The catalog is
285 modified in place. Must be indexed on:
286 `(visit, detector), diaSourceId`.
287 visit, detector : `int`
288 Visit and detector ids where ``diaSrc`` was observed.
290 Unique identifier of the DiaSource.
291 diaObjectCat : `list` of `dict`s
292 Catalog of diaObjects to append the new object o.
293 diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s
294 Set of coordinates of DiaSource locations that make up the
295 DiaObject average coordinate.
296 healPixIndices : `list` of `int`s
297 HealPix indices representing the locations of each currently
304 diaObjCoords[matchIndex].append(sphPoint)
305 aveCoord = geom.averageSpherePoint(diaObjCoords[matchIndex])
306 diaObjCat[matchIndex][
"ra"] = aveCoord.getRa().asDegrees()
307 diaObjCat[matchIndex][
"dec"] = aveCoord.getDec().asDegrees()
308 nSources = diaObjCat[matchIndex][
"nDiaSources"]
309 diaObjCat[matchIndex][
"nDiaSources"] = nSources + 1
310 healPixIndices[matchIndex] = toIndex(self.config.nside,
311 diaObjCat[matchIndex][
"ra"],
312 diaObjCat[matchIndex][
"dec"])
314 diaSources.loc[((visit, detector), diaSourceId),
"diaObjectId"] = \
315 diaObjCat[matchIndex][
"diaObjectId"]
318 """Search healPixels around DiaSource locations for DiaObjects.
323 DiaSource RA location.
325 DiaSource Dec location.
327 Size of annulus to convert to covering healPixels and search for
329 hpIndices : `list` of `int`s
330 List of heal pix indices containing the DiaObjects in ``diaObjs``.
331 diaObjs : `list` of `dict`s
332 Catalog diaObjects to with full location information for comparing
337 results : `lsst.pipe.base.Struct`
338 Results struct containing
341 Array of distances between the current DiaSource diaObjects.
342 (`numpy.ndarray` or `None`)
344 Array of array indices of diaObjects this DiaSource matches to.
345 (`numpy.ndarray` or `None`)
347 match_indices = query_disc(self.config.nside,
350 np.deg2rad(tol/3600.))
351 matchIndices = np.argwhere(np.isin(hpIndices, match_indices)).flatten()
353 if len(matchIndices) < 1:
354 return pipeBase.Struct(dists=
None, matches=
None)
357 [np.sqrt(np.sum((eq2xyz(src_ra, src_dec)
358 - eq2xyz(diaObjs[match][
"ra"],
359 diaObjs[match][
"dec"]))**2))
360 for match
in matchIndices])
361 return pipeBase.Struct(
363 matches=matchIndices)