28import lsst.meas.algorithms
as measAlg
32from lsst.utils.timer
import timeMethod
34from .imageMapReduce
import (ImageMapReduceConfig, ImageMapReduceTask,
36from .utils
import computeAveragePsf
38__all__ = (
"DecorrelateALKernelTask",
"DecorrelateALKernelConfig",
39 "DecorrelateALKernelMapper",
"DecorrelateALKernelMapReduceConfig",
40 "DecorrelateALKernelSpatialConfig",
"DecorrelateALKernelSpatialTask")
44 """Configuration parameters for the DecorrelateALKernelTask
47 ignoreMaskPlanes = pexConfig.ListField(
49 doc="""Mask planes to ignore for sigma-clipped statistics""",
50 default=(
"INTRP",
"EDGE",
"DETECTED",
"SAT",
"CR",
"BAD",
"NO_DATA",
"DETECTED_NEGATIVE")
52 completeVarPlanePropagation = pexConfig.Field(
55 doc=
"Compute the full effect of the decorrelated matching kernel on the variance plane."
56 " Otherwise use a model weighed sum of the input variances."
61 """Decorrelate the effect of convolution by Alard-Lupton matching kernel in image difference
64 ConfigClass = DecorrelateALKernelConfig
65 _DefaultName = "ip_diffim_decorrelateALKernel"
68 """Create the image decorrelation Task
73 arguments to be passed to ``lsst.pipe.base.task.Task.__init__``
75 keyword arguments to be passed to ``lsst.pipe.base.task.Task.__init__``
77 pipeBase.Task.__init__(self, *args, **kwargs)
82 self.statsControl.setAndMask(afwImage.Mask.getPlaneBitMask(self.config.ignoreMaskPlanes))
88 var = statObj.getValue(afwMath.MEANCLIP)
92 def run(self, scienceExposure, templateExposure, subtractedExposure, psfMatchingKernel,
93 preConvKernel=None, xcen=None, ycen=None, svar=None, tvar=None,
94 templateMatched=True, preConvMode=False, **kwargs):
95 """Perform decorrelation of an image difference or of a score difference exposure.
97 Corrects the difference or score image due to the convolution of the
98 templateExposure
with the A&L PSF matching kernel.
99 See [DMTN-021, Equation 1](http://dmtn-021.lsst.io/
100 [DMTN-179](http://dmtn-179.lsst.io/)
for details.
105 The original science exposure (before pre-convolution,
if ``preConvMode==
True``).
107 The original template exposure warped, but
not psf-matched, to the science exposure.
109 the subtracted exposure produced by
110 `ip_diffim.ImagePsfMatchTask.subtractExposures()`. The `subtractedExposure` must
111 inherit its PSF
from `exposure`, see notes below.
113 An (optionally spatially-varying) PSF matching kernel produced
114 by `ip_diffim.ImagePsfMatchTask.subtractExposures()`.
116 If
not `
None`, then the `scienceExposure` was pre-convolved
with (the reflection of)
117 this kernel. Must be normalized to sum to 1.
118 Allowed only
if ``templateMatched==
True``
and ``preConvMode==
True``.
119 Defaults to the PSF of the science exposure at the image center.
120 xcen : `float`, optional
121 X-pixel coordinate to use
for computing constant matching kernel to use
122 If `
None` (default), then use the center of the image.
123 ycen : `float`, optional
124 Y-pixel coordinate to use
for computing constant matching kernel to use
125 If `
None` (default), then use the center of the image.
126 svar : `float`, optional
127 Image variance
for science image
128 If `
None` (default) then compute the variance over the entire input science image.
129 tvar : `float`, optional
130 Image variance
for template image
131 If `
None` (default) then compute the variance over the entire input template image.
132 templateMatched : `bool`, optional
133 If
True, the template exposure was matched (convolved) to the science exposure.
134 See also notes below.
135 preConvMode : `bool`, optional
136 If
True, ``subtractedExposure``
is assumed to be a likelihood difference image
137 and will be noise corrected
as a likelihood image.
139 Additional keyword arguments propagated
from DecorrelateALKernelSpatialTask.
143 result : `lsst.pipe.base.Struct`
144 - ``correctedExposure`` : the decorrelated diffim
148 If ``preConvMode==
True``, ``subtractedExposure``
is assumed to be a
149 score image
and the noise correction
for likelihood images
150 is applied. The resulting image
is an optimal detection likelihood image
151 when the templateExposure has noise. (See DMTN-179) If ``preConvKernel``
is
152 not specified, the PSF of ``scienceExposure``
is assumed
as pre-convolution kernel.
154 The ``subtractedExposure``
is NOT updated. The returned ``correctedExposure``
155 has an updated but spatially fixed PSF. It
is calculated
as the center of
156 image PSF corrected by the center of image matching kernel.
158 If ``templateMatched==
True``, the templateExposure was matched (convolved)
159 to the ``scienceExposure`` by ``psfMatchingKernel`` during image differencing.
160 Otherwise the ``scienceExposure`` was matched (convolved) by ``psfMatchingKernel``.
161 In either case, note that the original template
and science images are required,
162 not the psf-matched version.
164 This task discards the variance plane of ``subtractedExposure``
and re-computes
165 it
from the variance planes of ``scienceExposure``
and ``templateExposure``.
166 The image plane of ``subtractedExposure`` must be at the photometric level
167 set by the AL PSF matching
in `ImagePsfMatchTask.subtractExposures`.
168 The assumptions about the photometric level are controlled by the
169 `templateMatched` option
in this task.
171 Here we currently convert a spatially-varying matching kernel into a constant kernel,
172 just by computing it at the center of the image (tickets DM-6243, DM-6244).
174 We are also using a constant accross-the-image measure of sigma (sqrt(variance)) to compute
175 the decorrelation kernel.
177 TODO DM-23857 As part of the spatially varying correction implementation
178 consider whether returning a Struct
is still necessary.
180 if preConvKernel
is not None and not (templateMatched
and preConvMode):
181 raise ValueError(
"Pre-convolution kernel is allowed only if "
182 "preConvMode==True and templateMatched==True.")
184 spatialKernel = psfMatchingKernel
185 kimg = afwImage.ImageD(spatialKernel.getDimensions())
186 bbox = subtractedExposure.getBBox()
188 xcen = (bbox.getBeginX() + bbox.getEndX()) / 2.
190 ycen = (bbox.getBeginY() + bbox.getEndY()) / 2.
191 self.log.info(
"Using matching kernel computed at (%d, %d)", xcen, ycen)
192 spatialKernel.computeImage(kimg,
False, xcen, ycen)
196 if preConvKernel
is None:
197 pos = scienceExposure.getPsf().getAveragePosition()
198 preConvKernel = scienceExposure.getPsf().getLocalKernel(pos)
199 preConvImg = afwImage.ImageD(preConvKernel.getDimensions())
200 preConvKernel.computeImage(preConvImg,
True)
206 self.log.info(
"Original variance plane means. Science:%.5e, warped template:%.5e)",
212 if np.isnan(svar)
or np.isnan(tvar):
214 if (np.all(np.isnan(scienceExposure.image.array))
215 or np.all(np.isnan(templateExposure.image.array))):
216 self.log.warning(
'Template or science image is entirely NaNs: skipping decorrelation.')
217 outExposure = subtractedExposure.clone()
218 return pipeBase.Struct(correctedExposure=outExposure, )
222 self.log.info(
"Decorrelation after template image convolution")
224 targetVarianceMean = tvar
226 variance = scienceExposure.variance.array
228 targetVariance = templateExposure.variance.array
231 psfImg = scienceExposure.getPsf().computeKernelImage(
geom.Point2D(xcen, ycen))
234 self.log.info(
"Decorrelation after science image convolution")
236 targetVarianceMean = svar
238 variance = templateExposure.variance.array
240 targetVariance = scienceExposure.variance.array
247 psfImg = templateExposure.getPsf().computeKernelImage(
geom.Point2D(xcen, ycen))
248 except InvalidParameterError:
249 psfImg = computeAveragePsf(templateExposure, psfExposureBuffer=0.05, psfExposureGrid=100)
253 mOverExpVar = targetVarianceMean/varianceMean
254 if mOverExpVar > 1e8:
255 self.log.warning(
"Diverging correction: matched image variance is "
256 " much larger than the unconvolved one's"
257 ", targetVarianceMean/varianceMean:%.2e", mOverExpVar)
260 self.log.info(
"Variance plane mean of uncorrected diffim: %f", oldVarMean)
263 diffimShape = subtractedExposure.image.array.shape
264 psfShape = psfImg.array.shape
267 self.log.info(
"Decorrelation of likelihood image")
269 psfShape, diffimShape)
272 self.log.info(
"Decorrelation of difference image")
282 if self.config.completeVarPlanePropagation:
283 self.log.debug(
"Using full variance plane calculation in decorrelation")
285 variance, targetVariance,
286 varianceMean, targetVarianceMean, corr.cnft, corr.crft)
288 self.log.debug(
"Using estimated variance plane calculation in decorrelation")
290 variance, targetVariance,
291 corr.cnft, corr.crft)
296 self.log.debug(
"Matching kernel sum: %.3e", kSum)
297 if not templateMatched:
300 correctedVariance /= kSumSq
301 subtractedExposure.image.array[...] = correctedImage
302 subtractedExposure.variance.array[...] = correctedVariance
303 subtractedExposure.setPsf(correctedPsf)
306 self.log.info(
"Variance plane mean of corrected diffim: %.5e", newVarMean)
310 return pipeBase.Struct(correctedExposure=subtractedExposure, )
313 """Calculate the common shape for FFT operations. Set `self.freqSpaceShape`
318 shapes : one or more `tuple` of `int`
319 Shapes of the arrays. All must have the same dimensionality.
320 At least one shape must be provided.
328 For each dimension, gets the smallest even number greater than
or equal to
329 `N1+N2-1` where `N1`
and `N2` are the two largest values.
330 In case of only one shape given, rounds up to even each dimension value.
332 S = np.array(shapes, dtype=int)
337 commonShape = np.sum(S, axis=0) - 1
340 commonShape[commonShape % 2 != 0] += 1
342 self.log.info(
"Common frequency space shape %s", self.
freqSpaceShape)
346 """Zero pad an image where the origin is at the center and replace the
347 origin to the corner as required by the periodic input of FFT. Implement also
348 the inverse operation, crop the padding
and re-center data.
353 An array to copy
from.
354 newShape : `tuple` of `int`
355 The dimensions of the resulting array. For padding, the resulting array
356 must be larger than A
in each dimension. For the inverse operation this
357 must be the original, before padding size of the array.
358 useInverse : bool, optional
359 Selector of forward, add padding, operation (
False)
360 or its inverse, crop padding, operation (
True).
365 The padded
or unpadded array
with shape of `newShape`
and the same dtype
as A.
369 For odd dimensions, the splitting
is rounded to
370 put the center pixel into the new corner origin (0,0). This
is to be consistent
371 e.g.
for a dirac delta kernel that
is originally located at the center pixel.
378 firstHalves = [x//2
for x
in A.shape]
379 secondHalves = [x-y
for x, y
in zip(A.shape, firstHalves)]
382 secondHalves = [x//2
for x
in newShape]
383 firstHalves = [x-y
for x, y
in zip(newShape, secondHalves)]
385 R = np.zeros_like(A, shape=newShape)
386 R[-firstHalves[0]:, -firstHalves[1]:] = A[:firstHalves[0], :firstHalves[1]]
387 R[:secondHalves[0], -firstHalves[1]:] = A[-secondHalves[0]:, :firstHalves[1]]
388 R[:secondHalves[0], :secondHalves[1]] = A[-secondHalves[0]:, -secondHalves[1]:]
389 R[-firstHalves[0]:, :secondHalves[1]] = A[:firstHalves[0], -secondHalves[1]:]
393 """Compute the Lupton decorrelation post-convolution kernel for decorrelating an
394 image difference, based on the PSF-matching kernel.
398 kappa : `numpy.ndarray` of `float`
399 A matching kernel 2-d numpy.array derived from Alard & Lupton PSF matching.
401 Average variance of science image used
for PSF matching.
403 Average variance of the template (matched) image used
for PSF matching.
407 corrft : `numpy.ndarray` of `float`
408 The frequency space representation of the correction. The array
is real (dtype float).
411 cnft, crft : `numpy.ndarray` of `complex`
412 The overall convolution (pre-conv, PSF matching, noise correction) kernel
413 for the science
and template images, respectively
for the variance plane
414 calculations. These are intermediate results
in frequency space.
418 The maximum correction factor converges to `sqrt(tvar/svar)` towards high frequencies.
419 This should be a plausible value.
423 kft = np.fft.fft2(kappa)
424 kftAbsSq = np.real(np.conj(kft) * kft)
426 denom = svar + tvar * kftAbsSq
427 corrft = np.sqrt((svar + tvar * kSum*kSum) / denom)
430 return pipeBase.Struct(corrft=corrft, cnft=cnft, crft=crft)
433 """Compute the correction kernel for a score image.
437 kappa : `numpy.ndarray`
438 A matching kernel 2-d numpy.array derived from Alard & Lupton PSF matching.
440 Average variance of science image used
for PSF matching (before pre-convolution).
442 Average variance of the template (matched) image used
for PSF matching.
443 preConvArr : `numpy.ndarray`
444 The pre-convolution kernel of the science image. It should be the PSF
445 of the science image
or an approximation of it. It must be normed to sum 1.
449 corrft : `numpy.ndarray` of `float`
450 The frequency space representation of the correction. The array
is real (dtype float).
452 cnft, crft : `numpy.ndarray` of `complex`
453 The overall convolution (pre-conv, PSF matching, noise correction) kernel
454 for the science
and template images, respectively
for the variance plane
455 calculations. These are intermediate results
in frequency space.
459 To be precise, the science image should be _correlated_ by ``preConvArray`` but this
460 does
not matter
for this calculation.
462 ``cnft``, ``crft`` contain the scaling factor
as well.
467 kft = np.fft.fft2(kappa)
469 preFt = np.fft.fft2(preConvArr)
470 preFtAbsSq = np.real(np.conj(preFt) * preFt)
471 kftAbsSq = np.real(np.conj(kft) * kft)
474 tiny = np.finfo(preFtAbsSq.dtype).tiny * 1000.
475 flt = preFtAbsSq < tiny
479 preFtAbsSq[flt] = tiny
480 denom = svar + tvar * kftAbsSq / preFtAbsSq
481 corrft = (svar + tvar * kSum*kSum) / denom
482 cnft = np.conj(preFt)*corrft
484 return pipeBase.Struct(corrft=corrft, cnft=cnft, crft=crft)
488 """Estimate the variance planes.
490 The estimation assumes that around each pixel the surrounding
491 pixels' sigmas within the convolution kernel are the same.
495 vplane1, vplane2 : `numpy.ndarray` of `float`
496 Variance planes of the original (before pre-convolution or matching)
498 c1ft, c2ft : `numpy.ndarray` of `complex`
499 The overall convolution that includes the matching
and the
500 afterburner
in frequency space. The result of either
501 ``computeScoreCorrection``
or ``computeDiffimCorrection``.
505 vplaneD : `numpy.ndarray` of `float`
506 The estimated variance plane of the difference/score image
507 as a weighted sum of the input variances.
511 See DMTN-179 Section 5 about the variance plane calculations.
513 w1 = np.sum(np.real(np.conj(c1ft)*c1ft)) / c1ft.size
514 w2 = np.sum(np.real(np.conj(c2ft)*c2ft)) / c2ft.size
517 return vplane1*w1 + vplane2*w2
520 """Full propagation of the variance planes of the original exposures.
522 The original variance planes of independent pixels are convolved with the
523 image space square of the overall kernels.
527 vplane1, vplane2 : `numpy.ndarray` of `float`
528 Variance planes of the original (before pre-convolution
or matching)
530 varMean1, varMean2 : `float`
531 Replacement average values
for non-finite ``vplane1``
and ``vplane2`` values respectively.
533 c1ft, c2ft : `numpy.ndarray` of `complex`
534 The overall convolution that includes the matching
and the
535 afterburner
in frequency space. The result of either
536 ``computeScoreCorrection``
or ``computeDiffimCorrection``.
540 vplaneD : `numpy.ndarray` of `float`
541 The variance plane of the difference/score images.
545 See DMTN-179 Section 5 about the variance plane calculations.
547 Infs
and NaNs are allowed
and kept
in the returned array.
549 D = np.real(np.fft.ifft2(c1ft))
550 c1SqFt = np.fft.fft2(D*D)
552 v1shape = vplane1.shape
553 filtInf = np.isinf(vplane1)
554 filtNan = np.isnan(vplane1)
556 vplane1 = np.copy(vplane1)
557 vplane1[filtInf | filtNan] = varMean1
559 v1 = np.real(np.fft.ifft2(np.fft.fft2(D) * c1SqFt))
564 D = np.real(np.fft.ifft2(c2ft))
565 c2SqFt = np.fft.fft2(D*D)
567 v2shape = vplane2.shape
568 filtInf = np.isinf(vplane2)
569 filtNan = np.isnan(vplane2)
570 vplane2 = np.copy(vplane2)
571 vplane2[filtInf | filtNan] = varMean2
573 v2 = np.real(np.fft.ifft2(np.fft.fft2(D) * c2SqFt))
581 """Compute the (decorrelated) difference image's new PSF.
585 corrft : `numpy.ndarray`
586 The frequency space representation of the correction calculated by
588 psfOld : `numpy.ndarray`
589 The psf of the difference image to be corrected.
593 correctedPsf : `lsst.meas.algorithms.KernelPsf`
594 The corrected psf, same shape as `psfOld`, sum normed to 1.
598 There
is no algorithmic guarantee that the corrected psf can
599 meaningfully fit to the same size
as the original one.
601 psfShape = psfOld.shape
603 psfNew = np.fft.fft2(psfNew)
605 psfNew = np.fft.ifft2(psfNew)
608 psfNew = psfNew/psfNew.sum()
610 psfcI = afwImage.ImageD(
geom.Extent2I(psfShape[1], psfShape[0]))
613 correctedPsf = measAlg.KernelPsf(psfcK)
617 """Compute the decorrelated difference image.
621 corrft : `numpy.ndarray`
622 The frequency space representation of the correction calculated by
624 imgOld : `numpy.ndarray`
625 The difference image to be corrected.
629 imgNew : `numpy.ndarray`
630 The corrected image, same size as the input.
632 expShape = imgOld.shape
633 imgNew = np.copy(imgOld)
634 filtInf = np.isinf(imgNew)
635 filtNan = np.isnan(imgNew)
636 imgNew[filtInf] = np.nan
637 imgNew[filtInf | filtNan] = np.nanmean(imgNew)
639 imgNew = np.fft.fft2(imgNew)
641 imgNew = np.fft.ifft2(imgNew)
644 imgNew[filtNan] = np.nan
645 imgNew[filtInf] = np.inf
650 """Task to be used as an ImageMapper for performing
651 A&L decorrelation on subimages on a grid across a A&L difference image.
653 This task subclasses DecorrelateALKernelTask in order to implement
654 all of that task
's configuration parameters, as well as its `run` method.
657 ConfigClass = DecorrelateALKernelConfig
658 _DefaultName = 'ip_diffim_decorrelateALKernelMapper'
661 DecorrelateALKernelTask.__init__(self, *args, **kwargs)
663 def run(self, subExposure, expandedSubExposure, fullBBox,
664 template, science, alTaskResult=None, psfMatchingKernel=None,
665 preConvKernel=None, **kwargs):
666 """Perform decorrelation operation on `subExposure`, using
667 `expandedSubExposure` to allow for invalid edge pixels arising
from
670 This method performs A&L decorrelation on `subExposure` using
671 local measures
for image variances
and PSF. `subExposure`
is a
672 sub-exposure of the non-decorrelated A&L diffim. It also
673 requires the corresponding sub-exposures of the template
674 (`template`)
and science (`science`) exposures.
679 the sub-exposure of the diffim
681 the expanded sub-exposure upon which to operate
683 the bounding box of the original exposure
685 the corresponding sub-exposure of the template exposure
687 the corresponding sub-exposure of the science exposure
688 alTaskResult : `lsst.pipe.base.Struct`
689 the result of A&L image differencing on `science`
and
690 `template`, importantly containing the resulting
691 `psfMatchingKernel`. Can be `
None`, only
if
692 `psfMatchingKernel`
is not `
None`.
693 psfMatchingKernel : Alternative parameter
for passing the
694 A&L `psfMatchingKernel` directly.
695 preConvKernel : If
not None, then pre-filtering was applied
696 to science exposure,
and this
is the pre-convolution
699 additional keyword arguments propagated
from
700 `ImageMapReduceTask.run`.
704 A `pipeBase.Struct` containing:
706 - ``subExposure`` : the result of the `subExposure` processing.
707 - ``decorrelationKernel`` : the decorrelation kernel, currently
712 This `run` method accepts parameters identical to those of
713 `ImageMapper.run`, since it
is called
from the
714 `ImageMapperTask`. See that
class for more information.
716 templateExposure = template
717 scienceExposure = science
718 if alTaskResult
is None and psfMatchingKernel
is None:
719 raise RuntimeError(
'Both alTaskResult and psfMatchingKernel cannot be None')
720 psfMatchingKernel = alTaskResult.psfMatchingKernel
if alTaskResult
is not None else psfMatchingKernel
724 subExp2 = scienceExposure.Factory(scienceExposure, expandedSubExposure.getBBox())
725 subExp1 = templateExposure.Factory(templateExposure, expandedSubExposure.getBBox())
728 logLevel = self.log.level
729 self.log.setLevel(self.log.WARNING)
730 res = DecorrelateALKernelTask.run(self, subExp2, subExp1, expandedSubExposure,
731 psfMatchingKernel, preConvKernel, **kwargs)
732 self.log.setLevel(logLevel)
734 diffim = res.correctedExposure.Factory(res.correctedExposure, subExposure.getBBox())
735 out = pipeBase.Struct(subExposure=diffim, )
740 """Configuration parameters for the ImageMapReduceTask to direct it to use
741 DecorrelateALKernelMapper as its mapper
for A&L decorrelation.
743 mapper = pexConfig.ConfigurableField(
744 doc='A&L decorrelation task to run on each sub-image',
745 target=DecorrelateALKernelMapper
750 """Configuration parameters for the DecorrelateALKernelSpatialTask.
752 decorrelateConfig = pexConfig.ConfigField(
753 dtype=DecorrelateALKernelConfig,
754 doc='DecorrelateALKernel config to use when running on complete exposure (non spatially-varying)',
757 decorrelateMapReduceConfig = pexConfig.ConfigField(
758 dtype=DecorrelateALKernelMapReduceConfig,
759 doc=
'DecorrelateALKernelMapReduce config to use when running on each sub-image (spatially-varying)',
762 ignoreMaskPlanes = pexConfig.ListField(
764 doc=
"""Mask planes to ignore for sigma-clipped statistics""",
765 default=(
"INTRP",
"EDGE",
"DETECTED",
"SAT",
"CR",
"BAD",
"NO_DATA",
"DETECTED_NEGATIVE")
776 """Decorrelate the effect of convolution by Alard-Lupton matching kernel in image difference
779 ConfigClass = DecorrelateALKernelSpatialConfig
780 _DefaultName = "ip_diffim_decorrelateALKernelSpatial"
783 """Create the image decorrelation Task
788 arguments to be passed to
789 `lsst.pipe.base.task.Task.__init__`
791 additional keyword arguments to be passed to
792 `lsst.pipe.base.task.Task.__init__`
794 pipeBase.Task.__init__(self, *args, **kwargs)
799 self.statsControl.setAndMask(afwImage.Mask.getPlaneBitMask(self.config.ignoreMaskPlanes))
802 """Compute the mean of the variance plane of `exposure`.
807 var = statObj.getValue(afwMath.MEANCLIP)
810 def run(self, scienceExposure, templateExposure, subtractedExposure, psfMatchingKernel,
811 spatiallyVarying=True, preConvKernel=None, templateMatched=True, preConvMode=False):
812 """Perform decorrelation of an image difference exposure.
814 Decorrelates the diffim due to the convolution of the
815 templateExposure with the A&L psfMatchingKernel. If
816 `spatiallyVarying`
is True, it utilizes the spatially varying
817 matching kernel via the `imageMapReduce` framework to perform
818 spatially-varying decorrelation on a grid of subExposures.
823 the science Exposure used
for PSF matching
825 the template Exposure used
for PSF matching
827 the subtracted Exposure produced by `ip_diffim.ImagePsfMatchTask.subtractExposures()`
828 psfMatchingKernel : an (optionally spatially-varying) PSF matching kernel produced
829 by `ip_diffim.ImagePsfMatchTask.subtractExposures()`
830 spatiallyVarying : `bool`
831 if True, perform the spatially-varying operation
832 preConvKernel : `lsst.meas.algorithms.Psf`
833 if not none, the scienceExposure has been pre-filtered
with this kernel. (Currently
834 this option
is experimental.)
835 templateMatched : `bool`, optional
836 If
True, the template exposure was matched (convolved) to the science exposure.
837 preConvMode : `bool`, optional
838 If
True, ``subtractedExposure``
is assumed to be a likelihood difference image
839 and will be noise corrected
as a likelihood image.
843 results : `lsst.pipe.base.Struct`
844 a structure containing:
845 - ``correctedExposure`` : the decorrelated diffim
847 self.log.info('Running A&L decorrelation: spatiallyVarying=%r', spatiallyVarying)
851 if np.isnan(svar)
or np.isnan(tvar):
853 if (np.all(np.isnan(scienceExposure.image.array))
854 or np.all(np.isnan(templateExposure.image.array))):
855 self.log.warning(
'Template or science image is entirely NaNs: skipping decorrelation.')
864 self.log.info(
"Variance (science, template): (%f, %f)", svar, tvar)
865 self.log.info(
"Variance (uncorrected diffim): %f", var)
866 config = self.config.decorrelateMapReduceConfig
868 results = task.run(subtractedExposure, science=scienceExposure,
869 template=templateExposure, psfMatchingKernel=psfMatchingKernel,
870 preConvKernel=preConvKernel, forceEvenSized=
True,
871 templateMatched=templateMatched, preConvMode=preConvMode)
872 results.correctedExposure = results.exposure
877 gm(results.correctedExposure)[:, :] = gm(subtractedExposure)
880 self.log.info(
"Variance (corrected diffim): %f", var)
883 config = self.config.decorrelateConfig
885 results = task.run(scienceExposure, templateExposure,
886 subtractedExposure, psfMatchingKernel, preConvKernel=preConvKernel,
887 templateMatched=templateMatched, preConvMode=preConvMode)
__init__(self, *args, **kwargs)
run(self, subExposure, expandedSubExposure, fullBBox, template, science, alTaskResult=None, psfMatchingKernel=None, preConvKernel=None, **kwargs)
decorrelateMapReduceConfig
__init__(self, *args, **kwargs)
computeVarianceMean(self, exposure)
run(self, scienceExposure, templateExposure, subtractedExposure, psfMatchingKernel, spatiallyVarying=True, preConvKernel=None, templateMatched=True, preConvMode=False)
computeCommonShape(self, *shapes)
computeScoreCorrection(self, kappa, svar, tvar, preConvArr)
__init__(self, *args, **kwargs)
estimateVariancePlane(vplane1, vplane2, c1ft, c2ft)
computeCorrectedDiffimPsf(self, corrft, psfOld)
run(self, scienceExposure, templateExposure, subtractedExposure, psfMatchingKernel, preConvKernel=None, xcen=None, ycen=None, svar=None, tvar=None, templateMatched=True, preConvMode=False, **kwargs)
padCenterOriginArray(A, tuple newShape, useInverse=False)
computeCorrectedImage(self, corrft, imgOld)
computeDiffimCorrection(self, kappa, svar, tvar)
calculateVariancePlane(self, vplane1, vplane2, varMean1, varMean2, c1ft, c2ft)
computeVarianceMean(self, exposure)
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())