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