24 __all__ = (
"MeasureApCorrConfig",
"MeasureApCorrTask")
30 from lsst.afw.math import ChebyshevBoundedField, ChebyshevBoundedFieldConfig
34 from .sourceSelector
import sourceSelectorRegistry
38 """A collection of keys for a given flux measurement algorithm 40 __slots__ = (
"flux",
"err",
"flag",
"used")
43 """Construct a FluxKeys 45 @parma[in] name name of flux measurement algorithm, e.g. "base_PsfFlux" 46 @param[in,out] schema catalog schema containing the flux field 47 read: {name}_flux, {name}_fluxSigma, {name}_flag 48 added: apcorr_{name}_used 50 self.
flux = schema.find(name +
"_flux").key
51 self.
err = schema.find(name +
"_fluxSigma").key
52 self.
flag = schema.find(name +
"_flag").key
53 self.
used = schema.addField(
"apcorr_" + name +
"_used", type=
"Flag",
54 doc=
"set if source was used in measuring aperture correction")
66 """!Configuration for MeasureApCorrTask 68 refFluxName = lsst.pex.config.Field(
69 doc=
"Field name prefix for the flux other measurements should be aperture corrected to match",
71 default=
"slot_CalibFlux",
73 sourceSelector = sourceSelectorRegistry.makeField(
74 doc=
"Selector that sets the stars that aperture corrections will be measured from.",
77 minDegreesOfFreedom = lsst.pex.config.RangeField(
78 doc=
"Minimum number of degrees of freedom (# of valid data points - # of parameters);" +
79 " if this is exceeded, the order of the fit is decreased (in both dimensions), and" +
80 " if we can't decrease it enough, we'll raise ValueError.",
85 fitConfig = lsst.pex.config.ConfigField(
86 doc=
"Configuration used in fitting the aperture correction fields",
87 dtype=ChebyshevBoundedFieldConfig,
89 numIter = lsst.pex.config.Field(
90 doc=
"Number of iterations for sigma clipping",
94 numSigmaClip = lsst.pex.config.Field(
95 doc=
"Number of standard devisations to clip at",
99 allowFailure = lsst.pex.config.ListField(
100 doc=
"Allow these measurement algorithms to fail without an exception",
106 lsst.pex.config.Config.validate(self)
108 raise lsst.pex.config.FieldValidationError(
109 "Star selectors that require matches are not permitted" 114 """!Task to measure aperture correction 116 @section measAlg_MeasureApCorrTask_Contents Contents 118 - @ref measAlg_MeasureApCorrTask_Purpose 119 - @ref measAlg_MeasureApCorrTask_Config 120 - @ref measAlg_MeasureApCorrTask_Debug 122 @section measAlg_MeasureApCorrTask_Purpose Description 124 @copybrief MeasureApCorrTask 126 This task measures aperture correction for the flux fields returned by 127 lsst.meas.base.getApCorrNameSet() 129 The main method is @ref MeasureApCorrTask.run "run". 131 @section measAlg_MeasureApCorrTask_Config Configuration parameters 133 See @ref MeasureApCorrConfig 135 @section measAlg_MeasureApCorrTask_Debug Debug variables 137 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag 138 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`. 140 MeasureApCorrTask has a debug dictionary containing a single boolean key: 143 <dd>If True: will show plots as aperture corrections are fitted 146 For example, put something like: 150 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 151 if name == "lsst.meas.algorithms.measureApCorr": 160 lsstDebug.Info = DebugInfo 162 into your `debug.py` file and run your command-line task with the `--debug` flag (or `import debug`). 164 ConfigClass = MeasureApCorrConfig
165 _DefaultName =
"measureApCorr" 168 """!Construct a MeasureApCorrTask 170 For every name in lsst.meas.base.getApCorrNameSet(): 171 - If the corresponding flux fields exist in the schema: 172 - Add a new field apcorr_{name}_used 173 - Add an entry to the self.toCorrect dict 174 - Otherwise silently skip the name 176 Task.__init__(self, **kwds)
179 for name
in getApCorrNameSet():
185 self.makeSubtask(
"sourceSelector")
187 def run(self, exposure, catalog):
188 """!Measure aperture correction 190 @param[in] exposure Exposure aperture corrections are being measured 191 on. The bounding box is retrieved from it, and 192 it is passed to the sourceSelector. 193 The output aperture correction map is *not* 194 added to the exposure; this is left to the 197 @param[in] catalog SourceCatalog containing measurements to be used 198 to compute aperturecorrections. 200 @return an lsst.pipe.base.Struct containing: 201 - apCorrMap: an aperture correction map (lsst.afw.image.ApCorrMap) that contains two entries 203 - flux field (e.g. base_PsfFlux_flux): 2d model 204 - flux sigma field (e.g. base_PsfFlux_fluxSigma): 2d model of error 206 bbox = exposure.getBBox()
210 self.log.info(
"Measuring aperture corrections for %d flux fields" % (len(self.
toCorrect),))
213 subset1 = [record
for record
in self.sourceSelector.
run(catalog, exposure=exposure).sourceCat
215 numpy.isfinite(record.get(self.
refFluxKeys.flux)))]
220 for name, keys
in self.
toCorrect.items():
221 fluxName = name +
"_flux" 222 fluxSigmaName = name +
"_fluxSigma" 226 fluxes = numpy.fromiter((record.get(keys.flux)
for record
in subset1), float)
227 with numpy.errstate(invalid=
"ignore"):
228 isGood = numpy.logical_and.reduce([
229 numpy.fromiter((
not record.get(keys.flag)
for record
in subset1), bool),
230 numpy.isfinite(fluxes),
233 subset2 = [record
for record, good
in zip(subset1, isGood)
if good]
237 if len(subset2) - 1 < self.config.minDegreesOfFreedom:
238 if name
in self.config.allowFailure:
239 self.log.warn(
"Unable to measure aperture correction for '%s': " 240 "only %d sources, but require at least %d." %
241 (name, len(subset2), self.config.minDegreesOfFreedom+1))
243 raise RuntimeError(
"Unable to measure aperture correction for required algorithm '%s': " 244 "only %d sources, but require at least %d." %
245 (name, len(subset2), self.config.minDegreesOfFreedom+1))
248 ctrl = self.config.fitConfig.makeControl()
249 while len(subset2) - ctrl.computeSize() < self.config.minDegreesOfFreedom:
256 x = numpy.zeros(len(subset2), dtype=float)
257 y = numpy.zeros(len(subset2), dtype=float)
258 apCorrData = numpy.zeros(len(subset2), dtype=float)
259 indices = numpy.arange(len(subset2), dtype=int)
260 for n, record
in enumerate(subset2):
263 apCorrData[n] = record.get(self.
refFluxKeys.flux)/record.get(keys.flux)
265 for _i
in range(self.config.numIter):
268 apCorrField = ChebyshevBoundedField.fit(bbox, x, y, apCorrData, ctrl)
271 plotApCorr(bbox, x, y, apCorrData, apCorrField,
"%s, iteration %d" % (name, _i))
275 apCorrDiffs = apCorrField.evaluate(x, y)
276 apCorrDiffs -= apCorrData
277 apCorrErr = numpy.mean(apCorrDiffs**2)**0.5
280 apCorrDiffLim = self.config.numSigmaClip * apCorrErr
281 with numpy.errstate(invalid=
"ignore"):
282 keep = numpy.fabs(apCorrDiffs) <= apCorrDiffLim
285 apCorrData = apCorrData[keep]
286 indices = indices[keep]
289 apCorrField = ChebyshevBoundedField.fit(bbox, x, y, apCorrData, ctrl)
291 self.log.info(
"Aperture correction for %s: RMS %f from %d" %
292 (name, numpy.mean((apCorrField.evaluate(x, y) - apCorrData)**2)**0.5, len(indices)))
295 plotApCorr(bbox, x, y, apCorrData, apCorrField,
"%s, final" % (name,))
301 apCorrMap[fluxName] = apCorrField
302 apCorrErrCoefficients = numpy.array([[apCorrErr]], dtype=float)
307 subset2[i].set(keys.used,
True)
315 """Plot aperture correction fit residuals 317 There are two subplots: residuals against x and y. 319 Intended for debugging. 321 @param bbox Bounding box (for bounds) 322 @param xx x coordinates 323 @param yy y coordinates 324 @param zzMeasure Measured value of the aperture correction 325 @param field Fit aperture correction field 326 @param title Title for plot 328 import matplotlib.pyplot
as plt
330 zzFit = field.evaluate(xx, yy)
331 residuals = zzMeasure - zzFit
333 fig, axes = plt.subplots(2, 1)
335 axes[0].scatter(xx, residuals, s=2, marker=
'o', lw=0, alpha=0.3)
336 axes[1].scatter(yy, residuals, s=2, marker=
'o', lw=0, alpha=0.3)
338 ax.set_ylabel(
"Residual")
339 ax.set_ylim(0.9*residuals.min(), 1.1*residuals.max())
340 axes[0].set_xlabel(
"x")
341 axes[0].set_xlim(bbox.getMinX(), bbox.getMaxX())
342 axes[1].set_xlabel(
"y")
343 axes[1].set_xlim(bbox.getMinY(), bbox.getMaxY())
Task to measure aperture correction.
def plotApCorr(bbox, xx, yy, zzMeasure, field, title)
def run(self, exposure, catalog)
Measure aperture correction.
Configuration for MeasureApCorrTask.
def __init__(self, name, schema)
def __init__(self, schema, kwds)
Construct a MeasureApCorrTask.