338 self, exposure, psfCandidateList, metadata=None, flagKey=None
340 """Determine a Piff PSF model for an exposure given a list of PSF
345 exposure : `lsst.afw.image.Exposure`
346 Exposure containing the PSF candidates.
347 psfCandidateList : `list` of `lsst.meas.algorithms.PsfCandidate`
348 A sequence of PSF candidates typically obtained by detecting sources
349 and then running them through a star selector.
350 metadata : `lsst.daf.base import PropertyList` or `None`, optional
351 A home for interesting tidbits of information.
352 flagKey : `str` or `None`, optional
353 Schema key used to mark sources actually used in PSF determination.
357 psf : `lsst.meas.extensions.piff.PiffPsf`
358 The measured PSF model.
360 Unused by this PsfDeterminer.
364 if self.config.stampSize:
365 stampSize = self.config.stampSize
366 if stampSize > psfCandidateList[0].getWidth():
367 self.log.warning(
"stampSize is larger than the PSF candidate size. Using candidate size.")
368 stampSize = psfCandidateList[0].getWidth()
370 self.log.debug(
"stampSize not set. Using candidate size.")
371 stampSize = psfCandidateList[0].getWidth()
373 scale = exposure.getWcs().getPixelScale(exposure.getBBox().getCenter()).asArcseconds()
375 match self.config.useCoordinates:
377 detector = exposure.getDetector()
378 pix_to_field = detector.getTransform(PIXELS, FIELD_ANGLE)
384 skyOrigin = exposure.getWcs().getSkyOrigin()
385 ra = skyOrigin.getLongitude().asDegrees()
386 dec = skyOrigin.getLatitude().asDegrees()
387 pointing = galsim.CelestialCoord(
393 gswcs = galsim.PixelScale(scale)
397 for candidate
in psfCandidateList:
398 cmi = candidate.getMaskedImage(stampSize, stampSize)
400 fracGood = np.sum(good)/good.size
401 if fracGood < self.config.minimumUnmaskedFraction:
406 bds = galsim.BoundsI(
407 galsim.PositionI(*bbox.getMin()),
408 galsim.PositionI(*bbox.getMax())
410 gsImage = galsim.Image(bds, wcs=gswcs, dtype=float)
411 gsImage.array[:] = cmi.image.array
412 gsWeight = galsim.Image(bds, wcs=gswcs, dtype=float)
413 gsWeight.array[:] = weight
415 source = candidate.getSource()
416 image_pos = galsim.PositionD(source.getX(), source.getY())
418 data = piff.StarData(
424 stars.append(piff.Star(data,
None))
426 if self.config.piffPsfConfigYaml
is None:
431 'scale': scale * self.config.samplingSize,
432 'size': self.config.modelSize,
433 'interp': self.config.interpolant,
436 'type':
'BasisPolynomial',
437 'order': self.config.spatialOrder,
441 'nsigma': self.config.outlierNSigma,
442 'max_remove': self.config.outlierMaxRemove,
446 piffConfig = yaml.safe_load(self.config.piffPsfConfigYaml)
448 piffResult = piff.PSF.process(piffConfig)
451 piffResult.fit(stars, wcs, pointing, logger=self.
piffLogger)
452 drawSize = 2*np.floor(0.5*stampSize/self.config.samplingSize) + 1
454 used_image_pos = [s.image_pos
for s
in piffResult.stars]
456 for candidate
in psfCandidateList:
457 source = candidate.getSource()
458 posd = galsim.PositionD(source.getX(), source.getY())
459 if posd
in used_image_pos:
460 source.set(flagKey,
True)
462 if metadata
is not None:
463 metadata[
"spatialFitChi2"] = piffResult.chisq
464 metadata[
"numAvailStars"] = len(stars)
465 metadata[
"numGoodStars"] = len(piffResult.stars)
466 metadata[
"avgX"] = np.mean([p.x
for p
in piffResult.stars])
467 metadata[
"avgY"] = np.mean([p.y
for p
in piffResult.stars])
469 if not self.config.debugStarData:
470 for star
in piffResult.stars:
473 del star.fit.params_var
478 del star.data.orig_weight
480 return PiffPsf(drawSize, drawSize, piffResult),
None