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
Public Member Functions | Public Attributes | List of all members
lsst.ip.diffim.dipoleFitTask.DipoleModel Class Reference
Inheritance diagram for lsst.ip.diffim.dipoleFitTask.DipoleModel:

Public Member Functions

def __init__ (self)
 
def makeBackgroundModel (self, in_x, pars=None)
 
def fitFootprintBackground (self, source, posImage, order=1)
 
def makeStarModel (self, bbox, psf, xcen, ycen, flux)
 
def makeModel (self, x, flux, xcenPos, ycenPos, xcenNeg, ycenNeg, fluxNeg=None, b=None, x1=None, y1=None, xy=None, x2=None, y2=None, bNeg=None, x1Neg=None, y1Neg=None, xyNeg=None, x2Neg=None, y2Neg=None, **kwargs)
 

Public Attributes

 debug
 
 log
 

Detailed Description

Lightweight class containing methods for generating a dipole model for fitting
to sources in diffims, used by DipoleFitAlgorithm.

See also:
`DMTN-007: Dipole characterization for image differencing  <https://dmtn-007.lsst.io>`_.

Definition at line 180 of file dipoleFitTask.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.ip.diffim.dipoleFitTask.DipoleModel.__init__ (   self)

Definition at line 188 of file dipoleFitTask.py.

188  def __init__(self):
189  import lsstDebug
190  self.debug = lsstDebug.Info(__name__).debug
191  self.log = Log.getLogger(__name__)
192 

Member Function Documentation

◆ fitFootprintBackground()

def lsst.ip.diffim.dipoleFitTask.DipoleModel.fitFootprintBackground (   self,
  source,
  posImage,
  order = 1 
)
Fit a linear (polynomial) model of given order (max 2) to the background of a footprint.

Only fit the pixels OUTSIDE of the footprint, but within its bounding box.

Parameters
----------
source : `lsst.afw.table.SourceRecord`
    SourceRecord, the footprint of which is to be fit
posImage : `lsst.afw.image.Exposure`
    The exposure from which to extract the footprint subimage
order : `int`
    Polynomial order of background gradient to fit.

Returns
-------
pars : `tuple` of `float`
    `tuple` of length (1 if order==0; 3 if order==1; 6 if order == 2),
    containing the resulting fit parameters

Definition at line 283 of file dipoleFitTask.py.

283  def fitFootprintBackground(self, source, posImage, order=1):
284  """Fit a linear (polynomial) model of given order (max 2) to the background of a footprint.
285 
286  Only fit the pixels OUTSIDE of the footprint, but within its bounding box.
287 
288  Parameters
289  ----------
290  source : `lsst.afw.table.SourceRecord`
291  SourceRecord, the footprint of which is to be fit
292  posImage : `lsst.afw.image.Exposure`
293  The exposure from which to extract the footprint subimage
294  order : `int`
295  Polynomial order of background gradient to fit.
296 
297  Returns
298  -------
299  pars : `tuple` of `float`
300  `tuple` of length (1 if order==0; 3 if order==1; 6 if order == 2),
301  containing the resulting fit parameters
302  """
303 
304  # TODO look into whether to use afwMath background methods -- see
305  # http://lsst-web.ncsa.illinois.edu/doxygen/x_masterDoxyDoc/_background_example.html
306  fp = source.getFootprint()
307  bbox = fp.getBBox()
308  bbox.grow(3)
309  posImg = afwImage.ImageF(posImage.getMaskedImage().getImage(), bbox, afwImage.PARENT)
310 
311  # This code constructs the footprint image so that we can identify the pixels that are
312  # outside the footprint (but within the bounding box). These are the pixels used for
313  # fitting the background.
314  posHfp = afwDet.HeavyFootprintF(fp, posImage.getMaskedImage())
315  posFpImg = self._getHeavyFootprintSubimage(posHfp, grow=3)
316 
317  isBg = np.isnan(posFpImg.getArray()).ravel()
318 
319  data = posImg.getArray().ravel()
320  data = data[isBg]
321  B = data
322 
323  x, y = np.mgrid[bbox.getBeginY():bbox.getEndY(), bbox.getBeginX():bbox.getEndX()]
324  x = x.astype(np.float64).ravel()
325  x -= np.mean(x)
326  x = x[isBg]
327  y = y.astype(np.float64).ravel()
328  y -= np.mean(y)
329  y = y[isBg]
330  b = np.ones_like(x, dtype=np.float64)
331 
332  M = np.vstack([b]).T # order = 0
333  if order == 1:
334  M = np.vstack([b, x, y]).T
335  elif order == 2:
336  M = np.vstack([b, x, y, x**2., y**2., x*y]).T
337 
338  pars = np.linalg.lstsq(M, B, rcond=-1)[0]
339  return pars
340 

