LSST Applications g0265f82a02+c6dfa2ddaf,g1162b98a3f+b2075782a9,g2079a07aa2+1b2e822518,g2bbee38e9b+c6dfa2ddaf,g337abbeb29+c6dfa2ddaf,g3ddfee87b4+a60788ef87,g50ff169b8f+2eb0e556e8,g52b1c1532d+90ebb246c7,g555ede804d+a60788ef87,g591dd9f2cf+ba8caea58f,g5ec818987f+864ee9cddb,g858d7b2824+9ee1ab4172,g876c692160+a40945ebb7,g8a8a8dda67+90ebb246c7,g8cdfe0ae6a+4fd9e222a8,g99cad8db69+5e309b7bc6,g9ddcbc5298+a1346535a5,ga1e77700b3+df8f93165b,ga8c6da7877+aa12a14d27,gae46bcf261+c6dfa2ddaf,gb0e22166c9+8634eb87fb,gb3f2274832+d0da15e3be,gba4ed39666+1ac82b564f,gbb8dafda3b+5dfd9c994b,gbeb006f7da+97157f9740,gc28159a63d+c6dfa2ddaf,gc86a011abf+9ee1ab4172,gcf0d15dbbd+a60788ef87,gdaeeff99f8+1cafcb7cd4,gdc0c513512+9ee1ab4172,ge79ae78c31+c6dfa2ddaf,geb67518f79+ba1859f325,geb961e4c1e+f9439d1e6f,gee10cc3b42+90ebb246c7,gf1cff7945b+9ee1ab4172,w.2024.12
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | List of all members
lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask Class Reference
Inheritance diagram for lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask:
lsst.ip.diffim.psfMatch.PsfMatchTask

Public Member Functions

 __init__ (self, *args, **kwargs)
 
 run (self, exposure, referencePsfModel, kernelSum=1.0)
 

Public Attributes

 kConfig
 
 log
 

Static Public Attributes

 ConfigClass = ModelPsfMatchConfig
 

Protected Member Functions

 _diagnostic (self, kernelCellSet, spatialSolution, spatialKernel, spatialBg)
 
 _buildCellSet (self, exposure, referencePsfModel)
 
 _makePsfMaskedImage (self, psfModel, posX, posY, dimensions=None)
 

Detailed Description

Matching of two model Psfs, and application of the Psf-matching kernel to an input Exposure

Definition at line 94 of file modelPsfMatch.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask.__init__ ( self,
* args,
** kwargs )
Create a ModelPsfMatchTask

Parameters
----------
*args
    arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
**kwargs
    keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__

Notes
-----
Upon initialization, the kernel configuration is defined by self.config.kernel.active.  This Task
does have a run() method, which is the default way to call the Task.

Reimplemented from lsst.ip.diffim.psfMatch.PsfMatchTask.

Definition at line 100 of file modelPsfMatch.py.

100 def __init__(self, *args, **kwargs):
101 """Create a ModelPsfMatchTask
102
103 Parameters
104 ----------
105 *args
106 arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
107 **kwargs
108 keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
109
110 Notes
111 -----
112 Upon initialization, the kernel configuration is defined by self.config.kernel.active. This Task
113 does have a run() method, which is the default way to call the Task.
114 """
115 PsfMatchTask.__init__(self, *args, **kwargs)
116 self.kConfig = self.config.kernel.active
117

Member Function Documentation

◆ _buildCellSet()

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask._buildCellSet ( self,
exposure,
referencePsfModel )
protected
Build a SpatialCellSet for use with the solve method

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    The science exposure that will be convolved; must contain a Psf
referencePsfModel : `lsst.afw.detection.Psf`
    Psf model to match to

Returns
-------
result : `struct`
    - ``kernelCellSet`` : a SpatialCellSet to be used by self._solve
    - ``referencePsfModel`` : Validated and/or modified
        reference model used to populate the SpatialCellSet

Notes
-----
If the reference Psf model and science Psf model have different dimensions,
adjust the referencePsfModel (the model to which the exposure PSF will be matched)
to match that of the science Psf. If the science Psf dimensions vary across the image,
as is common with a WarpedPsf, either pad or clip (depending on config.padPsf)
the dimensions to be constant.

Reimplemented from lsst.ip.diffim.psfMatch.PsfMatchTask.

Definition at line 206 of file modelPsfMatch.py.

