23 """Base measurement task, which subclassed by the single frame and forced measurement tasks.
26 import lsst.pex.config
28 from .pluginRegistry
import PluginMap
29 from .exceptions
import FatalAlgorithmError, MeasurementError
30 from .pluginsBase
import BasePluginConfig, BasePlugin
31 from .noiseReplacer
import NoiseReplacerConfig
33 __all__ = (
"BaseMeasurementPluginConfig",
"BaseMeasurementPlugin",
34 "BaseMeasurementConfig",
"BaseMeasurementTask")
37 FATAL_EXCEPTIONS = (MemoryError, FatalAlgorithmError)
42 Base config class for all measurement plugins
44 Most derived classes will want to override setDefaults() in order to customize
45 the default exceutionOrder.
47 A derived class whose corresponding Plugin class implements measureN() should
48 additionally add a bool doMeasureN field to replace the bool class attribute
52 doMeasure = lsst.pex.config.Field(dtype=bool, default=
True,
53 doc=
"whether to run this plugin in single-object mode")
60 Base class for all measurement plugins
62 This is class is a placeholder for future behavior which will be shared only between
63 measurement plugins and is implemented for symmetry with the measurement base plugin
69 class SourceSlotConfig(lsst.pex.config.Config):
71 Slot configuration which assigns a particular named plugin to each of a set of
72 slots. Each slot allows a type of measurement to be fetched from the SourceTable
73 without knowing which algorithm was used to produced the data.
75 NOTE: the default algorithm for each slot must be registered, even if the default is not used.
78 centroid = lsst.pex.config.Field(dtype=str, default=
"base_SdssCentroid", optional=
True,
79 doc=
"the name of the centroiding algorithm used to set source x,y")
80 shape = lsst.pex.config.Field(dtype=str, default=
"base_SdssShape", optional=
True,
81 doc=
"the name of the algorithm used to set source moments parameters")
82 apFlux = lsst.pex.config.Field(dtype=str, default=
"base_CircularApertureFlux_12_0", optional=
True,
83 doc=
"the name of the algorithm used to set the source aperture flux slot")
84 modelFlux = lsst.pex.config.Field(dtype=str, default=
"base_GaussianFlux", optional=
True,
85 doc=
"the name of the algorithm used to set the source model flux slot")
86 psfFlux = lsst.pex.config.Field(dtype=str, default=
"base_PsfFlux", optional=
True,
87 doc=
"the name of the algorithm used to set the source psf flux slot")
88 instFlux = lsst.pex.config.Field(dtype=str, default=
"base_GaussianFlux", optional=
True,
89 doc=
"the name of the algorithm used to set the source inst flux slot")
90 calibFlux = lsst.pex.config.Field(dtype=str, default=
"base_CircularApertureFlux_12_0", optional=
True,
91 doc=
"the name of the flux measurement algorithm used for calibration")
94 """Convenience method to setup a Schema's slots according to the config definition.
96 This is defined in the Config class to support use in unit tests without needing
97 to construct a Task object.
99 aliases = schema.getAliasMap()
101 aliases.set(
"slot_Centroid", self.
centroid)
102 if self.
shape is not None:
103 aliases.set(
"slot_Shape", self.
shape)
104 if self.
apFlux is not None:
105 aliases.set(
"slot_ApFlux", self.
apFlux)
107 aliases.set(
"slot_ModelFlux", self.
modelFlux)
109 aliases.set(
"slot_PsfFlux", self.
psfFlux)
111 aliases.set(
"slot_InstFlux", self.
instFlux)
113 aliases.set(
"slot_CalibFlux", self.
calibFlux)
118 Base config class for all measurement driver tasks.
120 Subclasses should define the 'plugins' and 'undeblended' registries, e.g.:
122 plugins = PluginBaseClass.registry.makeField(
125 doc="Plugins to be run and their configuration"
127 undeblended = PluginBaseClass.registry.makeField(
130 doc="Plugins to run on undeblended image"
133 where PluginBaseClass is the appropriate base class of the plugin
134 (e.g., SingleFramePlugin or ForcedPlugin).
137 slots = lsst.pex.config.ConfigField(
138 dtype=SourceSlotConfig,
139 doc=
"Mapping from algorithms to special aliases in Source."
142 doReplaceWithNoise = lsst.pex.config.Field(
143 dtype=bool, default=
True, optional=
False,
144 doc=
'When measuring, replace other detected footprints with noise?')
146 noiseReplacer = lsst.pex.config.ConfigField(
147 dtype=NoiseReplacerConfig,
148 doc=
"configuration that sets how to replace neighboring sources with noise"
150 undeblendedPrefix = lsst.pex.config.Field(
151 dtype=str, default=
"undeblended_",
152 doc=
"Prefix to give undeblended plugins"
156 lsst.pex.config.Config.validate(self)
157 if self.slots.centroid
is not None and self.slots.centroid
not in self.plugins.names:
158 raise ValueError(
"source centroid slot algorithm is not being run.")
159 if self.slots.shape
is not None and self.slots.shape
not in self.plugins.names:
160 raise ValueError(
"source shape slot algorithm '%s' is not being run." % self.slots.shape)
161 for slot
in (self.slots.psfFlux, self.slots.apFlux, self.slots.modelFlux,
162 self.slots.instFlux, self.slots.calibFlux):
164 for name
in self.plugins.names:
165 if len(name) <= len(slot)
and name == slot[:len(name)]:
168 raise ValueError(
"source flux slot algorithm '%s' is not being run." % slot)
179 Ultimate base class for all measurement tasks.
181 This base class for SingleFrameMeasurementTask and ForcedMeasurementTask mostly exists to share
182 code between the two, and generally should not be used directly.
185 ConfigClass = BaseMeasurementConfig
186 _DefaultName =
"measurement"
190 Constructor; only called by derived classes.
192 @param[in] algMetadata An lsst.daf.base.PropertyList that will be filled with metadata
193 about the plugins being run. If None, an empty PropertyList will
195 @param[in] **kwds Additional arguments passed to lsst.pipe.base.Task.__init__.
197 This attaches two public attributes to the class for use by derived classes and parent tasks:
198 - plugins: an empty PluginMap, which will eventually contain all active plugins that will by
199 invoked by the run() method (to be filled by subclasses). This should be considered read-only.
200 - algMetadata: a lsst.daf.base.PropertyList that will contain additional information about the
201 active plugins to be saved with the output catalog (to be filled by subclasses).
203 super(BaseMeasurementTask, self).
__init__(**kwds)
206 if algMetadata
is None:
207 algMetadata = lsst.daf.base.PropertyList()
211 return self.log.getName() +
'.' + pluginName
214 """Initialize the plugins (and slots) according to the configuration.
216 Derived class constructors should call this method to fill the self.plugins
217 attribute and add correspond output fields and slot aliases to the output schema.
219 In addition to the attributes added by BaseMeasurementTask.__init__, a self.schema
220 attribute holding the output schema must also be present before this method is called, .
222 Keyword arguments are forwarded directly to plugin constructors, allowing derived
223 classes to use plugins with different signatures.
228 if self.config.slots.centroid
is not None:
229 self.
plugins[self.config.slots.centroid] =
None
231 for executionOrder, name, config, PluginClass
in sorted(self.config.plugins.apply()):
234 if hasattr(PluginClass,
"hasLogName")
and PluginClass.hasLogName:
243 if self.config.slots.centroid
is not None and self.
plugins[self.config.slots.centroid]
is None:
244 del self.
plugins[self.config.slots.centroid]
246 for executionOrder, name, config, PluginClass
in sorted(self.config.undeblended.apply()):
247 undeblendedName = self.config.undeblendedPrefix + name
253 Call the measure() method on all plugins, handling exceptions in a consistent way.
255 @param[in,out] measRecord lsst.afw.table.SourceRecord that corresponds to the object being
256 measured, and where outputs should be written.
257 @param[in] *args Positional arguments forwarded to Plugin.measure()
258 @param[in] **kwds Keyword arguments. Two are handled locally:
259 - beginOrder: beginning execution order (inclusive): measurements with
260 executionOrder < beginOrder are not executed. None for no limit.
261 - endOrder: ending execution order (exclusive): measurements with
262 executionOrder >= endOrder are not executed. None for no limit.
263 the rest are forwarded to Plugin.measure()
265 This method can be used with plugins that have different signatures; the only requirement is that
266 'measRecord' be the first argument. Subsequent positional arguments and keyword arguments are
267 forwarded directly to the plugin.
269 This method should be considered "protected"; it is intended for use by derived classes, not users.
271 beginOrder = kwds.pop(
"beginOrder",
None)
272 endOrder = kwds.pop(
"endOrder",
None)
273 for plugin
in self.plugins.iter():
274 if beginOrder
is not None and plugin.getExecutionOrder() < beginOrder:
276 if endOrder
is not None and plugin.getExecutionOrder() >= endOrder:
282 Call the measure() method on the nominated plugin, handling exceptions in a consistent way.
284 @param[in] plugin Plugin that will measure
285 @param[in,out] measRecord lsst.afw.table.SourceRecord that corresponds to the object being
286 measured, and where outputs should be written.
287 @param[in] *args Positional arguments forwarded to plugin.measure()
288 @param[in] **kwds Keyword arguments forwarded to plugin.measure()
290 This method can be used with plugins that have different signatures; the only requirement is that
291 the 'plugin' and 'measRecord' be the first two arguments. Subsequent positional arguments and
292 keyword arguments are forwarded directly to the plugin.
294 This method should be considered "protected"; it is intended for use by derived classes, not users.
297 plugin.measure(measRecord, *args, **kwds)
298 except FATAL_EXCEPTIONS:
300 except MeasurementError
as error:
302 "MeasurementError in %s.measure on record %s: %s"
303 % (plugin.name, measRecord.getId(), error))
304 plugin.fail(measRecord, error)
305 except Exception
as error:
307 "Exception in %s.measure on record %s: %s"
308 % (plugin.name, measRecord.getId(), error))
309 plugin.fail(measRecord)
313 Call the measureN() method on all plugins, handling exceptions in a consistent way.
315 @param[in,out] measCat lsst.afw.table.SourceCatalog containing records for just
316 the source family to be measured, and where outputs should
318 @param[in] beginOrder beginning execution order (inclusive): measurements with
319 executionOrder < beginOrder are not executed. None for no limit.
320 @param[in] endOrder ending execution order (exclusive): measurements with
321 executionOrder >= endOrder are not executed. None for no limit.
322 @param[in] *args Positional arguments forwarded to Plugin.measure()
323 @param[in] **kwds Keyword arguments. Two are handled locally:
324 - beginOrder: beginning execution order (inclusive): measurements with
325 executionOrder < beginOrder are not executed. None for no limit.
326 - endOrder: ending execution order (exclusive): measurements with
327 executionOrder >= endOrder are not executed. None for no limit.
328 the rest are forwarded to Plugin.measure()
330 This method can be used with plugins that have different signatures; the only requirement is that
331 'measRecord' be the first argument. Subsequent positional arguments and keyword arguments are
332 forwarded directly to the plugin.
334 This method should be considered "protected"; it is intended for use by derived classes, not users.
336 beginOrder = kwds.pop(
"beginOrder",
None)
337 endOrder = kwds.pop(
"endOrder",
None)
338 for plugin
in self.plugins.iterN():
339 if beginOrder
is not None and plugin.getExecutionOrder() < beginOrder:
341 if endOrder
is not None and plugin.getExecutionOrder() >= endOrder:
347 Call the measureN() method on the nominated plugin, handling exceptions in a consistent way.
349 @param[in] plugin Plugin that will measure
350 @param[in,out] measCat lsst.afw.table.SourceCatalog containing records for just
351 the source family to be measured, and where outputs should
353 @param[in] *args Positional arguments forwarded to plugin.measureN()
354 @param[in] **kwds Keyword arguments forwarded to plugin.measureN()
356 This method can be used with plugins that have different signatures; the only requirement is that
357 the 'plugin' and 'measCat' be the first two arguments. Subsequent positional arguments and
358 keyword arguments are forwarded directly to the plugin.
360 This method should be considered "protected"; it is intended for use by derived classes, not users.
363 plugin.measureN(measCat, *args, **kwds)
364 except FATAL_EXCEPTIONS:
367 except MeasurementError
as error:
368 for measRecord
in measCat:
370 "MeasurementError in %s.measureN on records %s-%s: %s"
371 % (plugin.name, measCat[0].getId(), measCat[-1].getId(), error))
372 plugin.fail(measRecord, error)
373 except Exception
as error:
374 for measRecord
in measCat:
375 plugin.fail(measRecord)
377 "Exception in %s.measureN on records %s-%s: %s"
378 % (plugin.name, measCat[0].getId(), measCat[-1].getId(), error))
Base config class for all measurement plugins.
def __init__
Constructor; only called by derived classes.
def callMeasure
Call the measure() method on all plugins, handling exceptions in a consistent way.
def doMeasurement
Call the measure() method on the nominated plugin, handling exceptions in a consistent way...
def doMeasurementN
Call the measureN() method on the nominated plugin, handling exceptions in a consistent way...
Ultimate base class for all measurement tasks.
Base config class for all measurement driver tasks.
def callMeasureN
Call the measureN() method on all plugins, handling exceptions in a consistent way.