Esempio n. 1
0
def psf_residuals(expnum,
                  ccdname,
                  stampsize=35,
                  nstar=30,
                  magrange=(13, 17),
                  verbose=0,
                  splinesky=False):

    # Set the debugging level.
    if verbose == 0:
        lvl = logging.INFO
    else:
        lvl = logging.DEBUG
    logging.basicConfig(level=lvl, format='%(message)s', stream=sys.stdout)

    pngprefix = 'qapsf-{}-{}'.format(expnum, ccdname)

    # Gather all the info we need about this CCD.
    decals = Decals()
    ccd = decals.find_ccds(expnum=expnum, ccdname=ccdname)[0]
    band = ccd.filter
    ps1band = dict(g=0, r=1, i=2, z=3, Y=4)
    print('Band {}'.format(band))

    #scales = dict(g=0.0066, r=0.01, z=0.025)
    #vmin, vmax = np.arcsinh(-1), np.arcsinh(100)
    #print(scales[band])

    im = decals.get_image_object(ccd)
    iminfo = im.get_image_info()
    H, W = iminfo['dims']

    wcs = im.get_wcs()

    # Choose a uniformly selected subset of PS1 stars on this CCD.
    ps1 = ps1cat(ccdwcs=wcs)
    cat = ps1.get_stars(band=band, magrange=magrange)

    rand = np.random.RandomState(seed=expnum * ccd.ccdnum)
    these = rand.choice(len(cat) - 1, nstar, replace=False)
    #these = rand.random_integers(0,len(cat)-1,nstar)
    cat = cat[these]
    cat = cat[np.argsort(cat.median[:, ps1band[band]])]  # sort by magnitude
    #print(cat.nmag_ok)

    get_tim_kwargs = dict(const2psf=True, splinesky=splinesky)

    # Make a QAplot of the positions of all the stars.
    tim = im.get_tractor_image(**get_tim_kwargs)
    img = tim.getImage()
    #img = tim.getImage()/scales[band]

    fig = plt.figure(figsize=(5, 10))
    ax = fig.gca()
    ax.get_xaxis().get_major_formatter().set_useOffset(False)
    #ax.imshow(np.arcsinh(img),cmap='gray',interpolation='nearest',
    #          origin='lower',vmin=vmax,vmax=vmax)

    ax.imshow(img, **tim.ima)
    ax.axis('off')
    ax.set_title('{}: {}/{} AM={:.2f} Seeing={:.3f}"'.format(
        band, expnum, ccdname, ccd.airmass, ccd.seeing))

    for istar, ps1star in enumerate(cat):
        ra, dec = (ps1star.ra, ps1star.dec)
        ok, xpos, ypos = wcs.radec2pixelxy(ra, dec)
        ax.text(xpos,
                ypos,
                '{:2d}'.format(istar + 1),
                color='red',
                horizontalalignment='left')
        circ = plt.Circle((xpos, ypos), radius=30, color='g', fill=False, lw=1)
        ax.add_patch(circ)

    #radec = wcs.radec_bounds()
    #ax.scatter(cat.ra,cat.dec)
    #ax.set_xlim([radec[1],radec[0]])#*[1.0002,0.9998])
    #ax.set_ylim([radec[2],radec[3]])#*[0.985,1.015])
    #ax.set_xlabel('$RA\ (deg)$',fontsize=18)
    #ax.set_ylabel('$Dec\ (deg)$',fontsize=18)
    fig.savefig(pngprefix + '-ccd.png', bbox_inches='tight')

    # Initialize the many-stamp QAplot
    ncols = 3
    nrows = np.ceil(nstar / ncols).astype('int')

    inchperstamp = 2.0
    fig = plt.figure(figsize=(inchperstamp * 3 * ncols, inchperstamp * nrows))
    irow = 0
    icol = 0

    for istar, ps1star in enumerate(cat):
        ra, dec = (ps1star.ra, ps1star.dec)
        mag = ps1star.median[ps1band[band]]  # r-band

        ok, xpos, ypos = wcs.radec2pixelxy(ra, dec)
        ix, iy = int(xpos), int(ypos)

        # create a little tractor Image object around the star
        slc = (slice(max(iy - stampsize, 0), min(iy + stampsize + 1, H)),
               slice(max(ix - stampsize, 0), min(ix + stampsize + 1, W)))

        # The PSF model 'const2Psf' is the one used in DR1: a 2-component
        # Gaussian fit to PsfEx instantiated in the image center.
        tim = im.get_tractor_image(slc=slc, **get_tim_kwargs)
        stamp = tim.getImage()
        ivarstamp = tim.getInvvar()

        # Initialize a tractor PointSource from PS1 measurements
        flux = NanoMaggies.magToNanomaggies(mag)
        star = PointSource(RaDecPos(ra, dec), NanoMaggies(**{band: flux}))

        # Fit just the source RA,Dec,flux.
        tractor = Tractor([tim], [star])
        tractor.freezeParam('images')

        print('2-component MOG:', tim.psf)
        tractor.printThawedParams()

        for step in range(50):
            dlnp, X, alpha = tractor.optimize()
            if dlnp < 0.1:
                break
        print('Fit:', star)
        model_mog = tractor.getModelImage(0)
        chi2_mog = -2.0 * tractor.getLogLikelihood()
        mag_mog = NanoMaggies.nanomaggiesToMag(star.brightness)[0]

        # Now change the PSF model to a pixelized PSF model from PsfEx instantiated
        # at this place in the image.
        psf = PixelizedPsfEx(im.psffn)
        tim.psf = psf.constantPsfAt(xpos, ypos)

        #print('PSF model:', tim.psf)
        #tractor.printThawedParams()
        for step in range(50):
            dlnp, X, alpha = tractor.optimize()
            if dlnp < 0.1:
                break

        print('Fit:', star)
        model_psfex = tractor.getModelImage(0)
        chi2_psfex = -2.0 * tractor.getLogLikelihood()
        mag_psfex = NanoMaggies.nanomaggiesToMag(star.brightness)[0]

        #mn, mx = np.percentile((stamp-model_psfex)[ivarstamp>0],[1,95])
        sig = np.std((stamp - model_psfex)[ivarstamp > 0])
        mn, mx = [-2.0 * sig, 5 * sig]

        # Generate a QAplot.
        if (istar > 0) and (istar % (ncols) == 0):
            irow = irow + 1
        icol = 3 * istar - 3 * ncols * irow
        #print(istar, irow, icol, icol+1, icol+2)

        ax1 = plt.subplot2grid((nrows, 3 * ncols), (irow, icol),
                               aspect='equal')
        ax1.axis('off')
        #ax1.imshow(stamp, **tim.ima)
        ax1.imshow(stamp,
                   cmap='gray',
                   interpolation='nearest',
                   origin='lower',
                   vmin=mn,
                   vmax=mx)
        ax1.text(0.1,
                 0.9,
                 '{:2d}'.format(istar + 1),
                 color='white',
                 horizontalalignment='left',
                 verticalalignment='top',
                 transform=ax1.transAxes)

        ax2 = plt.subplot2grid((nrows, 3 * ncols), (irow, icol + 1),
                               aspect='equal')
        ax2.axis('off')
        #ax2.imshow(stamp-model_mog, **tim.ima)
        ax2.imshow(stamp - model_mog,
                   cmap='gray',
                   interpolation='nearest',
                   origin='lower',
                   vmin=mn,
                   vmax=mx)
        ax2.text(0.1,
                 0.9,
                 'MoG',
                 color='white',
                 horizontalalignment='left',
                 verticalalignment='top',
                 transform=ax2.transAxes)
        ax2.text(0.08,
                 0.08,
                 '{:.3f}'.format(mag_mog),
                 color='white',
                 horizontalalignment='left',
                 verticalalignment='bottom',
                 transform=ax2.transAxes)

        #ax2.set_title('{:.3f}, {:.2f}'.format(mag_psfex,chi2_psfex),fontsize=14)
        #ax2.set_title('{:.3f}, $\chi^{2}$={:.2f}'.format(mag_psfex,chi2_psfex))

        ax3 = plt.subplot2grid((nrows, 3 * ncols), (irow, icol + 2),
                               aspect='equal')
        ax3.axis('off')
        #ax3.imshow(stamp-model_psfex, **tim.ima)
        ax3.imshow(stamp - model_psfex,
                   cmap='gray',
                   interpolation='nearest',
                   origin='lower',
                   vmin=mn,
                   vmax=mx)
        ax3.text(0.1,
                 0.9,
                 'PSFEx',
                 color='white',
                 horizontalalignment='left',
                 verticalalignment='top',
                 transform=ax3.transAxes)
        ax3.text(0.08,
                 0.08,
                 '{:.3f}'.format(mag_psfex),
                 color='white',
                 horizontalalignment='left',
                 verticalalignment='bottom',
                 transform=ax3.transAxes)

        if istar == (nstar - 1):
            break
    fig.savefig(pngprefix + '-stargrid.png', bbox_inches='tight')
Esempio n. 2
0
import pylab as plt
import numpy as np
from astrometry.util.plotutils import *

from legacyanalysis.ps1cat import ps1cat
from legacypipe.common import Decals

from tractor import Image, PointSource, PixPos, NanoMaggies, Tractor

ps = PlotSequence('rewcs')

expnum, ccdname = 431109, 'N14'
cat = ps1cat(expnum=expnum, ccdname=ccdname)
stars = cat.get_stars()
print len(stars), 'stars'

decals = Decals()
ccd = decals.find_ccds(expnum=expnum,ccdname=ccdname)[0]
im = decals.get_image_object(ccd)
wcs = im.get_wcs()
tim = im.get_tractor_image(pixPsf=True, splinesky=True)

margin = 15
ok,stars.xx,stars.yy = wcs.radec2pixelxy(stars.ra, stars.dec) 
stars.xx -= 1.
stars.yy -= 1.
W,H = wcs.get_width(), wcs.get_height()
stars.ix = np.round(stars.xx).astype(int)
stars.iy = np.round(stars.yy).astype(int)
stars.cut((stars.ix >= margin) * (stars.ix < (W-margin)) *
          (stars.iy >= margin) * (stars.iy < (H-margin)))
