LSST Applications g0265f82a02+c6dfa2ddaf,g1162b98a3f+b2075782a9,g2079a07aa2+1b2e822518,g2bbee38e9b+c6dfa2ddaf,g337abbeb29+c6dfa2ddaf,g3ddfee87b4+a60788ef87,g50ff169b8f+2eb0e556e8,g52b1c1532d+90ebb246c7,g555ede804d+a60788ef87,g591dd9f2cf+ba8caea58f,g5ec818987f+864ee9cddb,g858d7b2824+9ee1ab4172,g876c692160+a40945ebb7,g8a8a8dda67+90ebb246c7,g8cdfe0ae6a+4fd9e222a8,g99cad8db69+5e309b7bc6,g9ddcbc5298+a1346535a5,ga1e77700b3+df8f93165b,ga8c6da7877+aa12a14d27,gae46bcf261+c6dfa2ddaf,gb0e22166c9+8634eb87fb,gb3f2274832+d0da15e3be,gba4ed39666+1ac82b564f,gbb8dafda3b+5dfd9c994b,gbeb006f7da+97157f9740,gc28159a63d+c6dfa2ddaf,gc86a011abf+9ee1ab4172,gcf0d15dbbd+a60788ef87,gdaeeff99f8+1cafcb7cd4,gdc0c513512+9ee1ab4172,ge79ae78c31+c6dfa2ddaf,geb67518f79+ba1859f325,geb961e4c1e+f9439d1e6f,gee10cc3b42+90ebb246c7,gf1cff7945b+9ee1ab4172,w.2024.12
LSST Data Management Base Package
Loading...
Searching...
No Matches
wrappers.py
Go to the documentation of this file.
1# This file is part of meas_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22import lsst.pex.config
23from .pluginsBase import BasePlugin
24from .pluginRegistry import generateAlgorithmName, register
25from .apCorrRegistry import addApCorrName
26from .sfm import SingleFramePlugin, SingleFramePluginConfig
27from .forcedMeasurement import ForcedPlugin, ForcedPluginConfig
28
29__all__ = ("wrapSingleFrameAlgorithm", "wrapForcedAlgorithm", "wrapSimpleAlgorithm",
30 "wrapAlgorithm", "wrapAlgorithmControl", "wrapTransform", "GenericPlugin")
31
32
34
35 def __init__(self, config, name, schema, metadata, logName=None):
36 SingleFramePlugin.__init__(self, config, name, schema, metadata, logName=logName)
37 if hasattr(self, "hasLogName") and self.hasLogName and logName is not None:
38 self.cpp = self.factory(config, name, schema, metadata, logName=logName)
39 else:
40 self.cpp = self.factory(config, name, schema, metadata)
41
42 def measure(self, measRecord, exposure):
43 self.cpp.measure(measRecord, exposure)
44
45 def measureN(self, measCat, exposure):
46 self.cpp.measureN(measCat, exposure)
47
48 def fail(self, measRecord, error=None):
49 self.cpp.fail(measRecord, error.cpp if error is not None else None)
50
51
53
54 def __init__(self, config, name, schemaMapper, metadata, logName=None):
55 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata, logName=logName)
56 if hasattr(self, "hasLogName") and self.hasLogName and logName is not None:
57 self.cpp = self.factory(config, name, schemaMapper, metadata, logName=logName)
58 else:
59 self.cpp = self.factory(config, name, schemaMapper, metadata)
60
61 def measure(self, measRecord, exposure, refRecord, refWcs):
62 self.cpp.measureForced(measRecord, exposure, refRecord, refWcs)
63
64 def measureN(self, measCat, exposure, refCat, refWcs):
65 self.cpp.measureNForced(measCat, exposure, refCat, refWcs)
66
67 def fail(self, measRecord, error=None):
68 self.cpp.fail(measRecord, error.cpp if error is not None else None)
69
70
71def wrapAlgorithmControl(Base, Control, module=None, hasMeasureN=False):
72 """Wrap a C++ algorithm's control class into a Python config class.
73
74 Parameters
75 ----------
76 Base : `SingleFramePluginConfig` or `ForcedPluginConfig`
77 Base class for the returned config.
78 Control : pybind11-wrapped version of a C++ class.
79 Control class to be wrapped.
80 module : module, `str`, `int`, or `None`; optional
81 Either a module object, a string specifying the name of the module, or
82 an integer specifying how far back in the stack to look for the module
83 to use: ``0`` is `lsst.pex.config.wrap`, ``1`` is
84 `lsst.meas.base.wrappers`, ``2`` is the immediate caller, etc. This
85 will be used to set ``__module__`` for the new config class, and the
86 class will also be added to the module. The default is none in which
87 case module will be looked up from Control.
88 hasMeasureN : `bool`, optional
89 Whether the plugin supports fitting multiple objects at once (if so, a
90 config option to enable/disable this will be added).
91
92 Returns
93 -------
94 ConfigClass : `lsst.pex.config.Config`
95 A new subclass of lsst.pex.config.Config.
96
97 Notes
98 -----
99 This function is generally only called by `wrapAlgorithm`; it is unlikely
100 users will have to call it directly.
101 """
102 if hasMeasureN:
103 # We need to add a Config field to enable multi-object measurement, to
104 # replace the simple bool class attribute that's on the base class.
105 # To do that, we create the Config class dynamically here, then call
106 # makeControlClass to finish it off by adding fields from the control
107 # object.
108 cls = type(
109 Control.__name__.replace("Control", "Config"),
110 (Base,),
111 {"doMeasureN": lsst.pex.config.Field(dtype=bool, default=True,
112 doc="whether to run this plugin in multi-object mode")}
113 )
114 ConfigClass = lsst.pex.config.makeConfigClass(Control, module=module, cls=cls)
115 else:
116 # If we don't have to add that Config field, we can delegate all of
117 # the work to pex_config's makeControlClass
118 ConfigClass = lsst.pex.config.makeConfigClass(Control, module=module, base=Base)
119 return ConfigClass
120
121
122def wrapAlgorithm(Base, AlgClass, factory, executionOrder, name=None, Control=None,
123 ConfigClass=None, TransformClass=None, doRegister=True, shouldApCorr=False,
124 apCorrList=(), hasLogName=False, **kwds):
125 """Wrap a C++ algorithm class to create a measurement plugin.
126
127 Parameters
128 ----------
129 Base : `SingleFramePlugin` or `ForcedPlugin`
130 Base class for the returned Plugin.
131 AlgClass : API compatible with `SingleFrameAlgorithm` or `ForcedAlgorithm`
132 C++ algorithm class to convert. May either derive directly from
133 `SingleFrameAlgorithm` or `ForcedAlgorithm`, or be an unrelated class
134 which has the same ``measure`` and ``measureN`` signatures.
135 factory : callable
136 A callable that is used to construct an instance of ``AlgClass``. It
137 must take four arguments, either ``(config, name, schema, metadata)``
138 or ``(config, name, schemaMapper, metadata)``, depending on whether
139 the algorithm is single-frame or forced.
140 executionOrder : `float`
141 The order this plugin should be run, relative to others
142 (see `BasePlugin.getExecutionOrder`).
143 name : `str`, optional
144 String to use when registering the algorithm. Ignored if
145 ``doRegistry=False``, set to ``generateAlgorithmName(AlgClass)`` if
146 `None`.
147 Control : Pybind11-wrapped version of a C++ class, optional
148 Pybind11-wrapped C++ Control class for the algorithm;
149 ``AlgClass.Control`` is used if `None`. Ignored if ``ConfigClass``
150 is not `None`.
151 ConfigClass : subclass of `BaseMeasurementPluginConfig`
152 Python config class that wraps the C++ algorithm's pybind11-wrapped
153 Control class. If `None`, `wrapAlgorithmControl` is called to
154 generate a Config class using the ``Control`` argument.
155 TransformClass : subclass of `MeasurementTransform`, optional
156 Transformation which may be used to post-process the results of
157 measurement. If `None`, the default defined by `BasePlugin` is
158 used.
159 doRegister : `bool`, optional
160 If `True` (the default), register the plugin with ``Base``'s
161 registry, allowing it to be used by measurement tasks.
162 shouldApCorr : `bool`, optional
163 Does this algorithm measure an instFlux that can be aperture
164 corrected? This is shorthand for ``apCorrList=[name]`` and is ignored
165 if ``apCorrList`` is specified.
166 apCorrList : iterable of `str`, optional
167 Field name prefixes for instFlux fields to be aperture corrected. If
168 an algorithm measures a single instFlux that should be aperture
169 corrected, then it is simpler to set ``shouldApCorr=True``. However,
170 if an algorithm produces multiple such fields, then specify
171 ``apCorrList`` instead. For example, ``modelfit_CModel`` produces
172 three such fields: ``apCorrList= ("modelfit_CModel_exp",
173 "modelfit_CModel_exp", "modelfit_CModel_def")`` If ``apCorrList`` is
174 not empty then ``shouldApCorr`` is ignored. If non-empty and
175 ``doRegister`` is `True` then the names are added to the set
176 retrieved by ``getApCorrNameSet``.
177 hasLogName : `bool`, optional
178 `True` if the C++ algorithm supports ``logName`` as a constructor
179 argument.
180 **kwds
181 Additional keyword arguments passed to generateAlgorithmControl, which
182 may include:
183
184 - ``hasMeasureN``: Whether the plugin supports fitting multiple
185 objects at once ;if so, a config option to enable/disable this will
186 be added (`bool`).
187 - ``executionOrder``: If not `None`, an override for the default
188 execution order for this plugin (the default is ``2.0``, which is
189 usually appropriate for fluxes; `bool`).
190
191 Returns
192 -------
193 PluginClass : subclass of ``Base``
194 The new plugin class.
195 """
196 if ConfigClass is None:
197 if Control is None:
198 Control = AlgClass.Control
199 ConfigClass = wrapAlgorithmControl(Base.ConfigClass, Control, **kwds)
200
201 def getExecutionOrder():
202 return executionOrder
203 typeDict = dict(AlgClass=AlgClass, ConfigClass=ConfigClass, factory=staticmethod(factory),
204 getExecutionOrder=staticmethod(getExecutionOrder))
205 if TransformClass:
206 typeDict['getTransformClass'] = staticmethod(lambda: TransformClass)
207 PluginClass = type(AlgClass.__name__ + Base.__name__, (Base,), typeDict)
208 if doRegister:
209 if name is None:
210 name = generateAlgorithmName(AlgClass)
211 Base.registry.register(name, PluginClass)
212 if shouldApCorr:
213 addApCorrName(name)
214 PluginClass.hasLogName = hasLogName
215 return PluginClass
216
217
218def wrapSingleFrameAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False,
219 hasLogName=False, **kwds):
220 """Expose a C++ ``SingleFrameAlgorithm`` class as a measurement plugin.
221
222 Parameters
223 ----------
224 AlgClass : API compatible with `SingleFrameAlgorithm`
225 C++ algorithm class to convert. May either derive directly from
226 `SingleFrameAlgorithm` or be an unrelated class which has the same
227 ``measure``, ``measureN`` and ``fail`` signatures.
228 executionOrder : `float`
229 The order this plugin should be run, relative to others
230 (see `BasePlugin.getExecutionOrder`).
231 name : `str`, optional
232 Name to use when registering the algorithm. Ignored if
233 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
234 `None`.
235 needsMetadata : `bool`, optional
236 Sets whether the ``AlgClass``'s constructor should be passed a
237 `~lsst.daf.base.PropertySet` metadata argument.
238 hasMeasureN : `bool`, optional
239 Does the algorithm support simultaneous measurement of multiple
240 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
241 the generated config class, and its value will be passed as the last
242 argument when calling the ``AlgClass`` constructor.
243 hasLogName : `bool`, optional
244 `True` if the C++ algorithm supports ``logName`` as a constructor
245 argument.
246 **kwds
247 Additional keyword arguments are passed to the lower-level
248 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
249
250 Returns
251 -------
252 singleFramePlugin : subclass of `SingleFramePlugin`
253 The new measurement plugin class.
254
255 Notes
256 -----
257 The first three arguments to the C++ constructor are expected to be
258 ``Control const & ctrl, std::string const & name, Schema & schema``.
259
260 If ``needsMetadata`` is `True`, we also append ``PropertySet & metadata``.
261
262 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
263
264 If ``hasLogName`` is `True`, we also append ``std::string logName``.
265
266 If more than one of the above is `True`, the metadata ``PropertySet``
267 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
268 three.
269 """
270 if hasMeasureN:
271 if needsMetadata:
272 def factory(config, name, schema, metadata, **kwargs):
273 return AlgClass(config.makeControl(), name, schema, metadata, config.doMeasureN, **kwargs)
274 else:
275 def factory(config, name, schema, metadata, **kwargs):
276 return AlgClass(config.makeControl(), name, schema, config.doMeasureN, **kwargs)
277 else:
278 if needsMetadata:
279 def factory(config, name, schema, metadata, **kwargs):
280 return AlgClass(config.makeControl(), name, schema, metadata, **kwargs)
281 else:
282 def factory(config, name, schema, metadata, **kwargs):
283 return AlgClass(config.makeControl(), name, schema, **kwargs)
284
285 return wrapAlgorithm(WrappedSingleFramePlugin, AlgClass, executionOrder=executionOrder, name=name,
286 factory=factory, hasMeasureN=hasMeasureN, hasLogName=hasLogName, **kwds)
287
288
289def wrapForcedAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False,
290 hasMeasureN=False, needsSchemaOnly=False, hasLogName=False, **kwds):
291 """Expose a C++ ``ForcedAlgorithm`` class as a measurement plugin.
292
293 Parameters
294 ----------
295 AlgClass : API compatible with `ForcedAlgorithm`
296 C++ algorithm class to convert. May either derive directly from
297 `ForcedAlgorithm` or be an unrelated class which has the same
298 ``measure``, ``measureN`` and ``fail`` signatures.
299 executionOrder : `float`
300 The order this plugin should be run, relative to others
301 (see `BasePlugin.getExecutionOrder`).
302 name : `str`, optional
303 Name to use when registering the algorithm. Ignored if
304 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
305 `None`.
306 needsMetadata : `bool`, optional
307 Sets whether the ``AlgClass``'s constructor should be passed a
308 `~lsst.daf.base.PropertySet` metadata argument.
309 hasMeasureN : `bool`, optional
310 Does the algorithm support simultaneous measurement of multiple
311 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
312 the generated config class, and its value will be passed as the last
313 argument when calling the ``AlgClass`` constructor.
314 hasLogName : `bool`, optional
315 `True` if the C++ algorithm supports ``logName`` as a constructor
316 argument.
317 needsSchemaOnly : `bool`, optional
318 Whether the algorithm constructor expects a Schema argument
319 (representing the output `~lsst.afw.table.Schema`) rather than the
320 full `~lsst.afw.table.SchemaMapper` (which provides access to both the
321 reference schema and the output schema).
322 **kwds
323 Additional keyword arguments are passed to the lower-level
324 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
325
326 Returns
327 -------
328 forcedPlugin : subclass of `ForcedPlugin`
329 The new measurement plugin class.
330
331 Notes
332 -----
333 The first two arguments to the C++ constructor are expected to be
334 ``Control const & ctrl, std::string const & name``
335
336 If ``needsSchemaOnly`` is `True`, then the third argument will be
337 ``Schema & schema``; otherwise, it will be ``SchemaMapper &
338 schemaMapper``.
339
340 If ``needsMetadata`` is `True`, we also append ``PropertySet &
341 metadata``.
342
343 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
344
345 If ``hasLogName`` is `True`, we also append ``std::string logName``.
346
347 If more than one of the above is `True`, the metadata ``PropertySet``
348 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
349 three.
350 """
351 if needsSchemaOnly:
352 def extractSchemaArg(m):
353 return m.editOutputSchema()
354 else:
355 def extractSchemaArg(m):
356 return m
357 if hasMeasureN:
358 if needsMetadata:
359 def factory(config, name, schemaMapper, metadata, **kwargs):
360 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
361 metadata, config.doMeasureN, **kwargs)
362 else:
363 def factory(config, name, schemaMapper, metadata, **kwargs):
364 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
365 config.doMeasureN, **kwargs)
366 else:
367 if needsMetadata:
368 def factory(config, name, schemaMapper, metadata, **kwargs):
369 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper),
370 metadata, **kwargs)
371 else:
372 def factory(config, name, schemaMapper, metadata, **kwargs):
373 return AlgClass(config.makeControl(), name, extractSchemaArg(schemaMapper), **kwargs)
374
375 return wrapAlgorithm(WrappedForcedPlugin, AlgClass, executionOrder=executionOrder, name=name,
376 factory=factory, hasLogName=hasLogName, **kwds)
377
378
379def wrapSimpleAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False,
380 hasLogName=False, **kwds):
381 r"""Expose a C++ ``SimpleAlgorithm`` class as a measurement plugin.
382
383 ``SimpleAlgorithm``\ s are made available as both `SingleFramePlugin`\ s
384 and `ForcedPlugin`\ s.
385
386 Parameters
387 ----------
388 AlgClass : Subclass of C++ ``SimpleAlgorithm``, or API compatible
389 Algorithm class to convert. The C++ class should be wrapped with
390 Pybind11, and must provide ``measure()``, ``measureN()`` and ``fail()`
391 signatures equivalent to ``SimpleAlgorithm``.
392 executionOrder : `float`
393 The order this plugin should be run, relative to others
394 (see `~BasePlugin.getExecutionOrder`).
395 name : `str`, optional
396 Name to use when registering the algorithm. Ignored if
397 ``doRegistry=False``; set to ``generateAlgorithmName(AlgClass)`` if
398 `None`.
399 needsMetadata : `bool`, optional
400 Sets whether the ``AlgClass``'s constructor should be passed a
401 `~lsst.daf.base.PropertySet` metadata argument.
402 hasMeasureN : `bool`, optional
403 Does the algorithm support simultaneous measurement of multiple
404 sources? If `True`, a `bool` ``doMeasureN`` field will be added to
405 the generated config class, and its value will be passed as the last
406 argument when calling the ``AlgClass`` constructor.
407 hasLogName : `bool`, optional
408 `True` if the C++ algorithm supports ``logName`` as a constructor
409 argument.
410 **kwds
411 Additional keyword arguments are passed to the lower-level
412 `wrapAlgorithm` and `wrapAlgorithmControl` classes.
413
414 Returns
415 -------
416 singleFramePlugin : subclass of `SingleFramePlugin`
417 The new single frame measurement plugin class.
418 forcedPlugin : subclass of `ForcedPlugin`
419 The new forced measurement plugin class.
420
421 Notes
422 -----
423 The first three arguments to the C++ constructor are expected to be
424 ``Control const & ctrl, std::string const & name, Schema & schema``.
425
426 If ``needsMetadata`` is `True`, we also append ``PropertySet &
427 metadata``.
428
429 If ``hasMeasureN`` is `True`, we also append ``bool doMeasureN``.
430
431 If ``hasLogName`` is `True`, we also append ``std::string logName``.
432
433 If more than one of the above is `True`, the metadata ``PropertySet``
434 precedes the ``doMeasureN`` ``bool`` and the ``logName`` comes last of the
435 three.
436 """
437 return (wrapSingleFrameAlgorithm(AlgClass, executionOrder=executionOrder, name=name,
438 needsMetadata=needsMetadata, hasLogName=hasLogName, **kwds),
439 wrapForcedAlgorithm(AlgClass, executionOrder=executionOrder, name=name,
440 needsMetadata=needsMetadata, hasLogName=hasLogName,
441 needsSchemaOnly=True, **kwds))
442
443
444def wrapTransform(transformClass, hasLogName=False):
445 """Modify a C++ transform to accept either a ``Config`` or a ``Control``.
446
447 That is, the configuration may either be provided as a (C++) ``Control``
448 object or an instance of a Python class derived from
449 `~lsst.meas.base.BasePluginConfig`.
450
451 Parameters
452 ----------
453 transformClass : Subclass of C++ ``BaseTransform``
454 A C++ transform class, wrapped with pybind11. Its constructor must
455 take a ``Control`` object, a ``std::string``, and a
456 `~lsst.afw.table.SchemaMapper`, in that order.
457 hasLogName : `bool`, optional
458 Unused.
459 """
460 oldInit = transformClass.__init__
461
462 def _init(self, ctrl, name, mapper, logName=None):
463 if hasattr(ctrl, "makeControl"):
464 ctrl = ctrl.makeControl()
465 # logName signature needs to be on this Class __init__, but is not
466 # needed by the C++ plugin.
467 oldInit(self, ctrl, name, mapper)
468
469 transformClass.__init__ = _init
470
471
473 """Abstract base class for a generic plugin.
474
475 Parameters
476 ----------
477 config : `lsst.pex.config.Config`
478 An instance of this class' ``ConfigClass``.
479 name : `str`
480 Name of this measurement plguin, for registering.
481 schema : `lsst.afw.table.Schema`
482 The catalog schema. New fields should be added here to
483 hold measurements produced by this plugin.
484 metadata : `lsst.daf.base.PropertySet`
485 Metadata that will be attached to the output catalog.
486 logName : `str`, optional
487 Name of log component.
488
489 Notes
490 -----
491 A generic plugin can be used with the `singleFramePluginFromGeneric`
492 and/or `forcedPluginFromGeneric` wrappers to create classes that can be
493 used for single frame measurement and/or forced measurement (as
494 appropriate). The only real difference between `SingleFramePlugin` and
495 `ForcedPlugin` is the ``measure`` method; this class introduces a shared
496 signature for `measure` that, in combination with the aforementioned
497 wrappers, allows both plugin styles to share a single implementation.
498
499 This doesn't use `abc.ABCMeta` because I couldn't get it to work
500 with a superclass.
501
502 Sub-classes should set `ConfigClass` and implement the `measure` and
503 `measureN` methods. They may optionally provide alternative
504 implementations for the `__init__`, `fail` and `getExecutionOrder`
505 methods.
506
507 This default implementation simply adds a field for recording
508 a fatal failure of the measurement plugin.
509 """
510 ConfigClass = None
511
512 @classmethod
514 return 0
515
516 def __init__(self, config, name, schema, metadata, logName=None):
517 BasePlugin.__init__(self, config, name, logName=logName)
518 self._failKey = schema.addField(name + '_flag', type="Flag", doc="Set for any fatal failure")
519
520 def measure(self, measRecord, exposure, center):
521 """Measure a single source.
522
523 It is the responsibility of this method to perform the desired
524 measurement and record the result in the `measRecord`.
525
526 Parameters
527 ----------
528 measRecord : `lsst.afw.table.SourceRecord`
529 Catalog record for the source being measured.
530 exposure : `lsst.afw.image.Exposure`
531 Exposure on which the source is being measured.
532 center : `lsst.geom.Point2D`
533 Pixel coordinates of the object.
534
535 Raises
536 ------
537 MeasurementError
538 Raised if the measurement fails for a known/justifiable reason.
539 """
540 raise NotImplementedError()
541
542 def measureN(self, measCat, exposure, refCat, refWcs):
543 """Measure multiple sources.
544
545 It is the responsibility of this method to perform the desired
546 measurement and record the result in the `measCat`.
547
548 Parameters
549 ----------
550 measCat : `lsst.afw.table.SourceCatalog`
551 Catalog for the sources being measured.
552 exposure : `lsst.afw.image.Exposure`
553 Exposure on which the source is being measured.
554 refCat : `lsst.afw.table.SourceCatalog`
555 Reference catalog.
556 refWcs : `lsst.afw.image.Wcs`
557 Astrometric solution for the reference image.
558
559 Raises
560 ------
561 MeasurementError
562 Raised if the measurement fails for a known/justifiable reason.
563 """
564 raise NotImplementedError()
565
566 def fail(self, measRecord, error=None):
567 """Record a measurement failure.
568
569 This default implementation simply records the failure in the source
570 record.
571
572 Parameters
573 ----------
574 measRecord : `lsst.afw.table.SourceRecord`
575 Catalog record for the source being measured.
576 error : `Exception`
577 Error causing failure, or `None`.
578 """
579 measRecord.set(self._failKey, True)
580
581 @classmethod
582 def makeSingleFramePlugin(cls, name):
583 """Produce a SingleFramePlugin subclass from this GenericPlugin class.
584
585 The class is also registered.
586
587 Parameters
588 ----------
589 name : `str`
590 Name of plugin to register.
591 """
592 class SingleFrameFromGenericConfig(cls.ConfigClass, SingleFramePluginConfig):
593 pass
594
595 @register(name)
596 class SingleFrameFromGenericPlugin(SingleFramePlugin):
597 ConfigClass = SingleFrameFromGenericConfig
598
599 def __init__(self, config, name, schema, metadata, logName=None):
600 SingleFramePlugin.__init__(self, config, name, schema, metadata, logName=logName)
601 self._generic = cls(config, name, schema, metadata)
602
603 def measure(self, measRecord, exposure):
604 center = measRecord.getCentroid()
605 return self._generic.measure(measRecord, exposure, center)
606
607 def measureN(self, measCat, exposure, refCat, refWcs):
608 return self._generic.measureN(measCat, exposure, refCat, refWcs)
609
610 def fail(self, measRecord, error=None):
611 self._generic.fail(measRecord, error if error is not None else None)
612
613 @staticmethod
614 def getExecutionOrder():
616
617 def getTransformClass(self):
618 return self._generic.getTransformClass()
619
620 return SingleFrameFromGenericPlugin
621
622 @classmethod
623 def makeForcedPlugin(cls, name):
624 """Produce a ForcedPlugin subclass from this GenericPlugin class.
625
626 The class is also registered.
627
628 Parameters
629 ----------
630 name : `str`
631 Name of plugin to register.
632 """
633 class ForcedFromGenericConfig(cls.ConfigClass, ForcedPluginConfig):
634 pass
635
636 @register(name)
637 class ForcedFromGenericPlugin(ForcedPlugin):
638 ConfigClass = ForcedFromGenericConfig
639
640 def __init__(self, config, name, schemaMapper, metadata, logName=None):
641 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata, logName=logName)
642 schema = schemaMapper.editOutputSchema()
643 self._generic = cls(config, name, schema, metadata)
644
645 def measure(self, measRecord, exposure, refRecord, refWcs):
646 # Forced photometry tasks should almost be configured with a
647 # centroider (populating measRecord.getCentroid()) that
648 # transforms the reference centroid, but we respect their
649 # decision if they decided to re-centroid (or do something more
650 # unusual) on the image being measured.
651 center = measRecord.getCentroid()
652 return self._generic.measure(measRecord, exposure, center)
653
654 def measureN(self, measCat, exposure, refCat, refWcs):
655 return self._generic.measureN(measCat, exposure, refCat, refWcs)
656
657 def fail(self, measRecord, error=None):
658 self._generic.fail(measRecord, error if error is not None else None)
659
660 @staticmethod
661 def getExecutionOrder():
663
664 def getTransformClass(self):
665 return self._generic.getTransformClass()
666
667 return ForcedFromGenericPlugin
measure(self, measRecord, exposure, center)
Definition wrappers.py:520
__init__(self, config, name, schema, metadata, logName=None)
Definition wrappers.py:516
fail(self, measRecord, error=None)
Definition wrappers.py:566
measureN(self, measCat, exposure, refCat, refWcs)
Definition wrappers.py:542
fail(self, measRecord, error=None)
Definition wrappers.py:67
measureN(self, measCat, exposure, refCat, refWcs)
Definition wrappers.py:64
__init__(self, config, name, schemaMapper, metadata, logName=None)
Definition wrappers.py:54
measure(self, measRecord, exposure, refRecord, refWcs)
Definition wrappers.py:61
__init__(self, config, name, schema, metadata, logName=None)
Definition wrappers.py:35
wrapSingleFrameAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, **kwds)
Definition wrappers.py:219
wrapSimpleAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, **kwds)
Definition wrappers.py:380
wrapTransform(transformClass, hasLogName=False)
Definition wrappers.py:444
wrapAlgorithm(Base, AlgClass, factory, executionOrder, name=None, Control=None, ConfigClass=None, TransformClass=None, doRegister=True, shouldApCorr=False, apCorrList=(), hasLogName=False, **kwds)
Definition wrappers.py:124
wrapForcedAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, needsSchemaOnly=False, hasLogName=False, **kwds)
Definition wrappers.py:290
wrapAlgorithmControl(Base, Control, module=None, hasMeasureN=False)
Definition wrappers.py:71