24import lsst.pipe.base
as pipeBase
31 """Image statistics options.
33 doCtiStatistics = pexConfig.Field(
35 doc="Measure CTI statistics from image and overscans?",
38 stat = pexConfig.Field(
41 doc=
"Statistic name to use to measure regions.",
43 nSigmaClip = pexConfig.Field(
46 doc=
"Clipping threshold for background",
48 nIter = pexConfig.Field(
51 doc=
"Clipping iterations for background",
53 badMask = pexConfig.ListField(
55 default=[
"BAD",
"INTRP",
"SAT"],
56 doc=
"Mask planes to ignore when identifying source pixels."
61 """Task to measure arbitrary statistics on ISR processed exposures.
63 The goal is to wrap a number of optional measurements that are
64 useful
for calibration production
and detector stability.
66 ConfigClass = IsrStatisticsTaskConfig
67 _DefaultName = "isrStatistics"
69 def __init__(self, statControl=None, **kwargs):
71 self.
statControl = afwMath.StatisticsControl(self.config.nSigmaClip, self.config.nIter,
72 afwImage.Mask.getPlaneBitMask(self.config.badMask))
73 self.
statType = afwMath.stringToStatisticsProperty(self.config.stat)
75 def run(self, inputExp, ptc=None, overscanResults=None, **kwargs):
76 """Task to run arbitrary statistics.
78 The statistics should be measured by individual methods, and
79 add to the dictionary
in the
return struct.
84 The exposure to measure.
85 ptc : `lsst.ip.isr.PtcDataset`, optional
86 A PTC object containing gains to use.
87 overscanResults : `list` [`lsst.pipe.base.Struct`], optional
88 List of overscan results. Expected fields are:
91 Value
or fit subtracted
from the amplifier image data
94 Value
or fit subtracted
from the overscan image data
97 Image of the overscan region
with the overscan
99 quantity
is used to estimate the amplifier read noise
104 resultStruct : `lsst.pipe.base.Struct`
105 Contains the measured statistics
as a dict stored
in a
106 field named ``results``.
111 Raised
if the amplifier gains could
not be found.
114 detector = inputExp.getDetector()
117 elif detector
is not None:
118 gains = {amp.getName(): amp.getGain()
for amp
in detector.getAmplifiers()}
120 raise RuntimeError(
"No source of gains provided.")
121 if self.config.doCtiStatistics:
122 ctiResults = self.
measureCti(inputExp, overscanResults, gains)
124 return pipeBase.Struct(
125 results={
'CTI': ctiResults, },
129 """Task to measure CTI statistics.
135 overscans : `list` [`lsst.pipe.base.Struct`]
136 List of overscan results. Expected fields are:
139 Value or fit subtracted
from the amplifier image data
142 Value
or fit subtracted
from the overscan image data
145 Image of the overscan region
with the overscan
147 quantity
is used to estimate the amplifier read noise
149 gains : `dict` [`str` `float]
150 Dictionary of per-amplifier gains, indexed by amplifier name.
154 outputStats : `dict` [`str`, [`dict` [`str`,`float]]
155 Dictionary of measurements, keyed by amplifier name
and
160 detector = inputExp.getDetector()
161 image = inputExp.image
164 assert len(overscans) == len(detector.getAmplifiers())
166 for ampIter, amp
in enumerate(detector.getAmplifiers()):
168 gain = gains[amp.getName()]
169 readoutCorner = amp.getReadoutCorner()
171 dataRegion = image[amp.getBBox()]
172 ampStats[
'IMAGE_MEAN'] = afwMath.makeStatistics(dataRegion, self.
statType,
176 pixelA = afwMath.makeStatistics(dataRegion.array[:, 0],
179 pixelZ = afwMath.makeStatistics(dataRegion.array[:, -1],
185 if readoutCorner
in (ReadoutCorner.LR, ReadoutCorner.UR):
186 ampStats[
'FIRST_MEAN'] = pixelZ
187 ampStats[
'LAST_MEAN'] = pixelA
189 ampStats[
'FIRST_MEAN'] = pixelA
190 ampStats[
'LAST_MEAN'] = pixelZ
193 if overscans[ampIter]
is None:
196 self.log.warn(
"No overscan information available for ISR statistics for amp %s.",
198 nCols = amp.getSerialOverscanBBox().getWidth()
199 ampStats[
'OVERSCAN_COLUMNS'] = np.full((nCols, ), np.nan)
200 ampStats[
'OVERSCAN_VALUES'] = np.full((nCols, ), np.nan)
202 overscanImage = overscans[ampIter].overscanImage
205 for column
in range(0, overscanImage.getWidth()):
206 osMean = afwMath.makeStatistics(overscanImage.image.array[:, column],
208 columns.append(column)
209 values.append(gain * osMean)
213 if readoutCorner
in (ReadoutCorner.LR, ReadoutCorner.UR):
214 ampStats[
'OVERSCAN_COLUMNS'] = list(reversed(columns))
215 ampStats[
'OVERSCAN_VALUES'] = list(reversed(values))
217 ampStats[
'OVERSCAN_COLUMNS'] = columns
218 ampStats[
'OVERSCAN_VALUES'] = values
220 outputStats[amp.getName()] = ampStats
def run(self, inputExp, ptc=None, overscanResults=None, **kwargs)
def __init__(self, statControl=None, **kwargs)
def measureCti(self, inputExp, overscans, gains)