22__all__ = [
"MakeKernelConfig",
"MakeKernelTask"]
32from lsst.meas.algorithms
import SourceDetectionTask, SubtractBackgroundTask
38from .makeKernelBasisList
import makeKernelBasisList
39from .psfMatch
import PsfMatchConfig, PsfMatchTask, PsfMatchConfigAL, PsfMatchConfigDF
41from .
import diffimLib
42from .utils
import evaluateMeanPsfFwhm, getPsfFwhm
46 kernel = lsst.pex.config.ConfigChoiceField(
54 selectDetection = lsst.pex.config.ConfigurableField(
55 target=SourceDetectionTask,
56 doc=
"Initial detections used to feed stars to kernel fitting",
58 selectMeasurement = lsst.pex.config.ConfigurableField(
59 target=SingleFrameMeasurementTask,
60 doc=
"Initial measurements used to feed stars to kernel fitting",
62 fwhmExposureGrid = lsst.pex.config.Field(
63 doc=
"Grid size to compute the average PSF FWHM in an exposure",
67 fwhmExposureBuffer = lsst.pex.config.Field(
68 doc=
"Fractional buffer margin to be left out of all sides of the image during construction"
69 "of grid to compute average PSF FWHM in an exposure",
82 self.
selectMeasurement.algorithms.names = (
'base_SdssCentroid',
'base_PsfFlux',
'base_PixelFlags',
83 'base_SdssShape',
'base_GaussianFlux',
'base_SkyCoord',
84 'base_ClassificationSizeExtendedness')
91 """Construct a kernel for PSF matching two exposures.
94 ConfigClass = MakeKernelConfig
95 _DefaultName =
"makeALKernel"
101 self.
background = SubtractBackgroundTask(config=self.
kConfig.afwBackgroundConfig, name=
"background",
106 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
109 def run(self, template, science, kernelSources, preconvolved=False,
110 templateFwhmPix=None, scienceFwhmPix=None):
111 """Solve for the kernel and background model that best match two
112 Exposures evaluated at the given source locations.
116 template : `lsst.afw.image.Exposure`
117 Exposure that will be convolved.
118 science : `lsst.afw.image.Exposure`
119 The exposure that will be matched.
120 kernelSources : `lsst.afw.table.SourceCatalog`
121 Kernel candidate sources with appropriately sized footprints.
122 Typically the output of `MakeKernelTask.selectKernelSources`.
123 preconvolved : `bool`, optional
124 Was the science image convolved with its own PSF?
125 templateFwhmPix, scienceFwhmPix : `float` or `None`, optional
126 FWHM of the template or science PSF, in pixels.
127 Will be recalculated if not specified.
131 results : `lsst.pipe.base.Struct`
133 ``psfMatchingKernel`` : `lsst.afw.math.LinearCombinationKernel`
134 Spatially varying Psf-matching kernel.
135 ``backgroundModel`` : `lsst.afw.math.Function2D`
136 Spatially varying background-matching function.
138 kernelCellSet = self.
_buildCellSet(template.maskedImage, science.maskedImage, kernelSources)
139 templateFwhmPix, scienceFwhmPix = self.
_checkPsfWidths(template, science,
140 templateFwhmPix, scienceFwhmPix,
141 preconvolved=preconvolved)
143 metadata=self.metadata)
144 spatialSolution, psfMatchingKernel, backgroundModel = self.
_solve(kernelCellSet, basisList)
145 return lsst.pipe.base.Struct(
146 psfMatchingKernel=psfMatchingKernel,
147 backgroundModel=backgroundModel,
151 templateFwhmPix=None, scienceFwhmPix=None):
152 """Select sources from a list of candidates, and extract footprints.
156 template : `lsst.afw.image.Exposure`
157 Exposure that will be convolved.
158 science : `lsst.afw.image.Exposure`
159 The exposure that will be matched.
160 candidateList : `lsst.afw.table.SourceCatalog`
161 Sources to check as possible kernel candidates.
162 preconvolved : `bool`, optional
163 Was the science image convolved with its own PSF?
164 templateFwhmPix, scienceFwhmPix : `float` or `None`, optional
165 FWHM of the template or science PSF, in pixels.
166 Will be recalculated if not specified.
170 kernelSources : `lsst.afw.table.SourceCatalog`
171 Kernel candidates with appropriate sized footprints.
173 templateFwhmPix, scienceFwhmPix = self.
_checkPsfWidths(template, science,
174 templateFwhmPix, scienceFwhmPix,
175 preconvolved=preconvolved)
178 candidateList=candidateList,
179 preconvolved=preconvolved)
183 """Get sources to use for Psf-matching.
185 This method runs detection and measurement on an exposure.
186 The returned set of sources will be used as candidates for
191 exposure : `lsst.afw.image.Exposure`
192 Exposure on which to run detection/measurement
193 sigma : `float`, optional
194 PSF sigma, in pixels, used for smoothing the image for detection.
195 If `None`, the PSF width will be used.
197 Whether or not to smooth the Exposure with Psf before detection
198 idFactory : `lsst.afw.table.IdFactory`
199 Factory for the generation of Source ids
204 source catalog containing candidates for the Psf-matching
210 mi = exposure.getMaskedImage()
212 imArr = mi.image.array
213 maskArr = mi.mask.array
214 miArr = np.ma.masked_array(imArr, mask=maskArr)
217 bkgd = fitBg.getImageF(self.
background.config.algorithm,
220 self.log.warning(
"Failed to get background model. Falling back to median background estimation")
221 bkgd = np.ma.median(miArr)
227 detRet = self.selectDetection.
run(
233 selectSources = detRet.sources
234 self.selectMeasurement.
run(measCat=selectSources, exposure=exposure)
240 self.log.info(
"Selected %d sources via detection measurement.", len(selectSources))
244 candidateList, preconvolved=False, sigma=None):
245 """Make a list of acceptable KernelCandidates.
247 Generate a list of candidate sources for Psf-matching, remove sources
248 with bad pixel masks set or that extend off the image.
252 convolved : `lsst.afw.image.Exposure`
253 Exposure that will be convolved. This is typically the template
254 image, and may have a large bbox than the reference exposure.
255 reference : `lsst.afw.image.Exposure`
256 Exposure that will be matched-to. This is typically the science
259 Dimensions of the Psf-matching Kernel, used to set detection
261 candidateList : `lsst.afw.table.SourceCatalog`
262 List of Sources to examine for kernel candidacy.
263 preconvolved : `bool`, optional
264 Was the science exposure already convolved with its PSF?
268 candidates : `lsst.afw.table.SourceCatalog`
269 Candidates with footprints extended to a ``kernelSize`` box.
274 If ``candidateList`` is empty after sub-selection.
276 if candidateList
is None:
277 candidateList = self.
getSelectSources(reference, doSmooth=
not preconvolved, sigma=sigma)
278 if len(candidateList) < 1:
279 raise RuntimeError(
"No kernel candidates after detection and measurement.")
281 bitmask = reference.mask.getPlaneBitMask(self.config.badMaskPlanes)
282 good = np.ones(len(candidateList), dtype=bool)
284 for i, candidate
in enumerate(candidateList):
286 peak = candidate.getFootprint().getPeaks()[0]
287 size = 2*kernelSize + 1
291 boxFootprint.addPeak(peak.getFx(), peak.getFy(), peak.getPeakValue())
292 candidate.setFootprint(boxFootprint)
295 if not reference.getBBox().contains(bbox)
or not convolved.getBBox().contains(bbox):
299 if (reference.subset(bbox).mask.array & bitmask).any():
304 if (convolved.subset(bbox).mask.array & bitmask).any():
307 candidates = candidateList[good].copy(deep=
True)
309 self.log.info(
"Selected %d / %d sources as kernel candidates.", good.sum(), len(candidateList))
311 if len(candidates) < 1:
312 raise RuntimeError(
"No good kernel candidates available.")
316 def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None,
317 basisDegGauss=None, basisSigmaGauss=None, metadata=None):
318 """Wrapper to set log messages for
319 `lsst.ip.diffim.makeKernelBasisList`.
323 targetFwhmPix : `float`, optional
324 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
325 Not used for delta function basis sets.
326 referenceFwhmPix : `float`, optional
327 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
328 Not used for delta function basis sets.
329 basisDegGauss : `list` of `int`, optional
330 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
331 Not used for delta function basis sets.
332 basisSigmaGauss : `list` of `int`, optional
333 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
334 Not used for delta function basis sets.
335 metadata : `lsst.daf.base.PropertySet`, optional
336 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
337 Not used for delta function basis sets.
341 basisList: `list` of `lsst.afw.math.kernel.FixedKernel`
342 List of basis kernels.
344 basisList = makeKernelBasisList(self.
kConfig,
345 targetFwhmPix=targetFwhmPix,
346 referenceFwhmPix=referenceFwhmPix,
347 basisDegGauss=basisDegGauss,
348 basisSigmaGauss=basisSigmaGauss,
350 if targetFwhmPix == referenceFwhmPix:
351 self.log.info(
"Target and reference psf fwhms are equal, falling back to config values")
352 elif referenceFwhmPix > targetFwhmPix:
353 self.log.info(
"Reference psf fwhm is the greater, normal convolution mode")
355 self.log.info(
"Target psf fwhm is the greater, deconvolution mode")
360 """Build a SpatialCellSet for use with the solve method.
364 convolved : `lsst.afw.image.MaskedImage`
365 MaskedImage to PSF-matched to reference.
366 reference : `lsst.afw.image.MaskedImage`
367 Reference MaskedImage.
368 candidateList : `lsst.afw.table.SourceCatalog`
369 Kernel candidate sources with footprints.
373 kernelCellSet : `lsst.afw.math.SpatialCellSet`
374 A SpatialCellSet for use with self._solve.
378 imageBBox = convolved.getBBox()
379 imageBBox.clip(reference.getBBox())
383 candidateConfig = lsst.pex.config.makePropertySet(self.
kConfig)
385 for candidate
in candidateList:
386 bbox = candidate.getFootprint().getBBox()
387 templateCutout = lsst.afw.image.MaskedImageF(convolved, bbox)
388 scienceCutout = lsst.afw.image.MaskedImageF(reference, bbox)
390 kernelCandidate = diffimLib.makeKernelCandidate(candidate,
395 self.log.debug(
"Candidate %d at %.2f, %.2f rating=%f",
396 kernelCandidate.getId(),
397 kernelCandidate.getXCenter(),
398 kernelCandidate.getYCenter(),
399 kernelCandidate.getCandidateRating())
400 kernelCellSet.insertCandidate(kernelCandidate)
405 """NOT IMPLEMENTED YET.
409 candidateList : `list`
410 A list of footprints/maskedImages for kernel candidates;
414 sizeCellX, sizeCellY : `int`
415 New dimensions to use for the kernel.
419 def _checkPsfWidths(self, template, science, templateFwhmPix, scienceFwhmPix, preconvolved=False):
420 """Check the science and template FWHM.
424 template : `lsst.afw.image.Exposure`
425 Exposure that will be convolved.
426 science : `lsst.afw.image.Exposure`
427 The exposure that will be matched.
428 templateFwhmPix, scienceFwhmPix : `float` or `None`
429 FWHM of the template or science PSF, in pixels.
430 Will be recalculated if not specified.
431 preconvolved : `bool`, optional
432 Was the science image convolved with its own PSF?
436 templateFwhmPix, scienceFwhmPix : `float`
439 if (scienceFwhmPix
is None)
or (templateFwhmPix
is None):
447 templateFwhmPix = getPsfFwhm(template.psf)
448 scienceFwhmPix = getPsfFwhm(science.psf)
449 except (InvalidParameterError, RangeError):
450 self.log.debug(
"Unable to evaluate PSF at the average position. "
451 "Evaluting PSF on a grid of points."
453 templateFwhmPix = evaluateMeanPsfFwhm(template,
454 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
455 fwhmExposureGrid=self.config.fwhmExposureGrid
457 scienceFwhmPix = evaluateMeanPsfFwhm(science,
458 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
459 fwhmExposureGrid=self.config.fwhmExposureGrid
465 scienceFwhmPix *= np.sqrt(2)
466 return templateFwhmPix, scienceFwhmPix
static std::shared_ptr< SourceTable > make(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
static Schema makeMinimalSchema()
static Box2I makeCenteredBox(Point2D const ¢er, Extent const &size)
makeCandidateList(self, convolved, reference, kernelSize, candidateList, preconvolved=False, sigma=None)
run(self, template, science, kernelSources, preconvolved=False, templateFwhmPix=None, scienceFwhmPix=None)
_checkPsfWidths(self, template, science, templateFwhmPix, scienceFwhmPix, preconvolved=False)
__init__(self, *args, **kwargs)
_buildCellSet(self, convolved, reference, candidateList)
_adaptCellSize(self, candidateList)
makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)
selectKernelSources(self, template, science, candidateList=None, preconvolved=False, templateFwhmPix=None, scienceFwhmPix=None)
getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None)
_solve(self, kernelCellSet, basisList)