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",
81 self.
selectMeasurement.algorithms.names = (
'base_SdssCentroid',
'base_PsfFlux',
'base_PixelFlags',
82 'base_SdssShape',
'base_GaussianFlux',
'base_SkyCoord')
89 """Construct a kernel for PSF matching two exposures.
92 ConfigClass = MakeKernelConfig
93 _DefaultName = "makeALKernel"
96 PsfMatchTask.__init__(self, *args, **kwargs)
104 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
107 def run(self, template, science, kernelSources, preconvolved=False):
108 """Solve for the kernel and background model that best match two
109 Exposures evaluated at the given source locations.
114 Exposure that will be convolved.
116 The exposure that will be matched.
117 kernelSources : `list` of `dict`
118 A list of dicts having a "source" and "footprint"
119 field
for the Sources deemed to be appropriate
for Psf
120 matching. Can be the output
from ``selectKernelSources``.
121 preconvolved : `bool`, optional
122 Was the science image convolved
with its own PSF?
126 results : `lsst.pipe.base.Struct`
129 Spatially varying Psf-matching kernel.
130 ``backgroundModel`` : `lsst.afw.math.Function2D`
131 Spatially varying background-matching function.
141 templateFwhmPix = getPsfFwhm(template.psf)
142 scienceFwhmPix = getPsfFwhm(science.psf)
143 except InvalidParameterError:
144 self.log.debug(
"Unable to evaluate PSF at the average position. "
145 "Evaluting PSF on a grid of points."
147 templateFwhmPix = evaluateMeanPsfFwhm(template,
148 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
149 fwhmExposureGrid=self.config.fwhmExposureGrid
151 scienceFwhmPix = evaluateMeanPsfFwhm(science,
152 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
153 fwhmExposureGrid=self.config.fwhmExposureGrid
157 scienceFwhmPix *= np.sqrt(2)
159 metadata=self.metadata)
160 spatialSolution, psfMatchingKernel, backgroundModel = self.
_solve(kernelCellSet, basisList)
161 return lsst.pipe.base.Struct(
162 psfMatchingKernel=psfMatchingKernel,
163 backgroundModel=backgroundModel,
167 """Select sources from a list of candidates, and extract footprints.
172 Exposure that will be convolved.
174 The exposure that will be matched.
175 candidateList : `list`, optional
176 List of Sources to examine. Elements must be of type afw.table.Source
177 or a type that wraps a Source
and has a getSource() method, such
as
178 meas.algorithms.PsfCandidateF.
179 preconvolved : `bool`, optional
180 Was the science image convolved
with its own PSF?
184 kernelSources : `list` of `dict`
185 A list of dicts having a
"source" and "footprint"
186 field
for the Sources deemed to be appropriate
for Psf
196 templateFwhmPix = getPsfFwhm(template.psf)
197 scienceFwhmPix = getPsfFwhm(science.psf)
198 except InvalidParameterError:
199 self.log.debug(
"Unable to evaluate PSF at the average position. "
200 "Evaluting PSF on a grid of points."
202 templateFwhmPix = evaluateMeanPsfFwhm(template,
203 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
204 fwhmExposureGrid=self.config.fwhmExposureGrid
206 scienceFwhmPix = evaluateMeanPsfFwhm(science,
207 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
208 fwhmExposureGrid=self.config.fwhmExposureGrid
211 scienceFwhmPix *= np.sqrt(2)
214 candidateList=candidateList,
215 preconvolved=preconvolved)
219 """Get sources to use for Psf-matching.
221 This method runs detection and measurement on an exposure.
222 The returned set of sources will be used
as candidates
for
228 Exposure on which to run detection/measurement
229 sigma : `float`, optional
230 PSF sigma,
in pixels, used
for smoothing the image
for detection.
231 If `
None`, the PSF width will be used.
233 Whether
or not to smooth the Exposure
with Psf before detection
235 Factory
for the generation of Source ids
240 source catalog containing candidates
for the Psf-matching
246 mi = exposure.getMaskedImage()
248 imArr = mi.image.array
249 maskArr = mi.mask.array
250 miArr = np.ma.masked_array(imArr, mask=maskArr)
253 bkgd = fitBg.getImageF(self.
background.config.algorithm,
256 self.log.warning(
"Failed to get background model. Falling back to median background estimation")
257 bkgd = np.ma.median(miArr)
263 detRet = self.selectDetection.
run(
269 selectSources = detRet.sources
270 self.selectMeasurement.
run(measCat=selectSources, exposure=exposure)
278 candidateList=None, preconvolved=False):
279 """Make a list of acceptable KernelCandidates.
281 Accept or generate a list of candidate sources
for
282 Psf-matching,
and examine the Mask planes
in both of the
283 images
for indications of bad pixels
288 Exposure that will be convolved
290 Exposure that will be matched-to
292 Dimensions of the Psf-matching Kernel, used to grow detection footprints
293 candidateList : `list`, optional
294 List of Sources to examine. Elements must be of type afw.table.Source
295 or a type that wraps a Source
and has a getSource() method, such
as
296 meas.algorithms.PsfCandidateF.
297 preconvolved : `bool`, optional
298 Was the science exposure already convolved
with its PSF?
302 candidateList : `list` of `dict`
303 A list of dicts having a
"source" and "footprint"
304 field
for the Sources deemed to be appropriate
for Psf
310 If ``candidateList``
is empty
or contains incompatible types.
312 if candidateList
is None:
313 candidateList = self.
getSelectSources(scienceExposure, doSmooth=
not preconvolved)
315 if len(candidateList) < 1:
316 raise RuntimeError(
"No candidates in candidateList")
318 listTypes = set(type(x)
for x
in candidateList)
319 if len(listTypes) > 1:
320 raise RuntimeError(
"Candidate list contains mixed types: %s" % [t
for t
in listTypes])
324 candidateList[0].getSource()
325 except Exception
as e:
326 raise RuntimeError(f
"Candidate List is of type: {type(candidateList[0])} "
327 "Can only make candidate list from list of afwTable.SourceRecords, "
328 f
"measAlg.PsfCandidateF or other type with a getSource() method: {e}")
329 candidateList = [c.getSource()
for c
in candidateList]
331 candidateList = diffimTools.sourceToFootprintList(candidateList,
332 templateExposure, scienceExposure,
336 if len(candidateList) == 0:
337 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
341 def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None,
342 basisDegGauss=None, basisSigmaGauss=None, metadata=None):
343 """Wrapper to set log messages for
348 targetFwhmPix : `float`, optional
349 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
350 Not used for delta function basis sets.
351 referenceFwhmPix : `float`, optional
352 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
353 Not used
for delta function basis sets.
354 basisDegGauss : `list` of `int`, optional
355 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
356 Not used
for delta function basis sets.
357 basisSigmaGauss : `list` of `int`, optional
358 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
359 Not used
for delta function basis sets.
361 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
362 Not used
for delta function basis sets.
366 basisList: `list` of `lsst.afw.math.kernel.FixedKernel`
367 List of basis kernels.
370 targetFwhmPix=targetFwhmPix,
371 referenceFwhmPix=referenceFwhmPix,
372 basisDegGauss=basisDegGauss,
373 basisSigmaGauss=basisSigmaGauss,
375 if targetFwhmPix == referenceFwhmPix:
376 self.log.info(
"Target and reference psf fwhms are equal, falling back to config values")
377 elif referenceFwhmPix > targetFwhmPix:
378 self.log.info(
"Reference psf fwhm is the greater, normal convolution mode")
380 self.log.info(
"Target psf fwhm is the greater, deconvolution mode")
384 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
385 """Build a SpatialCellSet for use with the solve method.
390 MaskedImage to PSF-matched to scienceMaskedImage
392 Reference MaskedImage
393 candidateList : `list`
394 A list of footprints/maskedImages for kernel candidates;
396 - Currently supported: list of Footprints
or measAlg.PsfCandidateF
401 a SpatialCellSet
for use
with self.
_solve
406 If no `candidateList`
is supplied.
408 if not candidateList:
409 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
413 imageBBox = templateMaskedImage.getBBox()
414 imageBBox.clip(scienceMaskedImage.getBBox())
420 for cand
in candidateList:
422 bbox = cand.getBBox()
424 bbox = cand[
'footprint'].getBBox()
425 tmi = lsst.afw.image.MaskedImageF(templateMaskedImage, bbox)
426 smi = lsst.afw.image.MaskedImageF(scienceMaskedImage, bbox)
430 cand = cand[
'source']
431 xPos = cand.getCentroid()[0]
432 yPos = cand.getCentroid()[1]
433 cand = diffimLib.makeKernelCandidate(xPos, yPos, tmi, smi, ps)
435 self.log.debug(
"Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
436 kernelCellSet.insertCandidate(cand)
440 def _adaptCellSize(self, candidateList):
441 """NOT IMPLEMENTED YET.
445 candidateList : `list`
446 A list of footprints/maskedImages for kernel candidates;
450 sizeCellX, sizeCellY : `int`
451 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()
def selectKernelSources(self, template, science, candidateList=None, preconvolved=False)
def run(self, template, science, kernelSources, preconvolved=False)
def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, basisSigmaGauss=None, metadata=None)
def getSelectSources(self, exposure, sigma=None, doSmooth=True, idFactory=None)
def makeCandidateList(self, templateExposure, scienceExposure, kernelSize, candidateList=None, preconvolved=False)
def _adaptCellSize(self, candidateList)
def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList)
def __init__(self, *args, **kwargs)
def _buildCellSet(self, *args)
def _solve(self, kernelCellSet, basisList, returnOnExcept=False)