206 def _buildCellSet(self, exposure, referencePsfModel):
207 """Build a SpatialCellSet for use with the solve method
208
209 Parameters
210 ----------
211 exposure : `lsst.afw.image.Exposure`
212 The science exposure that will be convolved; must contain a Psf
213 referencePsfModel : `lsst.afw.detection.Psf`
214 Psf model to match to
215
216 Returns
217 -------
218 result : `struct`
219 - ``kernelCellSet`` : a SpatialCellSet to be used by self._solve
220 - ``referencePsfModel`` : Validated and/or modified
221 reference model used to populate the SpatialCellSet
222
223 Notes
224 -----
225 If the reference Psf model and science Psf model have different dimensions,
226 adjust the referencePsfModel (the model to which the exposure PSF will be matched)
227 to match that of the science Psf. If the science Psf dimensions vary across the image,
228 as is common with a WarpedPsf, either pad or clip (depending on config.padPsf)
229 the dimensions to be constant.
230 """
231 sizeCellX = self.kConfig.sizeCellX
232 sizeCellY = self.kConfig.sizeCellY
233
234 scienceBBox = exposure.getBBox()
235 # Extend for proper spatial matching kernel all the way to edge, especially for narrow strips
236 scienceBBox.grow(geom.Extent2I(sizeCellX, sizeCellY))
237
238 sciencePsfModel = exposure.getPsf()
239
240 dimenR = referencePsfModel.getLocalKernel(scienceBBox.getCenter()).getDimensions()
241
242 regionSizeX, regionSizeY = scienceBBox.getDimensions()
243 scienceX0, scienceY0 = scienceBBox.getMin()
244
245 kernelCellSet = afwMath.SpatialCellSet(geom.Box2I(scienceBBox), sizeCellX, sizeCellY)
246
247 nCellX = regionSizeX//sizeCellX
248 nCellY = regionSizeY//sizeCellY
249
250 if nCellX == 0 or nCellY == 0:
251 raise ValueError("Exposure dimensions=%s and sizeCell=(%s, %s). Insufficient area to match" %
252 (scienceBBox.getDimensions(), sizeCellX, sizeCellY))
253
254 # Survey the PSF dimensions of the Spatial Cell Set
255 # to identify the minimum enclosed or maximum bounding square BBox.
256 widthList = []
257 heightList = []
258 for row in range(nCellY):
259 posY = sizeCellY*row + sizeCellY//2 + scienceY0
260 for col in range(nCellX):
261 posX = sizeCellX*col + sizeCellX//2 + scienceX0
262 widthS, heightS = sciencePsfModel.computeBBox(geom.Point2D(posX, posY)).getDimensions()
263 widthList.append(widthS)
264 heightList.append(heightS)
265
266 psfSize = max(max(heightList), max(widthList))
267
268 if self.config.doAutoPadPsf:
269 minPsfSize = nextOddInteger(self.kConfig.kernelSize*self.config.autoPadPsfTo)
270 paddingPix = max(0, minPsfSize - psfSize)
271 else:
272 if self.config.padPsfBy % 2 != 0:
273 raise ValueError("Config padPsfBy (%i pixels) must be even number." %
274 self.config.padPsfBy)
275 paddingPix = self.config.padPsfBy
276
277 if paddingPix > 0:
278 self.log.debug("Padding Science PSF from (%d, %d) to (%d, %d) pixels",
279 psfSize, psfSize, paddingPix + psfSize, paddingPix + psfSize)
280 psfSize += paddingPix
281
282 # Check that PSF is larger than the matching kernel
283 maxKernelSize = psfSize - 1
284 if maxKernelSize % 2 == 0:
285 maxKernelSize -= 1
286 if self.kConfig.kernelSize > maxKernelSize:
287 message = """
288 Kernel size (%d) too big to match Psfs of size %d.
289 Please reconfigure by setting one of the following:
290 1) kernel size to <= %d
291 2) doAutoPadPsf=True
292 3) padPsfBy to >= %s
293 """ % (self.kConfig.kernelSize, psfSize,
294 maxKernelSize, self.kConfig.kernelSize - maxKernelSize)
295 raise ValueError(message)
296
297 dimenS = geom.Extent2I(psfSize, psfSize)
298
299 if (dimenR != dimenS):
300 try:
301 referencePsfModel = referencePsfModel.resized(psfSize, psfSize)
302 self.log.info("Adjusted dimensions of reference PSF model from %s to %s", dimenR, dimenS)
303 except Exception as e:
304 self.log.warning("Zero padding or clipping the reference PSF model of type %s and dimensions"
305 " %s to the science Psf dimensions %s because: %s",
306 referencePsfModel.__class__.__name__, dimenR, dimenS, e)
307 dimenR = dimenS
308
309 ps = pexConfig.makePropertySet(self.kConfig)
310 for row in range(nCellY):
311 # place at center of cell
312 posY = sizeCellY*row + sizeCellY//2 + scienceY0
313
314 for col in range(nCellX):
315 # place at center of cell
316 posX = sizeCellX*col + sizeCellX//2 + scienceX0
317
318 getTraceLogger(self.log, 4).debug("Creating Psf candidate at %.1f %.1f", posX, posY)
319
320 # reference kernel image, at location of science subimage
321 referenceMI = self._makePsfMaskedImage(referencePsfModel, posX, posY, dimensions=dimenR)
322
323 # kernel image we are going to convolve
324 scienceMI = self._makePsfMaskedImage(sciencePsfModel, posX, posY, dimensions=dimenR)
325
326 # The image to convolve is the science image, to the reference Psf.
327 kc = diffimLib.makeKernelCandidate(posX, posY, scienceMI, referenceMI, ps)
328 kernelCellSet.insertCandidate(kc)
329
330 import lsstDebug
331 display = lsstDebug.Info(__name__).display
332 displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells
333 maskTransparency = lsstDebug.Info(__name__).maskTransparency
334 if not maskTransparency:
335 maskTransparency = 0
336 if display:
337 afwDisplay.setDefaultMaskTransparency(maskTransparency)
338 if display and displaySpatialCells:
339 dituils.showKernelSpatialCells(exposure.getMaskedImage(), kernelCellSet,
340 symb="o", ctype=afwDisplay.CYAN, ctypeUnused=afwDisplay.YELLOW,
341 ctypeBad=afwDisplay.RED, size=4, frame=lsstDebug.frame,
342 title="Image to be convolved")
343 lsstDebug.frame += 1
344 return pipeBase.Struct(kernelCellSet=kernelCellSet,
345 referencePsfModel=referencePsfModel,
346 )
347
int max
A collection of SpatialCells covering an entire image.
An integer coordinate rectangle.
Definition Box.h:55

