30from .apCorrRegistry
import getApCorrNameSet
38__all__ = (
"ApplyApCorrConfig",
"ApplyApCorrTask")
42 """Catalog field names and keys needed to aperture correct a particular
48 Source catalog schema. Three fields are used to generate keys:
50 - ``{name}_instFluxErr``
52 Three fields are added:
53 - ``{name}_apCorr`` (only if not already added by proxy)
54 - ``{name}_apCorrErr`` (only
if not already added by proxy)
55 - ``{name}_flag_apCorr``
57 Field name prefix
for instFlux
with aperture correction model, e.g.
60 Field name prefix
for instFlux needing aperture correction; may be
61 `
None`
if it
is the same
as ``model``
65 The aperture correction can be derived
from the meaasurements
in the
66 column being aperture-corrected
or from measurements
in a different
67 column (a
"proxy"). In the first case, we will add columns to contain
68 the aperture correction values;
in the second case (using a proxy),
69 we will add an alias to the proxy
's aperture correction values. In
70 all cases, we add a flag.
74 """Field name prefix for flux needing aperture correction (`str`).
78 """Field name for aperture correction model for flux (`str`).
82 """Field name for aperture correction model for fluxErr (`str`).
86 """Should we write the aperture correction values (`bool`)?
88 They should not be written
if they
're already being written by a proxy.
92 """Name of ``instFlux`` field (`str`).
95 instFluxErrName = None
96 """Name of ``instFlux`` sigma field (`str`).
100 """Key to ``instFlux`` field (`lsst.afw.table.schema.Key`).
103 instFluxErrKey = None
104 """Key to ``instFlux`` sigma field (`lsst.afw.table.schema.Key`).
108 """Key to the flux flag field (`lsst.afw.table.schema.Key`).
112 """Key to new aperture correction field (`lsst.afw.table.schema.Key`).
116 """Key to new aperture correction sigma field (`lsst.afw.table.schema.Key`).
120 """Key to new aperture correction flag field (`lsst.afw.table.schema.Key`).
127 self.
modelNamemodelName = model +
"_instFlux"
133 self.
fluxFlagKeyfluxFlagKey = schema.find(name +
"_flag").key
136 self.
doApCorrColumndoApCorrColumn = (name == model
or model +
"_apCorr" not in schema)
138 self.
apCorrKeyapCorrKey = schema.addField(
140 doc=
"aperture correction applied to %s" % (name,),
145 doc=
"standard deviation of aperture correction applied to %s" % (name,),
149 aliases = schema.getAliasMap()
150 aliases.set(name +
"_apCorr", model +
"_apCorr")
151 aliases.set(name +
"_apCorrErr", model +
"_apCorrErr")
152 self.
apCorrKeyapCorrKey = schema.find(name +
"_apCorr").key
153 self.
apCorrErrKeyapCorrErrKey = schema.find(name +
"_apCorrErr").key
156 name +
"_flag_apCorr",
157 doc=
"set if unable to aperture correct %s" % (name,),
163 """Aperture correction configuration.
166 ignoreList = lsst.pex.config.ListField(
167 doc="flux measurement algorithms in getApCorrNameSet() to ignore; "
168 "if a name is listed that does not appear in getApCorrNameSet() then a warning is logged",
173 doFlagApCorrFailures = lsst.pex.config.Field(
174 doc=
"set the general failure flag for a flux when it cannot be aperture-corrected?",
178 proxies = lsst.pex.config.DictField(
179 doc=
"flux measurement algorithms to be aperture-corrected by reference to another algorithm; "
180 "this is a mapping alg1:alg2, where 'alg1' is the algorithm being corrected, and 'alg2' "
181 "is the algorithm supplying the corrections",
186 loggingInterval = lsst.pex.config.Field(
187 doc=
"Interval (in seconds) to log messages (at VERBOSE level) while aperture correction is running",
194 """Apply aperture corrections.
200 ConfigClass = ApplyApCorrConfig
201 _DefaultName = "applyApCorr"
204 lsst.pipe.base.Task.__init__(self, **kwds)
208 ignoreSet = set(self.config.ignoreList)
209 missingNameSet = ignoreSet - set(apCorrNameSet)
211 self.log.warning(
"Fields in ignoreList that are not in fluxCorrectList: %s",
212 sorted(missingNameSet))
213 for name
in sorted(apCorrNameSet - ignoreSet):
214 if name +
"_instFlux" not in schema:
219 for name, model
in self.config.proxies.items():
220 if name
in apCorrNameSet:
223 if name +
"_instFlux" not in schema:
228 def run(self, catalog, apCorrMap):
229 """Apply aperture corrections to a catalog of sources.
234 Catalog of sources. Will be updated in place.
236 Aperture correction map
240 If you show debug-level log messages then you will see statistics
for
241 the effects of aperture correction.
243 self.log.info("Applying aperture corrections to %d instFlux fields", len(self.
apCorrInfoDictapCorrInfoDict))
245 self.log.debug(
"Use naive instFlux sigma computation")
247 self.log.debug(
"Use complex instFlux sigma computation that double-counts photon noise "
248 "and thus over-estimates instFlux uncertainty")
251 nextLogTime = time.time() + self.config.loggingInterval
254 apCorrModel = apCorrMap.get(apCorrInfo.modelName)
255 apCorrErrModel = apCorrMap.get(apCorrInfo.modelSigmaName)
256 if None in (apCorrModel, apCorrErrModel):
257 missingNames = [(apCorrInfo.modelName, apCorrInfo.modelSigmaName)[i]
258 for i, model
in enumerate((apCorrModel, apCorrErrModel))
if model
is None]
259 self.log.warning(
"Cannot aperture correct %s because could not find %s in apCorrMap",
260 apCorrInfo.name,
" or ".join(missingNames))
261 for source
in catalog:
262 source.set(apCorrInfo.apCorrFlagKey,
True)
265 for sourceIndex, source
in enumerate(catalog):
266 center = source.getCentroid()
268 source.set(apCorrInfo.apCorrFlagKey,
True)
269 oldFluxFlagState =
False
270 if self.config.doFlagApCorrFailures:
271 oldFluxFlagState = source.get(apCorrInfo.fluxFlagKey)
272 source.set(apCorrInfo.fluxFlagKey,
True)
277 apCorr = apCorrModel.evaluate(center)
278 if not UseNaiveFluxErr:
279 apCorrErr = apCorrErrModel.evaluate(center)
283 if apCorrInfo.doApCorrColumn:
284 source.set(apCorrInfo.apCorrKey, apCorr)
285 source.set(apCorrInfo.apCorrErrKey, apCorrErr)
287 if apCorr <= 0.0
or apCorrErr < 0.0:
290 instFlux = source.get(apCorrInfo.instFluxKey)
291 instFluxErr = source.get(apCorrInfo.instFluxErrKey)
292 source.set(apCorrInfo.instFluxKey, instFlux*apCorr)
294 source.set(apCorrInfo.instFluxErrKey, instFluxErr*apCorr)
296 a = instFluxErr/instFlux
298 source.set(apCorrInfo.instFluxErrKey, abs(instFlux*apCorr)*math.sqrt(a*a + b*b))
299 source.set(apCorrInfo.apCorrFlagKey,
False)
300 if self.config.doFlagApCorrFailures:
301 source.set(apCorrInfo.fluxFlagKey, oldFluxFlagState)
304 if (currentTime := time.time()) > nextLogTime:
305 self.log.verbose(
"Aperture corrections applied to %d sources out of %d",
306 sourceIndex + 1, len(catalog))
307 nextLogTime = currentTime + self.config.loggingInterval
309 if self.log.isEnabledFor(self.log.DEBUG):
311 apCorrArr = np.array([s.get(apCorrInfo.apCorrKey)
for s
in catalog])
312 apCorrErrArr = np.array([s.get(apCorrInfo.apCorrErrKey)
for s
in catalog])
313 self.log.debug(
"For instFlux field %r: mean apCorr=%s, stdDev apCorr=%s, "
314 "mean apCorrErr=%s, stdDev apCorrErr=%s for %s sources",
315 apCorrInfo.name, apCorrArr.mean(), apCorrArr.std(),
316 apCorrErrArr.mean(), apCorrErrArr.std(), len(catalog))
def __init__(self, schema, model, name=None)
def __init__(self, schema, **kwds)
def run(self, catalog, apCorrMap)