38     __nEigenComponents = pexConfig.Field(
    39         doc=
"number of eigen components for PSF kernel creation",
    43     spatialOrder = pexConfig.Field(
    44         doc=
"specify spatial order for PSF kernel creation",
    47         check=
lambda x: x >= 0,
    49     sizeCellX = pexConfig.Field(
    50         doc=
"size of cell used to determine PSF (pixels, column direction)",
    54         check=
lambda x: x >= 10,
    56     sizeCellY = pexConfig.Field(
    57         doc=
"size of cell used to determine PSF (pixels, row direction)",
    59         default=sizeCellX.default,
    61         check=
lambda x: x >= 10,
    63     __nStarPerCell = pexConfig.Field(
    64         doc=
"number of stars per psf cell for PSF kernel creation",
    68     samplingSize = pexConfig.Field(
    69         doc=
"Resolution of the internal PSF model relative to the pixel size; "    70         "e.g. 0.5 is equal to 2x oversampling",
    74     badMaskBits = pexConfig.ListField(
    75         doc=
"List of mask bits which cause a source to be rejected as bad "    76         "N.b. INTRP is used specially in PsfCandidateSet; it means \"Contaminated by neighbour\"",
    78         default=[
"INTRP", 
"SAT"],
    80     psfexBasis = pexConfig.ChoiceField(
    81         doc=
"BASIS value given to psfex.  PIXEL_AUTO will use the requested samplingSize only if "    82         "the FWHM < 3 pixels.  Otherwise, it will use samplingSize=1.  PIXEL will always use the "    83         "requested samplingSize",
    86             "PIXEL": 
"Always use requested samplingSize",
    87             "PIXEL_AUTO": 
"Only use requested samplingSize when FWHM < 3",
    92     __borderWidth = pexConfig.Field(
    93         doc=
"Number of pixels to ignore around the edge of PSF candidate postage stamps",
    97     __nStarPerCellSpatialFit = pexConfig.Field(
    98         doc=
"number of stars per psf Cell for spatial fitting",
   102     __constantWeight = pexConfig.Field(
   103         doc=
"Should each PSF candidate be given the same weight, independent of magnitude?",
   107     __nIterForPsf = pexConfig.Field(
   108         doc=
"number of iterations of PSF candidate star list",
   112     tolerance = pexConfig.Field(
   113         doc=
"tolerance of spatial fitting",
   117     lam = pexConfig.Field(
   118         doc=
"floor for variance is lam*data",
   122     reducedChi2ForPsfCandidates = pexConfig.Field(
   123         doc=
"for psf candidate evaluation",
   127     spatialReject = pexConfig.Field(
   128         doc=
"Rejection threshold (stdev) for candidates based on spatial fit",
   132     recentroid = pexConfig.Field(
   133         doc=
"Should PSFEX be permitted to recentroid PSF candidates?",
   143     ConfigClass = PsfexPsfDeterminerConfig
   145     def determinePsf(self, exposure, psfCandidateList, metadata=None, flagKey=None):
   146         """Determine a PSFEX PSF model for an exposure given a list of PSF candidates.   150         exposure: `lsst.afw.image.Exposure`   151             Exposure containing the PSF candidates.   152         psfCandidateList: iterable of `lsst.meas.algorithms.PsfCandidate`   153             Sequence of PSF candidates typically obtained by detecting sources and then running them through a    155         metadata: metadata, optional   156             A home for interesting tidbits of information.   157         flagKey: `lsst.afw.table.Key`, optional   158             Schema key used to mark sources actually used in PSF determination.   162         psf: `lsst.meas.extensions.psfex.PsfexPsf`   168         displayExposure = display 
and \
   170         displayPsfComponents = display 
and \
   172         showBadCandidates = display 
and \
   174         displayResiduals = display 
and \
   176         displayPsfMosaic = display 
and \
   181         mi = exposure.getMaskedImage()
   183         nCand = len(psfCandidateList)
   185             raise RuntimeError(
"No PSF candidates supplied.")
   191             bbox = mi.getBBox(afwImage.PARENT)
   196         sizes = np.empty(nCand)
   197         for i, psfCandidate 
in enumerate(psfCandidateList):
   200                     psfCellSet.insertCandidate(psfCandidate)
   201             except Exception 
as e:
   202                 self.log.
debug(
"Skipping PSF candidate %d of %d: %s", i, len(psfCandidateList), e)
   205             source = psfCandidate.getSource()
   206             quad = afwEll.Quadrupole(source.getIxx(), source.getIyy(), source.getIxy())
   207             rmsSize = quad.getTraceRadius()
   210         if self.config.kernelSize >= 15:
   211             self.log.
warn(
"NOT scaling kernelSize by stellar quadrupole moment, but using absolute value")
   212             actualKernelSize = 
int(self.config.kernelSize)
   214             actualKernelSize = 2 * 
int(self.config.kernelSize * np.sqrt(np.median(sizes)) + 0.5) + 1
   215             if actualKernelSize < self.config.kernelSizeMin:
   216                 actualKernelSize = self.config.kernelSizeMin
   217             if actualKernelSize > self.config.kernelSizeMax:
   218                 actualKernelSize = self.config.kernelSizeMax
   220                 rms = np.median(sizes)
   221                 print(
"Median PSF RMS size=%.2f pixels (\"FWHM\"=%.2f)" % (rms, 2*np.sqrt(2*np.log(2))*rms))
   224         pixKernelSize = actualKernelSize
   225         if self.config.samplingSize > 0:
   226             pixKernelSize = 
int(actualKernelSize*self.config.samplingSize)
   227             if pixKernelSize % 2 == 0:
   229         self.log.
trace(
"Psfex Kernel size=%.2f, Image Kernel Size=%.2f", actualKernelSize, pixKernelSize)
   230         psfCandidateList[0].setHeight(pixKernelSize)
   231         psfCandidateList[0].setWidth(pixKernelSize)
   237         defaultsFile = os.path.join(os.environ[
"MEAS_EXTENSIONS_PSFEX_DIR"], 
"config", 
"default-lsst.psfex")
   239         args_md.set(
"BASIS_TYPE", 
str(self.config.psfexBasis))
   240         args_md.set(
"PSFVAR_DEGREES", 
str(self.config.spatialOrder))
   241         args_md.set(
"PSF_SIZE", 
str(actualKernelSize))
   242         args_md.set(
"PSF_SAMPLING", 
str(self.config.samplingSize))
   243         prefs = psfex.Prefs(defaultsFile, args_md)
   244         prefs.setCommandLine([])
   245         prefs.addCatalog(
"psfexPsfDeterminer")
   248         principalComponentExclusionFlag = bool(bool(psfex.Context.REMOVEHIDDEN)
   249                                                if False else psfex.Context.KEEPHIDDEN)
   250         context = psfex.Context(prefs.getContextName(), prefs.getContextGroup(),
   251                                 prefs.getGroupDeg(), principalComponentExclusionFlag)
   252         set = psfex.Set(context)
   253         set.setVigSize(pixKernelSize, pixKernelSize)
   254         set.setFwhm(2*np.sqrt(2*np.log(2))*np.median(sizes))
   255         set.setRecentroid(self.config.recentroid)
   259         ccd = exposure.getDetector()
   261             gain = np.mean(np.array([a.getGain() 
for a 
in ccd]))
   264             self.log.
warn(
"Setting gain to %g" % (gain,))
   267         for i, key 
in enumerate(context.getName()):
   268             if context.getPcflag(i):
   269                 contextvalp.append(pcval[pc])
   273                     contextvalp.append(exposure.getMetadata().getScalar(key[1:]))
   275                     raise RuntimeError(
"*Error*: %s parameter not found in the header of %s" %
   276                                        (key[1:], prefs.getContextName()))
   279                     contextvalp.append(np.array([psfCandidateList[_].getSource().get(key)
   280                                                  for _ 
in range(nCand)]))
   282                     raise RuntimeError(
"*Error*: %s parameter not found" % (key,))
   283                 set.setContextname(i, key)
   288                 ds9.mtv(exposure, frame=frame, title=
"psf determination")
   290         badBits = mi.getMask().getPlaneBitMask(self.config.badMaskBits)
   291         fluxName = prefs.getPhotfluxRkey()
   292         fluxFlagName = 
"base_" + fluxName + 
"_flag"   295         for i, psfCandidate 
in enumerate(psfCandidateList):
   296             source = psfCandidate.getSource()
   297             xc, yc = source.getX(), source.getY()
   304                 pstamp = psfCandidate.getMaskedImage().
clone()
   305             except Exception 
as e:
   308             if fluxFlagName 
in source.schema 
and source.get(fluxFlagName):
   311             flux = source.get(fluxName)
   312             if flux < 0 
or np.isnan(flux):
   319                 sample = set.newSample()
   320                 sample.setCatindex(catindex)
   321                 sample.setExtindex(ext)
   322                 sample.setObjindex(i)
   324                 imArray = pstamp.getImage().getArray()
   325                 imArray[np.where(np.bitwise_and(pstamp.getMask().getArray(), badBits))] = \
   327                 sample.setVig(imArray)
   330                 sample.setBacknoise2(backnoise2)
   334                 sample.setFluxrad(sizes[i])
   336                 for j 
in range(set.getNcontext()):
   337                     sample.setContext(j, 
float(contextvalp[j][i]))
   338             except Exception 
as e:
   339                 self.log.
debug(
"Exception when processing sample at (%f,%f): %s", xc, yc, e)
   342                 set.finiSample(sample)
   348             with ds9.Buffering():
   349                 ds9.dot(
"o", xc, yc, ctype=ds9.CYAN, size=4, frame=frame)
   351         if set.getNsample() == 0:
   352             raise RuntimeError(
"No good PSF candidates to pass to PSFEx")
   355         for i 
in range(set.getNcontext()):
   356             cmin = contextvalp[i].
min()
   357             cmax = contextvalp[i].
max()
   358             set.setContextScale(i, cmax - cmin)
   359             set.setContextOffset(i, (cmin + cmax)/2.0)
   369         field = psfex.Field(
"Unknown")
   370         field.addExt(exposure.getWcs(), exposure.getWidth(), exposure.getHeight(), set.getNsample())
   378         psfex.makeit(fields, sets)
   379         psfs = field.getPsfs()
   383         for i 
in range(sets[0].getNsample()):
   384             index = sets[0].getSample(i).getObjindex()
   386                 good_indices.append(index)
   388         if flagKey 
is not None:
   389             for i, psfCandidate 
in enumerate(psfCandidateList):
   390                 source = psfCandidate.getSource()
   391                 if i 
in good_indices:
   392                     source.set(flagKey, 
True)
   394         xpos = np.array(xpos)
   395         ypos = np.array(ypos)
   396         numGoodStars = len(good_indices)
   397         avgX, avgY = np.mean(xpos), np.mean(ypos)
   401         if False and (displayResiduals 
or displayPsfMosaic):
   406             title = 
"psfexPsfDeterminer"   407             psfex.psfex.showPsf(psfs, set, ext,
   408                                 [(exposure.getWcs(), exposure.getWidth(), exposure.getHeight())],
   409                                 nspot=3, trim=5, frame=frame, diagnostics=diagnostics, outDir=catDir,
   415             assert psfCellSet 
is not None   418                 maUtils.showPsfSpatialCells(exposure, psfCellSet, showChi2=
True,
   419                                             symb=
"o", ctype=ds9.YELLOW, ctypeBad=ds9.RED, size=8, frame=frame)
   421                 maUtils.showPsfCandidates(exposure, psfCellSet, psf=psf, frame=4,
   422                                           normalize=normalizeResiduals,
   423                                           showBadCandidates=showBadCandidates)
   424             if displayPsfComponents:
   425                 maUtils.showPsf(psf, frame=6)
   427                 maUtils.showPsfMosaic(exposure, psf, frame=7, showFwhm=
True)
   428                 ds9.scale(
'linear', 0, 1, frame=7)
   434         if metadata 
is not None:
   435             metadata.set(
"spatialFitChi2", np.nan)
   436             metadata.set(
"numAvailStars", nCand)
   437             metadata.set(
"numGoodStars", numGoodStars)
   438             metadata.set(
"avgX", avgX)
   439             metadata.set(
"avgY", avgY)
   442         return psf, psfCellSet
   446 measAlg.psfDeterminerRegistry.register(
"psfex", PsfexPsfDeterminerTask)
 
def determinePsf(self, exposure, psfCandidateList, metadata=None, flagKey=None)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<> 
A collection of SpatialCells covering an entire image. 
Represent a PSF as a linear combination of PSFEX (== Karhunen-Loeve) basis functions. 
Class for storing generic metadata.