LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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 179 of file dipoleFitTask.py.

Constructor & Destructor Documentation

◆ __init__()

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

Definition at line 187 of file dipoleFitTask.py.

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

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 282 of file dipoleFitTask.py.

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

◆ 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 192 of file dipoleFitTask.py.

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

◆ 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 383 of file dipoleFitTask.py.

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

◆ 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 340 of file dipoleFitTask.py.

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

Member Data Documentation

◆ debug

lsst.ip.diffim.dipoleFitTask.DipoleModel.debug

Definition at line 189 of file dipoleFitTask.py.

◆ log

lsst.ip.diffim.dipoleFitTask.DipoleModel.log

Definition at line 190 of file dipoleFitTask.py.


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