Esempio n. 3
0
def read_forcedphot_ccds(ccds, survey):
    ccds.mdiff = np.zeros(len(ccds))
    ccds.mscatter = np.zeros(len(ccds))

    Nap = 8
    ccds.apdiff = np.zeros((len(ccds), Nap))
    ccds.apscatter = np.zeros((len(ccds), Nap))

    ccds.nforced = np.zeros(len(ccds), np.int16)
    ccds.nunmasked = np.zeros(len(ccds), np.int16)
    ccds.nmatched = np.zeros(len(ccds), np.int16)
    ccds.nps1 = np.zeros(len(ccds), np.int16)

    brickcache = {}

    FF = []

    for iccd, ccd in enumerate(ccds):
        print('CCD', iccd, 'of', len(ccds))
        F = fits_table(ccd.path)
        print(len(F), 'sources in', ccd.path)

        ccds.nforced[iccd] = len(F)

        # arr, have to match with brick sources to get RA,Dec.
        F.ra = np.zeros(len(F))
        F.dec = np.zeros(len(F))
        F.masked = np.zeros(len(F), bool)

        maglo, maghi = 14., 21.
        maxdmag = 1.

        F.mag = -2.5 * (np.log10(F.flux) - 9)
        F.cut((F.flux > 0) * (F.mag > maglo - maxdmag) *
              (F.mag < maghi + maxdmag))
        print(len(F), 'sources between', (maglo - maxdmag), 'and',
              (maghi + maxdmag), 'mag')

        im = survey.get_image_object(ccd)
        print('Reading DQ image for', im)
        dq = im.read_dq()
        H, W = dq.shape
        ix = np.clip(np.round(F.x), 0, W - 1).astype(int)
        iy = np.clip(np.round(F.y), 0, H - 1).astype(int)
        F.mask = dq[iy, ix]
        print(np.sum(F.mask != 0), 'sources are masked')

        for brickname in np.unique(F.brickname):
            if not brickname in brickcache:
                brickcache[brickname] = fits_table(
                    survey.find_file('tractor', brick=brickname))
            T = brickcache[brickname]
            idtoindex = np.zeros(T.objid.max() + 1, int) - 1
            idtoindex[T.objid] = np.arange(len(T))

            I = np.flatnonzero(F.brickname == brickname)
            J = idtoindex[F.objid[I]]
            assert (np.all(J >= 0))
            F.ra[I] = T.ra[J]
            F.dec[I] = T.dec[J]

            F.masked[I] = (T.decam_anymask[J, :].max(axis=1) > 0)

        #F.cut(F.masked == False)
        #print(len(F), 'not masked')
        print(np.sum(F.masked), 'masked in ANYMASK')

        ccds.nunmasked[iccd] = len(F)

        wcs = Tan(*[
            float(x) for x in [
                ccd.crval1, ccd.crval2, ccd.crpix1, ccd.crpix2, ccd.cd1_1,
                ccd.cd1_2, ccd.cd2_1, ccd.cd2_2, ccd.width, ccd.height
            ]
        ])

        ps1 = ps1cat(ccdwcs=wcs)
        stars = ps1.get_stars()
        print(len(stars), 'PS1 sources')
        ccds.nps1[iccd] = len(stars)

        # Now cut to just *stars* with good colors
        stars.gicolor = stars.median[:, 0] - stars.median[:, 2]
        keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
        stars.cut(keep)
        print(len(stars), 'PS1 stars with good colors')

        stars.cut(np.minimum(stars.stdev[:, 1], stars.stdev[:, 2]) < 0.05)
        print(len(stars), 'PS1 stars with min stdev(r,i) < 0.05')

        I, J, d = match_radec(F.ra, F.dec, stars.ra, stars.dec, 1. / 3600.)
        print(len(I), 'matches')

        band = ccd.filter

        colorterm = ps1_to_decam(stars.median[J], band)

        F.cut(I)
        F.psmag = stars.median[J, ps1.ps1band[band]] + colorterm

        K = np.flatnonzero((F.psmag > maglo) * (F.psmag < maghi))
        print(len(K), 'with mag', maglo, 'to', maghi)
        F.cut(K)

        K = np.flatnonzero(np.abs(F.mag - F.psmag) < maxdmag)
        print(len(K), 'with good mag matches (<', maxdmag, 'mag difference)')
        ccds.nmatched[iccd] = len(K)
        if len(K) == 0:
            continue
        F.cut(K)

        ccds.mdiff[iccd] = np.median(F.mag - F.psmag)
        ccds.mscatter[iccd] = (np.percentile(F.mag - F.psmag, 84) -
                               np.percentile(F.mag - F.psmag, 16)) / 2.

        for i in range(Nap):
            apmag = -2.5 * (np.log10(F.apflux[:, i]) - 9)

            ccds.apdiff[iccd, i] = np.median(apmag - F.psmag)
            ccds.apscatter[iccd, i] = (np.percentile(apmag - F.psmag, 84) -
                                       np.percentile(apmag - F.psmag, 16)) / 2.

        #F.about()
        for c in [
                'apflux_ivar', 'brickid', 'flux_ivar', 'mjd', 'objid',
                'fracflux', 'rchi2', 'x', 'y'
        ]:
            F.delete_column(c)

        F.expnum = np.zeros(len(F), np.int32) + ccd.expnum
        F.ccdname = np.array([ccd.ccdname] * len(F))
        F.iforced = np.zeros(len(F), np.int32) + iccd

        FF.append(F)

    FF = merge_tables(FF)

    return FF

    bricks = survey.get_bricks_readonly()
    bricks = bricks[(bricks.ra > ralo) * (bricks.ra < rahi) *
                    (bricks.dec > declo) * (bricks.dec < dechi)]
    print(len(bricks), 'bricks')

    I, = np.nonzero([
        os.path.exists(survey.find_file('tractor', brick=b.brickname))
        for b in bricks
    ])
    print(len(I), 'bricks with catalogs')
    bricks.cut(I)

    for band in bands:
        bricks.set('diff_%s' % band, np.zeros(len(bricks), np.float32))
        bricks.set('psfsize_%s' % band, np.zeros(len(bricks), np.float32))

    diffs = dict([(b, []) for b in bands])
    for ibrick, b in enumerate(bricks):
        fn = survey.find_file('tractor', brick=b.brickname)
        T = fits_table(fn)
        print(len(T), 'sources in', b.brickname)

        brickwcs = wcs_for_brick(b)

        ps1 = ps1cat(ccdwcs=brickwcs)
        stars = ps1.get_stars()
        print(len(stars), 'PS1 sources')

        # Now cut to just *stars* with good colors
        stars.gicolor = stars.median[:, 0] - stars.median[:, 2]
        keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
        stars.cut(keep)
        print(len(stars), 'PS1 stars with good colors')

        I, J, d = match_radec(T.ra, T.dec, stars.ra, stars.dec, 1. / 3600.)
        print(len(I), 'matches')

        for band in bands:
            bricks.get('psfsize_%s' % band)[ibrick] = np.median(
                T.decam_psfsize[:, survey.index_of_band(band)])

            colorterm = ps1_to_decam(stars.median[J], band)

            psmag = stars.median[J, ps1.ps1band[band]]
            psmag += colorterm

            decflux = T.decam_flux[I, survey.index_of_band(band)]
            decmag = -2.5 * (np.log10(decflux) - 9)

            #K = np.flatnonzero((psmag > 14) * (psmag < 24))
            #print(len(K), 'with mag 14 to 24')
            K = np.flatnonzero((psmag > 14) * (psmag < 21))
            print(len(K), 'with mag 14 to 21')
            decmag = decmag[K]
            psmag = psmag[K]
            K = np.flatnonzero(np.abs(decmag - psmag) < 1)
            print(len(K), 'with good mag matches (< 1 mag difference)')
            decmag = decmag[K]
            psmag = psmag[K]

            if False and ibrick == 0:
                plt.clf()
                #plt.plot(psmag, decmag, 'b.')
                plt.plot(psmag, decmag - psmag, 'b.')
                plt.xlabel('PS1 mag')
                plt.xlabel('DECam - PS1 mag')
                plt.title('PS1 matches for %s band, brick %s' %
                          (band, b.brickname))
                ps.savefig()

            mdiff = np.median(decmag - psmag)
            diffs[band].append(mdiff)
            print('Median difference:', mdiff)

            bricks.get('diff_%s' % band)[ibrick] = mdiff

    for band in bands:
        d = diffs[band]

        plt.clf()
        plt.hist(d, bins=20, range=(-0.02, 0.02), histtype='step')
        plt.xlabel('Median mag difference per brick')
        plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
        ps.savefig()

        print('Median differences in', band, 'band:', np.median(d))

    if False:
        plt.clf()
        plt.hist(diffs['g'],
                 bins=20,
                 range=(-0.02, 0.02),
                 histtype='step',
                 color='g')
        plt.hist(diffs['r'],
                 bins=20,
                 range=(-0.02, 0.02),
                 histtype='step',
                 color='r')
        plt.hist(diffs['z'],
                 bins=20,
                 range=(-0.02, 0.02),
                 histtype='step',
                 color='m')
        plt.xlabel('Median mag difference per brick')
        plt.title('DR3 EDR PS1 vs DECaLS')
        ps.savefig()

    rr, dd = np.meshgrid(np.linspace(ralo, rahi, 400),
                         np.linspace(declo, dechi, 400))
    I, J, d = match_radec(rr.ravel(),
                          dd.ravel(),
                          bricks.ra,
                          bricks.dec,
                          0.18,
                          nearest=True)
    print(len(I), 'matches')

    for band in bands:
        plt.clf()
        dmag = np.zeros_like(rr) - 1.
        dmag.ravel()[I] = bricks.get('diff_%s' % band)[J]
        plt.imshow(dmag,
                   interpolation='nearest',
                   origin='lower',
                   vmin=-0.01,
                   vmax=0.01,
                   cmap='hot',
                   extent=(ralo, rahi, declo, dechi))
        plt.colorbar()
        plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
        plt.xlabel('RA (deg)')
        plt.ylabel('Dec (deg)')
        plt.axis([ralo, rahi, declo, dechi])
        ps.savefig()

        plt.clf()
        # reuse 'dmag' map...
        dmag = np.zeros_like(rr)
        dmag.ravel()[I] = bricks.get('psfsize_%s' % band)[J]
        plt.imshow(dmag,
                   interpolation='nearest',
                   origin='lower',
                   cmap='hot',
                   extent=(ralo, rahi, declo, dechi))
        plt.colorbar()
        plt.title('DR3 EDR: DECaLS PSF size: %s band' % band)
        plt.xlabel('RA (deg)')
        plt.ylabel('Dec (deg)')
        plt.axis([ralo, rahi, declo, dechi])
        ps.savefig()

    if False:
        for band in bands:
            plt.clf()
            plt.scatter(bricks.ra,
                        bricks.dec,
                        c=bricks.get('diff_%s' % band),
                        vmin=-0.01,
                        vmax=0.01,
                        edgecolors='face',
                        s=200)
            plt.colorbar()
            plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
            plt.xlabel('RA (deg)')
            plt.ylabel('Dec (deg)')
            plt.axis('scaled')
            plt.axis([ralo, rahi, declo, dechi])
            ps.savefig()

    plt.clf()
    plt.plot(bricks.psfsize_g, bricks.diff_g, 'g.')
    plt.plot(bricks.psfsize_r, bricks.diff_r, 'r.')
    plt.plot(bricks.psfsize_z, bricks.diff_z, 'm.')
    plt.xlabel('PSF size (arcsec)')
    plt.ylabel('DECaLS PSF - PS1 (mag)')
    plt.title('DR3 EDR')
    ps.savefig()
