23 from __future__
import absolute_import, division, print_function
25 __all__ = [
"getRefFluxField",
"getRefFluxKeys",
"LoadReferenceObjectsTask",
"LoadReferenceObjectsConfig"]
31 import lsst.afw.coord
as afwCoord
33 import lsst.afw.table
as afwTable
34 import lsst.pex.config
as pexConfig
35 import lsst.pipe.base
as pipeBase
36 from future.utils
import with_metaclass
40 """!Get name of flux field in schema
42 if filterName is specified:
43 return *filterName*_camFlux if present
44 else return *filterName*_flux if present (camera filter name matches reference filter name)
45 else throw RuntimeError
47 return camFlux, if present,
48 else throw RuntimeError
50 @param[in] schema reference catalog schema
51 @param[in] filterName name of camera filter
52 @return flux field name
53 @throw RuntimeError if appropriate field is not found
55 if not isinstance(schema, afwTable.Schema):
56 raise RuntimeError(
"schema=%s is not a schema" % (schema,))
58 fluxFieldList = [filterName +
"_camFlux", filterName +
"_flux"]
60 fluxFieldList = [
"camFlux"]
61 for fluxField
in fluxFieldList:
62 if fluxField
in schema:
65 raise RuntimeError(
"Could not find flux field(s) %s" % (
", ".join(fluxFieldList)))
69 """!Return flux and flux error keys
71 @param[in] schema reference catalog schema
72 @param[in] filterName name of camera filter
73 @return a pair of keys:
75 flux error key, if present, else None
76 @throw RuntimeError if flux field not found
79 fluxErrField = fluxField +
"Sigma"
80 fluxKey = schema[fluxField].asKey()
82 fluxErrKey = schema[fluxErrField].asKey()
85 return (fluxKey, fluxErrKey)
89 pixelMargin = pexConfig.RangeField(
90 doc=
"Padding to add to 4 all edges of the bounding box (pixels)",
95 defaultFilter = pexConfig.Field(
96 doc=
"Default reference catalog filter to use if filter not specified in exposure; " +
97 "if blank then filter must be specified in exposure",
101 filterMap = pexConfig.DictField(
102 doc=
"Mapping of camera filter name: reference catalog filter name; " +
103 "each reference filter must exist",
119 """!Abstract base class to load objects from reference catalogs
121 @anchor LoadReferenceObjectsTask_
123 @section meas_algorithms_loadReferenceObjects_Contents Contents
125 - @ref meas_algorithms_loadReferenceObjects_Purpose
126 - @ref meas_algorithms_loadReferenceObjects_Initialize
127 - @ref meas_algorithms_loadReferenceObjects_IO
128 - @ref meas_algorithms_loadReferenceObjects_Schema
129 - @ref meas_algorithms_loadReferenceObjects_Config
131 @section meas_algorithms_loadReferenceObjects_Purpose Description
133 Abstract base class for tasks that load objects from a reference catalog
134 in a particular region of the sky.
136 Implementations must subclass this class, override the loadSkyCircle method,
137 and will typically override the value of ConfigClass with a task-specific config class.
139 @section meas_algorithms_loadReferenceObjects_Initialize Task initialisation
141 @copydoc \_\_init\_\_
143 @section meas_algorithms_loadReferenceObjects_IO Invoking the Task
145 @copydoc loadObjectsInBBox
147 @section meas_algorithms_loadReferenceObjects_Schema Schema of the reference object catalog
149 Reference object catalogs are instances of lsst.afw.table.SimpleCatalog with the following schema
150 (other fields may also be present):
151 - coord: position of star on sky (an lsst.afw.coord.IcrsCoord)
152 - centroid: position of star on an exposure, if relevant (an lsst.afw.Point2D)
153 - hasCentroid: is centroid usable?
154 - *referenceFilterName*_flux: brightness in the specified reference catalog filter (Jy)
155 Note: the function lsst.afw.image.abMagFromFlux will convert flux in Jy to AB Magnitude.
156 - *referenceFilterName*_fluxSigma (optional): brightness standard deviation (Jy);
157 omitted if no data is available; possibly nan if data is available for some objects but not others
158 - camFlux: brightness in default camera filter (Jy); omitted if defaultFilter not specified
159 - camFluxSigma: brightness standard deviation for default camera filter;
160 omitted if defaultFilter not specified or standard deviation not available that filter
161 - *cameraFilterName*_camFlux: brightness in specified camera filter (Jy)
162 - *cameraFilterName*_camFluxSigma (optional): brightness standard deviation
163 in specified camera filter (Jy); omitted if no data is available;
164 possibly nan if data is available for some objects but not others
165 - photometric (optional): is the object usable for photometric calibration?
166 - resolved (optional): is the object spatially resolved?
167 - variable (optional): does the object have variable brightness?
169 @section meas_algorithms_loadReferenceObjects_Config Configuration parameters
171 See @ref LoadReferenceObjectsConfig for a base set of configuration parameters.
172 Most subclasses will add configuration variables.
174 ConfigClass = LoadReferenceObjectsConfig
175 _DefaultName =
"LoadReferenceObjects"
178 """!Construct a LoadReferenceObjectsTask
180 @param[in] butler A daf.persistence.Butler object. This allows subclasses to use the butler to
181 access reference catalog files using the stack I/O abstraction scheme.
183 pipeBase.Task.__init__(self, *args, **kwargs)
188 """!Load reference objects that overlap a pixel-based rectangular region
190 The search algorithm works by searching in a region in sky coordinates whose center is the center
191 of the bbox and radius is large enough to just include all 4 corners of the bbox.
192 Stars that lie outside the bbox are then trimmed from the list.
194 @param[in] bbox bounding box for pixels (an lsst.afw.geom.Box2I or Box2D)
195 @param[in] wcs WCS (an lsst.afw.image.Wcs)
196 @param[in] filterName name of camera filter, or None or blank for the default filter
197 @param[in] calib calibration, or None if unknown
199 @return an lsst.pipe.base.Struct containing:
200 - refCat a catalog of reference objects with the
201 \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink
202 as documented in LoadReferenceObjects, including photometric, resolved and variable;
203 hasCentroid is False for all objects.
204 - fluxField = name of flux field for specified filterName
207 bbox = afwGeom.Box2D(bbox)
208 bbox.grow(self.config.pixelMargin)
209 ctrCoord = wcs.pixelToSky(bbox.getCenter())
210 maxRadius = max(ctrCoord.angularSeparation(wcs.pixelToSky(pp))
for pp
in bbox.getCorners())
213 self.log.info(
"Loading reference objects using center %s pix = %s sky and radius %s deg" %
214 (bbox.getCenter(), ctrCoord, maxRadius.asDegrees()))
215 loadRes = self.
loadSkyCircle(ctrCoord, maxRadius, filterName)
216 refCat = loadRes.refCat
217 numFound = len(refCat)
220 refCat = self.
_trimToBBox(refCat=refCat, bbox=bbox, wcs=wcs)
221 numTrimmed = numFound - len(refCat)
222 self.log.debug(
"trimmed %d out-of-bbox objects, leaving %d", numTrimmed, len(refCat))
223 self.log.info(
"Loaded %d reference objects", len(refCat))
225 loadRes.refCat = refCat
230 """!Load reference objects that overlap a circular sky region
232 @param[in] ctrCoord center of search region (an lsst.afw.geom.Coord)
233 @param[in] radius radius of search region (an lsst.afw.geom.Angle)
234 @param[in] filterName name of filter, or None for the default filter;
235 used for flux values in case we have flux limits (which are not yet implemented)
237 @return an lsst.pipe.base.Struct containing:
238 - refCat a catalog of reference objects with the
239 \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink
240 as documented in LoadReferenceObjects, including photometric, resolved and variable;
241 hasCentroid is False for all objects.
242 - fluxField = name of flux field for specified filterName
247 def _trimToBBox(refCat, bbox, wcs):
248 """!Remove objects outside a given pixel-based bbox and set centroid and hasCentroid fields
250 @param[in] refCat a catalog of objects (an lsst.afw.table.SimpleCatalog,
251 or other table type that supports getCoord() on records)
252 @param[in] bbox pixel region (an afwImage.Box2D)
253 @param[in] wcs WCS used to convert sky position to pixel position (an lsst.afw.math.WCS)
255 @return a catalog of reference objects in bbox, with centroid and hasCentroid fields set
257 centroidKey = afwTable.Point2DKey(refCat.schema[
"centroid"])
258 hasCentroidKey = refCat.schema[
"hasCentroid"].asKey()
259 retStarCat = type(refCat)(refCat.table)
261 point = wcs.skyToPixel(star.getCoord())
262 if bbox.contains(point):
263 star.set(centroidKey, point)
264 star.set(hasCentroidKey,
True)
265 retStarCat.append(star)
268 def _addFluxAliases(self, schema):
269 """Add aliases for camera filter fluxes to the schema
271 If self.config.defaultFilter then adds these aliases:
272 camFlux: <defaultFilter>_flux
273 camFluxSigma: <defaultFilter>_fluxSigma, if the latter exists
275 For each camFilter: refFilter in self.config.filterMap adds these aliases:
276 <camFilter>_camFlux: <refFilter>_flux
277 <camFilter>_camFluxSigma: <refFilter>_fluxSigma, if the latter exists
279 @throw RuntimeError if any reference flux field is missing from the schema
281 aliasMap = schema.getAliasMap()
283 def addAliasesForOneFilter(filterName, refFilterName):
284 """Add aliases for a single filter
286 @param[in] filterName camera filter name, or ""
287 the name is <filterName>_camFlux or camFlux if filterName is None
288 @param[in] refFilterName reference filter name; <refFilterName>_flux must exist
290 camFluxName = filterName +
"_camFlux" if filterName
is not None else "camFlux"
291 refFluxName = refFilterName +
"_flux"
292 if refFluxName
not in schema:
293 raise RuntimeError(
"Unknown reference filter %s" % (refFluxName,))
294 aliasMap.set(camFluxName, refFluxName)
295 refFluxErrName = refFluxName +
"Sigma"
296 if refFluxErrName
in schema:
297 camFluxErrName = camFluxName +
"Sigma"
298 aliasMap.set(camFluxErrName, refFluxErrName)
300 if self.config.defaultFilter:
301 addAliasesForOneFilter(
None, self.config.defaultFilter)
303 for filterName, refFilterName
in self.config.filterMap.items():
304 addAliasesForOneFilter(filterName, refFilterName)
308 addIsPhotometric=
False, addIsResolved=
False, addIsVariable=
False):
309 """!Make the standard schema for reference object catalogs
311 @param[in] filterNameList list of filter names; used to create *filterName*_flux fields
312 @param[in] addFluxSigma if True then include flux sigma fields
313 @param[in] addIsPhotometric if True add field "photometric"
314 @param[in] addIsResolved if True add field "resolved"
315 @param[in] addIsVariable if True add field "variable"
317 schema = afwTable.SimpleTable.makeMinimalSchema()
318 afwTable.Point2DKey.addFields(
321 "centroid on an exposure, if relevant",
327 doc=
"is position known?",
329 for filterName
in filterNameList:
331 field=
"%s_flux" % (filterName,),
333 doc=
"flux in filter %s" % (filterName,),
337 for filterName
in filterNameList:
339 field=
"%s_fluxSigma" % (filterName,),
341 doc=
"flux uncertainty in filter %s" % (filterName,),
348 doc=
"set if the object can be used for photometric calibration",
354 doc=
"set if the object is spatially resolved",
360 doc=
"set if the object has variable brightness",
365 """!Relink an unpersisted match list to sources and reference objects
367 A match list is persisted and unpersisted as a catalog of IDs produced by
368 afw.table.packMatches(), with match metadata (as returned by the astrometry tasks)
369 in the catalog's metadata attribute. This method converts such a match catalog
370 into a match list (an lsst.afw.table.ReferenceMatchVector) with links to source
371 records and reference object records.
373 @param[in] matchCat Unperisted packed match list (an lsst.afw.table.BaseCatalog).
374 matchCat.table.getMetadata() must contain match metadata,
375 as returned by the astrometry tasks.
376 @param[in,out] sourceCat Source catalog (an lsst.afw.table.SourceCatalog).
377 As a side effect, the catalog will be sorted by ID.
379 @return the match list (an lsst.afw.table.ReferenceMatchVector)
381 matchmeta = matchCat.table.getMetadata()
382 version = matchmeta.getInt(
'SMATCHV')
384 raise ValueError(
'SourceMatchVector version number is %i, not 1.' % version)
385 filterName = matchmeta.getString(
'FILTER').strip()
386 ctrCoord = afwCoord.IcrsCoord(
387 matchmeta.getDouble(
'RA') * afwGeom.degrees,
388 matchmeta.getDouble(
'DEC') * afwGeom.degrees,
390 rad = matchmeta.getDouble(
'RADIUS') * afwGeom.degrees
391 refCat = self.
loadSkyCircle(ctrCoord, rad, filterName).refCat
394 return afwTable.unpackMatches(matchCat, refCat, sourceCat)
def getRefFluxKeys
Return flux and flux error keys.
def _trimToBBox
Remove objects outside a given pixel-based bbox and set centroid and hasCentroid fields.
def loadPixelBox
Load reference objects that overlap a pixel-based rectangular region.
def loadSkyCircle
Load reference objects that overlap a circular sky region.
def __init__
Construct a LoadReferenceObjectsTask.
Abstract base class to load objects from reference catalogs.
def getRefFluxField
Get name of flux field in schema.
def joinMatchListWithCatalog
Relink an unpersisted match list to sources and reference objects.
def makeMinimalSchema
Make the standard schema for reference object catalogs.