Example #1
0
def wise_psf_stamp(band):
    # psf noise: ~roughly 0.1 count in outskirts of W1 and W2
    if band >= 3:
        raise ValueError('Need to stare at W3+ PSF more!')
    if os.getenv('WISE_PSF_DIR', None) is None:
        raise ValueError('WISE_PSF_DIR must be set.')
    psfnoise = 0.1
    stamp = fits.getdata(
        os.path.join(os.getenv('WISE_PSF_DIR'),
                     'psf_model_w' + str(band) + '.fits'))
    edges = numpy.concatenate(
        [stamp[0, 1:-1], stamp[-1, 1:-1], stamp[1:-1, 0], stamp[1:-1, -1]])
    medval = numpy.median(edges[edges != 0]) / 2
    stamp[stamp == 0] = medval
    stamp -= medval
    from scipy import signal
    stamp[stamp < 0] = 0.
    # suppress spurious warnings in signal.wiener
    olderr = numpy.seterr(invalid='ignore', divide='ignore')
    stamp = signal.wiener(stamp, 11, psfnoise)
    numpy.seterr(**olderr)
    # taper linearly over outer 60 pixels?
    stampszo2 = stamp.shape[0] // 2
    xx, yy = numpy.mgrid[-stampszo2:stampszo2 + 1, -stampszo2:stampszo2 + 1]
    edgedist = numpy.clip(stampszo2 - numpy.abs(xx), 0,
                          stampszo2 - numpy.abs(yy))
    stamp = stamp * numpy.clip(edgedist / 60., stamp < 10, 1)
    import psf
    stamp = psf.center_psf(stamp, censize=19)
    stamp = stamp / numpy.sum(stamp)
    return stamp
Example #2
0
def blend_psf(dstamp, mstamp, innerrad, outerrad):
    stampsz = dstamp.shape[-1]
    stampszo2 = stampsz // 2
    xx = numpy.arange(stampsz, dtype='f4').reshape(1, -1) - stampszo2
    yy = xx.copy().reshape(-1, 1)
    rr = numpy.sqrt(xx**2 + yy**2)
    weight = numpy.clip(1 - (rr - innerrad) / float(outerrad - innerrad), 0, 1)
    dstamp = (dstamp + dstamp[::-1, :] + dstamp[:, ::-1] +
              dstamp[::-1, ::-1]) / 4.
    blended = dstamp * weight + mstamp * (1 - weight)
    blended = psf.center_psf(blended)
    return blended
Example #3
0
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
Example #4
0
def wise_psf_stamp(band, nosmooth=False):
    # psf noise: ~roughly 0.1 count in outskirts of W1 and W2
    if band >= 3:
        raise ValueError('Need to stare at W3+ PSF more!')
    psfnoise = 0.1
    stampfn = resource_filename('unwise_psf',
                                'data/psf_model_w'+str(band)+'.fits')
    stamp = fits.getdata(stampfn)
    edges = numpy.concatenate([stamp[0, 1:-1], stamp[-1, 1:-1],
                               stamp[1:-1, 0], stamp[1:-1, -1]])
    medval = numpy.median(edges[edges != 0]) / 2
    stamp[stamp == 0] = medval
    stamp -= medval
    from scipy import signal
    stamp[stamp < 0] = 0.
    # suppress spurious warnings in signal.wiener
    olderr = numpy.seterr(invalid='ignore', divide='ignore')
    # update to scipy.signal means that Wiener filter uses an FFT
    # to perform the various convolutions, which causes bad errors
    # here unless we cast to f8.  It's not that hard to do something
    # a bit better than scipy.signal.wiener---morally we really want to do
    # something like smooth in log space on radial lines---but I don't
    # want to go further down that rabbit hole today.
    stamp = signal.wiener(stamp.astype('f8'),  11, psfnoise)
    stamp = stamp.astype('f4')
    numpy.seterr(**olderr)
    # taper linearly over outer 60 pixels?
    stampszo2 = stamp.shape[0] // 2
    xx, yy = numpy.mgrid[-stampszo2:stampszo2+1, -stampszo2:stampszo2+1]
    edgedist = numpy.clip(stampszo2-numpy.abs(xx), 0,
                          stampszo2-numpy.abs(yy))
    stamp = stamp * numpy.clip(edgedist / 60., stamp < 10, 1)
    import psf
    stamp = psf.center_psf(stamp, censize=19)
    stamp = stamp / numpy.sum(stamp)
    return stamp
Example #5
0
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)