22__all__ = [
"MakeKernelConfig",
"MakeKernelTask"]
31from lsst.meas.algorithms
import SourceDetectionTask, SubtractBackgroundTask
37from .makeKernelBasisList
import makeKernelBasisList
38from .psfMatch
import PsfMatchConfig, PsfMatchTask, PsfMatchConfigAL, PsfMatchConfigDF
40from .
import diffimLib
41from .
import diffimTools
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')
90 """Construct a kernel for PSF matching two exposures.
93 ConfigClass = MakeKernelConfig
94 _DefaultName =
"makeALKernel"
97 PsfMatchTask.__init__(self, *args, **kwargs)
105 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
108 def run(self, template, science, kernelSources, preconvolved=False):
109 """Solve for the kernel and background model that best match two
110 Exposures evaluated at the given source locations.
114 template : `lsst.afw.image.Exposure`
115 Exposure that will be convolved.
116 science : `lsst.afw.image.Exposure`
117 The exposure that will be matched.
118 kernelSources : `list` of `dict`
119 A list of dicts having a "source" and "footprint"
120 field for the Sources deemed to be appropriate for Psf
121 matching. Can be the output from ``selectKernelSources``.
122 preconvolved : `bool`, optional
123 Was the science image convolved with its own PSF?
127 results : `lsst.pipe.base.Struct`
129 ``psfMatchingKernel`` : `lsst.afw.math.LinearCombinationKernel`
130 Spatially varying Psf-matching kernel.
131 ``backgroundModel`` : `lsst.afw.math.Function2D`
132 Spatially varying background-matching function.
142 templateFwhmPix = getPsfFwhm(template.psf)
143 scienceFwhmPix = getPsfFwhm(science.psf)
144 except InvalidParameterError:
145 self.
log.debug(
"Unable to evaluate PSF at the average position. "
146 "Evaluting PSF on a grid of points."
148 templateFwhmPix = evaluateMeanPsfFwhm(template,
149 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
150 fwhmExposureGrid=self.config.fwhmExposureGrid
152 scienceFwhmPix = evaluateMeanPsfFwhm(science,
153 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
154 fwhmExposureGrid=self.config.fwhmExposureGrid
158 scienceFwhmPix *= np.sqrt(2)
160 metadata=self.metadata)
161 spatialSolution, psfMatchingKernel, backgroundModel = self.
_solve(kernelCellSet, basisList)
162 return lsst.pipe.base.Struct(
163 psfMatchingKernel=psfMatchingKernel,
164 backgroundModel=backgroundModel,
168 """Select sources from a list of candidates, and extract footprints.
172 template : `lsst.afw.image.Exposure`
173 Exposure that will be convolved.
174 science : `lsst.afw.image.Exposure`
175 The exposure that will be matched.
176 candidateList : `list`, optional
177 List of Sources to examine. Elements must be of type afw.table.Source
178 or a type that wraps a Source and has a getSource() method, such as
179 meas.algorithms.PsfCandidateF.
180 preconvolved : `bool`, optional
181 Was the science image convolved with its own PSF?
185 kernelSources : `list` of `dict`
186 A list of dicts having a "source" and "footprint"
187 field for the Sources deemed to be appropriate for Psf
197 templateFwhmPix = getPsfFwhm(template.psf)
198 scienceFwhmPix = getPsfFwhm(science.psf)
199 except InvalidParameterError:
200 self.
log.debug(
"Unable to evaluate PSF at the average position. "
201 "Evaluting PSF on a grid of points."
203 templateFwhmPix = evaluateMeanPsfFwhm(template,
204 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
205 fwhmExposureGrid=self.config.fwhmExposureGrid
207 scienceFwhmPix = evaluateMeanPsfFwhm(science,
208 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
209 fwhmExposureGrid=self.config.fwhmExposureGrid
212 scienceFwhmPix *= np.sqrt(2)
215 candidateList=candidateList,
216 preconvolved=preconvolved)
220 """Get sources to use for Psf-matching.
222 This method runs detection and measurement on an exposure.
223 The returned set of sources will be used as candidates for
228 exposure : `lsst.afw.image.Exposure`
229 Exposure on which to run detection/measurement
230 sigma : `float`, optional
231 PSF sigma, in pixels, used for smoothing the image for detection.
232 If `None`, the PSF width will be used.
234 Whether or not to smooth the Exposure with Psf before detection
235 idFactory : `lsst.afw.table.IdFactory`
236 Factory for the generation of Source ids
241 source catalog containing candidates for the Psf-matching
247 mi = exposure.getMaskedImage()
249 imArr = mi.image.array
250 maskArr = mi.mask.array
251 miArr = np.ma.masked_array(imArr, mask=maskArr)
254 bkgd = fitBg.getImageF(self.
background.config.algorithm,
257 self.
log.
warning(
"Failed to get background model. Falling back to median background estimation")
258 bkgd = np.ma.median(miArr)
264 detRet = self.selectDetection.
run(
270 selectSources = detRet.sources
271 self.selectMeasurement.
run(measCat=selectSources, exposure=exposure)
279 candidateList=None, preconvolved=False):
280 """Make a list of acceptable KernelCandidates.
282 Accept or generate a list of candidate sources for
283 Psf-matching, and examine the Mask planes in both of the
284 images for indications of bad pixels
288 templateExposure : `lsst.afw.image.Exposure`
289 Exposure that will be convolved
290 scienceExposure : `lsst.afw.image.Exposure`
291 Exposure that will be matched-to
293 Dimensions of the Psf-matching Kernel, used to grow detection footprints
294 candidateList : `list`, optional
295 List of Sources to examine. Elements must be of type afw.table.Source
296 or a type that wraps a Source and has a getSource() method, such as
297 meas.algorithms.PsfCandidateF.
298 preconvolved : `bool`, optional
299 Was the science exposure already convolved with its PSF?
303 candidateList : `list` of `dict`
304 A list of dicts having a "source" and "footprint"
305 field for the Sources deemed to be appropriate for Psf
311 If ``candidateList`` is empty or contains incompatible types.
313 if candidateList
is None:
314 candidateList = self.
getSelectSources(scienceExposure, doSmooth=
not preconvolved)
316 if len(candidateList) < 1:
317 raise RuntimeError(
"No candidates in candidateList")
319 listTypes = set(type(x)
for x
in candidateList)
320 if len(listTypes) > 1:
321 raise RuntimeError(
"Candidate list contains mixed types: %s" % [t
for t
in listTypes])
325 candidateList[0].getSource()
326 except Exception
as e:
327 raise RuntimeError(f
"Candidate List is of type: {type(candidateList[0])} "
328 "Can only make candidate list from list of afwTable.SourceRecords, "
329 f
"measAlg.PsfCandidateF or other type with a getSource() method: {e}")
330 candidateList = [c.getSource()
for c
in candidateList]
332 candidateList = diffimTools.sourceToFootprintList(candidateList,
333 templateExposure, scienceExposure,
337 if len(candidateList) == 0:
338 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
342 def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None,
343 basisDegGauss=None, basisSigmaGauss=None, metadata=None):
344 """Wrapper to set log messages for
345 `lsst.ip.diffim.makeKernelBasisList`.
349 targetFwhmPix : `float`, optional
350 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
351 Not used for delta function basis sets.
352 referenceFwhmPix : `float`, optional
353 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
354 Not used for delta function basis sets.
355 basisDegGauss : `list` of `int`, optional
356 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
357 Not used for delta function basis sets.
358 basisSigmaGauss : `list` of `int`, optional
359 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
360 Not used for delta function basis sets.
361 metadata : `lsst.daf.base.PropertySet`, optional
362 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
363 Not used for delta function basis sets.
367 basisList: `list` of `lsst.afw.math.kernel.FixedKernel`
368 List of basis kernels.
371 targetFwhmPix=targetFwhmPix,
372 referenceFwhmPix=referenceFwhmPix,
373 basisDegGauss=basisDegGauss,
374 basisSigmaGauss=basisSigmaGauss,
376 if targetFwhmPix == referenceFwhmPix:
377 self.
log.
info(
"Target and reference psf fwhms are equal, falling back to config values")
378 elif referenceFwhmPix > targetFwhmPix:
379 self.
log.
info(
"Reference psf fwhm is the greater, normal convolution mode")
381 self.
log.
info(
"Target psf fwhm is the greater, deconvolution mode")
385 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
386 """Build a SpatialCellSet for use with the solve method.
390 templateMaskedImage : `lsst.afw.image.MaskedImage`
391 MaskedImage to PSF-matched to scienceMaskedImage
392 scienceMaskedImage : `lsst.afw.image.MaskedImage`
393 Reference MaskedImage
394 candidateList : `list`
395 A list of footprints/maskedImages for kernel candidates;
397 - Currently supported: list of Footprints or measAlg.PsfCandidateF
401 kernelCellSet : `lsst.afw.math.SpatialCellSet`
402 a SpatialCellSet for use with self._solve
407 If no `candidateList` is supplied.
409 if not candidateList:
410 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
414 imageBBox = templateMaskedImage.getBBox()
415 imageBBox.clip(scienceMaskedImage.getBBox())
421 for cand
in candidateList:
423 bbox = cand.getBBox()
425 bbox = cand[
'footprint'].getBBox()
426 tmi = lsst.afw.image.MaskedImageF(templateMaskedImage, bbox)
427 smi = lsst.afw.image.MaskedImageF(scienceMaskedImage, bbox)
431 cand = cand[
'source']
432 xPos = cand.getCentroid()[0]
433 yPos = cand.getCentroid()[1]
434 cand = diffimLib.makeKernelCandidate(xPos, yPos, tmi, smi, ps)
436 self.
log.debug(
"Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
437 kernelCellSet.insertCandidate(cand)
442 """NOT IMPLEMENTED YET.
446 candidateList : `list`
447 A list of footprints/maskedImages for kernel candidates;
451 sizeCellX, sizeCellY : `int`
452 New dimensions to use for the kernel.
static std::shared_ptr< SourceTable > make(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
static Schema makeMinimalSchema()
Asseses the quality of a candidate given a spatial kernel and background model.
__init__(self, *args, **kwargs)
_buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList)
_adaptCellSize(self, candidateList)
makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)
selectKernelSources(self, template, science, candidateList=None, preconvolved=False)
run(self, template, science, kernelSources, preconvolved=False)
makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None, preconvolved=False)
getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None)
_solve(self, kernelCellSet, basisList, returnOnExcept=False)
_buildCellSet(self, *args)