1190 def run(self, ccdExposure, *, camera=None, bias=None, linearizer=None,
1191 crosstalk=None, crosstalkSources=None,
1192 dark=None, flat=None, ptc=None, bfKernel=None, bfGains=None, defects=None,
1193 fringes=pipeBase.Struct(fringes=
None), opticsTransmission=
None, filterTransmission=
None,
1194 sensorTransmission=
None, atmosphereTransmission=
None,
1195 detectorNum=
None, strayLightData=
None, illumMaskedImage=
None,
1196 deferredChargeCalib=
None,
1198 """Perform instrument signature removal on an exposure.
1200 Steps included in the ISR processing, in order performed, are:
1202 - saturation and suspect pixel masking
1203 - overscan subtraction
1204 - CCD assembly of individual amplifiers
1206 - variance image construction
1207 - linearization of non-linear response
1209 - brighter-fatter correction
1212 - stray light subtraction
1214 - masking of known defects and camera specific features
1215 - vignette calculation
1216 - appending transmission curve and distortion model
1220 ccdExposure : `lsst.afw.image.Exposure`
1221 The raw exposure that is to be run through ISR. The
1222 exposure is modified by this method.
1223 camera : `lsst.afw.cameraGeom.Camera`, optional
1224 The camera geometry for this exposure. Required if
1225 one or more of ``ccdExposure``, ``bias``, ``dark``, or
1226 ``flat`` does not have an associated detector.
1227 bias : `lsst.afw.image.Exposure`, optional
1228 Bias calibration frame.
1229 linearizer : `lsst.ip.isr.linearize.LinearizeBase`, optional
1230 Functor for linearization.
1231 crosstalk : `lsst.ip.isr.crosstalk.CrosstalkCalib`, optional
1232 Calibration for crosstalk.
1233 crosstalkSources : `list`, optional
1234 List of possible crosstalk sources.
1235 dark : `lsst.afw.image.Exposure`, optional
1236 Dark calibration frame.
1237 flat : `lsst.afw.image.Exposure`, optional
1238 Flat calibration frame.
1239 ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
1240 Photon transfer curve dataset, with, e.g., gains
1242 bfKernel : `numpy.ndarray`, optional
1243 Brighter-fatter kernel.
1244 bfGains : `dict` of `float`, optional
1245 Gains used to override the detector's nominal gains for the
1246 brighter-fatter correction. A dict keyed by amplifier name for
1247 the detector in question.
1248 defects : `lsst.ip.isr.Defects`, optional
1250 fringes : `lsst.pipe.base.Struct`, optional
1251 Struct containing the fringe correction data, with
1255 fringe calibration frame (`lsst.afw.image.Exposure`)
1257 random seed derived from the ``ccdExposureId`` for random
1258 number generator (`numpy.uint32`)
1259 opticsTransmission: `lsst.afw.image.TransmissionCurve`, optional
1260 A ``TransmissionCurve`` that represents the throughput of the,
1261 optics, to be evaluated in focal-plane coordinates.
1262 filterTransmission : `lsst.afw.image.TransmissionCurve`
1263 A ``TransmissionCurve`` that represents the throughput of the
1264 filter itself, to be evaluated in focal-plane coordinates.
1265 sensorTransmission : `lsst.afw.image.TransmissionCurve`
1266 A ``TransmissionCurve`` that represents the throughput of the
1267 sensor itself, to be evaluated in post-assembly trimmed detector
1269 atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
1270 A ``TransmissionCurve`` that represents the throughput of the
1271 atmosphere, assumed to be spatially constant.
1272 detectorNum : `int`, optional
1273 The integer number for the detector to process.
1274 strayLightData : `object`, optional
1275 Opaque object containing calibration information for stray-light
1276 correction. If `None`, no correction will be performed.
1277 illumMaskedImage : `lsst.afw.image.MaskedImage`, optional
1278 Illumination correction image.
1282 result : `lsst.pipe.base.Struct`
1283 Result struct with component:
1286 The fully ISR corrected exposure.
1287 (`lsst.afw.image.Exposure`)
1289 An alias for ``exposure``. (`lsst.afw.image.Exposure`)
1291 Thumbnail image of the exposure after overscan subtraction.
1294 Thumbnail image of the exposure after flat-field correction.
1296 ``outputStatistics``
1297 Values of the additional statistics calculated.
1302 Raised if a configuration option is set to `True`, but the
1303 required calibration data has not been specified.
1307 The current processed exposure can be viewed by setting the
1308 appropriate `lsstDebug` entries in the ``debug.display``
1309 dictionary. The names of these entries correspond to some of
1310 the `IsrTaskConfig` Boolean options, with the value denoting the
1311 frame to use. The exposure is shown inside the matching
1312 option check and after the processing of that step has
1313 finished. The steps with debug points are:
1324 In addition, setting the ``postISRCCD`` entry displays the
1325 exposure after all ISR processing has finished.
1328 ccdExposure = self.
ensureExposure(ccdExposure, camera, detectorNum)
1333 ccd = ccdExposure.getDetector()
1334 filterLabel = ccdExposure.getFilter()
1335 physicalFilter = isrFunctions.getPhysicalFilter(filterLabel, self.log)
1338 assert not self.config.doAssembleCcd,
"You need a Detector to run assembleCcd."
1339 ccd = [
FakeAmp(ccdExposure, self.config)]
1342 if self.config.doBias
and bias
is None:
1343 raise RuntimeError(
"Must supply a bias exposure if config.doBias=True.")
1345 raise RuntimeError(
"Must supply a linearizer if config.doLinearize=True for this detector.")
1346 if self.config.doBrighterFatter
and bfKernel
is None:
1347 raise RuntimeError(
"Must supply a kernel if config.doBrighterFatter=True.")
1348 if self.config.doDark
and dark
is None:
1349 raise RuntimeError(
"Must supply a dark exposure if config.doDark=True.")
1350 if self.config.doFlat
and flat
is None:
1351 raise RuntimeError(
"Must supply a flat exposure if config.doFlat=True.")
1352 if self.config.doDefect
and defects
is None:
1353 raise RuntimeError(
"Must supply defects if config.doDefect=True.")
1354 if (self.config.doFringe
and physicalFilter
in self.fringe.config.filters
1355 and fringes.fringes
is None):
1360 raise RuntimeError(
"Must supply fringe exposure as a pipeBase.Struct.")
1361 if (self.config.doIlluminationCorrection
and physicalFilter
in self.config.illumFilters
1362 and illumMaskedImage
is None):
1363 raise RuntimeError(
"Must supply an illumcor if config.doIlluminationCorrection=True.")
1364 if (self.config.doDeferredCharge
and deferredChargeCalib
is None):
1365 raise RuntimeError(
"Must supply a deferred charge calibration if config.doDeferredCharge=True.")
1366 if (self.config.usePtcGains
and ptc
is None):
1367 raise RuntimeError(
"No ptcDataset provided to use PTC gains.")
1368 if (self.config.usePtcReadNoise
and ptc
is None):
1369 raise RuntimeError(
"No ptcDataset provided to use PTC read noise.")
1372 exposureMetadata = ccdExposure.getMetadata()
1373 doRaise = self.config.doRaiseOnCalibMismatch
1374 keywords = self.config.cameraKeywordsToCompare
1375 if self.config.doBias:
1378 if self.config.doBrighterFatter:
1380 if self.config.doCrosstalk:
1382 if self.config.doDark:
1385 if self.config.doDefect:
1387 if self.config.doDeferredCharge:
1392 deferredChargeCalib,
1396 if self.config.doFlat:
1399 if (self.config.doFringe
and physicalFilter
in self.fringe.config.filters):
1408 if (self.config.doIlluminationCorrection
and physicalFilter
in self.config.illumFilters):
1419 if self.config.usePtcGains
or self.config.usePtcReadNoise:
1421 if self.config.doStrayLight:
1434 exposureMetadata[
"LSST ISR UNITS"] =
"adu"
1435 exposureMetadata[
"LSST ISR CROSSTALK APPLIED"] =
False
1436 exposureMetadata[
"LSST ISR LINEARIZER APPLIED"] =
False
1437 exposureMetadata[
"LSST ISR CTI APPLIED"] =
False
1438 exposureMetadata[
"LSST ISR BIAS APPLIED"] =
False
1439 exposureMetadata[
"LSST ISR DARK APPLIED"] =
False
1440 exposureMetadata[
"LSST ISR BF APPLIED"] =
False
1441 exposureMetadata[
"LSST ISR FLAT APPLIED"] =
False
1442 exposureMetadata[
"LSST ISR DEFECTS APPLIED"] =
False
1445 if self.config.doConvertIntToFloat:
1446 self.log.info(
"Converting exposure to floating point values.")
1449 if self.config.doBias
and self.config.doBiasBeforeOverscan:
1450 self.log.info(
"Applying bias correction.")
1451 isrFunctions.biasCorrection(ccdExposure.getMaskedImage(), bias.getMaskedImage(),
1452 trimToFit=self.config.doTrimToMatchCalib)
1454 ccdExposure.metadata[
"LSST ISR BIAS APPLIED"] =
True
1459 if self.config.doOverscan
and self.config.overscan.doParallelOverscan:
1461 self.overscan.maskParallelOverscan(ccdExposure, ccd)
1466 if ccdExposure.getBBox().contains(amp.getBBox()):
1471 if self.config.doOverscan
and not badAmp:
1474 self.log.debug(
"Corrected overscan for amplifier %s.", amp.getName())
1475 if overscanResults
is not None and \
1476 self.config.qa
is not None and self.config.qa.saveStats
is True:
1477 if isinstance(overscanResults.overscanMean, float):
1479 mean = overscanResults.overscanMean
1480 median = overscanResults.overscanMedian
1481 sigma = overscanResults.overscanSigma
1482 residMean = overscanResults.residualMean
1483 residMedian = overscanResults.residualMedian
1484 residSigma = overscanResults.residualSigma
1488 mean = overscanResults.overscanMean[0]
1489 median = overscanResults.overscanMedian[0]
1490 sigma = overscanResults.overscanSigma[0]
1491 residMean = overscanResults.residualMean[0]
1492 residMedian = overscanResults.residualMedian[0]
1493 residSigma = overscanResults.residualSigma[0]
1495 self.metadata[f
"FIT MEDIAN {amp.getName()}"] = median
1496 self.metadata[f
"FIT MEAN {amp.getName()}"] = mean
1497 self.metadata[f
"FIT STDEV {amp.getName()}"] = sigma
1498 self.log.debug(
" Overscan stats for amplifer %s: %f +/- %f",
1499 amp.getName(), mean, sigma)
1501 self.metadata[f
"RESIDUAL MEDIAN {amp.getName()}"] = residMedian
1502 self.metadata[f
"RESIDUAL MEAN {amp.getName()}"] = residMean
1503 self.metadata[f
"RESIDUAL STDEV {amp.getName()}"] = residSigma
1504 self.log.debug(
" Overscan stats for amplifer %s after correction: %f +/- %f",
1505 amp.getName(), residMean, residSigma)
1507 ccdExposure.getMetadata().set(
'OVERSCAN',
"Overscan corrected")
1510 self.log.warning(
"Amplifier %s is bad.", amp.getName())
1511 overscanResults =
None
1513 overscans.append(overscanResults
if overscanResults
is not None else None)
1515 self.log.info(
"Skipped OSCAN for %s.", amp.getName())
1521 if self.config.doDeferredCharge:
1522 self.log.info(
"Applying deferred charge/CTI correction.")
1523 self.deferredChargeCorrection.run(
1525 deferredChargeCalib,
1528 self.
debugView(ccdExposure,
"doDeferredCharge")
1529 ccdExposure.metadata[
"LSST ISR CTI APPLIED"] =
True
1531 if self.config.doCrosstalk
and self.config.doCrosstalkBeforeAssemble:
1532 self.log.info(
"Applying crosstalk correction.")
1533 self.crosstalk.run(ccdExposure, crosstalk=crosstalk,
1534 crosstalkSources=crosstalkSources, camera=camera)
1535 self.
debugView(ccdExposure,
"doCrosstalk")
1536 ccdExposure.metadata[
"LSST ISR CROSSTALK APPLIED"] =
True
1538 if self.config.doAssembleCcd:
1539 self.log.info(
"Assembling CCD from amplifiers.")
1540 ccdExposure = self.assembleCcd.assembleCcd(ccdExposure)
1542 if self.config.expectWcs
and not ccdExposure.getWcs():
1543 self.log.warning(
"No WCS found in input exposure.")
1544 self.
debugView(ccdExposure,
"doAssembleCcd")
1547 if self.config.qa.doThumbnailOss:
1548 ossThumb = isrQa.makeThumbnail(ccdExposure, isrQaConfig=self.config.qa)
1550 if self.config.doBias
and not self.config.doBiasBeforeOverscan:
1551 self.log.info(
"Applying bias correction.")
1552 isrFunctions.biasCorrection(ccdExposure.getMaskedImage(), bias.getMaskedImage(),
1553 trimToFit=self.config.doTrimToMatchCalib)
1555 ccdExposure.metadata[
"LSST ISR BIAS APPLIED"] =
True
1557 if self.config.doVariance:
1559 if ccdExposure.getBBox().contains(amp.getBBox()):
1560 self.log.debug(
"Constructing variance map for amplifer %s.", amp.getName())
1561 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1564 if self.config.qa
is not None and self.config.qa.saveStats
is True:
1566 afwMath.MEDIAN | afwMath.STDEVCLIP)
1567 self.metadata[f
"ISR VARIANCE {amp.getName()} MEDIAN"] = \
1568 qaStats.getValue(afwMath.MEDIAN)
1569 self.metadata[f
"ISR VARIANCE {amp.getName()} STDEV"] = \
1570 qaStats.getValue(afwMath.STDEVCLIP)
1571 self.log.debug(
" Variance stats for amplifer %s: %f +/- %f.",
1572 amp.getName(), qaStats.getValue(afwMath.MEDIAN),
1573 qaStats.getValue(afwMath.STDEVCLIP))
1574 if self.config.maskNegativeVariance:
1578 self.log.info(
"Applying linearizer.")
1579 linearizer.applyLinearity(image=ccdExposure.getMaskedImage().getImage(),
1580 detector=ccd, log=self.log)
1581 ccdExposure.metadata[
"LSST ISR LINEARIZER APPLIED"] =
True
1583 if self.config.doCrosstalk
and not self.config.doCrosstalkBeforeAssemble:
1584 self.log.info(
"Applying crosstalk correction.")
1585 self.crosstalk.run(ccdExposure, crosstalk=crosstalk,
1586 crosstalkSources=crosstalkSources)
1587 self.
debugView(ccdExposure,
"doCrosstalk")
1588 ccdExposure.metadata[
"LSST ISR CROSSTALK APPLIED"] =
True
1593 if self.config.doDefect:
1594 self.log.info(
"Masking defects.")
1596 ccdExposure.metadata[
"LSST ISR DEFECTS APPLIED"] =
True
1598 if self.config.numEdgeSuspect > 0:
1599 self.log.info(
"Masking edges as SUSPECT.")
1600 self.
maskEdges(ccdExposure, numEdgePixels=self.config.numEdgeSuspect,
1601 maskPlane=
"SUSPECT", level=self.config.edgeMaskLevel)
1603 if self.config.doNanMasking:
1604 self.log.info(
"Masking non-finite (NAN, inf) value pixels.")
1607 if self.config.doWidenSaturationTrails:
1608 self.log.info(
"Widening saturation trails.")
1609 isrFunctions.widenSaturationTrails(ccdExposure.getMaskedImage().getMask())
1611 if self.config.doCameraSpecificMasking:
1612 self.log.info(
"Masking regions for camera specific reasons.")
1613 self.masking.run(ccdExposure)
1615 if self.config.doBrighterFatter:
1625 interpExp = ccdExposure.clone()
1627 isrFunctions.interpolateFromMask(
1628 maskedImage=interpExp.getMaskedImage(),
1629 fwhm=self.config.fwhm,
1630 growSaturatedFootprints=self.config.growSaturationFootprintSize,
1631 maskNameList=list(self.config.brighterFatterMaskListToInterpolate),
1632 useLegacyInterp=self.config.useLegacyInterp,
1634 bfExp = interpExp.clone()
1636 self.log.info(
"Applying brighter-fatter correction using kernel type %s / gains %s.",
1637 type(bfKernel), type(bfGains))
1638 if self.config.doFluxConservingBrighterFatterCorrection:
1639 bfResults = isrFunctions.fluxConservingBrighterFatterCorrection(
1642 self.config.brighterFatterMaxIter,
1643 self.config.brighterFatterThreshold,
1644 self.config.brighterFatterApplyGain,
1648 bfResults = isrFunctions.brighterFatterCorrection(
1651 self.config.brighterFatterMaxIter,
1652 self.config.brighterFatterThreshold,
1653 self.config.brighterFatterApplyGain,
1656 bfCorrIters = bfResults[1]
1657 self.metadata[
"LSST ISR BF ITERS"] = bfCorrIters
1658 if bfCorrIters == self.config.brighterFatterMaxIter - 1:
1659 self.log.warning(
"Brighter-fatter correction did not converge, final difference %f.",
1662 self.log.info(
"Finished brighter-fatter correction in %d iterations.",
1664 image = ccdExposure.getMaskedImage().getImage()
1665 bfCorr = bfExp.getMaskedImage().getImage()
1666 bfCorr -= interpExp.getMaskedImage().getImage()
1675 self.log.info(
"Ensuring image edges are masked as EDGE to the brighter-fatter kernel size.")
1676 self.
maskEdges(ccdExposure, numEdgePixels=numpy.max(bfKernel.shape) // 2,
1679 if self.config.brighterFatterMaskGrowSize > 0:
1680 self.log.info(
"Growing masks to account for brighter-fatter kernel convolution.")
1681 for maskPlane
in self.config.brighterFatterMaskListToInterpolate:
1682 isrFunctions.growMasks(ccdExposure.getMask(),
1683 radius=self.config.brighterFatterMaskGrowSize,
1684 maskNameList=maskPlane,
1685 maskValue=maskPlane)
1687 self.
debugView(ccdExposure,
"doBrighterFatter")
1688 ccdExposure.metadata[
"LSST ISR BF APPLIED"] =
True
1690 if self.config.doDark:
1691 self.log.info(
"Applying dark correction.")
1694 ccdExposure.metadata[
"LSST ISR DARK APPLIED"] =
True
1696 if self.config.doFringe
and not self.config.fringeAfterFlat:
1697 self.log.info(
"Applying fringe correction before flat.")
1698 self.fringe.run(ccdExposure, **fringes.getDict())
1701 if self.config.doStrayLight
and self.strayLight.check(ccdExposure):
1702 self.log.info(
"Checking strayLight correction.")
1703 self.strayLight.run(ccdExposure, strayLightData)
1704 self.
debugView(ccdExposure,
"doStrayLight")
1706 if self.config.doFlat:
1707 self.log.info(
"Applying flat correction.")
1710 ccdExposure.metadata[
"LSST ISR FLAT APPLIED"] =
True
1714 if self.config.doApplyGains:
1715 self.log.info(
"Applying gain correction instead of flat.")
1716 isrFunctions.applyGains(ccdExposure, self.config.normalizeGains,
1718 exposureMetadata[
"LSST ISR UNITS"] =
"electron"
1720 if self.config.doFringe
and self.config.fringeAfterFlat:
1721 self.log.info(
"Applying fringe correction after flat.")
1722 self.fringe.run(ccdExposure, **fringes.getDict())
1724 if self.config.doVignette:
1725 if self.config.doMaskVignettePolygon:
1726 self.log.info(
"Constructing, attaching, and masking vignette polygon.")
1728 self.log.info(
"Constructing and attaching vignette polygon.")
1730 exposure=ccdExposure, doUpdateMask=self.config.doMaskVignettePolygon,
1731 vignetteValue=self.config.vignetteValue, log=self.log)
1733 if self.config.doAttachTransmissionCurve:
1734 self.log.info(
"Adding transmission curves.")
1735 isrFunctions.attachTransmissionCurve(ccdExposure, opticsTransmission=opticsTransmission,
1736 filterTransmission=filterTransmission,
1737 sensorTransmission=sensorTransmission,
1738 atmosphereTransmission=atmosphereTransmission)
1740 flattenedThumb =
None
1741 if self.config.qa.doThumbnailFlattened:
1742 flattenedThumb = isrQa.makeThumbnail(ccdExposure, isrQaConfig=self.config.qa)
1744 if self.config.doIlluminationCorrection
and physicalFilter
in self.config.illumFilters:
1745 self.log.info(
"Performing illumination correction.")
1746 isrFunctions.illuminationCorrection(ccdExposure.getMaskedImage(),
1747 illumMaskedImage, illumScale=self.config.illumScale,
1748 trimToFit=self.config.doTrimToMatchCalib)
1751 if self.config.doSaveInterpPixels:
1752 preInterpExp = ccdExposure.clone()
1767 if self.config.doSetBadRegions:
1768 badPixelCount, badPixelValue = isrFunctions.setBadRegions(ccdExposure)
1769 if badPixelCount > 0:
1770 self.log.info(
"Set %d BAD pixels to %f.", badPixelCount, badPixelValue)
1772 if self.config.doInterpolate:
1773 self.log.info(
"Interpolating masked pixels.")
1774 isrFunctions.interpolateFromMask(
1775 maskedImage=ccdExposure.getMaskedImage(),
1776 fwhm=self.config.fwhm,
1777 growSaturatedFootprints=self.config.growSaturationFootprintSize,
1778 maskNameList=list(self.config.maskListToInterpolate),
1779 useLegacyInterp=self.config.useLegacyInterp,
1785 if self.config.doAmpOffset:
1786 if self.config.ampOffset.doApplyAmpOffset:
1787 self.log.info(
"Measuring and applying amp offset corrections.")
1789 self.log.info(
"Measuring amp offset corrections only, without applying them.")
1790 self.ampOffset.run(ccdExposure)
1792 if self.config.doMeasureBackground:
1793 self.log.info(
"Measuring background level.")
1796 if self.config.qa
is not None and self.config.qa.saveStats
is True:
1798 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1800 afwMath.MEDIAN | afwMath.STDEVCLIP)
1801 self.metadata[f
"ISR BACKGROUND {amp.getName()} MEDIAN"] = qaStats.getValue(afwMath.MEDIAN)
1802 self.metadata[f
"ISR BACKGROUND {amp.getName()} STDEV"] = \
1803 qaStats.getValue(afwMath.STDEVCLIP)
1804 self.log.debug(
" Background stats for amplifer %s: %f +/- %f",
1805 amp.getName(), qaStats.getValue(afwMath.MEDIAN),
1806 qaStats.getValue(afwMath.STDEVCLIP))
1809 if self.config.doStandardStatistics:
1810 metadata = ccdExposure.getMetadata()
1812 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1813 ampName = amp.getName()
1814 metadata[f
"LSST ISR MASK SAT {ampName}"] = isrFunctions.countMaskedPixels(
1815 ampExposure.getMaskedImage(),
1816 [self.config.saturatedMaskName]
1818 metadata[f
"LSST ISR MASK BAD {ampName}"] = isrFunctions.countMaskedPixels(
1819 ampExposure.getMaskedImage(),
1823 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP)
1825 metadata[f
"LSST ISR FINAL MEAN {ampName}"] = qaStats.getValue(afwMath.MEAN)
1826 metadata[f
"LSST ISR FINAL MEDIAN {ampName}"] = qaStats.getValue(afwMath.MEDIAN)
1827 metadata[f
"LSST ISR FINAL STDEV {ampName}"] = qaStats.getValue(afwMath.STDEVCLIP)
1829 k1 = f
"LSST ISR FINAL MEDIAN {ampName}"
1830 k2 = f
"LSST ISR OVERSCAN SERIAL MEDIAN {ampName}"
1831 if self.config.doOverscan
and k1
in metadata
and k2
in metadata:
1832 metadata[f
"LSST ISR LEVEL {ampName}"] = metadata[k1] - metadata[k2]
1834 metadata[f
"LSST ISR LEVEL {ampName}"] = numpy.nan
1837 outputStatistics =
None
1838 if self.config.doCalculateStatistics:
1839 outputStatistics = self.isrStats.run(ccdExposure, serialOverscanResults=overscans,
1840 parallelOverscanResults=[
None for _
in overscans],
1841 bias=bias, dark=dark, flat=flat, ptc=ptc,
1843 doLegacyCtiStatistics=
True).results
1846 outputBin1Exposure =
None
1847 outputBin2Exposure =
None
1848 if self.config.doBinnedExposures:
1849 self.log.info(
"Creating binned exposures.")
1850 outputBin1Exposure = self.binning.run(
1852 binFactor=self.config.binFactor1,
1854 outputBin2Exposure = self.binning.run(
1856 binFactor=self.config.binFactor2,
1859 self.
debugView(ccdExposure,
"postISRCCD")
1861 return pipeBase.Struct(
1862 exposure=ccdExposure,
1864 flattenedThumb=flattenedThumb,
1866 outputBin1Exposure=outputBin1Exposure,
1867 outputBin2Exposure=outputBin2Exposure,
1869 preInterpExposure=preInterpExp,
1870 outputExposure=ccdExposure,
1871 outputOssThumbnail=ossThumb,
1872 outputFlattenedThumbnail=flattenedThumb,
1873 outputStatistics=outputStatistics,