1018 Mask SATURATED and SUSPECT pixels and check if any amplifiers
1023 badAmpDict : `str` [`bool`]
1024 Dictionary of amplifiers, keyed by name, value is True if
1025 amplifier is fully masked.
1026 ccdExposure : `lsst.afw.image.Exposure`
1027 Input exposure to be masked.
1028 detector : `lsst.afw.cameraGeom.Detector`
1030 defects : `lsst.ip.isr.Defects`
1031 List of defects. Used to determine if an entire
1033 detectorConfig : `lsst.ip.isr.OverscanDetectorConfig`
1034 Per-amplifier configurations.
1035 ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
1036 PTC dataset (used if configured to use PTCTURNOFF).
1040 badAmpDict : `str`[`bool`]
1041 Dictionary of amplifiers, keyed by name.
1043 maskedImage = ccdExposure.getMaskedImage()
1045 metadata = ccdExposure.metadata
1047 if self.config.doSaturation
and self.config.defaultSaturationSource ==
"PTCTURNOFF" and ptc
is None:
1048 raise RuntimeError(
"Must provide ptc if using PTCTURNOFF as saturation source.")
1049 if self.config.doSuspect
and self.config.defaultSuspectSource ==
"PTCTURNOFF" and ptc
is None:
1050 raise RuntimeError(
"Must provide ptc if using PTCTURNOFF as suspect source.")
1052 for amp
in detector:
1053 ampName = amp.getName()
1055 ampConfig = detectorConfig.getOverscanAmpConfig(amp)
1057 if badAmpDict[ampName]:
1063 if self.config.doSaturation:
1064 if self.config.defaultSaturationSource ==
"PTCTURNOFF":
1065 limits.update({self.config.saturatedMaskName: ptc.ptcTurnoff[amp.getName()]})
1066 elif self.config.defaultSaturationSource ==
"CAMERAMODEL":
1068 limits.update({self.config.saturatedMaskName: amp.getSaturation()})
1069 elif self.config.defaultSaturationSource ==
"NONE":
1070 limits.update({self.config.saturatedMaskName: numpy.inf})
1073 if math.isfinite(ampConfig.saturation):
1074 limits.update({self.config.saturatedMaskName: ampConfig.saturation})
1075 metadata[f
"LSST ISR SATURATION LEVEL {ampName}"] = limits[self.config.saturatedMaskName]
1077 if self.config.doSuspect:
1078 if self.config.defaultSuspectSource ==
"PTCTURNOFF":
1079 limits.update({self.config.suspectMaskName: ptc.ptcTurnoff[amp.getName()]})
1080 elif self.config.defaultSuspectSource ==
"CAMERAMODEL":
1082 limits.update({self.config.suspectMaskName: amp.getSuspectLevel()})
1083 elif self.config.defaultSuspectSource ==
"NONE":
1084 limits.update({self.config.suspectMaskName: numpy.inf})
1087 if math.isfinite(ampConfig.suspectLevel):
1088 limits.update({self.config.suspectMaskName: ampConfig.suspectLevel})
1089 metadata[f
"LSST ISR SUSPECT LEVEL {ampName}"] = limits[self.config.suspectMaskName]
1091 for maskName, maskThreshold
in limits.items():
1092 if not math.isnan(maskThreshold):
1093 dataView = maskedImage.Factory(maskedImage, amp.getRawBBox())
1094 toMask = (dataView.image.array >= maskThreshold)
1095 dataView.mask.array[toMask] |= dataView.mask.getPlaneBitMask(maskName)
1099 maskView =
afwImage.Mask(maskedImage.getMask(), amp.getRawDataBBox(),
1101 maskVal = maskView.getPlaneBitMask([self.config.saturatedMaskName,
1102 self.config.suspectMaskName])
1103 if numpy.all(maskView.getArray() & maskVal > 0):
1104 self.log.warning(
"Amplifier %s is bad (completely SATURATED or SUSPECT)", ampName)
1105 badAmpDict[ampName] =
True
1106 maskView |= maskView.getPlaneBitMask(
"BAD")
2029 deferredChargeCalib=None,
2032 gainCorrection=None,
2036 electroBfDistortionMatrix=None,
2041 """Run the IsrTaskLSST task.
2045 ccdExposure : `lsst.afw.image.Exposure`
2046 Exposure to run ISR.
2047 dnlLUT : `None`, optional
2048 DNL lookup table; placeholder, unused.
2049 bias : `lsst.afw.image.Exposure`, optional
2051 deferredChargeCalib : `lsst.ip.isr.DeferredChargeCalib`, optional
2052 Deferred charge calibration.
2053 linearizer : `lsst.ip.isr.Linearizer`, optional
2054 Linearizer calibration.
2055 ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
2057 gainCorrection : `lsst.ip.isr.GainCorrection`, optional
2058 Gain correction dataset.
2059 crosstalk : `lsst.ip.isr.CrosstalkCalib`, optional
2060 Crosstalk calibration dataset.
2061 defects : `lsst.ip.isr.Defects`, optional
2063 bfKernel : `lsst.ip.isr.BrighterFatterKernel`, optional
2064 Brighter-fatter kernel dataset.
2065 dark : `lsst.afw.image.Exposure`, optional
2067 flat : `lsst.afw.image.Exposure`, optional
2069 camera : `lsst.afw.cameraGeom.Camera`, optional
2074 result : `lsst.pipe.base.Struct`
2076 ``exposure``: `lsst.afw.image.Exposure`
2077 Calibrated exposure.
2078 ``outputBin1Exposure``: `lsst.afw.image.Exposure`
2079 Binned exposure (bin1 config).
2080 ``outputBin2Exposure``: `lsst.afw.image.Exposure`
2081 Binned exposure (bin2 config).
2082 ``outputExposure``: `lsst.afw.image.Exposure`
2083 Calibrated exposure (same as ``exposure``).
2084 ``outputStatistics``: `lsst.ip.isr.isrStatistics`
2085 Calibrated exposure statistics.
2087 detector = ccdExposure.getDetector()
2089 overscanDetectorConfig = self.config.overscanCamera.getOverscanDetectorConfig(detector)
2091 if self.config.doBootstrap:
2093 self.log.warning(
"Task configured with doBootstrap=True. Ignoring provided PTC.")
2096 if self.config.useGainsFrom ==
"LINEARIZER":
2097 if linearizer
is None:
2098 raise RuntimeError(
"doBootstrap==False and useGainsFrom == 'LINEARIZER' but "
2099 "no linearizer provided.")
2100 elif self.config.useGainsFrom ==
"PTC":
2102 raise RuntimeError(
"doBootstrap==False and useGainsFrom == 'PTC' but no PTC provided.")
2105 exposureMetadata = ccdExposure.metadata
2106 doRaise = self.config.doRaiseOnCalibMismatch
2107 keywords = self.config.cameraKeywordsToCompare
2108 if not self.config.doBootstrap:
2109 if self.config.useGainsFrom ==
"LINEARIZER":
2111 "LINEARIZER", log=self.log)
2112 elif self.config.useGainsFrom ==
"PTC":
2116 if self.config.doCorrectGains
and gainCorrection
is not None:
2126 if self.config.doCorrectGains:
2127 raise RuntimeError(
"doCorrectGains is True but no ptc provided.")
2128 if self.config.doDiffNonLinearCorrection:
2130 raise RuntimeError(
"doDiffNonLinearCorrection is True but no dnlLUT provided.")
2132 if self.config.doLinearize:
2133 if linearizer
is None:
2134 raise RuntimeError(
"doLinearize is True but no linearizer provided.")
2136 if self.config.doBias:
2138 raise RuntimeError(
"doBias is True but no bias provided.")
2141 if self.config.doCrosstalk:
2142 if crosstalk
is None:
2143 raise RuntimeError(
"doCrosstalk is True but no crosstalk provided.")
2145 if self.config.doDeferredCharge:
2146 if deferredChargeCalib
is None:
2147 raise RuntimeError(
"doDeferredCharge is True but no deferredChargeCalib provided.")
2152 deferredChargeCalib,
2156 if self.config.doDefect:
2158 raise RuntimeError(
"doDefect is True but no defects provided.")
2160 if self.config.doDark:
2162 raise RuntimeError(
"doDark is True but no dark frame provided.")
2165 if self.config.doBrighterFatter:
2166 if self.config.brighterFatterCorrectionMethod ==
"ASTIER23":
2167 if electroBfDistortionMatrix
is None:
2168 raise RuntimeError(
"Must supply an electroBfDistortionMatrix if BF "
2169 "correction method is ASTIER23.")
2171 electroBfDistortionMatrix,
"bf", log=self.log)
2172 elif self.config.brighterFatterCorrectionMethod
in [
"COULTON18",
"COULTON18_FLUX_CONSERVING"]:
2173 if bfKernel
is None:
2174 raise RuntimeError(
"Must supply an kernel if BF correction method is COULTON*.")
2177 raise ValueError(
"%s is not a known brighter-fatter correction "
2178 "method." % self.config.brighterFatterCorrectionMethod)
2179 if self.config.doFlat:
2181 raise RuntimeError(
"doFlat is True but no flat provided.")
2184 if self.config.doSaturation:
2185 if self.config.defaultSaturationSource
in [
"PTCTURNOFF",]:
2188 "doSaturation is True and defaultSaturationSource is "
2189 f
"{self.config.defaultSaturationSource}, but no ptc provided."
2191 if self.config.doSuspect:
2192 if self.config.defaultSuspectSource
in [
"PTCTURNOFF",]:
2195 "doSuspect is True and defaultSuspectSource is "
2196 f
"{self.config.defaultSuspectSource}, but no ptc provided."
2199 if self.config.doCheckUnprocessableData
and self.config.bssVoltageMinimum > 0.0:
2206 exposureMetadata[
"LSST ISR UNITS"] =
"adu"
2207 exposureMetadata[
"LSST ISR GAINCORRECTION APPLIED"] =
False
2208 exposureMetadata[
"LSST ISR CROSSTALK APPLIED"] =
False
2209 exposureMetadata[
"LSST ISR OVERSCANLEVEL CHECKED"] =
False
2210 exposureMetadata[
"LSST ISR NOISE CHECKED"] =
False
2211 exposureMetadata[
"LSST ISR LINEARIZER APPLIED"] =
False
2212 exposureMetadata[
"LSST ISR CTI APPLIED"] =
False
2213 exposureMetadata[
"LSST ISR BIAS APPLIED"] =
False
2214 exposureMetadata[
"LSST ISR DARK APPLIED"] =
False
2215 exposureMetadata[
"LSST ISR BF APPLIED"] =
False
2216 exposureMetadata[
"LSST ISR FLAT APPLIED"] =
False
2217 exposureMetadata[
"LSST ISR DEFECTS APPLIED"] =
False
2219 if self.config.doBootstrap:
2220 self.log.info(
"Configured using doBootstrap=True; using gain of 1.0 (adu units)")
2222 for amp
in detector:
2223 ptc.gain[amp.getName()] = 1.0
2224 ptc.noise[amp.getName()] = 0.0
2225 elif self.config.useGainsFrom ==
"LINEARIZER":
2226 self.log.info(
"Using gains from linearizer.")
2229 for amp
in detector:
2230 ptc.gain[amp.getName()] = linearizer.inputGain[amp.getName()]
2231 ptc.noise[amp.getName()] = 0.0
2233 exposureMetadata[
"LSST ISR BOOTSTRAP"] = self.config.doBootstrap
2240 for amp
in detector:
2241 if not math.isnan(gain := overscanDetectorConfig.getOverscanAmpConfig(amp).gain):
2242 gains[amp.getName()] = gain
2244 "Overriding gain for amp %s with configured value of %.3f.",
2251 self.log.debug(
"Converting exposure to floating point values.")
2263 if self.config.doDiffNonLinearCorrection:
2274 if overscanDetectorConfig.doAnySerialOverscan:
2277 overscanDetectorConfig,
2283 if self.config.doBootstrap
or self.config.useGainsFrom ==
"LINEARIZER":
2285 for amp, serialOverscan
in zip(detector, serialOverscans):
2286 if serialOverscan
is None:
2287 ptc.noise[amp.getName()] = 0.0
2295 ptc.noise[amp.getName()] = serialOverscan.residualSigma * gains[amp.getName()]
2297 serialOverscans = [
None]*len(detector)
2309 overscanDetectorConfig,
2315 if self.config.doCorrectGains
and gainCorrection
is not None:
2316 self.log.info(
"Correcting gains based on input GainCorrection.")
2317 gainCorrection.correctGains(gains, exposure=ccdExposure)
2318 exposureMetadata[
"LSST ISR GAINCORRECTION APPLIED"] =
True
2319 elif self.config.doCorrectGains:
2320 self.log.info(
"Skipping gain correction because no GainCorrection available.")
2325 if self.config.doApplyGains:
2326 self.log.info(
"Using gain values to convert from adu to electron units.")
2327 isrFunctions.applyGains(ccdExposure, normalizeGains=
False, ptcGains=gains, isTrimmed=
False)
2329 exposureMetadata[
"LSST ISR UNITS"] =
"electron"
2333 for amp
in detector:
2334 ampName = amp.getName()
2335 if (key := f
"LSST ISR SATURATION LEVEL {ampName}")
in exposureMetadata:
2336 exposureMetadata[key] *= gains[ampName]
2337 if (key := f
"LSST ISR SUSPECT LEVEL {ampName}")
in exposureMetadata:
2338 exposureMetadata[key] *= gains[ampName]
2341 metadata = ccdExposure.metadata
2342 metadata[
"LSST ISR READNOISE UNITS"] =
"electron"
2343 metadata[
"LSST ISR GAIN SOURCE"] = self.config.useGainsFrom
2344 for amp
in detector:
2346 metadata[f
"LSST ISR GAIN {amp.getName()}"] = gains[amp.getName()]
2349 noise = ptc.noise[amp.getName()]
2350 metadata[f
"LSST ISR READNOISE {amp.getName()}"] = noise
2354 if self.config.doCrosstalk:
2355 self.log.info(
"Applying crosstalk corrections to full amplifier region.")
2356 if self.config.doBootstrap
and numpy.any(crosstalk.fitGains != 0):
2357 crosstalkGains =
None
2359 crosstalkGains = gains
2362 crosstalk=crosstalk,
2363 gains=crosstalkGains,
2365 badAmpDict=badAmpDict,
2366 ignoreVariance=
True,
2368 ccdExposure.metadata[
"LSST ISR CROSSTALK APPLIED"] =
True
2371 if numpy.isfinite(self.config.serialOverscanMedianShiftSigmaThreshold):
2373 ccdExposure.metadata[
"LSST ISR OVERSCANLEVEL CHECKED"] =
True
2375 if numpy.isfinite(self.config.ampNoiseThreshold):
2376 badAmpDict = self.
checkAmpNoise(badAmpDict, ccdExposure, ptc)
2377 ccdExposure.metadata[
"LSST ISR NOISE CHECKED"] =
True
2379 if numpy.isfinite(self.config.serialOverscanMedianShiftSigmaThreshold)
or \
2380 numpy.isfinite(self.config.ampNoiseThreshold):
2385 parallelOverscans =
None
2386 if overscanDetectorConfig.doAnyParallelOverscan:
2390 overscanDetectorConfig,
2398 if self.config.doLinearize:
2399 self.log.info(
"Applying linearizer.")
2403 if exposureMetadata[
"LSST ISR UNITS"] ==
"electron":
2404 linearityGains = gains
2406 linearityGains =
None
2407 linearizer.applyLinearity(
2408 image=ccdExposure.image,
2411 gains=linearityGains,
2413 ccdExposure.metadata[
"LSST ISR LINEARIZER APPLIED"] =
True
2418 if self.config.doDeferredCharge:
2419 if self.config.doBootstrap:
2420 self.log.info(
"Applying deferred charge correction with doBootstrap=True: "
2421 "will need to use deferredChargeCalib.inputGain to apply "
2422 "CTI correction in electron units.")
2423 deferredChargeGains = deferredChargeCalib.inputGain
2424 if numpy.all(numpy.isnan(list(deferredChargeGains.values()))):
2425 self.log.warning(
"All gains contained in the deferredChargeCalib are "
2426 "NaN, approximating with gain of 1.0.")
2427 deferredChargeGains = gains
2429 deferredChargeGains = gains
2430 self.deferredChargeCorrection.run(
2432 deferredChargeCalib,
2433 gains=deferredChargeGains,
2435 ccdExposure.metadata[
"LSST ISR CTI APPLIED"] =
True
2439 untrimmedCcdExposure =
None
2440 if self.config.isrStats.doCtiStatistics:
2441 untrimmedCcdExposure = ccdExposure.clone()
2445 if self.config.doAssembleCcd:
2446 self.log.info(
"Assembling CCD from amplifiers.")
2447 ccdExposure = self.assembleCcd.assembleCcd(ccdExposure)
2449 if self.config.expectWcs
and not ccdExposure.getWcs():
2450 self.log.warning(
"No WCS found in input exposure.")
2453 if self.config.doE2VEdgeBleedMask
and detector.getPhysicalType() ==
"E2V":
2454 isrFunctions.maskE2VEdgeBleed(
2455 exposure=ccdExposure,
2456 e2vEdgeBleedSatMinArea=self.config.e2vEdgeBleedSatMinArea,
2457 e2vEdgeBleedSatMaxArea=self.config.e2vEdgeBleedSatMaxArea,
2458 e2vEdgeBleedYMax=self.config.e2vEdgeBleedYMax,
2459 saturatedMaskName=self.config.saturatedMaskName,
2464 for maskPlane
in self.config.itlDipMaskPlanes:
2465 if maskPlane
not in ccdExposure.mask.getMaskPlaneDict():
2466 self.log.info(
"Adding %s mask plane to image.", maskPlane)
2467 ccdExposure.mask.addMaskPlane(maskPlane)
2469 if self.config.doITLDipMask:
2470 isrFunctions.maskITLDip(
2471 exposure=ccdExposure,
2472 detectorConfig=overscanDetectorConfig,
2474 maskPlaneNames=self.config.itlDipMaskPlanes,
2477 if (self.config.doITLSatSagMask
or self.config.doITLEdgeBleedMask) \
2478 and detector.getPhysicalType() ==
'ITL':
2480 badAmpDict=badAmpDict)
2484 if self.config.doBias:
2485 self.log.info(
"Applying bias correction.")
2488 isrFunctions.biasCorrection(ccdExposure.maskedImage, bias.maskedImage)
2489 ccdExposure.metadata[
"LSST ISR BIAS APPLIED"] =
True
2493 if self.config.doDark:
2494 self.log.info(
"Applying dark subtraction.")
2498 ccdExposure.metadata[
"LSST ISR DARK APPLIED"] =
True
2504 if self.config.doDefect:
2505 self.log.info(
"Applying defect masking.")
2507 ccdExposure.metadata[
"LSST ISR DEFECTS APPLIED"] =
True
2509 self.log.info(
"Adding UNMASKEDNAN mask plane to image.")
2510 ccdExposure.mask.addMaskPlane(
"UNMASKEDNAN")
2511 if self.config.doNanMasking:
2512 self.log.info(
"Masking non-finite (NAN, inf) value pixels.")
2515 if self.config.doWidenSaturationTrails:
2516 self.log.info(
"Widening saturation trails.")
2517 isrFunctions.widenSaturationTrails(ccdExposure.getMaskedImage().getMask())
2521 if self.config.doBrighterFatter:
2522 if self.config.brighterFatterCorrectionMethod ==
"ASTIER23":
2524 self.log.info(
"Applying electrostatic brighter-fatter "
2526 bfCalib = electroBfDistortionMatrix
2527 bfGains = electroBfDistortionMatrix.gain
2529 elif self.config.brighterFatterCorrectionMethod ==
"COULTON18":
2531 self.log.info(
"Applying brighter-fatter correction.")
2536 elif self.config.brighterFatterCorrectionMethod ==
"COULTON18_FLUX_CONSERVING":
2543 raise RuntimeError(
"Cannot perform brighter-fatter correction with unknown"
2548 if exposureMetadata[
"LSST ISR UNITS"] ==
"electron":
2549 brighterFatterApplyGain =
False
2551 brighterFatterApplyGain =
True
2553 if brighterFatterApplyGain
and (ptc
is not None)
and (bfGains != gains):
2560 self.log.warning(
"Need to apply gain for brighter-fatter, but the stored"
2561 "gains in the kernel are not the same as the gains used"
2562 f
"by {self.config.useGainsFrom}. Using the gains stored"
2566 ccdExposure = bfCorrFunction(
2571 brighterFatterApplyGain,
2575 ccdExposure.metadata[
"LSST ISR BF APPLIED"] =
True
2576 ccdExposure.metadata[
"LSST ISR BF CORR METHOD"] = self.config.brighterFatterCorrectionMethod
2580 if self.config.doVariance:
2587 if self.config.doFlat:
2588 self.log.info(
"Applying flat correction.")
2589 isrFunctions.flatCorrection(
2590 maskedImage=ccdExposure.maskedImage,
2591 flatMaskedImage=flat.maskedImage,
2592 scalingType=self.config.flatScalingType,
2593 userScale=self.config.flatUserScale,
2600 if (validPolygon := flat.info.getValidPolygon())
is not None:
2601 ccdExposure.info.setValidPolygon(validPolygon)
2603 noData = (ccdExposure.mask.array & ccdExposure.mask.getPlaneBitMask(
"NO_DATA")) > 0
2604 ccdExposure.image.array[noData] = 0.0
2605 ccdExposure.variance.array[noData] = 0.0
2607 ccdExposure.metadata[
"LSST ISR FLAT APPLIED"] =
True
2608 ccdExposure.metadata[
"LSST ISR FLAT SOURCE"] = flat.metadata.get(
"FLATSRC",
"UNKNOWN")
2612 if self.config.doSaveInterpPixels:
2613 preInterpExp = ccdExposure.clone()
2615 if self.config.doSetBadRegions:
2616 self.log.info(
'Setting values in large contiguous bad regions.')
2619 if self.config.doInterpolate:
2620 self.log.info(
"Interpolating masked pixels.")
2621 isrFunctions.interpolateFromMask(
2622 maskedImage=ccdExposure.getMaskedImage(),
2623 fwhm=self.config.brighterFatterFwhmForInterpolation,
2624 growSaturatedFootprints=self.config.growSaturationFootprintSize,
2625 maskNameList=list(self.config.maskListToInterpolate),
2626 useLegacyInterp=self.config.useLegacyInterp,
2630 if self.config.doAmpOffset:
2631 if self.config.ampOffset.doApplyAmpOffset:
2632 self.log.info(
"Measuring and applying amp offset corrections.")
2634 self.log.info(
"Measuring amp offset corrections only, without applying them.")
2635 self.ampOffset.run(ccdExposure)
2638 if self.config.doStandardStatistics:
2639 metadata = ccdExposure.metadata
2640 for amp
in detector:
2641 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
2642 ampName = amp.getName()
2643 metadata[f
"LSST ISR MASK SAT {ampName}"] = isrFunctions.countMaskedPixels(
2644 ampExposure.getMaskedImage(),
2645 [self.config.saturatedMaskName]
2647 metadata[f
"LSST ISR MASK BAD {ampName}"] = isrFunctions.countMaskedPixels(
2648 ampExposure.getMaskedImage(),
2651 metadata[f
"LSST ISR MASK SUSPECT {ampName}"] = isrFunctions.countMaskedPixels(
2652 ampExposure.getMaskedImage(),
2656 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP)
2658 metadata[f
"LSST ISR FINAL MEAN {ampName}"] = qaStats.getValue(afwMath.MEAN)
2659 metadata[f
"LSST ISR FINAL MEDIAN {ampName}"] = qaStats.getValue(afwMath.MEDIAN)
2660 metadata[f
"LSST ISR FINAL STDEV {ampName}"] = qaStats.getValue(afwMath.STDEVCLIP)
2662 k1 = f
"LSST ISR FINAL MEDIAN {ampName}"
2663 k2 = f
"LSST ISR OVERSCAN SERIAL MEDIAN {ampName}"
2664 if overscanDetectorConfig.doAnySerialOverscan
and k1
in metadata
and k2
in metadata:
2665 metadata[f
"LSST ISR LEVEL {ampName}"] = metadata[k1] - metadata[k2]
2667 metadata[f
"LSST ISR LEVEL {ampName}"] = numpy.nan
2670 outputStatistics =
None
2671 if self.config.doCalculateStatistics:
2672 outputStatistics = self.isrStats.run(ccdExposure,
2673 untrimmedInputExposure=untrimmedCcdExposure,
2674 serialOverscanResults=serialOverscans,
2675 parallelOverscanResults=parallelOverscans,
2676 bias=bias, dark=dark, flat=flat,
2677 ptc=ptc, defects=defects).results
2680 outputBin1Exposure =
None
2681 outputBin2Exposure =
None
2682 if self.config.doBinnedExposures:
2683 self.log.info(
"Creating binned exposures.")
2684 outputBin1Exposure = self.binning.run(
2686 binFactor=self.config.binFactor1,
2688 outputBin2Exposure = self.binning.run(
2690 binFactor=self.config.binFactor2,
2693 return pipeBase.Struct(
2694 exposure=ccdExposure,
2696 outputBin1Exposure=outputBin1Exposure,
2697 outputBin2Exposure=outputBin2Exposure,
2699 preInterpExposure=preInterpExp,
2700 outputExposure=ccdExposure,
2701 outputStatistics=outputStatistics,