lsst.meas.astrom  13.0-14-g9415442+40
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Groups Pages
ref_match.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2016 AURA/LSST.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <https://www.lsstcorp.org/LegalNotices/>.
21 #
22 from __future__ import absolute_import, division, print_function
23 
24 __all__ = ['RefMatchConfig', 'RefMatchTask']
25 
26 from lsst.afw.image.utils import getDistortedWcs
27 import lsst.afw.geom as afwGeom
28 import lsst.afw.math as afwMath
29 import lsst.pex.config as pexConfig
30 import lsst.pipe.base as pipeBase
31 from .matchOptimisticB import MatchOptimisticBTask
32 from .display import displayAstrometry
33 from . import makeMatchStatistics
34 from .createMatchMetadata import createMatchMetadata
35 
36 
37 class RefMatchConfig(pexConfig.Config):
38  matcher = pexConfig.ConfigurableField(
39  target=MatchOptimisticBTask,
40  doc="reference object/source matcher",
41  )
42  matchDistanceSigma = pexConfig.RangeField(
43  doc="the maximum match distance is set to "
44  " mean_match_distance + matchDistanceSigma*std_dev_match_distance; " +
45  "ignored if not fitting a WCS",
46  dtype=float,
47  default=2,
48  min=0,
49  )
50 
51 # The following block adds links to this task from the Task Documentation page.
52 ## \addtogroup LSST_task_documentation
53 ## \{
54 ## \page measAlgorithms_RefMatchTask
55 ## \ref RefMatchTask_ "RefMatchTask"
56 ## Basic functionality for all calibration tasks: i.e. a matcher
57 ## \}
58 
59 
60 class RefMatchTask(pipeBase.Task):
61  """!Match an input source catalog with objects from a reference catalog
62 
63  @anchor RefMatchTask_
64  """
65  ConfigClass = RefMatchConfig
66  _DefaultName = "calibrationBaseClass"
67 
68  def __init__(self, refObjLoader, schema=None, **kwargs):
69  """!Construct a RefMatchTask
70 
71  @param[in] refObjLoader A reference object loader object
72  @param[in] schema ignored; available for compatibility with an older astrometry task
73  @param[in] kwargs additional keyword arguments for pipe_base Task.\_\_init\_\_
74  """
75  pipeBase.Task.__init__(self, **kwargs)
76  self.refObjLoader = refObjLoader
77  self.makeSubtask("matcher")
78 
79  @pipeBase.timeMethod
80  def loadAndMatch(self, exposure, sourceCat):
81  """!Load reference objects overlapping an exposure and match to sources detected on that exposure
82 
83  @param[in] exposure exposure that the sources overlap
84  @param[in] sourceCat catalog of sources detected on the exposure (an lsst.afw.table.SourceCatalog)
85 
86  @return an lsst.pipe.base.Struct with these fields:
87  - refCat reference object catalog of objects that overlap the exposure (with some margin)
88  (an lsst::afw::table::SimpleCatalog)
89  - matches a list of lsst.afw.table.ReferenceMatch
90  - matchMeta metadata needed to unpersist matches (an lsst.daf.base.PropertyList)
91 
92  @note ignores config.matchDistanceSigma
93  """
94  import lsstDebug
95  debug = lsstDebug.Info(__name__)
96 
97  matchMeta = createMatchMetadata(exposure, border=self.refObjLoader.config.pixelMargin)
98  expMd = self._getExposureMetadata(exposure)
99 
100  loadRes = self.refObjLoader.loadPixelBox(
101  bbox=expMd.bbox,
102  wcs=expMd.wcs,
103  filterName=expMd.filterName,
104  calib=expMd.calib,
105  )
106 
107  matchRes = self.matcher.matchObjectsToSources(
108  refCat=loadRes.refCat,
109  sourceCat=sourceCat,
110  wcs=expMd.wcs,
111  refFluxField=loadRes.fluxField,
112  match_tolerance=None,
113  )
114 
115  distStats = self._computeMatchStatsOnSky(matchRes.matches)
116  self.log.info(
117  "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
118  (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
119  )
120 
121  if debug.display:
122  frame = int(debug.frame)
124  refCat=loadRes.refCat,
125  sourceCat=sourceCat,
126  matches=matchRes.matches,
127  exposure=exposure,
128  bbox=expMd.bbox,
129  frame=frame,
130  title="Matches",
131  )
132 
133  return pipeBase.Struct(
134  refCat=loadRes.refCat,
135  matches=matchRes.matches,
136  matchMeta=matchMeta,
137  )
138 
139  def _computeMatchStatsOnSky(self, matchList):
140  """Compute on-sky radial distance statistics for a match list
141 
142  @param[in] matchList list of matches between reference object and sources;
143  the distance field is the only field read and it must be set to distance in radians
144 
145  @return a pipe_base Struct containing these fields:
146  - distMean clipped mean of on-sky radial separation
147  - distStdDev clipped standard deviation of on-sky radial separation
148  - maxMatchDist distMean + self.config.matchDistanceSigma*distStdDev
149  """
150  distStatsInRadians = makeMatchStatistics(matchList, afwMath.MEANCLIP | afwMath.STDEVCLIP)
151  distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*afwGeom.radians
152  distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*afwGeom.radians
153  return pipeBase.Struct(
154  distMean=distMean,
155  distStdDev=distStdDev,
156  maxMatchDist=distMean + self.config.matchDistanceSigma*distStdDev,
157  )
158 
159  def _getExposureMetadata(self, exposure):
160  """!Extract metadata from an exposure
161 
162  @return an lsst.pipe.base.Struct containing the following exposure metadata:
163  - bbox: parent bounding box
164  - wcs: WCS (an lsst.afw.image.Wcs)
165  - calib calibration (an lsst.afw.image.Calib), or None if unknown
166  - filterName: name of filter, or None if unknown
167  """
168  exposureInfo = exposure.getInfo()
169  filterName = exposureInfo.getFilter().getName() or None
170  if filterName == "_unknown_":
171  filterName = None
172  return pipeBase.Struct(
173  bbox=exposure.getBBox(),
174  wcs=getDistortedWcs(exposureInfo, log=self.log),
175  calib=exposureInfo.getCalib() if exposureInfo.hasCalib() else None,
176  filterName=filterName,
177  )
afw::math::Statistics makeMatchStatistics(std::vector< MatchT > const &matchList, int const flags, afw::math::StatisticsControl const &sctrl=afw::math::StatisticsControl())
Compute statistics of the distance field of a match list.
def __init__
Construct a RefMatchTask.
Definition: ref_match.py:68
def loadAndMatch
Load reference objects overlapping an exposure and match to sources detected on that exposure...
Definition: ref_match.py:80
Match an input source catalog with objects from a reference catalog.
Definition: ref_match.py:60
def _getExposureMetadata
Extract metadata from an exposure.
Definition: ref_match.py:159