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 
   99         doDropIndex = diaSources.index.names[0] 
is None 
  100         diaSources.reset_index(inplace=
True, drop=doDropIndex)
 
  104         diaSources.set_index([
"ccdVisitId", 
"diaSourceId"], inplace=
True)
 
  112         exposureIdInfo = ExposureIdInfo(tractPatchId, skymapBits)
 
  113         idFactory = exposureIdInfo.makeSourceIdFactory()
 
  115             afwTable.SourceTable.make(afwTable.SourceTable.makeMinimalSchema(),
 
  118         for ccdVisit 
in diaSources.index.levels[0]:
 
  121             ccdVisitSources = diaSources.loc[ccdVisit]
 
  122             if len(diaObjectCat) == 0:
 
  123                 for diaSourceId, diaSrc 
in ccdVisitSources.iterrows():
 
  134             usedMatchIndicies = []
 
  136             for diaSourceId, diaSrc 
in ccdVisitSources.iterrows():
 
  138                 matchResult = self.
findMatchesfindMatches(diaSrc[
"ra"],
 
  140                                                2*self.config.tolerance,
 
  143                 dists = matchResult.dists
 
  144                 matches = matchResult.matches
 
  157                 if np.min(dists) < np.deg2rad(self.config.tolerance/3600):
 
  158                     matchDistArg = np.argmin(dists)
 
  159                     matchIndex = matches[matchDistArg]
 
  161                     if np.isin([matchIndex], usedMatchIndicies).sum() < 1:
 
  170                         usedMatchIndicies.append(matchIndex)
 
  195         diaSources.reset_index(inplace=
True)
 
  196         diaSources.set_index(
"diaSourceId", inplace=
True, verify_integrity=
True)
 
  198         objs = diaObjectCat 
if diaObjectCat 
else np.array([], dtype=[(
'diaObjectId', 
'int64'),
 
  201                                                                      (
'nDiaSources', 
'int64')])
 
  202         diaObjects = pd.DataFrame(data=objs)
 
  204         if "diaObjectId" in diaObjects.columns:
 
  205             diaObjects.set_index(
"diaObjectId", inplace=
True, verify_integrity=
True)
 
  207         return pipeBase.Struct(
 
  208             assocDiaSources=diaSources,
 
  209             diaObjects=diaObjects)
 
  220         """Create a new DiaObject and append its data. 
  224         diaSrc : `pandas.Series` 
  225             Full unassociated DiaSource to create a DiaObject from. 
  226         diaSources : `pandas.DataFrame` 
  227             DiaSource catalog to update information in. The catalog is 
  230             Unique identifier of the ccdVisit where ``diaSrc`` was observed. 
  232             Unique identifier of the DiaSource. 
  233         diaObjectCat : `list` of `dict`s 
  234             Catalog of diaObjects to append the new object o. 
  235         idCat : `lsst.afw.table.SourceCatalog` 
  236             Catalog with the IdFactory used to generate unique DiaObject 
  238         diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s 
  239             Set of coordinates of DiaSource locations that make up the 
  240             DiaObject average coordinate. 
  241         healPixIndices : `list` of `int`s 
  242             HealPix indices representing the locations of each currently 
  245         hpIndex = 
toIndex(self.config.nside,
 
  248         healPixIndices.append(hpIndex)
 
  253         diaObjCoords.append([sphPoint])
 
  255         diaObjId = idCat.addNew().get(
"id")
 
  259         diaSources.loc[(ccdVisit, diaSourceId), 
"diaObjectId"] = diaObjId
 
  270         """Update DiaObject and DiaSource values after an association. 
  275             Array index location of the DiaObject that ``diaSrc`` was 
  277         diaSrc : `pandas.Series` 
  278             Full unassociated DiaSource to create a DiaObject from. 
  279         diaSources : `pandas.DataFrame` 
  280             DiaSource catalog to update information in. The catalog is 
  283             Unique identifier of the ccdVisit where ``diaSrc`` was observed. 
  285             Unique identifier of the DiaSource. 
  286         diaObjectCat : `list` of `dict`s 
  287             Catalog of diaObjects to append the new object o. 
  288         diaObjectCoords : `list` of `list`s of `lsst.geom.SpherePoint`s 
  289             Set of coordinates of DiaSource locations that make up the 
  290             DiaObject average coordinate. 
  291         healPixIndices : `list` of `int`s 
  292             HealPix indices representing the locations of each currently 
  299         diaObjCoords[matchIndex].
append(sphPoint)
 
  301         diaObjCat[matchIndex][
"ra"] = aveCoord.getRa().asDegrees()
 
  302         diaObjCat[matchIndex][
"decl"] = aveCoord.getDec().asDegrees()
 
  303         nSources = diaObjCat[matchIndex][
"nDiaSources"]
 
  304         diaObjCat[matchIndex][
"nDiaSources"] = nSources + 1
 
  305         healPixIndices[matchIndex] = 
toIndex(self.config.nside,
 
  306                                              diaObjCat[matchIndex][
"ra"],
 
  307                                              diaObjCat[matchIndex][
"decl"])
 
  309         diaSources.loc[(ccdVisit, diaSourceId), 
"diaObjectId"] = \
 
  310             diaObjCat[matchIndex][
"diaObjectId"]
 
  313         """Search healPixels around DiaSource locations for DiaObjects. 
  318             DiaSource RA location. 
  320             DiaSource Dec location. 
  322             Size of annulus to convert to covering healPixels and search for 
  324         hpIndices : `list` of `int`s 
  325             List of heal pix indices containing the DiaObjects in ``diaObjs``. 
  326         diaObjs : `list` of `dict`s 
  327             Catalog diaObjects to with full location information for comparing 
  332         results : `lsst.pipe.base.Struct` 
  333             Results struct containing 
  336                 Array of distances between the current DiaSource diaObjects. 
  337                 (`numpy.ndarray` or `None`) 
  339                 Array of array indices of diaObjects this DiaSource matches to. 
  340                 (`numpy.ndarray` or `None`) 
  345                                    np.deg2rad(tol/3600.))
 
  346         matchIndices = np.argwhere(np.isin(hpIndices, match_indices)).flatten()
 
  348         if len(matchIndices) < 1:
 
  349             return pipeBase.Struct(dists=
None, matches=
None)
 
  352             [np.sqrt(np.sum((
eq2xyz(src_ra, src_dec)
 
  353                              - 
eq2xyz(diaObjs[match][
"ra"],
 
  354                                       diaObjs[match][
"decl"]))**2))
 
  355              for match 
in matchIndices])
 
  356         return pipeBase.Struct(
 
  358             matches=matchIndices)
 
  361         """Create a simple empty DiaObject with location and id information. 
  366             Unique ID for this new DiaObject. 
  368             RA location of this DiaObject. 
  370             Dec location of this DiaObject 
  375             Dictionary of values representing a DiaObject. 
  377         new_dia_object = {
"diaObjectId": objId,
 
  381         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)