23 __all__ = [
'RefMatchConfig', 
'RefMatchTask']
 
   30 import lsst.pex.config 
as pexConfig
 
   34 from .matchPessimisticB 
import MatchPessimisticBTask
 
   35 from .display 
import displayAstrometry
 
   36 from . 
import makeMatchStatistics
 
   40     matcher = pexConfig.ConfigurableField(
 
   41         target=MatchPessimisticBTask,
 
   42         doc=
"reference object/source matcher",
 
   44     matchDistanceSigma = pexConfig.RangeField(
 
   45         doc=
"the maximum match distance is set to " 
   46         " mean_match_distance + matchDistanceSigma*std_dev_match_distance; " 
   47         "ignored if not fitting a WCS",
 
   52     sourceSelector = sourceSelectorRegistry.makeField(
 
   53         doc=
"How to select sources for cross-matching.",
 
   56     referenceSelector = pexConfig.ConfigurableField(
 
   57         target=ReferenceSourceSelectorTask,
 
   58         doc=
"How to select reference objects for cross-matching." 
   60     sourceFluxType = pexConfig.Field(
 
   62         doc=
"Source flux type to use in source selection.",
 
   77     """Match an input source catalog with objects from a reference catalog. 
   81     refObjLoader : `lsst.meas.algorithms.ReferenceLoader` 
   82         A reference object loader object 
   84         additional keyword arguments for pipe_base `lsst.pipe.base.Task` 
   86     ConfigClass = RefMatchConfig
 
   87     _DefaultName = 
"calibrationBaseClass" 
   90         pipeBase.Task.__init__(self, **kwargs)
 
   96         if self.config.sourceSelector.name == 
'matcher':
 
   97             if self.config.sourceSelector[
'matcher'].sourceFluxType != self.config.sourceFluxType:
 
   98                 raise RuntimeError(
"The sourceFluxType in the sourceSelector['matcher'] must match " 
   99                                    "the configured sourceFluxType")
 
  101         self.makeSubtask(
"matcher")
 
  102         self.makeSubtask(
"sourceSelector")
 
  103         self.makeSubtask(
"referenceSelector")
 
  106         """Sets the reference object loader for the task 
  111             An instance of a reference object loader task or class 
  117         """Load reference objects overlapping an exposure and match to sources 
  118         detected on that exposure. 
  122         exposure : `lsst.afw.image.Exposure` 
  123             exposure that the sources overlap 
  124         sourceCat : `lsst.afw.table.SourceCatalog.` 
  125             catalog of sources detected on the exposure 
  129         result : `lsst.pipe.base.Struct` 
  130             Result struct with Components: 
  132             - ``refCat`` : reference object catalog of objects that overlap the 
  133               exposure (`lsst.afw.table.SimpleCatalog`) 
  134             - ``matches`` :  Matched sources and references 
  135               (`list` of `lsst.afw.table.ReferenceMatch`) 
  136             - ``matchMeta`` : metadata needed to unpersist matches 
  137               (`lsst.daf.base.PropertyList`) 
  141         ignores config.matchDistanceSigma 
  144             raise RuntimeError(
"Running matcher task with no refObjLoader set in __ini__ or setRefObjLoader")
 
  150         sourceSelection = self.sourceSelector.
run(sourceCat)
 
  152         sourceFluxField = 
"slot_%sFlux_instFlux" % (self.config.sourceFluxType)
 
  157             filterName=expMd.filterName,
 
  158             photoCalib=expMd.photoCalib,
 
  161         refSelection = self.referenceSelector.
run(loadRes.refCat)
 
  166             filterName=expMd.filterName,
 
  167             photoCalib=expMd.photoCalib,
 
  170         matchRes = self.matcher.matchObjectsToSources(
 
  171             refCat=refSelection.sourceCat,
 
  172             sourceCat=sourceSelection.sourceCat,
 
  174             sourceFluxField=sourceFluxField,
 
  175             refFluxField=loadRes.fluxField,
 
  176             match_tolerance=
None,
 
  181             "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
 
  182             (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
 
  186             frame = int(debug.frame)
 
  188                 refCat=refSelection.sourceCat,
 
  189                 sourceCat=sourceSelection.sourceCat,
 
  190                 matches=matchRes.matches,
 
  197         return pipeBase.Struct(
 
  198             refCat=loadRes.refCat,
 
  199             refSelection=refSelection,
 
  200             sourceSelection=sourceSelection,
 
  201             matches=matchRes.matches,
 
  205     def _computeMatchStatsOnSky(self, matchList):
 
  206         """Compute on-sky radial distance statistics for a match list 
  210         matchList : `list` of `lsst.afw.table.ReferenceMatch` 
  211             list of matches between reference object and sources; 
  212             the distance field is the only field read and it must be set to distance in radians 
  216         result : `lsst.pipe.base.Struct` 
  217             Result struct with components: 
  219             - ``distMean`` : clipped mean of on-sky radial separation (`float`) 
  220             - ``distStdDev`` : clipped standard deviation of on-sky radial 
  222             - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma * 
  226         distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
 
  227         distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
 
  228         return pipeBase.Struct(
 
  230             distStdDev=distStdDev,
 
  231             maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
 
  234     def _getExposureMetadata(self, exposure):
 
  235         """Extract metadata from an exposure. 
  239         exposure : `lsst.afw.image.Exposure` 
  243         result : `lsst.pipe.base.Struct` 
  244             Result struct with components: 
  246             - ``bbox`` : parent bounding box (`lsst.geom.Box2I`) 
  247             - ``wcs`` : exposure WCS (`lsst.afw.geom.SkyWcs`) 
  248             - ``photoCalib`` : photometric calibration (`lsst.afw.image.PhotoCalib`) 
  249             - ``filterName`` : name of filter (`str`) 
  250             - ``epoch`` : date of exposure (`astropy.time.Time`) 
  253         exposureInfo = exposure.getInfo()
 
  254         filterName = exposureInfo.getFilter().getName() 
or None 
  255         if filterName == 
"_unknown_":
 
  258         if exposure.getInfo().hasVisitInfo():
 
  259             epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
 
  261             epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
 
  263         return pipeBase.Struct(
 
  264             bbox=exposure.getBBox(),
 
  265             wcs=exposureInfo.getWcs(),
 
  266             photoCalib=exposureInfo.getPhotoCalib(),
 
  267             filterName=filterName,