Esempio n. 4
0
def star_profiles(ps):
    # Run an example CCD, 292604-N4, with fairly large difference vs PS1.

    # python -c "from astrometry.util.fits import *; T = merge_tables([fits_table('/project/projectdirs/desiproc/dr3/tractor/244/tractor-244%s.fits' % b) for b in ['2p065','4p065', '7p065']]); T.writeto('tst-cat.fits')"
    # python legacypipe/forced_photom_decam.py --save-data tst-data.fits --save-model tst-model.fits 292604 N4 tst-cat.fits tst-phot.fits

    # -> tst-{model,data,phot}.fits

    datafn = 'tst-data.fits'
    modfn = 'tst-model.fits'
    photfn = 'tst-phot.fits'
    catfn = 'tst-cat.fits'

    img = fitsio.read(datafn)
    mod = fitsio.read(modfn)
    phot = fits_table(photfn)
    cat = fits_table(catfn)
    print(len(phot), 'forced-photometry results')
    margin = 25
    phot.cut((phot.x > 0 + margin) * (phot.x < 2046 - margin) *
             (phot.y > 0 + margin) * (phot.y < 4096 - margin))
    print(len(phot), 'in bounds')

    cmap = dict([((b, o), i)
                 for i, (b, o) in enumerate(zip(cat.brickname, cat.objid))])
    I = np.array(
        [cmap.get((b, o), -1) for b, o in zip(phot.brickname, phot.objid)])
    print(np.sum(I >= 0), 'forced-phot matched cat')
    phot.type = cat.type[I]

    wcs = Sip(datafn)

    phot.ra, phot.dec = wcs.pixelxy2radec(phot.x + 1, phot.y + 1)
    phot.cut(np.argsort(phot.flux))

    phot.sn = phot.flux * np.sqrt(phot.flux_ivar)

    phot.cut(phot.sn > 5)
    print(len(phot), 'with S/N > 5')

    ps1 = ps1cat(ccdwcs=wcs)
    stars = ps1.get_stars()
    print(len(stars), 'PS1 sources')
    # Now cut to just *stars* with good colors
    stars.gicolor = stars.median[:, 0] - stars.median[:, 2]
    keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
    stars.cut(keep)
    print(len(stars), 'PS1 stars with good colors')
    stars.cut(np.minimum(stars.stdev[:, 1], stars.stdev[:, 2]) < 0.05)
    print(len(stars), 'PS1 stars with min stdev(r,i) < 0.05')
    I, J, d = match_radec(phot.ra, phot.dec, stars.ra, stars.dec, 1. / 3600.)
    print(len(I), 'matches')

    plt.clf()
    ha = dict(histtype='step', bins=20, range=(0, 100), normed=True)
    plt.hist(phot.flux, color='b', **ha)
    plt.hist(phot.flux[I], color='r', **ha)
    ps.savefig()

    plt.clf()
    plt.hist(phot.flux * np.sqrt(phot.flux_ivar), bins=100, range=(-10, 50))
    plt.xlabel('Flux S/N')
    ps.savefig()

    K = np.argsort(phot.flux[I])
    I = I[K]
    J = J[K]

    ix = np.round(phot.x).astype(int)
    iy = np.round(phot.y).astype(int)
    sz = 10

    P = np.flatnonzero(phot.type == 'PSF ')
    print(len(P), 'PSFs')

    imed = len(P) / 2
    i1 = int(len(P) * 0.75)
    i2 = int(len(P) * 0.25)
    N = 401

    allmods = []
    allimgs = []

    for II, tt in [  #(I[:len(I)/2], 'faint matches to PS1'),
            #(I[len(I)/2:], 'bright matches to PS1'),
            #(P[i2: i2+N], '25th pct PSFs'),
            #(P[imed: imed+N], 'median PSFs'),
            #(P[i1: i1+N], '75th pct PSFs'),
            #(P[-25:], 'brightest PSFs'),
        (P[i2:imed], '2nd quartile of PSFs'),
        (P[imed:i1], '3rd quartile of PSFs'),
            #(P[:len(P)/2], 'faint half of PSFs'),
            #(P[len(P)/2:], 'bright half of PSFs'),
    ]:
        imgs = []
        mods = []
        shimgs = []
        shmods = []
        imgsum = modsum = 0

        #plt.clf()
        for i in II:

            from astrometry.util.util import lanczos_shift_image

            dy = phot.y[i] - iy[i]
            dx = phot.x[i] - ix[i]

            sub = img[iy[i] - sz:iy[i] + sz + 1, ix[i] - sz:ix[i] + sz + 1]
            shimg = lanczos_shift_image(sub, -dx, -dy)

            sub = mod[iy[i] - sz:iy[i] + sz + 1, ix[i] - sz:ix[i] + sz + 1]
            shmod = lanczos_shift_image(sub, -dx, -dy)

            iyslice = img[iy[i], ix[i] - sz:ix[i] + sz + 1]
            myslice = mod[iy[i], ix[i] - sz:ix[i] + sz + 1]
            ixslice = img[iy[i] - sz:iy[i] + sz + 1, ix[i]]
            mxslice = mod[iy[i] - sz:iy[i] + sz + 1, ix[i]]
            mx = iyslice.max()
            # plt.plot(iyslice/mx, 'b-', alpha=0.1)
            # plt.plot(myslice/mx, 'r-', alpha=0.1)
            # plt.plot(ixslice/mx, 'b-', alpha=0.1)
            # plt.plot(mxslice/mx, 'r-', alpha=0.1)

            siyslice = shimg[sz, :]
            sixslice = shimg[:, sz]
            smyslice = shmod[sz, :]
            smxslice = shmod[:, sz]

            shimgs.append(siyslice / mx)
            shimgs.append(sixslice / mx)
            shmods.append(smyslice / mx)
            shmods.append(smxslice / mx)

            imgs.append(iyslice / mx)
            imgs.append(ixslice / mx)
            mods.append(myslice / mx)
            mods.append(mxslice / mx)

            imgsum = imgsum + ixslice + iyslice
            modsum = modsum + mxslice + myslice

        # plt.ylim(-0.1, 1.1)
        # plt.title(tt)
        # ps.savefig()
        mimg = np.median(np.array(imgs), axis=0)
        mmod = np.median(np.array(mods), axis=0)
        mshim = np.median(np.array(shimgs), axis=0)
        mshmo = np.median(np.array(shmods), axis=0)

        allmods.append(mshmo)
        allimgs.append(mshim)

        plt.clf()
        # plt.plot(mimg, 'b-')
        # plt.plot(mmod, 'r-')
        plt.plot(mshim, 'g-')
        plt.plot(mshmo, 'm-')

        plt.ylim(-0.1, 1.1)
        plt.title(tt + ': median; sums %.3f/%.3f' %
                  (np.sum(mimg), np.sum(mmod)))
        ps.savefig()

        # plt.clf()
        # mx = imgsum.max()
        # plt.plot(imgsum/mx, 'b-')
        # plt.plot(modsum/mx, 'r-')
        # plt.ylim(-0.1, 1.1)
        # plt.title(tt + ': sum')
        # ps.savefig()

        plt.clf()
        plt.plot((mimg + 0.01) / (mmod + 0.01), 'k-')
        plt.plot((imgsum / mx + 0.01) / (modsum / mx + 0.01), 'g-')
        plt.plot((mshim + 0.01) / (mshmo + 0.01), 'm-')
        plt.ylabel('(img + 0.01) / (mod + 0.01)')
        plt.title(tt)
        ps.savefig()

    iq2, iq3 = allimgs
    mq2, mq3 = allmods
    plt.clf()

    plt.plot(iq2, 'r-')
    plt.plot(mq2, 'm-')

    plt.plot(iq3, 'b-')
    plt.plot(mq3, 'g-')

    plt.title('Q2 vs Q3')
    ps.savefig()
