LSST Applications 29.0.1,g0fba68d861+132dd21e0a,g107a963962+1bb9f809a9,g1fd858c14a+005be21cae,g21d47ad084+8a07b29876,g325378336f+5d73323c8f,g330003fc43+40b4eaffc6,g35bb328faa+fcb1d3bbc8,g36ff55ed5b+9c28a42a87,g4e0f332c67+5fbd1e3e73,g53246c7159+fcb1d3bbc8,g60b5630c4e+9c28a42a87,g67b6fd64d1+a38b34ea13,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g86c591e316+6b2b2d0295,g8852436030+bf14db0e33,g89139ef638+a38b34ea13,g8b8da53e10+e3777245af,g9125e01d80+fcb1d3bbc8,g989de1cb63+a38b34ea13,g9f1445be69+9c28a42a87,g9f33ca652e+52c8f07962,ga9baa6287d+9c28a42a87,ga9e4eb89a6+9f84bd6575,gabe3b4be73+1e0a283bba,gb037a4e798+f3cbcd26c0,gb1101e3267+e7be8da0f8,gb58c049af0+f03b321e39,gb89ab40317+a38b34ea13,gcf25f946ba+bf14db0e33,gd6cbbdb0b4+bce7f7457e,gd9a9a58781+fcb1d3bbc8,gde0f65d7ad+53d424b1ae,ge278dab8ac+222406d50a,ge410e46f29+a38b34ea13,ge80e9994a3+664d6357dc,gf67bdafdda+a38b34ea13
LSST Data Management Base Package
Loading...
Searching...
No Matches
lsst.meas.algorithms.measureApCorr.MeasureApCorrTask Class Reference
Inheritance diagram for lsst.meas.algorithms.measureApCorr.MeasureApCorrTask:

Public Member Functions

 __init__ (self, schema, namesToCorrect=None, **kwargs)
 
 run (self, exposure, catalog)
 

Public Attributes

 refFluxNames = _FluxNames(self.config.refFluxName, schema)
 
dict toCorrect = {}
 

Static Public Attributes

 ConfigClass = MeasureApCorrConfig
 

Static Protected Attributes

str _DefaultName = "measureApCorr"
 

Detailed Description

Task to measure aperture correction.

For every name to correct, a new field apcorr_{name}_used will
be added, and will be logged in self.toCorrect.

Parameters
----------
schema : `lsst.afw.table.Schema`
    Schema for the input table; will be modified in place to
    add ``apcorr_{name}_used`` fields.
namesToCorrect : `list` [`str`], optional
    List of names to correct.  If `None` then the set of
    registered fields in lsst.meas.base.getApCorrNameSet()
    will be used.
**kwargs : `dict`
    Additional kwargs to pass to lsst.pipe.base.Task.__init__()

Raises
------
MeasureApCorrError if any of the names to correct fails and is
not in the config.allowFailure list.

Definition at line 186 of file measureApCorr.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.__init__ ( self,
schema,
namesToCorrect = None,
** kwargs )

Definition at line 212 of file measureApCorr.py.

212 def __init__(self, schema, namesToCorrect=None, **kwargs):
213 Task.__init__(self, **kwargs)
214 self.refFluxNames = _FluxNames(self.config.refFluxName, schema)
215 self.toCorrect = {} # dict of flux field name prefix: FluxKeys instance
216 names = namesToCorrect if namesToCorrect else getApCorrNameSet()
217 for name in sorted(names):
218 try:
219 self.toCorrect[name] = _FluxNames(name, schema)
220 except KeyError:
221 # if a field in the registry is missing, just ignore it.
222 pass
223 self.makeSubtask("sourceSelector")
224

Member Function Documentation

◆ run()

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.run ( self,
exposure,
catalog )
Measure aperture correction

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure aperture corrections are being measured on. The
    bounding box is retrieved from it, and it is passed to the
    sourceSelector. The output aperture correction map is *not*
    added to the exposure; this is left to the caller.