◆ makeBackgroundModel()

def lsst.ip.diffim.dipoleFitTask.DipoleModel.makeBackgroundModel (   self,
  in_x,
  pars = None 
)
Generate gradient model (2-d array) with up to 2nd-order polynomial

Parameters
----------
in_x : `numpy.array`
    (2, w, h)-dimensional `numpy.array`, containing the
    input x,y meshgrid providing the coordinates upon which to
    compute the gradient. This will typically be generated via
    `_generateXYGrid()`. `w` and `h` correspond to the width and
    height of the desired grid.
pars : `list` of `float`, optional
    Up to 6 floats for up
    to 6 2nd-order 2-d polynomial gradient parameters, in the
    following order: (intercept, x, y, xy, x**2, y**2). If `pars`
    is emtpy or `None`, do nothing and return `None` (for speed).

Returns
-------
result : `None` or `numpy.array`
    return None, or 2-d numpy.array of width/height matching
    input bbox, containing computed gradient values.

Definition at line 193 of file dipoleFitTask.py.

193  def makeBackgroundModel(self, in_x, pars=None):
194  """Generate gradient model (2-d array) with up to 2nd-order polynomial
195 
196  Parameters
197  ----------
198  in_x : `numpy.array`
199  (2, w, h)-dimensional `numpy.array`, containing the
200  input x,y meshgrid providing the coordinates upon which to
201  compute the gradient. This will typically be generated via
202  `_generateXYGrid()`. `w` and `h` correspond to the width and
203  height of the desired grid.
204  pars : `list` of `float`, optional
205  Up to 6 floats for up
206  to 6 2nd-order 2-d polynomial gradient parameters, in the
207  following order: (intercept, x, y, xy, x**2, y**2). If `pars`
208  is emtpy or `None`, do nothing and return `None` (for speed).
209 
210  Returns
211  -------
212  result : `None` or `numpy.array`
213  return None, or 2-d numpy.array of width/height matching
214  input bbox, containing computed gradient values.
215  """
216 
217  # Don't fit for other gradient parameters if the intercept is not included.
218  if (pars is None) or (len(pars) <= 0) or (pars[0] is None):
219  return
220 
221  y, x = in_x[0, :], in_x[1, :]
222  gradient = np.full_like(x, pars[0], dtype='float64')
223  if len(pars) > 1 and pars[1] is not None:
224  gradient += pars[1] * x
225  if len(pars) > 2 and pars[2] is not None:
226  gradient += pars[2] * y
227  if len(pars) > 3 and pars[3] is not None:
228  gradient += pars[3] * (x * y)
229  if len(pars) > 4 and pars[4] is not None:
230  gradient += pars[4] * (x * x)
231  if len(pars) > 5 and pars[5] is not None:
232  gradient += pars[5] * (y * y)
233 
234  return gradient
235 

◆ makeModel()

def lsst.ip.diffim.dipoleFitTask.DipoleModel.makeModel (   self,
  x,
  flux,
  xcenPos,
  ycenPos,
  xcenNeg,
  ycenNeg,
  fluxNeg = None,
  b = None,
  x1 = None,
  y1 = None,
  xy = None,
  x2 = None,
  y2 = None,
  bNeg = None,
  x1Neg = None,
  y1Neg = None,
  xyNeg = None,
  x2Neg = None,
  y2Neg = None,
**  kwargs 
)
Generate dipole model with given parameters.

This is the function whose sum-of-squared difference from data
is minimized by `lmfit`.

x : TODO: DM-17458
    Input independent variable. Used here as the grid on
    which to compute the background gradient model.
flux : `float`
    Desired flux of the positive lobe of the dipole
xcenPos : `float`
    Desired x-centroid of the positive lobe of the dipole
