23 from __future__
import absolute_import, division, print_function
25 __all__ = [
"getRefFluxField",
"getRefFluxKeys",
"LoadReferenceObjectsTask",
"LoadReferenceObjectsConfig"]
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: ICRS position of star on sky (an lsst.afw.geom.SpherePoint) 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.geom.SkyWcs) 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 209 self.log.info(
"Loading reference objects using center %s and radius %s deg" %
210 (circle.coord, circle.radius.asDegrees()))
211 loadRes = self.
loadSkyCircle(circle.coord, circle.radius, filterName)
212 refCat = loadRes.refCat
213 numFound = len(refCat)
216 refCat = self.
_trimToBBox(refCat=refCat, bbox=circle.bbox, wcs=wcs)
217 numTrimmed = numFound - len(refCat)
218 self.log.debug(
"trimmed %d out-of-bbox objects, leaving %d", numTrimmed, len(refCat))
219 self.log.info(
"Loaded %d reference objects", len(refCat))
221 loadRes.refCat = refCat
226 """!Load reference objects that overlap a circular sky region 228 @param[in] ctrCoord ICRS center of search region (an lsst.afw.geom.SpherePoint) 229 @param[in] radius radius of search region (an lsst.afw.geom.Angle) 230 @param[in] filterName name of filter, or None for the default filter; 231 used for flux values in case we have flux limits (which are not yet implemented) 233 @return an lsst.pipe.base.Struct containing: 234 - refCat a catalog of reference objects with the 235 \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink 236 as documented in LoadReferenceObjects, including photometric, resolved and variable; 237 hasCentroid is False for all objects. 238 - fluxField = name of flux field for specified filterName 243 def _trimToBBox(refCat, bbox, wcs):
244 """!Remove objects outside a given pixel-based bbox and set centroid and hasCentroid fields 246 @param[in,out] refCat a catalog of objects (an lsst.afw.table.SimpleCatalog, 247 or other table type that has fields "coord", "centroid" and "hasCentroid"). 248 The "coord" field is read. 249 The "centroid" and "hasCentroid" fields are set. 250 @param[in] bbox pixel region (an afwImage.Box2D) 251 @param[in] wcs WCS used to convert sky position to pixel position (an lsst.afw.math.WCS) 253 @return a catalog of reference objects in bbox, with centroid and hasCentroid fields set 255 afwTable.updateRefCentroids(wcs, refCat)
256 centroidKey = afwTable.Point2DKey(refCat.schema[
"centroid"])
257 retStarCat = type(refCat)(refCat.table)
259 point = star.get(centroidKey)
260 if bbox.contains(point):
261 retStarCat.append(star)
264 def _addFluxAliases(self, schema):
265 """Add aliases for camera filter fluxes to the schema 267 If self.config.defaultFilter then adds these aliases: 268 camFlux: <defaultFilter>_flux 269 camFluxSigma: <defaultFilter>_fluxSigma, if the latter exists 271 For each camFilter: refFilter in self.config.filterMap adds these aliases: 272 <camFilter>_camFlux: <refFilter>_flux 273 <camFilter>_camFluxSigma: <refFilter>_fluxSigma, if the latter exists 275 @throw RuntimeError if any reference flux field is missing from the schema 277 aliasMap = schema.getAliasMap()
279 def addAliasesForOneFilter(filterName, refFilterName):
280 """Add aliases for a single filter 282 @param[in] filterName camera filter name, or "" 283 the name is <filterName>_camFlux or camFlux if filterName is None 284 @param[in] refFilterName reference filter name; <refFilterName>_flux must exist 286 camFluxName = filterName +
"_camFlux" if filterName
is not None else "camFlux" 287 refFluxName = refFilterName +
"_flux" 288 if refFluxName
not in schema:
289 raise RuntimeError(
"Unknown reference filter %s" % (refFluxName,))
290 aliasMap.set(camFluxName, refFluxName)
291 refFluxErrName = refFluxName +
"Sigma" 292 if refFluxErrName
in schema:
293 camFluxErrName = camFluxName +
"Sigma" 294 aliasMap.set(camFluxErrName, refFluxErrName)
296 if self.config.defaultFilter:
297 addAliasesForOneFilter(
None, self.config.defaultFilter)
299 for filterName, refFilterName
in self.config.filterMap.items():
300 addAliasesForOneFilter(filterName, refFilterName)
304 addIsPhotometric=False, addIsResolved=False, addIsVariable=False):
305 """!Make the standard schema for reference object catalogs 307 @param[in] filterNameList list of filter names; used to create *filterName*_flux fields 308 @param[in] addFluxSigma if True then include flux sigma fields 309 @param[in] addIsPhotometric if True add field "photometric" 310 @param[in] addIsResolved if True add field "resolved" 311 @param[in] addIsVariable if True add field "variable" 313 schema = afwTable.SimpleTable.makeMinimalSchema()
314 afwTable.Point2DKey.addFields(
317 "centroid on an exposure, if relevant",
323 doc=
"is position known?",
325 for filterName
in filterNameList:
327 field=
"%s_flux" % (filterName,),
329 doc=
"flux in filter %s" % (filterName,),
333 for filterName
in filterNameList:
335 field=
"%s_fluxSigma" % (filterName,),
337 doc=
"flux uncertainty in filter %s" % (filterName,),
344 doc=
"set if the object can be used for photometric calibration",
350 doc=
"set if the object is spatially resolved",
356 doc=
"set if the object has variable brightness",
360 def _calculateCircle(self, bbox, wcs):
361 """!Compute on-sky center and radius of search region 363 @param[in] bbox bounding box for pixels (an lsst.afw.geom.Box2I or Box2D) 364 @param[in] wcs WCS (an lsst.afw.geom.SkyWcs) 365 @return an lsst.pipe.base.Struct containing: 366 - coord: ICRS center of the search region (lsst.afw.geom.SpherePoint) 367 - radius: the radius of the search region (lsst.afw.geom.Angle) 368 - bbox: the bounding box used to compute the circle (lsst.afw.geom.Box2D) 371 bbox.grow(self.config.pixelMargin)
372 coord = wcs.pixelToSky(bbox.getCenter())
373 radius = max(coord.separation(wcs.pixelToSky(pp))
for pp
in bbox.getCorners())
374 return pipeBase.Struct(coord=coord, radius=radius, bbox=bbox)
377 """!Return metadata about the load 379 This metadata is used for reloading the catalog (e.g., for 380 reconstituting a normalised match list. 382 @param[in] bbox bounding box for pixels (an lsst.afw.geom.Box2I or Box2D) 383 @param[in] wcs WCS (an lsst.afw.geom.SkyWcs) 384 @param[in] filterName name of camera filter, or None or blank for the default filter 385 @param[in] calib calibration, or None if unknown 386 @return metadata (lsst.daf.base.PropertyList) 392 """!Return metadata about the load 394 This metadata is used for reloading the catalog (e.g., for 395 reconstituting a normalised match list. 397 @param[in] coord ICRS centr of circle (lsst.afw.geom.SpherePoint) 398 @param[in] radius radius of circle (lsst.afw.geom.Angle) 399 @param[in] filterName name of camera filter, or None or blank for the default filter 400 @param[in] calib calibration, or None if unknown 401 @return metadata (lsst.daf.base.PropertyList) 404 md.add(
'RA', coord.getRa().asDegrees(),
'field center in degrees')
405 md.add(
'DEC', coord.getDec().asDegrees(),
'field center in degrees')
406 md.add(
'RADIUS', radius.asDegrees(),
'field radius in degrees, minimum')
407 md.add(
'SMATCHV', 1,
'SourceMatchVector version number')
408 filterName =
"UNKNOWN" if filterName
is None else str(filterName)
409 md.add(
'FILTER', filterName,
'filter name for photometric data')
413 """!Relink an unpersisted match list to sources and reference objects 415 A match list is persisted and unpersisted as a catalog of IDs produced by 416 afw.table.packMatches(), with match metadata (as returned by the astrometry tasks) 417 in the catalog's metadata attribute. This method converts such a match catalog 418 into a match list (an lsst.afw.table.ReferenceMatchVector) with links to source 419 records and reference object records. 421 @param[in] matchCat Unperisted packed match list (an lsst.afw.table.BaseCatalog). 422 matchCat.table.getMetadata() must contain match metadata, 423 as returned by the astrometry tasks. 424 @param[in,out] sourceCat Source catalog (an lsst.afw.table.SourceCatalog). 425 As a side effect, the catalog will be sorted by ID. 427 @return the match list (an lsst.afw.table.ReferenceMatchVector) 429 matchmeta = matchCat.table.getMetadata()
430 version = matchmeta.getInt(
'SMATCHV')
432 raise ValueError(
'SourceMatchVector version number is %i, not 1.' % version)
433 filterName = matchmeta.getString(
'FILTER').strip()
435 matchmeta.getDouble(
'DEC'), afwGeom.degrees)
436 rad = matchmeta.getDouble(
'RADIUS') * afwGeom.degrees
437 refCat = self.
loadSkyCircle(ctrCoord, rad, filterName).refCat
440 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 getMetadataCircle(self, coord, radius, filterName, calib=None)
Return metadata about the load.
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.
def _calculateCircle(self, bbox, wcs)
Compute on-sky center and radius of search region.
def getMetadataBox(self, bbox, wcs, filterName=None, calib=None)
Return metadata about the load.