24 __all__ = (
"MeasureApCorrConfig",
"MeasureApCorrTask")
30 from lsst.afw.math import ChebyshevBoundedField, ChebyshevBoundedFieldConfig
34 from .
import flaggedStarSelector
35 from .starSelector
import starSelectorRegistry
39 """A collection of keys for a given flux measurement algorithm 41 __slots__ = (
"flux",
"err",
"flag",
"used")
44 """Construct a FluxKeys 46 @parma[in] name name of flux measurement algorithm, e.g. "base_PsfFlux" 47 @param[in,out] schema catalog schema containing the flux field 48 read: {name}_flux, {name}_fluxSigma, {name}_flag 49 added: apcorr_{name}_used 51 self.
flux = schema.find(name +
"_flux").key
52 self.
err = schema.find(name +
"_fluxSigma").key
53 self.
flag = schema.find(name +
"_flag").key
54 self.
used = schema.addField(
"apcorr_" + name +
"_used", type=
"Flag",
55 doc=
"set if source was used in measuring aperture correction")
67 """!Configuration for MeasureApCorrTask 69 refFluxName = lsst.pex.config.Field(
70 doc=
"Field name prefix for the flux other measurements should be aperture corrected to match",
72 default=
"slot_CalibFlux",
74 starSelector = starSelectorRegistry.makeField(
75 doc=
"Selector that sets the stars that aperture corrections will be measured from",
78 minDegreesOfFreedom = lsst.pex.config.RangeField(
79 doc=
"Minimum number of degrees of freedom (# of valid data points - # of parameters);" +
80 " if this is exceeded, the order of the fit is decreased (in both dimensions), and" +
81 " if we can't decrease it enough, we'll raise ValueError.",
86 fitConfig = lsst.pex.config.ConfigField(
87 doc=
"Configuration used in fitting the aperture correction fields",
88 dtype=ChebyshevBoundedFieldConfig,
90 numIter = lsst.pex.config.Field(
91 doc=
"Number of iterations for sigma clipping",
95 numSigmaClip = lsst.pex.config.Field(
96 doc=
"Number of standard devisations to clip at",
100 allowFailure = lsst.pex.config.ListField(
101 doc=
"Allow these measurement algorithms to fail without an exception",
107 lsst.pex.config.Config.validate(self)
109 raise lsst.pex.config.FieldValidationError(
110 "Star selectors that require matches are not permitted" 115 """!Task to measure aperture correction 117 @section measAlg_MeasureApCorrTask_Contents Contents 119 - @ref measAlg_MeasureApCorrTask_Purpose 120 - @ref measAlg_MeasureApCorrTask_Config 121 - @ref measAlg_MeasureApCorrTask_Debug 123 @section measAlg_MeasureApCorrTask_Purpose Description 125 @copybrief MeasureApCorrTask 127 This task measures aperture correction for the flux fields returned by 128 lsst.meas.base.getApCorrNameSet() 130 The main method is @ref MeasureApCorrTask.run "run". 132 @section measAlg_MeasureApCorrTask_Config Configuration parameters 134 See @ref MeasureApCorrConfig 136 @section measAlg_MeasureApCorrTask_Debug Debug variables 138 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag 139 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`. 141 MeasureApCorrTask has a debug dictionary containing a single boolean key: 144 <dd>If True: will show plots as aperture corrections are fitted 147 For example, put something like: 151 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 152 if name == "lsst.meas.algorithms.measureApCorr": 161 lsstDebug.Info = DebugInfo 163 into your `debug.py` file and run your command-line task with the `--debug` flag (or `import debug`). 165 ConfigClass = MeasureApCorrConfig
166 _DefaultName =
"measureApCorr" 169 """!Construct a MeasureApCorrTask 171 For every name in lsst.meas.base.getApCorrNameSet(): 172 - If the corresponding flux fields exist in the schema: 173 - Add a new field apcorr_{name}_used 174 - Add an entry to the self.toCorrect dict 175 - Otherwise silently skip the name 177 Task.__init__(self, **kwds)
180 for name
in getApCorrNameSet():
186 self.makeSubtask(
"starSelector", schema=schema)
188 def run(self, exposure, catalog):
189 """!Measure aperture correction 191 @param[in] exposure Exposure aperture corrections are being measured 192 on. Aside from the bounding box, the exposure 193 is only used by the starSelector subtask (which 194 may need it to construct PsfCandidates, as 195 PsfCanidate construction can do some filtering). 196 The output aperture correction map is *not* 197 added to the exposure; this is left to the 200 @param[in] catalog SourceCatalog containing measurements to be used 201 to compute aperturecorrections. 203 @return an lsst.pipe.base.Struct containing: 204 - apCorrMap: an aperture correction map (lsst.afw.image.ApCorrMap) that contains two entries 206 - flux field (e.g. base_PsfFlux_flux): 2d model 207 - flux sigma field (e.g. base_PsfFlux_fluxSigma): 2d model of error 209 bbox = exposure.getBBox()
213 self.log.info(
"Measuring aperture corrections for %d flux fields" % (len(self.
toCorrect),))
216 subset1 = [record
for record
in self.starSelector.selectStars(exposure, catalog).starCat
218 numpy.isfinite(record.get(self.
refFluxKeys.flux)))]
223 for name, keys
in self.
toCorrect.items():
224 fluxName = name +
"_flux" 225 fluxSigmaName = name +
"_fluxSigma" 229 fluxes = numpy.fromiter((record.get(keys.flux)
for record
in subset1), float)
230 with numpy.errstate(invalid=
"ignore"):
231 isGood = numpy.logical_and.reduce([
232 numpy.fromiter((
not record.get(keys.flag)
for record
in subset1), bool),
233 numpy.isfinite(fluxes),
236 subset2 = [record
for record, good
in zip(subset1, isGood)
if good]
240 if len(subset2) - 1 < self.config.minDegreesOfFreedom:
241 if name
in self.config.allowFailure:
242 self.log.warn(
"Unable to measure aperture correction for '%s': " 243 "only %d sources, but require at least %d." %
244 (name, len(subset2), self.config.minDegreesOfFreedom+1))
246 raise RuntimeError(
"Unable to measure aperture correction for required algorithm '%s': " 247 "only %d sources, but require at least %d." %
248 (name, len(subset2), self.config.minDegreesOfFreedom+1))
251 ctrl = self.config.fitConfig.makeControl()
252 while len(subset2) - ctrl.computeSize() < self.config.minDegreesOfFreedom:
259 x = numpy.zeros(len(subset2), dtype=float)
260 y = numpy.zeros(len(subset2), dtype=float)
261 apCorrData = numpy.zeros(len(subset2), dtype=float)
262 indices = numpy.arange(len(subset2), dtype=int)
263 for n, record
in enumerate(subset2):
266 apCorrData[n] = record.get(self.
refFluxKeys.flux)/record.get(keys.flux)
268 for _i
in range(self.config.numIter):
271 apCorrField = ChebyshevBoundedField.fit(bbox, x, y, apCorrData, ctrl)
274 plotApCorr(bbox, x, y, apCorrData, apCorrField,
"%s, iteration %d" % (name, _i))
278 apCorrDiffs = apCorrField.evaluate(x, y)
279 apCorrDiffs -= apCorrData
280 apCorrErr = numpy.mean(apCorrDiffs**2)**0.5
283 apCorrDiffLim = self.config.numSigmaClip * apCorrErr
284 with numpy.errstate(invalid=
"ignore"):
285 keep = numpy.fabs(apCorrDiffs) <= apCorrDiffLim
288 apCorrData = apCorrData[keep]
289 indices = indices[keep]
292 apCorrField = ChebyshevBoundedField.fit(bbox, x, y, apCorrData, ctrl)
294 self.log.info(
"Aperture correction for %s: RMS %f from %d" %
295 (name, numpy.mean((apCorrField.evaluate(x, y) - apCorrData)**2)**0.5, len(indices)))
298 plotApCorr(bbox, x, y, apCorrData, apCorrField,
"%s, final" % (name,))
304 apCorrMap[fluxName] = apCorrField
305 apCorrErrCoefficients = numpy.array([[apCorrErr]], dtype=float)
310 subset2[i].set(keys.used,
True)
318 """Plot aperture correction fit residuals 320 There are two subplots: residuals against x and y. 322 Intended for debugging. 324 @param bbox Bounding box (for bounds) 325 @param xx x coordinates 326 @param yy y coordinates 327 @param zzMeasure Measured value of the aperture correction 328 @param field Fit aperture correction field 329 @param title Title for plot 331 import matplotlib.pyplot
as plt
333 zzFit = field.evaluate(xx, yy)
334 residuals = zzMeasure - zzFit
336 fig, axes = plt.subplots(2, 1)
338 axes[0].scatter(xx, residuals, s=2, marker=
'o', lw=0, alpha=0.3)
339 axes[1].scatter(yy, residuals, s=2, marker=
'o', lw=0, alpha=0.3)
341 ax.set_ylabel(
"Residual")
342 ax.set_ylim(0.9*residuals.min(), 1.1*residuals.max())
343 axes[0].set_xlabel(
"x")
344 axes[0].set_xlim(bbox.getMinX(), bbox.getMaxX())
345 axes[1].set_xlabel(
"y")
346 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.