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 joinMatchListWithCatalog(self, matchCat, sourceCat)
Relink an unpersisted match list to sources and reference objects.
def __init__(self, butler=None, args, kwargs)
Construct a LoadReferenceObjectsTask.
def _trimToBBox(refCat, bbox, wcs)
Remove objects outside a given pixel-based bbox and set centroid and hasCentroid fields.
def loadPixelBox(self, bbox, wcs, filterName=None, calib=None)
Load reference objects that overlap a pixel-based rectangular region.
def getRefFluxField(schema, filterName=None)
Get name of flux field in schema.
def getRefFluxKeys(schema, filterName=None)
Return flux and flux error keys.
def makeMinimalSchema(filterNameList, addFluxSigma=False, addIsPhotometric=False, addIsResolved=False, addIsVariable=False)
Make the standard schema for reference object catalogs.
Abstract base class to load objects from reference catalogs.
def loadSkyCircle(self, ctrCoord, radius, filterName=None)
Load reference objects that overlap a circular sky region.