24 __all__ = [
"getRefFluxField",
"getRefFluxKeys",
"LoadReferenceObjectsTask",
"LoadReferenceObjectsConfig",
25 "ReferenceObjectLoader"]
42 from lsst
import sphgeom
47 """This is a private helper class which filters catalogs by 48 row based on the row being inside the region used to initialize 53 region : `lsst.sphgeom.Region` 54 The spatial region which all objects should lie within 60 """This call method on an instance of this class takes in a reference 61 catalog, and the region from which the catalog was generated. 63 If the catalog region is entirely contained within the region used to 64 initialize this class, then all the entries in the catalog must be 65 within the region and so the whole catalog is returned. 67 If the catalog region is not entirely contained, then the location for 68 each record is tested against the region used to initialize the class. 69 Records which fall inside this region are added to a new catalog, and 70 this catalog is then returned. 74 refCat : `lsst.afw.table.SourceCatalog` 75 SourceCatalog to be filtered. 76 catRegion : `lsst.sphgeom.Region` 77 Region in which the catalog was created 79 if catRegion.isWithin(self.
region):
83 filteredRefCat =
type(refCat)(refCat.table)
86 filteredRefCat.append(record)
91 """ This class facilitates loading reference catalogs with gen 3 middleware 93 The middleware preflight solver will create a list of datarefs that may 94 possibly overlap a given region. These datarefs are then used to construct 95 and instance of this class. The class instance should then be passed into 96 a task which needs reference catalogs. These tasks should then determine 97 the exact region of the sky reference catalogs will be loaded for, and 98 call a corresponding method to load the reference objects. 100 def __init__(self, dataIds, butler, config, log=None):
101 """ Constructs an instance of ReferenceObjectLoader 105 dataIds : iterable of `lsst.daf.butler.DataIds` 106 An iterable object of DataSetRefs which point to reference catalogs 107 in a gen 3 repository 108 bulter : `lsst.daf.bulter.Butler` 109 A gen 3 butler instance 111 Logger object used to write out messages. If `None` (default) the default 112 lsst logger will be used 121 def _makeBoxRegion(BBox, wcs, BBoxPadding):
128 outerLocalBBox.grow(BBoxPadding)
129 innerLocalBBox.grow(-1*BBoxPadding)
137 innerBoxCorners = innerLocalBBox.getCorners()
138 innerSphCorners = [wcs.pixelToSky(corner).getVector()
for corner
in innerBoxCorners]
143 outerBoxCorners = outerLocalBBox.getCorners()
144 outerSphCorners = [wcs.pixelToSky(corner).getVector()
for corner
in outerBoxCorners]
148 return innerSkyRegion, outerSkyRegion, innerSphCorners, outerSphCorners
150 def loadPixelBox(self, bbox, wcs, filterName=None, epoch=None, calib=None, bboxPadding=100):
151 """Load reference objects that are within a pixel-based rectangular region 153 This algorithm works by creating a spherical box whose corners correspond 154 to the WCS converted corners of the input bounding box (possibly padded). 155 It then defines a filtering function which will look at a reference 156 objects pixel position and accept objects that lie within the specified 159 The spherical box region and filtering function are passed to the generic 160 loadRegion method which will load and filter the reference objects from 161 the datastore and return a single catalog containing all reference objects 165 bbox : `lsst.geom.box2I` 166 Box which bounds a region in pixel space 167 wcs : `lsst.afw.geom.SkyWcs` 168 Wcs object defining the pixel to sky (and inverse) transform for the space 169 of pixels of the supplied bbox 171 Name of camera filter, or None or blank for the default filter 172 epoch : `astropy.time.Time` (optional) 173 Epoch to which to correct proper motion and parallax, 174 or None to not apply such corrections. 176 Deprecated and ignored, only included for api compatibility 178 Number describing how much to pad the input bbox by (in pixels), defaults 179 to 100. This parameter is necessary because optical distortions in telescopes 180 can cause a rectangular pixel grid to map into a non "rectangular" spherical 181 region in sky coordinates. This padding is used to create a spherical 182 "rectangle", which will for sure enclose the input box. This padding is only 183 used to determine if the reference catalog for a sky patch will be loaded from 184 the data store, this function will filter out objects which lie within the 185 padded region but fall outside the input bounding box region. 189 referenceCatalog : `lsst.afw.table.SimpleCatalog` 190 Catalog containing reference objects inside the specified bounding box 194 `lsst.pex.exception.RuntimeError` 195 Raised if no reference catalogs could be found for the specified region 197 `lsst.pex.exception.TypeError` 198 Raised if the loaded reference catalogs do not have matching schemas 200 innerSkyRegion, outerSkyRegion, _, _ = self.
_makeBoxRegion(bbox, wcs, bboxPadding)
202 def _filterFunction(refCat, region):
209 if innerSkyRegion.contains(region):
212 filteredRefCat =
type(refCat)(refCat.table)
214 for record
in refCat:
215 pixCoords = record[centroidKey]
217 filteredRefCat.append(record)
218 return filteredRefCat
219 return self.
loadRegion(outerSkyRegion, filtFunc=_filterFunction, epoch=epoch, filterName=filterName)
221 def loadRegion(self, region, filtFunc=None, filterName=None, epoch=None):
222 """ Load reference objects within a specified region 224 This function loads the DataIds used to construct an instance of this class 225 which intersect or are contained within the specified region. The reference 226 catalogs which intersect but are not fully contained within the input region are 227 further filtered by the specified filter function. This function will return a 228 single source catalog containing all reference objects inside the specified region. 232 region : `lsst.sphgeom.Region` 233 This can be any type that is derived from `lsst.sphgeom.region` and should 234 define the spatial region for which reference objects are to be loaded. 236 This optional parameter should be a callable object that takes a reference 237 catalog and its corresponding region as parameters, filters the catalog by 238 some criteria and returns the filtered reference catalog. If the value is 239 left as the default (None) than an internal filter function is used which 240 filters according to if a reference object falls within the input region. 242 Name of camera filter, or None or blank for the default filter 243 epoch : `astropy.time.Time` (optional) 244 Epoch to which to correct proper motion and parallax, 245 or None to not apply such corrections. 249 referenceCatalog : `lsst.afw.table.SourceCatalog` 250 Catalog containing reference objects which intersect the input region, 251 filtered by the specified filter function 255 `lsst.pex.exception.RuntimeError` 256 Raised if no reference catalogs could be found for the specified region 258 `lsst.pex.exception.TypeError` 259 Raised if the loaded reference catalogs do not have matching schemas 262 regionBounding = region.getBoundingBox()
263 self.
log.
info(
"Loading reference objects from region bounded by {}, {} lat lon".
format(
264 regionBounding.getLat(), regionBounding.getLon()))
273 intersects = dataId.region.intersects(region)
275 intersects = region.intersects(dataId.region)
278 overlapList.append(dataId)
280 if len(overlapList) == 0:
283 firstCat = self.
butler.get(
'ref_cat', overlapList[0])
284 refCat = filtFunc(firstCat, overlapList[0].region)
285 trimmedAmount = len(firstCat) - len(refCat)
288 for dataId
in overlapList[1:]:
289 tmpCat = self.
butler.get(
'ref_cat', dataId)
291 if tmpCat.schema != firstCat.schema:
294 filteredCat = filtFunc(tmpCat, dataId.region)
295 refCat.extend(filteredCat)
296 trimmedAmount += len(tmpCat) - len(filteredCat)
298 self.
log.
debug(f
"Trimmed {trimmedAmount} out of region objects, leaving {len(refCat)}")
299 self.
log.
info(f
"Loaded {len(refCat)} reference objects")
301 if epoch
is not None and "pm_ra" in refCat.schema:
303 if isinstance(refCat.schema[
"pm_ra"].asKey(), lsst.afw.table.KeyAngle):
306 self.
log.
warn(
"Catalog pm_ra field is not an Angle; not applying proper motion")
314 if not expandedCat.isContiguous():
315 expandedCat = refCat.copy(deep=
True)
317 fluxField =
getRefFluxField(schema=expandedCat.schema, filterName=filterName)
318 return pipeBase.Struct(refCat=expandedCat, fluxField=fluxField)
321 """Load reference objects that lie within a circular region on the sky 323 This method constructs a circular region from an input center and angular radius, 324 loads reference catalogs which are contained in or intersect the circle, and 325 filters reference catalogs which intersect down to objects which lie within 330 ctrCoord : `lsst.geom.SpherePoint` 331 Point defining the center of the circular region 332 radius : `lsst.geom.Angle` 333 Defines the angular radius of the circular region 335 Name of camera filter, or None or blank for the default filter 336 epoch : `astropy.time.Time` (optional) 337 Epoch to which to correct proper motion and parallax, 338 or None to not apply such corrections. 342 referenceCatalog : `lsst.afw.table.SourceCatalog` 343 Catalog containing reference objects inside the specified bounding box 347 `lsst.pex.exception.RuntimeError` 348 Raised if no reference catalogs could be found for the specified region 350 `lsst.pex.exception.TypeError` 351 Raised if the loaded reference catalogs do not have matching schemas 354 centerVector = ctrCoord.getVector()
357 return self.
loadRegion(circularRegion, filterName=filterName, epoch=
None)
360 """Relink an unpersisted match list to sources and reference 363 A match list is persisted and unpersisted as a catalog of IDs 364 produced by afw.table.packMatches(), with match metadata 365 (as returned by the astrometry tasks) in the catalog's metadata 366 attribute. This method converts such a match catalog into a match 367 list, with links to source records and reference object records. 371 matchCat : `lsst.afw.table.BaseCatalog` 372 Unpersisted packed match list. 373 ``matchCat.table.getMetadata()`` must contain match metadata, 374 as returned by the astrometry tasks. 375 sourceCat : `lsst.afw.table.SourceCatalog` 376 Source catalog. As a side effect, the catalog will be sorted 381 matchList : `lsst.afw.table.ReferenceMatchVector` 387 def getMetadataBox(cls, bbox, wcs, filterName=None, calib=None, epoch=None, bboxPadding=100):
388 """Return metadata about the load 390 This metadata is used for reloading the catalog (e.g., for 391 reconstituting a normalised match list.) 395 bbox : `lsst.geom.Box2I` 396 Bounding bos for the pixels 397 wcs : `lsst.afw.geom.SkyWcs 399 filterName : `str` or None 400 filterName of the camera filter, or None or blank for the default filter 402 Deprecated, only included for api compatibility 403 epoch : `astropy.time.Time` (optional) 404 Epoch to which to correct proper motion and parallax, 405 or None to not apply such corrections. 407 Number describing how much to pad the input bbox by (in pixels), defaults 408 to 100. This parameter is necessary because optical distortions in telescopes 409 can cause a rectangular pixel grid to map into a non "rectangular" spherical 410 region in sky coordinates. This padding is used to create a spherical 411 "rectangle", which will for sure enclose the input box. This padding is only 412 used to determine if the reference catalog for a sky patch will be loaded from 413 the data store, this function will filter out objects which lie within the 414 padded region but fall outside the input bounding box region. 417 md : `lsst.daf.base.PropertyList` 419 _, _, innerCorners, outerCorners = cls.
_makeBoxRegion(bbox, wcs, bboxPadding)
421 for box, corners
in zip((
"INNER",
"OUTER"), (innerCorners, outerCorners)):
422 for (name, corner)
in zip((
"UPPER_LEFT",
"UPPER_RIGHT",
"LOWER_LEFT",
"LOWER_RIGHT"),
424 md.add(f
"{box}_{name}_RA",
geom.SpherePoint(corner).getRa().asDegrees(), f
"{box}_corner")
425 md.add(f
"{box}_{name}_DEC",
geom.SpherePoint(corner).getDec().asDegrees(), f
"{box}_corner")
426 md.add(
"SMATCHV", 1,
'SourceMatchVector version number')
427 filterName =
"UNKNOWN" if filterName
is None else str(filterName)
428 md.add(
'FILTER', filterName,
'filter name for photometric data')
431 md.add(
'EPOCH',
"NONE" if epoch
is None else str(epoch),
'Epoch (TAI MJD) for catalog')
436 """Return metadata about the load 438 This metadata is used for reloading the catalog (e.g. for reconstituting 439 a normalized match list.) 443 coord : `lsst.geom.SpherePoint` 444 ICRS center of a circle 445 radius : `lsst.geom.angle` 447 filterName : `str` or None 448 filterName of the camera filter, or None or blank for the default filter 450 Deprecated, only included for api compatibility 451 epoch : `astropy.time.Time` (optional) 452 Epoch to which to correct proper motion and parallax, 453 or None to not apply such corrections. 457 md : `lsst.daf.base.PropertyList` 460 md.add(
'RA', coord.getRa().asDegrees(),
'field center in degrees')
461 md.add(
'DEC', coord.getDec().asDegrees(),
'field center in degrees')
462 md.add(
'RADIUS', radius.asDegrees(),
'field radius in degrees, minimum')
463 md.add(
'SMATCHV', 1,
'SourceMatchVector version number')
464 filterName =
"UNKNOWN" if filterName
is None else str(filterName)
465 md.add(
'FILTER', filterName,
'filter name for photometric data')
466 md.add(
'EPOCH',
"NONE" if epoch
is None else epoch,
'Epoch (TAI MJD) for catalog')
471 """This function creates a new catalog containing the information of the input refCat 472 as well as added flux columns and aliases between camera and reference flux. 476 refCat : `lsst.afw.table.SimpleCatalog` 477 Catalog of reference objects 478 defaultFilter : `str` 479 Name of the default reference filter 480 filterReferenceMap : `dict` of `str` 481 Dictionary with keys corresponding to a filter name, and values which 482 correspond to the name of the reference filter. 486 refCat : `lsst.afw.table.SimpleCatalog` 487 Reference catalog with columns added to track reference filters 492 If specified reference filter name is not a filter specifed as a key in the 493 reference filter map. 495 refCat = ReferenceObjectLoader.remapReferenceCatalogSchema(refCat,
496 filterNameList=filterReferenceMap.keys())
497 aliasMap = refCat.schema.getAliasMap()
499 if filterReferenceMap
is None:
500 filterReferenceMap = {}
501 for filterName, refFilterName
in itertools.chain([(
None, defaultFilter)],
502 filterReferenceMap.items()):
504 camFluxName = filterName +
"_camFlux" if filterName
is not None else "camFlux" 505 refFluxName = refFilterName +
"_flux" 506 if refFluxName
not in refCat.schema:
507 raise RuntimeError(
"Unknown reference filter %s" % (refFluxName,))
508 aliasMap.set(camFluxName, refFluxName)
510 refFluxErrName = refFluxName +
"Err" 511 camFluxErrName = camFluxName +
"Err" 512 aliasMap.set(camFluxErrName, refFluxErrName)
518 """This function takes in a reference catalog and creates a new catalog with additional 519 columns defined the remaining function arguments. 523 refCat : `lsst.afw.table.SimpleCatalog` 524 Reference catalog to map to new catalog 528 expandedCat : `lsst.afw.table.SimpleCatalog` 529 Deep copy of input reference catalog with additional columns added 532 mapper.addMinimalSchema(refCat.schema,
True)
533 mapper.editOutputSchema().disconnectAliases()
535 for filterName
in filterNameList:
536 mapper.editOutputSchema().addField(f
"{filterName}_flux",
538 doc=f
"flux in filter {filterName}",
541 mapper.editOutputSchema().addField(f
"{filterName}_fluxErr",
543 doc=f
"flux uncertanty in filter {filterName}",
548 mapper.editOutputSchema().addField(
"centroid_x", type=float, doReplace=
True)
549 mapper.editOutputSchema().addField(
"centroid_y", type=float, doReplace=
True)
550 mapper.editOutputSchema().addField(
"hasCentroid", type=
"Flag", doReplace=
True)
551 mapper.editOutputSchema().getAliasMap().
set(
"slot_Centroid",
"centroid")
554 mapper.editOutputSchema().addField(
"photometric",
556 doc=
"set if the object can be used for photometric" +
559 mapper.editOutputSchema().addField(
"resolved",
561 doc=
"set if the object is spatially resolved" 563 mapper.editOutputSchema().addField(
"variable",
565 doc=
"set if the object has variable brightness" 569 expandedCat.extend(refCat, mapper=mapper)
575 """Get the name of a flux field from a schema. 577 if filterName is specified: 578 return *filterName*_camFlux if present 579 else return *filterName*_flux if present (camera filter name matches reference filter name) 580 else throw RuntimeError 582 return camFlux, if present, 583 else throw RuntimeError 587 schema : `lsst.afw.table.Schema` 588 Reference catalog schema. 590 Name of camera filter. 594 fluxFieldName : `str` 600 If an appropriate field is not found. 603 raise RuntimeError(
"schema=%s is not a schema" % (schema,))
605 fluxFieldList = [filterName +
"_camFlux", filterName +
"_flux"]
607 fluxFieldList = [
"camFlux"]
608 for fluxField
in fluxFieldList:
609 if fluxField
in schema:
612 raise RuntimeError(
"Could not find flux field(s) %s" % (
", ".join(fluxFieldList)))
616 """Return keys for flux and flux error. 620 schema : `lsst.afw.table.Schema` 621 Reference catalog schema. 623 Name of camera filter. 627 keys : `tuple` of (`lsst.afw.table.Key`, `lsst.afw.table.Key`) 631 - flux error key, if present, else None 636 If flux field not found. 639 fluxErrField = fluxField +
"Err" 640 fluxKey = schema[fluxField].asKey()
642 fluxErrKey = schema[fluxErrField].asKey()
645 return (fluxKey, fluxErrKey)
649 pixelMargin = pexConfig.RangeField(
650 doc=
"Padding to add to 4 all edges of the bounding box (pixels)",
655 defaultFilter = pexConfig.Field(
656 doc=
"Default reference catalog filter to use if filter not specified in exposure; " 657 "if blank then filter must be specified in exposure",
661 filterMap = pexConfig.DictField(
662 doc=
"Mapping of camera filter name: reference catalog filter name; " 663 "each reference filter must exist",
668 requireProperMotion = pexConfig.Field(
669 doc=
"Require that the fields needed to correct proper motion " 670 "(epoch, pm_ra and pm_dec) are present?",
685 r"""!Abstract base class to load objects from reference catalogs 687 @anchor LoadReferenceObjectsTask_ 689 @section meas_algorithms_loadReferenceObjects_Contents Contents 691 - @ref meas_algorithms_loadReferenceObjects_Purpose 692 - @ref meas_algorithms_loadReferenceObjects_Initialize 693 - @ref meas_algorithms_loadReferenceObjects_IO 694 - @ref meas_algorithms_loadReferenceObjects_Schema 695 - @ref meas_algorithms_loadReferenceObjects_Config 697 @section meas_algorithms_loadReferenceObjects_Purpose Description 699 Abstract base class for tasks that load objects from a reference catalog 700 in a particular region of the sky. 702 Implementations must subclass this class, override the loadSkyCircle method, 703 and will typically override the value of ConfigClass with a task-specific config class. 705 @section meas_algorithms_loadReferenceObjects_Initialize Task initialisation 707 @copydoc \_\_init\_\_ 709 @section meas_algorithms_loadReferenceObjects_IO Invoking the Task 711 @copydoc loadPixelBox 713 @section meas_algorithms_loadReferenceObjects_Schema Schema of the reference object catalog 715 Reference object catalogs are instances of lsst.afw.table.SimpleCatalog with the following schema 716 (other fields may also be present). 717 The units use astropy quantity conventions, so a 2 suffix means squared. 718 See also makeMinimalSchema. 719 - coord: ICRS position of star on sky (an lsst.geom.SpherePoint) 720 - centroid: position of star on an exposure, if relevant (an lsst.afw.Point2D) 721 - hasCentroid: is centroid usable? (a Flag) 722 - *referenceFilterName*_flux: brightness in the specified reference catalog filter (Jy) 723 Note: the function lsst.afw.image.abMagFromFlux will convert flux in Jy to AB Magnitude. 724 - *referenceFilterName*_fluxErr (optional): brightness standard deviation (Jy); 725 omitted if no data is available; possibly nan if data is available for some objects but not others 726 - camFlux: brightness in default camera filter (Jy); omitted if defaultFilter not specified 727 - camFluxErr: brightness standard deviation for default camera filter; 728 omitted if defaultFilter not specified or standard deviation not available that filter 729 - *cameraFilterName*_camFlux: brightness in specified camera filter (Jy) 730 - *cameraFilterName*_camFluxErr (optional): brightness standard deviation 731 in specified camera filter (Jy); omitted if no data is available; 732 possibly nan if data is available for some objects but not others 733 - photometric (optional): is the object usable for photometric calibration? (a Flag) 734 - resolved (optional): is the object spatially resolved? (a Flag) 735 - variable (optional): does the object have variable brightness? (a Flag) 736 - coord_raErr: uncertainty in `coord` along the direction of right ascension (radian, an Angle) 737 = uncertainty in ra * cos(dec); nan if unknown 738 - coord_decErr: uncertainty in `coord` along the direction of declination (radian, an Angle); 741 The following are optional; fields should only be present if the 742 information is available for at least some objects. 743 Numeric values are `nan` if unknown: 744 - epoch: date of observation as TAI MJD (day) 746 - pm_ra: proper motion along the direction of right ascension (rad/year, an Angle) = dra/dt * cos(dec) 747 - pm_dec: proper motion along the direction of declination (rad/year, and Angle) 748 - pm_raErr: uncertainty in `pm_ra` (rad/year) 749 - pm_decErr: uncertainty in `pm_dec` (rad/year) 750 - pm_ra_dec_Cov: covariance between pm_ra and pm_dec (rad2/year2) 751 - pm_flag: set if proper motion, error or covariance is bad 753 - parallax: parallax (rad, an Angle) 754 - parallaxErr: uncertainty in `parallax` (rad) 755 - parallax_flag: set if parallax value or parallaxErr is bad 757 - coord_ra_pm_ra_Cov: covariance between coord_ra and pm_ra (rad2/year) 758 - coord_ra_pm_dec_Cov: covariance between coord_ra and pm_dec (rad2/year) 759 - coord_ra_parallax_Cov: covariance between coord_ra and parallax (rad2/year) 760 - coord_dec_pm_ra_Cov: covariance between coord_dec and pm_ra (rad2/year) 761 - coord_dec_pm_dec_Cov: covariance between coord_dec and pm_dec (rad2/year) 762 - coord_dec_parallax_Cov: covariance between coord_dec and parallax (rad2/year) 763 - pm_ra_parallax_Cov: covariance between pm_ra and parallax (rad2/year) 764 - pm_dec_parallax_Cov: covariance between pm_dec and parallax (rad2/year) 766 @section meas_algorithms_loadReferenceObjects_Config Configuration parameters 768 See @ref LoadReferenceObjectsConfig for a base set of configuration parameters. 769 Most subclasses will add configuration variables. 771 ConfigClass = LoadReferenceObjectsConfig
772 _DefaultName =
"LoadReferenceObjects" 775 """Construct a LoadReferenceObjectsTask 779 butler : `lsst.daf.persistence.Butler` 780 Data butler, for access reference catalogs. 782 pipeBase.Task.__init__(self, *args, **kwargs)
786 def loadPixelBox(self, bbox, wcs, filterName=None, calib=None, epoch=None):
787 """Load reference objects that overlap a rectangular pixel region. 791 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 792 Bounding box for pixels. 793 wcs : `lsst.afw.geom.SkyWcs` 794 WCS; used to convert pixel positions to sky coordinates 797 Name of filter, or `None` or `""` for the default filter. 798 This is used for flux values in case we have flux limits 799 (which are not yet implemented). 800 calib : `lsst.afw.image.Calib` (optional) 801 Calibration, or `None` if unknown. 802 epoch : `astropy.time.Time` (optional) 803 Epoch to which to correct proper motion and parallax, 804 or None to not apply such corrections. 808 results : `lsst.pipe.base.Struct` 809 A Struct containing the following fields: 810 refCat : `lsst.afw.catalog.SimpleCatalog` 811 A catalog of reference objects with the standard 812 schema, as documented in the main doc string for 813 `LoadReferenceObjects`. 814 The catalog is guaranteed to be contiguous. 816 Name of flux field for specified `filterName`. 820 The search algorithm works by searching in a region in sky 821 coordinates whose center is the center of the bbox and radius 822 is large enough to just include all 4 corners of the bbox. 823 Stars that lie outside the bbox are then trimmed from the list. 828 self.log.
info(
"Loading reference objects using center %s and radius %s deg" %
829 (circle.coord, circle.radius.asDegrees()))
830 loadRes = self.
loadSkyCircle(circle.coord, circle.radius, filterName)
831 refCat = loadRes.refCat
832 numFound = len(refCat)
835 refCat = self.
_trimToBBox(refCat=refCat, bbox=circle.bbox, wcs=wcs)
836 numTrimmed = numFound - len(refCat)
837 self.log.
debug(
"trimmed %d out-of-bbox objects, leaving %d", numTrimmed, len(refCat))
838 self.log.
info(
"Loaded %d reference objects", len(refCat))
841 if not refCat.isContiguous():
842 loadRes.refCat = refCat.copy(deep=
True)
848 """Load reference objects that overlap a circular sky region. 852 ctrCoord : `lsst.geom.SpherePoint` 853 ICRS center of search region. 854 radius : `lsst.geom.Angle` 855 Radius of search region. 856 filterName : `str` (optional) 857 Name of filter, or `None` or `""` for the default filter. 858 This is used for flux values in case we have flux limits 859 (which are not yet implemented). 860 epoch : `astropy.time.Time` (optional) 861 Epoch to which to correct proper motion and parallax, 862 or None to not apply such corrections. 866 results : `lsst.pipe.base.Struct` 867 A Struct containing the following fields: 868 refCat : `lsst.afw.catalog.SimpleCatalog` 869 A catalog of reference objects with the standard 870 schema, as documented in the main doc string for 871 `LoadReferenceObjects`. 872 The catalog is guaranteed to be contiguous. 874 Name of flux field for specified `filterName`. 878 Note that subclasses are responsible for performing the proper motion 879 correction, since this is the lowest-level interface for retrieving 885 def _trimToBBox(refCat, bbox, wcs):
886 """Remove objects outside a given pixel bounding box and set 887 centroid and hasCentroid fields. 891 refCat : `lsst.afw.table.SimpleCatalog` 892 A catalog of objects. The schema must include fields 893 "coord", "centroid" and "hasCentroid". 894 The "coord" field is read. 895 The "centroid" and "hasCentroid" fields are set. 896 bbox : `lsst.geom.Box2D` 898 wcs : `lsst.afw.geom.SkyWcs` 899 WCS; used to convert sky coordinates to pixel positions. 901 @return a catalog of reference objects in bbox, with centroid and hasCentroid fields set 905 retStarCat =
type(refCat)(refCat.table)
907 point = star.get(centroidKey)
908 if bbox.contains(point):
909 retStarCat.append(star)
912 def _addFluxAliases(self, schema):
913 """Add aliases for camera filter fluxes to the schema. 915 If self.config.defaultFilter then adds these aliases: 916 camFlux: <defaultFilter>_flux 917 camFluxErr: <defaultFilter>_fluxErr, if the latter exists 919 For each camFilter: refFilter in self.config.filterMap adds these aliases: 920 <camFilter>_camFlux: <refFilter>_flux 921 <camFilter>_camFluxErr: <refFilter>_fluxErr, if the latter exists 925 schema : `lsst.afw.table.Schema` 926 Schema for reference catalog. 931 If any reference flux field is missing from the schema. 933 aliasMap = schema.getAliasMap()
935 def addAliasesForOneFilter(filterName, refFilterName):
936 """Add aliases for a single filter 940 filterName : `str` (optional) 941 Camera filter name. The resulting alias name is 942 <filterName>_camFlux, or simply "camFlux" if `filterName` 944 refFilterName : `str` 945 Reference catalog filter name; the field 946 <refFilterName>_flux must exist. 948 camFluxName = filterName +
"_camFlux" if filterName
is not None else "camFlux" 949 refFluxName = refFilterName +
"_flux" 950 if refFluxName
not in schema:
951 raise RuntimeError(
"Unknown reference filter %s" % (refFluxName,))
952 aliasMap.set(camFluxName, refFluxName)
953 refFluxErrName = refFluxName +
"Err" 954 if refFluxErrName
in schema:
955 camFluxErrName = camFluxName +
"Err" 956 aliasMap.set(camFluxErrName, refFluxErrName)
958 if self.config.defaultFilter:
959 addAliasesForOneFilter(
None, self.config.defaultFilter)
961 for filterName, refFilterName
in self.config.filterMap.items():
962 addAliasesForOneFilter(filterName, refFilterName)
966 addIsPhotometric=False, addIsResolved=False,
967 addIsVariable=False, coordErrDim=2,
968 addProperMotion=False, properMotionErrDim=2,
969 addParallax=False, addParallaxErr=True):
970 """Make a standard schema for reference object catalogs. 974 filterNameList : `list` of `str` 975 List of filter names. Used to create <filterName>_flux fields. 976 addIsPhotometric : `bool` 977 If True then add field "photometric". 978 addIsResolved : `bool` 979 If True then add field "resolved". 980 addIsVariable : `bool` 981 If True then add field "variable". 983 Number of coord error fields; must be one of 0, 2, 3: 985 - If 2 or 3: add fields "coord_raErr" and "coord_decErr". 986 - If 3: also add field "coord_radecErr". 987 addProperMotion : `bool` 988 If True add fields "epoch", "pm_ra", "pm_dec" and "pm_flag". 989 properMotionErrDim : `int` 990 Number of proper motion error fields; must be one of 0, 2, 3; 991 ignored if addProperMotion false: 992 - If 2 or 3: add fields "pm_raErr" and "pm_decErr". 993 - If 3: also add field "pm_radecErr". 995 If True add fields "epoch", "parallax", "parallaxErr" 997 addParallaxErr : `bool` 998 If True add field "parallaxErr"; ignored if addParallax false. 1002 schema : `lsst.afw.table.Schema` 1003 Schema for reference catalog, an 1004 `lsst.afw.table.SimpleCatalog`. 1008 Reference catalogs support additional covariances, such as 1009 covariance between RA and proper motion in declination, 1010 that are not supported by this method, but can be added after 1011 calling this method. 1013 schema = afwTable.SimpleTable.makeMinimalSchema()
1015 afwTable.Point2DKey.addFields(
1018 "centroid on an exposure, if relevant",
1022 field=
"hasCentroid",
1024 doc=
"is position known?",
1026 for filterName
in filterNameList:
1028 field=
"%s_flux" % (filterName,),
1030 doc=
"flux in filter %s" % (filterName,),
1033 for filterName
in filterNameList:
1035 field=
"%s_fluxErr" % (filterName,),
1037 doc=
"flux uncertainty in filter %s" % (filterName,),
1040 if addIsPhotometric:
1042 field=
"photometric",
1044 doc=
"set if the object can be used for photometric calibration",
1050 doc=
"set if the object is spatially resolved",
1056 doc=
"set if the object has variable brightness",
1058 if coordErrDim
not in (0, 2, 3):
1059 raise ValueError(
"coordErrDim={}; must be (0, 2, 3)".
format(coordErrDim))
1061 afwTable.CovarianceMatrix2fKey.addFields(
1064 names=[
"ra",
"dec"],
1065 units=[
"rad",
"rad"],
1066 diagonalOnly=(coordErrDim == 2),
1069 if addProperMotion
or addParallax:
1073 doc=
"date of observation (TAI, MJD)",
1081 doc=
"proper motion in the right ascension direction = dra/dt * cos(dec)",
1087 doc=
"proper motion in the declination direction",
1090 if properMotionErrDim
not in (0, 2, 3):
1091 raise ValueError(
"properMotionErrDim={}; must be (0, 2, 3)".
format(properMotionErrDim))
1092 if properMotionErrDim > 0:
1093 afwTable.CovarianceMatrix2fKey.addFields(
1096 names=[
"ra",
"dec"],
1097 units=[
"rad/year",
"rad/year"],
1098 diagonalOnly=(properMotionErrDim == 2),
1103 doc=
"Set if proper motion or proper motion error is bad",
1115 field=
"parallaxErr",
1117 doc=
"uncertainty in parallax",
1121 field=
"parallax_flag",
1123 doc=
"Set if parallax or parallax error is bad",
1127 def _calculateCircle(self, bbox, wcs):
1128 """Compute on-sky center and radius of search region. 1132 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 1134 wcs : `lsst.afw.geom.SkyWcs` 1135 WCS; used to convert pixel positions to sky coordinates. 1139 results : `lsst.pipe.base.Struct` 1140 A Struct containing: 1142 - coord : `lsst.geom.SpherePoint` 1143 ICRS center of the search region. 1144 - radius : `lsst.geom.Angle` 1145 Radius of the search region. 1146 - bbox : `lsst.afw.geom.Box2D` 1147 Bounding box used to compute the circle. 1150 bbox.grow(self.config.pixelMargin)
1151 coord = wcs.pixelToSky(bbox.getCenter())
1152 radius =
max(coord.separation(wcs.pixelToSky(pp))
for pp
in bbox.getCorners())
1153 return pipeBase.Struct(coord=coord, radius=radius, bbox=bbox)
1156 """Return metadata about the load. 1158 This metadata is used for reloading the catalog (e.g., for 1159 reconstituting a normalised match list. 1163 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D` 1165 wcs : `lsst.afw.geom.SkyWcs` 1166 WCS; used to convert pixel positions to sky coordinates. 1168 Name of camera filter, or `None` or `""` for the default 1170 calib : `lsst.afw.image.Calib` (optional) 1171 Calibration, or `None` if unknown. 1172 epoch : `astropy.time.Time` (optional) 1173 Epoch to which to correct proper motion and parallax, 1174 or None to not apply such corrections. 1178 metadata : lsst.daf.base.PropertyList 1179 Metadata about the load. 1185 """Return metadata about the load. 1187 This metadata is used for reloading the catalog (e.g., for 1188 reconstituting a normalised match list. 1192 coord : `lsst.geom.SpherePoint` 1193 ICRS center of the search region. 1194 radius : `lsst.geom.Angle` 1195 Radius of the search region. 1197 Name of camera filter, or `None` or `""` for the default 1199 calib : `lsst.afw.image.Calib` (optional) 1200 Calibration, or `None` if unknown. 1201 epoch : `astropy.time.Time` (optional) 1202 Epoch to which to correct proper motion and parallax, 1203 or None to not apply such corrections. 1207 metadata : lsst.daf.base.PropertyList 1208 Metadata about the load 1211 md.add(
'RA', coord.getRa().asDegrees(),
'field center in degrees')
1212 md.add(
'DEC', coord.getDec().asDegrees(),
'field center in degrees')
1213 md.add(
'RADIUS', radius.asDegrees(),
'field radius in degrees, minimum')
1214 md.add(
'SMATCHV', 1,
'SourceMatchVector version number')
1215 filterName =
"UNKNOWN" if filterName
is None else str(filterName)
1216 md.add(
'FILTER', filterName,
'filter name for photometric data')
1217 md.add(
'EPOCH',
"NONE" if epoch
is None else epoch,
'Epoch (TAI MJD) for catalog')
1221 """Relink an unpersisted match list to sources and reference 1224 A match list is persisted and unpersisted as a catalog of IDs 1225 produced by afw.table.packMatches(), with match metadata 1226 (as returned by the astrometry tasks) in the catalog's metadata 1227 attribute. This method converts such a match catalog into a match 1228 list, with links to source records and reference object records. 1232 matchCat : `lsst.afw.table.BaseCatalog` 1233 Unperisted packed match list. 1234 ``matchCat.table.getMetadata()`` must contain match metadata, 1235 as returned by the astrometry tasks. 1236 sourceCat : `lsst.afw.table.SourceCatalog` 1237 Source catalog. As a side effect, the catalog will be sorted 1242 matchList : `lsst.afw.table.ReferenceMatchVector` 1248 """Apply proper motion correction to a reference catalog. 1250 Adjust position and position error in the ``catalog`` 1251 for proper motion to the specified ``epoch``, 1252 modifying the catalong in place. 1256 catalog : `lsst.afw.table.SimpleCatalog` 1257 Catalog of positions, containing: 1259 - Coordinates, retrieved by the table's coordinate key. 1260 - ``coord_raErr`` : Error in Right Ascension (rad). 1261 - ``coord_decErr`` : Error in Declination (rad). 1262 - ``pm_ra`` : Proper motion in Right Ascension (rad/yr, 1264 - ``pm_raErr`` : Error in ``pm_ra`` (rad/yr), optional. 1265 - ``pm_dec`` : Proper motion in Declination (rad/yr, 1267 - ``pm_decErr`` : Error in ``pm_dec`` (rad/yr), optional. 1268 - ``epoch`` : Mean epoch of object (an astropy.time.Time) 1269 epoch : `astropy.time.Time` (optional) 1270 Epoch to which to correct proper motion and parallax, 1271 or None to not apply such corrections. 1273 if (
"epoch" not in catalog.schema
or "pm_ra" not in catalog.schema
or "pm_dec" not in catalog.schema):
1274 if self.config.requireProperMotion:
1275 raise RuntimeError(
"Proper motion correction required but not available from catalog")
1276 self.log.
warn(
"Proper motion correction not available from catalog")
1282 """Relink an unpersisted match list to sources and reference 1285 A match list is persisted and unpersisted as a catalog of IDs 1286 produced by afw.table.packMatches(), with match metadata 1287 (as returned by the astrometry tasks) in the catalog's metadata 1288 attribute. This method converts such a match catalog into a match 1289 list, with links to source records and reference object records. 1294 Reference object loader to use in getting reference objects 1295 matchCat : `lsst.afw.table.BaseCatalog` 1296 Unperisted packed match list. 1297 ``matchCat.table.getMetadata()`` must contain match metadata, 1298 as returned by the astrometry tasks. 1299 sourceCat : `lsst.afw.table.SourceCatalog` 1300 Source catalog. As a side effect, the catalog will be sorted 1305 matchList : `lsst.afw.table.ReferenceMatchVector` 1308 matchmeta = matchCat.table.getMetadata()
1309 version = matchmeta.getInt(
'SMATCHV')
1311 raise ValueError(
'SourceMatchVector version number is %i, not 1.' % version)
1312 filterName = matchmeta.getString(
'FILTER').
strip()
1314 epoch = matchmeta.getDouble(
'EPOCH')
1317 if 'RADIUS' in matchmeta:
1320 matchmeta.getDouble(
'DEC'), lsst.geom.degrees)
1321 rad = matchmeta.getDouble(
'RADIUS') * lsst.geom.degrees
1322 refCat = refObjLoader.loadSkyCircle(ctrCoord, rad, filterName, epoch=epoch).refCat
1323 elif "INNER_UPPER_LEFT_RA" in matchmeta:
1329 for place
in (
"UPPER_LEFT",
"UPPER_RIGHT",
"LOWER_LEFT",
"LOWER_RIGHT"):
1331 matchmeta.getDouble(f
"OUTER_{place}_DEC"),
1332 lsst.geom.degrees).getVector()
1335 refCat = refObjLoader.loadRegion(outerBox, filterName=filterName, epoch=epoch).refCat
1343 """Apply proper motion correction to a reference catalog. 1345 Adjust position and position error in the ``catalog`` 1346 for proper motion to the specified ``epoch``, 1347 modifying the catalong in place. 1351 log : `lsst.log.log` 1352 log object to write to 1353 catalog : `lsst.afw.table.SimpleCatalog` 1354 Catalog of positions, containing: 1356 - Coordinates, retrieved by the table's coordinate key. 1357 - ``coord_raErr`` : Error in Right Ascension (rad). 1358 - ``coord_decErr`` : Error in Declination (rad). 1359 - ``pm_ra`` : Proper motion in Right Ascension (rad/yr, 1361 - ``pm_raErr`` : Error in ``pm_ra`` (rad/yr), optional. 1362 - ``pm_dec`` : Proper motion in Declination (rad/yr, 1364 - ``pm_decErr`` : Error in ``pm_dec`` (rad/yr), optional. 1365 - ``epoch`` : Mean epoch of object (an astropy.time.Time) 1366 epoch : `astropy.time.Time` (optional) 1367 Epoch to which to correct proper motion and parallax, 1368 or None to not apply such corrections. 1370 if "epoch" not in catalog.schema
or "pm_ra" not in catalog.schema
or "pm_dec" not in catalog.schema:
1371 log.warn(
"Proper motion correction not available from catalog")
1373 if not catalog.isContiguous():
1374 raise RuntimeError(
"Catalog must be contiguous")
1375 catEpoch = astropy.time.Time(catalog[
"epoch"], scale=
"tai", format=
"mjd")
1376 log.debug(
"Correcting reference catalog for proper motion to %r", epoch)
1378 timeDiffsYears = (epoch.tai - catEpoch).
to(astropy.units.yr).value
1379 coordKey = catalog.table.getCoordKey()
1382 pmRaRad = catalog[
"pm_ra"]
1383 pmDecRad = catalog[
"pm_dec"]
1384 offsetsRaRad = pmRaRad*timeDiffsYears
1385 offsetsDecRad = pmDecRad*timeDiffsYears
1393 offsetBearingsRad = numpy.arctan2(pmDecRad*1e6, pmRaRad*1e6)
1394 offsetAmountsRad = numpy.hypot(offsetsRaRad, offsetsDecRad)
1395 for record, bearingRad, amountRad
in zip(catalog, offsetBearingsRad, offsetAmountsRad):
1396 record.set(coordKey,
1397 record.get(coordKey).offset(bearing=bearingRad*lsst.geom.radians,
1398 amount=amountRad*lsst.geom.radians))
1400 if "coord_raErr" in catalog.schema:
1401 catalog[
"coord_raErr"] = numpy.hypot(catalog[
"coord_raErr"],
1402 catalog[
"pm_raErr"]*timeDiffsYears)
1403 if "coord_decErr" in catalog.schema:
1404 catalog[
"coord_decErr"] = numpy.hypot(catalog[
"coord_decErr"],
1405 catalog[
"pm_decErr"]*timeDiffsYears)
static Log getDefaultLogger()
Return default logger instance, same as default constructor.
Defines the fields and offsets for a table.
def loadPixelBox(self, bbox, wcs, filterName=None, calib=None, epoch=None)
def joinMatchListWithCatalog(self, matchCat, sourceCat)
def __call__(self, refCat, catRegion)
bool contains(VertexIterator const begin, VertexIterator const end, UnitVector3d const &v)
def addFluxAliases(refCat, defaultFilter, filterReferenceMap)
A floating-point coordinate rectangle geometry.
def getMetadataCircle(coord, radius, filterName, calib=None, epoch=None)
def loadSkyCircle(self, ctrCoord, radius, filterName=None, epoch=None)
Class for storing ordered metadata with comments.
A mapping between the keys of two Schemas, used to copy data between them.
def __init__(self, butler=None, args, kwargs)
def applyProperMotions(self, catalog, epoch)
def _trimToBBox(refCat, bbox, wcs)
daf::base::PropertySet * set
Box represents a rectangle in spherical coordinate space that contains its boundary.
void updateRefCentroids(geom::SkyWcs const &wcs, ReferenceCollection &refList)
Update centroids in a collection of reference objects.
Reports attempts to access elements using an invalid key.
def __init__(self, region)
def getMetadataBox(self, bbox, wcs, filterName=None, calib=None, epoch=None)
def joinMatchListWithCatalog(self, matchCat, sourceCat)
def getRefFluxField(schema, filterName=None)
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
def loadRegion(self, region, filtFunc=None, filterName=None, epoch=None)
def getRefFluxKeys(schema, filterName=None)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Abstract base class to load objects from reference catalogs.
def applyProperMotionsImpl(log, catalog, epoch)
def makeMinimalSchema(filterNameList, addCentroid=True, addIsPhotometric=False, addIsResolved=False, addIsVariable=False, coordErrDim=2, addProperMotion=False, properMotionErrDim=2, addParallax=False, addParallaxErr=True)
Circle is a circular region on the unit sphere that contains its boundary.
ConvexPolygon is a closed convex polygon on the unit sphere.
def loadPixelBox(self, bbox, wcs, filterName=None, epoch=None, calib=None, bboxPadding=100)
def getMetadataCircle(self, coord, radius, filterName, calib=None, epoch=None)
def _makeBoxRegion(BBox, wcs, BBoxPadding)
def joinMatchListWithCatalogImpl(refObjLoader, matchCat, sourceCat)
Angle represents an angle in radians.
Point in an unspecified spherical coordinate system.
def getMetadataBox(cls, bbox, wcs, filterName=None, calib=None, epoch=None, bboxPadding=100)
def __init__(self, dataIds, butler, config, log=None)
def loadSkyCircle(self, ctrCoord, radius, filterName=None, epoch=None)
template SourceMatchVector unpackMatches(BaseCatalog const &, SourceCatalog const &, SourceCatalog const &)
Reports errors from accepting an object of an unexpected or inappropriate type.
def _calculateCircle(self, bbox, wcs)
def remapReferenceCatalogSchema(refCat, filterNameList=None, position=False, photometric=False)
Reports errors that are due to events beyond the control of the program.