22 from collections 
import namedtuple
 
   25 import lsst.pex.config
 
   28 from .pluginsBase 
import BasePlugin, BasePluginConfig
 
   29 from .pluginRegistry 
import PluginRegistry, PluginMap
 
   30 from . 
import FatalAlgorithmError, MeasurementError
 
   34 FATAL_EXCEPTIONS = (MemoryError, FatalAlgorithmError)
 
   36 __all__ = (
"CatalogCalculationPluginConfig", 
"CatalogCalculationPlugin", 
"CatalogCalculationConfig",
 
   37            "CatalogCalculationTask")
 
   41     """Default configuration class for catalog calcuation plugins. 
   47     """Base class for catalog calculation plugins. 
   51     config : `CatalogCalculationPlugin.ConfigClass` 
   54         The string the plugin was registered with. 
   55     schema : `lsst.afw.table.Schema` 
   56         The source schema, New fields should be added here to 
   57         hold output produced by this plugin. 
   58     metadata : `lsst.daf.base.PropertySet` 
   59         Plugin metadata that will be attached to the output catalog 
   62     ConfigClass = CatalogCalculationPluginConfig  
 
   65     """List of available plugins (`lsst.meas.base.PluginRegistry`). 
   69     """Does the plugin operate on a single source or the whole catalog (`str`)? 
   71     If the plugin operates on a single source at a time, this should be set to 
   72     ``"single"``; if it expects the whoe catalog, to ``"multi"``.  If the 
   73     plugin is of type ``"multi"``, the `fail` method must be implemented to 
   74     accept the whole catalog. If the plugin is of type ``"single"``, `fail` 
   75     should accept a single source record. 
   78     def __init__(self, config, name, schema, metadata):
 
   79         BasePlugin.__init__(self, config, name)
 
   83         r"""Used to set the relative order of plugin execution. 
   85         The values returned by `getExecutionOrder` are compared across all 
   86         plugins, and smaller numbers run first. 
   90         `CatalogCalculationPlugin`\s must run with 
   91         `BasePlugin.DEFAULT_CATALOGCALCULATION` or higher. 
   93         All plugins must implement this method with an appropriate run level 
   95         raise NotImplementedError()
 
   98         """Perform the calculation specified by this plugin. 
  100         This method can either be used to operate on a single catalog record 
  101         or a whole catalog, populating it with the output defined by this 
  104         Note that results may be added to catalog records as new columns, or 
  105         may result in changes to existing values. 
  109         cat : `lsst.afw.table.SourceCatalog` or `lsst.afw.table.SourceRecord` 
  110             May either be a `~lsst.afw.table.SourceCatalog` or a single 
  111             `~lsst.afw.table.SourceRecord`, depending on the plugin type. Will 
  112             be updated in place to contain the results of plugin execution. 
  114             Any additional keyword arguments that may be passed to the plugin. 
  116         raise NotImplementedError()
 
  120     """Handle errors that are thrown by catalog calculation plugins. 
  122     This is a context manager. 
  126     plugin : `CatalogCalculationPlugin` 
  127         The plugin that is to be run. 
  128     cat : `lsst.afw.table.SourceCatalog` or `lsst.afw.table.SourceRecord` 
  129         May either be a `~lsst.afw.table.SourceCatalog` or a single 
  130         `~lsst.afw.table.SourceRecord`, depending on the plugin type. 
  132         A logger. Generally, this should be the logger of the object in which 
  133         the context manager is being used. 
  143     def __exit__(self, exc_type, exc_value, traceback):
 
  146         if exc_type 
in FATAL_EXCEPTIONS:
 
  148         elif exc_type 
is MeasurementError:
 
  149             self.plugin.fail(self.cat, exc_value)
 
  151             self.log.
warn(
"Error in {}.calculate: {}".
format(self.plugin.name, exc_value))
 
  156     """Config class for the catalog calculation driver task. 
  158     Specifies which plugins will execute when the `CatalogCalculationTask` 
  159     associated with this configuration is run. 
  162     plugins = CatalogCalculationPlugin.registry.makeField(
 
  164         default=[
"base_ClassificationExtendedness",
 
  165                  "base_FootprintArea"],
 
  166         doc=
"Plugins to be run and their configuration")
 
  170     """Run plugins which operate on a catalog of sources. 
  172     This task facilitates running plugins which will operate on a source 
  173     catalog. These plugins may do things such as classifying an object based 
  174     on source record entries inserted during a measurement task. 
  178     plugMetaData : `lsst.daf.base.PropertyList` or `None` 
  179         Will be modified in-place to contain metadata about the plugins being 
  180         run. If `None`, an empty `~lsst.daf.base.PropertyList` will be 
  183         Additional arguments passed to the superclass constructor. 
  187     Plugins may either take an entire catalog to work on at a time, or work on 
  190     ConfigClass = CatalogCalculationConfig
 
  191     _DefaultName = 
"catalogCalculation" 
  193     def __init__(self, schema, plugMetadata=None, **kwargs):
 
  194         lsst.pipe.base.Task.__init__(self, **kwargs)
 
  196         if plugMetadata 
is None:
 
  204         """Initialize the plugins according to the configuration. 
  207         pluginType = namedtuple(
'pluginType', 
'single multi')
 
  213         for executionOrder, name, config, PluginClass 
in sorted(self.
config.plugins.apply()):
 
  215                 self.
executionDict[executionOrder] = pluginType(single=[], multi=[])
 
  216             if PluginClass.getExecutionOrder() >= BasePlugin.DEFAULT_CATALOGCALCULATION:
 
  219                 if plug.plugType == 
'single':
 
  221                 elif plug.plugType == 
'multi':
 
  224                 errorTuple = (PluginClass, PluginClass.getExecutionOrder(),
 
  225                               BasePlugin.DEFAULT_CATALOGCALCULATION)
 
  226                 raise ValueError(
"{} has an execution order less than the minimum for an catalogCalculation " 
  227                                  "plugin. Value {} : Minimum {}".
format(*errorTuple))
 
  229     @lsst.pipe.base.timeMethod
 
  231         """The entry point for the catalog calculation task. 
  235         meascat : `lsst.afw.table.SourceCatalog` 
  236             Catalog for measurement. 
  241         """Run each of the plugins on the catalog. 
  245         catalog : `lsst.afw.table.SourceCatalog` 
  246             The catalog on which the plugins will operate. 
  252                     plug.calculate(catalog)
 
  254             for measRecord 
in catalog:
 
  257                         plug.calculate(measRecord)