ycenPos : `float`
    Desired y-centroid of the positive lobe of the dipole
xcenNeg : `float`
    Desired x-centroid of the negative lobe of the dipole
ycenNeg : `float`
    Desired y-centroid of the negative lobe of the dipole
fluxNeg : `float`, optional
    Desired flux of the negative lobe of the dipole, set to 'flux' if None
b, x1, y1, xy, x2, y2 : `float`
    Gradient parameters for positive lobe.
bNeg, x1Neg, y1Neg, xyNeg, x2Neg, y2Neg : `float`, optional
    Gradient parameters for negative lobe.
    They are set to the corresponding positive values if None.

**kwargs
    Keyword arguments passed through ``lmfit`` and
    used by this function. These must include:

    - ``psf`` Psf model used to generate the 'star'
    - ``rel_weight`` Used to signify least-squares weighting of posImage/negImage
        relative to diffim. If ``rel_weight == 0`` then posImage/negImage are ignored.
    - ``bbox`` Bounding box containing region to be modelled

Returns
-------
zout : `numpy.array`
    Has width and height matching the input bbox, and
    contains the dipole model with given centroids and flux(es). If
    ``rel_weight`` = 0, this is a 2-d array with dimensions matching
    those of bbox; otherwise a stack of three such arrays,
    representing the dipole (diffim), positive and negative images
    respectively.

Definition at line 384 of file dipoleFitTask.py.

387  **kwargs):
388  """Generate dipole model with given parameters.
389 
390  This is the function whose sum-of-squared difference from data
391  is minimized by `lmfit`.
392 
393  x : TODO: DM-17458
394  Input independent variable. Used here as the grid on
395  which to compute the background gradient model.
396  flux : `float`
397  Desired flux of the positive lobe of the dipole
398  xcenPos : `float`
399  Desired x-centroid of the positive lobe of the dipole
400  ycenPos : `float`
401  Desired y-centroid of the positive lobe of the dipole
402  xcenNeg : `float`
403  Desired x-centroid of the negative lobe of the dipole
404  ycenNeg : `float`
405  Desired y-centroid of the negative lobe of the dipole
406  fluxNeg : `float`, optional
407  Desired flux of the negative lobe of the dipole, set to 'flux' if None
408  b, x1, y1, xy, x2, y2 : `float`
409  Gradient parameters for positive lobe.
410  bNeg, x1Neg, y1Neg, xyNeg, x2Neg, y2Neg : `float`, optional
411  Gradient parameters for negative lobe.
412  They are set to the corresponding positive values if None.
413 
414  **kwargs
415  Keyword arguments passed through ``lmfit`` and
416  used by this function. These must include:
417 
418  - ``psf`` Psf model used to generate the 'star'
419  - ``rel_weight`` Used to signify least-squares weighting of posImage/negImage
420  relative to diffim. If ``rel_weight == 0`` then posImage/negImage are ignored.
421  - ``bbox`` Bounding box containing region to be modelled
422 
423  Returns
424  -------
425  zout : `numpy.array`
426  Has width and height matching the input bbox, and
427  contains the dipole model with given centroids and flux(es). If
428  ``rel_weight`` = 0, this is a 2-d array with dimensions matching
429  those of bbox; otherwise a stack of three such arrays,
430  representing the dipole (diffim), positive and negative images
431  respectively.
432  """
433 
434  psf = kwargs.get('psf')
435  rel_weight = kwargs.get('rel_weight') # if > 0, we're including pre-sub. images
436  fp = kwargs.get('footprint')
437  bbox = fp.getBBox()
438 
439  if fluxNeg is None:
440  fluxNeg = flux
441 
442  if self.debug:
443  self.log.debug('%.2f %.2f %.2f %.2f %.2f %.2f',
444  flux, fluxNeg, xcenPos, ycenPos, xcenNeg, ycenNeg)
445  if x1 is not None:
446  self.log.debug(' %.2f %.2f %.2f', b, x1, y1)
447  if xy is not None:
448  self.log.debug(' %.2f %.2f %.2f', xy, x2, y2)
449 
450  posIm = self.makeStarModel(bbox, psf, xcenPos, ycenPos, flux)
451  negIm = self.makeStarModel(bbox, psf, xcenNeg, ycenNeg, fluxNeg)
452 
453  in_x = x
454  if in_x is None: # use the footprint to generate the input grid
455  y, x = np.mgrid[bbox.getBeginY():bbox.getEndY(), bbox.getBeginX():bbox.getEndX()]
456  in_x = np.array([x, y]) * 1.
457  in_x[0, :] -= in_x[0, :].mean() # center it!
458  in_x[1, :] -= in_x[1, :].mean()
459 
460  if b is not None:
461  gradient = self.makeBackgroundModel(in_x, (b, x1, y1, xy, x2, y2))
462 
463  # If bNeg is None, then don't fit the negative background separately
464  if bNeg is not None:
465  gradientNeg = self.makeBackgroundModel(in_x, (bNeg, x1Neg, y1Neg, xyNeg, x2Neg, y2Neg))
466  else:
467  gradientNeg = gradient
468 
469  posIm.getArray()[:, :] += gradient
470  negIm.getArray()[:, :] += gradientNeg
471 
472  # Generate the diffIm model
473  diffIm = afwImage.ImageF(bbox)
474  diffIm += posIm
475  diffIm -= negIm
476 
477  zout = diffIm.getArray()
478  if rel_weight > 0.:
479  zout = np.append([zout], [posIm.getArray(), negIm.getArray()], axis=0)
480 
481  return zout
482 
483 

