367 self, exposure, psfCandidateList, metadata=None, flagKey=None
369 """Determine a Piff PSF model for an exposure given a list of PSF
374 exposure : `lsst.afw.image.Exposure`
375 Exposure containing the PSF candidates.
376 psfCandidateList : `list` of `lsst.meas.algorithms.PsfCandidate`
377 A sequence of PSF candidates typically obtained by detecting sources
378 and then running them through a star selector.
379 metadata : `lsst.daf.base import PropertyList` or `None`, optional
380 A home for interesting tidbits of information.
381 flagKey : `str` or `None`, optional
382 Schema key used to mark sources actually used in PSF determination.
386 psf : `lsst.meas.extensions.piff.PiffPsf`
387 The measured PSF model.
389 Unused by this PsfDeterminer.
393 if self.config.stampSize:
394 stampSize = self.config.stampSize
395 if stampSize > psfCandidateList[0].getWidth():
396 self.log.warning(
"stampSize is larger than the PSF candidate size. Using candidate size.")
397 stampSize = psfCandidateList[0].getWidth()
399 self.log.debug(
"stampSize not set. Using candidate size.")
400 stampSize = psfCandidateList[0].getWidth()
402 scale = exposure.getWcs().getPixelScale(exposure.getBBox().getCenter()).asArcseconds()
404 match self.config.useCoordinates:
406 detector = exposure.getDetector()
407 pix_to_field = detector.getTransform(PIXELS, FIELD_ANGLE)
413 skyOrigin = exposure.getWcs().getSkyOrigin()
414 ra = skyOrigin.getLongitude().asDegrees()
415 dec = skyOrigin.getLatitude().asDegrees()
416 pointing = galsim.CelestialCoord(
422 gswcs = galsim.PixelScale(scale)
426 for candidate
in psfCandidateList:
427 cmi = candidate.getMaskedImage(stampSize, stampSize)
429 fracGood = np.sum(good)/good.size
430 if fracGood < self.config.minimumUnmaskedFraction:
435 bds = galsim.BoundsI(
436 galsim.PositionI(*bbox.getMin()),
437 galsim.PositionI(*bbox.getMax())
439 gsImage = galsim.Image(bds, wcs=gswcs, dtype=float)
440 gsImage.array[:] = cmi.image.array
441 gsWeight = galsim.Image(bds, wcs=gswcs, dtype=float)
442 gsWeight.array[:] = weight
444 source = candidate.getSource()
445 image_pos = galsim.PositionD(source.getX(), source.getY())
447 data = piff.StarData(
453 stars.append(piff.Star(data,
None))
455 if self.config.piffPsfConfigYaml
is None:
460 'scale': scale * self.config.samplingSize,
461 'size': self.config.modelSize,
462 'interp': self.config.interpolant,
463 'centered': self.config.piffPixelGridFitCenter,
466 'type':
'BasisPolynomial',
467 'order': self.config.spatialOrder,
468 'solver': self.config.piffBasisPolynomialSolver,
472 'nsigma': self.config.outlierNSigma,
473 'max_remove': self.config.outlierMaxRemove,
475 'max_iter': self.config.piffMaxIter
478 piffConfig = yaml.safe_load(self.config.piffPsfConfigYaml)
480 def _get_threshold(nth_order):
482 freeParameters = ((nth_order + 1) * (nth_order + 2)) // 2
483 return freeParameters
485 if self.config.zerothOrderInterpNotEnoughStars:
486 if piffConfig[
'interp'][
'type']
in [
'BasisPolynomial',
'Polynomial']:
487 threshold = _get_threshold(piffConfig[
'interp'][
'order'])
488 if len(stars) <= threshold:
490 f
"Only {len(stars)} stars found, "
491 f
"but {threshold} required. Using zeroth order interpolation."
493 piffConfig[
'interp'][
'order'] = 0
496 piffConfig[
'max_iter'] = 1
499 piffResult = piff.PSF.process(piffConfig)
502 piffResult.fit(stars, wcs, pointing, logger=self.
piffLogger)
503 drawSize = 2*np.floor(0.5*stampSize/self.config.samplingSize) + 1
505 used_image_pos = [s.image_pos
for s
in piffResult.stars]
507 for candidate
in psfCandidateList:
508 source = candidate.getSource()
509 posd = galsim.PositionD(source.getX(), source.getY())
510 if posd
in used_image_pos:
511 source.set(flagKey,
True)
513 if metadata
is not None:
514 metadata[
"spatialFitChi2"] = piffResult.chisq
515 metadata[
"numAvailStars"] = len(stars)
516 metadata[
"numGoodStars"] = len(piffResult.stars)
517 metadata[
"avgX"] = np.mean([p.x
for p
in piffResult.stars])
518 metadata[
"avgY"] = np.mean([p.y
for p
in piffResult.stars])
520 if not self.config.debugStarData:
521 for star
in piffResult.stars:
524 del star.fit.params_var
529 del star.data.orig_weight
531 return PiffPsf(drawSize, drawSize, piffResult),
None