Esempio n. 5
0
def star_profiles(ps):
    # Run an example CCD, 292604-N4, with fairly large difference vs PS1.
    
    # python -c "from astrometry.util.fits import *; T = merge_tables([fits_table('/project/projectdirs/desiproc/dr3/tractor/244/tractor-244%s.fits' % b) for b in ['2p065','4p065', '7p065']]); T.writeto('tst-cat.fits')"
    # python legacypipe/forced_photom_decam.py --save-data tst-data.fits --save-model tst-model.fits 292604 N4 tst-cat.fits tst-phot.fits

    # -> tst-{model,data,phot}.fits

    datafn = 'tst-data.fits'
    modfn = 'tst-model.fits'
    photfn = 'tst-phot.fits'
    catfn = 'tst-cat.fits'
    
    img = fitsio.read(datafn)
    mod = fitsio.read(modfn)
    phot = fits_table(photfn)
    cat = fits_table(catfn)
    print(len(phot), 'forced-photometry results')
    margin = 25
    phot.cut((phot.x > 0+margin) * (phot.x < 2046-margin) *
             (phot.y > 0+margin) * (phot.y < 4096-margin))
    print(len(phot), 'in bounds')

    cmap = dict([((b,o),i) for i,(b,o) in enumerate(zip(cat.brickname, cat.objid))])
    I = np.array([cmap.get((b,o), -1) for b,o in zip(phot.brickname, phot.objid)])
    print(np.sum(I >= 0), 'forced-phot matched cat')
    phot.type = cat.type[I]

    wcs = Sip(datafn)
    
    phot.ra,phot.dec = wcs.pixelxy2radec(phot.x+1, phot.y+1)
    phot.cut(np.argsort(phot.flux))

    phot.sn = phot.flux * np.sqrt(phot.flux_ivar)

    phot.cut(phot.sn > 5)
    print(len(phot), 'with S/N > 5')
    
    ps1 = ps1cat(ccdwcs=wcs)
    stars = ps1.get_stars()
    print(len(stars), 'PS1 sources')
    # Now cut to just *stars* with good colors
    stars.gicolor = stars.median[:,0] - stars.median[:,2]
    keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
    stars.cut(keep)
    print(len(stars), 'PS1 stars with good colors')
    stars.cut(np.minimum(stars.stdev[:,1], stars.stdev[:,2]) < 0.05)
    print(len(stars), 'PS1 stars with min stdev(r,i) < 0.05')
    I,J,d = match_radec(phot.ra, phot.dec, stars.ra, stars.dec, 1./3600.)
    print(len(I), 'matches')

    plt.clf()
    ha=dict(histtype='step', bins=20, range=(0,100), normed=True)
    plt.hist(phot.flux, color='b', **ha)
    plt.hist(phot.flux[I], color='r', **ha)
    ps.savefig()

    plt.clf()
    plt.hist(phot.flux * np.sqrt(phot.flux_ivar), bins=100,
             range=(-10, 50))
    plt.xlabel('Flux S/N')
    ps.savefig()
    
    K = np.argsort(phot.flux[I])
    I = I[K]
    J = J[K]

    ix = np.round(phot.x).astype(int)
    iy = np.round(phot.y).astype(int)
    sz = 10

    P = np.flatnonzero(phot.type == 'PSF ')
    print(len(P), 'PSFs')

    imed = len(P)/2
    i1 = int(len(P) * 0.75)
    i2 = int(len(P) * 0.25)
    N = 401

    allmods = []
    allimgs = []
    
    for II,tt in [#(I[:len(I)/2], 'faint matches to PS1'),
        #(I[len(I)/2:], 'bright matches to PS1'),
        #(P[i2: i2+N], '25th pct PSFs'),
        #(P[imed: imed+N], 'median PSFs'),
        #(P[i1: i1+N], '75th pct PSFs'),
        #(P[-25:], 'brightest PSFs'),
        (P[i2:imed], '2nd quartile of PSFs'),
        (P[imed:i1], '3rd quartile of PSFs'),
        #(P[:len(P)/2], 'faint half of PSFs'),
        #(P[len(P)/2:], 'bright half of PSFs'),
                  ]:
        imgs = []
        mods = []
        shimgs = []
        shmods = []
        imgsum = modsum = 0

        #plt.clf()
        for i in II:

            from astrometry.util.util import lanczos_shift_image
            
            dy = phot.y[i] - iy[i]
            dx = phot.x[i] - ix[i]

            sub = img[iy[i]-sz : iy[i]+sz+1, ix[i]-sz : ix[i]+sz+1]
            shimg = lanczos_shift_image(sub, -dx, -dy)

            sub = mod[iy[i]-sz : iy[i]+sz+1, ix[i]-sz : ix[i]+sz+1]
            shmod = lanczos_shift_image(sub, -dx, -dy)

            iyslice = img[iy[i], ix[i]-sz : ix[i]+sz+1]
            myslice = mod[iy[i], ix[i]-sz : ix[i]+sz+1]
            ixslice = img[iy[i]-sz : iy[i]+sz+1, ix[i]]
            mxslice = mod[iy[i]-sz : iy[i]+sz+1, ix[i]]
            mx = iyslice.max()
            # plt.plot(iyslice/mx, 'b-', alpha=0.1)
            # plt.plot(myslice/mx, 'r-', alpha=0.1)
            # plt.plot(ixslice/mx, 'b-', alpha=0.1)
            # plt.plot(mxslice/mx, 'r-', alpha=0.1)

            siyslice = shimg[sz, :]
            sixslice = shimg[:, sz]
            smyslice = shmod[sz, :]
            smxslice = shmod[:, sz]

            shimgs.append(siyslice/mx)
            shimgs.append(sixslice/mx)
            shmods.append(smyslice/mx)
            shmods.append(smxslice/mx)

            imgs.append(iyslice/mx)
            imgs.append(ixslice/mx)
            mods.append(myslice/mx)
            mods.append(mxslice/mx)

            imgsum = imgsum + ixslice + iyslice
            modsum = modsum + mxslice + myslice

        # plt.ylim(-0.1, 1.1)
        # plt.title(tt)
        # ps.savefig()
        mimg = np.median(np.array(imgs), axis=0)
        mmod = np.median(np.array(mods), axis=0)
        mshim = np.median(np.array(shimgs), axis=0)
        mshmo = np.median(np.array(shmods), axis=0)

        allmods.append(mshmo)
        allimgs.append(mshim)
        
        plt.clf()
        # plt.plot(mimg, 'b-')
        # plt.plot(mmod, 'r-')
        plt.plot(mshim, 'g-')
        plt.plot(mshmo, 'm-')
        
        plt.ylim(-0.1, 1.1)
        plt.title(tt + ': median; sums %.3f/%.3f' % (np.sum(mimg), np.sum(mmod)))
        ps.savefig()
        
        # plt.clf()
        # mx = imgsum.max()
        # plt.plot(imgsum/mx, 'b-')
        # plt.plot(modsum/mx, 'r-')
        # plt.ylim(-0.1, 1.1)
        # plt.title(tt + ': sum')
        # ps.savefig()

        plt.clf()
        plt.plot((mimg + 0.01) / (mmod + 0.01), 'k-')
        plt.plot((imgsum/mx + 0.01) / (modsum/mx + 0.01), 'g-')
        plt.plot((mshim + 0.01) / (mshmo + 0.01), 'm-')
        plt.ylabel('(img + 0.01) / (mod + 0.01)')
        plt.title(tt)
        ps.savefig()
        

    iq2,iq3 = allimgs
    mq2,mq3 = allmods
    plt.clf()

    plt.plot(iq2, 'r-')
    plt.plot(mq2, 'm-')

    plt.plot(iq3, 'b-')
    plt.plot(mq3, 'g-')

    plt.title('Q2 vs Q3')
    ps.savefig()
Esempio n. 6
0
def read_forcedphot_ccds(ccds, survey):
    ccds.mdiff = np.zeros(len(ccds))
    ccds.mscatter = np.zeros(len(ccds))

    Nap = 8
    ccds.apdiff = np.zeros((len(ccds), Nap))
    ccds.apscatter = np.zeros((len(ccds), Nap))

    ccds.nforced = np.zeros(len(ccds), np.int16)
    ccds.nunmasked = np.zeros(len(ccds), np.int16)
    ccds.nmatched = np.zeros(len(ccds), np.int16)
    ccds.nps1 = np.zeros(len(ccds), np.int16)
    
    brickcache = {}

    FF = []
    
    for iccd,ccd in enumerate(ccds):
        print('CCD', iccd, 'of', len(ccds))
        F = fits_table(ccd.path)
        print(len(F), 'sources in', ccd.path)

        ccds.nforced[iccd] = len(F)
        
        # arr, have to match with brick sources to get RA,Dec.
        F.ra  = np.zeros(len(F))
        F.dec = np.zeros(len(F))
        F.masked = np.zeros(len(F), bool)

        maglo,maghi = 14.,21.
        maxdmag = 1.
        
        F.mag = -2.5 * (np.log10(F.flux) - 9)
        F.cut((F.flux > 0) * (F.mag > maglo-maxdmag) * (F.mag < maghi+maxdmag))
        print(len(F), 'sources between', (maglo-maxdmag), 'and', (maghi+maxdmag), 'mag')

        im = survey.get_image_object(ccd)
        print('Reading DQ image for', im)
        dq = im.read_dq()
        H,W = dq.shape
        ix = np.clip(np.round(F.x), 0, W-1).astype(int)
        iy = np.clip(np.round(F.y), 0, H-1).astype(int)
        F.mask = dq[iy,ix]
        print(np.sum(F.mask != 0), 'sources are masked')
        
        for brickname in np.unique(F.brickname):
            if not brickname in brickcache:
                brickcache[brickname] = fits_table(survey.find_file('tractor', brick=brickname))
            T = brickcache[brickname]
            idtoindex = np.zeros(T.objid.max()+1, int) - 1
            idtoindex[T.objid] = np.arange(len(T))

            I = np.flatnonzero(F.brickname == brickname)
            J = idtoindex[F.objid[I]]
            assert(np.all(J >= 0))
            F.ra [I] = T.ra [J]
            F.dec[I] = T.dec[J]

            F.masked[I] = (T.decam_anymask[J,:].max(axis=1) > 0)

        #F.cut(F.masked == False)
        #print(len(F), 'not masked')
        print(np.sum(F.masked), 'masked in ANYMASK')

        ccds.nunmasked[iccd] = len(F)
            
        wcs = Tan(*[float(x) for x in [ccd.crval1, ccd.crval2, ccd.crpix1, ccd.crpix2,
                                       ccd.cd1_1, ccd.cd1_2, ccd.cd2_1, ccd.cd2_2,
                                       ccd.width, ccd.height]])

        ps1 = ps1cat(ccdwcs=wcs)
        stars = ps1.get_stars()
        print(len(stars), 'PS1 sources')
        ccds.nps1[iccd] = len(stars)
        
        # Now cut to just *stars* with good colors
        stars.gicolor = stars.median[:,0] - stars.median[:,2]
        keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
        stars.cut(keep)
        print(len(stars), 'PS1 stars with good colors')

        stars.cut(np.minimum(stars.stdev[:,1], stars.stdev[:,2]) < 0.05)
        print(len(stars), 'PS1 stars with min stdev(r,i) < 0.05')
        
        I,J,d = match_radec(F.ra, F.dec, stars.ra, stars.dec, 1./3600.)
        print(len(I), 'matches')

        band = ccd.filter

        colorterm = ps1_to_decam(stars.median[J], band)

        F.cut(I)
        F.psmag = stars.median[J, ps1.ps1band[band]] + colorterm

        K = np.flatnonzero((F.psmag > maglo) * (F.psmag < maghi))
        print(len(K), 'with mag', maglo, 'to', maghi)
        F.cut(K)

        K = np.flatnonzero(np.abs(F.mag - F.psmag) < maxdmag)
        print(len(K), 'with good mag matches (<', maxdmag, 'mag difference)')
        ccds.nmatched[iccd] = len(K)
        if len(K) == 0:
            continue
        F.cut(K)
        
        ccds.mdiff[iccd] = np.median(F.mag - F.psmag)
        ccds.mscatter[iccd] = (np.percentile(F.mag - F.psmag, 84) -
                               np.percentile(F.mag - F.psmag, 16))/2.

        for i in range(Nap):
            apmag = -2.5 * (np.log10(F.apflux[:, i]) - 9)

            ccds.apdiff[iccd,i] = np.median(apmag - F.psmag)
            ccds.apscatter[iccd,i] = (np.percentile(apmag - F.psmag, 84) -
                                      np.percentile(apmag - F.psmag, 16))/2.

        #F.about()
        for c in ['apflux_ivar', 'brickid', 'flux_ivar',
                  'mjd', 'objid', 'fracflux', 'rchi2', 'x','y']:
            F.delete_column(c)

        F.expnum = np.zeros(len(F), np.int32) + ccd.expnum
        F.ccdname = np.array([ccd.ccdname] * len(F))
        F.iforced = np.zeros(len(F), np.int32) + iccd
        
        FF.append(F)

    FF = merge_tables(FF)
        
    return FF



    

    bricks = survey.get_bricks_readonly()
    bricks = bricks[(bricks.ra > ralo) * (bricks.ra < rahi) *
                    (bricks.dec > declo) * (bricks.dec < dechi)]
    print(len(bricks), 'bricks')

    I, = np.nonzero([os.path.exists(survey.find_file('tractor', brick=b.brickname))
                    for b in bricks])
    print(len(I), 'bricks with catalogs')
    bricks.cut(I)
    
    for band in bands:
        bricks.set('diff_%s' % band, np.zeros(len(bricks), np.float32))
        bricks.set('psfsize_%s' % band, np.zeros(len(bricks), np.float32))
        
    diffs = dict([(b,[]) for b in bands])
    for ibrick,b in enumerate(bricks):
        fn = survey.find_file('tractor', brick=b.brickname)
        T = fits_table(fn)
        print(len(T), 'sources in', b.brickname)

        brickwcs = wcs_for_brick(b)
        
        ps1 = ps1cat(ccdwcs=brickwcs)
        stars = ps1.get_stars()
        print(len(stars), 'PS1 sources')

        # Now cut to just *stars* with good colors
        stars.gicolor = stars.median[:,0] - stars.median[:,2]
        keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
        stars.cut(keep)
        print(len(stars), 'PS1 stars with good colors')
        
        I,J,d = match_radec(T.ra, T.dec, stars.ra, stars.dec, 1./3600.)
        print(len(I), 'matches')
        
        for band in bands:
            bricks.get('psfsize_%s' % band)[ibrick] = np.median(
                T.decam_psfsize[:, survey.index_of_band(band)])

            colorterm = ps1_to_decam(stars.median[J], band)

            psmag = stars.median[J, ps1.ps1band[band]]
            psmag += colorterm
            
            decflux = T.decam_flux[I, survey.index_of_band(band)]
            decmag = -2.5 * (np.log10(decflux) - 9)

            #K = np.flatnonzero((psmag > 14) * (psmag < 24))
            #print(len(K), 'with mag 14 to 24')
            K = np.flatnonzero((psmag > 14) * (psmag < 21))
            print(len(K), 'with mag 14 to 21')
            decmag = decmag[K]
            psmag  = psmag [K]
            K = np.flatnonzero(np.abs(decmag - psmag) < 1)
            print(len(K), 'with good mag matches (< 1 mag difference)')
            decmag = decmag[K]
            psmag  = psmag [K]

            if False and ibrick == 0:
                plt.clf()
                #plt.plot(psmag, decmag, 'b.')
                plt.plot(psmag, decmag - psmag, 'b.')
                plt.xlabel('PS1 mag')
                plt.xlabel('DECam - PS1 mag')
                plt.title('PS1 matches for %s band, brick %s' % (band, b.brickname))
                ps.savefig()

            mdiff = np.median(decmag - psmag)
            diffs[band].append(mdiff)
            print('Median difference:', mdiff)

            bricks.get('diff_%s' % band)[ibrick] = mdiff

            
    for band in bands:
        d = diffs[band]

        plt.clf()
        plt.hist(d, bins=20, range=(-0.02, 0.02), histtype='step')
        plt.xlabel('Median mag difference per brick')
        plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
        ps.savefig()

        print('Median differences in', band, 'band:', np.median(d))
        
    if False:
        plt.clf()
        plt.hist(diffs['g'], bins=20, range=(-0.02, 0.02), histtype='step', color='g')
        plt.hist(diffs['r'], bins=20, range=(-0.02, 0.02), histtype='step', color='r')
        plt.hist(diffs['z'], bins=20, range=(-0.02, 0.02), histtype='step', color='m')
        plt.xlabel('Median mag difference per brick')
        plt.title('DR3 EDR PS1 vs DECaLS')
        ps.savefig()

    rr,dd = np.meshgrid(np.linspace(ralo,rahi, 400), np.linspace(declo,dechi, 400))
    I,J,d = match_radec(rr.ravel(), dd.ravel(), bricks.ra, bricks.dec, 0.18, nearest=True)
    print(len(I), 'matches')

    for band in bands:
        plt.clf()
        dmag = np.zeros_like(rr) - 1.
        dmag.ravel()[I] = bricks.get('diff_%s' % band)[J]
        plt.imshow(dmag, interpolation='nearest', origin='lower',
                   vmin=-0.01, vmax=0.01, cmap='hot',
                   extent=(ralo,rahi,declo,dechi))
        plt.colorbar()
        plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
        plt.xlabel('RA (deg)')
        plt.ylabel('Dec (deg)')
        plt.axis([ralo,rahi,declo,dechi])
        ps.savefig()


        plt.clf()
        # reuse 'dmag' map...
        dmag = np.zeros_like(rr)
        dmag.ravel()[I] = bricks.get('psfsize_%s' % band)[J]
        plt.imshow(dmag, interpolation='nearest', origin='lower',
                   cmap='hot', extent=(ralo,rahi,declo,dechi))
        plt.colorbar()
        plt.title('DR3 EDR: DECaLS PSF size: %s band' % band)
        plt.xlabel('RA (deg)')
        plt.ylabel('Dec (deg)')
        plt.axis([ralo,rahi,declo,dechi])
        ps.savefig()

    if False:
        for band in bands:
            plt.clf()
            plt.scatter(bricks.ra, bricks.dec, c=bricks.get('diff_%s' % band), vmin=-0.01, vmax=0.01,
                        edgecolors='face', s=200)
            plt.colorbar()
            plt.title('DR3 EDR PS1 vs DECaLS: %s band' % band)
            plt.xlabel('RA (deg)')
            plt.ylabel('Dec (deg)')
            plt.axis('scaled')
            plt.axis([ralo,rahi,declo,dechi])
            ps.savefig()


    plt.clf()
    plt.plot(bricks.psfsize_g, bricks.diff_g, 'g.')
    plt.plot(bricks.psfsize_r, bricks.diff_r, 'r.')
    plt.plot(bricks.psfsize_z, bricks.diff_z, 'm.')
    plt.xlabel('PSF size (arcsec)')
    plt.ylabel('DECaLS PSF - PS1 (mag)')
    plt.title('DR3 EDR')
    ps.savefig()
