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