LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
modelPsfMatch.py
Go to the documentation of this file.
1 # This file is part of ip_diffim.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 import numpy as np
23 
24 from . import diffimLib
25 import lsst.afw.display as afwDisplay
26 import lsst.afw.image as afwImage
27 import lsst.afw.math as afwMath
28 import lsst.geom as geom
29 import lsst.log as log
30 import lsst.pex.config as pexConfig
31 import lsst.pipe.base as pipeBase
32 from .makeKernelBasisList import makeKernelBasisList
33 from .psfMatch import PsfMatchTask, PsfMatchConfigAL
34 from . import utils as dituils
35 
36 __all__ = ("ModelPsfMatchTask", "ModelPsfMatchConfig")
37 
38 sigma2fwhm = 2.*np.sqrt(2.*np.log(2.))
39 
40 
42  nextInt = int(np.ceil(x))
43  return nextInt + 1 if nextInt%2 == 0 else nextInt
44 
45 
46 class ModelPsfMatchConfig(pexConfig.Config):
47  """Configuration for model-to-model Psf matching"""
48 
49  kernel = pexConfig.ConfigChoiceField(
50  doc="kernel type",
51  typemap=dict(
52  AL=PsfMatchConfigAL,
53  ),
54  default="AL",
55  )
56  doAutoPadPsf = pexConfig.Field(
57  dtype=bool,
58  doc=("If too small, automatically pad the science Psf? "
59  "Pad to smallest dimensions appropriate for the matching kernel dimensions, "
60  "as specified by autoPadPsfTo. If false, pad by the padPsfBy config."),
61  default=True,
62  )
63  autoPadPsfTo = pexConfig.RangeField(
64  dtype=float,
65  doc=("Minimum Science Psf dimensions as a fraction of matching kernel dimensions. "
66  "If the dimensions of the Psf to be matched are less than the "
67  "matching kernel dimensions * autoPadPsfTo, pad Science Psf to this size. "
68  "Ignored if doAutoPadPsf=False."),
69  default=1.4,
70  min=1.0,
71  max=2.0
72  )
73  padPsfBy = pexConfig.Field(
74  dtype=int,
75  doc="Pixels (even) to pad Science Psf by before matching. Ignored if doAutoPadPsf=True",
76  default=0,
77  )
78 
79  def setDefaults(self):
80  # No sigma clipping
81  self.kernelkernel.active.singleKernelClipping = False
82  self.kernelkernel.active.kernelSumClipping = False
83  self.kernelkernel.active.spatialKernelClipping = False
84  self.kernelkernel.active.checkConditionNumber = False
85 
86  # Variance is ill defined
87  self.kernelkernel.active.constantVarianceWeighting = True
88 
89  # Do not change specified kernel size
90  self.kernelkernel.active.scaleByFwhm = False
91 
92 
94  """Matching of two model Psfs, and application of the Psf-matching kernel to an input Exposure
95 
96  Notes
97  -----
98 
99  This Task differs from ImagePsfMatchTask in that it matches two Psf _models_, by realizing
100  them in an Exposure-sized SpatialCellSet and then inserting each Psf-image pair into KernelCandidates.
101  Because none of the pairs of sources that are to be matched should be invalid, all sigma clipping is
102  turned off in ModelPsfMatchConfig. And because there is no tracked _variance_ in the Psf images, the
103  debugging and logging QA info should be interpreted with caution.
104 
105  One item of note is that the sizes of Psf models are fixed (e.g. its defined as a 21x21 matrix). When the
106  Psf-matching kernel is being solved for, the Psf "image" is convolved with each kernel basis function,
107  leading to a loss of information around the borders.
108  This pixel loss will be problematic for the numerical
109  stability of the kernel solution if the size of the convolution kernel
110  (set by ModelPsfMatchConfig.kernelSize) is much bigger than: psfSize//2.
111  Thus the sizes of Psf-model matching kernels are typically smaller
112  than their image-matching counterparts. If the size of the kernel is too small, the convolved stars will
113  look "boxy"; if the kernel is too large, the kernel solution will be "noisy". This is a trade-off that
114  needs careful attention for a given dataset.
115 
116  The primary use case for this Task is in matching an Exposure to a
117  constant-across-the-sky Psf model for the purposes of image coaddition.
118  It is important to note that in the code, the "template" Psf is the Psf
119  that the science image gets matched to. In this sense the order of template and science image are
120  reversed, compared to ImagePsfMatchTask, which operates on the template image.
121 
122  Debug variables
123 
124  The `lsst.pipe.base.cmdLineTask.CmdLineTask` command line task interface supports a
125  flag -d/--debug to import debug.py from your PYTHONPATH. The relevant contents of debug.py
126  for this Task include:
127 
128  .. code-block:: py
129 
130  import sys
131  import lsstDebug
132  def DebugInfo(name):
133  di = lsstDebug.getInfo(name)
134  if name == "lsst.ip.diffim.psfMatch":
135  di.display = True # global
136  di.maskTransparency = 80 # mask transparency
137  di.displayCandidates = True # show all the candidates and residuals
138  di.displayKernelBasis = False # show kernel basis functions
139  di.displayKernelMosaic = True # show kernel realized across the image
140  di.plotKernelSpatialModel = False # show coefficients of spatial model
141  di.showBadCandidates = True # show the bad candidates (red) along with good (green)
142  elif name == "lsst.ip.diffim.modelPsfMatch":
143  di.display = True # global
144  di.maskTransparency = 30 # mask transparency
145  di.displaySpatialCells = True # show spatial cells before the fit
146  return di
147  lsstDebug.Info = DebugInfo
148  lsstDebug.frame = 1
149 
150  Note that if you want addional logging info, you may add to your scripts:
151 
152  .. code-block:: py
153 
154  import lsst.log.utils as logUtils
155  logUtils.traceSetAt("ip.diffim", 4)
156 
157  Examples
158  --------
159  A complete example of using ModelPsfMatchTask
160 
161  This code is modelPsfMatchTask.py in the examples directory, and can be run as e.g.
162 
163  .. code-block :: none
164 
165  examples/modelPsfMatchTask.py
166  examples/modelPsfMatchTask.py --debug
167  examples/modelPsfMatchTask.py --debug --template /path/to/templateExp.fits
168  --science /path/to/scienceExp.fits
169 
170  Create a subclass of ModelPsfMatchTask that accepts two exposures.
171  Note that the "template" exposure contains the Psf that will get matched to,
172  and the "science" exposure is the one that will be convolved:
173 
174  .. code-block :: none
175 
176  class MyModelPsfMatchTask(ModelPsfMatchTask):
177  def __init__(self, *args, **kwargs):
178  ModelPsfMatchTask.__init__(self, *args, **kwargs)
179  def run(self, templateExp, scienceExp):
180  return ModelPsfMatchTask.run(self, scienceExp, templateExp.getPsf())
181 
182  And allow the user the freedom to either run the script in default mode,
183  or point to their own images on disk. Note that these
184  images must be readable as an lsst.afw.image.Exposure:
185 
186  .. code-block :: none
187 
188  if __name__ == "__main__":
189  import argparse
190  parser = argparse.ArgumentParser(description="Demonstrate the use of ModelPsfMatchTask")
191  parser.add_argument("--debug", "-d", action="store_true", help="Load debug.py?", default=False)
192  parser.add_argument("--template", "-t", help="Template Exposure to use", default=None)
193  parser.add_argument("--science", "-s", help="Science Exposure to use", default=None)
194  args = parser.parse_args()
195 
196  We have enabled some minor display debugging in this script via the –debug option.
197  However, if you have an lsstDebug debug.py in your PYTHONPATH you will get additional
198  debugging displays. The following block checks for this script:
199 
200  .. code-block :: none
201 
202  if args.debug:
203  try:
204  import debug
205  # Since I am displaying 2 images here, set the starting frame number for the LSST debug LSST
206  debug.lsstDebug.frame = 3
207  except ImportError as e:
208  print(e, file=sys.stderr)
209 
210  Finally, we call a run method that we define below.
211  First set up a Config and modify some of the parameters.
212  In particular we don't want to "grow" the sizes of the kernel or KernelCandidates,
213  since we are operating with fixed–size images (i.e. the size of the input Psf models).
214 
215  .. code-block :: none
216 
217  def run(args):
218  #
219  # Create the Config and use sum of gaussian basis
220  #
221  config = ModelPsfMatchTask.ConfigClass()
222  config.kernel.active.scaleByFwhm = False
223 
224  Make sure the images (if any) that were sent to the script exist on disk and are readable.
225  If no images are sent, make some fake data up for the sake of this example script
226  (have a look at the code if you want more details on generateFakeData):
227 
228  .. code-block :: none
229 
230  # Run the requested method of the Task
231  if args.template is not None and args.science is not None:
232  if not os.path.isfile(args.template):
233  raise FileNotFoundError("Template image %s does not exist" % (args.template))
234  if not os.path.isfile(args.science):
235  raise FileNotFoundError("Science image %s does not exist" % (args.science))
236  try:
237  templateExp = afwImage.ExposureF(args.template)
238  except Exception as e:
239  raise RuntimeError("Cannot read template image %s" % (args.template))
240  try:
241  scienceExp = afwImage.ExposureF(args.science)
242  except Exception as e:
243  raise RuntimeError("Cannot read science image %s" % (args.science))
244  else:
245  templateExp, scienceExp = generateFakeData()
246  config.kernel.active.sizeCellX = 128
247  config.kernel.active.sizeCellY = 128
248 
249  .. code-block :: none
250 
251  if args.debug:
252  afwDisplay.Display(frame=1).mtv(templateExp, title="Example script: Input Template")
253  afwDisplay.Display(frame=2).mtv(scienceExp, title="Example script: Input Science Image")
254 
255  Create and run the Task:
256 
257  .. code-block :: none
258 
259  # Create the Task
260  psfMatchTask = MyModelPsfMatchTask(config=config)
261  # Run the Task
262  result = psfMatchTask.run(templateExp, scienceExp)
263 
264  And finally provide optional debugging display of the Psf-matched (via the Psf models) science image:
265 
266  .. code-block :: none
267 
268  if args.debug:
269  # See if the LSST debug has incremented the frame number; if not start with frame 3
270  try:
271  frame = debug.lsstDebug.frame + 1
272  except Exception:
273  frame = 3
274  afwDisplay.Display(frame=frame).mtv(result.psfMatchedExposure,
275  title="Example script: Matched Science Image")
276 
277  """
278  ConfigClass = ModelPsfMatchConfig
279 
280  def __init__(self, *args, **kwargs):
281  """Create a ModelPsfMatchTask
282 
283  Parameters
284  ----------
285  *args
286  arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
287  **kwargs
288  keyword arguments to be passed to lsst.ip.diffim.PsfMatchTask.__init__
289 
290  Notes
291  -----
292  Upon initialization, the kernel configuration is defined by self.config.kernel.active. This Task
293  does have a run() method, which is the default way to call the Task.
294  """
295  PsfMatchTask.__init__(self, *args, **kwargs)
296  self.kConfigkConfigkConfig = self.config.kernel.active
297 
298  @pipeBase.timeMethod
299  def run(self, exposure, referencePsfModel, kernelSum=1.0):
300  """Psf-match an exposure to a model Psf
301 
302  Parameters
303  ----------
304  exposure : `lsst.afw.image.Exposure`
305  Exposure to Psf-match to the reference Psf model;
306  it must return a valid PSF model via exposure.getPsf()
307  referencePsfModel : `lsst.afw.detection.Psf`
308  The Psf model to match to
309  kernelSum : `float`, optional
310  A multipicative factor to apply to the kernel sum (default=1.0)
311 
312  Returns
313  -------
314  result : `struct`
315  - ``psfMatchedExposure`` : the Psf-matched Exposure.
316  This has the same parent bbox, Wcs, PhotoCalib and
317  Filter as the input Exposure but no Psf.
318  In theory the Psf should equal referencePsfModel but
319  the match is likely not exact.
320  - ``psfMatchingKernel`` : the spatially varying Psf-matching kernel
321  - ``kernelCellSet`` : SpatialCellSet used to solve for the Psf-matching kernel
322  - ``referencePsfModel`` : Validated and/or modified reference model used
323 
324  Raises
325  ------
326  RuntimeError
327  if the Exposure does not contain a Psf model
328  """
329  if not exposure.hasPsf():
330  raise RuntimeError("exposure does not contain a Psf model")
331 
332  maskedImage = exposure.getMaskedImage()
333 
334  self.log.info("compute Psf-matching kernel")
335  result = self._buildCellSet_buildCellSet_buildCellSet(exposure, referencePsfModel)
336  kernelCellSet = result.kernelCellSet
337  referencePsfModel = result.referencePsfModel
338  fwhmScience = exposure.getPsf().computeShape().getDeterminantRadius()*sigma2fwhm
339  fwhmModel = referencePsfModel.computeShape().getDeterminantRadius()*sigma2fwhm
340 
341  basisList = makeKernelBasisList(self.kConfigkConfigkConfig, fwhmScience, fwhmModel, metadata=self.metadata)
342  spatialSolution, psfMatchingKernel, backgroundModel = self._solve_solve(kernelCellSet, basisList)
343 
344  if psfMatchingKernel.isSpatiallyVarying():
345  sParameters = np.array(psfMatchingKernel.getSpatialParameters())
346  sParameters[0][0] = kernelSum
347  psfMatchingKernel.setSpatialParameters(sParameters)
348  else:
349  kParameters = np.array(psfMatchingKernel.getKernelParameters())
350  kParameters[0] = kernelSum
351  psfMatchingKernel.setKernelParameters(kParameters)
352 
353  self.log.info("Psf-match science exposure to reference")
354  psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs())
355  psfMatchedExposure.setFilterLabel(exposure.getFilterLabel())
356  psfMatchedExposure.setPhotoCalib(exposure.getPhotoCalib())
357  psfMatchedExposure.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo())
358  psfMatchedExposure.setPsf(referencePsfModel)
359  psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage()
360 
361  # Normalize the psf-matching kernel while convolving since its magnitude is meaningless
362  # when PSF-matching one model to another.
363  convolutionControl = afwMath.ConvolutionControl()
364  convolutionControl.setDoNormalize(True)
365  afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, convolutionControl)
366 
367  self.log.info("done")
368  return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure,
369  psfMatchingKernel=psfMatchingKernel,
370  kernelCellSet=kernelCellSet,
371  metadata=self.metadata,
372  )
373 
374  def _diagnostic(self, kernelCellSet, spatialSolution, spatialKernel, spatialBg):
375  """Print diagnostic information on spatial kernel and background fit
376 
377  The debugging diagnostics are not really useful here, since the images we are matching have
378  no variance. Thus override the _diagnostic method to generate no logging information"""
379  return
380 
381  def _buildCellSet(self, exposure, referencePsfModel):
382  """Build a SpatialCellSet for use with the solve method
383 
384  Parameters
385  ----------
386  exposure : `lsst.afw.image.Exposure`
387  The science exposure that will be convolved; must contain a Psf
388  referencePsfModel : `lsst.afw.detection.Psf`
389  Psf model to match to
390 
391  Returns
392  -------
393  result : `struct`
394  - ``kernelCellSet`` : a SpatialCellSet to be used by self._solve
395  - ``referencePsfModel`` : Validated and/or modified
396  reference model used to populate the SpatialCellSet
397 
398  Notes
399  -----
400  If the reference Psf model and science Psf model have different dimensions,
401  adjust the referencePsfModel (the model to which the exposure PSF will be matched)
402  to match that of the science Psf. If the science Psf dimensions vary across the image,
403  as is common with a WarpedPsf, either pad or clip (depending on config.padPsf)
404  the dimensions to be constant.
405  """
406  sizeCellX = self.kConfig.sizeCellX
407  sizeCellY = self.kConfig.sizeCellY
408 
409  scienceBBox = exposure.getBBox()
410  # Extend for proper spatial matching kernel all the way to edge, especially for narrow strips
411  scienceBBox.grow(geom.Extent2I(sizeCellX, sizeCellY))
412 
413  sciencePsfModel = exposure.getPsf()
414 
415  dimenR = referencePsfModel.getLocalKernel().getDimensions()
416  psfWidth, psfHeight = dimenR
417 
418  regionSizeX, regionSizeY = scienceBBox.getDimensions()
419  scienceX0, scienceY0 = scienceBBox.getMin()
420 
421  kernelCellSet = afwMath.SpatialCellSet(geom.Box2I(scienceBBox), sizeCellX, sizeCellY)
422 
423  nCellX = regionSizeX//sizeCellX
424  nCellY = regionSizeY//sizeCellY
425 
426  if nCellX == 0 or nCellY == 0:
427  raise ValueError("Exposure dimensions=%s and sizeCell=(%s, %s). Insufficient area to match" %
428  (scienceBBox.getDimensions(), sizeCellX, sizeCellY))
429 
430  # Survey the PSF dimensions of the Spatial Cell Set
431  # to identify the minimum enclosed or maximum bounding square BBox.
432  widthList = []
433  heightList = []
434  for row in range(nCellY):
435  posY = sizeCellY*row + sizeCellY//2 + scienceY0
436  for col in range(nCellX):
437  posX = sizeCellX*col + sizeCellX//2 + scienceX0
438  widthS, heightS = sciencePsfModel.computeBBox(geom.Point2D(posX, posY)).getDimensions()
439  widthList.append(widthS)
440  heightList.append(heightS)
441 
442  psfSize = max(max(heightList), max(widthList))
443 
444  if self.config.doAutoPadPsf:
445  minPsfSize = nextOddInteger(self.kConfig.kernelSize*self.config.autoPadPsfTo)
446  paddingPix = max(0, minPsfSize - psfSize)
447  else:
448  if self.config.padPsfBy % 2 != 0:
449  raise ValueError("Config padPsfBy (%i pixels) must be even number." %
450  self.config.padPsfBy)
451  paddingPix = self.config.padPsfBy
452 
453  if paddingPix > 0:
454  self.log.info("Padding Science PSF from (%s, %s) to (%s, %s) pixels" %
455  (psfSize, psfSize, paddingPix + psfSize, paddingPix + psfSize))
456  psfSize += paddingPix
457 
458  # Check that PSF is larger than the matching kernel
459  maxKernelSize = psfSize - 1
460  if maxKernelSize % 2 == 0:
461  maxKernelSize -= 1
462  if self.kConfig.kernelSize > maxKernelSize:
463  message = """
464  Kernel size (%d) too big to match Psfs of size %d.
465  Please reconfigure by setting one of the following:
466  1) kernel size to <= %d
467  2) doAutoPadPsf=True
468  3) padPsfBy to >= %s
469  """ % (self.kConfig.kernelSize, psfSize,
470  maxKernelSize, self.kConfig.kernelSize - maxKernelSize)
471  raise ValueError(message)
472 
473  dimenS = geom.Extent2I(psfSize, psfSize)
474 
475  if (dimenR != dimenS):
476  try:
477  referencePsfModel = referencePsfModel.resized(psfSize, psfSize)
478  self.log.info("Adjusted dimensions of reference PSF model from %s to %s" % (dimenR, dimenS))
479  except Exception as e:
480  self.log.warn("Zero padding or clipping the reference PSF model of type %s and dimensions %s"
481  " to the science Psf dimensions %s because: %s",
482  referencePsfModel.__class__.__name__, dimenR, dimenS, e)
483  dimenR = dimenS
484 
485  ps = pexConfig.makePropertySet(self.kConfig)
486  for row in range(nCellY):
487  # place at center of cell
488  posY = sizeCellY*row + sizeCellY//2 + scienceY0
489 
490  for col in range(nCellX):
491  # place at center of cell
492  posX = sizeCellX*col + sizeCellX//2 + scienceX0
493 
494  log.log("TRACE4." + self.log.getName(), log.DEBUG,
495  "Creating Psf candidate at %.1f %.1f", posX, posY)
496 
497  # reference kernel image, at location of science subimage
498  referenceMI = self._makePsfMaskedImage(referencePsfModel, posX, posY, dimensions=dimenR)
499 
500  # kernel image we are going to convolve
501  scienceMI = self._makePsfMaskedImage(sciencePsfModel, posX, posY, dimensions=dimenR)
502 
503  # The image to convolve is the science image, to the reference Psf.
504  kc = diffimLib.makeKernelCandidate(posX, posY, scienceMI, referenceMI, ps)
505  kernelCellSet.insertCandidate(kc)
506 
507  import lsstDebug
508  display = lsstDebug.Info(__name__).display
509  displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells
510  maskTransparency = lsstDebug.Info(__name__).maskTransparency
511  if not maskTransparency:
512  maskTransparency = 0
513  if display:
514  afwDisplay.setDefaultMaskTransparency(maskTransparency)
515  if display and displaySpatialCells:
516  dituils.showKernelSpatialCells(exposure.getMaskedImage(), kernelCellSet,
517  symb="o", ctype=afwDisplay.CYAN, ctypeUnused=afwDisplay.YELLOW,
518  ctypeBad=afwDisplay.RED, size=4, frame=lsstDebug.frame,
519  title="Image to be convolved")
520  lsstDebug.frame += 1
521  return pipeBase.Struct(kernelCellSet=kernelCellSet,
522  referencePsfModel=referencePsfModel,
523  )
524 
525  def _makePsfMaskedImage(self, psfModel, posX, posY, dimensions=None):
526  """Return a MaskedImage of the a PSF Model of specified dimensions
527  """
528  rawKernel = psfModel.computeKernelImage(geom.Point2D(posX, posY)).convertF()
529  if dimensions is None:
530  dimensions = rawKernel.getDimensions()
531  if rawKernel.getDimensions() == dimensions:
532  kernelIm = rawKernel
533  else:
534  # make image of proper size
535  kernelIm = afwImage.ImageF(dimensions)
536  bboxToPlace = geom.Box2I(geom.Point2I((dimensions.getX() - rawKernel.getWidth())//2,
537  (dimensions.getY() - rawKernel.getHeight())//2),
538  rawKernel.getDimensions())
539  kernelIm.assign(rawKernel, bboxToPlace)
540 
541  kernelMask = afwImage.Mask(dimensions, 0x0)
542  kernelVar = afwImage.ImageF(dimensions, 1.0)
543  return afwImage.MaskedImageF(kernelIm, kernelMask, kernelVar)
int max
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
Parameters to control convolution.
Definition: ConvolveImage.h:50
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:387
An integer coordinate rectangle.
Definition: Box.h:55
def run(self, exposure, referencePsfModel, kernelSum=1.0)
def _buildCellSet(self, exposure, referencePsfModel)
def _solve(self, kernelCellSet, basisList, returnOnExcept=False)
Definition: psfMatch.py:880
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::string const & getName() const noexcept
Return a filter's name.
Definition: Filter.h:78
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.
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)
Definition: Log.h:706