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 posInPix = det.makeCameraPoint(center, lsst.afw.cameraGeom.PIXELS)
147 fp = det.transform(posInPix, lsst.afw.cameraGeom.FOCAL_PLANE).getPoint()
150 def fail(self, measRecord, error=None):
155 pixelScale = lsst.pex.config.Field(dtype=float, default=0.5, doc=
"Nominal pixel size (arcsec)")
161 Algorithm which computes the Jacobian about a source and computes its ratio with a nominal pixel area. 162 This allows one to compare relative instead of absolute areas of pixels. 165 ConfigClass = SingleFrameJacobianConfig
171 def __init__(self, config, name, schema, metadata):
172 SingleFramePlugin.__init__(self, config, name, schema, metadata)
173 self.
jacValue = schema.addField(name +
'_value', type=
"D", doc=
"Jacobian correction")
174 self.
jacFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to 1 for any fatal failure")
179 center = measRecord.getCentroid()
182 result = numpy.abs(self.
scale*exposure.getWcs().linearizePixelToSky(
184 lsst.afw.geom.arcseconds).getLinear().computeDeterminant())
185 measRecord.set(self.
jacValue, result)
187 def fail(self, measRecord, error=None):
188 measRecord.set(self.
jacFlag,
True)
192 scale = lsst.pex.config.Field(dtype=float, default=5.0, optional=
True,
193 doc=
"Scale factor to apply to shape for aperture")
194 mask = lsst.pex.config.ListField(doc=
"Mask planes to ignore", dtype=str,
195 default=[
"DETECTED",
"DETECTED_NEGATIVE",
"BAD",
"SAT"])
200 Calculate the median variance within a Footprint scaled from the object shape so 201 the value is not terribly influenced by the object and instead represents the 202 variance in the background near the object. 204 ConfigClass = VarianceConfig
205 FAILURE_BAD_CENTROID = 1
206 FAILURE_EMPTY_FOOTPRINT = 2
210 return BasePlugin.FLUX_ORDER
212 def __init__(self, config, name, schema, metadata):
213 GenericPlugin.__init__(self, config, name, schema, metadata)
214 self.
varValue = schema.addField(name +
'_value', type=
"D", doc=
"Variance at object position")
216 doc=
"Set to True when the footprint has no usable pixels")
220 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
222 def measure(self, measRecord, exposure, center):
225 if not numpy.all(numpy.isfinite(measRecord.getCentroid())):
227 aperture = lsst.afw.geom.Ellipse(measRecord.getShape(), measRecord.getCentroid())
228 aperture.scale(self.
config.scale)
231 foot.clipTo(exposure.getBBox(lsst.afw.image.PARENT))
234 maskedImage = exposure.getMaskedImage()
236 maskBits = maskedImage.getMask().getPlaneBitMask(self.
config.mask)
237 logicalMask = numpy.logical_not(pixels.getMaskArray() & maskBits)
241 if numpy.any(logicalMask):
242 medVar = numpy.median(pixels.getVarianceArray()[logicalMask])
243 measRecord.set(self.
varValue, medVar)
245 raise MeasurementError(
"Footprint empty, or all pixels are masked, can't compute median",
248 def fail(self, measRecord, error=None):
250 if isinstance(error, MeasurementError):
255 measRecord.set(self.
varValue, numpy.nan)
256 GenericPlugin.fail(self, measRecord, error)
259 SingleFrameVariancePlugin = VariancePlugin.makeSingleFramePlugin(
"base_Variance")
260 ForcedVariancePlugin = VariancePlugin.makeForcedPlugin(
"base_Variance")
267 class InputCountPlugin(GenericPlugin):
269 Plugin to count how many input images contributed to each source. This information 270 is in the exposure's coaddInputs. Some limitations: 271 * This is only for the pixel containing the center, not for all the pixels in the 273 * This does not account for any clipping in the coadd 276 ConfigClass = InputCountConfig
277 FAILURE_BAD_CENTROID = 1
278 FAILURE_NO_INPUTS = 2
282 return BasePlugin.SHAPE_ORDER
284 def __init__(self, config, name, schema, metadata):
285 GenericPlugin.__init__(self, config, name, schema, metadata)
286 self.
numberKey = schema.addField(name +
'_value', type=
"I",
287 doc=
"Number of images contributing at center, not including any" 289 self.
noInputsFlag = schema.addField(name +
'_flag_noInputs', type=
"Flag",
290 doc=
"No coadd inputs available")
293 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
295 def measure(self, measRecord, exposure, center):
296 if not exposure.getInfo().getCoaddInputs():
298 if not numpy.all(numpy.isfinite(center)):
301 ccds = exposure.getInfo().getCoaddInputs().ccds
302 measRecord.set(self.
numberKey, len(ccds.subsetContaining(center, exposure.getWcs())))
304 def fail(self, measRecord, error=None):
305 if error
is not None:
310 GenericPlugin.fail(self, measRecord, error)
313 SingleFrameInputCountPlugin = InputCountPlugin.makeSingleFramePlugin(
"base_InputCount")
314 ForcedInputCountPlugin = InputCountPlugin.makeForcedPlugin(
"base_InputCount")
324 A centroid algorithm that simply uses the first (i.e. highest) Peak in the Source's 325 Footprint as the centroid. This is of course a relatively poor measure of the true 326 centroid of the object; this algorithm is provided mostly for testing and debugging. 329 ConfigClass = SingleFramePeakCentroidConfig
335 def __init__(self, config, name, schema, metadata):
336 SingleFramePlugin.__init__(self, config, name, schema, metadata)
337 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
338 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
339 self.
flag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Centroiding failed")
342 peak = measRecord.getFootprint().getPeaks()[0]
343 measRecord.set(self.
keyX, peak.getFx())
344 measRecord.set(self.
keyY, peak.getFy())
346 def fail(self, measRecord, error=None):
347 measRecord.set(self.
flag,
True)
351 return SimpleCentroidTransform
361 A measurement plugin that sets the "coord" field (part of the Source minimal schema) 362 using the slot centroid and the Wcs attached to the Exposure. 365 ConfigClass = SingleFrameSkyCoordConfig
374 if not exposure.hasWcs():
375 raise Exception(
"Wcs not attached to exposure. Required for " + self.
name +
" algorithm")
376 measRecord.updateCoord(exposure.getWcs())
378 def fail(self, measRecord, error=None):
387 class ForcedPeakCentroidConfig(ForcedPluginConfig):
394 The forced peak centroid is like the SFM peak centroid plugin, except that it must transform 395 the peak coordinate from the original (reference) coordinate system to the coordinate system 396 of the exposure being measured. 399 ConfigClass = ForcedPeakCentroidConfig
405 def __init__(self, config, name, schemaMapper, metadata):
406 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
407 schema = schemaMapper.editOutputSchema()
408 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
409 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
411 def measure(self, measRecord, exposure, refRecord, refWcs):
412 targetWcs = exposure.getWcs()
413 peak = refRecord.getFootprint().getPeaks()[0]
415 result = targetWcs.skyToPixel(refWcs.pixelToSky(result))
416 measRecord.set(self.
keyX, result.getX())
417 measRecord.set(self.
keyY, result.getY())
421 return SimpleCentroidTransform
428 @
register(
"base_TransformedCentroid")
430 """A centroid pseudo-algorithm for forced measurement that simply transforms the centroid 431 from the reference catalog to the measurement coordinate system. This is used as 432 the slot centroid by default in forced measurement, allowing subsequent measurements 433 to simply refer to the slot value just as they would in single-frame measurement. 436 ConfigClass = ForcedTransformedCentroidConfig
442 def __init__(self, config, name, schemaMapper, metadata):
443 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
444 schema = schemaMapper.editOutputSchema()
446 xKey = schema.addField(name +
"_x", type=
"D", doc=
"transformed reference centroid column",
448 yKey = schema.addField(name +
"_y", type=
"D", doc=
"transformed reference centroid row",
454 if "slot_Centroid_flag" in schemaMapper.getInputSchema():
455 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
456 doc=
"whether the reference centroid is marked as bad")
460 def measure(self, measRecord, exposure, refRecord, refWcs):
461 targetWcs = exposure.getWcs()
462 if not refWcs == targetWcs:
463 targetPos = targetWcs.skyToPixel(refWcs.pixelToSky(refRecord.getCentroid()))
466 measRecord.set(self.
centroidKey, refRecord.getCentroid())
468 measRecord.set(self.
flagKey, refRecord.getCentroidFlag())
477 """A shape pseudo-algorithm for forced measurement that simply transforms the shape 478 from the reference catalog to the measurement coordinate system. This is used as 479 the slot shape by default in forced measurement, allowing subsequent measurements 480 to simply refer to the slot value just as they would in single-frame measurement. 483 ConfigClass = ForcedTransformedShapeConfig
489 def __init__(self, config, name, schemaMapper, metadata):
490 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
491 schema = schemaMapper.editOutputSchema()
493 xxKey = schema.addField(name +
"_xx", type=
"D", doc=
"transformed reference shape x^2 moment",
495 yyKey = schema.addField(name +
"_yy", type=
"D", doc=
"transformed reference shape y^2 moment",
497 xyKey = schema.addField(name +
"_xy", type=
"D", doc=
"transformed reference shape xy moment",
503 if "slot_Shape_flag" in schemaMapper.getInputSchema():
504 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
505 doc=
"whether the reference shape is marked as bad")
509 def measure(self, measRecord, exposure, refRecord, refWcs):
510 targetWcs = exposure.getWcs()
511 if not refWcs == targetWcs:
512 fullTransform = makeWcsPairTransform(refWcs, targetWcs)
514 measRecord.set(self.
shapeKey, refRecord.getShape().
transform(localTransform.getLinear()))
516 measRecord.set(self.
shapeKey, refRecord.getShape())
518 measRecord.set(self.
flagKey, refRecord.getShapeFlag())
Base config class for all measurement plugins.
def measure(self, measRecord, exposure)
def getExecutionOrder(cls)
def getExecutionOrder(cls)
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, Point2I offset=Point2I())
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)
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)