Esempio n. 7
0
def psf_residuals(expnum,ccdname,stampsize=35,nstar=30,
                  magrange=(13,17),verbose=0):

    # Set the debugging level.
    if verbose==0:
        lvl = logging.INFO
    else:
        lvl = logging.DEBUG
    logging.basicConfig(level=lvl,format='%(message)s',stream=sys.stdout)

    pngprefix = 'qapsf-{}-{}'.format(expnum,ccdname)

    # Gather all the info we need about this CCD.
    decals = Decals()
    ccd = decals.find_ccds(expnum=expnum,ccdname=ccdname)[0]
    band = ccd.filter
    ps1band = dict(g=0,r=1,i=2,z=3,Y=4)
    print('Band {}'.format(band))

    #scales = dict(g=0.0066, r=0.01, z=0.025)
    #vmin, vmax = np.arcsinh(-1), np.arcsinh(100)
    #print(scales[band])

    im = DecamImage(decals,ccd)
    iminfo = im.get_image_info()
    H,W = iminfo['dims']

    wcs = im.get_wcs()

    # Choose a uniformly selected subset of PS1 stars on this CCD.
    ps1 = ps1cat(ccdwcs=wcs)
    cat = ps1.get_stars(band=band,magrange=magrange)

    rand = np.random.RandomState(seed=expnum*ccd.ccdnum)
    these = rand.choice(len(cat)-1,nstar,replace=False)
    #these = rand.random_integers(0,len(cat)-1,nstar)
    cat = cat[these]
    cat = cat[np.argsort(cat.median[:,ps1band[band]])] # sort by magnitude
    #print(cat.nmag_ok)

    # Make a QAplot of the positions of all the stars.
    tim = im.get_tractor_image(const2psf=True)
    img = tim.getImage()
    #img = tim.getImage()/scales[band]

    fig = plt.figure(figsize=(5,10))
    ax = fig.gca()
    ax.get_xaxis().get_major_formatter().set_useOffset(False)
    #ax.imshow(np.arcsinh(img),cmap='gray',interpolation='nearest',
    #          origin='lower',vmin=vmax,vmax=vmax)
    
    ax.imshow(img, **tim.ima)
    ax.axis('off')
    ax.set_title('{}: {}/{} AM={:.2f} Seeing={:.3f}"'.
                 format(band,expnum,ccdname,ccd.airmass,ccd.seeing))

    for istar, ps1star in enumerate(cat):
        ra, dec = (ps1star.ra, ps1star.dec)
        ok, xpos, ypos = wcs.radec2pixelxy(ra, dec)
        ax.text(xpos,ypos,'{:2d}'.format(istar+1),color='red',
                horizontalalignment='left')
        circ = plt.Circle((xpos,ypos),radius=30,color='g',fill=False,lw=1)
        ax.add_patch(circ)

    #radec = wcs.radec_bounds()
    #ax.scatter(cat.ra,cat.dec)
    #ax.set_xlim([radec[1],radec[0]])#*[1.0002,0.9998])
    #ax.set_ylim([radec[2],radec[3]])#*[0.985,1.015])
    #ax.set_xlabel('$RA\ (deg)$',fontsize=18)
    #ax.set_ylabel('$Dec\ (deg)$',fontsize=18)
    fig.savefig(pngprefix+'-ccd.png',bbox_inches='tight')

    # Initialize the many-stamp QAplot
    ncols = 3
    nrows = np.ceil(nstar/ncols).astype('int')

    inchperstamp = 2.0
    fig = plt.figure(figsize=(inchperstamp*3*ncols,inchperstamp*nrows))
    irow = 0
    icol = 0
    
    for istar, ps1star in enumerate(cat):
        ra, dec = (ps1star.ra, ps1star.dec)
        mag = ps1star.median[ps1band[band]] # r-band

        ok, xpos, ypos = wcs.radec2pixelxy(ra, dec)
        ix,iy = int(xpos), int(ypos)

        # create a little tractor Image object around the star
        slc = (slice(max(iy-stampsize, 0), min(iy+stampsize+1, H)),
               slice(max(ix-stampsize, 0), min(ix+stampsize+1, W)))

        # The PSF model 'const2Psf' is the one used in DR1: a 2-component
        # Gaussian fit to PsfEx instantiated in the image center.
        tim = im.get_tractor_image(slc=slc, const2psf=True)
        stamp = tim.getImage()
        ivarstamp = tim.getInvvar()

        # Initialize a tractor PointSource from PS1 measurements
        flux = NanoMaggies.magToNanomaggies(mag)
        star = PointSource(RaDecPos(ra,dec), NanoMaggies(**{band: flux}))

        # Fit just the source RA,Dec,flux.
        tractor = Tractor([tim], [star])
        tractor.freezeParam('images')

        print('2-component MOG:', tim.psf)
        tractor.printThawedParams()

        for step in range(50):
            dlnp,X,alpha = tractor.optimize()
            if dlnp < 0.1:
                break
        print('Fit:', star)
        model_mog = tractor.getModelImage(0)
        chi2_mog = -2.0*tractor.getLogLikelihood()
        mag_mog = NanoMaggies.nanomaggiesToMag(star.brightness)[0]

        # Now change the PSF model to a pixelized PSF model from PsfEx instantiated
        # at this place in the image.
        psf = PixelizedPsfEx(im.psffn)
        tim.psf = psf.constantPsfAt(xpos, ypos)

        #print('PSF model:', tim.psf)
        #tractor.printThawedParams()
        for step in range(50):
            dlnp,X,alpha = tractor.optimize()
            if dlnp < 0.1:
                break

        print('Fit:', star)
        model_psfex = tractor.getModelImage(0)
        chi2_psfex = -2.0*tractor.getLogLikelihood()
        mag_psfex = NanoMaggies.nanomaggiesToMag(star.brightness)[0]

        #mn, mx = np.percentile((stamp-model_psfex)[ivarstamp>0],[1,95])
        sig = np.std((stamp-model_psfex)[ivarstamp>0])
        mn, mx = [-2.0*sig,5*sig]

        # Generate a QAplot.
        if (istar>0) and (istar%(ncols)==0):
            irow = irow+1
        icol = 3*istar - 3*ncols*irow
        #print(istar, irow, icol, icol+1, icol+2)

        ax1 = plt.subplot2grid((nrows,3*ncols), (irow,icol), aspect='equal')
        ax1.axis('off')
        #ax1.imshow(stamp, **tim.ima)
        ax1.imshow(stamp,cmap='gray',interpolation='nearest',
                   origin='lower',vmin=mn,vmax=mx)
        ax1.text(0.1,0.9,'{:2d}'.format(istar+1),color='white',
                horizontalalignment='left',verticalalignment='top',
                transform=ax1.transAxes)

        ax2 = plt.subplot2grid((nrows,3*ncols), (irow,icol+1), aspect='equal')
        ax2.axis('off')
        #ax2.imshow(stamp-model_mog, **tim.ima)
        ax2.imshow(stamp-model_mog,cmap='gray',interpolation='nearest',
                   origin='lower',vmin=mn,vmax=mx)
        ax2.text(0.1,0.9,'MoG',color='white',
                horizontalalignment='left',verticalalignment='top',
                transform=ax2.transAxes)
        ax2.text(0.08,0.08,'{:.3f}'.format(mag_mog),color='white',
                 horizontalalignment='left',verticalalignment='bottom',
                 transform=ax2.transAxes)

        #ax2.set_title('{:.3f}, {:.2f}'.format(mag_psfex,chi2_psfex),fontsize=14)
        #ax2.set_title('{:.3f}, $\chi^{2}$={:.2f}'.format(mag_psfex,chi2_psfex))

        ax3 = plt.subplot2grid((nrows,3*ncols), (irow,icol+2), aspect='equal')
        ax3.axis('off')
        #ax3.imshow(stamp-model_psfex, **tim.ima)
        ax3.imshow(stamp-model_psfex,cmap='gray',interpolation='nearest',
                   origin='lower',vmin=mn,vmax=mx)
        ax3.text(0.1,0.9,'PSFEx',color='white',
                horizontalalignment='left',verticalalignment='top',
                transform=ax3.transAxes)
        ax3.text(0.08,0.08,'{:.3f}'.format(mag_psfex),color='white',
                 horizontalalignment='left',verticalalignment='bottom',
                 transform=ax3.transAxes)

        if istar==(nstar-1):
            break
    fig.savefig(pngprefix+'-stargrid.png',bbox_inches='tight')
Esempio n. 8
0
    def run(self, ps=None, focus=False, momentsize=5, n_fwhm=100):
        import pylab as plt
        from astrometry.util.plotutils import dimshow, plothist
        from legacyanalysis.ps1cat import ps1cat
        import photutils
        import tractor

        fn = self.fn
        ext = self.ext
        pixsc = self.pixscale

        F = fitsio.FITS(fn)
        primhdr = F[0].read_header()
        self.primhdr = primhdr
        img, hdr = self.read_raw(F, ext)
        self.hdr = hdr

        # pre sky-sub
        mn, mx = np.percentile(img.ravel(), [25, 98])
        self.imgkwa = dict(vmin=mn, vmax=mx, cmap='gray')

        if self.debug and ps is not None:
            plt.clf()
            dimshow(img, **self.imgkwa)
            plt.title('Raw image')
            ps.savefig()

            M = 200
            plt.clf()
            plt.subplot(2, 2, 1)
            dimshow(img[-M:, :M], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 2)
            dimshow(img[-M:, -M:], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 3)
            dimshow(img[:M, :M], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 4)
            dimshow(img[:M, -M:], ticks=False, **self.imgkwa)
            plt.suptitle('Raw image corners')
            ps.savefig()

        img, trim_x0, trim_y0 = self.trim_edges(img)

        fullH, fullW = img.shape

        if self.debug and ps is not None:
            plt.clf()
            dimshow(img, **self.imgkwa)
            plt.title('Trimmed image')
            ps.savefig()

            M = 200
            plt.clf()
            plt.subplot(2, 2, 1)
            dimshow(img[-M:, :M], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 2)
            dimshow(img[-M:, -M:], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 3)
            dimshow(img[:M, :M], ticks=False, **self.imgkwa)
            plt.subplot(2, 2, 4)
            dimshow(img[:M, -M:], ticks=False, **self.imgkwa)
            plt.suptitle('Trimmed corners')
            ps.savefig()

        band = self.get_band(primhdr)
        exptime = primhdr['EXPTIME']
        airmass = primhdr['AIRMASS']
        print('Band', band, 'Exptime', exptime, 'Airmass', airmass)

        zp0 = self.nom.zeropoint(band, ext=self.ext)
        sky0 = self.nom.sky(band)
        kx = self.nom.fiducial_exptime(band).k_co

        # Find the sky value and noise level
        sky, sig1 = self.get_sky_and_sigma(img)

        sky1 = np.median(sky)
        skybr = -2.5 * np.log10(sky1 / pixsc / pixsc / exptime) + zp0
        print('Sky brightness: %8.3f mag/arcsec^2' % skybr)
        print('Fiducial:       %8.3f mag/arcsec^2' % sky0)

        img -= sky

        self.remove_sky_gradients(img)

        # Post sky-sub
        mn, mx = np.percentile(img.ravel(), [25, 98])
        self.imgkwa = dict(vmin=mn, vmax=mx, cmap='gray')

        if ps is not None:
            plt.clf()
            dimshow(img, **self.imgkwa)
            plt.title('Sky-sub image: %s-%s' % (os.path.basename(fn).replace(
                '.fits', '').replace('.fz', ''), ext))
            plt.colorbar()
            ps.savefig()

        # Read WCS header and compute boresight
        wcs = self.get_wcs(hdr)
        ra_ccd, dec_ccd = wcs.pixelxy2radec((fullW + 1) / 2., (fullH + 1) / 2.)

        # Detect stars
        psfsig = self.nominal_fwhm / 2.35
        detsn = self.detection_map(img, sig1, psfsig, ps)

        slices = self.detect_sources(detsn, self.det_thresh, ps)
        print(len(slices), 'sources detected')
        if len(slices) < 20:
            slices = self.detect_sources(detsn, 10., ps)
            print(len(slices), 'sources detected')
        ndetected = len(slices)

        camera = primhdr.get('INSTRUME', '').strip().lower()
        # -> "decam" / "mosaic3"
        meas = dict(band=band,
                    airmass=airmass,
                    skybright=skybr,
                    pixscale=pixsc,
                    primhdr=primhdr,
                    hdr=hdr,
                    wcs=wcs,
                    ra_ccd=ra_ccd,
                    dec_ccd=dec_ccd,
                    extension=ext,
                    camera=camera,
                    ndetected=ndetected)

        if ndetected == 0:
            print('NO SOURCES DETECTED')
            return meas

        xx, yy = [], []
        fx, fy = [], []
        mx2, my2, mxy = [], [], []
        wmx2, wmy2, wmxy = [], [], []
        # "Peak" region to centroid
        P = momentsize
        H, W = img.shape

        for i, slc in enumerate(slices):
            y0 = slc[0].start
            x0 = slc[1].start
            subimg = detsn[slc]
            imax = np.argmax(subimg)
            y, x = np.unravel_index(imax, subimg.shape)
            if (x0 + x) < P or (x0 + x) > W - 1 - P or (y0 + y) < P or (
                    y0 + y) > H - 1 - P:
                #print('Skipping edge peak', x0+x, y0+y)
                continue
            xx.append(x0 + x)
            yy.append(y0 + y)
            pkarea = detsn[y0 + y - P:y0 + y + P + 1,
                           x0 + x - P:x0 + x + P + 1]

            from scipy.ndimage.measurements import center_of_mass
            cy, cx = center_of_mass(pkarea)
            #print('Center of mass', cx,cy)
            fx.append(x0 + x - P + cx)
            fy.append(y0 + y - P + cy)
            #print('x,y', x0+x, y0+y, 'vs centroid', x0+x-P+cx, y0+y-P+cy)

            ### HACK -- measure source ellipticity
            # go back to the image (not detection map)
            #subimg = img[slc]
            subimg = img[y0 + y - P:y0 + y + P + 1,
                         x0 + x - P:x0 + x + P + 1].copy()
            subimg /= subimg.sum()
            ph, pw = subimg.shape
            px, py = np.meshgrid(np.arange(pw), np.arange(ph))
            mx2.append(np.sum(subimg * (px - cx)**2))
            my2.append(np.sum(subimg * (py - cy)**2))
            mxy.append(np.sum(subimg * (px - cx) * (py - cy)))
            # Gaussian windowed version
            s = 1.
            wimg = subimg * np.exp(-0.5 * ((px - cx)**2 + (py - cy)**2) / s**2)
            wimg /= np.sum(wimg)
            wmx2.append(np.sum(wimg * (px - cx)**2))
            wmy2.append(np.sum(wimg * (py - cy)**2))
            wmxy.append(np.sum(wimg * (px - cx) * (py - cy)))

        mx2 = np.array(mx2)
        my2 = np.array(my2)
        mxy = np.array(mxy)
        wmx2 = np.array(wmx2)
        wmy2 = np.array(wmy2)
        wmxy = np.array(wmxy)

        # semi-major/minor axes and position angle
        theta = np.rad2deg(np.arctan2(2 * mxy, mx2 - my2) / 2.)
        theta = np.abs(theta) * np.sign(mxy)
        s = np.sqrt(((mx2 - my2) / 2.)**2 + mxy**2)
        a = np.sqrt((mx2 + my2) / 2. + s)
        b = np.sqrt((mx2 + my2) / 2. - s)
        ell = 1. - b / a

        wtheta = np.rad2deg(np.arctan2(2 * wmxy, wmx2 - wmy2) / 2.)
        wtheta = np.abs(wtheta) * np.sign(wmxy)
        ws = np.sqrt(((wmx2 - wmy2) / 2.)**2 + wmxy**2)
        wa = np.sqrt((wmx2 + wmy2) / 2. + ws)
        wb = np.sqrt((wmx2 + wmy2) / 2. - ws)
        well = 1. - wb / wa

        fx = np.array(fx)
        fy = np.array(fy)
        xx = np.array(xx)
        yy = np.array(yy)

        if ps is not None:

            plt.clf()
            dimshow(detsn, vmin=-3, vmax=50, cmap='gray')
            ax = plt.axis()
            plt.plot(fx, fy, 'go', mec='g', mfc='none', ms=10)
            plt.colorbar()
            plt.title('Detected sources')
            plt.axis(ax)
            ps.savefig()

            # show centroids too
            # plt.plot(xx, yy, 'go', mec='g', mfc='none', ms=8)
            # plt.axis(ax)
            # ps.savefig()

        # if ps is not None:
        #     plt.clf()
        #     plt.subplot(2,1,1)
        #     mx = np.percentile(np.append(mx2,my2), 99)
        #     ha = dict(histtype='step', range=(0,mx), bins=50)
        #     plt.hist(mx2, color='b', label='mx2', **ha)
        #     plt.hist(my2, color='r', label='my2', **ha)
        #     plt.hist(mxy, color='g', label='mxy', **ha)
        #     plt.legend()
        #     plt.xlim(0,mx)
        #     plt.subplot(2,1,2)
        #     mx = np.percentile(np.append(wmx2,wmy2), 99)
        #     ha = dict(histtype='step', range=(0,mx), bins=50, lw=3, alpha=0.3)
        #     plt.hist(wmx2, color='b', label='wx2', **ha)
        #     plt.hist(wmy2, color='r', label='wy2', **ha)
        #     plt.hist(wmxy, color='g', label='wxy', **ha)
        #     plt.legend()
        #     plt.xlim(0,mx)
        #     plt.suptitle('Source moments')
        #     ps.savefig()
        #
        #     #mx = np.percentile(np.abs(np.append(mxy,wmxy)), 99)
        #     plt.clf()
        #     plt.subplot(2,1,1)
        #     ha = dict(histtype='step', range=(0,1), bins=50)
        #     plt.hist(ell, color='g', label='ell', **ha)
        #     plt.hist(well, color='g', lw=3, alpha=0.3, label='windowed ell', **ha)
        #     plt.legend()
        #     plt.subplot(2,1,2)
        #     ha = dict(histtype='step', range=(-90,90), bins=50)
        #     plt.hist(theta, color='g', label='theta', **ha)
        #     plt.hist(wtheta, color='g', lw=3, alpha=0.3,
        #              label='windowed theta', **ha)
        #     plt.xlim(-90,90)
        #     plt.legend()
        #     plt.suptitle('Source ellipticities & angles')
        #     ps.savefig()

        # Cut down to stars whose centroids are within 1 pixel of their peaks...
        #keep = (np.hypot(fx - xx, fy - yy) < 2)
        #print(sum(keep), 'of', len(keep), 'stars have centroids within 2 of peaks')
        #print('mean dx', np.mean(fx-xx), 'dy', np.mean(fy-yy), 'pixels')
        #assert(float(sum(keep)) / len(keep) > 0.9)
        #fx = fx[keep]
        #fy = fy[keep]

        apxy = np.vstack((fx, fy)).T
        ap = []
        aprad_pix = self.aprad / pixsc
        aper = photutils.CircularAperture(apxy, aprad_pix)
        p = photutils.aperture_photometry(img, aper)
        apflux = p.field('aperture_sum')

        # Manual aperture photometry to get clipped means in sky annulus
        sky_inner_r, sky_outer_r = [r / pixsc for r in self.skyrad]
        sky = []
        for xi, yi in zip(fx, fy):
            ix = int(np.round(xi))
            iy = int(np.round(yi))
            skyR = int(np.ceil(sky_outer_r))
            xlo = max(0, ix - skyR)
            xhi = min(W, ix + skyR + 1)
            ylo = max(0, iy - skyR)
            yhi = min(H, iy + skyR + 1)
            xx, yy = np.meshgrid(np.arange(xlo, xhi), np.arange(ylo, yhi))
            r2 = (xx - xi)**2 + (yy - yi)**2
            inannulus = ((r2 >= sky_inner_r**2) * (r2 < sky_outer_r**2))
            skypix = img[ylo:yhi, xlo:xhi][inannulus]
            #print('ylo,yhi, xlo,xhi', ylo,yhi, xlo,xhi, 'img subshape', img[ylo:yhi, xlo:xhi].shape, 'inann shape', inannulus.shape)
            s, nil = sensible_sigmaclip(skypix)
            sky.append(s)
        sky = np.array(sky)

        apflux2 = apflux - sky * (np.pi * aprad_pix**2)
        good = (apflux2 > 0) * (apflux > 0)
        apflux = apflux[good]
        apflux2 = apflux2[good]
        fx = fx[good]
        fy = fy[good]

        # Read in the PS1 catalog, and keep those within 0.25 deg of CCD center
        # and those with main sequence colors
        pscat = ps1cat(ccdwcs=wcs)
        stars = pscat.get_stars()
        #print('Got PS1 stars:', len(stars))

        # we add the color term later
        ps1band = ps1cat.ps1band[band]
        stars.mag = stars.median[:, ps1band]

        ok, px, py = wcs.radec2pixelxy(stars.ra, stars.dec)
        px -= 1
        py -= 1

        if ps is not None:
            #kwa = dict(vmin=-3*sig1, vmax=50*sig1, cmap='gray')
            # Add to the 'detected sources' plot
            # mn,mx = np.percentile(img.ravel(), [50,99])
            # kwa = dict(vmin=mn, vmax=mx, cmap='gray')
            # plt.clf()
            # dimshow(img, **kwa)
            ax = plt.axis()
            #plt.plot(fx, fy, 'go', mec='g', mfc='none', ms=10)
            K = np.argsort(stars.mag)
            plt.plot(px[K[:10]] - trim_x0,
                     py[K[:10]] - trim_y0,
                     'o',
                     mec='m',
                     mfc='none',
                     ms=12,
                     mew=2)
            plt.plot(px[K[10:]] - trim_x0,
                     py[K[10:]] - trim_y0,
                     'o',
                     mec='m',
                     mfc='none',
                     ms=8)
            plt.axis(ax)
            plt.title('PS1 stars')
            #plt.colorbar()
            ps.savefig()

        # we trimmed the image before running detection; re-add that margin
        fullx = fx + trim_x0
        fully = fy + trim_y0

        # Match PS1 to our detections, find offset
        radius = self.maxshift / pixsc

        I, J, dx, dy = self.match_ps1_stars(px, py, fullx, fully, radius,
                                            stars)
        print(len(I), 'spatial matches with large radius', self.maxshift,
              'arcsec,', radius, 'pix')

        bins = 2 * int(np.ceil(radius))
        #print('Histogramming with', bins, 'bins')
        histo, xe, ye = np.histogram2d(dx,
                                       dy,
                                       bins=bins,
                                       range=((-radius, radius), (-radius,
                                                                  radius)))
        # smooth histogram before finding peak -- fuzzy matching
        from scipy.ndimage.filters import gaussian_filter
        histo = gaussian_filter(histo, 1.)
        histo = histo.T
        mx = np.argmax(histo)
        my, mx = np.unravel_index(mx, histo.shape)
        shiftx = (xe[mx] + xe[mx + 1]) / 2.
        shifty = (ye[my] + ye[my + 1]) / 2.

        if ps is not None:
            plt.clf()
            plothist(dx, dy, range=((-radius, radius), (-radius, radius)))
            plt.xlabel('dx (pixels)')
            plt.ylabel('dy (pixels)')
            plt.title('Offsets to PS1 stars')
            ax = plt.axis()
            plt.axhline(0, color='b')
            plt.axvline(0, color='b')
            plt.plot(shiftx, shifty, 'o', mec='m', mfc='none', ms=15, mew=3)
            plt.axis(ax)
            ps.savefig()

        # Refine with smaller search radius
        radius2 = 3. / pixsc
        I, J, dx, dy = self.match_ps1_stars(px, py, fullx + shiftx,
                                            fully + shifty, radius2, stars)
        print(len(J), 'matches to PS1 with small radius', 3, 'arcsec')
        shiftx2 = np.median(dx)
        shifty2 = np.median(dy)
        #print('Stage-1 shift', shiftx, shifty)
        #print('Stage-2 shift', shiftx2, shifty2)
        sx = shiftx + shiftx2
        sy = shifty + shifty2
        print('Astrometric shift (%.0f, %.0f) pixels' % (sx, sy))

        if self.debug and ps is not None:
            plt.clf()
            plothist(dx, dy, range=((-radius2, radius2), (-radius2, radius2)))
            plt.xlabel('dx (pixels)')
            plt.ylabel('dy (pixels)')
            plt.title('Offsets to PS1 stars')
            ax = plt.axis()
            plt.axhline(0, color='b')
            plt.axvline(0, color='b')
            plt.plot(shiftx2, shifty2, 'o', mec='m', mfc='none', ms=15, mew=3)
            plt.axis(ax)
            ps.savefig()

        if ps is not None:
            mn, mx = np.percentile(img.ravel(), [50, 99])
            kwa2 = dict(vmin=mn, vmax=mx, cmap='gray')
            plt.clf()
            dimshow(img, **kwa2)
            ax = plt.axis()
            plt.plot(fx[J], fy[J], 'go', mec='g', mfc='none', ms=10, mew=2)
            plt.plot(px[I] - sx - trim_x0,
                     py[I] - sy - trim_y0,
                     'm+',
                     ms=10,
                     mew=2)
            plt.axis(ax)
            plt.title('Matched PS1 stars')
            plt.colorbar()
            ps.savefig()

            plt.clf()
            dimshow(img, **kwa2)
            ax = plt.axis()
            plt.plot(fx[J], fy[J], 'go', mec='g', mfc='none', ms=10, mew=2)
            K = np.argsort(stars.mag)
            plt.plot(px[K[:10]] - sx - trim_x0,
                     py[K[:10]] - sy - trim_y0,
                     'o',
                     mec='m',
                     mfc='none',
                     ms=12,
                     mew=2)
            plt.plot(px[K[10:]] - sx - trim_x0,
                     py[K[10:]] - sy - trim_y0,
                     'o',
                     mec='m',
                     mfc='none',
                     ms=8,
                     mew=2)
            plt.axis(ax)
            plt.title('All PS1 stars')
            plt.colorbar()
            ps.savefig()

        # Now cut to just *stars* with good colors
        stars.gicolor = stars.median[:, 0] - stars.median[:, 2]
        keep = (stars.gicolor > 0.4) * (stars.gicolor < 2.7)
        stars.cut(keep)
        if len(stars) == 0:
            print('No overlap or too few stars in PS1')
            return None
        px = px[keep]
        py = py[keep]
        # Re-match
        I, J, dx, dy = self.match_ps1_stars(px, py, fullx + sx, fully + sy,
                                            radius2, stars)
        print('Cut to', len(stars), 'PS1 stars with good colors; matched',
              len(I))

        nmatched = len(I)

        meas.update(dx=sx, dy=sy, nmatched=nmatched)

        if focus:
            meas.update(img=img,
                        hdr=hdr,
                        primhdr=primhdr,
                        fx=fx,
                        fy=fy,
                        px=px - trim_x0 - sx,
                        py=py - trim_y0 - sy,
                        sig1=sig1,
                        stars=stars,
                        moments=(mx2, my2, mxy, theta, a, b, ell),
                        wmoments=(wmx2, wmy2, wmxy, wtheta, wa, wb, well),
                        apflux=apflux,
                        apflux2=apflux2)
            return meas

        #print('Mean astrometric shift (arcsec): delta-ra=', -np.mean(dy)*0.263, 'delta-dec=', np.mean(dx)*0.263)

        # Compute photometric offset compared to PS1
        # as the PS1 minus observed mags
        colorterm = self.colorterm_ps1_to_observed(stars.median, band)
        stars.mag += colorterm
        ps1mag = stars.mag[I]

        if False and ps is not None:
            plt.clf()
            plt.semilogy(ps1mag, apflux2[J], 'b.')
            plt.xlabel('PS1 mag')
            plt.ylabel('DECam ap flux (with sky sub)')
            ps.savefig()

            plt.clf()
            plt.semilogy(ps1mag, apflux[J], 'b.')
            plt.xlabel('PS1 mag')
            plt.ylabel('DECam ap flux (no sky sub)')
            ps.savefig()

        apmag2 = -2.5 * np.log10(apflux2) + zp0 + 2.5 * np.log10(exptime)
        apmag = -2.5 * np.log10(apflux) + zp0 + 2.5 * np.log10(exptime)

        if ps is not None:
            plt.clf()
            plt.plot(ps1mag, apmag[J], 'b.', label='No sky sub')
            plt.plot(ps1mag, apmag2[J], 'r.', label='Sky sub')
            # ax = plt.axis()
            # mn = min(ax[0], ax[2])
            # mx = max(ax[1], ax[3])
            # plt.plot([mn,mx], [mn,mx], 'k-', alpha=0.1)
            # plt.axis(ax)
            plt.xlabel('PS1 mag')
            plt.ylabel('DECam ap mag')
            plt.legend(loc='upper left')
            plt.title('Zeropoint')
            ps.savefig()

        dm = ps1mag - apmag[J]
        dmag, dsig = sensible_sigmaclip(dm, nsigma=2.5)
        print('Mag offset: %8.3f' % dmag)
        print('Scatter:    %8.3f' % dsig)

        if not np.isfinite(dmag) or not np.isfinite(dsig):
            print('FAILED TO GET ZEROPOINT!')
            meas.update(zp=None)
            return meas

        from scipy.stats import sigmaclip
        goodpix, lo, hi = sigmaclip(dm, low=3, high=3)
        dmagmed = np.median(goodpix)
        print(len(goodpix), 'stars used for zeropoint median')
        print('Using median zeropoint:')
        zp_med = zp0 + dmagmed
        trans_med = 10.**(-0.4 * (zp0 - zp_med - kx * (airmass - 1.)))
        print('Zeropoint %6.3f' % zp_med)
        print('Transparency: %.3f' % trans_med)

        dm = ps1mag - apmag2[J]
        dmag2, dsig2 = sensible_sigmaclip(dm, nsigma=2.5)
        #print('Sky-sub mag offset', dmag2)
        #print('Scatter', dsig2)

        if ps is not None:
            plt.clf()
            plt.plot(ps1mag,
                     apmag[J] + dmag - ps1mag,
                     'b.',
                     label='No sky sub')
            plt.plot(ps1mag, apmag2[J] + dmag2 - ps1mag, 'r.', label='Sky sub')
            plt.xlabel('PS1 mag')
            plt.ylabel('DECam ap mag - PS1 mag')
            plt.legend(loc='upper left')
            plt.ylim(-0.25, 0.25)
            plt.axhline(0, color='k', alpha=0.25)
            plt.title('Zeropoint')
            ps.savefig()

        zp_obs = zp0 + dmag
        transparency = 10.**(-0.4 * (zp0 - zp_obs - kx * (airmass - 1.)))
        meas.update(zp=zp_obs, transparency=transparency)

        print('Zeropoint %6.3f' % zp_obs)
        print('Fiducial  %6.3f' % zp0)
        print('Transparency: %.3f' % transparency)

        # print('Using sky-subtracted values:')
        # zp_sky = zp0 + dmag2
        # trans_sky = 10.**(-0.4 * (zp0 - zp_sky - kx * (airmass - 1.)))
        # print('Zeropoint %6.3f' % zp_sky)
        # print('Transparency: %.3f' % trans_sky)

        fwhms = []
        psf_r = 15
        if n_fwhm not in [0, None]:
            Jf = J[:n_fwhm]

        for i, (xi, yi, fluxi) in enumerate(zip(fx[Jf], fy[Jf], apflux[Jf])):
            #print('Fitting source', i, 'of', len(Jf))
            ix = int(np.round(xi))
            iy = int(np.round(yi))
            xlo = max(0, ix - psf_r)
            xhi = min(W, ix + psf_r + 1)
            ylo = max(0, iy - psf_r)
            yhi = min(H, iy + psf_r + 1)
            xx, yy = np.meshgrid(np.arange(xlo, xhi), np.arange(ylo, yhi))
            r2 = (xx - xi)**2 + (yy - yi)**2
            keep = (r2 < psf_r**2)
            pix = img[ylo:yhi, xlo:xhi].copy()
            ie = np.zeros_like(pix)
            ie[keep] = 1. / sig1
            #print('fitting source at', ix,iy)
            #print('number of active pixels:', np.sum(ie > 0), 'shape', ie.shape)

            psf = tractor.NCircularGaussianPSF([4.], [1.])
            tim = tractor.Image(data=pix, inverr=ie, psf=psf)
            src = tractor.PointSource(tractor.PixPos(xi - xlo, yi - ylo),
                                      tractor.Flux(fluxi))
            tr = tractor.Tractor([tim], [src])

            #print('Posterior before prior:', tr.getLogProb())
            src.pos.addGaussianPrior('x', 0., 1.)
            #print('Posterior after prior:', tr.getLogProb())

            doplot = (i < 5) * (ps is not None)
            if doplot:
                mod0 = tr.getModelImage(0)

            tim.freezeAllBut('psf')
            psf.freezeAllBut('sigmas')

            # print('Optimizing params:')
            # tr.printThawedParams()

            #print('Parameter step sizes:', tr.getStepSizes())
            optargs = dict(priors=False, shared_params=False)
            for step in range(50):
                dlnp, x, alpha = tr.optimize(**optargs)
                #print('dlnp', dlnp)
                #print('src', src)
                #print('psf', psf)
                if dlnp == 0:
                    break
            # Now fit only the PSF size
            tr.freezeParam('catalog')
            # print('Optimizing params:')
            # tr.printThawedParams()

            for step in range(50):
                dlnp, x, alpha = tr.optimize(**optargs)
                #print('dlnp', dlnp)
                #print('src', src)
                #print('psf', psf)
                if dlnp == 0:
                    break

            fwhms.append(psf.sigmas[0] * 2.35 * pixsc)

            if doplot:
                mod1 = tr.getModelImage(0)
                chi1 = tr.getChiImage(0)

                plt.clf()
                plt.subplot(2, 2, 1)
                plt.title('Image')
                dimshow(pix, **self.imgkwa)
                plt.subplot(2, 2, 2)
                plt.title('Initial model')
                dimshow(mod0, **self.imgkwa)
                plt.subplot(2, 2, 3)
                plt.title('Final model')
                dimshow(mod1, **self.imgkwa)
                plt.subplot(2, 2, 4)
                plt.title('Final chi')
                dimshow(chi1, vmin=-10, vmax=10)
                plt.suptitle('PSF fit')
                ps.savefig()

        fwhms = np.array(fwhms)
        fwhm = np.median(fwhms)
        print('Median FWHM: %.3f' % np.median(fwhms))
        meas.update(seeing=fwhm)

        if False and ps is not None:
            lo, hi = np.percentile(fwhms, [5, 95])
            lo -= 0.1
            hi += 0.1
            plt.clf()
            plt.hist(fwhms, 25, range=(lo, hi), histtype='step', color='b')
            plt.xlabel('FWHM (arcsec)')
            ps.savefig()

        if ps is not None:
            plt.clf()
            for i, (xi, yi) in enumerate(zip(fx[J], fy[J])[:50]):
                ix = int(np.round(xi))
                iy = int(np.round(yi))
                xlo = max(0, ix - psf_r)
                xhi = min(W, ix + psf_r + 1)
                ylo = max(0, iy - psf_r)
                yhi = min(H, iy + psf_r + 1)
                pix = img[ylo:yhi, xlo:xhi]

                slc = pix[iy - ylo, :].copy()
                slc /= np.sum(slc)
                p1 = plt.plot(slc, 'b-', alpha=0.2)
                slc = pix[:, ix - xlo].copy()
                slc /= np.sum(slc)
                p2 = plt.plot(slc, 'r-', alpha=0.2)
                ph, pw = pix.shape
                cx, cy = pw / 2, ph / 2
                if i == 0:
                    xx = np.linspace(0, pw, 300)
                    dx = xx[1] - xx[0]
                    sig = fwhm / pixsc / 2.35
                    yy = np.exp(-0.5 * (xx - cx)**2 / sig**2)  # * np.sum(pix)
                    yy /= (np.sum(yy) * dx)
                    p3 = plt.plot(xx, yy, 'k-', zorder=20)
            #plt.ylim(-0.2, 1.0)
            plt.legend([p1[0], p2[0], p3[0]],
                       ['image slice (y)', 'image slice (x)', 'fit'])
            plt.title('PSF fit')
            ps.savefig()

        return meas
