LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | List of all members
lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer Class Reference

A measurePsfTask psf estimator. More...

Inheritance diagram for lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer:

Public Member Functions

def __init__
 Construct a PCA PSF Fitter. More...
 
def determinePsf
 Determine a PCA PSF model for an exposure given a list of PSF candidates. More...
 

Public Attributes

 config
 
 debugLog
 
 warnLog
 

Static Public Attributes

 ConfigClass = PcaPsfDeterminerConfig
 

Private Member Functions

def _fitPsf
 

Detailed Description

A measurePsfTask psf estimator.

Definition at line 143 of file pcaPsfDeterminer.py.

Constructor & Destructor Documentation

def lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.__init__ (   self,
  config 
)

Construct a PCA PSF Fitter.

Parameters
[in]configinstance of PcaPsfDeterminerConfig

Definition at line 149 of file pcaPsfDeterminer.py.

150  def __init__(self, config):
151  """!Construct a PCA PSF Fitter
152 
153  \param[in] config instance of PcaPsfDeterminerConfig
154  """
155  self.config = config
156  # N.b. name of component is meas.algorithms.psfDeterminer so you can turn on psf debugging
157  # independent of which determiner is active
158  self.debugLog = pexLog.Debug("meas.algorithms.psfDeterminer")
159  self.warnLog = pexLog.Log(pexLog.getDefaultLog(), "meas.algorithms.psfDeterminer")
a place to record messages and descriptions of the state of processing.
Definition: Log.h:154

Member Function Documentation

def lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer._fitPsf (   self,
  exposure,
  psfCellSet,
  kernelSize,
  nEigenComponents 
)
private

Definition at line 160 of file pcaPsfDeterminer.py.

161  def _fitPsf(self, exposure, psfCellSet, kernelSize, nEigenComponents):
162  algorithmsLib.PsfCandidateF.setPixelThreshold(self.config.pixelThreshold)
163  algorithmsLib.PsfCandidateF.setMaskBlends(self.config.doMaskBlends)
164  #
165  # Loop trying to use nEigenComponents, but allowing smaller numbers if necessary
166  #
167  for nEigen in range(nEigenComponents, 0, -1):
168  # Determine KL components
169  try:
170  kernel, eigenValues = algorithmsLib.createKernelFromPsfCandidates(
171  psfCellSet, exposure.getDimensions(), exposure.getXY0(), nEigen,
172  self.config.spatialOrder, kernelSize, self.config.nStarPerCell,
173  bool(self.config.constantWeight))
174 
175  break # OK, we can get nEigen components
176  except pexExceptions.LengthError as e:
177  if nEigen == 1: # can't go any lower
178  raise
179 
180  self.warnLog.log(pexLog.Log.WARN, "%s: reducing number of eigen components" % e.what())
181  #
182  # We got our eigen decomposition so let's use it
183  #
184  # Express eigenValues in units of reduced chi^2 per star
185  size = kernelSize + 2*self.config.borderWidth
186  nu = size*size - 1 # number of degrees of freedom/star for chi^2
187  eigenValues = [l/float(algorithmsLib.countPsfCandidates(psfCellSet, self.config.nStarPerCell)*nu)
188  for l in eigenValues]
189 
190  # Fit spatial model
191  status, chi2 = algorithmsLib.fitSpatialKernelFromPsfCandidates(
192  kernel, psfCellSet, bool(self.config.nonLinearSpatialFit),
193  self.config.nStarPerCellSpatialFit, self.config.tolerance, self.config.lam)
194 
195  psf = algorithmsLib.PcaPsf(kernel)
196 
197  return psf, eigenValues, nEigen, chi2
198 
def lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.determinePsf (   self,
  exposure,
  psfCandidateList,
  metadata = None,
  flagKey = None 
)

Determine a PCA PSF model for an exposure given a list of PSF candidates.