◆ _diagnostic()

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask._diagnostic ( self,
kernelCellSet,
spatialSolution,
spatialKernel,
spatialBg )
protected
Print diagnostic information on spatial kernel and background fit

The debugging diagnostics are not really useful here, since the images we are matching have
no variance.  Thus override the _diagnostic method to generate no logging information

Reimplemented from lsst.ip.diffim.psfMatch.PsfMatchTask.

Definition at line 199 of file modelPsfMatch.py.

199 def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg):
200 """Print diagnostic information on spatial kernel and background fit
201
202 The debugging diagnostics are not really useful here, since the images we are matching have
203 no variance. Thus override the _diagnostic method to generate no logging information"""
204 return
205

◆ _makePsfMaskedImage()

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask._makePsfMaskedImage ( self,
psfModel,
posX,
posY,
dimensions = None )
protected
Return a MaskedImage of the a PSF Model of specified dimensions

Definition at line 348 of file modelPsfMatch.py.

348 def _makePsfMaskedImage(self, psfModel, posX, posY, dimensions=None):
349 """Return a MaskedImage of the a PSF Model of specified dimensions
350 """
351 rawKernel = psfModel.computeKernelImage(geom.Point2D(posX, posY)).convertF()
352 if dimensions is None:
353 dimensions = rawKernel.getDimensions()
354 if rawKernel.getDimensions() == dimensions:
355 kernelIm = rawKernel
356 else:
357 # make image of proper size
358 kernelIm = afwImage.ImageF(dimensions)
359 bboxToPlace = geom.Box2I(geom.Point2I((dimensions.getX() - rawKernel.getWidth())//2,
360 (dimensions.getY() - rawKernel.getHeight())//2),
361 rawKernel.getDimensions())
362 kernelIm.assign(rawKernel, bboxToPlace)
363
364 kernelMask = afwImage.Mask(dimensions, 0x0)
365 kernelVar = afwImage.ImageF(dimensions, 1.0)
366 return afwImage.MaskedImageF(kernelIm, kernelMask, kernelVar)
Represent a 2-dimensional array of bitmask pixels.
Definition Mask.h:77

◆ run()

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask.run ( self,
exposure,
referencePsfModel,
kernelSum = 1.0 )
Psf-match an exposure to a model Psf

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to Psf-match to the reference Psf model;
    it must return a valid PSF model via exposure.getPsf()
referencePsfModel : `lsst.afw.detection.Psf`
    The Psf model to match to
kernelSum : `float`, optional
    A multipicative factor to apply to the kernel sum (default=1.0)

Returns
-------
result : `struct`
    - ``psfMatchedExposure`` : the Psf-matched Exposure.
        This has the same parent bbox, Wcs, PhotoCalib and
        Filter as the input Exposure but no Psf.
        In theory the Psf should equal referencePsfModel but
        the match is likely not exact.
    - ``psfMatchingKernel`` : the spatially varying Psf-matching kernel
    - ``kernelCellSet`` : SpatialCellSet used to solve for the Psf-matching kernel
    - ``referencePsfModel`` : Validated and/or modified reference model used

Raises
------
RuntimeError
    if the Exposure does not contain a Psf model

Definition at line 119 of file modelPsfMatch.py.

119 def run(self, exposure, referencePsfModel, kernelSum=1.0):
120 """Psf-match an exposure to a model Psf
121
122 Parameters
123 ----------
124 exposure : `lsst.afw.image.Exposure`
125 Exposure to Psf-match to the reference Psf model;
126 it must return a valid PSF model via exposure.getPsf()
127 referencePsfModel : `lsst.afw.detection.Psf`
128 The Psf model to match to
129 kernelSum : `float`, optional
130 A multipicative factor to apply to the kernel sum (default=1.0)
131
132 Returns
133 -------
134 result : `struct`
135 - ``psfMatchedExposure`` : the Psf-matched Exposure.
136 This has the same parent bbox, Wcs, PhotoCalib and
137 Filter as the input Exposure but no Psf.
138 In theory the Psf should equal referencePsfModel but
139 the match is likely not exact.
140 - ``psfMatchingKernel`` : the spatially varying Psf-matching kernel
141 - ``kernelCellSet`` : SpatialCellSet used to solve for the Psf-matching kernel
142 - ``referencePsfModel`` : Validated and/or modified reference model used
143
144 Raises
145 ------
146 RuntimeError
147 if the Exposure does not contain a Psf model
148 """
149 if not exposure.hasPsf():
150 raise RuntimeError("exposure does not contain a Psf model")
151
152 maskedImage = exposure.getMaskedImage()
153
154 self.log.info("compute Psf-matching kernel")
155 result = self._buildCellSet(exposure, referencePsfModel)
156 kernelCellSet = result.kernelCellSet
157 referencePsfModel = result.referencePsfModel
158 # TODO: This should be evaluated at (or close to) the center of the
159 # exposure's bounding box in DM-32756.
160 sciAvgPos = exposure.getPsf().getAveragePosition()
161 modelAvgPos = referencePsfModel.getAveragePosition()
162 fwhmScience = exposure.getPsf().computeShape(sciAvgPos).getDeterminantRadius()*sigma2fwhm
163 fwhmModel = referencePsfModel.computeShape(modelAvgPos).getDeterminantRadius()*sigma2fwhm
164
165 basisList = makeKernelBasisList(self.kConfig, fwhmScience, fwhmModel, metadata=self.metadata)
166 spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList)
167
168 if psfMatchingKernel.isSpatiallyVarying():
169 sParameters = np.array(psfMatchingKernel.getSpatialParameters())
170 sParameters[0][0] = kernelSum
171 psfMatchingKernel.setSpatialParameters(sParameters)
172 else:
173 kParameters = np.array(psfMatchingKernel.getKernelParameters())
174 kParameters[0] = kernelSum
175 psfMatchingKernel.setKernelParameters(kParameters)
176
177 self.log.info("Psf-match science exposure to reference")
178 psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs())
179 psfMatchedExposure.info.id = exposure.info.id
180 psfMatchedExposure.setFilter(exposure.getFilter())
181 psfMatchedExposure.setPhotoCalib(exposure.getPhotoCalib())
182 psfMatchedExposure.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo())
183 psfMatchedExposure.setPsf(referencePsfModel)
184 psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage()
185
186 # Normalize the psf-matching kernel while convolving since its magnitude is meaningless
187 # when PSF-matching one model to another.
188 convolutionControl = afwMath.ConvolutionControl()
189 convolutionControl.setDoNormalize(True)
190 afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, convolutionControl)
191
192 self.log.info("done")
193 return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure,
194 psfMatchingKernel=psfMatchingKernel,
195 kernelCellSet=kernelCellSet,
196 metadata=self.metadata,
197 )
198
Parameters to control convolution.
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image.

Member Data Documentation

◆ ConfigClass

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask.ConfigClass = ModelPsfMatchConfig
static

Definition at line 98 of file modelPsfMatch.py.

◆ kConfig

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask.kConfig

Definition at line 116 of file modelPsfMatch.py.

◆ log

lsst.ip.diffim.modelPsfMatch.ModelPsfMatchTask.log

Definition at line 318 of file modelPsfMatch.py.


The documentation for this class was generated from the following file: