Exemplo n.º 1
0
def check_results(fns, tag):
    def get_field(ds, col):
        return ds.evaluate(ds[col.upper()])

    rr = []
    dd = []
    for fn in fns:
        df = pd.read_hdf(fn, key='data')
        ds = vaex.from_pandas(df)
        print(len(ds), 'rows')
        ra = get_field(ds, 'ra')
        dec = get_field(ds, 'dec')
        rr.append(ra)
        dd.append(dec)
    rr = np.hstack(rr)
    dd = np.hstack(dd)
    print('Total of', len(rr), 'stars')

    T = fits_table()
    T.ra = rr
    T.dec = dd
    T.writeto('all-rd-%s.fits' % tag)

    plothist(rr, dd, 500)
    plt.xlabel('RA (deg)')
    plt.ylabel('Dec (deg)')
    plt.savefig('all-radec-%s.png' % tag)

    I, J, d = match_radec(rr, dd, rr, dd, 0.2 / 3600, notself=True)
    plt.clf()
    plt.hist(d * 3600. * 1000., bins=50)
    plt.xlabel('Distance between stars (milli-arcsec)')
    plt.savefig('all-dists-%s.png' % tag)
def showSipSolutions(srcs, wcs0, andDir, x0, y0, W, H, filterName, plotPrefix):
    '''
    srcs: afw Catalog of sources
    wcs0: original WCS
    andDir: astrometry_net_data directory
    '''
    imargs = dict(imageSize=(W, H), filterName=filterName, x0=x0, y0=y0)

    # Set up astrometry_net_data
    os.environ['ASTROMETRY_NET_DATA_DIR'] = andDir
    andConfig = measAstrom.AstrometryNetDataConfig()
    fn = os.path.join(andDir, 'andConfig.py')
    andConfig.load(fn)

    # Set up meas_astrom
    conf = measAstrom.ANetBasicAstrometryConfig(sipOrder=4)
    ast = measAstrom.ANetBasicAstrometryTask(conf,
                                             andConfig,
                                             logLevel=Log.DEBUG)

    # What reference sources are in the original WCS
    refs = ast.getReferenceSourcesForWcs(wcs0, **imargs)
    print('Got', len(refs), 'reference objects for initial WCS')

    # How does a straight TAN solution look?
    conf2 = measAstrom.ANetBasicAstrometryConfig(sipOrder=4,
                                                 calculateSip=False)
    ast2 = measAstrom.ANetBasicAstrometryTask(conf2,
                                              andConfig,
                                              logLevel=Log.DEBUG)
    solve = ast2.determineWcs2(srcs, **imargs)
    tanwcs = solve.tanWcs

    # How about if we fit a SIP WCS using the *original* WCS?
    wcs2 = ast.getSipWcsFromWcs(wcs0, (W, H), x0=x0, y0=y0)

    # (We determineWcs() for a SIP solution below...)

    # Make some plots in pixel space by pushing ref sources through WCSes
    rx0, ry0 = [], []
    rx2, ry2 = [], []
    rx3, ry3 = [], []
    for src in refs:
        xy = wcs0.skyToPixel(src.getCoord())
        rx0.append(xy[0])
        ry0.append(xy[1])

        xy = tanwcs.skyToPixel(src.getCoord())
        rx2.append(xy[0])
        ry2.append(xy[1])

        xy = wcs2.skyToPixel(src.getCoord())
        rx3.append(xy[0])
        ry3.append(xy[1])

    rx0 = np.array(rx0)
    ry0 = np.array(ry0)
    rx2 = np.array(rx2)
    ry2 = np.array(ry2)
    rx3 = np.array(rx3)
    ry3 = np.array(ry3)

    x = np.array([src.getX() for src in srcs])
    y = np.array([src.getY() for src in srcs])

    from astrometry.libkd.spherematch import match
    from astrometry.util.plotutils import plothist, PlotSequence

    ps = PlotSequence(plotPrefix)

    # Match up various sources...
    R = 2.

    II, d = match(np.vstack((x, y)).T, np.vstack((rx0, ry0)).T, R)
    I = II[:, 0]
    J = II[:, 1]

    pa = dict(range=((-R, R), (-R, R)))

    plt.clf()
    plothist(x[I] - rx0[J], y[I] - ry0[J], 200, **pa)
    plt.title('Source positions - Reference positions (initial WCS)')
    plt.xlabel('delta-X (pixels)')
    plt.ylabel('delta-Y (pixels)')
    ps.savefig()

    II, d = match(np.vstack((x, y)).T, np.vstack((rx2, ry2)).T, R)
    I = II[:, 0]
    J = II[:, 1]

    plt.clf()
    plothist(x[I] - rx2[J], y[I] - ry2[J], 200, **pa)
    plt.title('Source positions - Reference positions (TAN WCS)')
    plt.xlabel('delta-X (pixels)')
    plt.ylabel('delta-Y (pixels)')
    ps.savefig()

    II, d = match(np.vstack((x, y)).T, np.vstack((rx3, ry3)).T, R)
    I = II[:, 0]
    J = II[:, 1]
    plt.clf()
    plothist(x[I] - rx3[J], y[I] - ry3[J], 200, **pa)
    plt.title('Source positions - Reference positions (SIP WCS #2)')
    plt.xlabel('delta-X (pixels)')
    plt.ylabel('delta-Y (pixels)')
    ps.savefig()

    II, d = match(np.vstack((rx0, ry0)).T, np.vstack((rx3, ry3)).T, R)
    I = II[:, 0]
    J = II[:, 1]
    plt.clf()
    plothist(rx0[I] - rx3[J], ry0[I] - ry3[J], 200, **pa)
    plt.title(
        'Reference positions (Original WCS) - Reference positions (SIP WCS #2)'
    )
    plt.xlabel('delta-X (pixels)')
    plt.ylabel('delta-Y (pixels)')
    ps.savefig()

    matches = solve.tanMatches
    msx, msy = [], []
    mrx, mry = [], []
    for m in matches:
        ref, src = m.first, m.second
        xy = tanwcs.skyToPixel(ref.getCoord())
        mrx.append(xy[0])
        mry.append(xy[1])
        msx.append(src.getX())
        msy.append(src.getY())

    plt.clf()
    plt.plot(x, y, 'r.')
    plt.plot(msx, msy, 'o', mec='r')
    plt.plot(rx0, ry0, 'g.')
    plt.plot(mrx, mry, 'gx')
    plt.title('TAN matches')
    ps.savefig()

    # Get SIP solution (4th order)

    solve = ast.determineWcs2(srcs, **imargs)
    wcs1 = solve.sipWcs

    matches = solve.sipMatches
    msx, msy = [], []
    mrx, mry = [], []
    for m in matches:
        ref, src = m.first, m.second
        xy = tanwcs.skyToPixel(ref.getCoord())
        mrx.append(xy[0])
        mry.append(xy[1])
        msx.append(src.getX())
        msy.append(src.getY())

    plt.clf()
    plt.plot(x, y, 'r.')
    plt.plot(msx, msy, 'o', mec='r')
    plt.plot(rx0, ry0, 'g.')
    plt.plot(mrx, mry, 'gx')
    plt.title('SIP matches')
    ps.savefig()

    rx1, ry1 = [], []
    for src in refs:
        xy = wcs1.skyToPixel(src.getCoord())
        rx1.append(xy[0])
        ry1.append(xy[1])
    rx1 = np.array(rx1)
    ry1 = np.array(ry1)

    plt.clf()
    plt.plot(x, y, 'o', mec='r', mfc='none')
    plt.plot(rx0, ry0, 'bx')
    plt.plot(rx1, ry1, 'g+')
    plt.plot(rx2, ry2, 'mx')
    plt.plot(rx3, ry3, 'r+')
    ps.savefig()

    plt.axis([x0, x0 + 500, y0, y0 + 500])
    ps.savefig()

    II, d = match(np.vstack((x, y)).T, np.vstack((rx1, ry1)).T, R)
    I = II[:, 0]
    J = II[:, 1]

    plt.clf()
    plothist(x[I] - rx1[J], y[I] - ry1[J], 200, **pa)
    plt.title('Source positions - Reference positions (SIP WCS)')
    plt.xlabel('delta-X (pixels)')
    plt.ylabel('delta-Y (pixels)')
    ps.savefig()
Exemplo n.º 3
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
Exemplo n.º 4
0
def find_alignments(fns, wcsfns, gaia_fn, aff_fn, aligned_fn):
    from astrometry.libkd.spherematch import tree_build_radec, trees_match
    from astrometry.libkd.spherematch import match_radec
    from astrometry.util.plotutils import plothist
    from astrometry.util.util import Tan
    import fitsio

    from astrom_common import getwcsoutline
    from singles import find_overlaps

    if True:
        WCS = []
        for fn in wcsfns:
            wcs = Tan(fn)
            WCS.append(wcs)

    names = [fn.replace('-bright.fits', '') for fn in fns]

    outlines = [getwcsoutline(wcs) for wcs in WCS]

    overlaps, areas = find_overlaps(outlines)

    print('Reading tables...')
    TT = [fits_table(fn) for fn in fns]
    print('Building trees...')
    kds = [tree_build_radec(T.ra, T.dec) for T in TT]

    for T, name in zip(TT, names):
        T.name = np.array([name] * len(T))

    allra = np.hstack([T.ra for T in TT])
    alldec = np.hstack([T.dec for T in TT])
    minra = np.min(allra)
    maxra = np.max(allra)
    mindec = np.min(alldec)
    maxdec = np.max(alldec)

    print('RA,Dec range:', minra, maxra, mindec, maxdec)

    plothist(allra, alldec)
    plt.axis([maxra, minra, mindec, maxdec])
    plt.xlabel('RA (deg)')
    plt.ylabel('Dec (deg)')
    plt.savefig('match-all.png')

    Tref = fits_table(gaia_fn)
    r_arcsec = 0.2
    I, J, d = match_radec(Tref.ra, Tref.dec, allra, alldec, r_arcsec / 3600.)
    dec = alldec[J]
    cosdec = np.cos(np.deg2rad(dec))
    dr = (Tref.ra[I] - allra[J]) * cosdec * 3600.
    dd = (Tref.dec[I] - alldec[J]) * 3600.
    plt.clf()
    rr = (-r_arcsec * 1000, +r_arcsec * 1000)
    plothist(dr * 1000., dd * 1000., nbins=100, range=(rr, rr))
    plt.xlabel('dRA (milli-arcsec)')
    plt.ylabel('dDec (milli-arcsec)')
    plt.savefig('match-all-ref-before.png')

    # Initial matching of all stars
    r_arcsec = 0.2
    I, J, d = match_radec(allra,
                          alldec,
                          allra,
                          alldec,
                          r_arcsec / 3600.,
                          notself=True)
    dec = alldec[I]
    cosdec = np.cos(np.deg2rad(dec))
    dr = (allra[I] - allra[J]) * cosdec * 3600.
    dd = (alldec[I] - alldec[J]) * 3600.

    plt.clf()
    rr = (-r_arcsec * 1000, +r_arcsec * 1000)
    plothist(dr * 1000., dd * 1000., nbins=100, range=(rr, rr))
    plt.xlabel('dRA (milli-arcsec)')
    plt.ylabel('dDec (milli-arcsec)')
    plt.savefig('match-all-before.png')

    hulls = []
    from scipy.spatial import ConvexHull
    for T in TT:
        hull = ConvexHull(np.vstack((T.ra, T.dec)).T)
        ra = T.ra[hull.vertices]
        ra = np.append(ra, ra[0])
        dec = T.dec[hull.vertices]
        dec = np.append(dec, dec[0])
        hulls.append((ra, dec))

    aligns = {}

    #for i in []:
    for i in range(len(kds)):
        for j in range(i + 1, len(kds)):
            print('Matching trees', i, 'and', j)

            r_arcsec = 0.2
            radius = np.deg2rad(r_arcsec / 3600)

            I, J, d2 = trees_match(kds[i], kds[j], radius)
            print(len(I), 'matches')
            if len(I) == 0:
                continue

            Ti = TT[i]
            Tj = TT[j]
            dec = Ti[I].dec
            cosdec = np.cos(np.deg2rad(dec))
            dr = (Ti[I].ra - Tj[J].ra) * cosdec * 3600.
            dd = (Ti[I].dec - Tj[J].dec) * 3600.

            if False:
                al = Alignment(Ti, Tj, searchradius=r_arcsec)
                print('Aligning...')
                if not al.shift():
                    print('Failed to find Alignment between fields')
                    continue
                aligns[(i, j)] = al

                plt.clf()
                plotalignment(al)
                plt.savefig('match-align-%02i-%02i.png' % (i, j))

            plt.clf()
            #plothist(np.append(Ti.ra, Tj.ra), np.append(Ti.dec, Tj.dec), docolorbar=False, doclf=False, dohot=False,
            #         imshowargs=dict(cmap=antigray))
            plothist(Ti.ra[I], Ti.dec[I], docolorbar=False, doclf=False)
            r, d = hulls[i]
            plt.plot(r, d, 'r-')
            r, d = hulls[j]
            plt.plot(r, d, 'b-')
            mra = Ti.ra[I]
            mdec = Ti.dec[I]
            mnra = np.min(mra)
            mxra = np.max(mra)
            mndec = np.min(mdec)
            mxdec = np.max(mdec)
            plt.plot([mnra, mnra, mxra, mxra, mnra],
                     [mndec, mxdec, mxdec, mndec, mndec], 'g-')

            plt.axis([maxra, minra, mindec, maxdec])
            plt.xlabel('RA (deg)')
            plt.ylabel('Dec (deg)')
            plt.savefig('match-radec-%02i-%02i.png' % (i, j))

            plt.clf()
            rr = (-r_arcsec, +r_arcsec)
            plothist(dr, dd, nbins=100, range=(rr, rr))
            plt.xlabel('dRA (arcsec)')
            plt.ylabel('dDec (arcsec)')
            plt.savefig('match-dradec-%02i-%02i.png' % (i, j))

    #for roundi,(Nk,R) in enumerate(NkeepRads):

    refrad = 0.15
    targetrad = 0.005

    ps = PlotSequence('shift')

    from astrom_intra import intrabrickshift
    from singles import plot_all_alignments

    #Rads = [0.25, 0.1]
    Rads = [0.2, 0.050, 0.020]
    #Rads = [0.1]
    affs = None
    # this is the reference point around which rotations take place, NOT reference catalog stars.
    refrd = None
    for roundi, R in enumerate(Rads):

        if roundi > 0:
            refrad = 0.050

        TT1 = TT

        nb = int(np.ceil(R / targetrad))
        nb = max(nb, 5)
        if nb % 2 == 0:
            nb += 1
        print('Round', roundi + 1, ': matching with radius', R)
        print('Nbins:', nb)

        # kwargs to pass to intrabrickshift
        ikwargs = {}
        minoverlap = 0.01
        tryoverlaps = (overlaps > minoverlap)
        ikwargs.update(
            do_affine=True,  #mp=mp,
            #alignplotargs=dict(bins=25),
            alignplotargs=dict(bins=50),
            overlaps=tryoverlaps)

        ikwargs.update(ref=Tref, refrad=refrad)

        # kwargs to pass to Alignment
        akwargs = {}

        i1 = intrabrickshift(TT1,
                             matchradius=R,
                             refradecs=refrd,
                             align_kwargs=dict(histbins=nb, **akwargs),
                             **ikwargs)

        refrd = i1.get_reference_radecs()

        filts = ['' for n in names]
        ap = i1.alplotgrid
        Nk = 100000
        plot_all_alignments(ap, R * 1000, refrad * 1000, roundi + 1, names,
                            filts, ps, overlaps, outlines, Nk)
        for T, aff in zip(TT, i1.affines):
            T.ra, T.dec = aff.apply(T.ra, T.dec)

        if affs is None:
            affs = i1.affines
        else:
            for a, a2 in zip(affs, i1.affines):
                a.add(a2)

    from astrom_common import Affine
    T = Affine.toTable(affs)
    T.filenames = fns
    #T.flt = fltfns
    #T.gst = gstfns
    #T.chip = chips

    # FAKE -- used as a name in alignment_plots
    T.gst = np.array([n + '.gst.fits' for n in names])

    T.writeto(aff_fn)

    # Final matching of all stars
    allra = np.hstack([T.ra for T in TT])
    alldec = np.hstack([T.dec for T in TT])

    r_arcsec = 0.2
    I, J, d = match_radec(allra,
                          alldec,
                          allra,
                          alldec,
                          r_arcsec / 3600.,
                          notself=True)
    dec = alldec[I]
    cosdec = np.cos(np.deg2rad(dec))
    dr = (allra[I] - allra[J]) * cosdec * 3600.
    dd = (alldec[I] - alldec[J]) * 3600.

    plt.clf()
    rr = (-r_arcsec * 1000, +r_arcsec * 1000)
    plothist(dr * 1000., dd * 1000., nbins=100, range=(rr, rr))
    plt.xlabel('dRA (milli-arcsec)')
    plt.ylabel('dDec (milli-arcsec)')
    plt.savefig('match-all-after.png')

    I, J, d = match_radec(Tref.ra, Tref.dec, allra, alldec, r_arcsec / 3600.)
    dec = alldec[J]
    cosdec = np.cos(np.deg2rad(dec))
    dr = (Tref.ra[I] - allra[J]) * cosdec * 3600.
    dd = (Tref.dec[I] - alldec[J]) * 3600.
    plt.clf()
    rr = (-r_arcsec * 1000, +r_arcsec * 1000)
    plothist(dr * 1000., dd * 1000., nbins=100, range=(rr, rr))
    plt.xlabel('dRA (milli-arcsec)')
    plt.ylabel('dDec (milli-arcsec)')
    plt.savefig('match-all-ref-after.png')

    r_arcsec = 0.02
    I, J, d = match_radec(allra,
                          alldec,
                          allra,
                          alldec,
                          r_arcsec / 3600.,
                          notself=True)
    dec = alldec[I]
    cosdec = np.cos(np.deg2rad(dec))
    dr = (allra[I] - allra[J]) * cosdec * 3600.
    dd = (alldec[I] - alldec[J]) * 3600.
    plt.clf()
    rr = (-r_arcsec * 1000, +r_arcsec * 1000)
    plothist(dr * 1000., dd * 1000., nbins=100, range=(rr, rr))
    plt.xlabel('dRA (milli-arcsec)')
    plt.ylabel('dDec (milli-arcsec)')
    plt.savefig('match-all-after2.png')

    T = fits_table()
    T.ra = allra
    T.dec = alldec
    for col in [
            'f814w_vega', 'f475w_vega', 'f336w_vega', 'f275w_vega',
            'f110w_vega', 'f160w_vega', 'name'
    ]:
        T.set(col, np.hstack([t.get(col) for t in TT]))
    T.writeto(aligned_fn)

    if False:
        from singles import alignment_plots

        dataset = 'M31'
        Nkeep = 100000
        R = 0.1
        minoverlap = 0.01
        perfield = False
        nocache = True

        from astrometry.util.multiproc import multiproc
        mp = multiproc()

        filts = ['F475W' for n in names]
        chips = [-1] * len(names)
        exptimes = [1] * len(names)
        Nall = [0] * len(names)
        rd = (minra, maxra, mindec, maxdec)
        cnames = names
        meta = (chips, names, cnames, filts, exptimes, Nall, rd)

        alignment_plots(afffn,
                        dataset,
                        Nkeep,
                        0,
                        R,
                        minoverlap,
                        perfield,
                        nocache,
                        mp,
                        0,
                        tables=(TT, outlines, meta),
                        lexsort=False)