catalog : `lsst.afw.table.SourceCatalog`
    SourceCatalog containing measurements to be used to
    compute aperture corrections.

Returns
-------
Struct : `lsst.pipe.base.Struct`
    Contains the following:

    ``apCorrMap``
        aperture correction map (`lsst.afw.image.ApCorrMap`)
        that contains two entries for each flux field:
        - flux field (e.g. base_PsfFlux_instFlux): 2d model
        - flux sigma field (e.g. base_PsfFlux_instFluxErr): 2d model of error

Definition at line 225 of file measureApCorr.py.

225 def run(self, exposure, catalog):
226 """Measure aperture correction
227
228 Parameters
229 ----------
230 exposure : `lsst.afw.image.Exposure`
231 Exposure aperture corrections are being measured on. The
232 bounding box is retrieved from it, and it is passed to the
233 sourceSelector. The output aperture correction map is *not*
234 added to the exposure; this is left to the caller.
235 catalog : `lsst.afw.table.SourceCatalog`
236 SourceCatalog containing measurements to be used to
237 compute aperture corrections.
238
239 Returns
240 -------
241 Struct : `lsst.pipe.base.Struct`
242 Contains the following:
243
244 ``apCorrMap``
245 aperture correction map (`lsst.afw.image.ApCorrMap`)
246 that contains two entries for each flux field:
247 - flux field (e.g. base_PsfFlux_instFlux): 2d model
248 - flux sigma field (e.g. base_PsfFlux_instFluxErr): 2d model of error
249 """
250 bbox = exposure.getBBox()
251 import lsstDebug
252 display = lsstDebug.Info(__name__).display
253 doPause = lsstDebug.Info(__name__).doPause
254
255 self.log.info("Measuring aperture corrections for %d flux fields", len(self.toCorrect))
256
257 # First, create a subset of the catalog that contains only selected stars
258 # with non-flagged reference fluxes.
259 selected = self.sourceSelector.run(catalog, exposure=exposure)
260
261 use = (
262 ~selected.sourceCat[self.refFluxNames.flagName]
263 & (np.isfinite(selected.sourceCat[self.refFluxNames.fluxName]))
264 )
265 goodRefCat = selected.sourceCat[use].copy()
266
267 apCorrMap = ApCorrMap()
268
269 # Outer loop over the fields we want to correct
270 for name, fluxNames in self.toCorrect.items():
271 # Create a more restricted subset with only the objects where the to-be-correct flux
272 # is not flagged.
273 fluxes = goodRefCat[fluxNames.fluxName]
274 with np.errstate(invalid="ignore"): # suppress NaN warnings.
275 isGood = (
276 (~goodRefCat[fluxNames.flagName])
277 & (np.isfinite(fluxes))
278 & (fluxes > 0.0)
279 )
280
281 # The 1 is the minimum number of ctrl.computeSize() when the order
282 # drops to 0 in both x and y.
283 if (isGood.sum() - 1) < self.config.minDegreesOfFreedom:
284 if name in self.config.allowFailure:
285 self.log.warning("Unable to measure aperture correction for '%s': "
286 "only %d sources, but require at least %d.",
287 name, isGood.sum(), self.config.minDegreesOfFreedom + 1)
288 continue
289 else:
290 raise MeasureApCorrError(name=name, nSources=isGood.sum(),
291 ndof=self.config.minDegreesOfFreedom + 1)
292
293 goodCat = goodRefCat[isGood].copy()
294
295 x = goodCat['slot_Centroid_x']
296 y = goodCat['slot_Centroid_y']
297 z = goodCat[self.refFluxNames.fluxName]/goodCat[fluxNames.fluxName]
298 ids = goodCat['id']
299
300 # We start with an initial fit that is the median offset; this
301 # works well in practice.
302 fitValues = np.median(z)
303
304 ctrl = self.config.fitConfig.makeControl()
305
306 allBad = False
307 for iteration in range(self.config.numIter):
308 resid = z - fitValues
309 # We add a small (epsilon) amount of floating-point slop because
310 # the median_abs_deviation may give a value that is just larger than 0
311 # even if given a completely flat residual field (as in tests).
312 apCorrErr = median_abs_deviation(resid, scale="normal") + 1e-7
313 keep = np.abs(resid) <= self.config.numSigmaClip * apCorrErr
314
315 self.log.debug("Removing %d sources as outliers.", len(resid) - keep.sum())
316
317 x = x[keep]
318 y = y[keep]
319 z = z[keep]
320 ids = ids[keep]
321
322 while (len(x) - ctrl.computeSize()) < self.config.minDegreesOfFreedom:
323 if ctrl.orderX > 0:
324 ctrl.orderX -= 1
325 else:
326 allBad = True
327 break
328 if ctrl.orderY > 0:
329 ctrl.orderY -= 1
330 else:
331 allBad = True
332 break
333
334 if allBad:
335 if name in self.config.allowFailure:
336 self.log.warning("Unable to measure aperture correction for '%s': "
337 "only %d sources remain, but require at least %d." %
338 (name, keep.sum(), self.config.minDegreesOfFreedom + 1))
339 break
340 else:
341 raise MeasureApCorrError(name=name, nSources=keep.sum(),
342 ndof=self.config.minDegreesOfFreedom + 1,
343 iteration=iteration+1)
344
345 apCorrField = ChebyshevBoundedField.fit(bbox, x, y, z, ctrl)
346 fitValues = apCorrField.evaluate(x, y)
347
348 if allBad:
349 continue
350
351 if self.config.doFinalMedianShift:
352 med = np.median(fitValues - z)
353 coeffs = apCorrField.getCoefficients().copy()
354 coeffs[0, 0] -= med
355 apCorrField = ChebyshevBoundedField(bbox, coeffs)
356 fitValues = apCorrField.evaluate(x, y)
357
358 self.log.info(
359 "Aperture correction for %s from %d stars: med %f, MAD %f, RMS %f",
360 name,
361 len(x),
362 np.median(fitValues - z),
363 median_abs_deviation(fitValues - z, scale="normal"),
364 np.mean((fitValues - z)**2.)**0.5,
365 )
366
367 if display:
368 plotApCorr(bbox, x, y, z, apCorrField, "%s, final" % (name,), doPause)
369
370 # Record which sources were used.
371 used = np.zeros(len(catalog), dtype=bool)
372 used[np.searchsorted(catalog['id'], ids)] = True
373 catalog[fluxNames.usedName] = used
374
375 # Save the result in the output map
376 # The error is constant spatially (we could imagine being
377 # more clever, but we're not yet sure if it's worth the effort).
378 # We save the errors as a 0th-order ChebyshevBoundedField
379 apCorrMap[fluxNames.fluxName] = apCorrField
380 apCorrMap[fluxNames.errName] = ChebyshevBoundedField(
381 bbox,
382 np.array([[apCorrErr]]),
383 )
384
385 return Struct(
386 apCorrMap=apCorrMap,
387 )
388
389

Member Data Documentation

◆ _DefaultName

str lsst.meas.algorithms.measureApCorr.MeasureApCorrTask._DefaultName = "measureApCorr"
staticprotected

Definition at line 210 of file measureApCorr.py.

◆ ConfigClass

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.ConfigClass = MeasureApCorrConfig
static

Definition at line 209 of file measureApCorr.py.

◆ refFluxNames

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.refFluxNames = _FluxNames(self.config.refFluxName, schema)

Definition at line 214 of file measureApCorr.py.

◆ toCorrect

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.toCorrect = {}

Definition at line 215 of file measureApCorr.py.


The documentation for this class was generated from the following file: