示例#1
0
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
示例#2
0
def compute_stats(xs, ys, impsfstack, psfstack, weightstack, imstack, flux):
    residstack = impsfstack - psfstack
    norm = numpy.sum(psfstack, axis=(1, 2))
    psfstack = psfstack / (norm + (norm == 0)).reshape(-1, 1, 1)
    qf = numpy.sum(psfstack*(weightstack > 0), axis=(1, 2))
    fluxunc = numpy.sum(psfstack**2.*weightstack**2., axis=(1, 2))
    fluxunc = fluxunc + (fluxunc == 0)*1e-20
    fluxunc = (fluxunc**(-0.5)).astype('f4')
    posunc = [numpy.zeros(len(qf), dtype='f4'),
              numpy.zeros(len(qf), dtype='f4')]
    psfderiv = numpy.gradient(-psfstack, axis=(1, 2))
    for i, p in enumerate(psfderiv):
        dp = numpy.sum((p*weightstack*flux[:, None, None])**2., axis=(1, 2))
        dp = dp + (dp == 0)*1e-40
        dp = dp**(-0.5)
        posunc[i][:] = dp
    rchi2 = numpy.sum(residstack**2.*weightstack**2.*psfstack,
                      axis=(1, 2)) / (qf + (qf == 0.)*1e-20).astype('f4')
    fracfluxn = numpy.sum(impsfstack*(weightstack > 0)*psfstack,
                          axis=(1, 2))
    fracfluxd = numpy.sum(imstack*(weightstack > 0)*psfstack,
                          axis=(1, 2))
    fracfluxd = fracfluxd + (fracfluxd == 0)*1e-20
    fracflux = (fracfluxn / fracfluxd).astype('f4')
    fluxlbs, dfluxlbs = compute_lbs_flux(impsfstack, psfstack, weightstack,
                                         flux/norm)
    fluxlbs = fluxlbs.astype('f4')
    dfluxlbs = dfluxlbs.astype('f4')
    fwhm = psfmod.neff_fwhm(psfstack).astype('f4')
    return OrderedDict([('dx', posunc[0]), ('dy', posunc[1]),
                        ('dflux', fluxunc),
                        ('qf', qf), ('rchi2', rchi2), ('fracflux', fracflux),
                        ('fluxlbs', fluxlbs), ('dfluxlbs', dfluxlbs),
                        ('fwhm', fwhm)])
示例#3
0
def spread_model(impsfstack, psfstack, weightstack):
    # need to convolve psfs with 1/16 FWHM exponential
    # can get FWHM from n_eff
    # better way?  n_eff can be a bit annoying; not necessarily what one
    # expects if there's a sharp peak on a broad background.
    # spread_model is on the whole a bit goofy: one sixteenth of a FWHM is very
    # little.  So this is really more like the significance of the derivative
    # of the PSF with radius, which I would compute a bit differently.
    # still, other people compute spread_model, and it's well defined, so...
    import galconv
    fwhm = psfmod.neff_fwhm(psfstack)
    sigma = fwhm / 16.
    re = sigma * 1.67834699
    expgalstack = galconv.gal_psfstack_conv(re, 0, 0, galconv.ExpGalaxy,
                                            numpy.eye(2), 0, 0, psfstack)
    GWp = numpy.sum(expgalstack * weightstack**2 * impsfstack, axis=(1, 2))
    PWp = numpy.sum(psfstack * weightstack**2 * impsfstack, axis=(1, 2))
    GWP = numpy.sum(expgalstack * weightstack**2 * psfstack, axis=(1, 2))
    PWP = numpy.sum(psfstack**2 * weightstack**2, axis=(1, 2))
    GWG = numpy.sum(expgalstack**2 * weightstack**2, axis=(1, 2))
    spread = (GWp / (PWp + (PWp == 0)) - GWP / (PWP + (PWP == 0)))
    dspread = numpy.sqrt((PWp**2 * GWG + GWp**2 * PWP - 2 * GWp * PWp * GWP) /
                         (PWp + (PWp == 0))**4)
    return spread, dspread
