lsst.meas.astrom  15.0-1-g1eca518
directMatch.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division, print_function
2 
3 __all__ = ["DirectMatchConfig", "DirectMatchTask", "DirectMatchConfigWithoutLoader"]
4 
5 from lsst.pex.config import Config, Field, ConfigurableField
6 from lsst.pipe.base import Task, Struct
7 from lsst.meas.algorithms import (LoadIndexedReferenceObjectsTask, ScienceSourceSelectorTask,
8  ReferenceSourceSelectorTask)
9 import lsst.afw.table as afwTable
10 from lsst.afw.geom import arcseconds, averageSpherePoint
11 
12 
14  """Configuration for DirectMatchTask when an already-initialized
15  refObjLoader will be passed to this task."""
16  matchRadius = Field(dtype=float, default=0.25, doc="Matching radius, arcsec")
17  sourceSelection = ConfigurableField(target=ScienceSourceSelectorTask,
18  doc="Selection of science sources")
19  referenceSelection = ConfigurableField(target=ReferenceSourceSelectorTask,
20  doc="Selection of reference sources")
21 
22 
24  """Configuration for DirectMatchTask"""
25  refObjLoader = ConfigurableField(target=LoadIndexedReferenceObjectsTask, doc="Load reference objects")
26 
27 
28 class DirectMatchTask(Task):
29  """!Simple matching of a source catalog to a reference catalog
30 
31  @anchor DirectMatchTask_
32 
33  @section meas_astrom_match_Contents Contents
34 
35  - @ref meas_astrom_match_Purpose
36  - @ref meas_astrom_match_Initialize
37  - @ref meas_astrom_match_IO
38  - @ref meas_astrom_match_Config
39  - @ref meas_astrom_match_Example
40 
41  @section meas_astrom_match_Purpose Description
42 
43  Match sources to reference objects. The matching permits no rotation or scaling,
44  but uses the existing sky positions in the source catalog. This is often useful
45  for QA, as it allows validating the pipeline astrometry and photometry against
46  the reference catalog.
47 
48  Note that this DirectMatchTask is not currently suitable for use within the
49  AstrometryTask, as it has a different interface and serves a different purpose.
50 
51  @section meas_astrom_match_Initialize Task initialisation
52 
53  @copydoc \_\_init\_\_
54 
55  @section meas_astrom_match_IO Invoking the Task
56 
57  @copydoc run
58 
59  @section meas_astrom_match_Config Configuration parameters
60 
61  See @ref DirectMatchConfig
62 
63  @section meas_astrom_match_Example A complete example of using DirectMatchTask
64 
65  config = DirectMatchConfig()
66  task = DirectMatchTask(butler=butler, config=config)
67  matchResults = task.run(catalog)
68 
69  """
70 
71  ConfigClass = DirectMatchConfig
72  _DefaultName = "directMatch"
73 
74  def __init__(self, butler=None, refObjLoader=None, **kwargs):
75  """!Ctor
76 
77  Either a 'butler' or 'refObjLoader' is required.
78 
79  @param butler Data butler, or None
80  @param refObjLoader For loading reference objects (lsst.meas.algorithms.LoadReferenceObjectsTask), or
81  None
82  @param kwargs Other keyword arguments required for instantiating a Task (e.g., 'config')
83  """
84  Task.__init__(self, **kwargs)
85  if not refObjLoader:
86  if not isinstance(self.config, DirectMatchConfig):
87  raise RuntimeError("DirectMatchTask must be initialized with DirectMatchConfig "
88  "if a refObjLoader is not supplied at initialization")
89  self.makeSubtask("refObjLoader", butler=butler)
90  else:
91  self.refObjLoader = refObjLoader
92  self.makeSubtask("sourceSelection")
93  self.makeSubtask("referenceSelection")
94 
95  def run(self, catalog, filterName=None):
96  """!Load reference objects and match to them
97 
98  @param[in] catalog Catalog to match to (lsst.afw.table.SourceCatalog)
99  @param[in] filterName Name of filter, for loading fluxes (str)
100  @return Struct with matches (lsst.afw.table.SourceMatchVector) and
101  matchMeta (lsst.meas.astrom.MatchMetadata)
102  """
103  circle = self.calculateCircle(catalog)
104  matchMeta = self.refObjLoader.getMetadataCircle(circle.center, circle.radius, filterName)
105  emptyResult = Struct(matches=[], matchMeta=matchMeta)
106  sourceSelection = self.sourceSelection.selectSources(catalog)
107  if len(sourceSelection.sourceCat) == 0:
108  self.log.warn("No objects selected from %d objects in source catalog", len(catalog))
109  return emptyResult
110  refData = self.refObjLoader.loadSkyCircle(circle.center, circle.radius, filterName)
111  refCat = refData.refCat
112  refSelection = self.referenceSelection.selectSources(refCat)
113  if len(refSelection.sourceCat) == 0:
114  self.log.warn("No objects selected from %d objects in reference catalog", len(refCat))
115  return emptyResult
116  matches = afwTable.matchRaDec(refSelection.sourceCat, sourceSelection.sourceCat,
117  self.config.matchRadius*arcseconds)
118  self.log.info("Matched %d from %d/%d input and %d/%d reference sources" %
119  (len(matches), len(sourceSelection.sourceCat), len(catalog),
120  len(refSelection.sourceCat), len(refCat)))
121  return Struct(matches=matches, matchMeta=matchMeta, refCat=refCat, sourceSelection=sourceSelection,
122  refSelection=refSelection)
123 
124  def calculateCircle(self, catalog):
125  """!Calculate a circle enclosing the catalog
126 
127  @param[in] catalog Catalog we will encircle (lsst.afw.table.SourceCatalog)
128  @return Struct with ICRS center (lsst.afw.geom.SpherePoint) and radius (lsst.afw.geom.Angle)
129  """
130  coordList = [src.getCoord() for src in catalog]
131  center = averageSpherePoint(coordList)
132  radius = max(center.separation(coord) for coord in coordList)
133  return Struct(center=center, radius=radius + self.config.matchRadius*arcseconds)
Simple matching of a source catalog to a reference catalog.
Definition: directMatch.py:28
def run(self, catalog, filterName=None)
Load reference objects and match to them.
Definition: directMatch.py:95
template SourceMatchVector matchRaDec(SourceCatalog const &, Angle, MatchControl const &)
def calculateCircle(self, catalog)
Calculate a circle enclosing the catalog.
Definition: directMatch.py:124
def __init__(self, butler=None, refObjLoader=None, kwargs)
Ctor.
Definition: directMatch.py:74