◆ makeStarModel()

def lsst.ip.diffim.dipoleFitTask.DipoleModel.makeStarModel (   self,
  bbox,
  psf,
  xcen,
  ycen,
  flux 
)
Generate a 2D image model of a single PDF centered at the given coordinates.

Parameters
----------
bbox : `lsst.geom.Box`
    Bounding box marking pixel coordinates for generated model
psf : TODO: DM-17458
    Psf model used to generate the 'star'
xcen : `float`
    Desired x-centroid of the 'star'
ycen : `float`
    Desired y-centroid of the 'star'
flux : `float`
    Desired flux of the 'star'

Returns
-------
p_Im : `lsst.afw.image.Image`
    2-d stellar image of width/height matching input ``bbox``,
    containing PSF with given centroid and flux

Definition at line 341 of file dipoleFitTask.py.

341  def makeStarModel(self, bbox, psf, xcen, ycen, flux):
342  """Generate a 2D image model of a single PDF centered at the given coordinates.
343 
344  Parameters
345  ----------
346  bbox : `lsst.geom.Box`
347  Bounding box marking pixel coordinates for generated model
348  psf : TODO: DM-17458
349  Psf model used to generate the 'star'
350  xcen : `float`
351  Desired x-centroid of the 'star'
352  ycen : `float`
353  Desired y-centroid of the 'star'
354  flux : `float`
355  Desired flux of the 'star'
356 
357  Returns
358  -------
359  p_Im : `lsst.afw.image.Image`
360  2-d stellar image of width/height matching input ``bbox``,
361  containing PSF with given centroid and flux
362  """
363 
364  # Generate the psf image, normalize to flux
365  psf_img = psf.computeImage(geom.Point2D(xcen, ycen)).convertF()
366  psf_img_sum = np.nansum(psf_img.getArray())
367  psf_img *= (flux/psf_img_sum)
368 
369  # Clip the PSF image bounding box to fall within the footprint bounding box
370  psf_box = psf_img.getBBox()
371  psf_box.clip(bbox)
372  psf_img = afwImage.ImageF(psf_img, psf_box, afwImage.PARENT)
373 
374  # Then actually crop the psf image.
375  # Usually not necessary, but if the dipole is near the edge of the image...
376  # Would be nice if we could compare original pos_box with clipped pos_box and
377  # see if it actually was clipped.
378  p_Im = afwImage.ImageF(bbox)
379  tmpSubim = afwImage.ImageF(p_Im, psf_box, afwImage.PARENT)
380  tmpSubim += psf_img
381 
382  return p_Im
383 

Member Data Documentation

◆ debug

lsst.ip.diffim.dipoleFitTask.DipoleModel.debug

Definition at line 190 of file dipoleFitTask.py.

◆ log

lsst.ip.diffim.dipoleFitTask.DipoleModel.log

Definition at line 191 of file dipoleFitTask.py.


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