2 from builtins
import range
33 from .
import utils
as diUtils
34 from .
import diffimLib
38 """!Configuration for detecting sources on images for building a PSF-matching kernel
40 Configuration for turning detected lsst.afw.detection.FootPrints into an acceptable
41 (unmasked, high signal-to-noise, not too large or not too small) list of
42 lsst.ip.diffim.KernelSources that are used to build the Psf-matching kernel"""
44 detThreshold = pexConfig.Field(
46 doc=
"Value of footprint detection threshold",
48 check=
lambda x: x >= 3.0
50 detThresholdType = pexConfig.ChoiceField(
52 doc=
"Type of detection threshold",
53 default=
"pixel_stdev",
55 "value":
"Use counts as the detection threshold type",
56 "stdev":
"Use standard deviation of image plane",
57 "variance":
"Use variance of image plane",
58 "pixel_stdev":
"Use stdev derived from variance plane"
61 detOnTemplate = pexConfig.Field(
63 doc=
"""If true run detection on the template (image to convolve);
64 if false run detection on the science image""",
67 badMaskPlanes = pexConfig.ListField(
69 doc=
"""Mask planes that lead to an invalid detection.
70 Options: NO_DATA EDGE SAT BAD CR INTRP""",
71 default=(
"NO_DATA",
"EDGE",
"SAT")
73 fpNpixMin = pexConfig.Field(
75 doc=
"Minimum number of pixels in an acceptable Footprint",
77 check=
lambda x: x >= 5
79 fpNpixMax = pexConfig.Field(
81 doc=
"""Maximum number of pixels in an acceptable Footprint;
82 too big and the subsequent convolutions become unwieldy""",
84 check=
lambda x: x <= 500
86 fpGrowKernelScaling = pexConfig.Field(
88 doc=
"""If config.scaleByFwhm, grow the footprint based on
89 the final kernelSize. Each footprint will be
90 2*fpGrowKernelScaling*kernelSize x
91 2*fpGrowKernelScaling*kernelSize. With the value
92 of 1.0, the remaining pixels in each KernelCandiate
93 after convolution by the basis functions will be
94 equal to the kernel size itself.""",
96 check=
lambda x: x >= 1.0
98 fpGrowPix = pexConfig.Field(
100 doc=
"""Growing radius (in pixels) for each raw detection
101 footprint. The smaller the faster; however the
102 kernel sum does not converge if the stamp is too
103 small; and the kernel is not constrained at all if
104 the stamp is the size of the kernel. The grown stamp
105 is 2 * fpGrowPix pixels larger in each dimension.
106 This is overridden by fpGrowKernelScaling if scaleByFwhm""",
108 check=
lambda x: x >= 10
110 scaleByFwhm = pexConfig.Field(
112 doc=
"Scale fpGrowPix by input Fwhm?",
118 """!Base configuration for Psf-matching
120 The base configuration of the Psf-matching kernel, and of the warping, detection,
121 and background modeling subTasks."""
123 warpingConfig = pexConfig.ConfigField(
"Config for warping exposures to a common alignment",
124 afwMath.warper.WarperConfig)
125 detectionConfig = pexConfig.ConfigField(
"Controlling the detection of sources for kernel building",
127 afwBackgroundConfig = pexConfig.ConfigField(
"Controlling the Afw background fitting",
128 SubtractBackgroundConfig)
130 useAfwBackground = pexConfig.Field(
132 doc=
"Use afw background subtraction instead of ip_diffim",
135 fitForBackground = pexConfig.Field(
137 doc=
"Include terms (including kernel cross terms) for background in ip_diffim",
140 kernelBasisSet = pexConfig.ChoiceField(
142 doc=
"Type of basis set for PSF matching kernel.",
143 default=
"alard-lupton",
145 "alard-lupton" :
"""Alard-Lupton sum-of-gaussians basis set,
146 * The first term has no spatial variation
147 * The kernel sum is conserved
148 * You may want to turn off 'usePcaForSpatialKernel'""",
149 "delta-function" :
"""Delta-function kernel basis set,
150 * You may enable the option useRegularization
151 * You should seriously consider usePcaForSpatialKernel, which will also
152 enable kernel sum conservation for the delta function kernels"""
155 kernelSize = pexConfig.Field(
157 doc=
"""Number of rows/columns in the convolution kernel; should be odd-valued.
158 Modified by kernelSizeFwhmScaling if scaleByFwhm = true""",
161 scaleByFwhm = pexConfig.Field(
163 doc=
"Scale kernelSize, alardGaussians by input Fwhm",
166 kernelSizeFwhmScaling = pexConfig.Field(
168 doc=
"""How much to scale the kernel size based on the largest AL Sigma""",
170 check=
lambda x: x >= 1.0
172 kernelSizeMin = pexConfig.Field(
174 doc=
"""Minimum Kernel Size""",
177 kernelSizeMax = pexConfig.Field(
179 doc=
"""Maximum Kernel Size""",
182 spatialModelType = pexConfig.ChoiceField(
184 doc=
"Type of spatial functions for kernel and background",
185 default=
"chebyshev1",
187 "chebyshev1":
"Chebyshev polynomial of the first kind",
188 "polynomial":
"Standard x,y polynomial",
191 spatialKernelOrder = pexConfig.Field(
193 doc=
"Spatial order of convolution kernel variation",
195 check=
lambda x: x >= 0
197 spatialBgOrder = pexConfig.Field(
199 doc=
"Spatial order of differential background variation",
201 check=
lambda x: x >= 0
203 sizeCellX = pexConfig.Field(
205 doc=
"Size (rows) in pixels of each SpatialCell for spatial modeling",
207 check=
lambda x: x >= 32
209 sizeCellY = pexConfig.Field(
211 doc=
"Size (columns) in pixels of each SpatialCell for spatial modeling",
213 check=
lambda x: x >= 32
215 nStarPerCell = pexConfig.Field(
217 doc=
"Number of KernelCandidates in each SpatialCell to use in the spatial fitting",
219 check=
lambda x: x >= 1
221 maxSpatialIterations = pexConfig.Field(
223 doc=
"Maximum number of iterations for rejecting bad KernelCandidates in spatial fitting",
225 check=
lambda x: x >= 1
and x <= 5
227 usePcaForSpatialKernel = pexConfig.Field(
229 doc=
"""Use Pca to reduce the dimensionality of the kernel basis sets.
230 This is particularly useful for delta-function kernels.
231 Functionally, after all Cells have their raw kernels determined, we run
232 a Pca on these Kernels, re-fit the Cells using the eigenKernels and then
233 fit those for spatial variation using the same technique as for Alard-Lupton kernels.
234 If this option is used, the first term will have no spatial variation and the
235 kernel sum will be conserved.""",
238 subtractMeanForPca = pexConfig.Field(
240 doc=
"Subtract off the mean feature before doing the Pca",
243 numPrincipalComponents = pexConfig.Field(
245 doc=
"""Number of principal components to use for Pca basis, including the
246 mean kernel if requested.""",
248 check=
lambda x: x >= 3
250 singleKernelClipping = pexConfig.Field(
252 doc=
"Do sigma clipping on each raw kernel candidate",
255 kernelSumClipping = pexConfig.Field(
257 doc=
"Do sigma clipping on the ensemble of kernel sums",
260 spatialKernelClipping = pexConfig.Field(
262 doc=
"Do sigma clipping after building the spatial model",
265 checkConditionNumber = pexConfig.Field(
267 doc=
"""Test for maximum condition number when inverting a kernel matrix.
268 Anything above maxConditionNumber is not used and the candidate is set as BAD.
269 Also used to truncate inverse matrix in estimateBiasedRisk. However,
270 if you are doing any deconvolution you will want to turn this off, or use
271 a large maxConditionNumber""",
274 badMaskPlanes = pexConfig.ListField(
276 doc=
"""Mask planes to ignore when calculating diffim statistics
277 Options: NO_DATA EDGE SAT BAD CR INTRP""",
278 default=(
"NO_DATA",
"EDGE",
"SAT")
280 candidateResidualMeanMax = pexConfig.Field(
282 doc=
"""Rejects KernelCandidates yielding bad difference image quality.
283 Used by BuildSingleKernelVisitor, AssessSpatialKernelVisitor.
284 Represents average over pixels of (image/sqrt(variance)).""",
286 check=
lambda x: x >= 0.0
288 candidateResidualStdMax = pexConfig.Field(
290 doc=
"""Rejects KernelCandidates yielding bad difference image quality.
291 Used by BuildSingleKernelVisitor, AssessSpatialKernelVisitor.
292 Represents stddev over pixels of (image/sqrt(variance)).""",
294 check=
lambda x: x >= 0.0
296 useCoreStats = pexConfig.Field(
298 doc=
"""Use the core of the footprint for the quality statistics, instead of the entire footprint.
299 WARNING: if there is deconvolution we probably will need to turn this off""",
302 candidateCoreRadius = pexConfig.Field(
304 doc=
"""Radius for calculation of stats in 'core' of KernelCandidate diffim.
305 Total number of pixels used will be (2*radius)**2.
306 This is used both for 'core' diffim quality as well as ranking of
307 KernelCandidates by their total flux in this core""",
309 check=
lambda x: x >= 1
311 maxKsumSigma = pexConfig.Field(
313 doc=
"""Maximum allowed sigma for outliers from kernel sum distribution.
314 Used to reject variable objects from the kernel model""",
316 check=
lambda x: x >= 0.0
318 maxConditionNumber = pexConfig.Field(
320 doc=
"Maximum condition number for a well conditioned matrix",
322 check=
lambda x: x >= 0.0
324 conditionNumberType = pexConfig.ChoiceField(
326 doc=
"Use singular values (SVD) or eigen values (EIGENVALUE) to determine condition number",
327 default=
"EIGENVALUE",
329 "SVD":
"Use singular values",
330 "EIGENVALUE":
"Use eigen values (faster)",
333 maxSpatialConditionNumber = pexConfig.Field(
335 doc=
"Maximum condition number for a well conditioned spatial matrix",
337 check=
lambda x: x >= 0.0
339 iterateSingleKernel = pexConfig.Field(
341 doc=
"""Remake KernelCandidate using better variance estimate after first pass?
342 Primarily useful when convolving a single-depth image, otherwise not necessary.""",
345 constantVarianceWeighting = pexConfig.Field(
347 doc=
"""Use constant variance weighting in single kernel fitting?
348 In some cases this is better for bright star residuals.""",
351 calculateKernelUncertainty = pexConfig.Field(
353 doc=
"""Calculate kernel and background uncertainties for each kernel candidate?
354 This comes from the inverse of the covariance matrix.
355 Warning: regularization can cause problems for this step.""",
358 useBicForKernelBasis = pexConfig.Field(
360 doc=
"""Use Bayesian Information Criterion to select the number of bases going into the kernel""",
366 """!The parameters specific to the "Alard-Lupton" (sum-of-Gaussian) Psf-matching basis"""
369 PsfMatchConfig.setDefaults(self)
373 alardNGauss = pexConfig.Field(
375 doc=
"Number of Gaussians in alard-lupton basis",
377 check=
lambda x: x >= 1
379 alardDegGauss = pexConfig.ListField(
381 doc=
"Polynomial order of spatial modification of Gaussians. Must in number equal alardNGauss",
384 alardSigGauss = pexConfig.ListField(
386 doc=
"""Sigma in pixels of Gaussians (FWHM = 2.35 sigma). Must in number equal alardNGauss""",
387 default=(0.7, 1.5, 3.0),
389 alardGaussBeta = pexConfig.Field(
391 doc=
"""Default scale factor between Gaussian sigmas """,
393 check=
lambda x: x >= 0.0,
395 alardMinSig = pexConfig.Field(
397 doc=
"""Minimum Sigma (pixels) for Gaussians""",
399 check=
lambda x: x >= 0.25
401 alardDegGaussDeconv = pexConfig.Field(
403 doc=
"""Degree of spatial modification of ALL gaussians in AL basis during deconvolution""",
405 check=
lambda x: x >= 1
407 alardMinSigDeconv = pexConfig.Field(
409 doc=
"""Minimum Sigma (pixels) for Gaussians during deconvolution;
410 make smaller than alardMinSig as this is only indirectly used""",
412 check=
lambda x: x >= 0.25
414 alardNGaussDeconv = pexConfig.Field(
416 doc=
"Number of Gaussians in AL basis during deconvolution",
418 check=
lambda x: x >= 1
423 """!The parameters specific to the delta-function (one basis per-pixel) Psf-matching basis"""
426 PsfMatchConfig.setDefaults(self)
433 useRegularization = pexConfig.Field(
435 doc=
"Use regularization to smooth the delta function kernels",
438 regularizationType = pexConfig.ChoiceField(
440 doc=
"Type of regularization.",
441 default=
"centralDifference",
443 "centralDifference":
"Penalize second derivative using 2-D stencil of central finite difference",
444 "forwardDifference":
"Penalize first, second, third derivatives using forward finite differeces"
447 centralRegularizationStencil = pexConfig.ChoiceField(
449 doc=
"Type of stencil to approximate central derivative (for centralDifference only)",
452 5:
"5-point stencil including only adjacent-in-x,y elements",
453 9:
"9-point stencil including diagonal elements"
456 forwardRegularizationOrders = pexConfig.ListField(
458 doc=
"Array showing which order derivatives to penalize (for forwardDifference only)",
460 itemCheck=
lambda x: (x > 0)
and (x < 4)
462 regularizationBorderPenalty = pexConfig.Field(
464 doc=
"Value of the penalty for kernel border pixels",
466 check=
lambda x: x >= 0.0
468 lambdaType = pexConfig.ChoiceField(
470 doc=
"How to choose the value of the regularization strength",
473 "absolute":
"Use lambdaValue as the value of regularization strength",
474 "relative":
"Use lambdaValue as fraction of the default regularization strength (N.R. 18.5.8)",
475 "minimizeBiasedRisk":
"Minimize biased risk estimate",
476 "minimizeUnbiasedRisk":
"Minimize unbiased risk estimate",
479 lambdaValue = pexConfig.Field(
481 doc=
"Value used for absolute determinations of regularization strength",
484 lambdaScaling = pexConfig.Field(
486 doc=
"Fraction of the default lambda strength (N.R. 18.5.8) to use. 1e-4 or 1e-5",
489 lambdaStepType = pexConfig.ChoiceField(
491 doc=
"""If a scan through lambda is needed (minimizeBiasedRisk, minimizeUnbiasedRisk),
492 use log or linear steps""",
495 "log":
"Step in log intervals; e.g. lambdaMin, lambdaMax, lambdaStep = -1.0, 2.0, 0.1",
496 "linear":
"Step in linear intervals; e.g. lambdaMin, lambdaMax, lambdaStep = 0.1, 100, 0.1",
499 lambdaMin = pexConfig.Field(
501 doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk),
502 start at this value. If lambdaStepType = log:linear, suggest -1:0.1""",
505 lambdaMax = pexConfig.Field(
507 doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk),
508 stop at this value. If lambdaStepType = log:linear, suggest 2:100""",
511 lambdaStep = pexConfig.Field(
513 doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk),
514 step in these increments. If lambdaStepType = log:linear, suggest 0.1:0.1""",
529 \anchor PsfMatchTask_
531 \brief Base class for Psf Matching; should not be called directly
533 \section ip_diffim_psfmatch_Contents Contents
535 - \ref ip_diffim_psfmatch_Purpose
536 - \ref ip_diffim_psfmatch_Initialize
537 - \ref ip_diffim_psfmatch_IO
538 - \ref ip_diffim_psfmatch_Config
539 - \ref ip_diffim_psfmatch_Metadata
540 - \ref ip_diffim_psfmatch_Debug
541 - \ref ip_diffim_psfmatch_Example
543 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
545 \section ip_diffim_psfmatch_Purpose Description
547 PsfMatchTask is a base class that implements the core functionality for matching the
548 Psfs of two images using a spatially varying Psf-matching lsst.afw.math.LinearCombinationKernel.
549 The Task requires the user to provide an instance of an lsst.afw.math.SpatialCellSet,
550 filled with lsst.ip.diffim.KernelCandidate instances, and an lsst.afw.math.KernelList
551 of basis shapes that will be used for the decomposition. If requested, the Task
552 also performs background matching and returns the differential background model as an
553 lsst.afw.math.Kernel.SpatialFunction.
555 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
557 \section ip_diffim_psfmatch_Initialize Task initialization
559 \copydoc \_\_init\_\_
561 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
563 \section ip_diffim_psfmatch_IO Invoking the Task
565 As a base class, this Task is not directly invoked. However, run() methods that are
566 implemented on derived classes will make use of the core _solve() functionality,
567 which defines a sequence of lsst.afw.math.CandidateVisitor classes that iterate
568 through the KernelCandidates, first building up a per-candidate solution and then
569 building up a spatial model from the ensemble of candidates. Sigma clipping is
570 performed using the mean and standard deviation of all kernel sums (to reject
571 variable objects), on the per-candidate substamp diffim residuals
572 (to indicate a bad choice of kernel basis shapes for that particular object),
573 and on the substamp diffim residuals using the spatial kernel fit (to indicate a bad
574 choice of spatial kernel order, or poor constraints on the spatial model). The
575 _diagnostic() method logs information on the quality of the spatial fit, and also
576 modifies the Task metadata.
578 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
580 \section ip_diffim_psfmatch_Config Configuration parameters
582 See \ref PsfMatchConfig, \ref PsfMatchConfigAL, \ref PsfMatchConfigDF, and \ref DetectionConfig.
584 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
586 \section ip_diffim_psfmatch_Metadata Quantities set in Metadata
590 <DT> spatialConditionNum <DD> Condition number of the spatial kernel fit;
591 via \link lsst.ip.diffim.PsfMatchTask._diagnostic PsfMatchTask._diagnostic \endlink </DD> </DT>
592 <DT> spatialKernelSum <DD> Kernel sum (10^{-0.4 * Δ zeropoint}) of the spatial Psf-matching kernel;
593 via \link lsst.ip.diffim.PsfMatchTask._diagnostic PsfMatchTask._diagnostic \endlink </DD> </DT>
595 <DT> ALBasisNGauss <DD> If using sum-of-Gaussian basis, the number of gaussians used;
596 via \link lsst.ip.diffim.makeKernelBasisList.generateAlardLuptonBasisList
597 generateAlardLuptonBasisList\endlink </DD> </DT>
598 <DT> ALBasisDegGauss <DD> If using sum-of-Gaussian basis, the degree of spatial variation of the Gaussians;
599 via \link lsst.ip.diffim.makeKernelBasisList.generateAlardLuptonBasisList
600 generateAlardLuptonBasisList\endlink </DD> </DT>
601 <DT> ALBasisSigGauss <DD> If using sum-of-Gaussian basis, the widths (sigma) of the Gaussians;
602 via \link lsst.ip.diffim.makeKernelBasisList.generateAlardLuptonBasisList
603 generateAlardLuptonBasisList\endlink </DD> </DT>
604 <DT> ALKernelSize <DD> If using sum-of-Gaussian basis, the kernel size;
605 via \link lsst.ip.diffim.makeKernelBasisList.generateAlardLuptonBasisList
606 generateAlardLuptonBasisList\endlink </DD> </DT>
608 <DT> NFalsePositivesTotal <DD> Total number of diaSources;
609 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
610 <DT> NFalsePositivesRefAssociated <DD> Number of diaSources that associate with the reference catalog;
611 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
612 <DT> NFalsePositivesRefAssociated <DD> Number of diaSources that associate with the source catalog;
613 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
614 <DT> NFalsePositivesUnassociated <DD> Number of diaSources that are orphans;
615 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
616 <DT> metric_MEAN <DD> Mean value of substamp diffim quality metrics across all KernelCandidates,
617 for both the per-candidate (LOCAL) and SPATIAL residuals;
618 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
619 <DT> metric_MEDIAN <DD> Median value of substamp diffim quality metrics across all KernelCandidates,
620 for both the per-candidate (LOCAL) and SPATIAL residuals;
621 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
622 <DT> metric_STDEV <DD> Standard deviation of substamp diffim quality metrics across all KernelCandidates,
623 for both the per-candidate (LOCAL) and SPATIAL residuals;
624 via \link lsst.ip.diffim.KernelCandidateQa.aggregate KernelCandidateQa.aggregate\endlink </DD> </DT>
628 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
630 \section ip_diffim_psfmatch_Debug Debug variables
633 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
634 flag \c -d/--debug to import \b debug.py from your \c PYTHONPATH. The relevant contents of debug.py
635 for this Task include:
641 di = lsstDebug.getInfo(name)
642 if name == "lsst.ip.diffim.psfMatch":
643 di.display = True # enable debug output
644 di.maskTransparency = 80 # ds9 mask transparency
645 di.displayCandidates = True # show all the candidates and residuals
646 di.displayKernelBasis = False # show kernel basis functions
647 di.displayKernelMosaic = True # show kernel realized across the image
648 di.plotKernelSpatialModel = False # show coefficients of spatial model
649 di.showBadCandidates = True # show the bad candidates (red) along with good (green)
651 lsstDebug.Info = DebugInfo
656 Note that if you want addional logging info, you may add to your scripts:
658 import lsst.log.utils as logUtils
659 logUtils.traceSetAt("ip.diffim", 4)
662 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
664 \section ip_diffim_psfmatch_Example Example code
666 As a base class, there is no example code for PsfMatchTask.
667 However, see \link lsst.ip.diffim.imagePsfMatch.ImagePsfMatchTask ImagePsfMatchTask\endlink,
668 \link lsst.ip.diffim.snapPsfMatch.SnapPsfMatchTask SnapPsfMatchTask\endlink, and
669 \link lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask ModelPsfMatchTask\endlink.
671 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
674 ConfigClass = PsfMatchConfig
675 _DefaultName =
"psfMatch"
678 """!Create the psf-matching Task
680 \param *args arguments to be passed to lsst.pipe.base.task.Task.__init__
681 \param **kwargs keyword arguments to be passed to lsst.pipe.base.task.Task.__init__
683 The initialization sets the Psf-matching kernel configuration using the value of
684 self.config.kernel.active. If the kernel is requested with regularization to moderate
685 the bias/variance tradeoff, currently only used when a delta function kernel basis
686 is provided, it creates a regularization matrix stored as member variable
689 pipeBase.Task.__init__(self, *args, **kwargs)
693 if 'useRegularization' in self.
kConfig:
699 self.
hMat = diffimLib.makeRegularizationMatrix(pexConfig.makePolicy(self.
kConfig))
701 def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg):
702 """!Provide logging diagnostics on quality of spatial kernel fit
704 @param kernelCellSet: Cellset that contains the KernelCandidates used in the fitting
705 @param spatialSolution: KernelSolution of best-fit
706 @param spatialKernel: Best-fit spatial Kernel model
707 @param spatialBg: Best-fit spatial background model
711 kImage = afwImage.ImageD(spatialKernel.getDimensions())
712 kSum = spatialKernel.computeImage(kImage,
False)
713 self.log.info(
"Final spatial kernel sum %.3f" % (kSum))
716 conditionNum = spatialSolution.getConditionNumber(
717 getattr(diffimLib.KernelSolution, self.kConfig.conditionNumberType))
718 self.log.info(
"Spatial model condition number %.3e" % (conditionNum))
720 if conditionNum < 0.0:
721 self.log.warn(
"Condition number is negative (%.3e)" % (conditionNum))
722 if conditionNum > self.kConfig.maxSpatialConditionNumber:
723 self.log.warn(
"Spatial solution exceeds max condition number (%.3e > %.3e)" % (
724 conditionNum, self.kConfig.maxSpatialConditionNumber))
726 self.metadata.set(
"spatialConditionNum", conditionNum)
727 self.metadata.set(
"spatialKernelSum", kSum)
730 nBasisKernels = spatialKernel.getNBasisKernels()
731 nKernelTerms = spatialKernel.getNSpatialParameters()
732 if nKernelTerms == 0:
736 nBgTerms = spatialBg.getNParameters()
738 if spatialBg.getParameters()[0] == 0.0:
744 for cell
in kernelCellSet.getCellList():
745 for cand
in cell.begin(
False):
746 cand = diffimLib.KernelCandidateF.cast(cand)
748 if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
750 if cand.getStatus() == afwMath.SpatialCellCandidate.BAD:
753 self.log.info(
"Doing stats of kernel candidates used in the spatial fit.")
757 self.log.warn(
"Many more candidates rejected than accepted; %d total, %d rejected, %d used" % (
760 self.log.info(
"%d candidates total, %d rejected, %d used" % (nTot, nBad, nGood))
763 if nGood < nKernelTerms:
764 self.log.warn(
"Spatial kernel model underconstrained; %d candidates, %d terms, %d bases" % (
765 nGood, nKernelTerms, nBasisKernels))
766 self.log.warn(
"Consider lowering the spatial order")
767 elif nGood <= 2*nKernelTerms:
768 self.log.warn(
"Spatial kernel model poorly constrained; %d candidates, %d terms, %d bases" % (
769 nGood, nKernelTerms, nBasisKernels))
770 self.log.warn(
"Consider lowering the spatial order")
772 self.log.info(
"Spatial kernel model well constrained; %d candidates, %d terms, %d bases" % (
773 nGood, nKernelTerms, nBasisKernels))
776 self.log.warn(
"Spatial background model underconstrained; %d candidates, %d terms" % (
778 self.log.warn(
"Consider lowering the spatial order")
779 elif nGood <= 2*nBgTerms:
780 self.log.warn(
"Spatial background model poorly constrained; %d candidates, %d terms" % (
782 self.log.warn(
"Consider lowering the spatial order")
784 self.log.info(
"Spatial background model appears well constrained; %d candidates, %d terms" % (
788 """!Provide visualization of the inputs and ouputs to the Psf-matching code
790 @param kernelCellSet: the SpatialCellSet used in determining the matching kernel and background
791 @param spatialKernel: spatially varying Psf-matching kernel
792 @param spatialBackground: spatially varying background-matching function
798 displayKernelMosaic =
lsstDebug.Info(__name__).displayKernelMosaic
799 plotKernelSpatialModel =
lsstDebug.Info(__name__).plotKernelSpatialModel
802 if not maskTransparency:
804 ds9.setMaskTransparency(maskTransparency)
806 if displayCandidates:
807 diUtils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
808 frame=lsstDebug.frame,
809 showBadCandidates=showBadCandidates)
811 diUtils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
812 frame=lsstDebug.frame,
813 showBadCandidates=showBadCandidates,
816 diUtils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
817 frame=lsstDebug.frame,
818 showBadCandidates=showBadCandidates,
822 if displayKernelBasis:
823 diUtils.showKernelBasis(spatialKernel, frame=lsstDebug.frame)
826 if displayKernelMosaic:
827 diUtils.showKernelMosaic(kernelCellSet.getBBox(), spatialKernel, frame=lsstDebug.frame)
830 if plotKernelSpatialModel:
831 diUtils.plotKernelSpatialModel(spatialKernel, kernelCellSet, showBadCandidates=showBadCandidates)
834 """!Create Principal Component basis
836 If a principal component analysis is requested, typically when using a delta function basis,
837 perform the PCA here and return a new basis list containing the new principal components.
839 @param kernelCellSet: a SpatialCellSet containing KernelCandidates, from which components are derived
840 @param nStarPerCell: the number of stars per cell to visit when doing the PCA
841 @param policy: input policy controlling the single kernel visitor
844 - nRejectedPca: number of KernelCandidates rejected during PCA loop
845 - spatialBasisList: basis list containing the principal shapes as Kernels
848 nComponents = self.kConfig.numPrincipalComponents
849 imagePca = diffimLib.KernelPcaD()
850 importStarVisitor = diffimLib.KernelPcaVisitorF(imagePca)
851 kernelCellSet.visitCandidates(importStarVisitor, nStarPerCell)
852 if self.kConfig.subtractMeanForPca:
853 importStarVisitor.subtractMean()
856 eigenValues = imagePca.getEigenValues()
857 pcaBasisList = importStarVisitor.getEigenKernels()
859 eSum = num.sum(eigenValues)
861 raise RuntimeError(
"Eigenvalues sum to zero")
862 for j
in range(len(eigenValues)):
863 log.log(
"TRACE5." + self.log.getName() +
"._solve", log.DEBUG,
864 "Eigenvalue %d : %f (%f)", j, eigenValues[j], eigenValues[j]/eSum)
866 nToUse = min(nComponents, len(eigenValues))
868 for j
in range(nToUse):
870 kimage = afwImage.ImageD(pcaBasisList[j].getDimensions())
871 pcaBasisList[j].computeImage(kimage,
False)
872 if not (
True in num.isnan(kimage.getArray())):
873 trimBasisList.push_back(pcaBasisList[j])
876 spatialBasisList = diffimLib.renormalizeKernelList(trimBasisList)
879 singlekvPca = diffimLib.BuildSingleKernelVisitorF(spatialBasisList, policy)
880 singlekvPca.setSkipBuilt(
False)
881 kernelCellSet.visitCandidates(singlekvPca, nStarPerCell)
882 singlekvPca.setSkipBuilt(
True)
883 nRejectedPca = singlekvPca.getNRejected()
885 return nRejectedPca, spatialBasisList
888 """!Fill a SpatialCellSet with KernelCandidates for the Psf-matching process;
889 override in derived classes"""
893 def _solve(self, kernelCellSet, basisList, returnOnExcept=False):
894 """!Solve for the PSF matching kernel
896 @param kernelCellSet: a SpatialCellSet to use in determining the matching kernel
897 (typically as provided by _buildCellSet)
898 @param basisList: list of Kernels to be used in the decomposition of the spatially varying kernel
899 (typically as provided by makeKernelBasisList)
900 @param returnOnExcept: if True then return (None, None) if an error occurs, else raise the exception
903 - psfMatchingKernel: PSF matching kernel
904 - backgroundModel: differential background model
906 Raise Exception if unable to determine PSF matching kernel and returnOnExcept False
912 maxSpatialIterations = self.kConfig.maxSpatialIterations
913 nStarPerCell = self.kConfig.nStarPerCell
914 usePcaForSpatialKernel = self.kConfig.usePcaForSpatialKernel
917 policy = pexConfig.makePolicy(self.
kConfig)
919 singlekv = diffimLib.BuildSingleKernelVisitorF(basisList, policy, self.
hMat)
921 singlekv = diffimLib.BuildSingleKernelVisitorF(basisList, policy)
924 ksv = diffimLib.KernelSumVisitorF(policy)
931 while (thisIteration < maxSpatialIterations):
935 while (nRejectedSkf != 0):
936 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
937 "Building single kernels...")
938 kernelCellSet.visitCandidates(singlekv, nStarPerCell)
939 nRejectedSkf = singlekv.getNRejected()
940 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
941 "Iteration %d, rejected %d candidates due to initial kernel fit",
942 thisIteration, nRejectedSkf)
946 ksv.setMode(diffimLib.KernelSumVisitorF.AGGREGATE)
947 kernelCellSet.visitCandidates(ksv, nStarPerCell)
948 ksv.processKsumDistribution()
949 ksv.setMode(diffimLib.KernelSumVisitorF.REJECT)
950 kernelCellSet.visitCandidates(ksv, nStarPerCell)
952 nRejectedKsum = ksv.getNRejected()
953 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
954 "Iteration %d, rejected %d candidates due to kernel sum",
955 thisIteration, nRejectedKsum)
958 if nRejectedKsum > 0:
967 if (usePcaForSpatialKernel):
968 log.log(
"TRACE0." + self.log.getName() +
"._solve", log.DEBUG,
969 "Building Pca basis")
971 nRejectedPca, spatialBasisList = self.
_createPcaBasis(kernelCellSet, nStarPerCell, policy)
972 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
973 "Iteration %d, rejected %d candidates due to Pca kernel fit",
974 thisIteration, nRejectedPca)
985 if (nRejectedPca > 0):
989 spatialBasisList = basisList
992 regionBBox = kernelCellSet.getBBox()
993 spatialkv = diffimLib.BuildSpatialKernelVisitorF(spatialBasisList, regionBBox, policy)
994 kernelCellSet.visitCandidates(spatialkv, nStarPerCell)
995 spatialkv.solveLinearEquation()
996 log.log(
"TRACE2." + self.log.getName() +
"._solve", log.DEBUG,
997 "Spatial kernel built with %d candidates", spatialkv.getNCandidates())
998 spatialKernel, spatialBackground = spatialkv.getSolutionPair()
1001 assesskv = diffimLib.AssessSpatialKernelVisitorF(spatialKernel, spatialBackground, policy)
1002 kernelCellSet.visitCandidates(assesskv, nStarPerCell)
1003 nRejectedSpatial = assesskv.getNRejected()
1004 nGoodSpatial = assesskv.getNGood()
1005 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
1006 "Iteration %d, rejected %d candidates due to spatial kernel fit",
1007 thisIteration, nRejectedSpatial)
1008 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
1009 "%d candidates used in fit", nGoodSpatial)
1012 if nGoodSpatial == 0
and nRejectedSpatial == 0:
1013 raise RuntimeError(
"No kernel candidates for spatial fit")
1015 if nRejectedSpatial == 0:
1023 if (nRejectedSpatial > 0)
and (thisIteration == maxSpatialIterations):
1024 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG,
"Final spatial fit")
1025 if (usePcaForSpatialKernel):
1026 nRejectedPca, spatialBasisList = self.
_createPcaBasis(kernelCellSet, nStarPerCell, policy)
1027 regionBBox = kernelCellSet.getBBox()
1028 spatialkv = diffimLib.BuildSpatialKernelVisitorF(spatialBasisList, regionBBox, policy)
1029 kernelCellSet.visitCandidates(spatialkv, nStarPerCell)
1030 spatialkv.solveLinearEquation()
1031 log.log(
"TRACE2." + self.log.getName() +
"._solve", log.DEBUG,
1032 "Spatial kernel built with %d candidates", spatialkv.getNCandidates())
1033 spatialKernel, spatialBackground = spatialkv.getSolutionPair()
1035 spatialSolution = spatialkv.getKernelSolution()
1037 except Exception
as e:
1038 self.log.error(
"ERROR: Unable to calculate psf matching kernel")
1040 log.log(
"TRACE1." + self.log.getName() +
"._solve", log.DEBUG, str(e))
1044 log.log(
"TRACE0." + self.log.getName() +
"._solve", log.DEBUG,
1045 "Total time to compute the spatial kernel : %.2f s", (t1 - t0))
1048 self.
_displayDebug(kernelCellSet, spatialKernel, spatialBackground)
1050 self.
_diagnostic(kernelCellSet, spatialSolution, spatialKernel, spatialBackground)
1052 return spatialSolution, spatialKernel, spatialBackground
1054 PsfMatch = PsfMatchTask
Configuration for detecting sources on images for building a PSF-matching kernel. ...
The parameters specific to the "Alard-Lupton" (sum-of-Gaussian) Psf-matching basis.
Base configuration for Psf-matching.
The parameters specific to the delta-function (one basis per-pixel) Psf-matching basis.
Base class for Psf Matching; should not be called directly.
def _displayDebug
Provide visualization of the inputs and ouputs to the Psf-matching code.
def _diagnostic
Provide logging diagnostics on quality of spatial kernel fit.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
def __init__
Create the psf-matching Task.
def _buildCellSet
Fill a SpatialCellSet with KernelCandidates for the Psf-matching process; override in derived classes...
def _createPcaBasis
Create Principal Component basis.
tuple usePcaForSpatialKernel
def _solve
Solve for the PSF matching kernel.
std::vector< boost::shared_ptr< Kernel > > KernelList
tuple useBicForKernelBasis