22 r"""Base classes for single-frame measurement plugins and the associated task. 
   24 In single-frame measurement, we assume that detection and probably deblending 
   25 have already been run on the same frame, so a `~lsst.afw.table.SourceCatalog` 
   26 has already been created with `lsst.afw.detection.Footprint`\ s (which may be 
   27 "heavy" — that is, include pixel data). Measurements are generally recorded in 
   28 the coordinate system of the image being measured (and all slot-eligible 
   29 fields must be), but non-slot fields may be recorded in other coordinate 
   30 systems if necessary to avoid information loss (this should, of course, be 
   31 indicated in the field documentation). 
   36 from .pluginRegistry 
import PluginRegistry
 
   37 from .baseMeasurement 
import (BaseMeasurementPluginConfig, BaseMeasurementPlugin,
 
   38                               BaseMeasurementConfig, BaseMeasurementTask)
 
   39 from .noiseReplacer 
import NoiseReplacer, DummyNoiseReplacer
 
   41 __all__ = (
"SingleFramePluginConfig", 
"SingleFramePlugin",
 
   42            "SingleFrameMeasurementConfig", 
"SingleFrameMeasurementTask")
 
   46     """Base class for single-frame plugin configuration classes. 
   52     """Base class for single-frame measurement plugin. 
   56     config : `SingleFramePlugin.ConfigClass` 
   57         Configuration for this plugin. 
   59         The string with which the plugin was registered. 
   60     schema : `lsst.afw.table.Schema` 
   61         The schema for the source table . New fields are added here to 
   62         hold measurements produced by this plugin. 
   63     metadata : `lsst.daf.base.PropertySet` 
   64         Plugin metadata that will be attached to the output catalog 
   65     logName : `str`, optional 
   66         Name to use when logging errors. 
   70     New plugins can be created in Python by inheriting directly from this 
   71     class and implementing the `measure`, `fail` (from `BasePlugin`), and 
   72     optionally `__init__` and `measureN` methods.  Plugins can also be defined 
   73     in C++ via the `WrappedSingleFramePlugin` class. 
   77     """Registry of subclasses of `SingleFramePlugin` (`PluginRegistry`). 
   80     ConfigClass = SingleFramePluginConfig
 
   82     def __init__(self, config, name, schema, metadata, logName=None, **kwds):
 
   83         BaseMeasurementPlugin.__init__(self, config, name, logName=logName)
 
   86         """Measure the properties of a source on a single image. 
   88         The image may be from a single epoch, or it may be a coadd. 
   92         measRecord : `lsst.afw.table.SourceRecord` 
   93             Record describing the object being measured. Previously-measured 
   94             quantities may be retrieved from here, and it will be updated 
   95             in-place tih the outputs of this plugin. 
   96         exposure : `lsst.afw.image.ExposureF` 
   97             The pixel data to be measured, together with the associated PSF, 
   98             WCS, etc. All other sources in the image should have been replaced 
   99             by noise according to deblender outputs. 
  101         raise NotImplementedError()
 
  104         """Measure the properties of blended sources on a single image. 
  106         This operates on all members of a blend family at once. The image may 
  107         be from a single epoch, or it may be a coadd. 
  111         measCat : `lsst.afw.table.SourceCatalog` 
  112             Catalog describing the objects (and only those objects) being 
  113             measured. Previously-measured quantities will be retrieved from 
  114             here, and it will be updated in-place with the outputs of this 
  116         exposure : `lsst.afw.image.ExposureF` 
  117             The pixel data to be measured, together with the associated PSF, 
  118             WCS, etc. All other sources in the image should have been replaced 
  119             by noise according to deblender outputs. 
  123         Derived classes that do not implement ``measureN`` should just inherit 
  124         this disabled version.  Derived classes that do implement ``measureN`` 
  125         should additionally add a bool doMeasureN config field to their config 
  126         class to signal that measureN-mode is available. 
  128         raise NotImplementedError()
 
  132     """Config class for single frame measurement driver task. 
  135     plugins = SingleFramePlugin.registry.makeField(
 
  137         default=[
"base_PixelFlags",
 
  139                  "base_NaiveCentroid",
 
  143                  "base_CircularApertureFlux",
 
  147                  "base_LocalBackground",
 
  149         doc=
"Plugins to be run and their configuration" 
  151     algorithms = property(
lambda self: self.
plugins, doc=
"backwards-compatibility alias for plugins")
 
  152     undeblended = SingleFramePlugin.registry.makeField(
 
  155         doc=
"Plugins to run on undeblended image" 
  160     """A subtask for measuring the properties of sources on a single exposure. 
  164     schema : `lsst.afw.table.Schema` 
  165         Schema of the output resultant catalog. Will be updated to provide 
  166         fields to accept the outputs of plugins which will be executed by this 
  168     algMetadata : `lsst.daf.base.PropertyList`, optional 
  169         Used to record metadaa about algorithm execution. An empty 
  170         `lsst.daf.base.PropertyList` will be created if `None`. 
  172         Keyword arguments forwarded to `BaseMeasurementTask`. 
  175     ConfigClass = SingleFrameMeasurementConfig
 
  177     NOISE_SEED_MULTIPLIER = 
"NOISE_SEED_MULTIPLIER" 
  178     """Name by which the noise seed multiplier is recorded in metadata ('str'). 
  181     NOISE_SOURCE = 
"NOISE_SOURCE" 
  182     """Name by which the noise source is recorded in metadata ('str'). 
  185     NOISE_OFFSET = 
