460 def runDataRef(self, dataRef, visitPairs):
461 """Run the brighter-fatter measurement task.
463 For a dataRef (which is each detector here),
464 and given a list of visit pairs, calculate the
465 brighter-fatter kernel for the detector.
469 dataRef : `list` of `lsst.daf.persistence.ButlerDataRef`
470 dataRef for the detector for the visits to be fit.
471 visitPairs : `iterable` of `tuple` of `int`
472 Pairs of visit numbers to be processed together
482 detNum = dataRef.dataId[self.config.ccdKey]
483 detector = dataRef.get(
'camera')[dataRef.dataId[self.config.ccdKey]]
484 amps = detector.getAmplifiers()
485 ampNames = [amp.getName()
for amp
in amps]
487 if self.config.level ==
'DETECTOR':
488 kernels = {detNum: []}
490 xcorrs = {detNum: []}
491 meanXcorrs = {detNum: []}
492 elif self.config.level ==
'AMP':
493 kernels = {key: []
for key
in ampNames}
494 means = {key: []
for key
in ampNames}
495 xcorrs = {key: []
for key
in ampNames}
496 meanXcorrs = {key: []
for key
in ampNames}
498 raise RuntimeError(
"Unsupported level: {}".
format(self.config.level))
501 if not self.config.doCalcGains:
504 deleteMe = dataRef.get(
'photonTransferCurveDataset')
505 except butlerExceptions.NoResults:
507 deleteMe = dataRef.get(
'brighterFatterGain')
508 except butlerExceptions.NoResults:
511 raise RuntimeError(
"doCalcGains == False and gains could not be got from butler")
from None
519 if self.config.level ==
'DETECTOR':
520 if self.config.doCalcGains:
521 self.log.
info(
'Computing gains for detector %s' % detNum)
522 gains, nomGains = self.estimateGains(dataRef, visitPairs)
523 dataRef.put(gains, datasetType=
'brighterFatterGain')
524 self.log.
debug(
'Finished gain estimation for detector %s' % detNum)
526 gains = dataRef.get(
'brighterFatterGain')
528 raise RuntimeError(
'Failed to retrieved gains for detector %s' % detNum)
529 self.log.
info(
'Retrieved stored gain for detector %s' % detNum)
530 self.log.
debug(
'Detector %s has gains %s' % (detNum, gains))
532 gains = BrighterFatterGain({}, {})
533 for ampName
in ampNames:
534 gains.gains[ampName] = 1.0
536 ptcConfig = MeasurePhotonTransferCurveTaskConfig()
537 ptcConfig.isrForbiddenSteps = []
538 ptcConfig.doFitBootstrap =
True
539 ptcConfig.ptcFitType =
'POLYNOMIAL'
540 ptcConfig.polynomialFitDegree = 3
541 ptcConfig.minMeanSignal = self.config.minMeanSignal
542 ptcConfig.maxMeanSignal = self.config.maxMeanSignal
543 ptcTask = MeasurePhotonTransferCurveTask(config=ptcConfig)
544 ptcDataset = PhotonTransferCurveDataset(ampNames)
548 for (v1, v2)
in visitPairs:
549 dataRef.dataId[
'expId'] = v1
550 exp1 = self.isr.runDataRef(dataRef).exposure
551 dataRef.dataId[
'expId'] = v2
552 exp2 = self.isr.runDataRef(dataRef).exposure
553 del dataRef.dataId[
'expId']
556 self.log.
info(
'Preparing images for cross-correlation calculation for detector %s' % detNum)
558 _scaledMaskedIms1, _means1 = self._makeCroppedExposures(exp1, gains, self.config.level)
559 _scaledMaskedIms2, _means2 = self._makeCroppedExposures(exp2, gains, self.config.level)
566 for det_object
in _scaledMaskedIms1.keys():
567 self.log.
debug(
"Calculating correlations for %s" % det_object)
568 _xcorr, _mean = self._crossCorrelate(_scaledMaskedIms1[det_object],
569 _scaledMaskedIms2[det_object])
570 xcorrs[det_object].
append(_xcorr)
571 means[det_object].
append([_means1[det_object], _means2[det_object]])
572 if self.config.level !=
'DETECTOR':
574 expTime = exp1.getInfo().getVisitInfo().getExposureTime()
575 ptcDataset.rawExpTimes[det_object].
append(expTime)
576 ptcDataset.rawMeans[det_object].
append((_means1[det_object] + _means2[det_object]) / 2.0)
577 ptcDataset.rawVars[det_object].
append(_xcorr[0, 0] / 2.0)
583 rawMeans = copy.deepcopy(means)
584 rawXcorrs = copy.deepcopy(xcorrs)
589 if self.config.level !=
'DETECTOR':
590 if self.config.doCalcGains:
591 self.log.
info(
'Calculating gains for detector %s using PTC task' % detNum)
592 ptcDataset = ptcTask.fitPtc(ptcDataset, ptcConfig.ptcFitType)
593 dataRef.put(ptcDataset, datasetType=
'photonTransferCurveDataset')
594 self.log.
debug(
'Finished gain estimation for detector %s' % detNum)
596 ptcDataset = dataRef.get(
'photonTransferCurveDataset')
598 self._applyGains(means, xcorrs, ptcDataset)
600 if self.config.doPlotPtcs:
601 dirname = dataRef.getUri(datasetType=
'cpPipePlotRoot', write=
True)
602 if not os.path.exists(dirname):
604 detNum = dataRef.dataId[self.config.ccdKey]
605 filename = f
"PTC_det{detNum}.pdf"
606 filenameFull = os.path.join(dirname, filename)
607 with PdfPages(filenameFull)
as pdfPages:
608 ptcTask._plotPtc(ptcDataset, ptcConfig.ptcFitType, pdfPages)
612 self.log.
info(
'Generating kernel(s) for %s' % detNum)
613 for det_object
in xcorrs.keys():
614 if self.config.level ==
'DETECTOR':
615 objId =
'detector %s' % det_object
616 elif self.config.level ==
'AMP':
617 objId =
'detector %s AMP %s' % (detNum, det_object)
620 meanXcorr, kernel = self.generateKernel(xcorrs[det_object], means[det_object], objId)
621 kernels[det_object] = kernel
622 meanXcorrs[det_object] = meanXcorr
625 self.log.
warn(
'RuntimeError during kernel generation for %s' % objId)
628 bfKernel = BrighterFatterKernel(self.config.level)
629 bfKernel.means = means
630 bfKernel.rawMeans = rawMeans
631 bfKernel.rawXcorrs = rawXcorrs
632 bfKernel.xCorrs = xcorrs
633 bfKernel.meanXcorrs = meanXcorrs
634 bfKernel.originalLevel = self.config.level
636 bfKernel.gain = ptcDataset.gain
637 bfKernel.gainErr = ptcDataset.gainErr
638 bfKernel.noise = ptcDataset.noise
639 bfKernel.noiseErr = ptcDataset.noiseErr
643 if self.config.level ==
'AMP':
644 bfKernel.ampwiseKernels = kernels
645 ex = self.config.ignoreAmpsForAveraging
646 bfKernel.detectorKernel = bfKernel.makeDetectorKernelFromAmpwiseKernels(detNum, ampsToExclude=ex)
648 elif self.config.level ==
'DETECTOR':
649 bfKernel.detectorKernel = kernels
651 raise RuntimeError(
'Invalid level for kernel calculation; this should not be possible.')
653 dataRef.put(bfKernel)
655 self.log.
info(
'Finished generating kernel(s) for %s' % detNum)
656 return pipeBase.Struct(exitStatus=0)
def checkExpLengthEqual(exp1, exp2, v1=None, v2=None, raiseWithMessage=False)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)