24 Definitions and registration of pure-Python plugins with trivial implementations, 25 and automatic plugin-from-algorithm calls for those implemented in C++. 27 from __future__
import absolute_import, division, print_function
36 from .pluginRegistry
import register
37 from .pluginsBase
import BasePlugin
38 from .baseMeasurement
import BaseMeasurementPluginConfig
39 from .sfm
import SingleFramePluginConfig, SingleFramePlugin
40 from .forcedMeasurement
import ForcedPluginConfig, ForcedPlugin
41 from .wrappers
import wrapSimpleAlgorithm, wrapTransform, GenericPlugin
42 from .transforms
import SimpleCentroidTransform
44 from .apertureFlux
import ApertureFluxControl, ApertureFluxTransform
45 from .transform
import BaseTransform
46 from .blendedness
import BlendednessAlgorithm, BlendednessControl
47 from .circularApertureFlux
import CircularApertureFluxAlgorithm
48 from .gaussianFlux
import GaussianFluxAlgorithm, GaussianFluxControl, GaussianFluxTransform
49 from .exceptions
import MeasurementError
50 from .localBackground
import LocalBackgroundControl, LocalBackgroundAlgorithm, LocalBackgroundTransform
51 from .naiveCentroid
import NaiveCentroidAlgorithm, NaiveCentroidControl, NaiveCentroidTransform
52 from .peakLikelihoodFlux
import PeakLikelihoodFluxAlgorithm, PeakLikelihoodFluxControl, \
53 PeakLikelihoodFluxTransform
54 from .pixelFlags
import PixelFlagsAlgorithm, PixelFlagsControl
55 from .psfFlux
import PsfFluxAlgorithm, PsfFluxControl, PsfFluxTransform
56 from .scaledApertureFlux
import ScaledApertureFluxAlgorithm, ScaledApertureFluxControl, \
57 ScaledApertureFluxTransform
58 from .sdssCentroid
import SdssCentroidAlgorithm, SdssCentroidControl, SdssCentroidTransform
59 from .sdssShape
import SdssShapeAlgorithm, SdssShapeControl, SdssShapeTransform
62 "SingleFrameFPPositionConfig",
"SingleFrameFPPositionPlugin",
63 "SingleFrameJacobianConfig",
"SingleFrameJacobianPlugin",
64 "VarianceConfig",
"SingleFrameVariancePlugin",
"ForcedVariancePlugin",
65 "InputCountConfig",
"SingleFrameInputCountPlugin",
"ForcedInputCountPlugin",
66 "SingleFramePeakCentroidConfig",
"SingleFramePeakCentroidPlugin",
67 "SingleFrameSkyCoordConfig",
"SingleFrameSkyCoordPlugin",
68 "ForcedPeakCentroidConfig",
"ForcedPeakCentroidPlugin",
69 "ForcedTransformedCentroidConfig",
"ForcedTransformedCentroidPlugin",
70 "ForcedTransformedShapeConfig",
"ForcedTransformedShapePlugin",
76 TransformClass=PsfFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
77 shouldApCorr=
True, hasLogName=
True)
79 TransformClass=PeakLikelihoodFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
81 TransformClass=GaussianFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
84 TransformClass=NaiveCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
86 TransformClass=SdssCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
88 executionOrder=BasePlugin.FLUX_ORDER)
90 TransformClass=SdssShapeTransform, executionOrder=BasePlugin.SHAPE_ORDER)
92 TransformClass=ScaledApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
95 TransformClass=ApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
97 TransformClass=BaseTransform, executionOrder=BasePlugin.SHAPE_ORDER)
100 TransformClass=LocalBackgroundTransform, executionOrder=BasePlugin.FLUX_ORDER)
122 Algorithm to calculate the position of a centroid on the focal plane 125 ConfigClass = SingleFrameFPPositionConfig
131 def __init__(self, config, name, schema, metadata):
132 SingleFramePlugin.__init__(self, config, name, schema, metadata)
133 self.
focalValue = lsst.afw.table.Point2DKey.addFields(schema, name,
"Position on the focal plane",
135 self.
focalFlag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Set to True for any fatal failure")
136 self.
detectorFlag = schema.addField(name +
"_missingDetector_flag", type=
"Flag",
137 doc=
"Set to True if detector object is missing")
140 det = exposure.getDetector()
145 center = measRecord.getCentroid()
146 fp = det.transform(center, lsst.afw.cameraGeom.PIXELS, lsst.afw.cameraGeom.FOCAL_PLANE)
149 def fail(self, measRecord, error=None):
154 pixelScale = lsst.pex.config.Field(dtype=float, default=0.5, doc=
"Nominal pixel size (arcsec)")
160 Algorithm which computes the Jacobian about a source and computes its ratio with a nominal pixel area. 161 This allows one to compare relative instead of absolute areas of pixels. 164 ConfigClass = SingleFrameJacobianConfig
170 def __init__(self, config, name, schema, metadata):
171 SingleFramePlugin.__init__(self, config, name, schema, metadata)
172 self.
jacValue = schema.addField(name +
'_value', type=
"D", doc=
"Jacobian correction")
173 self.
jacFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to 1 for any fatal failure")
178 center = measRecord.getCentroid()
181 result = numpy.abs(self.
scale*exposure.getWcs().linearizePixelToSky(
183 lsst.afw.geom.arcseconds).getLinear().computeDeterminant())
184 measRecord.set(self.
jacValue, result)
186 def fail(self, measRecord, error=None):
187 measRecord.set(self.
jacFlag,
True)
191 scale = lsst.pex.config.Field(dtype=float, default=5.0, optional=
True,
192 doc=
"Scale factor to apply to shape for aperture")
193 mask = lsst.pex.config.ListField(doc=
"Mask planes to ignore", dtype=str,
194 default=[
"DETECTED",
"DETECTED_NEGATIVE",
"BAD",
"SAT"])
199 Calculate the median variance within a Footprint scaled from the object shape so 200 the value is not terribly influenced by the object and instead represents the 201 variance in the background near the object. 203 ConfigClass = VarianceConfig
204 FAILURE_BAD_CENTROID = 1
205 FAILURE_EMPTY_FOOTPRINT = 2
209 return BasePlugin.FLUX_ORDER
211 def __init__(self, config, name, schema, metadata):
212 GenericPlugin.__init__(self, config, name, schema, metadata)
213 self.
varValue = schema.addField(name +
'_value', type=
"D", doc=
"Variance at object position")
215 doc=
"Set to True when the footprint has no usable pixels")
219 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
221 def measure(self, measRecord, exposure, center):
224 if not numpy.all(numpy.isfinite(measRecord.getCentroid())):
226 aperture = lsst.afw.geom.Ellipse(measRecord.getShape(), measRecord.getCentroid())
227 aperture.scale(self.
config.scale)
230 foot.clipTo(exposure.getBBox(lsst.afw.image.PARENT))
233 maskedImage = exposure.getMaskedImage()
235 maskBits = maskedImage.getMask().getPlaneBitMask(self.
config.mask)
236 logicalMask = numpy.logical_not(pixels.getMaskArray() & maskBits)
240 if numpy.any(logicalMask):
241 medVar = numpy.median(pixels.getVarianceArray()[logicalMask])
242 measRecord.set(self.
varValue, medVar)
244 raise MeasurementError(
"Footprint empty, or all pixels are masked, can't compute median",
247 def fail(self, measRecord, error=None):
249 if isinstance(error, MeasurementError):
254 measRecord.set(self.
varValue, numpy.nan)
255 GenericPlugin.fail(self, measRecord, error)
258 SingleFrameVariancePlugin = VariancePlugin.makeSingleFramePlugin(
"base_Variance")
259 ForcedVariancePlugin = VariancePlugin.makeForcedPlugin(
"base_Variance")
266 class InputCountPlugin(GenericPlugin):
268 Plugin to count how many input images contributed to each source. This information 269 is in the exposure's coaddInputs. Some limitations: 270 * This is only for the pixel containing the center, not for all the pixels in the 272 * This does not account for any clipping in the coadd 275 ConfigClass = InputCountConfig
276 FAILURE_BAD_CENTROID = 1
277 FAILURE_NO_INPUTS = 2
281 return BasePlugin.SHAPE_ORDER
283 def __init__(self, config, name, schema, metadata):
284 GenericPlugin.__init__(self, config, name, schema, metadata)
285 self.
numberKey = schema.addField(name +
'_value', type=
"I",
286 doc=
"Number of images contributing at center, not including any" 288 self.
noInputsFlag = schema.addField(name +
'_flag_noInputs', type=
"Flag",
289 doc=
"No coadd inputs available")
292 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
294 def measure(self, measRecord, exposure, center):
295 if not exposure.getInfo().getCoaddInputs():
297 if not numpy.all(numpy.isfinite(center)):
300 ccds = exposure.getInfo().getCoaddInputs().ccds
301 measRecord.set(self.
numberKey, len(ccds.subsetContaining(center, exposure.getWcs())))
303 def fail(self, measRecord, error=None):
304 if error
is not None:
309 GenericPlugin.fail(self, measRecord, error)
312 SingleFrameInputCountPlugin = InputCountPlugin.makeSingleFramePlugin(
"base_InputCount")
313 ForcedInputCountPlugin = InputCountPlugin.makeForcedPlugin(
"base_InputCount")
323 A centroid algorithm that simply uses the first (i.e. highest) Peak in the Source's 324 Footprint as the centroid. This is of course a relatively poor measure of the true 325 centroid of the object; this algorithm is provided mostly for testing and debugging. 328 ConfigClass = SingleFramePeakCentroidConfig
334 def __init__(self, config, name, schema, metadata):
335 SingleFramePlugin.__init__(self, config, name, schema, metadata)
336 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
337 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
338 self.
flag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Centroiding failed")
341 peak = measRecord.getFootprint().getPeaks()[0]
342 measRecord.set(self.
keyX, peak.getFx())
343 measRecord.set(self.
keyY, peak.getFy())
345 def fail(self, measRecord, error=None):
346 measRecord.set(self.
flag,
True)
350 return SimpleCentroidTransform
360 A measurement plugin that sets the "coord" field (part of the Source minimal schema) 361 using the slot centroid and the Wcs attached to the Exposure. 364 ConfigClass = SingleFrameSkyCoordConfig
373 if not exposure.hasWcs():
374 raise Exception(
"Wcs not attached to exposure. Required for " + self.
name +
" algorithm")
375 measRecord.updateCoord(exposure.getWcs())
377 def fail(self, measRecord, error=None):
386 class ForcedPeakCentroidConfig(ForcedPluginConfig):
393 The forced peak centroid is like the SFM peak centroid plugin, except that it must transform 394 the peak coordinate from the original (reference) coordinate system to the coordinate system 395 of the exposure being measured. 398 ConfigClass = ForcedPeakCentroidConfig
404 def __init__(self, config, name, schemaMapper, metadata):
405 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
406 schema = schemaMapper.editOutputSchema()
407 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
408 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
410 def measure(self, measRecord, exposure, refRecord, refWcs):
411 targetWcs = exposure.getWcs()
412 peak = refRecord.getFootprint().getPeaks()[0]
414 result = targetWcs.skyToPixel(refWcs.pixelToSky(result))
415 measRecord.set(self.
keyX, result.getX())
416 measRecord.set(self.
keyY, result.getY())
420 return SimpleCentroidTransform
427 @
register(
"base_TransformedCentroid")
429 """A centroid pseudo-algorithm for forced measurement that simply transforms the centroid 430 from the reference catalog to the measurement coordinate system. This is used as 431 the slot centroid by default in forced measurement, allowing subsequent measurements 432 to simply refer to the slot value just as they would in single-frame measurement. 435 ConfigClass = ForcedTransformedCentroidConfig
441 def __init__(self, config, name, schemaMapper, metadata):
442 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
443 schema = schemaMapper.editOutputSchema()
445 xKey = schema.addField(name +
"_x", type=
"D", doc=
"transformed reference centroid column",
447 yKey = schema.addField(name +
"_y", type=
"D", doc=
"transformed reference centroid row",
453 if "slot_Centroid_flag" in schemaMapper.getInputSchema():
454 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
455 doc=
"whether the reference centroid is marked as bad")
459 def measure(self, measRecord, exposure, refRecord, refWcs):
460 targetWcs = exposure.getWcs()
461 if not refWcs == targetWcs:
462 targetPos = targetWcs.skyToPixel(refWcs.pixelToSky(refRecord.getCentroid()))
465 measRecord.set(self.
centroidKey, refRecord.getCentroid())
467 measRecord.set(self.
flagKey, refRecord.getCentroidFlag())
476 """A shape pseudo-algorithm for forced measurement that simply transforms the shape 477 from the reference catalog to the measurement coordinate system. This is used as 478 the slot shape by default in forced measurement, allowing subsequent measurements 479 to simply refer to the slot value just as they would in single-frame measurement. 482 ConfigClass = ForcedTransformedShapeConfig
488 def __init__(self, config, name, schemaMapper, metadata):
489 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
490 schema = schemaMapper.editOutputSchema()
492 xxKey = schema.addField(name +
"_xx", type=
"D", doc=
"transformed reference shape x^2 moment",
494 yyKey = schema.addField(name +
"_yy", type=
"D", doc=
"transformed reference shape y^2 moment",
496 xyKey = schema.addField(name +
"_xy", type=
"D", doc=
"transformed reference shape xy moment",
502 if "slot_Shape_flag" in schemaMapper.getInputSchema():
503 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
504 doc=
"whether the reference shape is marked as bad")
508 def measure(self, measRecord, exposure, refRecord, refWcs):
509 targetWcs = exposure.getWcs()
510 if not refWcs == targetWcs:
511 fullTransform = makeWcsPairTransform(refWcs, targetWcs)
513 measRecord.set(self.
shapeKey, refRecord.getShape().
transform(localTransform.getLinear()))
515 measRecord.set(self.
shapeKey, refRecord.getShape())
517 measRecord.set(self.
flagKey, refRecord.getShapeFlag())
Base config class for all measurement plugins.
def measure(self, measRecord, exposure)
def getExecutionOrder(cls)
def getExecutionOrder(cls)
def fail(self, measRecord, error=None)
def __init__(self, config, name, schema, metadata)
def fail(self, measRecord, error=None)
def fail(self, measRecord, error=None)
def __init__(self, config, name, schema, metadata)
def measure(self, measRecord, exposure)
Base class for configs of single-frame plugin algorithms.
AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, Point2D const &inPoint)
def getExecutionOrder(cls)
int FAILURE_EMPTY_FOOTPRINT
def fail(self, measRecord, error=None)
def __init__(self, config, name, schemaMapper, metadata)
Base class for single-frame plugin algorithms.
def getExecutionOrder(cls)
def fail(self, measRecord, error=None)
def getExecutionOrder(cls)
def register(name, shouldApCorr=False, apCorrList=())
A Python decorator that registers a class, using the given name, in its base class's PluginRegistry...
def getExecutionOrder(cls)
def measure(self, measRecord, exposure)
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, Point2I offset=Point2I())
def wrapTransform(transformClass, hasLogName=False)
def measure(self, measRecord, exposure, refRecord, refWcs)
def __init__(self, config, name, schema, metadata)
def measure(self, measRecord, exposure)
def measure(self, measRecord, exposure, center)
def wrapSimpleAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, kwds)
Wrap a C++ SimpleAlgorithm class into both a Python SingleFramePlugin and ForcedPlugin classes...
def __init__(self, config, name, schema, metadata)
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=NULL)