"NOISE_OFFSET" 
  186     """Name by which the noise offset is recorded in metadata ('str'). 
  189     NOISE_EXPOSURE_ID = 
"NOISE_EXPOSURE_ID" 
  190     """Name by which the noise exposire ID is recorded in metadata ('str'). 
  193     def __init__(self, schema, algMetadata=None, **kwds):
 
  194         super(SingleFrameMeasurementTask, self).
__init__(algMetadata=algMetadata, **kwds)
 
  200         if 'base_Blendedness' in self.
plugins:
 
  207     def run(self, measCat, exposure, noiseImage=None, exposureId=None, beginOrder=None, endOrder=None):
 
  208         r"""Run single frame measurement over an exposure and source catalog. 
  212         measCat : `lsst.afw.table.SourceCatalog` 
  213             Catalog to be filled with the results of measurement. Must contain 
  214             all the `lsst.afw.table.SourceRecord`\ s to be measured (with 
  215             `lsst.afw.detection.Footprint`\ s attached), and have a schema 
  216             that is a superset of ``self.schema``. 
  217         exposure : `lsst.afw.image.ExposureF` 
  218             Image containing the pixel data to be measured together with 
  219             associated PSF, WCS, etc. 
  220         noiseImage : `lsst.afw.image.ImageF`, optional 
  221             Can be used to specify the a predictable noise replacement field 
  222             for testing purposes. 
  223         exposureId : `int`, optional 
  224             Unique exposure identifier used to calculate the random number 
  225             generator seed during noise replacement. 
  226         beginOrder : `float`, optional 
  227             Start execution order (inclusive): measurements with 
  228             ``executionOrder < beginOrder`` are not executed. `None` for no 
  230         endOrder : `float`, optional 
  231             Final execution order (exclusive): measurements with 
  232             ``executionOrder >= endOrder`` are not executed. `None` for no 
  236         footprints = {measRecord.getId(): (measRecord.getParent(), measRecord.getFootprint())
 
  237                       for measRecord 
in measCat}
 
  245         if self.
config.doReplaceWithNoise:
 
  247                                           noiseImage=noiseImage, log=self.
log, exposureId=exposureId)
 
  248             algMetadata = measCat.getMetadata()
 
  249             if algMetadata 
is not None:
 
  253                 if exposureId 
is not None:
 
  258         self.
runPlugins(noiseReplacer, measCat, exposure, beginOrder, endOrder)
 
  260     def runPlugins(self, noiseReplacer, measCat, exposure, beginOrder=None, endOrder=None):
 
  261         r"""Call the configured measument plugins on an image. 
  265         noiseReplacer : `NoiseReplacer` 
  266             Used to fill sources not being measured with noise. 
  267         measCat : `lsst.afw.table.SourceCatalog` 
  268             Catalog to be filled with the results of measurement. Must contain 
  269             all the `lsst.afw.table.SourceRecord`\ s to be measured (with 
  270             `lsst.afw.detection.Footprint`\ s attached), and have a schema 
  271             that is a superset of ``self.schema``. 
  272         exposure : `lsst.afw.image.ExposureF` 
  273             Image containing the pixel data to be measured together with 
  274             associated PSF, WCS, etc. 
  275         beginOrder : `float`, optional 
  276             Start execution order (inclusive): measurements with 
  277             ``executionOrder < beginOrder`` are not executed. `None` for no 
  279         endOrder : `float`, optional 
  280             Final execution order (exclusive): measurements with 
  281             ``executionOrder >= endOrder`` are not executed. `None` for no 
  286         measParentCat = measCat.getChildren(0)
 
  288         nMeasCat = len(measCat)
 
  289         nMeasParentCat = len(measParentCat)
 
  290         self.
log.
info(
"Measuring %d source%s (%d parent%s, %d child%s) ",
 
  291                       nMeasCat, (
"" if nMeasCat == 1 
else "s"),
 
  292                       nMeasParentCat, (
"" if nMeasParentCat == 1 
else "s"),
 
  293                       nMeasCat - nMeasParentCat, (
"" if nMeasCat - nMeasParentCat == 1 
else "ren"))
 
  295         for parentIdx, measParentRecord 
in enumerate(measParentCat):
 
  298             measChildCat = measCat.getChildren(measParentRecord.getId())
 
  301             for measChildRecord 
in measChildCat:
 
  302                 noiseReplacer.insertSource(measChildRecord.getId())
 
  303                 self.
callMeasure(measChildRecord, exposure, beginOrder=beginOrder, endOrder=endOrder)
 
  306                     self.
blendPlugin.cpp.measureChildPixels(exposure.getMaskedImage(), measChildRecord)
 
  308                 noiseReplacer.removeSource(measChildRecord.getId())
 
  311             noiseReplacer.insertSource(measParentRecord.getId())
 
  312             self.
callMeasure(measParentRecord, exposure, beginOrder=beginOrder, endOrder=endOrder)
 
  315                 self.
blendPlugin.cpp.measureChildPixels(exposure.getMaskedImage(), measParentRecord)
 
  318             self.
callMeasureN(measParentCat[parentIdx:parentIdx+1], exposure,
 
  319                               beginOrder=beginOrder, endOrder=endOrder)
 
  320             self.
callMeasureN(measChildCat, exposure, beginOrder=beginOrder, endOrder=endOrder)
 
  321             noiseReplacer.removeSource(measParentRecord.getId())
 
  328             for source 
in measCat:
 
  334             for source 
in measCat:
 
  335                 self.
blendPlugin.cpp.measureParentPixels(exposure.getMaskedImage(), source)
 
  338         """Backwards-compatibility alias for `run`. 
  340         self.
run(measCat, exposure)