def decam_psf(filt, fwhm): if filt not in 'ugrizY': tpsf = psfmod.moffat_psf(fwhm, stampsz=511, deriv=False) return psfmod.SimplePSF(tpsf) fname = os.path.join(os.environ['DECAM_DIR'], 'data', 'psfs', 'psf_%s_deconv_mod.fits.gz' % filt[0]) normalizesz = 59 tpsf = fits.getdata(fname).T.copy() tpsf /= numpy.sum(psfmod.central_stamp(tpsf, normalizesz)) # omitting central_stamp here places too much # emphasis on the wings relative to the pipeline estimate. tpsffwhm = psfmod.neff_fwhm(psfmod.central_stamp(tpsf)) from scipy.ndimage.filters import convolve if tpsffwhm < fwhm: convpsffwhm = numpy.sqrt(fwhm**2. - tpsffwhm**2.) convpsf = psfmod.moffat_psf(convpsffwhm, stampsz=39, deriv=False) tpsf = convolve(tpsf, convpsf, mode='constant', cval=0., origin=0) else: convpsffwhm = 0. tpsf = psfmod.stamp2model(numpy.array([tpsf, tpsf, tpsf, tpsf]), normalize=normalizesz) nlinperpar = 3 pixsz = 9 extraparam = numpy.zeros(1, dtype=[('convparam', 'f4', 3 * nlinperpar + 1), ('resparam', 'f4', (nlinperpar, pixsz, pixsz))]) extraparam['convparam'][0, 0:4] = [convpsffwhm, 1., 0., 1.] extraparam['resparam'][0, :, :, :] = 0. tpsf.extraparam = extraparam tpsf.fitfun = partial(psfmod.fit_linear_static_wing, filter=filt) return tpsf
def objective(par): mod = psfmod.moffat_psf(par[0], beta=2.5, xy=par[2], yy=par[3], deriv=False, stampsz=tpsf.shape[0]) mod /= numpy.sum(mod) return ((tpsf - mod)[overlap]).reshape(-1)
def make_new_psfs(write=False, **kw): path = os.path.join(os.environ['DECAM_DIR'], 'data', 'psfs', 'includeu') res = {} for f in filt: tpsf = fits.getdata(os.path.join(path, 'psf_%s.fits.gz' % f)) tpsf = psf.center_psf(tpsf) fitres = psf.fit_moffat(psf.central_stamp(tpsf, censize=19).copy()) fit = fitres[0] deconvfac = 0.7 kernel = psf.moffat_psf(fit[1] * deconvfac, yy=fit[4], beta=fit[2], xy=fit[3], stampsz=69, deriv=False) psfde = restoration.richardson_lucy(tpsf, kernel, 20) psfde = psf.center_psf(psfde) res[f] = psfde if write: for f in filt: fits.writeto(os.path.join(path, 'psf_%s_deconv.fits.gz' % f), res[f], **kw) return res
default=numpy.inf, help='pixel brightness limit for saturation') args = parser.parse_args() imagefn = args.imagefn[0] ivarfn = args.ivarfn[0] flagfn = args.flagfn[0] if getattr(args, 'psffn', None): # stamp = numpy.clip(fits.getdata(args.psffn), 1e-10, numpy.inf) stamp = fits.getdata(args.psffn) stamp[stamp < 0] = 0. stamp = stamp / numpy.sum(stamp) psf = psfmod.SimplePSF(stamp) from functools import partial psf.fitfun = partial(psfmod.wise_psf_fit, fname=args.psffn) else: print('using moffat') psf = psfmod.SimplePSF(psfmod.moffat_psf(2.5, beta=2.5)[0]) res = process(imagefn, ivarfn, flagfn, psf, refit_psf=args.refit_psf, verbose=args.verbose, nx=4, ny=4, satlimit=args.satlimit) outfn = args.outfn[0] fits.writeto(outfn, res[0]) fits.append(outfn, res[1]) fits.append(outfn, res[2])
def find_psf(xcen, shiftx, ycen, shifty, psfstack, weightstack, imstack, stampsz=59, nkeep=100): """Find PSF from stamps.""" # let's just go ahead and correlate the noise xr = numpy.round(shiftx) yr = numpy.round(shifty) psfqf = (numpy.sum(psfstack*(weightstack > 0), axis=(1, 2)) / numpy.sum(psfstack, axis=(1, 2))) totalflux = numpy.sum(psfstack, axis=(1, 2)) timflux = numpy.sum(imstack, axis=(1, 2)) toneflux = numpy.sum(psfstack, axis=(1, 2)) tmedflux = numpy.median(psfstack, axis=(1, 2)) tfracflux = toneflux / numpy.clip(timflux, 100, numpy.inf) tfracflux2 = ((toneflux-tmedflux*psfstack.shape[1]*psfstack.shape[2]) / numpy.clip(timflux, 100, numpy.inf)) okpsf = ((numpy.abs(psfqf - 1) < 0.03) & (tfracflux > 0.5) & (tfracflux2 > 0.2)) if numpy.sum(okpsf) > 0: shiftxm = numpy.median(shiftx[okpsf]) shiftym = numpy.median(shifty[okpsf]) okpsf = (okpsf & (numpy.abs(shiftx-shiftxm) < 1.) & (numpy.abs(shifty-shiftym) < 1.)) if numpy.sum(okpsf) <= 5: print('Fewer than 5 stars accepted in image, keeping original PSF') return None if numpy.sum(okpsf) > nkeep: okpsf = okpsf & (totalflux > -numpy.sort(-totalflux[okpsf])[nkeep-1]) psfstack = psfstack[okpsf, :, :] weightstack = weightstack[okpsf, :, :] totalflux = totalflux[okpsf] xcen = xcen[okpsf] ycen = ycen[okpsf] shiftx = shiftx[okpsf] shifty = shifty[okpsf] for i in range(psfstack.shape[0]): psfstack[i, :, :] = shift(psfstack[i, :, :], [-shiftx[i], -shifty[i]]) if (numpy.abs(xr[i]) > 0) or (numpy.abs(yr[i]) > 0): weightstack[i, :, :] = shift(weightstack[i, :, :], [-xr[i], -yr[i]], mode='constant', cval=0.) # our best guess as to the PSFs & their weights # select some reasonable sample of the PSFs totalflux = numpy.sum(psfstack, axis=(1, 2)) psfstack /= totalflux.reshape(-1, 1, 1) weightstack *= totalflux.reshape(-1, 1, 1) tpsf = numpy.median(psfstack, axis=0) tpsf = psfmod.center_psf(tpsf) if tpsf.shape == stampsz: return tpsf xc = numpy.arange(tpsf.shape[0]).reshape(-1, 1)-tpsf.shape[0]//2 yc = xc.reshape(1, -1) rc = numpy.sqrt(xc**2.+yc**2.) stampszo2 = psfstack[0].shape[0] // 2 wt = numpy.clip((stampszo2+1-rc)/4., 0., 1.) overlap = (wt != 1) & (wt != 0) def objective(par): mod = psfmod.moffat_psf(par[0], beta=2.5, xy=par[2], yy=par[3], deriv=False, stampsz=tpsf.shape[0]) mod /= numpy.sum(mod) return ((tpsf-mod)[overlap]).reshape(-1) from scipy.optimize import leastsq par = leastsq(objective, [4., 3., 0., 1.])[0] modpsf = psfmod.moffat_psf(par[0], beta=2.5, xy=par[2], yy=par[3], deriv=False, stampsz=stampsz) modpsf /= numpy.sum(psfmod.central_stamp(modpsf)) npsf = modpsf.copy() npsfcen = psfmod.central_stamp(npsf, tpsf.shape[0]) npsfcen[:, :] = tpsf*wt+(1-wt)*npsfcen[:, :] npsf /= numpy.sum(npsf) return psfmod.SimplePSF(npsf, normalize=-1)