22__all__ = [
"MakeKernelConfig",
"MakeKernelTask"]
31from lsst.meas.algorithms
import SourceDetectionTask, SubtractBackgroundTask
36from .makeKernelBasisList
import makeKernelBasisList
37from .psfMatch
import PsfMatchConfig, PsfMatchTask, PsfMatchConfigAL, PsfMatchConfigDF
39from .
import diffimLib
40from .
import diffimTools
41from .utils
import evaluateMeanPsfFwhm
45 kernel = lsst.pex.config.ConfigChoiceField(
53 selectDetection = lsst.pex.config.ConfigurableField(
54 target=SourceDetectionTask,
55 doc=
"Initial detections used to feed stars to kernel fitting",
57 selectMeasurement = lsst.pex.config.ConfigurableField(
58 target=SingleFrameMeasurementTask,
59 doc=
"Initial measurements used to feed stars to kernel fitting",
61 fwhmExposureGrid = lsst.pex.config.Field(
62 doc=
"Grid size to compute the average PSF FWHM in an exposure",
66 fwhmExposureBuffer = lsst.pex.config.Field(
67 doc=
"Fractional buffer margin to be left out of all sides of the image during construction"
68 "of grid to compute average PSF FWHM in an exposure",
80 self.
selectMeasurement.algorithms.names = (
'base_SdssCentroid',
'base_PsfFlux',
'base_PixelFlags',
81 'base_SdssShape',
'base_GaussianFlux',
'base_SkyCoord')
88 """Construct a kernel for PSF matching two exposures.
91 ConfigClass = MakeKernelConfig
92 _DefaultName = "makeALKernel"
95 PsfMatchTask.__init__(self, *args, **kwargs)
103 self.makeSubtask(
"selectDetection", schema=self.
selectSchema)
106 def run(self, template, science, kernelSources, preconvolved=False):
107 """Solve for the kernel and background model that best match two
108 Exposures evaluated at the given source locations.
113 Exposure that will be convolved.
115 The exposure that will be matched.
116 kernelSources : `list` of `dict`
117 A list of dicts having a "source" and "footprint"
118 field
for the Sources deemed to be appropriate
for Psf
119 matching. Can be the output
from ``selectKernelSources``.
120 preconvolved : `bool`, optional
121 Was the science image convolved
with its own PSF?
125 results : `lsst.pipe.base.Struct`
128 Spatially varying Psf-matching kernel.
129 ``backgroundModel`` : `lsst.afw.math.Function2D`
130 Spatially varying background-matching function.
133 templateFwhmPix = evaluateMeanPsfFwhm(template,
134 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
135 fwhmExposureGrid=self.config.fwhmExposureGrid
137 scienceFwhmPix = evaluateMeanPsfFwhm(science,
138 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
139 fwhmExposureGrid=self.config.fwhmExposureGrid
142 scienceFwhmPix *= np.sqrt(2)
144 metadata=self.metadata)
145 spatialSolution, psfMatchingKernel, backgroundModel = self.
_solve(kernelCellSet, basisList)
146 return lsst.pipe.base.Struct(
147 psfMatchingKernel=psfMatchingKernel,
148 backgroundModel=backgroundModel,
152 """Select sources from a list of candidates, and extract footprints.
157 Exposure that will be convolved.
159 The exposure that will be matched.
160 candidateList : `list`, optional
161 List of Sources to examine. Elements must be of type afw.table.Source
162 or a type that wraps a Source
and has a getSource() method, such
as
163 meas.algorithms.PsfCandidateF.
164 preconvolved : `bool`, optional
165 Was the science image convolved
with its own PSF?
169 kernelSources : `list` of `dict`
170 A list of dicts having a
"source" and "footprint"
171 field
for the Sources deemed to be appropriate
for Psf
174 templateFwhmPix = evaluateMeanPsfFwhm(template,
175 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
176 fwhmExposureGrid=self.config.fwhmExposureGrid
178 scienceFwhmPix = evaluateMeanPsfFwhm(science,
179 fwhmExposureBuffer=self.config.fwhmExposureBuffer,
180 fwhmExposureGrid=self.config.fwhmExposureGrid
183 scienceFwhmPix *= np.sqrt(2)
186 candidateList=candidateList,
187 preconvolved=preconvolved)
191 """Get sources to use for Psf-matching.
193 This method runs detection and measurement on an exposure.
194 The returned set of sources will be used
as candidates
for
200 Exposure on which to run detection/measurement
201 sigma : `float`, optional
202 PSF sigma,
in pixels, used
for smoothing the image
for detection.
203 If `
None`, the PSF width will be used.
205 Whether
or not to smooth the Exposure
with Psf before detection
207 Factory
for the generation of Source ids
212 source catalog containing candidates
for the Psf-matching
218 mi = exposure.getMaskedImage()
220 imArr = mi.getImage().getArray()
221 maskArr = mi.getMask().getArray()
222 miArr = np.ma.masked_array(imArr, mask=maskArr)
225 bkgd = fitBg.getImageF(self.
background.config.algorithm,
228 self.log.warning(
"Failed to get background model. Falling back to median background estimation")
229 bkgd = np.ma.median(miArr)
235 detRet = self.selectDetection.
run(
241 selectSources = detRet.sources
242 self.selectMeasurement.
run(measCat=selectSources, exposure=exposure)
250 candidateList=None, preconvolved=False):
251 """Make a list of acceptable KernelCandidates.
253 Accept or generate a list of candidate sources
for
254 Psf-matching,
and examine the Mask planes
in both of the
255 images
for indications of bad pixels
260 Exposure that will be convolved
262 Exposure that will be matched-to
264 Dimensions of the Psf-matching Kernel, used to grow detection footprints
265 candidateList : `list`, optional
266 List of Sources to examine. Elements must be of type afw.table.Source
267 or a type that wraps a Source
and has a getSource() method, such
as
268 meas.algorithms.PsfCandidateF.
269 preconvolved : `bool`, optional
270 Was the science exposure already convolved
with its PSF?
274 candidateList : `list` of `dict`
275 A list of dicts having a
"source" and "footprint"
276 field
for the Sources deemed to be appropriate
for Psf
282 If ``candidateList``
is empty
or contains incompatible types.
284 if candidateList
is None:
285 candidateList = self.
getSelectSources(scienceExposure, doSmooth=
not preconvolved)
287 if len(candidateList) < 1:
288 raise RuntimeError(
"No candidates in candidateList")
290 listTypes = set(type(x)
for x
in candidateList)
291 if len(listTypes) > 1:
292 raise RuntimeError(
"Candidate list contains mixed types: %s" % [t
for t
in listTypes])
296 candidateList[0].getSource()
297 except Exception
as e:
298 raise RuntimeError(f
"Candidate List is of type: {type(candidateList[0])} "
299 "Can only make candidate list from list of afwTable.SourceRecords, "
300 f
"measAlg.PsfCandidateF or other type with a getSource() method: {e}")
301 candidateList = [c.getSource()
for c
in candidateList]
303 candidateList = diffimTools.sourceToFootprintList(candidateList,
304 templateExposure, scienceExposure,
308 if len(candidateList) == 0:
309 raise RuntimeError(
"Cannot find any objects suitable for KernelCandidacy")
313 def makeKernelBasisList(self, targetFwhmPix=None, referenceFwhmPix=None,
314 basisDegGauss=None, basisSigmaGauss=None, metadata=None):
315 """Wrapper to set log messages for
320 targetFwhmPix : `float`, optional
321 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
322 Not used for delta function basis sets.
323 referenceFwhmPix : `float`, optional
324 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
325 Not used
for delta function basis sets.
326 basisDegGauss : `list` of `int`, optional
327 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
328 Not used
for delta function basis sets.
329 basisSigmaGauss : `list` of `int`, optional
330 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
331 Not used
for delta function basis sets.
333 Passed on to `lsst.ip.diffim.generateAlardLuptonBasisList`.
334 Not used
for delta function basis sets.
338 basisList: `list` of `lsst.afw.math.kernel.FixedKernel`
339 List of basis kernels.
342 targetFwhmPix=targetFwhmPix,
343 referenceFwhmPix=referenceFwhmPix,
344 basisDegGauss=basisDegGauss,
345 basisSigmaGauss=basisSigmaGauss,
347 if targetFwhmPix == referenceFwhmPix:
348 self.log.info(
"Target and reference psf fwhms are equal, falling back to config values")
349 elif referenceFwhmPix > targetFwhmPix:
350 self.log.info(
"Reference psf fwhm is the greater, normal convolution mode")
352 self.log.info(
"Target psf fwhm is the greater, deconvolution mode")
356 def _buildCellSet(self, templateMaskedImage, scienceMaskedImage, candidateList):
357 """Build a SpatialCellSet for use with the solve method.
362 MaskedImage to PSF-matched to scienceMaskedImage
364 Reference MaskedImage
365 candidateList : `list`
366 A list of footprints/maskedImages for kernel candidates;
368 - Currently supported: list of Footprints
or measAlg.PsfCandidateF
373 a SpatialCellSet
for use
with self.
_solve
378 If no `candidateList`
is supplied.
380 if not candidateList:
381 raise RuntimeError(
"Candidate list must be populated by makeCandidateList")
385 imageBBox = templateMaskedImage.getBBox()
386 imageBBox.clip(scienceMaskedImage.getBBox())
392 for cand
in candidateList:
394 bbox = cand.getBBox()
396 bbox = cand[
'footprint'].getBBox()
397 tmi = lsst.afw.image.MaskedImageF(templateMaskedImage, bbox)
398 smi = lsst.afw.image.MaskedImageF(scienceMaskedImage, bbox)
402 cand = cand[
'source']
403 xPos = cand.getCentroid()[0]
404 yPos = cand.getCentroid()[1]
405 cand = diffimLib.makeKernelCandidate(xPos, yPos, tmi, smi, ps)
407 self.log.debug(
"Candidate %d at %f, %f", cand.getId(), cand.getXCenter(), cand.getYCenter())
408 kernelCellSet.insertCandidate(cand)
412 def _adaptCellSize(self, candidateList):
413 """NOT IMPLEMENTED YET.
417 candidateList : `list`
418 A list of footprints/maskedImages for kernel candidates;
422 sizeCellX, sizeCellY : `int`
423 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)