254 """Return a selection of psf-like objects.
258 sourceCat : `lsst.afw.table.SourceCatalog`
259 Catalog of sources to select from.
260 This catalog must be contiguous in memory.
261 matches : `list` of `lsst.afw.table.ReferenceMatch` or None
262 Ignored by this source selector.
263 exposure : `lsst.afw.image.Exposure` or None
264 The exposure the catalog was built from; used for debug display.
268 struct : `lsst.pipe.base.Struct`
269 The struct contains the following data:
271 - selected : `numpy.ndarray` of `bool``
272 Boolean array of sources that were selected, same length as
278 displayExposure = display
and \
280 plotFwhmHistogram = display
and plt
and \
282 plotFlags = display
and plt
and \
284 plotRejection = display
and plt
and \
286 afwDisplay.setDefaultMaskTransparency(75)
288 fluxName = self.config.fluxName
289 fluxErrName = self.config.fluxErrName
290 minFwhm = self.config.minFwhm
291 maxFwhm = self.config.maxFwhm
292 maxFwhmVariability = self.config.maxFwhmVariability
293 maxellip = self.config.maxellip
294 minsn = self.config.minsn
296 maxelong = (maxellip + 1.0)/(1.0 - maxellip)
if maxellip < 1.0
else 100
299 shape = sourceCat.getShapeDefinition()
300 ixx = sourceCat.get(
"%s.xx" % shape)
301 iyy = sourceCat.get(
"%s.yy" % shape)
303 fwhm = 2*np.sqrt(2*np.log(2))*np.sqrt(0.5*(ixx + iyy))
304 elong = 0.5*(ixx - iyy)/(ixx + iyy)
306 flux = sourceCat.get(fluxName)
307 fluxErr = sourceCat.get(fluxErrName)
308 sn = flux/np.where(fluxErr > 0, fluxErr, 1)
309 sn[fluxErr <= 0] = -psfexLib.BIG
312 for i, f
in enumerate(self.config.badFlags):
313 flags = np.bitwise_or(flags, np.where(sourceCat.get(f), 1 << i, 0))
317 good = np.logical_and(sn > minsn, np.logical_not(flags))
318 good = np.logical_and(good, elong < maxelong)
319 good = np.logical_and(good, fwhm >= minFwhm)
320 good = np.logical_and(good, fwhm < maxFwhm)
322 fwhmMode, fwhmMin, fwhmMax = compute_fwhmrange(fwhm[good], maxFwhmVariability, minFwhm, maxFwhm,
323 plot=dict(fwhmHistogram=plotFwhmHistogram))
335 selectionVectors = []
336 selectionVectors.append((bad,
"flags %d" % sum(bad)))
340 bad = np.logical_or(bad, dbad)
342 selectionVectors.append((dbad,
"S/N %d" % sum(dbad)))
344 dbad = fwhm < fwhmMin
346 bad = np.logical_or(bad, dbad)
348 selectionVectors.append((dbad,
"fwhmMin %d" % sum(dbad)))
350 dbad = fwhm > fwhmMax
352 bad = np.logical_or(bad, dbad)
354 selectionVectors.append((dbad,
"fwhmMax %d" % sum(dbad)))
356 dbad = elong > maxelong
358 bad = np.logical_or(bad, dbad)
360 selectionVectors.append((dbad,
"elong %d" % sum(dbad)))
362 good = np.logical_not(bad)
368 mi = exposure.getMaskedImage()
369 disp = afwDisplay.Display(frame=frame)
370 disp.mtv(mi, title=
"PSF candidates")
372 with disp.Buffering():
373 for i, source
in enumerate(sourceCat):
375 ctype = afwDisplay.GREEN
377 ctype = afwDisplay.RED
379 disp.dot(
"+", source.getX() - mi.getX0(), source.getY() - mi.getY0(),
382 if plotFlags
or plotRejection:
383 imag = -2.5*np.log10(flux)
388 isSet = np.where(flags == 0x0)[0]
389 plt.plot(imag[isSet], fwhm[isSet],
'o', alpha=alpha, label=
"good")
391 for i, f
in enumerate(self.config.badFlags):
393 isSet = np.where(np.bitwise_and(flags, mask))[0]
395 if np.isfinite(imag[isSet] + fwhm[isSet]).any():
396 label = re.sub(
r"\_flag",
"",
397 re.sub(
r"^base\_",
"",
398 re.sub(
r"^.*base\_PixelFlags\_flag\_",
"", f)))
399 plt.plot(imag[isSet], fwhm[isSet],
'o', alpha=alpha, label=label)
401 for bad, label
in selectionVectors:
402 plt.plot(imag[bad], fwhm[bad],
'o', alpha=alpha, label=label)
404 plt.plot(imag[good], fwhm[good],
'o', color=
"black", label=
"selected")
405 [plt.axhline(_, color=
'red')
for _
in [fwhmMin, fwhmMax]]
406 plt.xlim(np.median(imag[good]) + 5*np.array([-1, 1]))
407 plt.ylim(fwhm[np.where(np.isfinite(fwhm + imag))].
min(), 2*fwhmMax)
409 plt.xlabel(
"Instrumental %s Magnitude" % fluxName.split(
".")[-1].title())
411 title =
"PSFEX Star Selection"
412 plt.title(
"%s %d selected" % (title, sum(good)))
416 eventHandler =
EventHandler(plt.axes(), imag, fwhm, sourceCat.getX(), sourceCat.getY(),
419 if plotFlags
or plotRejection:
422 reply = input(
"continue? [y[es] h(elp) p(db) q(uit)] ").
strip()
431At this prompt, you can continue with almost any key; 'p' enters pdb,
432 'q' returns to the shell, and
438If you put the cursor on a point in the matplotlib scatter plot and hit 'p' you'll see it in ds9.""")
439 elif reply[0] ==
"p":
442 elif reply[0] ==
'q':
447 return Struct(selected=good)