22 """Base measurement task, which subclassed by the single frame and forced 
   27 import lsst.pex.config
 
   29 from .pluginRegistry 
import PluginMap
 
   30 from .exceptions 
import FatalAlgorithmError, MeasurementError
 
   31 from .pluginsBase 
import BasePluginConfig, BasePlugin
 
   32 from .noiseReplacer 
import NoiseReplacerConfig
 
   34 __all__ = (
"BaseMeasurementPluginConfig", 
"BaseMeasurementPlugin",
 
   35            "BaseMeasurementConfig", 
"BaseMeasurementTask")
 
   38 FATAL_EXCEPTIONS = (MemoryError, FatalAlgorithmError)
 
   42     """Base config class for all measurement plugins. 
   46     Most derived classes will want to override `setDefaults` in order to 
   47     customize the default `executionOrder`. 
   49     A derived class whose corresponding Plugin class implements a do `measureN` 
   50     method should additionally add a bool `doMeasureN` field to replace the 
   51     bool class attribute defined here. 
   54     doMeasure = lsst.pex.config.Field(dtype=bool, default=
True,
 
   55                                       doc=
"whether to run this plugin in single-object mode")
 
   61     """Base class for all measurement plugins. 
   65     This is class is a placeholder for future behavior which will be shared 
   66     only between measurement plugins and is implemented for symmetry with the 
   67     measurement base plugin configuration class 
   74     """Assign named plugins to measurement slots. 
   76     Slot configuration which assigns a particular named plugin to each of a set 
   77     of slots.  Each slot allows a type of measurement to be fetched from the 
   78     `lsst.afw.table.SourceTable` without knowing which algorithm was used to 
   83     The default algorithm for each slot must be registered, even if the default 
   87     Field = lsst.pex.config.Field
 
   88     centroid = 
Field(dtype=str, default=
"base_SdssCentroid", optional=
True,
 
   89                      doc=
"the name of the centroiding algorithm used to set source x,y")
 
   90     shape = 
Field(dtype=str, default=
"base_SdssShape", optional=
True,
 
   91                   doc=
"the name of the algorithm used to set source moments parameters")
 
   92     psfShape = 
Field(dtype=str, default=
"base_SdssShape_psf", optional=
True,
 
   93                      doc=
"the name of the algorithm used to set PSF moments parameters")
 
   94     apFlux = 
Field(dtype=str, default=
"base_CircularApertureFlux_12_0", optional=
True,
 
   95                    doc=
"the name of the algorithm used to set the source aperture instFlux slot")
 
   96     modelFlux = 
Field(dtype=str, default=
"base_GaussianFlux", optional=
True,
 
   97                       doc=
"the name of the algorithm used to set the source model instFlux slot")
 
   98     psfFlux = 
Field(dtype=str, default=
"base_PsfFlux", optional=
True,
 
   99                     doc=
"the name of the algorithm used to set the source psf instFlux slot")
 
  100     gaussianFlux = 
Field(dtype=str, default=
"base_GaussianFlux", optional=
True,
 
  101                          doc=
"the name of the algorithm used to set the source Gaussian instFlux slot")
 
  102     calibFlux = 