示例#4
0
def fit_im(im, psf, weight=None, dq=None, psfderiv=True,
           nskyx=0, nskyy=0, refit_psf=False, fixedstars=None,
           verbose=False, miniter=4, maxiter=10, blist=None):
    if fixedstars is not None and len(fixedstars['x']) > 0:
        fixedpsflist = {'psfob': fixedstars['psfob'], 'ind': fixedstars['psf']}
        fixedmodel = build_model(fixedstars['x'], fixedstars['y'],
                                 fixedstars['flux'], im.shape[0], im.shape[1],
                                 psflist=fixedpsflist,
                                 offset=fixedstars['offset'])
    else:
        fixedmodel = numpy.zeros_like(im)

    if isinstance(weight, int):
        weight = numpy.ones_like(im)*weight

    im = im
    model = numpy.zeros_like(im)+fixedmodel
    xa = numpy.zeros(0, dtype='f4')
    ya = xa.copy()
    lsky = numpy.median(im[weight > 0])
    hsky = numpy.median(im[weight > 0])
    msky = 0
    passno = numpy.zeros(0, dtype='i4')
    guessflux, guesssky = None, None
    titer = -1
    lastiter = -1

    roughfwhm = psfmod.neff_fwhm(psf(im.shape[0]//2, im.shape[1]//2))
    roughfwhm = numpy.max([roughfwhm, 3.])

    while True:
        titer += 1
        hsky = sky_im(im-model, weight=weight, npix=20)
        lsky = sky_im(im-model, weight=weight, npix=10*roughfwhm)
        if titer != lastiter:
            # in first passes, do not split sources!
            blendthresh = 2 if titer < 2 else 0.2
            xn, yn = peakfind(im-model-hsky,
                              model-msky, weight, dq, psf,
                              keepsat=(titer == 0),
                              blendthreshhold=blendthresh)
            if len(xa) > 0 and len(xn) > 0:
                keep = neighbor_dist(xn, yn, xa, ya) > 1.5
                xn, yn = (c[keep] for c in (xn, yn))
            if (titer == 0) and (blist is not None):
                xnb, ynb = add_bright_stars(xn, yn, blist, im)
                xn = numpy.concatenate([xn, xnb]).astype('f4')
                yn = numpy.concatenate([yn, ynb]).astype('f4')
            xa, ya = (numpy.concatenate([xa, xn]).astype('f4'),
                      numpy.concatenate([ya, yn]).astype('f4'))
            passno = numpy.concatenate([passno, numpy.zeros(len(xn))+titer])
            if verbose:
                print('Iteration %d, found %d sources.' % (titer+1, len(xn)))
        else:
            xn, yn = numpy.zeros(0, dtype='f4'), numpy.zeros(0, dtype='f4')
        if titer != lastiter:
            if (titer == maxiter-1) or (
                    (titer >= miniter-1) and (len(xn) < 100)) or (
                    len(xa) > 40000):
                lastiter = titer + 1
        sz = get_sizes(xa, ya, im-hsky, weight=weight, blist=blist)
        if guessflux is not None:
            guess = numpy.concatenate([guessflux, numpy.zeros_like(xn),
                                       guesssky])
        else:
            guess = None
        sky = hsky if titer >= 2 else lsky
        # in final iteration, no longer allow shifting locations; just fit
        # centroids.
        tpsfderiv = psfderiv if lastiter != titer else False
        psfs = build_psf_list(xa, ya, psf, sz, psfderiv=tpsfderiv)
        flux, model, msky = fit_once(im-sky, xa, ya, psfs, psfderiv=tpsfderiv,
                                     weight=weight, guess=guess,
                                     nskyx=nskyx, nskyy=nskyy)

        model += fixedmodel
        centroids = compute_centroids(xa, ya, psfs, flux[0], im-(sky+msky),
                                      im-model-sky,
                                      weight)
        xcen, ycen, stamps = centroids
        if titer == lastiter:
            tflux, tskypar = unpack_fitpar(flux[0], len(xa), False)
            stats = compute_stats(xa-numpy.round(xa), ya-numpy.round(ya),
                                  stamps[0], stamps[2],
                                  stamps[3], stamps[1],
                                  tflux)
            stats['flags'] = extract_im(xa, ya, dq).astype('i4')
            stats['sky'] = extract_im(xa, ya, sky+msky).astype('f4')
            break
        guessflux, guesssky = unpack_fitpar(flux[0], len(xa),
                                            psfderiv)
        if refit_psf and len(xa) > 0:
            # how far the centroids of the model PSFs would
            # be from (0, 0) if instantiated there
            # this initial definition includes the known offset (since
            # we instantiated off a pixel center), and the model offset
            xe, ye = psfmod.simple_centroid(
                psfmod.central_stamp(stamps[4], censize=stamps[0].shape[-1]))
            # now we subtract the known offset
            xe -= xa-numpy.round(xa)
            ye -= ya-numpy.round(ya)
            if hasattr(psf, 'fitfun'):
                psffitfun = psf.fitfun
                npsf = psffitfun(xa, ya, xcen+xe, ycen+ye, stamps[0],
                                 stamps[1], stamps[2], stamps[3], nkeep=200)
                if npsf is not None:
                    npsf.fitfun = psffitfun
            else:
                shiftx = xcen + xe + xa - numpy.round(xa)
                shifty = ycen + ye + ya - numpy.round(ya)
                npsf = find_psf(xa, shiftx, ya, shifty,
                                stamps[0], stamps[3], stamps[1])
            # we removed the centroid offset of the model PSFs;
            # we need to correct the positions to compensate
            xa += xe
            ya += ye
            psf = npsf
        xcen, ycen = (numpy.clip(c, -3, 3) for c in (xcen, ycen))
        xa, ya = (numpy.clip(c, -0.499, s-0.501)
                  for c, s in zip((xa+xcen, ya+ycen), im.shape))
        fluxunc = numpy.sum(stamps[2]**2.*stamps[3]**2., axis=(1, 2))
        fluxunc = fluxunc + (fluxunc == 0)*1e-20
        fluxunc = (fluxunc**(-0.5)).astype('f4')
        # for very bright stars, fluxunc is unreliable because the entire
        # (small) stamp is saturated.
        # these stars all have very bright inferred fluxes
        # i.e., 50k saturates, so we can cut there.
        keep = (((guessflux/fluxunc > 3) | (guessflux > 1e5)) &
                cull_near(xa, ya, guessflux))
        xa, ya = (c[keep] for c in (xa, ya))
        passno = passno[keep]
        guessflux = guessflux[keep]
        # should probably also subtract these stars from the model image
        # which is used for peak finding.  But the faint stars should
        # make little difference?

    if fixedmodel is not None:
        model += fixedmodel
    flux, skypar = unpack_fitpar(flux[0], len(xa), False)
    stars = OrderedDict([('x', xa), ('y', ya), ('flux', flux)] +
                        [(f, stats[f]) for f in stats])
    res = (stars, skypar, model+sky, sky+msky, psf)
    return res