24 Definitions and registration of pure-Python plugins with trivial implementations,
25 and automatic plugin-from-algorithm calls for those implemented in C++.
33 from .pluginRegistry
import register
34 from .
import baseLib
as bl
35 from .pluginsBase
import BasePlugin
36 from .sfm
import SingleFramePluginConfig, SingleFramePlugin
37 from .forcedMeasurement
import ForcedPluginConfig, ForcedPlugin
38 from .wrappers
import wrapSimpleAlgorithm
39 from .transforms
import SimpleCentroidTransform
42 "SingleFrameFPPositionConfig",
"SingleFrameFPPositionPlugin",
43 "SingleFrameJacobianConfig",
"SingleFrameJacobianPlugin",
44 "SingleFrameVarianceConfig",
"SingleFrameVariancePlugin",
45 "SingleFrameInputCountConfig",
"SingleFrameInputCountPlugin",
46 "SingleFramePeakCentroidConfig",
"SingleFramePeakCentroidPlugin",
47 "SingleFrameSkyCoordConfig",
"SingleFrameSkyCoordPlugin",
48 "ForcedPeakCentroidConfig",
"ForcedPeakCentroidPlugin",
49 "ForcedTransformedCentroidConfig",
"ForcedTransformedCentroidPlugin",
50 "ForcedTransformedShapeConfig",
"ForcedTransformedShapePlugin",
56 TransformClass=bl.PsfFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
59 TransformClass=bl.PeakLikelihoodFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
61 TransformClass=bl.GaussianFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
64 TransformClass=bl.GaussianCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
66 TransformClass=bl.NaiveCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
68 TransformClass=bl.SdssCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
70 executionOrder=BasePlugin.FLUX_ORDER)
72 TransformClass=bl.SdssShapeTransform, executionOrder=BasePlugin.SHAPE_ORDER)
74 TransformClass=bl.ScaledApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
76 wrapSimpleAlgorithm(bl.CircularApertureFluxAlgorithm, needsMetadata=
True, Control=bl.ApertureFluxControl,
77 TransformClass=bl.ApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
79 TransformClass=bl.BaseTransform, executionOrder=BasePlugin.SHAPE_ORDER)
91 Algorithm to calculate the position of a centroid on the focal plane
94 ConfigClass = SingleFrameFPPositionConfig
98 return cls.SHAPE_ORDER
100 def __init__(self, config, name, schema, metadata):
101 SingleFramePlugin.__init__(self, config, name, schema, metadata)
102 self.
focalValue = lsst.afw.table.Point2DKey.addFields(schema, name,
"Position on the focal plane",
104 self.
focalFlag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Set to True for any fatal failure")
105 self.
detectorFlag = schema.addField(name +
"_missingDetector_flag", type=
"Flag",
106 doc=
"Set to True if detector object is missing")
109 det = exposure.getDetector()
114 center = measRecord.getCentroid()
115 posInPix = det.makeCameraPoint(center, lsst.afw.cameraGeom.PIXELS)
116 fp = det.transform(posInPix, lsst.afw.cameraGeom.FOCAL_PLANE).getPoint()
119 def fail(self, measRecord, error=None):
124 pixelScale = lsst.pex.config.Field(dtype=float, default=0.5, doc=
"Nominal pixel size (arcsec)")
130 Algorithm which computes the Jacobian about a source and computes its ratio with a nominal pixel area.
131 This allows one to compare relative instead of absolute areas of pixels.
134 ConfigClass = SingleFrameJacobianConfig
138 return cls.SHAPE_ORDER
140 def __init__(self, config, name, schema, metadata):
141 SingleFramePlugin.__init__(self, config, name, schema, metadata)
142 self.
jacValue = schema.addField(name +
'_value', type=
"D", doc=
"Jacobian correction")
143 self.
jacFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to 1 for any fatal failure")
145 self.
scale = pow(self.config.pixelScale, -2)
148 center = measRecord.getCentroid()
151 result = numpy.abs(self.
scale*exposure.getWcs().linearizePixelToSky(
153 lsst.afw.geom.arcseconds).getLinear().computeDeterminant())
154 measRecord.set(self.
jacValue, result)
156 def fail(self, measRecord, error=None):
157 measRecord.set(self.
jacFlag,
True)
161 scale = lsst.pex.config.Field(dtype=float, default=5.0, optional=
True,
162 doc=
"Scale factor to apply to shape for aperture")
163 mask = lsst.pex.config.ListField(doc=
"Mask planes to ignore", dtype=str,
164 default=[
"DETECTED",
"DETECTED_NEGATIVE",
"BAD",
"SAT"])
170 Calculate the median variance within a Footprint scaled from the object shape so
171 the value is not terribly influenced by the object and instead represents the
172 variance in the background near the object.
174 ConfigClass = SingleFrameVarianceConfig
175 FAILURE_BAD_CENTROID = 1
176 FAILURE_EMPTY_FOOTPRINT = 2
180 return cls.FLUX_ORDER
182 def __init__(self, config, name, schema, metadata):
183 SingleFramePlugin.__init__(self, config, name, schema, metadata)
184 self.
varValue = schema.addField(name +
'_value', type=
"D", doc=
"Variance at object position")
185 self.
varFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to True for any fatal failure")
187 doc=
"Set to True when the footprint has no usable pixels")
191 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
194 if measRecord.getCentroidFlag():
199 aperture.scale(self.config.scale)
201 foot.clipTo(exposure.getBBox(lsst.afw.image.PARENT))
204 maskedImage = exposure.getMaskedImage()
206 maskBits = maskedImage.getMask().getPlaneBitMask(self.config.mask)
207 logicalMask = numpy.logical_not(pixels.getMaskArray() & maskBits)
211 if numpy.any(logicalMask):
212 medVar = numpy.median(pixels.getVarianceArray()[logicalMask])
213 measRecord.set(self.
varValue, medVar)
215 raise bl.MeasurementError(
"Footprint empty, or all pixels are masked, can't compute median",
218 def fail(self, measRecord, error=None):
220 if isinstance(error, bl.MeasurementError):
225 measRecord.set(self.
varValue, numpy.nan)
226 measRecord.set(self.
varFlag,
True)
236 Plugin to count how many input images contributed to each source. This information
237 is in the exposure's coaddInputs. Some limitations:
238 * This is only for the pixel containing the center, not for all the pixels in the
240 * This does not account for any clipping in the coadd
243 ConfigClass = SingleFrameInputCountConfig
244 FAILURE_BAD_CENTROID = 1
245 FAILURE_NO_INPUTS = 2
249 return cls.SHAPE_ORDER
251 def __init__(self, config, name, schema, metadata):
252 SingleFramePlugin.__init__(self, config, name, schema, metadata)
253 self.
numberKey = schema.addField(name +
'_value', type=
"I",
254 doc=
"Number of images contributing at center, not including any"
256 self.
numberFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to True for fatal failure")
257 self.
noInputsFlag = schema.addField(name +
'_flag_noInputs', type=
"Flag",
258 doc=
"No coadd inputs available")
261 schema.getAliasMap().set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
264 if not exposure.getInfo().getCoaddInputs():
266 if measRecord.getCentroidFlag():
269 center = measRecord.getCentroid()
270 ccds = exposure.getInfo().getCoaddInputs().ccds
271 measRecord.set(self.
numberKey, len(ccds.subsetContaining(center, exposure.getWcs())))
273 def fail(self, measRecord, error=None):
275 if error
is not None:
289 A centroid algorithm that simply uses the first (i.e. highest) Peak in the Source's
290 Footprint as the centroid. This is of course a relatively poor measure of the true
291 centroid of the object; this algorithm is provided mostly for testing and debugging.
294 ConfigClass = SingleFramePeakCentroidConfig
298 return cls.CENTROID_ORDER
300 def __init__(self, config, name, schema, metadata):
301 SingleFramePlugin.__init__(self, config, name, schema, metadata)
302 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
303 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
304 self.
flag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Centroiding failed")
307 peak = measRecord.getFootprint().getPeaks()[0]
308 measRecord.set(self.
keyX, peak.getFx())
309 measRecord.set(self.
keyY, peak.getFy())
311 def fail(self, measRecord, error=None):
312 measRecord.set(self.
flag,
True)
316 return SimpleCentroidTransform
326 A measurement plugin that sets the "coord" field (part of the Source minimal schema)
327 using the slot centroid and the Wcs attached to the Exposure.
330 ConfigClass = SingleFrameSkyCoordConfig
334 return cls.SHAPE_ORDER
339 if not exposure.hasWcs():
340 raise Exception(
"Wcs not attached to exposure. Required for " + self.name +
" algorithm")
341 measRecord.updateCoord(exposure.getWcs())
343 def fail(self, measRecord, error=None):
352 class ForcedPeakCentroidConfig(ForcedPluginConfig):
359 The forced peak centroid is like the SFM peak centroid plugin, except that it must transform
360 the peak coordinate from the original (reference) coordinate system to the coordinate system
361 of the exposure being measured.
364 ConfigClass = ForcedPeakCentroidConfig
368 return cls.CENTROID_ORDER
370 def __init__(self, config, name, schemaMapper, metadata):
371 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
372 schema = schemaMapper.editOutputSchema()
373 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
374 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
376 def measure(self, measRecord, exposure, refRecord, refWcs):
377 targetWcs = exposure.getWcs()
378 peak = refRecord.getFootprint().getPeaks()[0]
380 if not refWcs == targetWcs:
381 result = targetWcs.skyToPixel(refWcs.pixelToSky(result))
382 measRecord.set(self.
keyX, result.getX())
383 measRecord.set(self.
keyY, result.getY())
387 return SimpleCentroidTransform
394 @
register(
"base_TransformedCentroid")
396 """A centroid pseudo-algorithm for forced measurement that simply transforms the centroid
397 from the reference catalog to the measurement coordinate system. This is used as
398 the slot centroid by default in forced measurement, allowing subsequent measurements
399 to simply refer to the slot value just as they would in single-frame measurement.
402 ConfigClass = ForcedTransformedCentroidConfig
406 return cls.CENTROID_ORDER
408 def __init__(self, config, name, schemaMapper, metadata):
409 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
410 schema = schemaMapper.editOutputSchema()
412 xKey = schema.addField(name +
"_x", type=
"D", doc=
"transformed reference centroid column",
414 yKey = schema.addField(name +
"_y", type=
"D", doc=
"transformed reference centroid row",
420 if "slot_Centroid_flag" in schemaMapper.getInputSchema():
421 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
422 doc=
"whether the reference centroid is marked as bad")
426 def measure(self, measRecord, exposure, refRecord, refWcs):
427 targetWcs = exposure.getWcs()
428 if not refWcs == targetWcs:
429 targetPos = targetWcs.skyToPixel(refWcs.pixelToSky(refRecord.getCentroid()))
432 measRecord.set(self.
centroidKey, refRecord.getCentroid())
434 measRecord.set(self.
flagKey, refRecord.getCentroidFlag())
443 """A shape pseudo-algorithm for forced measurement that simply transforms the shape
444 from the reference catalog to the measurement coordinate system. This is used as
445 the slot shape by default in forced measurement, allowing subsequent measurements
446 to simply refer to the slot value just as they would in single-frame measurement.
449 ConfigClass = ForcedTransformedShapeConfig
453 return cls.SHAPE_ORDER
455 def __init__(self, config, name, schemaMapper, metadata):
456 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
457 schema = schemaMapper.editOutputSchema()
459 xxKey = schema.addField(name +
"_xx", type=
"D", doc=
"transformed reference shape x^2 moment",
461 yyKey = schema.addField(name +
"_yy", type=
"D", doc=
"transformed reference shape y^2 moment",
463 xyKey = schema.addField(name +
"_xy", type=
"D", doc=
"transformed reference shape xy moment",
469 if "slot_Shape_flag" in schemaMapper.getInputSchema():
470 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
471 doc=
"whether the reference shape is marked as bad")
475 def measure(self, measRecord, exposure, refRecord, refWcs):
476 targetWcs = exposure.getWcs()
477 if not refWcs == targetWcs:
479 localTransform = fullTransform.linearizeForwardTransform(refRecord.getCentroid())
480 measRecord.set(self.
shapeKey, refRecord.getShape().transform(localTransform.getLinear()))
482 measRecord.set(self.
shapeKey, refRecord.getShape())
484 measRecord.set(self.
flagKey, refRecord.getShapeFlag())
int FAILURE_EMPTY_FOOTPRINT
An ellipse defined by an arbitrary BaseCore and a center point.
def wrapSimpleAlgorithm
Wrap a C++ SimpleAlgorithm class into both a Python SingleFramePlugin and ForcedPlugin classes...
A FunctorKey used to get or set a geom::ellipses::Quadrupole from a tuple of constituent Keys...
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=NULL)