22 __all__ = [
"DetectionConfig", 
"PsfMatchConfig", 
"PsfMatchConfigAL", 
"PsfMatchConfigDF", 
"PsfMatchTask"]
 
   35 from lsst.utils.timer 
import timeMethod
 
   36 from . 
import utils 
as diutils
 
   37 from . 
import diffimLib
 
   41     """Configuration for detecting sources on images for building a 
   44     Configuration for turning detected lsst.afw.detection.FootPrints into an 
   45     acceptable (unmasked, high signal-to-noise, not too large or not too small) 
   46     list of `lsst.ip.diffim.KernelSources` that are used to build the 
   47     Psf-matching kernel""" 
   49     detThreshold = pexConfig.Field(
 
   51         doc=
"Value of footprint detection threshold",
 
   53         check=
lambda x: x >= 3.0
 
   55     detThresholdType = pexConfig.ChoiceField(
 
   57         doc=
"Type of detection threshold",
 
   58         default=
"pixel_stdev",
 
   60             "value": 
"Use counts as the detection threshold type",
 
   61             "stdev": 
"Use standard deviation of image plane",
 
   62             "variance": 
"Use variance of image plane",
 
   63             "pixel_stdev": 
"Use stdev derived from variance plane" 
   66     detOnTemplate = pexConfig.Field(
 
   68         doc=
"""If true run detection on the template (image to convolve); 
   69                  if false run detection on the science image""",
 
   72     badMaskPlanes = pexConfig.ListField(
 
   74         doc=
"""Mask planes that lead to an invalid detection. 
   75                  Options: NO_DATA EDGE SAT BAD CR INTRP""",
 
   76         default=(
"NO_DATA", 
"EDGE", 
"SAT")
 
   78     fpNpixMin = pexConfig.Field(
 
   80         doc=
"Minimum number of pixels in an acceptable Footprint",
 
   82         check=
lambda x: x >= 5
 
   84     fpNpixMax = pexConfig.Field(
 
   86         doc=
"""Maximum number of pixels in an acceptable Footprint; 
   87                  too big and the subsequent convolutions become unwieldy""",
 
   89         check=
lambda x: x <= 500
 
   91     fpGrowKernelScaling = pexConfig.Field(
 
   93         doc=
"""If config.scaleByFwhm, grow the footprint based on 
   94                  the final kernelSize.  Each footprint will be 
   95                  2*fpGrowKernelScaling*kernelSize x 
   96                  2*fpGrowKernelScaling*kernelSize.  With the value 
   97                  of 1.0, the remaining pixels in each KernelCandiate 
   98                  after convolution by the basis functions will be 
   99                  equal to the kernel size itself.""",
 
  101         check=
lambda x: x >= 1.0
 
  103     fpGrowPix = pexConfig.Field(
 
  105         doc=
"""Growing radius (in pixels) for each raw detection 
  106                  footprint.  The smaller the faster; however the 
  107                  kernel sum does not converge if the stamp is too 
  108                  small; and the kernel is not constrained at all if 
  109                  the stamp is the size of the kernel.  The grown stamp 
  110                  is 2 * fpGrowPix pixels larger in each dimension. 
  111                  This is overridden by fpGrowKernelScaling if scaleByFwhm""",
 
  113         check=
lambda x: x >= 10
 
  115     scaleByFwhm = pexConfig.Field(
 
  117         doc=
"Scale fpGrowPix by input Fwhm?",
 
  123     """Base configuration for Psf-matching 
  125     The base configuration of the Psf-matching kernel, and of the warping, detection, 
  126     and background modeling subTasks.""" 
  128     warpingConfig = pexConfig.ConfigField(
"Config for warping exposures to a common alignment",
 
  130     detectionConfig = pexConfig.ConfigField(
"Controlling the detection of sources for kernel building",
 
  132     afwBackgroundConfig = pexConfig.ConfigField(
"Controlling the Afw background fitting",
 
  133                                                 SubtractBackgroundConfig)
 
  135     useAfwBackground = pexConfig.Field(
 
  137         doc=
"Use afw background subtraction instead of ip_diffim",
 
  140     fitForBackground = pexConfig.Field(
 
  142         doc=
"Include terms (including kernel cross terms) for background in ip_diffim",
 
  145     kernelBasisSet = pexConfig.ChoiceField(
 
  147         doc=
"Type of basis set for PSF matching kernel.",
 
  148         default=
"alard-lupton",
 
  150             "alard-lupton": 
"""Alard-Lupton sum-of-gaussians basis set, 
  151                            * The first term has no spatial variation 
  152                            * The kernel sum is conserved 
  153                            * You may want to turn off 'usePcaForSpatialKernel'""",
 
  154             "delta-function": 
"""Delta-function kernel basis set, 
  155                            * You may enable the option useRegularization 
  156                            * You should seriously consider usePcaForSpatialKernel, which will also 
  157                              enable kernel sum conservation for the delta function kernels""" 
  160     kernelSize = pexConfig.Field(
 
  162         doc=
"""Number of rows/columns in the convolution kernel; should be odd-valued. 
  163                  Modified by kernelSizeFwhmScaling if scaleByFwhm = true""",
 
  166     scaleByFwhm = pexConfig.Field(
 
  168         doc=
"Scale kernelSize, alardGaussians by input Fwhm",
 
  171     kernelSizeFwhmScaling = pexConfig.Field(
 
  173         doc=
"Multiplier of the largest AL Gaussian basis sigma to get the kernel bbox (pixel) size.",
 
  175         check=
lambda x: x >= 1.0
 
  177     kernelSizeMin = pexConfig.Field(
 
  179         doc=
"Minimum kernel bbox (pixel) size.",
 
  182     kernelSizeMax = pexConfig.Field(
 
  184         doc=
"Maximum kernel bbox (pixel) size.",
 
  187     spatialModelType = pexConfig.ChoiceField(
 
  189         doc=
"Type of spatial functions for kernel and background",
 
  190         default=
"chebyshev1",
 
  192             "chebyshev1": 
"Chebyshev polynomial of the first kind",
 
  193             "polynomial": 
"Standard x,y polynomial",
 
  196     spatialKernelOrder = pexConfig.Field(
 
  198         doc=
"Spatial order of convolution kernel variation",
 
  200         check=
lambda x: x >= 0
 
  202     spatialBgOrder = pexConfig.Field(
 
  204         doc=
"Spatial order of differential background variation",
 
  206         check=
lambda x: x >= 0
 
  208     sizeCellX = pexConfig.Field(
 
  210         doc=
"Size (rows) in pixels of each SpatialCell for spatial modeling",
 
  212         check=
lambda x: x >= 32
 
  214     sizeCellY = pexConfig.Field(
 
  216         doc=
"Size (columns) in pixels of each SpatialCell for spatial modeling",
 
  218         check=
lambda x: x >= 32
 
  220     nStarPerCell = pexConfig.Field(
 
  222         doc=
"Number of KernelCandidates in each SpatialCell to use in the spatial fitting",
 
  224         check=
lambda x: x >= 1
 
  226     maxSpatialIterations = pexConfig.Field(
 
  228         doc=
"Maximum number of iterations for rejecting bad KernelCandidates in spatial fitting",
 
  230         check=
lambda x: x >= 1 
and x <= 5
 
  232     usePcaForSpatialKernel = pexConfig.Field(
 
  234         doc=
"""Use Pca to reduce the dimensionality of the kernel basis sets. 
  235                  This is particularly useful for delta-function kernels. 
  236                  Functionally, after all Cells have their raw kernels determined, we run 
  237                  a Pca on these Kernels, re-fit the Cells using the eigenKernels and then 
  238                  fit those for spatial variation using the same technique as for Alard-Lupton kernels. 
  239                  If this option is used, the first term will have no spatial variation and the 
  240                  kernel sum will be conserved.""",
 
  243     subtractMeanForPca = pexConfig.Field(
 
  245         doc=
"Subtract off the mean feature before doing the Pca",
 
  248     numPrincipalComponents = pexConfig.Field(
 
  250         doc=
"""Number of principal components to use for Pca basis, including the 
  251                  mean kernel if requested.""",
 
  253         check=
lambda x: x >= 3
 
  255     singleKernelClipping = pexConfig.Field(
 
  257         doc=
"Do sigma clipping on each raw kernel candidate",
 
  260     kernelSumClipping = pexConfig.Field(
 
  262         doc=
"Do sigma clipping on the ensemble of kernel sums",
 
  265     spatialKernelClipping = pexConfig.Field(
 
  267         doc=
"Do sigma clipping after building the spatial model",
 
  270     checkConditionNumber = pexConfig.Field(
 
  272         doc=
"""Test for maximum condition number when inverting a kernel matrix. 
  273                  Anything above maxConditionNumber is not used and the candidate is set as BAD. 
  274                  Also used to truncate inverse matrix in estimateBiasedRisk.  However, 
  275                  if you are doing any deconvolution you will want to turn this off, or use 
  276                  a large maxConditionNumber""",
 
  279     badMaskPlanes = pexConfig.ListField(
 
  281         doc=
"""Mask planes to ignore when calculating diffim statistics 
  282                  Options: NO_DATA EDGE SAT BAD CR INTRP""",
 
  283         default=(
"NO_DATA", 
"EDGE", 
"SAT")
 
  285     candidateResidualMeanMax = pexConfig.Field(
 
  287         doc=
"""Rejects KernelCandidates yielding bad difference image quality. 
  288                  Used by BuildSingleKernelVisitor, AssessSpatialKernelVisitor. 
  289                  Represents average over pixels of (image/sqrt(variance)).""",
 
  291         check=
lambda x: x >= 0.0
 
  293     candidateResidualStdMax = pexConfig.Field(
 
  295         doc=
"""Rejects KernelCandidates yielding bad difference image quality. 
  296                  Used by BuildSingleKernelVisitor, AssessSpatialKernelVisitor. 
  297                  Represents stddev over pixels of (image/sqrt(variance)).""",
 
  299         check=
lambda x: x >= 0.0
 
  301     useCoreStats = pexConfig.Field(
 
  303         doc=
"""Use the core of the footprint for the quality statistics, instead of the entire footprint. 
  304                  WARNING: if there is deconvolution we probably will need to turn this off""",
 
  307     candidateCoreRadius = pexConfig.Field(
 
  309         doc=
"""Radius for calculation of stats in 'core' of KernelCandidate diffim. 
  310                  Total number of pixels used will be (2*radius)**2. 
  311                  This is used both for 'core' diffim quality as well as ranking of 
  312                  KernelCandidates by their total flux in this core""",
 
  314         check=
lambda x: x >= 1
 
  316     maxKsumSigma = pexConfig.Field(
 
  318         doc=
"""Maximum allowed sigma for outliers from kernel sum distribution. 
  319                  Used to reject variable objects from the kernel model""",
 
  321         check=
lambda x: x >= 0.0
 
  323     maxConditionNumber = pexConfig.Field(
 
  325         doc=
"Maximum condition number for a well conditioned matrix",
 
  327         check=
lambda x: x >= 0.0
 
  329     conditionNumberType = pexConfig.ChoiceField(
 
  331         doc=
"Use singular values (SVD) or eigen values (EIGENVALUE) to determine condition number",
 
  332         default=
"EIGENVALUE",
 
  334             "SVD": 
"Use singular values",
 
  335             "EIGENVALUE": 
"Use eigen values (faster)",
 
  338     maxSpatialConditionNumber = pexConfig.Field(
 
  340         doc=
"Maximum condition number for a well conditioned spatial matrix",
 
  342         check=
lambda x: x >= 0.0
 
  344     iterateSingleKernel = pexConfig.Field(
 
  346         doc=
"""Remake KernelCandidate using better variance estimate after first pass? 
  347                  Primarily useful when convolving a single-depth image, otherwise not necessary.""",
 
  350     constantVarianceWeighting = pexConfig.Field(
 
  352         doc=
"""Use constant variance weighting in single kernel fitting? 
  353                  In some cases this is better for bright star residuals.""",
 
  356     calculateKernelUncertainty = pexConfig.Field(
 
  358         doc=
"""Calculate kernel and background uncertainties for each kernel candidate? 
  359                  This comes from the inverse of the covariance matrix. 
  360                  Warning: regularization can cause problems for this step.""",
 
  363     useBicForKernelBasis = pexConfig.Field(
 
  365         doc=
"""Use Bayesian Information Criterion to select the number of bases going into the kernel""",
 
  371     """The parameters specific to the "Alard-Lupton" (sum-of-Gaussian) Psf-matching basis""" 
  374         PsfMatchConfig.setDefaults(self)
 
  378     alardNGauss = pexConfig.Field(
 
  380         doc=
"Number of base Gaussians in alard-lupton kernel basis function generation.",
 
  382         check=
lambda x: x >= 1
 
  384     alardDegGauss = pexConfig.ListField(
 
  386         doc=
"Polynomial order of spatial modification of base Gaussians. " 
  387             "List length must be `alardNGauss`.",
 
  390     alardSigGauss = pexConfig.ListField(
 
  392         doc=
"Default sigma values in pixels of base Gaussians. " 
  393             "List length must be `alardNGauss`.",
 
  394         default=(0.7, 1.5, 3.0),
 
  396     alardGaussBeta = pexConfig.Field(
 
  398         doc=
"Used if `scaleByFwhm==True`, scaling multiplier of base " 
  399             "Gaussian sigmas for automated sigma determination",
 
  401         check=
lambda x: x >= 0.0,
 
  403     alardMinSig = pexConfig.Field(
 
  405         doc=
"Used if `scaleByFwhm==True`, minimum sigma (pixels) for base Gaussians",
 
  407         check=
lambda x: x >= 0.25
 
  409     alardDegGaussDeconv = pexConfig.Field(
 
  411         doc=
"Used if `scaleByFwhm==True`, degree of spatial modification of ALL base Gaussians " 
  412             "in AL basis during deconvolution",
 
  414         check=
lambda x: x >= 1
 
  416     alardMinSigDeconv = pexConfig.Field(
 
  418         doc=
"Used if `scaleByFwhm==True`, minimum sigma (pixels) for base Gaussians during deconvolution; " 
  419             "make smaller than `alardMinSig` as this is only indirectly used",
 
  421         check=
lambda x: x >= 0.25
 
  423     alardNGaussDeconv = pexConfig.Field(
 
  425         doc=
"Used if `scaleByFwhm==True`, number of base Gaussians in AL basis during deconvolution",
 
  427         check=
lambda x: x >= 1
 
  432     """The parameters specific to the delta-function (one basis per-pixel) Psf-matching basis""" 
  435         PsfMatchConfig.setDefaults(self)
 
  442     useRegularization = pexConfig.Field(
 
  444         doc=
"Use regularization to smooth the delta function kernels",
 
  447     regularizationType = pexConfig.ChoiceField(
 
  449         doc=
"Type of regularization.",
 
  450         default=
"centralDifference",
 
  452             "centralDifference": 
"Penalize second derivative using 2-D stencil of central finite difference",
 
  453             "forwardDifference": 
"Penalize first, second, third derivatives using forward finite differeces" 
  456     centralRegularizationStencil = pexConfig.ChoiceField(
 
  458         doc=
"Type of stencil to approximate central derivative (for centralDifference only)",
 
  461             5: 
"5-point stencil including only adjacent-in-x,y elements",
 
  462             9: 
"9-point stencil including diagonal elements" 
  465     forwardRegularizationOrders = pexConfig.ListField(
 
  467         doc=
"Array showing which order derivatives to penalize (for forwardDifference only)",
 
  469         itemCheck=
lambda x: (x > 0) 
and (x < 4)
 
  471     regularizationBorderPenalty = pexConfig.Field(
 
  473         doc=
"Value of the penalty for kernel border pixels",
 
  475         check=
lambda x: x >= 0.0
 
  477     lambdaType = pexConfig.ChoiceField(
 
  479         doc=
"How to choose the value of the regularization strength",
 
  482             "absolute": 
"Use lambdaValue as the value of regularization strength",
 
  483             "relative": 
"Use lambdaValue as fraction of the default regularization strength (N.R. 18.5.8)",
 
  484             "minimizeBiasedRisk": 
"Minimize biased risk estimate",
 
  485             "minimizeUnbiasedRisk": 
"Minimize unbiased risk estimate",
 
  488     lambdaValue = pexConfig.Field(
 
  490         doc=
"Value used for absolute determinations of regularization strength",
 
  493     lambdaScaling = pexConfig.Field(
 
  495         doc=
"Fraction of the default lambda strength (N.R. 18.5.8) to use.  1e-4 or 1e-5",
 
  498     lambdaStepType = pexConfig.ChoiceField(
 
  500         doc=
"""If a scan through lambda is needed (minimizeBiasedRisk, minimizeUnbiasedRisk), 
  501                  use log or linear steps""",
 
  504             "log": 
"Step in log intervals; e.g. lambdaMin, lambdaMax, lambdaStep = -1.0, 2.0, 0.1",
 
  505             "linear": 
"Step in linear intervals; e.g. lambdaMin, lambdaMax, lambdaStep = 0.1, 100, 0.1",
 
  508     lambdaMin = pexConfig.Field(
 
  510         doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk), 
  511                  start at this value.  If lambdaStepType = log:linear, suggest -1:0.1""",
 
  514     lambdaMax = pexConfig.Field(
 
  516         doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk), 
  517                  stop at this value.  If lambdaStepType = log:linear, suggest 2:100""",
 
  520     lambdaStep = pexConfig.Field(
 
  522         doc=
"""If scan through lambda needed (minimizeBiasedRisk, minimizeUnbiasedRisk), 
  523                  step in these increments.  If lambdaStepType = log:linear, suggest 0.1:0.1""",
 
  529     """Base class for Psf Matching; should not be called directly 
  533     PsfMatchTask is a base class that implements the core functionality for matching the 
  534     Psfs of two images using a spatially varying Psf-matching `lsst.afw.math.LinearCombinationKernel`. 
  535     The Task requires the user to provide an instance of an `lsst.afw.math.SpatialCellSet`, 
  536     filled with `lsst.ip.diffim.KernelCandidate` instances, and a list of `lsst.afw.math.Kernels` 
  537     of basis shapes that will be used for the decomposition.  If requested, the Task 
  538     also performs background matching and returns the differential background model as an 
  539     `lsst.afw.math.Kernel.SpatialFunction`. 
  541     **Invoking the Task** 
  543     As a base class, this Task is not directly invoked.  However, ``run()`` methods that are 
  544     implemented on derived classes will make use of the core ``_solve()`` functionality, 
  545     which defines a sequence of `lsst.afw.math.CandidateVisitor` classes that iterate 
  546     through the KernelCandidates, first building up a per-candidate solution and then 
  547     building up a spatial model from the ensemble of candidates.  Sigma clipping is 
  548     performed using the mean and standard deviation of all kernel sums (to reject 
  549     variable objects), on the per-candidate substamp diffim residuals 
  550     (to indicate a bad choice of kernel basis shapes for that particular object), 
  551     and on the substamp diffim residuals using the spatial kernel fit (to indicate a bad 
  552     choice of spatial kernel order, or poor constraints on the spatial model).  The 
  553     ``_diagnostic()`` method logs information on the quality of the spatial fit, and also 
  554     modifies the Task metadata. 
  556     .. list-table:: Quantities set in Metadata 
  561        * - ``spatialConditionNum`` 
  562          - Condition number of the spatial kernel fit 
  563        * - ``spatialKernelSum`` 
  564          - Kernel sum (10^{-0.4 * ``Delta``; zeropoint}) of the spatial Psf-matching kernel 
  565        * - ``ALBasisNGauss`` 
  566          - If using sum-of-Gaussian basis, the number of gaussians used 
  567        * - ``ALBasisDegGauss`` 
  568          - If using sum-of-Gaussian basis, the deg of spatial variation of the Gaussians 
  569        * - ``ALBasisSigGauss`` 
  570          - If using sum-of-Gaussian basis, the widths (sigma) of the Gaussians 
  572          - If using sum-of-Gaussian basis, the kernel size 
  573        * - ``NFalsePositivesTotal`` 
  574          - Total number of diaSources 
  575        * - ``NFalsePositivesRefAssociated`` 
  576          - Number of diaSources that associate with the reference catalog 
  577        * - ``NFalsePositivesRefAssociated`` 
  578          - Number of diaSources that associate with the source catalog 
  579        * - ``NFalsePositivesUnassociated`` 
  580          - Number of diaSources that are orphans 
  582          - Mean value of substamp diffim quality metrics across all KernelCandidates, 
  583            for both the per-candidate (LOCAL) and SPATIAL residuals 
  584        * - ``metric_MEDIAN`` 
  585          - Median value of substamp diffim quality metrics across all KernelCandidates, 
  586            for both the per-candidate (LOCAL) and SPATIAL residuals 
  588          - Standard deviation of substamp diffim quality metrics across all KernelCandidates, 
  589            for both the per-candidate (LOCAL) and SPATIAL residuals 
  593     The `lsst.pipe.base.cmdLineTask.CmdLineTask` command line task interface supports a 
  594     flag -d/--debug to import @b debug.py from your PYTHONPATH.  The relevant contents of debug.py 
  595     for this Task include: 
  602             di = lsstDebug.getInfo(name) 
  603             if name == "lsst.ip.diffim.psfMatch": 
  604                 # enable debug output 
  606                 # display mask transparency 
  607                 di.maskTransparency = 80 
  608                 # show all the candidates and residuals 
  609                 di.displayCandidates = True 
  610                 # show kernel basis functions 
  611                 di.displayKernelBasis = False 
  612                 # show kernel realized across the image 
  613                 di.displayKernelMosaic = True 
  614                 # show coefficients of spatial model 
  615                 di.plotKernelSpatialModel = False 
  616                 # show fixed and spatial coefficients and coefficient histograms 
  617                 di.plotKernelCoefficients = True 
  618                 # show the bad candidates (red) along with good (green) 
  619                 di.showBadCandidates = True 
  621         lsstDebug.Info = DebugInfo 
  624     Note that if you want additional logging info, you may add to your scripts: 
  628         import lsst.log.utils as logUtils 
  629         logUtils.traceSetAt("lsst.ip.diffim", 4) 
  631     ConfigClass = PsfMatchConfig
 
  632     _DefaultName = 
"psfMatch" 
  635         """Create the psf-matching Task 
  640             Arguments to be passed to ``lsst.pipe.base.task.Task.__init__`` 
  642             Keyword arguments to be passed to ``lsst.pipe.base.task.Task.__init__`` 
  646         The initialization sets the Psf-matching kernel configuration using the value of 
  647         self.config.kernel.active.  If the kernel is requested with regularization to moderate 
  648         the bias/variance tradeoff, currently only used when a delta function kernel basis 
  649         is provided, it creates a regularization matrix stored as member variable 
  652         pipeBase.Task.__init__(self, *args, **kwargs)
 
  653         self.
kConfigkConfig = self.config.kernel.active
 
  655         if 'useRegularization' in self.
kConfigkConfig:
 
  661             self.
hMathMat = diffimLib.makeRegularizationMatrix(pexConfig.makePropertySet(self.
kConfigkConfig))
 
  663     def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg):
 
  664         """Provide logging diagnostics on quality of spatial kernel fit 
  668         kernelCellSet : `lsst.afw.math.SpatialCellSet` 
  669             Cellset that contains the KernelCandidates used in the fitting 
  670         spatialSolution : `lsst.ip.diffim.SpatialKernelSolution` 
  671             KernelSolution of best-fit 
  672         spatialKernel : `lsst.afw.math.LinearCombinationKernel` 
  673             Best-fit spatial Kernel model 
  674         spatialBg : `lsst.afw.math.Function2D` 
  675             Best-fit spatial background model 
  678         kImage = afwImage.ImageD(spatialKernel.getDimensions())
 
  679         kSum = spatialKernel.computeImage(kImage, 
False)
 
  680         self.log.
info(
"Final spatial kernel sum %.3f", kSum)
 
  683         conditionNum = spatialSolution.getConditionNumber(
 
  684             getattr(diffimLib.KernelSolution, self.
kConfigkConfig.conditionNumberType))
 
  685         self.log.
info(
"Spatial model condition number %.3e", conditionNum)
 
  687         if conditionNum < 0.0:
 
  688             self.log.
warning(
"Condition number is negative (%.3e)", conditionNum)
 
  689         if conditionNum > self.
kConfigkConfig.maxSpatialConditionNumber:
 
  690             self.log.
warning(
"Spatial solution exceeds max condition number (%.3e > %.3e)",
 
  691                              conditionNum, self.
kConfigkConfig.maxSpatialConditionNumber)
 
  693         self.metadata[
"spatialConditionNum"] = conditionNum
 
  694         self.metadata[
"spatialKernelSum"] = kSum
 
  697         nBasisKernels = spatialKernel.getNBasisKernels()
 
  698         nKernelTerms = spatialKernel.getNSpatialParameters()
 
  699         if nKernelTerms == 0:  
 
  703         nBgTerms = spatialBg.getNParameters()
 
  705             if spatialBg.getParameters()[0] == 0.0:
 
  711         for cell 
in kernelCellSet.getCellList():
 
  712             for cand 
in cell.begin(
False):  
 
  714                 if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
 
  716                 if cand.getStatus() == afwMath.SpatialCellCandidate.BAD:
 
  719         self.log.
info(
"Doing stats of kernel candidates used in the spatial fit.")
 
  723             self.log.
warning(
"Many more candidates rejected than accepted; %d total, %d rejected, %d used",
 
  726             self.log.
info(
"%d candidates total, %d rejected, %d used", nTot, nBad, nGood)
 
  729         if nGood < nKernelTerms:
 
  730             self.log.
warning(
"Spatial kernel model underconstrained; %d candidates, %d terms, %d bases",
 
  731                              nGood, nKernelTerms, nBasisKernels)
 
  732             self.log.
warning(
"Consider lowering the spatial order")
 
  733         elif nGood <= 2*nKernelTerms:
 
  734             self.log.
warning(
"Spatial kernel model poorly constrained; %d candidates, %d terms, %d bases",
 
  735                              nGood, nKernelTerms, nBasisKernels)
 
  736             self.log.
warning(
"Consider lowering the spatial order")
 
  738             self.log.
info(
"Spatial kernel model well constrained; %d candidates, %d terms, %d bases",
 
  739                           nGood, nKernelTerms, nBasisKernels)
 
  742             self.log.
warning(
"Spatial background model underconstrained; %d candidates, %d terms",
 
  744             self.log.
warning(
"Consider lowering the spatial order")
 
  745         elif nGood <= 2*nBgTerms:
 
  746             self.log.
warning(
"Spatial background model poorly constrained; %d candidates, %d terms",
 
  748             self.log.
warning(
"Consider lowering the spatial order")
 
  750             self.log.
info(
"Spatial background model appears well constrained; %d candidates, %d terms",
 
  753     def _displayDebug(self, kernelCellSet, spatialKernel, spatialBackground):
 
  754         """Provide visualization of the inputs and ouputs to the Psf-matching code 
  758         kernelCellSet : `lsst.afw.math.SpatialCellSet` 
  759             The SpatialCellSet used in determining the matching kernel and background 
  760         spatialKernel : `lsst.afw.math.LinearCombinationKernel` 
  761             Spatially varying Psf-matching kernel 
  762         spatialBackground : `lsst.afw.math.Function2D` 
  763             Spatially varying background-matching function 
  768         displayKernelMosaic = 
lsstDebug.Info(__name__).displayKernelMosaic
 
  769         plotKernelSpatialModel = 
lsstDebug.Info(__name__).plotKernelSpatialModel
 
  770         plotKernelCoefficients = 
lsstDebug.Info(__name__).plotKernelCoefficients
 
  773         if not maskTransparency:
 
  775         afwDisplay.setDefaultMaskTransparency(maskTransparency)
 
  777         if displayCandidates:
 
  778             diutils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
 
  779                                          frame=lsstDebug.frame,
 
  780                                          showBadCandidates=showBadCandidates)
 
  782             diutils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
 
  783                                          frame=lsstDebug.frame,
 
  784                                          showBadCandidates=showBadCandidates,
 
  787             diutils.showKernelCandidates(kernelCellSet, kernel=spatialKernel, background=spatialBackground,
 
  788                                          frame=lsstDebug.frame,
 
  789                                          showBadCandidates=showBadCandidates,
 
  793         if displayKernelBasis:
 
  794             diutils.showKernelBasis(spatialKernel, frame=lsstDebug.frame)
 
  797         if displayKernelMosaic:
 
  798             diutils.showKernelMosaic(kernelCellSet.getBBox(), spatialKernel, frame=lsstDebug.frame)
 
  801         if plotKernelSpatialModel:
 
  802             diutils.plotKernelSpatialModel(spatialKernel, kernelCellSet, showBadCandidates=showBadCandidates)
 
  804         if plotKernelCoefficients:
 
  805             diutils.plotKernelCoefficients(spatialKernel, kernelCellSet)
 
  807     def _createPcaBasis(self, kernelCellSet, nStarPerCell, ps):
 
  808         """Create Principal Component basis 
  810         If a principal component analysis is requested, typically when using a delta function basis, 
  811         perform the PCA here and return a new basis list containing the new principal components. 
  815         kernelCellSet : `lsst.afw.math.SpatialCellSet` 
  816             a SpatialCellSet containing KernelCandidates, from which components are derived 
  818             the number of stars per cell to visit when doing the PCA 
  819         ps : `lsst.daf.base.PropertySet` 
  820             input property set controlling the single kernel visitor 
  825             number of KernelCandidates rejected during PCA loop 
  826         spatialBasisList : `list` of `lsst.afw.math.kernel.FixedKernel` 
  827             basis list containing the principal shapes as Kernels 
  832             If the Eigenvalues sum to zero. 
  834         nComponents = self.
kConfigkConfig.numPrincipalComponents
 
  835         imagePca = diffimLib.KernelPcaD()
 
  836         importStarVisitor = diffimLib.KernelPcaVisitorF(imagePca)
 
  837         kernelCellSet.visitCandidates(importStarVisitor, nStarPerCell)
 
  838         if self.
kConfigkConfig.subtractMeanForPca:
 
  839             importStarVisitor.subtractMean()
 
  842         eigenValues = imagePca.getEigenValues()
 
  843         pcaBasisList = importStarVisitor.getEigenKernels()
 
  845         eSum = np.sum(eigenValues)
 
  847             raise RuntimeError(
"Eigenvalues sum to zero")
 
  848         for j 
in range(len(eigenValues)):
 
  849             log.log(
"TRACE5." + self.log.name + 
"._solve", log.DEBUG,
 
  850                     "Eigenvalue %d : %f (%f)", j, eigenValues[j], eigenValues[j]/eSum)
 
  852         nToUse = 
min(nComponents, len(eigenValues))
 
  854         for j 
in range(nToUse):
 
  856             kimage = afwImage.ImageD(pcaBasisList[j].getDimensions())
 
  857             pcaBasisList[j].computeImage(kimage, 
False)
 
  858             if not (
True in np.isnan(kimage.getArray())):
 
  859                 trimBasisList.append(pcaBasisList[j])
 
  862         spatialBasisList = diffimLib.renormalizeKernelList(trimBasisList)
 
  865         singlekvPca = diffimLib.BuildSingleKernelVisitorF(spatialBasisList, ps)
 
  866         singlekvPca.setSkipBuilt(
False)
 
  867         kernelCellSet.visitCandidates(singlekvPca, nStarPerCell)
 
  868         singlekvPca.setSkipBuilt(
True)
 
  869         nRejectedPca = singlekvPca.getNRejected()
 
  871         return nRejectedPca, spatialBasisList
 
  873     def _buildCellSet(self, *args):
 
  874         """Fill a SpatialCellSet with KernelCandidates for the Psf-matching process; 
  875         override in derived classes""" 
  879     def _solve(self, kernelCellSet, basisList, returnOnExcept=False):
 
  880         """Solve for the PSF matching kernel 
  884         kernelCellSet : `lsst.afw.math.SpatialCellSet` 
  885             a SpatialCellSet to use in determining the matching kernel 
  886              (typically as provided by _buildCellSet) 
  887         basisList : `list` of `lsst.afw.math.kernel.FixedKernel` 
  888             list of Kernels to be used in the decomposition of the spatially varying kernel 
  889             (typically as provided by makeKernelBasisList) 
  890         returnOnExcept : `bool`, optional 
  891             if True then return (None, None) if an error occurs, else raise the exception 
  895         psfMatchingKernel : `lsst.afw.math.LinearCombinationKernel` 
  896             Spatially varying Psf-matching kernel 
  897         backgroundModel : `lsst.afw.math.Function2D` 
  898             Spatially varying background-matching function 
  903             If unable to determine PSF matching kernel and ``returnOnExcept==False``. 
  909         maxSpatialIterations = self.
kConfigkConfig.maxSpatialIterations
 
  910         nStarPerCell = self.
kConfigkConfig.nStarPerCell
 
  911         usePcaForSpatialKernel = self.
kConfigkConfig.usePcaForSpatialKernel
 
  914         ps = pexConfig.makePropertySet(self.
kConfigkConfig)
 
  916             singlekv = diffimLib.BuildSingleKernelVisitorF(basisList, ps, self.
hMathMat)
 
  918             singlekv = diffimLib.BuildSingleKernelVisitorF(basisList, ps)
 
  921         ksv = diffimLib.KernelSumVisitorF(ps)
 
  928             while (thisIteration < maxSpatialIterations):
 
  932                 while (nRejectedSkf != 0):
 
  933                     log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
  934                             "Building single kernels...")
 
  935                     kernelCellSet.visitCandidates(singlekv, nStarPerCell)
 
  936                     nRejectedSkf = singlekv.getNRejected()
 
  937                     log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
  938                             "Iteration %d, rejected %d candidates due to initial kernel fit",
 
  939                             thisIteration, nRejectedSkf)
 
  943                 ksv.setMode(diffimLib.KernelSumVisitorF.AGGREGATE)
 
  944                 kernelCellSet.visitCandidates(ksv, nStarPerCell)
 
  945                 ksv.processKsumDistribution()
 
  946                 ksv.setMode(diffimLib.KernelSumVisitorF.REJECT)
 
  947                 kernelCellSet.visitCandidates(ksv, nStarPerCell)
 
  949                 nRejectedKsum = ksv.getNRejected()
 
  950                 log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
  951                         "Iteration %d, rejected %d candidates due to kernel sum",
 
  952                         thisIteration, nRejectedKsum)
 
  955                 if nRejectedKsum > 0:
 
  964                 if (usePcaForSpatialKernel):
 
  965                     log.log(
"TRACE0." + self.log.name + 
"._solve", log.DEBUG,
 
  966                             "Building Pca basis")
 
  968                     nRejectedPca, spatialBasisList = self.
_createPcaBasis_createPcaBasis(kernelCellSet, nStarPerCell, ps)
 
  969                     log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
  970                             "Iteration %d, rejected %d candidates due to Pca kernel fit",
 
  971                             thisIteration, nRejectedPca)
 
  982                     if (nRejectedPca > 0):
 
  986                     spatialBasisList = basisList
 
  989                 regionBBox = kernelCellSet.getBBox()
 
  990                 spatialkv = diffimLib.BuildSpatialKernelVisitorF(spatialBasisList, regionBBox, ps)
 
  991                 kernelCellSet.visitCandidates(spatialkv, nStarPerCell)
 
  992                 spatialkv.solveLinearEquation()
 
  993                 log.log(
"TRACE2." + self.log.name + 
"._solve", log.DEBUG,
 
  994                         "Spatial kernel built with %d candidates", spatialkv.getNCandidates())
 
  995                 spatialKernel, spatialBackground = spatialkv.getSolutionPair()
 
  998                 assesskv = diffimLib.AssessSpatialKernelVisitorF(spatialKernel, spatialBackground, ps)
 
  999                 kernelCellSet.visitCandidates(assesskv, nStarPerCell)
 
 1000                 nRejectedSpatial = assesskv.getNRejected()
 
 1001                 nGoodSpatial = assesskv.getNGood()
 
 1002                 log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
 1003                         "Iteration %d, rejected %d candidates due to spatial kernel fit",
 
 1004                         thisIteration, nRejectedSpatial)
 
 1005                 log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG,
 
 1006                         "%d candidates used in fit", nGoodSpatial)
 
 1009                 if nGoodSpatial == 0 
and nRejectedSpatial == 0:
 
 1010                     raise RuntimeError(
"No kernel candidates for spatial fit")
 
 1012                 if nRejectedSpatial == 0:
 
 1020             if (nRejectedSpatial > 0) 
and (thisIteration == maxSpatialIterations):
 
 1021                 log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG, 
"Final spatial fit")
 
 1022                 if (usePcaForSpatialKernel):
 
 1023                     nRejectedPca, spatialBasisList = self.
_createPcaBasis_createPcaBasis(kernelCellSet, nStarPerCell, ps)
 
 1024                 regionBBox = kernelCellSet.getBBox()
 
 1025                 spatialkv = diffimLib.BuildSpatialKernelVisitorF(spatialBasisList, regionBBox, ps)
 
 1026                 kernelCellSet.visitCandidates(spatialkv, nStarPerCell)
 
 1027                 spatialkv.solveLinearEquation()
 
 1028                 log.log(
"TRACE2." + self.log.name + 
"._solve", log.DEBUG,
 
 1029                         "Spatial kernel built with %d candidates", spatialkv.getNCandidates())
 
 1030                 spatialKernel, spatialBackground = spatialkv.getSolutionPair()
 
 1032             spatialSolution = spatialkv.getKernelSolution()
 
 1034         except Exception 
as e:
 
 1035             self.log.
error(
"ERROR: Unable to calculate psf matching kernel")
 
 1037             log.log(
"TRACE1." + self.log.name + 
"._solve", log.DEBUG, 
"%s", e)
 
 1041         log.log(
"TRACE0." + self.log.name + 
"._solve", log.DEBUG,
 
 1042                 "Total time to compute the spatial kernel : %.2f s", (t1 - t0))
 
 1045             self.
_displayDebug_displayDebug(kernelCellSet, spatialKernel, spatialBackground)
 
 1047         self.
_diagnostic_diagnostic(kernelCellSet, spatialSolution, spatialKernel, spatialBackground)
 
 1049         return spatialSolution, spatialKernel, spatialBackground
 
 1052 PsfMatch = PsfMatchTask
 
def __init__(self, *args, **kwargs)
 
def _createPcaBasis(self, kernelCellSet, nStarPerCell, ps)
 
def _displayDebug(self, kernelCellSet, spatialKernel, spatialBackground)
 
def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg)
 
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
 
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.