Parameters
[in]exposureexposure containing the psf candidates (lsst.afw.image.Exposure)
[in]psfCandidateLista sequence of PSF candidates (each an lsst.meas.algorithms.PsfCandidate); typically obtained by detecting sources and then running them through a star selector
[in,out]metadataa home for interesting tidbits of information
[in]flagKeyschema key used to mark sources actually used in PSF determination
Returns
a list of
  • psf: the measured PSF, an lsst.meas.algorithms.PcaPsf
  • cellSet: an lsst.afw.math.SpatialCellSet containing the PSF candidates

Definition at line 199 of file pcaPsfDeterminer.py.

200  def determinePsf(self, exposure, psfCandidateList, metadata=None, flagKey=None):
201  """!Determine a PCA PSF model for an exposure given a list of PSF candidates
202 
203  \param[in] exposure exposure containing the psf candidates (lsst.afw.image.Exposure)
204  \param[in] psfCandidateList a sequence of PSF candidates (each an lsst.meas.algorithms.PsfCandidate);
205  typically obtained by detecting sources and then running them through a star selector
206  \param[in,out] metadata a home for interesting tidbits of information
207  \param[in] flagKey schema key used to mark sources actually used in PSF determination
208 
209  \return a list of
210  - psf: the measured PSF, an lsst.meas.algorithms.PcaPsf
211  - cellSet: an lsst.afw.math.SpatialCellSet containing the PSF candidates
212  """
213  import lsstDebug
214  display = lsstDebug.Info(__name__).display
215  displayExposure = lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells
216  displayPsfCandidates = lsstDebug.Info(__name__).displayPsfCandidates # show the viable candidates
217  displayIterations = lsstDebug.Info(__name__).displayIterations # display on each PSF iteration
218  displayPsfComponents = lsstDebug.Info(__name__).displayPsfComponents # show the PCA components
219  displayResiduals = lsstDebug.Info(__name__).displayResiduals # show residuals
220  displayPsfMosaic = lsstDebug.Info(__name__).displayPsfMosaic # show mosaic of reconstructed PSF(x,y)
221  matchKernelAmplitudes = lsstDebug.Info(__name__).matchKernelAmplitudes # match Kernel amplitudes for spatial plots
222  keepMatplotlibPlots = lsstDebug.Info(__name__).keepMatplotlibPlots # Keep matplotlib alive post mortem
223  displayPsfSpatialModel = lsstDebug.Info(__name__).displayPsfSpatialModel # Plot spatial model?
224  showBadCandidates = lsstDebug.Info(__name__).showBadCandidates # Include bad candidates
225  normalizeResiduals = lsstDebug.Info(__name__).normalizeResiduals # Normalise residuals by object amplitude
226  pause = lsstDebug.Info(__name__).pause # Prompt user after each iteration?
227 
228  if display > 1:
229  pause = True
230 
231  mi = exposure.getMaskedImage()
232 
233  if len(psfCandidateList) == 0:
234  raise RuntimeError("No PSF candidates supplied.")
235 
236  # construct and populate a spatial cell set
237  bbox = mi.getBBox()
238  psfCellSet = afwMath.SpatialCellSet(bbox, self.config.sizeCellX, self.config.sizeCellY)
239  sizes = []
240  for i, psfCandidate in enumerate(psfCandidateList):
241  try:
242  psfCellSet.insertCandidate(psfCandidate)
243  except Exception, e:
244  self.debugLog.debug(2, "Skipping PSF candidate %d of %d: %s" % (i, len(psfCandidateList), e))
245  continue
246  source = psfCandidate.getSource()
247 
248  quad = afwEll.Quadrupole(source.getIxx(), source.getIyy(), source.getIxy())
249  axes = afwEll.Axes(quad)
250  sizes.append(axes.getA())
251  if len(sizes) == 0:
252  raise RuntimeError("No usable PSF candidates supplied")
253  nEigenComponents = self.config.nEigenComponents # initial version
254 
255  if self.config.kernelSize >= 15:
256  self.debugLog.debug(1, \
257  "WARNING: NOT scaling kernelSize by stellar quadrupole moment " +
258  "because config.kernelSize=%s >= 15; using config.kernelSize as as the width, instead" \
259  % (self.config.kernelSize,)
260  )
261  actualKernelSize = int(self.config.kernelSize)
262  else:
263  medSize = numpy.median(sizes)
264  actualKernelSize = 2 * int(self.config.kernelSize * math.sqrt(medSize) + 0.5) + 1
265  if actualKernelSize < self.config.kernelSizeMin:
266  actualKernelSize = self.config.kernelSizeMin
267  if actualKernelSize > self.config.kernelSizeMax:
268  actualKernelSize = self.config.kernelSizeMax
269 
270  if display:
271  print "Median size=%s" % (medSize,)
272  self.debugLog.debug(3, "Kernel size=%s" % (actualKernelSize,))
273 
274  # Set size of image returned around candidate
275  psfCandidateList[0].setHeight(actualKernelSize)
276  psfCandidateList[0].setWidth(actualKernelSize)
277 
278  if self.config.doRejectBlends:
279  # Remove blended candidates completely
280  blendedCandidates = [] # Candidates to remove; can't do it while iterating
281  for cell, cand in candidatesIter(psfCellSet, False):
282  if len(cand.getSource().getFootprint().getPeaks()) > 1:
283  blendedCandidates.append((cell, cand))
284  continue
285  if display:
286  print "Removing %d blended Psf candidates" % len(blendedCandidates)
287  for cell, cand in blendedCandidates:
288  cell.removeCandidate(cand)
289  if sum(1 for cand in candidatesIter(psfCellSet, False)) == 0:
290  raise RuntimeError("All PSF candidates removed as blends")
291 
292  if display:
293  frame = 0
294  if displayExposure:
295  ds9.mtv(exposure, frame=frame, title="psf determination")
296  maUtils.showPsfSpatialCells(exposure, psfCellSet, self.config.nStarPerCell,
297  symb="o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW,
298  size=4, frame=frame)
299 
300  #
301  # Do a PCA decomposition of those PSF candidates
302  #
303  reply = "y" # used in interactive mode
304  for iter in range(self.config.nIterForPsf):
305  if display and displayPsfCandidates: # Show a mosaic of usable PSF candidates
306  #
307  import lsst.afw.display.utils as displayUtils
308 
309  stamps = []
310  for cell in psfCellSet.getCellList():
311  for cand in cell.begin(not showBadCandidates): # maybe include bad candidates
312  cand = algorithmsLib.cast_PsfCandidateF(cand)
313 
314  try:
315  im = cand.getMaskedImage()
316 
317  chi2 = cand.getChi2()
318  if chi2 > 1e100:
319  chi2 = numpy.nan
320 
321  stamps.append((im, "%d%s" %
322  (maUtils.splitId(cand.getSource().getId(), True)["objId"], chi2),
323  cand.getStatus()))
324  except Exception, e:
325  continue
326 
327  mos = displayUtils.Mosaic()
328  for im, label, status in stamps:
329  im = type(im)(im, True)
330  try:
331  im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()
332  except NotImplementedError:
333  pass
334 
335  mos.append(im, label,
336  ds9.GREEN if status == afwMath.SpatialCellCandidate.GOOD else
337  ds9.YELLOW if status == afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)
338 
339 
340  if mos.images:
341  mos.makeMosaic(frame=8, title="Psf Candidates")
342 
343  # Re-fit until we don't have any candidates with naughty chi^2 values influencing the fit
344  cleanChi2 = False # Any naughty (negative/NAN) chi^2 values?
345  while not cleanChi2:
346  cleanChi2 = True
347  #
348  # First, estimate the PSF
349  #
350  psf, eigenValues, nEigenComponents, fitChi2 = \
351  self._fitPsf(exposure, psfCellSet, actualKernelSize, nEigenComponents)
352  #
353  # In clipping, allow all candidates to be innocent until proven guilty on this iteration.
354  # Throw out any prima facie guilty candidates (naughty chi^2 values)
355  #
356  for cell in psfCellSet.getCellList():
357  awfulCandidates = []
358  for cand in cell.begin(False): # include bad candidates
359  cand = algorithmsLib.cast_PsfCandidateF(cand)
360  cand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN) # until proven guilty
361  rchi2 = cand.getChi2()
362  if not numpy.isfinite(rchi2) or rchi2 <= 0:
363  # Guilty prima facie
364  awfulCandidates.append(cand)
365  cleanChi2 = False
366  self.debugLog.debug(2, "chi^2=%s; id=%s" %
367  (cand.getChi2(), cand.getSource().getId()))
368  for cand in awfulCandidates:
369  if display:
370  print "Removing bad candidate: id=%d, chi^2=%f" % \
371  (cand.getSource().getId(), cand.getChi2())
372  cell.removeCandidate(cand)
373 
374  #
375  # Clip out bad fits based on reduced chi^2
376  #
377  badCandidates = list()
378  for cell in psfCellSet.getCellList():
379  for cand in cell.begin(False): # include bad candidates
380  cand = algorithmsLib.cast_PsfCandidateF(cand)
381  rchi2 = cand.getChi2() # reduced chi^2 when fitting PSF to candidate
382  assert rchi2 > 0
383  if rchi2 > self.config.reducedChi2ForPsfCandidates:
384  badCandidates.append(cand)
385 
386  badCandidates.sort(key=lambda x: x.getChi2(), reverse=True)
387  numBad = int(len(badCandidates) * (iter + 1) / self.config.nIterForPsf + 0.5)
388  for i, c in zip(range(numBad), badCandidates):
389  if display:
390  chi2 = c.getChi2()
391  if chi2 > 1e100:
392  chi2 = numpy.nan
393 
394  print "Chi^2 clipping %-4d %.2g" % (c.getSource().getId(), chi2)
395  c.setStatus(afwMath.SpatialCellCandidate.BAD)
396 
397  #
398  # Clip out bad fits based on spatial fitting.
399  #
400  # This appears to be better at getting rid of sources that have a single dominant kernel component
401  # (other than the zeroth; e.g., a nearby contaminant) because the surrounding sources (which help
402  # set the spatial model) don't contain that kernel component, and so the spatial modeling
403  # downweights the component.
404  #
405 
406  residuals = list()
407  candidates = list()
408  kernel = psf.getKernel()
409  noSpatialKernel = afwMath.cast_LinearCombinationKernel(psf.getKernel())
410  for cell in psfCellSet.getCellList():
411  for cand in cell.begin(False):
412  cand = algorithmsLib.cast_PsfCandidateF(cand)
413  candCenter = afwGeom.PointD(cand.getXCenter(), cand.getYCenter())
414  try:
415  im = cand.getMaskedImage(kernel.getWidth(), kernel.getHeight())
416  except Exception, e:
417  continue
418 
419  fit = algorithmsLib.fitKernelParamsToImage(noSpatialKernel, im, candCenter)
420  params = fit[0]
421  kernels = fit[1]
422  amp = 0.0
423  for p, k in zip(params, kernels):
424  amp += p * afwMath.cast_FixedKernel(k).getSum()
425 
426  predict = [kernel.getSpatialFunction(k)(candCenter.getX(), candCenter.getY()) for
427  k in range(kernel.getNKernelParameters())]
428 
429  #print cand.getSource().getId(), [a / amp for a in params], predict
430 
431  residuals.append([a / amp - p for a, p in zip(params, predict)])
432  candidates.append(cand)
433 
434  residuals = numpy.array(residuals)
435 
436  for k in range(kernel.getNKernelParameters()):
437  if False:
438  # Straight standard deviation
439  mean = residuals[:,k].mean()
440  rms = residuals[:,k].std()
441  elif False:
442  # Using interquartile range
443  sr = numpy.sort(residuals[:,k])
444  mean = sr[int(0.5*len(sr))] if len(sr) % 2 else \
445  0.5 * (sr[int(0.5*len(sr))] + sr[int(0.5*len(sr))+1])
446  rms = 0.74 * (sr[int(0.75*len(sr))] - sr[int(0.25*len(sr))])
447  else:
448  stats = afwMath.makeStatistics(residuals[:,k], afwMath.MEANCLIP | afwMath.STDEVCLIP)
449  mean = stats.getValue(afwMath.MEANCLIP)
450  rms = stats.getValue(afwMath.STDEVCLIP)
451 
452  rms = max(1.0e-4, rms) # Don't trust RMS below this due to numerical issues
453 
454  if display:
455  print "Mean for component %d is %f" % (k, mean)
456  print "RMS for component %d is %f" % (k, rms)
457  badCandidates = list()
458  for i, cand in enumerate(candidates):
459  if numpy.fabs(residuals[i,k] - mean) > self.config.spatialReject * rms:
460  badCandidates.append(i)
461 
462  badCandidates.sort(key=lambda x: numpy.fabs(residuals[x,k] - mean), reverse=True)
463 
464  numBad = int(len(badCandidates) * (iter + 1) / self.config.nIterForPsf + 0.5)
465 
466  for i, c in zip(range(min(len(badCandidates), numBad)), badCandidates):
467  cand = candidates[c]
468  if display:
469  print "Spatial clipping %d (%f,%f) based on %d: %f vs %f" % \
470  (cand.getSource().getId(), cand.getXCenter(), cand.getYCenter(), k,
471  residuals[badCandidates[i],k], self.config.spatialReject * rms)
472  cand.setStatus(afwMath.SpatialCellCandidate.BAD)
473 
474  #
475  # Display results
476  #
477  if display and displayIterations:
478  if displayExposure:
479  if iter > 0:
480  ds9.erase(frame=frame)
481  maUtils.showPsfSpatialCells(exposure, psfCellSet, self.config.nStarPerCell, showChi2=True,
482  symb="o", size=8, frame=frame,
483  ctype=ds9.YELLOW, ctypeBad=ds9.RED, ctypeUnused=ds9.MAGENTA)
484  if self.config.nStarPerCellSpatialFit != self.config.nStarPerCell:
485  maUtils.showPsfSpatialCells(exposure, psfCellSet, self.config.nStarPerCellSpatialFit,
486  symb="o", size=10, frame=frame,
487  ctype=ds9.YELLOW, ctypeBad=ds9.RED)
488  if displayResiduals:
489  while True:
490  try:
491  maUtils.showPsfCandidates(exposure, psfCellSet, psf=psf, frame=4,
492  normalize=normalizeResiduals,
493  showBadCandidates=showBadCandidates)
494  maUtils.showPsfCandidates(exposure, psfCellSet, psf=psf, frame=5,
495  normalize=normalizeResiduals,
496  showBadCandidates=showBadCandidates,
497  variance=True)
498  except:
499  if not showBadCandidates:
500  showBadCandidates = True
501  continue
502  break
503 
504  if displayPsfComponents:
505  maUtils.showPsf(psf, eigenValues, frame=6)
506  if displayPsfMosaic:
507  maUtils.showPsfMosaic(exposure, psf, frame=7, showFwhm=True)
508  ds9.scale('linear', 0, 1, frame=7)
509  if displayPsfSpatialModel:
510  maUtils.plotPsfSpatialModel(exposure, psf, psfCellSet, showBadCandidates=True,
511  matchKernelAmplitudes=matchKernelAmplitudes,
512  keepPlots=keepMatplotlibPlots)
513 
514  if pause:
515  while True:
516  try:
517  reply = raw_input("Next iteration? [ynchpqQs] ").strip()
518  except EOFError:
519  reply = "n"
520 
521  reply = reply.split()
522  if reply:
523  reply, args = reply[0], reply[1:]
524  else:
525  reply = ""
526 
527  if reply in ("", "c", "h", "n", "p", "q", "Q", "s", "y"):
528  if reply == "c":
529  pause = False
530  elif reply == "h":
531  print "c[ontinue without prompting] h[elp] n[o] p[db] q[uit displaying] s[ave fileName] y[es]"
532  continue
533  elif reply == "p":
534  import pdb; pdb.set_trace()
535  elif reply == "q":
536  display = False
537  elif reply == "Q":
538  sys.exit(1)
539  elif reply == "s":
540  fileName = args.pop(0)
541  if not fileName:
542  print "Please provide a filename"
543  continue
544 
545  print "Saving to %s" % fileName
546  maUtils.saveSpatialCellSet(psfCellSet, fileName=fileName)
547  continue
548  break
549  else:
550  print >> sys.stderr, "Unrecognised response: %s" % reply
551 
552  if reply == "n":
553  break
554 
555  # One last time, to take advantage of the last iteration
556  psf, eigenValues, nEigenComponents, fitChi2 = \
557  self._fitPsf(exposure, psfCellSet, actualKernelSize, nEigenComponents)
558 
559  #
560  # Display code for debugging
561  #
562  if display and reply != "n":
563  if displayExposure:
564  maUtils.showPsfSpatialCells(exposure, psfCellSet, self.config.nStarPerCell, showChi2=True,
565  symb="o", ctype=ds9.YELLOW, ctypeBad=ds9.RED, size=8, frame=frame)
566  if self.config.nStarPerCellSpatialFit != self.config.nStarPerCell:
567  maUtils.showPsfSpatialCells(exposure, psfCellSet, self.config.nStarPerCellSpatialFit,
568  symb="o", ctype=ds9.YELLOW, ctypeBad=ds9.RED,
569  size=10, frame=frame)
570  if displayResiduals:
571  maUtils.showPsfCandidates(exposure, psfCellSet, psf=psf, frame=4,
572  normalize=normalizeResiduals,
573  showBadCandidates=showBadCandidates)
574 
575  if displayPsfComponents:
576  maUtils.showPsf(psf, eigenValues, frame=6)
577 
578  if displayPsfMosaic:
579  maUtils.showPsfMosaic(exposure, psf, frame=7, showFwhm=True)
580  ds9.scale("linear", 0, 1, frame=7)
581  if displayPsfSpatialModel:
582  maUtils.plotPsfSpatialModel(exposure, psf, psfCellSet, showBadCandidates=True,
583  matchKernelAmplitudes=matchKernelAmplitudes,
584  keepPlots=keepMatplotlibPlots)
585  #
586  # Generate some QA information
587  #
588  # Count PSF stars
589  #
590  numGoodStars = 0
591  numAvailStars = 0
592 
593  avgX = 0.0
594  avgY = 0.0
595 
596  for cell in psfCellSet.getCellList():
597  for cand in cell.begin(False): # don't ignore BAD stars
598  numAvailStars += 1
599 
600  for cand in cell.begin(True): # do ignore BAD stars
601  cand = algorithmsLib.cast_PsfCandidateF(cand)
602  src = cand.getSource()
603  if flagKey is not None:
604  src.set(flagKey, True)
605  avgX += src.getX()
606  avgY += src.getY()
607  numGoodStars += 1
608 
609  avgX /= numGoodStars
610  avgY /= numGoodStars
611 
612  if metadata != None:
613  metadata.set("spatialFitChi2", fitChi2)
614  metadata.set("numGoodStars", numGoodStars)
615  metadata.set("numAvailStars", numAvailStars)
616  metadata.set("avgX", avgX)
617  metadata.set("avgY", avgY)
618 
619  psf = algorithmsLib.PcaPsf(psf.getKernel(), afwGeom.Point2D(avgX, avgY))
620 
621  return psf, psfCellSet
622 
STL namespace.
boost::enable_if< typename ExpressionTraits< Scalar >::IsScalar, Scalar >::type sum(Scalar const &scalar)
Definition: operators.h:1250
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:378
def determinePsf
Determine a PCA PSF model for an exposure given a list of PSF candidates.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1082
def candidatesIter
Generator for Psf candidates.

Member Data Documentation

lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.config

Definition at line 154 of file pcaPsfDeterminer.py.

lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.ConfigClass = PcaPsfDeterminerConfig
static

Definition at line 147 of file pcaPsfDeterminer.py.

lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.debugLog

Definition at line 157 of file pcaPsfDeterminer.py.

lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.warnLog

Definition at line 158 of file pcaPsfDeterminer.py.


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