25from .pluginsBase
import BasePlugin
26from .pluginRegistry
import generateAlgorithmName, register
27from .apCorrRegistry
import addApCorrName
28from .sfm
import SingleFramePlugin, SingleFramePluginConfig
29from .forcedMeasurement
import ForcedPlugin, ForcedPluginConfig
31__all__ = (
"wrapSingleFrameAlgorithm",
"wrapForcedAlgorithm",
"wrapSimpleAlgorithm",
32 "wrapAlgorithm",
"wrapAlgorithmControl",
"wrapTransform",
"GenericPlugin")
37 def __init__(self, config, name, schema, metadata, logName=None):
38 SingleFramePlugin.__init__(self, config, name, schema, metadata, logName=logName)
39 if hasattr(self,
"hasLogName")
and self.hasLogName
and logName
is not None:
40 self.
cpp = self.factory(config, name, schema, metadata, logName=logName)
42 self.
cpp = self.factory(config, name, schema, metadata)
50 def fail(self, measRecord, error=None):
51 self.
cpp.
fail(measRecord, error.cpp
if error
is not None else None)
56 def __init__(self, config, name, schemaMapper, metadata, logName=None):
57 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata, logName=logName)
58 if hasattr(self,
"hasLogName")
and self.hasLogName
and logName
is not None:
59 self.
cpp = self.factory(config, name, schemaMapper, metadata, logName=logName)
61 self.
cpp = self.factory(config, name, schemaMapper, metadata)
63 def measure(self, measRecord, exposure, refRecord, refWcs):
64 self.
cpp.measureForced(measRecord, exposure, refRecord, refWcs)
66 def measureN(self, measCat, exposure, refCat, refWcs):
67 self.
cpp.measureNForced(measCat, exposure, refCat, refWcs)
69 def fail(self, measRecord, error=None):
70 self.
cpp.
fail(measRecord, error.cpp
if error
is not None else None)
74 """Wrap a C++ algorithm's control class into a Python config class.
78 Base : `SingleFramePluginConfig` or `ForcedPluginConfig`
79 Base class for the returned config.
80 Control : pybind11-wrapped version of a C++ class.
81 Control class to be wrapped.
82 module : module, `str`, `int`, or `None`; optional
83 Either a module object, a string specifying the name of the module, or
84 an integer specifying how far back in the stack to look for the module
85 to use: ``0`` is `lsst.pex.config.wrap`, ``1`` is
86 `lsst.meas.base.wrappers`, ``2`` is the immediate caller, etc. This
87 will be used to set ``__module__`` for the new config class, and the
88 class will also be added to the module. The default is none in which
89 case module will be looked up from Control.
90 hasMeasureN : `bool`, optional
91 Whether the plugin supports fitting multiple objects at once (if so, a
92 config option to enable/disable this will be added).
96 ConfigClass : `lsst.pex.config.Config`
97 A new subclass of lsst.pex.config.Config.
101 This function is generally only called by `wrapAlgorithm`; it is unlikely
102 users will have to call it directly.
111 Control.__name__.replace(
"Control",
"Config"),
114 doc=
"whether to run this plugin in multi-object mode")}
116 ConfigClass = lsst.pex.config.makeConfigClass(Control, module=module, cls=cls)
120 ConfigClass = lsst.pex.config.makeConfigClass(Control, module=module, base=Base)
124def wrapAlgorithm(Base, AlgClass, factory, executionOrder, name=None, Control=None,
125 ConfigClass=None, TransformClass=None, doRegister=True, shouldApCorr=False,
126 apCorrList=(), hasLogName=
False, **kwds):
127 """Wrap a C++ algorithm class to create a measurement plugin.
131 Base : `SingleFramePlugin` or `ForcedPlugin`
132 Base class for the returned Plugin.
133 AlgClass : API compatible with `SingleFrameAlgorithm` or `ForcedAlgorithm`
134 C++ algorithm class to convert. May either derive directly from
135 `SingleFrameAlgorithm` or `ForcedAlgorithm`, or be an unrelated class
136 which has the same ``measure`` and ``measureN`` signatures.
138 A callable that is used to construct an instance of ``AlgClass``. It
139 must take four arguments, either ``(config, name, schema, metadata)``
140 or ``(config, name, schemaMapper, metadata)``, depending on whether
141 the algorithm is single-frame or forced.
142 executionOrder : `float`
143 The order this plugin should be run, relative to others
144 (see `BasePlugin.getExecutionOrder`).
145 name : `str`, optional
146 String to use when registering the algorithm. Ignored if
147 ``doRegistry=False``, set to ``generateAlgorithmName(AlgClass)`` if
149 Control : Pybind11-wrapped version of a C++ class, optional
150 Pybind11-wrapped C++ Control class for the algorithm;
151 ``AlgClass.Control`` is used if `None`. Ignored if ``ConfigClass``
153 ConfigClass : subclass of `BaseMeasurementPluginConfig`
154 Python config class that wraps the C++ algorithm's pybind11-wrapped
155 Control class. If `None`, `wrapAlgorithmControl` is called to
156 generate a Config class using the ``Control`` argument.
157 TransformClass : subclass of `MeasurementTransform`, optional
158 Transformation which may be used to post-process the results of
159 measurement. If `None`, the default defined by `BasePlugin` is
161 doRegister : `bool`, optional
162 If `True` (the default), register the plugin with ``Base``'s
163 registry, allowing it to be used by measurement tasks.
164 shouldApCorr : `bool`, optional
165 Does this algorithm measure an instFlux that can be aperture
166 corrected? This is shorthand for ``apCorrList=[name]`` and is ignored
167 if ``apCorrList`` is specified.
168 apCorrList : iterable of `str`, optional
169 Field name prefixes for instFlux fields to be aperture corrected. If
170 an algorithm measures a single instFlux that should be aperture
171 corrected, then it is simpler to set ``shouldApCorr=True``. However,
172 if an algorithm produces multiple such fields, then specify
173 ``apCorrList`` instead. For example, ``modelfit_CModel`` produces
174 three such fields: ``apCorrList= ("modelfit_CModel_exp",
175 "modelfit_CModel_exp", "modelfit_CModel_def")`` If ``apCorrList`` is
176 not empty then ``shouldApCorr`` is ignored. If non-empty and
177 ``doRegister`` is `True` then the names are added to the set
178 retrieved by ``getApCorrNameSet``.
179 hasLogName : `bool`, optional
180 `True` if the C++ algorithm supports ``logName`` as a constructor
183 Additional keyword arguments passed to generateAlgorithmControl, which
186 - ``hasMeasureN``: Whether the plugin supports fitting multiple
187 objects at once ;if so, a config option to enable/disable this will
189 - ``executionOrder``: If not `None`, an override for the default
190 execution order for this plugin (the default is ``2.0``, which is
191 usually appropriate for fluxes; `bool`).
195 PluginClass : subclass of ``Base``
196 The new plugin class.
198 if ConfigClass
is None:
200 Control = AlgClass.Control
203 def getExecutionOrder():
204 return executionOrder
205 typeDict = dict(AlgClass=AlgClass, ConfigClass=ConfigClass, factory=staticmethod(factory),
206 getExecutionOrder=staticmethod(getExecutionOrder))
208 typeDict[
'getTransformClass'] = staticmethod(
lambda: TransformClass)
209 PluginClass = type(AlgClass.__name__ + Base.__name__, (Base,), typeDict)
213 Base.registry.register(name, PluginClass)
216 PluginClass.hasLogName = hasLogName
221 hasLogName=False, deprecated=None, **kwds):
222 """Expose a C++ ``SingleFrameAlgorithm`` class as a measurement plugin.
226 AlgClass : API compatible with `SingleFrameAlgorithm`
227 C++ algorithm class to convert. May either derive directly from
228 `SingleFrameAlgorithm` or be an unrelated class which has the same
229 ``measure``, ``measureN`` and ``fail`` signatures.
230 executionOrder : `float`
231 The order this plugin should be run, relative to others
232 (see `BasePlugin.getExecutionOrder`).
233 name : `str`, optional
234 Name to use when registering the algorithm. Ignored if
235 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
237 needsMetadata : `bool`, optional
238 Sets whether the ``AlgClass``'s constructor should be passed a
239 `~lsst.daf.base.PropertySet` metadata argument.
240 hasMeasureN : `bool`, optional
241 Does the algorithm support simultaneous measurement of multiple
242 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
243 the generated config class, and its value will be passed as the last
244 argument when calling the ``AlgClass`` constructor.
245 hasLogName : `bool`, optional
246 `True` if the C++ algorithm supports ``logName`` as a constructor
248 deprecated : `str`, optional
249 If specified, emit as a deprecation warning when the plugin is
252 Additional keyword arguments are passed to the lower-level
253 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
257 singleFramePlugin : subclass of `SingleFramePlugin`
258 The new measurement plugin class.
262 The first three arguments to the C++ constructor are expected to be
263 ``Control const & ctrl, std::string const & name, Schema & schema``.
265 If ``needsMetadata`` is `True`, we also append ``PropertySet & metadata``.
267 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
269 If ``hasLogName`` is `True`, we also append ``std::string logName``.
271 If more than one of the above is `True`, the metadata ``PropertySet``
272 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
277 def factory(config, name, schema, metadata, **kwargs):
279 warnings.warn(deprecated, category=FutureWarning)
280 return AlgClass(config.makeControl(), name, schema, metadata, config.doMeasureN, **kwargs)
282 def factory(config, name, schema, metadata, **kwargs):
284 warnings.warn(deprecated, category=FutureWarning)
285 return AlgClass(config.makeControl(), name, schema, config.doMeasureN, **kwargs)
288 def factory(config, name, schema, metadata, **kwargs):
290 warnings.warn(deprecated, category=FutureWarning)
291 return AlgClass(config.makeControl(), name, schema, metadata, **kwargs)
293 def factory(config, name, schema, metadata, **kwargs):
295 warnings.warn(deprecated, category=FutureWarning)
296 return AlgClass(config.makeControl(), name, schema, **kwargs)
298 return wrapAlgorithm(WrappedSingleFramePlugin, AlgClass, executionOrder=executionOrder, name=name,
299 factory=factory, hasMeasureN=hasMeasureN, hasLogName=hasLogName, **kwds)
303 hasMeasureN=False, needsSchemaOnly=False, hasLogName=False,
304 deprecated=None, **kwds):
305 """Expose a C++ ``ForcedAlgorithm`` class as a measurement plugin.
309 AlgClass : API compatible with `ForcedAlgorithm`
310 C++ algorithm class to convert. May either derive directly from
311 `ForcedAlgorithm` or be an unrelated class which has the same
312 ``measure``, ``measureN`` and ``fail`` signatures.
313 executionOrder : `float`
314 The order this plugin should be run, relative to others
315 (see `BasePlugin.getExecutionOrder`).
316 name : `str`, optional
317 Name to use when registering the algorithm. Ignored if
318 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
320 needsMetadata : `bool`, optional
321 Sets whether the ``AlgClass``'s constructor should be passed a
322 `~lsst.daf.base.PropertySet` metadata argument.
323 hasMeasureN : `bool`, optional
324 Does the algorithm support simultaneous measurement of multiple
325 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
326 the generated config class, and its value will be passed as the last
327 argument when calling the ``AlgClass`` constructor.
328 hasLogName : `bool`, optional
329 `True` if the C++ algorithm supports ``logName`` as a constructor
331 needsSchemaOnly : `bool`, optional
332 Whether the algorithm constructor expects a Schema argument
333 (representing the output `~lsst.afw.table.Schema`) rather than the
334 full `~lsst.afw.table.SchemaMapper` (which provides access to both the
335 reference schema and the output schema).
336 deprecated : `str`, optional
337 If specified, emit as a deprecation warning when the plugin is
340 Additional keyword arguments are passed to the lower-level
341 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
345 forcedPlugin : subclass of `ForcedPlugin`
346 The new measurement plugin class.
350 The first two arguments to the C++ constructor are expected to be
351 ``Control const & ctrl, std::string const & name``
353 If ``needsSchemaOnly`` is `True`, then the third argument will be
354 ``Schema & schema``; otherwise, it will be ``SchemaMapper &
357 If ``needsMetadata`` is `True`, we also append ``PropertySet &
360 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
362 If ``hasLogName`` is `True`, we also append ``std::string logName``.
364 If more than one of the above is `True`, the metadata ``PropertySet``
365 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
369 def extractSchemaArg(m):
370 return m.editOutputSchema()
372 def extractSchemaArg(m):
376 def factory(config, name, schemaMapper, metadata, **kwargs):
378 warnings.warn(deprecated, category=FutureWarning)
379 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
380 metadata, config.doMeasureN, **kwargs)
382 def factory(config, name, schemaMapper, metadata, **kwargs):
384 warnings.warn(deprecated, category=FutureWarning)
385 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
386 config.doMeasureN, **kwargs)
389 def factory(config, name, schemaMapper, metadata, **kwargs):
391 warnings.warn(deprecated, category=FutureWarning)
392 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
395 def factory(config, name, schemaMapper, metadata, **kwargs):
397 warnings.warn(deprecated, category=FutureWarning)
398 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper), **kwargs)
400 return wrapAlgorithm(WrappedForcedPlugin, AlgClass, executionOrder=executionOrder, name=name,
401 factory=factory, hasLogName=hasLogName, **kwds)
405 hasLogName=False, deprecated=None, **kwds):
406 r"""Expose a C++ ``SimpleAlgorithm`` class as a measurement plugin.
408 ``SimpleAlgorithm``\ s are made available as both `SingleFramePlugin`\ s
409 and `ForcedPlugin`\ s.
413 AlgClass : Subclass of C++ ``SimpleAlgorithm``, or API compatible
414 Algorithm class to convert. The C++ class should be wrapped with
415 Pybind11, and must provide ``measure()``, ``measureN()`` and ``fail()`
416 signatures equivalent to ``SimpleAlgorithm``.
417 executionOrder : `float`
418 The order this plugin should be run, relative to others
419 (see `~BasePlugin.getExecutionOrder`).
420 name : `str`, optional
421 Name to use when registering the algorithm. Ignored if
422 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
424 needsMetadata : `bool`, optional
425 Sets whether the ``AlgClass``'s constructor should be passed a
426 `~lsst.daf.base.PropertySet` metadata argument.
427 hasMeasureN : `bool`, optional
428 Does the algorithm support simultaneous measurement of multiple
429 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
430 the generated config class, and its value will be passed as the last
431 argument when calling the ``AlgClass`` constructor.
432 hasLogName : `bool`, optional
433 `True` if the C++ algorithm supports ``logName`` as a constructor
435 deprecated : `str`, optional
436 If specified, emit as a deprecation warning when the plugin is
439 Additional keyword arguments are passed to the lower-level
440 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
444 singleFramePlugin : subclass of `SingleFramePlugin`
445 The new single frame measurement plugin class.
446 forcedPlugin : subclass of `ForcedPlugin`
447 The new forced measurement plugin class.
451 The first three arguments to the C++ constructor are expected to be
452 ``Control const & ctrl, std::string const & name, Schema & schema``.
454 If ``needsMetadata`` is `True`, we also append ``PropertySet &
457 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
459 If ``hasLogName`` is `True`, we also append ``std::string logName``.
461 If more than one of the above is `True`, the metadata ``PropertySet``
462 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
466 needsMetadata=needsMetadata, hasLogName=hasLogName,
467 deprecated=deprecated, **kwds),
469 needsMetadata=needsMetadata, hasLogName=hasLogName,
470 needsSchemaOnly=
True, **kwds))
474 """Modify a C++ transform to accept either a ``Config`` or a ``Control``.
476 That is, the configuration may either be provided as a (C++) ``Control``
477 object or an instance of a Python class derived from
478 `~lsst.meas.base.BasePluginConfig`.
482 transformClass : Subclass of C++ ``BaseTransform``
483 A C++ transform class, wrapped with pybind11. Its constructor must
484 take a ``Control`` object, a ``std::string``, and a
485 `~lsst.afw.table.SchemaMapper`, in that order.
486 hasLogName : `bool`, optional
489 oldInit = transformClass.__init__
491 def _init(self, ctrl, name, mapper, logName=None):
492 if hasattr(ctrl,
"makeControl"):
493 ctrl = ctrl.makeControl()
496 oldInit(self, ctrl, name, mapper)
498 transformClass.__init__ = _init
502 """Abstract base class for a generic plugin.
506 config : `lsst.pex.config.Config`
507 An instance of this class' ``ConfigClass``.
509 Name of this measurement plguin, for registering.
510 schema : `lsst.afw.table.Schema`
511 The catalog schema. New fields should be added here to
512 hold measurements produced by this plugin.
513 metadata : `lsst.daf.base.PropertySet`
514 Metadata that will be attached to the output catalog.
515 logName : `str`, optional
516 Name of log component.
520 A generic plugin can be used with the `singleFramePluginFromGeneric`
521 and/or `forcedPluginFromGeneric` wrappers to create classes that can be
522 used for single frame measurement and/or forced measurement (as
523 appropriate). The only real difference between `SingleFramePlugin` and
524 `ForcedPlugin` is the ``measure`` method; this class introduces a shared
525 signature for `measure` that, in combination with the aforementioned
526 wrappers, allows both plugin styles to share a single implementation.
528 This doesn't use `abc.ABCMeta` because I couldn't get it to work
531 Sub-classes should set `ConfigClass` and implement the `measure` and
532 `measureN` methods. They may optionally provide alternative
533 implementations for the `__init__`, `fail` and `getExecutionOrder`
536 This default implementation simply adds a field for recording
537 a fatal failure of the measurement plugin.
545 def __init__(self, config, name, schema, metadata, logName=None):
546 BasePlugin.__init__(self, config, name, logName=logName)
547 self.
_failKey = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set for any fatal failure")
549 def measure(self, measRecord, exposure, center):
550 """Measure a single source.
552 It is the responsibility of this method to perform the desired
553 measurement and record the result in the `measRecord`.
557 measRecord : `lsst.afw.table.SourceRecord`
558 Catalog record for the source being measured.
559 exposure : `lsst.afw.image.Exposure`
560 Exposure on which the source is being measured.
561 center : `lsst.geom.Point2D`
562 Pixel coordinates of the object.
567 Raised if the measurement fails for a known/justifiable reason.
569 raise NotImplementedError()
571 def measureN(self, measCat, exposure, refCat, refWcs):
572 """Measure multiple sources.
574 It is the responsibility of this method to perform the desired
575 measurement and record the result in the `measCat`.
579 measCat : `lsst.afw.table.SourceCatalog`
580 Catalog for the sources being measured.
581 exposure : `lsst.afw.image.Exposure`
582 Exposure on which the source is being measured.
583 refCat : `lsst.afw.table.SourceCatalog`
585 refWcs : `lsst.afw.image.Wcs`
586 Astrometric solution for the reference image.
591 Raised if the measurement fails for a known/justifiable reason.
593 raise NotImplementedError()
595 def fail(self, measRecord, error=None):
596 """Record a measurement failure.
598 This default implementation simply records the failure in the source
603 measRecord : `lsst.afw.table.SourceRecord`
604 Catalog record for the source being measured.
606 Error causing failure, or `None`.
612 """Produce a SingleFramePlugin subclass from this GenericPlugin class.
614 The class is also registered.
619 Name of plugin to register.
626 ConfigClass = SingleFrameFromGenericConfig
628 def __init__(self, config, name, schema, metadata, logName=None):
629 SingleFramePlugin.__init__(self, config, name, schema, metadata, logName=logName)
630 self.
_generic = cls(config, name, schema, metadata)
632 def measure(self, measRecord, exposure):
633 center = measRecord.getCentroid()
636 def measureN(self, measCat, exposure, refCat, refWcs):
639 def fail(self, measRecord, error=None):
640 self.
_generic.
fail(measRecord, error
if error
is not None else None)
649 return SingleFrameFromGenericPlugin
653 """Produce a ForcedPlugin subclass from this GenericPlugin class.
655 The class is also registered.
660 Name of plugin to register.
667 ConfigClass = ForcedFromGenericConfig
669 def __init__(self, config, name, schemaMapper, metadata, logName=None):
670 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata, logName=logName)
671 schema = schemaMapper.editOutputSchema()
672 self.
_generic = cls(config, name, schema, metadata)
674 def measure(self, measRecord, exposure, refRecord, refWcs):
680 center = measRecord.getCentroid()
683 def measureN(self, measCat, exposure, refCat, refWcs):
686 def fail(self, measRecord, error=None):
687 self.
_generic.
fail(measRecord, error
if error
is not None else None)
696 return ForcedFromGenericPlugin
makeSingleFramePlugin(cls, name)
measure(self, measRecord, exposure, center)
__init__(self, config, name, schema, metadata, logName=None)
fail(self, measRecord, error=None)
makeForcedPlugin(cls, name)
measureN(self, measCat, exposure, refCat, refWcs)
fail(self, measRecord, error=None)
measureN(self, measCat, exposure, refCat, refWcs)
__init__(self, config, name, schemaMapper, metadata, logName=None)
measure(self, measRecord, exposure, refRecord, refWcs)
measureN(self, measCat, exposure)
fail(self, measRecord, error=None)
measure(self, measRecord, exposure)
__init__(self, config, name, schema, metadata, logName=None)
generateAlgorithmName(AlgClass)
wrapSingleFrameAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, deprecated=None, **kwds)
wrapTransform(transformClass, hasLogName=False)
wrapAlgorithm(Base, AlgClass, factory, executionOrder, name=None, Control=None, ConfigClass=None, TransformClass=None, doRegister=True, shouldApCorr=False, apCorrList=(), hasLogName=False, **kwds)
wrapSimpleAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, deprecated=None, **kwds)
wrapForcedAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, needsSchemaOnly=False, hasLogName=False, deprecated=None, **kwds)
wrapAlgorithmControl(Base, Control, module=None, hasMeasureN=False)