Esempio n. 9
0
if __name__ == '__main__':
    expnum, ccdname = 292604, 'N4'
    
    survey = LegacySurveyData(output_dir='onechip-civ')
    ccds = survey.find_ccds(expnum=expnum, ccdname=ccdname)
    print('Found', len(ccds), 'CCD')
    # HACK -- cut to JUST that ccd.
    survey.ccds = ccds

    ccd = ccds[0]
    im = survey.get_image_object(ccd)
    wcs = survey.get_approx_wcs(ccd)
    rc,dc = wcs.radec_center()

    # Read PS-1 catalog to find out which blobs to process.
    ps1 = ps1cat(ccdwcs=wcs)
    stars = ps1.get_stars()
    print('Read', len(stars), 'PS1 stars')

    brickname = ('custom-%06i%s%05i' %
                 (int(1000*rc), 'm' if dc < 0 else 'p', int(1000*np.abs(dc))))

    outfn = survey.find_file('tractor', brick=brickname, output=True)
    print('Output catalog:', outfn)

    if not os.path.exists(outfn):
        run_brick(None, survey, radec=(rc,dc),
                  width=ccd.height, height=ccd.width,    # CCDs are rotated
                  bands=im.band,
                  wise=False,
                  blobradec=zip(stars.ra, stars.dec),