Field(dtype=str, default=
"base_CircularApertureFlux_12_0", optional=
True,
 
  103                       doc=
"the name of the instFlux measurement algorithm used for calibration")
 
  106         """Set up a slots in a schema following configuration directives. 
  110         schema : `lsst.afw.table.Schema` 
  111             The schema in which slots will be set up. 
  115         This is defined in this configuration class to support use in unit 
  116         tests without needing to construct an `lsst.pipe.base.Task` object. 
  118         aliases = schema.getAliasMap()
 
  120             aliases.set(
"slot_Centroid", self.
centroid)
 
  121         if self.
shape is not None:
 
  122             aliases.set(
"slot_Shape", self.
shape)
 
  124             aliases.set(
"slot_PsfShape", self.
psfShape)
 
  125         if self.
apFlux is not None:
 
  126             aliases.set(
"slot_ApFlux", self.
apFlux)
 
  128             aliases.set(
"slot_ModelFlux", self.
modelFlux)
 
  130             aliases.set(
"slot_PsfFlux", self.
psfFlux)
 
  134             aliases.set(
"slot_CalibFlux", self.
calibFlux)
 
  138     """Base configuration for all measurement driver tasks. 
  142     Subclasses should define the 'plugins' and 'undeblended' registries, e.g. 
  146         plugins = PluginBaseClass.registry.makeField( 
  149             doc="Plugins to be run and their configuration" 
  151         undeblended = PluginBaseClass.registry.makeField( 
  154             doc="Plugins to run on undeblended image" 
  157     where ``PluginBaseClass`` is the appropriate base class of the plugin 
  158     (e.g., `SingleFramePlugin` or `ForcedPlugin`). 
  161     slots = lsst.pex.config.ConfigField(
 
  162         dtype=SourceSlotConfig,
 
  163         doc=
"Mapping from algorithms to special aliases in Source." 
  166     doReplaceWithNoise = lsst.pex.config.Field(
 
  167         dtype=bool, default=
True, optional=
False,
 
  168         doc=
'When measuring, replace other detected footprints with noise?')
 
  170     noiseReplacer = lsst.pex.config.ConfigField(
 
  171         dtype=NoiseReplacerConfig,
 
  172         doc=
"configuration that sets how to replace neighboring sources with noise" 
  174     undeblendedPrefix = lsst.pex.config.Field(
 
  175         dtype=str, default=
"undeblended_",
 
  176         doc=
"Prefix to give undeblended plugins" 
  180         lsst.pex.config.Config.validate(self)
 
  181         if self.
slots.centroid 
is not None and self.
slots.centroid 
not in self.plugins.names:
 
  182             raise ValueError(
"source centroid slot algorithm is not being run.")
 
  183         if self.
slots.shape 
is not None and self.
slots.shape 
not in self.plugins.names:
 
  184             raise ValueError(
"source shape slot algorithm '%s' is not being run." % self.
slots.shape)
 
  185         for slot 
in (self.
slots.psfFlux, self.
slots.apFlux, self.
slots.modelFlux,
 
  186                      self.
slots.gaussianFlux, self.
slots.calibFlux):
 
  188                 for name 
in self.plugins.names:
 
  189                     if len(name) <= len(slot) 
and name == slot[:len(name)]:
 
  192                     raise ValueError(
"source instFlux slot algorithm '%s' is not being run." % slot)
 
  196     """Ultimate base class for all measurement tasks. 
  200     algMetadata : `lsst.daf.base.PropertyList` or `None` 
  201         Will be modified in-place to contain metadata about the plugins being 
  202         run. If `None`, an empty `~lsst.daf.base.PropertyList` will be 
  205         Additional arguments passed to `lsst.pipe.base.Task.__init__`. 
  209     This base class for `SingleFrameMeasurementTask` and 
  210     `ForcedMeasurementTask` mostly exists to share code between the two, and 
  211     generally should not be used directly. 
  214     ConfigClass = BaseMeasurementConfig
 
  215     _DefaultName = 
"measurement" 
  218     """Plugins to be invoked (`PluginMap`). 
  220     Initially empty, this will be populated as plugins are initialized. It 
  221     should be considered read-only. 
  225     """Metadata about active plugins (`lsst.daf.base.PropertyList`). 
  227     Contains additional information about active plugins to be saved with 
  228     the output catalog. Will be filled by subclasses. 
  232         super(BaseMeasurementTask, self).
__init__(**kwds)
 
  235         if algMetadata 
is None:
 
  243         """Initialize plugins (and slots) according to configuration. 
  248             Keyword arguments forwarded directly to plugin constructors. 
  252         Derived class constructors should call this method to fill the 
  253         `plugins` attribute and add corresponding output fields and slot 
  254         aliases to the output schema. 
  256         In addition to the attributes added by `BaseMeasurementTask.__init__`, 
  257         a ``schema``` attribute holding the output schema must be present 
  258         before this method is called. 
  260         Keyword arguments are forwarded directly to plugin constructors, 
  261         allowing derived classes to use plugins with different signatures. 
  266         if self.
config.slots.centroid 
is not None:
 
  269         for executionOrder, name, config, PluginClass 
in sorted(self.
config.plugins.apply()):
 
  272             if hasattr(PluginClass, 
"hasLogName") 
and PluginClass.hasLogName:
 
  281         if self.
config.slots.centroid 
is not None and self.
plugins[self.
config.slots.centroid] 
is None:
 
  284         for executionOrder, name, config, PluginClass 
in sorted(self.
config.undeblended.apply()):
 
  285             undeblendedName = self.
config.undeblendedPrefix + name
 
  290         """Call ``measure`` on all plugins and consistently handle exceptions. 
  294         measRecord : `lsst.afw.table.SourceRecord` 
  295             The record corresponding to the object being measured. Will be 
  296             updated in-place with the results of measurement. 
  298             Positional arguments forwarded to ``plugin.measure`` 
  300             Keyword arguments. Two are handled locally: 
  303                 Beginning execution order (inclusive). Measurements with 
  304                 ``executionOrder`` < ``beginOrder`` are not executed. `None` 
  308                 Ending execution order (exclusive). Measurements with 
  309                 ``executionOrder`` >= ``endOrder`` are not executed. `None` 
  312             Others are forwarded to ``plugin.measure()``. 
  316         This method can be used with plugins that have different signatures; 
  317         the only requirement is that ``measRecord`` be the first argument. 
  318         Subsequent positional arguments and keyword arguments are forwarded 
  319         directly to the plugin. 
  321         This method should be considered "protected": it is intended for use by 
  322         derived classes, not users. 
  324         beginOrder = kwds.pop(
"beginOrder", 
None)
 
  325         endOrder = kwds.pop(
"endOrder", 
None)
 
  327             if beginOrder 
is not None and plugin.getExecutionOrder() < beginOrder:
 
  329             if endOrder 
is not None and plugin.getExecutionOrder() >= endOrder:
 
  334         """Call ``measure`` on the specified plugin. 
  336         Exceptions are handled in a consistent way. 
  340         plugin : subclass of `BasePlugin` 
  341             Plugin that will be executed. 
  342         measRecord : `lsst.afw.table.SourceRecord` 
  343             The record corresponding to the object being measured. Will be 
  344             updated in-place with the results of measurement. 
  346             Positional arguments forwarded to ``plugin.measure()``. 
  348             Keyword arguments forwarded to ``plugin.measure()``. 
  352         This method can be used with plugins that have different signatures; 
  353         the only requirement is that ``plugin`` and ``measRecord`` be the first 
  354         two arguments.  Subsequent positional arguments and keyword arguments 
  355         are forwarded directly to the plugin. 
  357         This method should be considered "protected": it is intended for use by 
  358         derived classes, not users. 
  361             plugin.measure(measRecord, *args, **kwds)
 
  362         except FATAL_EXCEPTIONS:
 
  364         except MeasurementError 
as error:
 
  366                 "MeasurementError in %s.measure on record %s: %s" 
  367                 % (plugin.name, measRecord.getId(), error))
 
  368             plugin.fail(measRecord, error)
 
  369         except Exception 
as error:
 
  371                 "Exception in %s.measure on record %s: %s" 
  372                 % (plugin.name, measRecord.getId(), error))
 
  373             plugin.fail(measRecord)
 
  376         """Call ``measureN`` on all plugins and consistently handle exceptions. 
  380         measCat : `lsst.afw.table.SourceCatalog` 
  381             Catalog containing only the records for the source family to be 
  382             measured, and where outputs should be written. 
  384             Positional arguments forwarded to ``plugin.measure()`` 
  386             Keyword arguments. Two are handled locally: 
  389                 Beginning execution order (inclusive): Measurements with 
  390                 ``executionOrder`` < ``beginOrder`` are not executed. `None` 
  393                 Ending execution order (exclusive): measurements with 
  394                 ``executionOrder`` >= ``endOrder`` are not executed. `None` for 
  397             Others are are forwarded to ``plugin.measure()``. 
  401         This method can be used with plugins that have different signatures; 
  402         the only requirement is that ``measRecord`` be the first argument. 
  403         Subsequent positional arguments and keyword arguments are forwarded 
  404         directly to the plugin. 
  406         This method should be considered "protected": it is intended for use by 
  407         derived classes, not users. 
  409         beginOrder = kwds.pop(
"beginOrder", 
None)
 
  410         endOrder = kwds.pop(
"endOrder", 
None)
 
  411         for plugin 
in self.
plugins.iterN():
 
  412             if beginOrder 
is not None and plugin.getExecutionOrder() < beginOrder:
 
  414             if endOrder 
is not None and plugin.getExecutionOrder() >= endOrder:
 
  419         """Call ``measureN`` on the specified plugin. 
  421         Exceptions are handled in a consistent way. 
  425         plugin : subclass of `BasePlugin` 
  426             Plugin that will be executed. 
  427         measCat : `lsst.afw.table.SourceCatalog` 
  428             Catalog containing only the records for the source family to be 
  429             measured, and where outputs should be written. 
  431             Positional arguments forwarded to ``plugin.measureN()``. 
  433             Keyword arguments forwarded to ``plugin.measureN()``. 
  437         This method can be used with plugins that have different signatures; 
  438         the only requirement is that the ``plugin`` and ``measCat`` be the 
  439         first two arguments. Subsequent positional arguments and keyword 
  440         arguments are forwarded directly to the plugin. 
  442         This method should be considered "protected": it is intended for use by 
  443         derived classes, not users. 
  446             plugin.measureN(measCat, *args, **kwds)
 
  447         except FATAL_EXCEPTIONS:
 
  450         except MeasurementError 
as error:
 
  451             for measRecord 
in measCat:
 
  453                     "MeasurementError in %s.measureN on records %s-%s: %s" 
  454                     % (plugin.name, measCat[0].getId(), measCat[-1].getId(), error))
 
  455                 plugin.fail(measRecord, error)
 
  456         except Exception 
as error:
 
  457             for measRecord 
in measCat:
 
  458                 plugin.fail(measRecord)
 
  460                     "Exception in %s.measureN on records %s-%s: %s" 
  461                     % (plugin.name, measCat[0].getId(), measCat[-1].getId(), error))