LSST Applications g0265f82a02+0e5473021a,g02d81e74bb+0dd8ce4237,g1470d8bcf6+3ea6592b6f,g2079a07aa2+86d27d4dc4,g2305ad1205+5ca4c0b359,g295015adf3+d10818ec9d,g2a9a014e59+6f9be1b9cd,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g3ddfee87b4+703ba97ebf,g487adcacf7+4fa16da234,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+ffa42b374e,g5a732f18d5+53520f316c,g64a986408d+0dd8ce4237,g858d7b2824+0dd8ce4237,g8a8a8dda67+585e252eca,g99cad8db69+d39438377f,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+f1d96605c8,gb0e22166c9+60f28cb32d,gb6a65358fc+0e5473021a,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e5339d463f,gc120e1dc64+da31e9920e,gc28159a63d+0e5473021a,gcf0d15dbbd+703ba97ebf,gdaeeff99f8+f9a426f77a,ge6526c86ff+889fc9d533,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gf18bd8381d+7268b93478,gff1a9f87cc+0dd8ce4237,w.2024.16
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Static Public Attributes | Static Protected Attributes | List of all members
lsst.meas.algorithms.measureApCorr.MeasureApCorrTask Class Reference
Inheritance diagram for lsst.meas.algorithms.measureApCorr.MeasureApCorrTask:

Public Member Functions

 __init__ (self, schema, **kwargs)
 
 run (self, exposure, catalog)
 

Public Attributes

 refFluxNames
 
 toCorrect
 

Static Public Attributes

 ConfigClass = MeasureApCorrConfig
 

Static Protected Attributes

str _DefaultName = "measureApCorr"
 

Detailed Description

Task to measure aperture correction.

Definition at line 180 of file measureApCorr.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.__init__ ( self,
schema,
** kwargs )
Construct a MeasureApCorrTask

For every name in lsst.meas.base.getApCorrNameSet():
- If the corresponding flux fields exist in the schema:
    - Add a new field apcorr_{name}_used
    - Add an entry to the self.toCorrect dict
- Otherwise silently skip the name

Definition at line 186 of file measureApCorr.py.

186 def __init__(self, schema, **kwargs):
187 """Construct a MeasureApCorrTask
188
189 For every name in lsst.meas.base.getApCorrNameSet():
190 - If the corresponding flux fields exist in the schema:
191 - Add a new field apcorr_{name}_used
192 - Add an entry to the self.toCorrect dict
193 - Otherwise silently skip the name
194 """
195 Task.__init__(self, **kwargs)
196 self.refFluxNames = _FluxNames(self.config.refFluxName, schema)
197 self.toCorrect = {} # dict of flux field name prefix: FluxKeys instance
198 for name in sorted(getApCorrNameSet()):
199 try:
200 self.toCorrect[name] = _FluxNames(name, schema)
201 except KeyError:
202 # if a field in the registry is missing, just ignore it.
203 pass
204 self.makeSubtask("sourceSelector")
205

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 206 of file measureApCorr.py.

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

Member Data Documentation

◆ _DefaultName

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

Definition at line 184 of file measureApCorr.py.

◆ ConfigClass

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

Definition at line 183 of file measureApCorr.py.

◆ refFluxNames

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.refFluxNames

Definition at line 196 of file measureApCorr.py.

◆ toCorrect

lsst.meas.algorithms.measureApCorr.MeasureApCorrTask.toCorrect

Definition at line 197 of file measureApCorr.py.


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