lsst.meas.extensions.astrometryNet  18.0.0-1-g27bbc53+3
loadAstrometryNetObjects.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division, print_function
2 
3 __all__ = ["LoadAstrometryNetObjectsTask", "LoadAstrometryNetObjectsConfig"]
4 
5 from builtins import object
6 
7 import lsst.pipe.base as pipeBase
8 from lsst.meas.algorithms import LoadReferenceObjectsTask, getRefFluxField
9 from lsst.meas.algorithms.loadReferenceObjects import convertToNanojansky
10 from . import astrometry_net
11 from .multiindex import AstrometryNetCatalog, getConfigFromEnvironment
12 
13 LoadAstrometryNetObjectsConfig = LoadReferenceObjectsTask.ConfigClass
14 
15 # The following block adds links to this task from the Task Documentation page.
16 
22 
23 
24 class LoadAstrometryNetObjectsTask(LoadReferenceObjectsTask):
25  """!Load reference objects from astrometry.net index files
26 
27  @anchor LoadAstrometryNetObjectsTask_
28 
29  @section meas_astrom_loadAstrometryNetObjects_Contents Contents
30 
31  - @ref meas_astrom_loadAstrometryNetObjects_Purpose
32  - @ref meas_astrom_loadAstrometryNetObjects_Initialize
33  - @ref meas_astrom_loadAstrometryNetObjects_IO
34  - @ref meas_algorithms_loadReferenceObjects_Schema
35  - @ref meas_astrom_loadAstrometryNetObjects_Config
36  - @ref meas_astrom_loadAstrometryNetObjects_Example
37  - @ref meas_astrom_loadAstrometryNetObjects_Debug
38 
39  @section meas_astrom_loadAstrometryNetObjects_Purpose Description
40 
41  Load reference objects from astrometry.net index files.
42 
43  @section meas_astrom_loadAstrometryNetObjects_Initialize Task initialisation
44 
45  @copydoc \_\_init\_\_
46 
47  @section meas_astrom_loadAstrometryNetObjects_IO Invoking the Task
48 
49  @copydoc loadObjectsInBBox
50 
51  @section meas_astrom_loadAstrometryNetObjects_Config Configuration parameters
52 
53  See @ref LoadAstrometryNetObjectsConfig
54 
55  @section meas_astrom_loadAstrometryNetObjects_Example A complete example of using
56  LoadAstrometryNetObjectsTask
57 
58  LoadAstrometryNetObjectsTask is a subtask of AstrometryTask, which is called by PhotoCalTask.
59  See \ref pipe_tasks_photocal_Example.
60 
61  @section meas_astrom_loadAstrometryNetObjects_Debug Debug variables
62 
63  LoadAstrometryNetObjectsTask does not support any debug variables.
64  """
65  ConfigClass = LoadAstrometryNetObjectsConfig
66 
67  def __init__(self, config=None, andConfig=None, **kwargs):
68  """!Create a LoadAstrometryNetObjectsTask
69 
70  @param[in] config configuration (an instance of self.ConfigClass); if None use self.ConfigClass()
71  @param[in] andConfig astrometry.net data config (an instance of AstromNetDataConfig, or None);
72  if None then use andConfig.py in the astrometry_net_data product (which must be setup)
73  @param[in] kwargs additional keyword arguments for pipe_base Task.\_\_init\_\_
74 
75  @throw RuntimeError if andConfig is None and the configuration cannot be found,
76  either because astrometry_net_data is not setup in eups
77  or because the setup version does not include the file "andConfig.py"
78  """
79  LoadReferenceObjectsTask.__init__(self, config=config, **kwargs)
80  self.andConfig = andConfig
81  self.haveIndexFiles = False # defer reading index files until we know they are needed
82  # because astrometry may not be used, in which case it may not be properly configured
83 
84  @pipeBase.timeMethod
85  def loadSkyCircle(self, ctrCoord, radius, filterName=None, epoch=None, centroids=True):
86  """!Load reference objects that overlap a circular sky region
87 
88  @param[in] ctrCoord center of search region (an afwGeom.Coord)
89  @param[in] radius radius of search region (an afwGeom.Angle)
90  @param[in] filterName name of filter, or None for the default filter;
91  used for flux values in case we have flux limits (which are not yet implemented)
92  @param[in] epoch Epoch for proper motion and parallax correction
93  (an astropy.time.Time), or None
94  centroids : `bool` (optional)
95  Ignored: a.net refcats always have centroid fields.
96 
97  No proper motion correction is made, since our astrometry.net catalogs
98  typically don't support that, and even if they do they format is uncertain.
99  Users interested in proper motion corrections should use the
100  lsst.meas.algorithms.LoadIndexedReferenceObjectsTask or they will need to
101  subclass and define how the proper motion correction is to be done.
102 
103  @return an lsst.pipe.base.Struct containing:
104  - refCat a catalog of reference objects with the
105  \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink
106  as documented in LoadReferenceObjects, including photometric, resolved and variable;
107  hasCentroid is False for all objects.
108  - fluxField = name of flux field for specified filterName
109  """
110  self._readIndexFiles()
111 
112  names = []
113  mcols = []
114  ecols = []
115  for col, mcol in self.andConfig.magColumnMap.items():
116  names.append(col)
117  mcols.append(mcol)
118  ecols.append(self.andConfig.magErrorColumnMap.get(col, ''))
119  margs = (names, mcols, ecols)
120 
121  solver = self._getSolver()
122 
123  # Find multi-index files within range
124  multiInds = self._getMIndexesWithinRange(ctrCoord, radius)
125 
126  # compute solver.getCatalog arguments that follow the list of star kd-trees:
127  # - center equatorial angle (e.g. RA) in deg
128  # - center polar angle (e.g. Dec) in deg
129  # - radius, in deg
130  # - idColumn
131  # - (margs)
132  # - star-galaxy column
133  # - variability column
134  fixedArgTuple = (
135  ctrCoord,
136  radius,
137  self.andConfig.idColumn,
138  ) + margs + (
139  self.andConfig.starGalaxyColumn,
140  self.andConfig.variableColumn,
141  True, # eliminate duplicate IDs
142  )
143 
144  self.log.debug("search for objects at %s with radius %s deg", ctrCoord, radius.asDegrees())
145  with LoadMultiIndexes(multiInds):
146  # We just want to pass the star kd-trees, so just pass the
147  # first element of each multi-index.
148  inds = tuple(mi[0] for mi in multiInds)
149  refCat = solver.getCatalog(inds, *fixedArgTuple)
150 
151  self._addFluxAliases(schema=refCat.schema)
152 
153  fluxField = getRefFluxField(schema=refCat.schema, filterName=filterName)
154 
155  # NOTE: sourceSelectors require contiguous catalogs, so ensure
156  # contiguity now, so views are preserved from here on.
157  if not refCat.isContiguous():
158  refCat = refCat.copy(deep=True)
159 
160  # Update flux fields to be nJy. a.net catalogs do not have a conversion script.
161  self.log.warn("Loading A.net reference catalog with old style units in schema.")
162  self.log.warn("A.net reference catalogs will not be supported in the future.")
163  self.log.warn("See RFC-562 and RFC-575 for more details.")
164  refCat = convertToNanojansky(refCat, self.log)
165 
166  self.log.debug("found %d objects", len(refCat))
167  return pipeBase.Struct(
168  refCat=refCat,
169  fluxField=fluxField,
170  )
171 
172  @pipeBase.timeMethod
173  def _readIndexFiles(self):
174  """!Read all astrometry.net index files, if not already read
175  """
176  if self.haveIndexFiles:
177  return
178 
179  self.log.debug("read index files")
180  self.haveIndexFiles = True # just try once
181 
182  if self.andConfig is None:
184 
186 
187  def _getMIndexesWithinRange(self, ctrCoord, radius):
188  """!Get list of muti-index objects within range
189 
190  @param[in] ctrCoord center of search region (an afwGeom.Coord)
191  @param[in] radius radius of search region (an afwGeom.Angle)
192 
193  @return list of multiindex objects
194  """
195  return [mi for mi in self.multiInds if mi.isWithinRange(ctrCoord, radius)]
196 
197  def _getSolver(self):
198  solver = astrometry_net.Solver()
199  # HACK, set huge default pixel scale range.
200  lo, hi = 0.01, 3600.
201  solver.setPixelScaleRange(lo, hi)
202  return solver
203 
204 
205 class LoadMultiIndexes(object):
206  """Context manager for loading and unloading astrometry.net multi-index files
207  """
208 
209  def __init__(self, multiInds):
210  self.multiInds = multiInds
211 
212  def __enter__(self):
213  for mi in self.multiInds:
214  mi.reload()
215  return self.multiInds
216 
217  def __exit__(self, typ, val, trace):
218  for mi in self.multiInds:
219  mi.unload()
def _readIndexFiles(self)
Read all astrometry.net index files, if not already read.
def _getMIndexesWithinRange(self, ctrCoord, radius)
Get list of muti-index objects within range.
def loadSkyCircle(self, ctrCoord, radius, filterName=None, epoch=None, centroids=True)
Load reference objects that overlap a circular sky region.
def __init__(self, config=None, andConfig=None, kwargs)
Create a LoadAstrometryNetObjectsTask.