613 for amp, overscanResults
in zip(ccd, overscans):
614 if ccdExposure.getBBox().contains(amp.getBBox()):
615 self.log.debug(
"Constructing variance map for amplifer %s.", amp.getName())
616 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
620 if self.config.qa
is not None and self.config.qa.saveStats
is True:
621 qaStats = afwMath.makeStatistics(ampExposure.getVariance(),
622 afwMath.MEDIAN | afwMath.STDEVCLIP)
623 self.log.debug(
" Variance stats for amplifer %s: %f +/- %f.",
624 amp.getName(), qaStats.getValue(afwMath.MEDIAN),
625 qaStats.getValue(afwMath.STDEVCLIP))
626 if self.config.maskNegativeVariance:
792 interpExp = ccdExposure.clone()
794 isrFunctions.interpolateFromMask(
795 maskedImage=interpExp.getMaskedImage(),
796 fwhm=self.config.brighterFatterFwhmForInterpolation,
797 growSaturatedFootprints=self.config.growSaturationFootprintSize,
798 maskNameList=list(self.config.brighterFatterMaskListToInterpolate)
800 bfExp = interpExp.clone()
801 self.log.info(
"Applying brighter-fatter correction using kernel type %s / gains %s.",
802 type(bfKernel), type(bfGains))
803 bfResults = isrFunctions.brighterFatterCorrection(bfExp, bfKernel,
804 self.config.brighterFatterMaxIter,
805 self.config.brighterFatterThreshold,
806 self.config.brighterFatterApplyGain,
808 if bfResults[1] == self.config.brighterFatterMaxIter:
809 self.log.warning(
"Brighter-fatter correction did not converge, final difference %f.",
812 self.log.info(
"Finished brighter-fatter correction in %d iterations.",
815 image = ccdExposure.getMaskedImage().getImage()
816 bfCorr = bfExp.getMaskedImage().getImage()
817 bfCorr -= interpExp.getMaskedImage().getImage()
826 self.log.info(
"Ensuring image edges are masked as EDGE to the brighter-fatter kernel size.")
827 self.
maskEdges(ccdExposure, numEdgePixels=numpy.max(bfKernel.shape) // 2,
830 if self.config.brighterFatterMaskGrowSize > 0:
831 self.log.info(
"Growing masks to account for brighter-fatter kernel convolution.")
832 for maskPlane
in self.config.brighterFatterMaskListToInterpolate:
833 isrFunctions.growMasks(ccdExposure.getMask(),
834 radius=self.config.brighterFatterMaskGrowSize,
835 maskNameList=maskPlane,
948 def run(self, *, ccdExposure, dnlLUT=None, bias=None, deferredChargeCalib=None, linearizer=None,
949 ptc=None, crosstalk=None, defects=None, bfKernel=None, bfGains=None, dark=None,
953 detector = ccdExposure.getDetector()
955 if self.config.doHeaderProvenance:
958 exposureMetadata = ccdExposure.getMetadata()
960 if self.config.doDiffNonLinearCorrection:
962 if self.config.doBias:
964 if self.config.doDeferredCharge:
965 exposureMetadata[
"LSST CALIB DATE CTI"] = self.
extractCalibDate(deferredChargeCalib)
967 exposureMetadata[
"LSST CALIB DATE LINEARIZER"] = self.
extractCalibDate(linearizer)
968 if self.config.doCrosstalk:
969 exposureMetadata[
"LSST CALIB DATE CROSSTALK"] = self.
extractCalibDate(crosstalk)
970 if self.config.doDefect:
971 exposureMetadata[
"LSST CALIB DATE DEFECTS"] = self.
extractCalibDate(defects)
972 if self.config.doBrighterFatter:
974 if self.config.doDark:
977 if self.config.doDiffNonLinearCorrection:
980 if self.config.doOverscan:
984 if self.config.doAssembleCcd:
986 self.log.info(
"Assembling CCD from amplifiers.")
987 ccdExposure = self.assembleCcd.assembleCcd(ccdExposure)
989 if self.config.expectWcs
and not ccdExposure.getWcs():
990 self.log.warning(
"No WCS found in input exposure.")
992 if self.config.doBias:
994 self.log.info(
"Applying bias correction.")
995 isrFunctions.biasCorrection(ccdExposure.getMaskedImage(), bias.getMaskedImage())
997 if self.config.doDeferredCharge:
999 self.log.info(
"Applying deferred charge/CTI correction.")
1000 self.deferredChargeCorrection.
run(ccdExposure, deferredChargeCalib)
1002 if self.config.doLinearize:
1004 self.log.info(
"Applying linearizer.")
1006 linearizer.applyLinearity(image=ccdExposure.getMaskedImage().getImage(),
1007 detector=detector, log=self.log)
1009 if self.config.doGainNormalize:
1015 if self.config.doVariance:
1019 if self.config.doCrosstalk:
1021 self.log.info(
"Applying crosstalk correction.")
1022 self.crosstalk.
run(ccdExposure, crosstalk=crosstalk)
1026 if self.config.doDefect:
1028 self.log.info(
"Applying defects masking.")
1031 if self.config.doNanMasking:
1032 self.log.info(
"Masking non-finite (NAN, inf) value pixels.")
1035 if self.config.doWidenSaturationTrails:
1036 self.log.info(
"Widening saturation trails.")
1037 isrFunctions.widenSaturationTrails(ccdExposure.getMaskedImage().getMask())
1040 if self.config.doSaveInterpPixels:
1041 preInterpExp = ccdExposure.clone()
1043 if self.config.doSetBadRegions:
1044 self.log.info(
'Counting pixels in BAD regions.')
1047 if self.config.doInterpolate:
1048 self.log.info(
"Interpolating masked pixels.")
1049 isrFunctions.interpolateFromMask(
1050 maskedImage=ccdExposure.getMaskedImage(),
1051 fwhm=self.config.brighterFatterFwhmForInterpolation,
1052 growSaturatedFootprints=self.config.growSaturationFootprintSize,
1053 maskNameList=list(self.config.maskListToInterpolate)
1056 if self.config.doBrighterFatter:
1058 self.log.info(
"Applying Bright-Fatter kernels.")
1062 if self.config.doDark:
1064 self.log.info(
"Applying dark subtraction.")
1068 if self.config.doStandardStatistics:
1069 metadata = ccdExposure.getMetadata()
1070 for amp
in detector:
1071 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1072 ampName = amp.getName()
1073 metadata[f
"LSST ISR MASK SAT {ampName}"] = isrFunctions.countMaskedPixels(
1074 ampExposure.getMaskedImage(),
1075 [self.config.saturatedMaskName]
1077 metadata[f
"LSST ISR MASK BAD {ampName}"] = isrFunctions.countMaskedPixels(
1078 ampExposure.getMaskedImage(),
1081 qaStats = afwMath.makeStatistics(ampExposure.getImage(),
1082 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP)
1084 metadata[f
"LSST ISR FINAL MEAN {ampName}"] = qaStats.getValue(afwMath.MEAN)
1085 metadata[f
"LSST ISR FINAL MEDIAN {ampName}"] = qaStats.getValue(afwMath.MEDIAN)
1086 metadata[f
"LSST ISR FINAL STDEV {ampName}"] = qaStats.getValue(afwMath.STDEVCLIP)
1088 k1 = f
"LSST ISR FINAL MEDIAN {ampName}"
1089 k2 = f
"LSST ISR OVERSCAN SERIAL MEDIAN {ampName}"
1090 if self.config.doOverscan
and k1
in metadata
and k2
in metadata:
1091 metadata[f
"LSST ISR LEVEL {ampName}"] = metadata[k1] - metadata[k2]
1093 metadata[f
"LSST ISR LEVEL {ampName}"] = numpy.nan
1096 outputStatistics =
None
1097 if self.config.doCalculateStatistics:
1098 outputStatistics = self.isrStats.
run(ccdExposure, overscanResults=overscans,
1102 outputBin1Exposure =
None
1103 outputBin2Exposure =
None
1104 if self.config.doBinnedExposures:
1105 outputBin1Exposure, outputBin2Exposure = self.
makeBinnedImages(ccdExposure)
1107 return pipeBase.Struct(
1108 exposure=ccdExposure,
1110 outputBin1Exposure=outputBin1Exposure,
1111 outputBin2Exposure=outputBin2Exposure,
1113 preInterpExposure=preInterpExp,
1114 outputExposure=ccdExposure,
1115 outputStatistics=outputStatistics,