Exemple #1
0
def galex_tractor_image(tile, band, galex_dir, radecbox, bandname):
    from tractor import (NanoMaggies, Image, LinearPhotoCal,
                         ConstantFitsWcs, ConstantSky)

    assert(band in ['n','f'])

    #nicegbands = ['NUV', 'FUV']
    #zps = dict(n=20.08, f=18.82)
    #zp = zps[band]
    
    imfn = os.path.join(galex_dir, tile.tilename.strip(),
                        '%s-%sd-intbgsub.fits.gz' % (tile.visitname.strip(), band))
    gwcs = Tan(*[float(f) for f in
                 [tile.crval1, tile.crval2, tile.crpix1, tile.crpix2,
                  tile.cdelt1, 0., 0., tile.cdelt2, 3840., 3840.]])
    (r0,r1,d0,d1) = radecbox
    H,W = gwcs.shape
    ok,xx,yy = gwcs.radec2pixelxy([r0,r0,r1,r1], [d0,d1,d1,d0])
    #print('GALEX WCS pixel positions of RA,Dec box:', xx, yy)
    if np.any(np.logical_not(ok)):
        return None
    x0 = np.clip(np.floor(xx-1).astype(int).min(), 0, W-1)
    x1 = np.clip(np.ceil (xx-1).astype(int).max(), 0, W)
    if x1-x0 <= 1:
        return None
    y0 = np.clip(np.floor(yy-1).astype(int).min(), 0, H-1)
    y1 = np.clip(np.ceil (yy-1).astype(int).max(), 0, H)
    if y1-y0 <= 1:
        return None
    debug('Reading GALEX subimage x0,y0', x0,y0, 'size', x1-x0, y1-y0)
    gwcs = gwcs.get_subimage(x0, y0, x1 - x0, y1 - y0)
    twcs = ConstantFitsWcs(gwcs)
    roislice = (slice(y0, y1), slice(x0, x1))
    
    fitsimg = fitsio.FITS(imfn)[0]
    hdr = fitsimg.read_header()
    img = fitsimg[roislice]

    inverr = np.ones_like(img)
    inverr[img == 0.] = 0.

    zp = tile.get('%s_zpmag' % band)
    
    photocal = LinearPhotoCal(NanoMaggies.zeropointToScale(zp), band=bandname)

    tsky = ConstantSky(0.)

    name = 'GALEX ' + hdr['OBJECT'] + ' ' + band

    psfimg = galex_psf(band, galex_dir)
    tpsf = PixelizedPSF(psfimg)

    tim = Image(data=img, inverr=inverr, psf=tpsf, wcs=twcs,
                sky=tsky, photocal=photocal, name=name)
    tim.roi = [x0,x1,y0,y1]
    return tim
Exemple #2
0
tractors = []

stars.x0 = stars.ix - margin
stars.y0 = stars.iy - margin

plt.clf()
for i,s in enumerate(stars):

    #x0,y0 = s.ix - margin, s.iy - margin
    x0,y0 = s.x0, s.y0
    slc = (slice(y0, s.iy + margin+1),
           slice(x0, s.ix + margin+1))
    subpsf = tim.psf.constantPsfAt(s.ix, s.iy)
    
    subtim = Image(data=tim.data[slc],
                   inverr=tim.inverr[slc],
                   psf=subpsf, photocal=tim.photocal,
                   name=tim.name + '/star %i' % i)

    flux = NanoMaggies.magToNanomaggies(s.mag)
    print 'Flux:', flux
    flux = max(flux, 1.)
    src = PointSource(PixPos(s.xx - x0, s.yy - y0),
                      NanoMaggies(**{tim.band: flux}))

    tr = Tractor([subtim], [src])
    mod = tr.getModelImage(0)
    #mod = src.getModelImage(tsubtim)
    tractors.append(tr)
    
    resids.append((subtim.data - mod) * (subtim.inverr > 0))
    chis.append((subtim.data - mod) * subtim.inverr)
Exemple #3
0
def main():
    # Where are the data?
    datadir = os.path.join(os.path.dirname(__file__), 'data-decam')
    name = 'decam-520206-S16'
    imagefn = os.path.join(datadir, '%s-image-sub.fits' % name)
    invvarfn = os.path.join(datadir, '%s-invvar-sub.fits' % name)
    psfexfn = os.path.join(datadir, '%s-psfex.fits' % name)
    catfn = os.path.join(datadir, 'tractor-1816p325-sub.fits')

    # Read the image and inverse-variance maps.
    image = fitsio.read(imagefn)
    invvar = fitsio.read(invvarfn)
    # The DECam inverse-variance maps are unfortunately corrupted
    # by fpack, causing zeros to become negative.  Fix those.
    invvar[invvar < np.median(invvar) * 0.1] = 0.
    H, W = image.shape
    print('Subimage size:', image.shape)

    # For the PSF model, we need to know what subimage region this is:
    subimage_offset = (35, 1465)
    # We also need the calibrated zeropoint.
    zeropoint = 24.7787

    # What filter was this image taken in?  (z)
    prim_header = fitsio.read_header(imagefn)
    band = prim_header['FILTER'].strip()[0]
    print('Band:', band)
    # These DECam images were calibrated so that the zeropoints need
    # an exposure-time factor, so add that in.
    exptime = prim_header['EXPTIME']
    zeropoint += 2.5 * np.log10(exptime)

    # Read the PsfEx model file
    psf = PixelizedPsfEx(psfexfn)
    # Instantiate a constant pixelized PSF at the image center
    # (of the subimage)
    x0, y0 = subimage_offset
    psf = psf.constantPsfAt(x0 + W / 2., y0 + H / 2.)

    # Load the WCS model from the header
    # We convert from the RA---TPV type to RA---SIP
    header = fitsio.read_header(imagefn, ext=1)
    wcsobj = wcs_pv2sip_hdr(header, stepsize=10)

    # We'll just use a rough sky estimate...
    skyval = np.median(image)

    # Create the Tractor Image (tim).
    tim = Image(data=image,
                invvar=invvar,
                psf=psf,
                wcs=ConstantFitsWcs(wcsobj),
                sky=ConstantSky(skyval),
                photocal=LinearPhotoCal(
                    NanoMaggies.zeropointToScale(zeropoint), band=band))

    # Read the official DECaLS DR3 catalog -- it has only two sources in this subimage.
    catalog = fits_table(catfn)
    print('Read', len(catalog), 'sources')
    print('Source types:', catalog.type)

    # Create Tractor sources corresponding to these two catalog
    # entries.

    # In DECaLS, the "SIMP" type is a round Exponential galaxy with a
    # fixed 0.45" radius, but we'll treat it as a general Exp galaxy.

    sources = []
    for c in catalog:
        # Create a "position" object given the catalog RA,Dec
        position = RaDecPos(c.ra, c.dec)
        # Create a "brightness" object; in the catalog, the fluxes are
        # stored in a [ugrizY] array, so pull out the right index
        band_index = 'ugrizY'.index(band)
        flux = c.decam_flux[band_index]
        brightness = NanoMaggies(**{band: flux})

        # Depending on the source classification in the catalog, pull
        # out different fields for the galaxy shape, and for the
        # galaxy type.  The DECaLS catalogs, conveniently, store
        # galaxy shapes as (radius, e1, e2) ellipses.
        if c.type.strip() == 'DEV':
            shape = EllipseE(c.shapedev_r, c.shapedev_e1, c.shapedev_e2)
            galclass = DevGalaxy
        elif c.type.strip() == 'SIMP':
            shape = EllipseE(c.shapeexp_r, c.shapeexp_e1, c.shapeexp_e2)
            galclass = ExpGalaxy
        else:
            assert (False)
        # Create the tractor galaxy object
        source = galclass(position, brightness, shape)
        print('Created', source)
        sources.append(source)

    # Create the Tractor object -- a list of tractor Images and a list of tractor sources.
    tractor = Tractor([tim], sources)

    # Render the initial model image.
    print('Getting initial model...')
    mod = tractor.getModelImage(0)
    make_plot(tim, mod, 'Initial Scene', 'mod0.png')

    # Instantiate a new source at the location of the unmodelled peak.
    print('Adding new source...')
    # Find the peak very naively...
    ipeak = np.argmax((image - mod) * tim.inverr)
    iy, ix = np.unravel_index(ipeak, tim.shape)
    print('Residual peak at', ix, iy)
    # Compute the RA,Dec location of the peak...
    radec = tim.getWcs().pixelToPosition(ix, iy)
    print('RA,Dec', radec)

    # Try modelling it as a point source.
    # We'll initialize the brightness arbitrarily to 1 nanomaggy (= mag 22.5)
    brightness = NanoMaggies(**{band: 1.})
    source = PointSource(radec, brightness)

    # Add it to the catalog!
    tractor.catalog.append(source)

    # Render the new model image with this source added.
    mod = tractor.getModelImage(0)
    make_plot(tim, mod, 'New Source (Before Fit)', 'mod1.png')

    print('Fitting new source...')
    # Now we're going to fit for the properties of the new source we
    # added.
    # We don't want to fit for any of the image calibration properties:
    tractor.freezeParam('images')
    # And we don't (yet) want to fit the existing sources.  The new
    # source is index number 2, so freeze everything else in the catalog.
    tractor.catalog.freezeAllBut(2)

    print('Fitting parameters:')
    tractor.printThawedParams()

    # Do the actual optimization:
    tractor.optimize_loop()

    mod = tractor.getModelImage(0)
    make_plot(tim, mod, 'New Source Fit', 'mod2.png')

    print('Fitting sources simultaneously...')
    # Now let's unfreeze all the sources and fit them simultaneously.
    tractor.catalog.thawAllParams()
    tractor.printThawedParams()

    tractor.optimize_loop()

    mod = tractor.getModelImage(0)
    make_plot(tim, mod, 'Simultaneous Fit', 'mod3.png')
def scan_dchisq(seeing, target_dchisq, ps, e1=0.):
    pixscale = 0.262
    psfsigma = seeing / pixscale / 2.35
    print('PSF sigma:', psfsigma, 'pixels')
    psf = GaussianMixturePSF(1., 0., 0., psfsigma**2, psfsigma**2, 0.)

    sig1 = 0.01
    psfnorm = 1./(2. * np.sqrt(np.pi) * psfsigma)
    detsig1 = sig1 / psfnorm

    sz = 50
    cd = pixscale / 3600.
    wcs = Tan(0., 0., float(sz/2), float(sz/2), -cd, 0., 0., cd,
              float(sz), float(sz))
    band = 'r'

    tim = Image(data=np.zeros((sz,sz)), inverr=np.ones((sz,sz)) / sig1,
                psf=psf,
                wcs = ConstantFitsWcs(wcs),
                photocal = LinearPhotoCal(1., band=band))
    
    re_vals = np.logspace(-1., 0., 50)
    
    all_runs = []

    mods = []
    
    for i,re in enumerate(re_vals):
        true_src = ExpGalaxy(RaDecPos(0., 0.),
                             NanoMaggies(**{band: 1.}),
                             EllipseE(re, e1, 0.))
        print('True source:', true_src)
        tr = Tractor([tim], [true_src])
        tr.freezeParams('images')
        true_mod = tr.getModelImage(0)

        dchisq_none = np.sum((true_mod * tim.inverr)**2)
        scale = np.sqrt(target_dchisq / dchisq_none)

        true_src.brightness.setParams([scale])

        true_mod = tr.getModelImage(0)
        dchisq_none = np.sum((true_mod * tim.inverr)**2)

        mods.append(true_mod)
        
        tim.data = true_mod
        
        exp_src = true_src.copy()
        psf_src = PointSource(true_src.pos.copy(), true_src.brightness.copy())
        simp_src = SimpleGalaxy(true_src.pos.copy(), true_src.brightness.copy())

        dchisqs = []
        #for src in [psf_src, simp_src, exp_src]:
        for src in [psf_src, simp_src]:
            src.freezeParam('pos')
            #print('Fitting source:', src)
            #src.printThawedParams()
            tr.catalog[0] = src
            tr.optimize_loop()
            #print('Fitted:', src)
            mod = tr.getModelImage(0)
            dchisqs.append(dchisq_none - np.sum(((true_mod - mod) * tim.inverr)**2))
            #print('dchisq:', dchisqs[-1])
        dchisqs.append(dchisq_none)
        
        all_runs.append([re,] + dchisqs)

    all_runs = np.array(all_runs)

    re = all_runs[:,0]
    dchi_psf  = all_runs[:,1]
    dchi_simp = all_runs[:,2]
    dchi_exp  = all_runs[:,3]

    dchi_ps = np.maximum(dchi_psf, dchi_simp)
    dchi_cut1 = dchi_ps + 3+9
    dchi_cut2 = dchi_ps + dchi_psf * 0.02
    dchi_cut3 = dchi_ps + dchi_psf * 0.008
    
    plt.clf()
    plt.plot(re, dchi_psf, 'k-', label='PSF')
    plt.plot(re, dchi_simp, 'b-', label='SIMP')
    plt.plot(re, dchi_exp, 'r-', label='EXP')

    plt.plot(re, dchi_cut2, 'm--', alpha=0.5, lw=2, label='Cut: 2%')
    plt.plot(re, dchi_cut3, 'm:',  alpha=0.5, lw=2, label='Cut: 0.08%')
    plt.plot(re, dchi_cut1, 'm-',  alpha=0.5, lw=2, label='Cut: 12')

    plt.xlabel('True r_e (arcsec)')
    plt.ylabel('dchisq')
    #plt.legend(loc='lower left')
    plt.legend(loc='upper right')
    tt = 'Seeing = %g arcsec, S/N ~ %i' % (seeing, int(np.round(np.sqrt(target_dchisq))))
    if e1 != 0.:
        tt += ', Ellipticity %g' % e1
    plt.title(tt)
    plt.ylim(0.90 * target_dchisq, 1.05 * target_dchisq)

    # aspect = 1.2
    # ax = plt.axis()
    # dre  = (ax[1]-ax[0]) / 20 / aspect
    # dchi = (ax[3]-ax[2]) / 20
    # I = np.linspace(0, len(re_vals)-1, 8).astype(int)
    # for mod,re in [(mods[i], re_vals[i]) for i in I]:
    #     print('extent:', [re-dre, re+dre, ax[2], ax[2]+dchi])
    #     plt.imshow(mod, interpolation='nearest', origin='lower', aspect='auto',
    #                extent=[re-dre, re+dre, ax[2], ax[2]+dchi], cmap='gray')
    # plt.axis(ax)
        
    ps.savefig()
    Nother= np.zeros_like(Nexp)

    np.random.seed(42)

    sz = 50
    cd = pixscale / 3600.
    wcs = Tan(0., 0., float(sz/2), float(sz/2), -cd, 0., 0., cd,
              float(sz), float(sz))
    band = 'r'

    #all_dchisqs = []

    all_runs = []

    tim = Image(data=np.zeros((sz,sz)), inverr=np.ones((sz,sz)) / sig1,
                psf=psf,
                wcs = ConstantFitsWcs(wcs),
                photocal = LinearPhotoCal(1., band=band))
    
    for i,sn in enumerate(sn_vals):
        for j,re in enumerate(re_vals):
            ## HACK -- this is the flux required for a PSF to be
            ## detected at target S/N... adjust for galaxy?
            flux = sn * detsig1
            # Create round EXP galaxy
            #PixPos(sz/2, sz/2),
            true_src = ExpGalaxy(RaDecPos(0., 0.),
                                 NanoMaggies(**{band: flux}),
                                 EllipseE(re, 0., 0.))
            
            tr = Tractor([tim], [true_src])
            tr.freezeParams('images')
Exemple #6
0
def rbmain():
    travis = 'travis' in sys.argv

    extra_args = [
        '--old-calibs-ok',
        #'--verbose',
    ]
    if travis:
        extra_args.extend(
            ['--no-wise-ceres', '--no-gaia', '--no-large-galaxies'])

    if 'ceres' in sys.argv:
        surveydir = os.path.join(os.path.dirname(__file__), 'testcase3')
        main(args=[
            '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
            '--no-wise', '--force-all', '--no-write', '--ceres',
            '--survey-dir', surveydir, '--outdir', 'out-testcase3-ceres',
            '--no-depth-cut'
        ])
        sys.exit(0)

    # demo RexGalaxy, with plots
    if False:
        from legacypipe.survey import RexGalaxy
        from tractor import NanoMaggies, PixPos
        from tractor import Image, GaussianMixturePSF, LinearPhotoCal
        from legacypipe.survey import LogRadius
        rex = RexGalaxy(PixPos(1., 2.), NanoMaggies(r=3.), LogRadius(0.))
        print('Rex:', rex)
        print('Rex params:', rex.getParams())
        print('Rex nparams:', rex.numberOfParams())
        H, W = 100, 100
        tim = Image(data=np.zeros((H, W), np.float32),
                    inverr=np.ones((H, W), np.float32),
                    psf=GaussianMixturePSF(1., 0., 0., 4., 4., 0.),
                    photocal=LinearPhotoCal(1., band='r'))
        derivs = rex.getParamDerivatives(tim)
        print('Derivs:', len(derivs))
        print('Rex params:', rex.getParamNames())

        import pylab as plt
        from astrometry.util.plotutils import PlotSequence
        ps = PlotSequence('rex')

        for d, nm in zip(derivs, rex.getParamNames()):
            plt.clf()
            plt.imshow(d.patch, interpolation='nearest', origin='lower')
            plt.title('Derivative %s' % nm)
            ps.savefig()

        sys.exit(0)

    # Test RexGalaxy

    surveydir = os.path.join(os.path.dirname(__file__), 'testcase6')
    outdir = 'out-testcase6-rex'
    main(args=[
        '--brick',
        '1102p240',
        '--zoom',
        '500',
        '600',
        '650',
        '750',
        '--force-all',
        '--no-write',
        '--no-wise',
        #'--rex', #'--plots',
        '--survey-dir',
        surveydir,
        '--outdir',
        outdir
    ] + extra_args)
    fn = os.path.join(outdir, 'tractor', '110', 'tractor-1102p240.fits')
    assert (os.path.exists(fn))
    T = fits_table(fn)
    assert (len(T) == 2)
    print('Types:', T.type)
    # Since there is a Tycho-2 star in the blob, forced to be PSF.
    assert (T.type[0] == 'PSF ')
    cmd = (
        '(cd %s && sha256sum -c %s)' %
        (outdir, os.path.join('tractor', '110', 'brick-1102p240.sha256sum')))
    print(cmd)
    rtn = os.system(cmd)
    assert (rtn == 0)

    # Test with a Tycho-2 star in the blob.

    surveydir = os.path.join(os.path.dirname(__file__), 'testcase6')
    outdir = 'out-testcase6'
    main(args=[
        '--brick', '1102p240', '--zoom', '500', '600', '650', '750',
        '--force-all', '--no-write', '--no-wise', '--survey-dir', surveydir,
        '--outdir', outdir
    ] + extra_args)
    fn = os.path.join(outdir, 'tractor', '110', 'tractor-1102p240.fits')
    assert (os.path.exists(fn))
    T = fits_table(fn)
    assert (len(T) == 2)
    print('Types:', T.type)
    # Since there is a Tycho-2 star in the blob, forced to be PSF.
    assert (T.type[0] == 'PSF ')

    # Test that we can run splinesky calib if required...

    from legacypipe.decam import DecamImage
    DecamImage.splinesky_boxsize = 128

    surveydir = os.path.join(os.path.dirname(__file__), 'testcase4')
    outdir = 'out-testcase4'

    fn = os.path.join(surveydir, 'calib', 'decam', 'splinesky', '00431',
                      '00431608', 'decam-00431608-N3.fits')
    if os.path.exists(fn):
        os.unlink(fn)

    main(args=[
        '--brick', '1867p255', '--zoom', '2050', '2300', '1150', '1400',
        '--force-all', '--no-write', '--coadd-bw', '--unwise-dir',
        os.path.join(surveydir, 'images', 'unwise'), '--unwise-tr-dir',
        os.path.join(surveydir, 'images', 'unwise-tr'), '--blob-image',
        '--no-hybrid-psf', '--survey-dir', surveydir, '--outdir', outdir
    ] + extra_args + ['-v'])
    print('Checking for calib file', fn)
    assert (os.path.exists(fn))

    # Wrap-around, hybrid PSF
    surveydir = os.path.join(os.path.dirname(__file__), 'testcase8')
    outdir = 'out-testcase8'

    main(args=[
        '--brick',
        '1209p050',
        '--zoom',
        '720',
        '1095',
        '3220',
        '3500',
        '--force-all',
        '--no-write',
        '--no-wise',  #'--plots',
        '--survey-dir',
        surveydir,
        '--outdir',
        outdir
    ] + extra_args)

    # Test with a Tycho-2 star + another saturated star in the blob.

    surveydir = os.path.join(os.path.dirname(__file__), 'testcase7')
    outdir = 'out-testcase7'
    # remove --no-gaia
    my_extra_args = [a for a in extra_args if a != '--no-gaia']
    os.environ['GAIA_CAT_DIR'] = os.path.join(surveydir, 'gaia-dr2')
    os.environ['GAIA_CAT_VER'] = '2'
    main(args=[
        '--brick',
        '1102p240',
        '--zoom',
        '250',
        '350',
        '1550',
        '1650',
        '--force-all',
        '--no-write',
        '--no-wise',  #'--plots',
        '--survey-dir',
        surveydir,
        '--outdir',
        outdir
    ] + my_extra_args)
    del os.environ['GAIA_CAT_DIR']
    del os.environ['GAIA_CAT_VER']
    fn = os.path.join(outdir, 'tractor', '110', 'tractor-1102p240.fits')
    assert (os.path.exists(fn))
    T = fits_table(fn)
    assert (len(T) == 4)

    # Check skipping blobs outside the brick's unique area.
    # (this now doesn't detect any sources at all, reasonably)
    # surveydir = os.path.join(os.path.dirname(__file__), 'testcase5')
    # outdir = 'out-testcase5'
    #
    # fn = os.path.join(outdir, 'tractor', '186', 'tractor-1867p255.fits')
    # if os.path.exists(fn):
    #     os.unlink(fn)
    #
    # main(args=['--brick', '1867p255', '--zoom', '0', '150', '0', '150',
    #            '--force-all', '--no-write', '--coadd-bw',
    #            '--survey-dir', surveydir,
    #            '--early-coadds',
    #            '--outdir', outdir] + extra_args)
    #
    # assert(os.path.exists(fn))
    # T = fits_table(fn)
    # assert(len(T) == 1)

    # Custom RA,Dec; blob ra,dec.
    surveydir = os.path.join(os.path.dirname(__file__), 'testcase4')
    outdir = 'out-testcase4b'
    # Catalog written with one entry (--blobradec)
    fn = os.path.join(outdir, 'tractor', 'cus',
                      'tractor-custom-186743p25461.fits')
    if os.path.exists(fn):
        os.unlink(fn)
    main(args=[
        '--radec', '186.743965', '25.461788', '--width', '250', '--height',
        '250', '--force-all', '--no-write', '--no-wise', '--blobradec',
        '186.740369', '25.453855', '--survey-dir', surveydir, '--outdir',
        outdir
    ] + extra_args)

    assert (os.path.exists(fn))
    T = fits_table(fn)
    assert (len(T) == 1)

    surveydir = os.path.join(os.path.dirname(__file__), 'testcase3')
    outdir = 'out-testcase3'
    checkpoint_fn = os.path.join(outdir, 'checkpoint.pickle')
    if os.path.exists(checkpoint_fn):
        os.unlink(checkpoint_fn)
    main(args=[
        '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
        '--no-wise', '--force-all', '--no-write', '--survey-dir', surveydir,
        '--outdir', outdir, '--checkpoint', checkpoint_fn,
        '--checkpoint-period', '1', '--threads', '2'
    ] + extra_args)

    # Read catalog into Tractor sources to test read_fits_catalog
    from legacypipe.catalog import read_fits_catalog
    from legacypipe.survey import LegacySurveyData, GaiaSource
    from tractor.galaxy import DevGalaxy
    from tractor import PointSource

    survey = LegacySurveyData(survey_dir=outdir)
    fn = survey.find_file('tractor', brick='2447p120')
    print('Checking', fn)
    T = fits_table(fn)
    cat = read_fits_catalog(T, fluxPrefix='')
    print('Read catalog:', cat)
    assert (len(cat) == 2)
    src = cat[0]
    assert (type(src) == DevGalaxy)
    assert (np.abs(src.pos.ra - 244.77973) < 0.00001)
    assert (np.abs(src.pos.dec - 12.07233) < 0.00001)
    src = cat[1]
    print('Source', src)
    assert (type(src) in [PointSource, GaiaSource])
    assert (np.abs(src.pos.ra - 244.77830) < 0.00001)
    assert (np.abs(src.pos.dec - 12.07250) < 0.00001)
    # DevGalaxy(pos=RaDecPos[244.77975494973529, 12.072348111713127], brightness=NanoMaggies: g=19.2, r=17.9, z=17.1, shape=re=2.09234, e1=-0.198453, e2=0.023652,
    # PointSource(RaDecPos[244.77833280764278, 12.072521274981987], NanoMaggies: g=25, r=23, z=21.7)

    # Check that we can run again, using that checkpoint file.
    main(args=[
        '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
        '--no-wise', '--force-all', '--no-write', '--survey-dir', surveydir,
        '--outdir', outdir, '--checkpoint', checkpoint_fn,
        '--checkpoint-period', '1', '--threads', '2'
    ] + extra_args)
    # Assert...... something?

    # Test --checkpoint without --threads
    main(args=[
        '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
        '--no-wise', '--force-all', '--no-write', '--survey-dir', surveydir,
        '--outdir', outdir, '--checkpoint', checkpoint_fn,
        '--checkpoint-period', '1'
    ] + extra_args)

    # MzLS + BASS data
    # surveydir2 = os.path.join(os.path.dirname(__file__), 'mzlsbass')
    # main(args=['--brick', '3521p002', '--zoom', '2400', '2450', '1200', '1250',
    #            '--no-wise', '--force-all', '--no-write',
    #            '--survey-dir', surveydir2,
    #            '--outdir', 'out-mzlsbass'])

    # From Kaylan's Bootes pre-DR4 run
    # surveydir2 = os.path.join(os.path.dirname(__file__), 'mzlsbass3')
    # main(args=['--brick', '2173p350', '--zoom', '100', '200', '100', '200',
    #            '--no-wise', '--force-all', '--no-write',
    #            '--survey-dir', surveydir2,
    #            '--outdir', 'out-mzlsbass3'] + extra_args)

    # With plots!
    main(args=[
        '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
        '--no-wise', '--force-all', '--no-write', '--survey-dir', surveydir,
        '--outdir', 'out-testcase3', '--plots', '--nblobs', '1'
    ] + extra_args)

    # Decals Image Simulations
    # Uncomment WHEN galsim build for Travis
    #os.environ["DECALS_SIM_DIR"]= os.path.join(os.path.dirname(__file__),'image_sims')
    #brick= '2447p120'
    #sim_main(args=['--brick', brick, '-n', '2', '-o', 'STAR', \
    #               '-ic', '1', '--rmag-range', '18', '26', '--threads', '1',\
    #               '--zoom', '1020', '1070', '2775', '2815'])
    # Check if correct files written out
    #rt_dir= os.path.join(os.getenv('DECALS_SIM_DIR'),brick,'star','001')
    #assert( os.path.exists(os.path.join(rt_dir,'../','metacat-'+brick+'-star.fits')) )
    #for fn in ['tractor-%s-star-01.fits' % brick,'simcat-%s-star-01.fits' % brick]:
    #    assert( os.path.exists(os.path.join(rt_dir,fn)) )
    #for fn in ['image','model','resid','simscoadd']:
    #    assert( os.path.exists(os.path.join(rt_dir,'qa-'+brick+'-star-'+fn+'-01.jpg')) )

    if not travis:
        # With ceres
        main(args=[
            '--brick', '2447p120', '--zoom', '1020', '1070', '2775', '2815',
            '--no-wise', '--force-all', '--no-write', '--ceres',
            '--survey-dir', surveydir, '--outdir', 'out-testcase3-ceres'
        ] + extra_args)
                photocal = LinearPhotoCal(NanoMaggies.zeropointToScale(zp),
                                          band=band)
                tsky = ConstantSky(0.)

                # HACK -- circular Gaussian PSF of fixed size...
                # in arcsec
                #fwhms = dict(NUV=6.0, FUV=6.0)
                # -> sigma in pixels
                #sig = fwhms[band] / 2.35 / twcs.pixel_scale()
                sig = 6.0 / 2.35 / twcs.pixel_scale()
                tpsf = NCircularGaussianPSF([sig], [1.])

                tim = Image(data=timg,
                            inverr=tie,
                            psf=tpsf,
                            wcs=twcs,
                            sky=tsky,
                            photocal=photocal,
                            name='GALEX ' + band + brick.brickname)
                tractor = Tractor([tim], srcs)
                mod = tractor.getModelImage(0)

                print('Tractor image', tim.name)
                plt.clf()
                plt.imshow(timg, interpolation='nearest', origin='lower')
                ps.savefig()

                print('Tractor model', tim.name)
                plt.clf()
                plt.imshow(mod, interpolation='nearest', origin='lower')
                ps.savefig()
Exemple #8
0
def galex_coadds(onegal,
                 galaxy=None,
                 radius_mosaic=30,
                 radius_mask=None,
                 pixscale=1.5,
                 ref_pixscale=0.262,
                 output_dir=None,
                 galex_dir=None,
                 log=None,
                 centrals=True,
                 verbose=False):
    '''Generate custom GALEX cutouts.
    
    radius_mosaic and radius_mask in arcsec
    
    pixscale: GALEX pixel scale in arcsec/pixel.

    '''
    import fitsio
    import matplotlib.pyplot as plt

    from astrometry.libkd.spherematch import match_radec
    from astrometry.util.resample import resample_with_wcs, OverlapError
    from tractor import (Tractor, NanoMaggies, Image, LinearPhotoCal,
                         NCircularGaussianPSF, ConstantFitsWcs, ConstantSky)

    from legacypipe.survey import imsave_jpeg
    from legacypipe.catalog import read_fits_catalog

    if galaxy is None:
        galaxy = 'galaxy'

    if galex_dir is None:
        galex_dir = os.environ.get('GALEX_DIR')

    if output_dir is None:
        output_dir = '.'

    if radius_mask is None:
        radius_mask = radius_mosaic
        radius_search = 5.0  # [arcsec]
    else:
        radius_search = radius_mask

    W = H = np.ceil(2 * radius_mosaic / pixscale).astype('int')  # [pixels]
    targetwcs = Tan(onegal['RA'], onegal['DEC'], (W + 1) / 2.0, (H + 1) / 2.0,
                    -pixscale / 3600.0, 0.0, 0.0, pixscale / 3600.0, float(W),
                    float(H))

    # Read the custom Tractor catalog
    tractorfile = os.path.join(output_dir, '{}-tractor.fits'.format(galaxy))
    if not os.path.isfile(tractorfile):
        print('Missing Tractor catalog {}'.format(tractorfile))
        return 0

    cat = fits_table(tractorfile)
    print('Read {} sources from {}'.format(len(cat), tractorfile),
          flush=True,
          file=log)

    keep = np.ones(len(cat)).astype(bool)
    if centrals:
        # Find the large central galaxy and mask out (ignore) all the models
        # which are within its elliptical mask.

        # This algorithm will have to change for mosaics not centered on large
        # galaxies, e.g., in galaxy groups.
        m1, m2, d12 = match_radec(cat.ra,
                                  cat.dec,
                                  onegal['RA'],
                                  onegal['DEC'],
                                  radius_search / 3600.0,
                                  nearest=False)
        if len(m1) == 0:
            print('No central galaxies found at the central coordinates!',
                  flush=True,
                  file=log)
        else:
            pixfactor = ref_pixscale / pixscale  # shift the optical Tractor positions
            for mm in m1:
                morphtype = cat.type[mm].strip()
                if morphtype == 'EXP' or morphtype == 'COMP':
                    e1, e2, r50 = cat.shapeexp_e1[mm], cat.shapeexp_e2[
                        mm], cat.shapeexp_r[mm]  # [arcsec]
                elif morphtype == 'DEV' or morphtype == 'COMP':
                    e1, e2, r50 = cat.shapedev_e1[mm], cat.shapedev_e2[
                        mm], cat.shapedev_r[mm]  # [arcsec]
                else:
                    r50 = None

                if r50:
                    majoraxis = r50 * 5 / pixscale  # [pixels]
                    ba, phi = SGA.misc.convert_tractor_e1e2(e1, e2)
                    these = SGA.misc.ellipse_mask(W / 2, W / 2, majoraxis,
                                                  ba * majoraxis,
                                                  np.radians(phi),
                                                  cat.bx * pixfactor,
                                                  cat.by * pixfactor)
                    if np.sum(these) > 0:
                        #keep[these] = False
                        pass
                print('Hack!')
                keep[mm] = False

            #srcs = read_fits_catalog(cat)
            #_srcs = np.array(srcs)[~keep].tolist()
            #mod = SGA.misc.srcs2image(_srcs, ConstantFitsWcs(targetwcs), psf_sigma=3.0)
            #import matplotlib.pyplot as plt
            ##plt.imshow(mod, origin='lower') ; plt.savefig('junk.png')
            #plt.imshow(np.log10(mod), origin='lower') ; plt.savefig('junk.png')
            #pdb.set_trace()

    srcs = read_fits_catalog(cat)
    for src in srcs:
        src.freezeAllBut('brightness')
    #srcs_nocentral = np.array(srcs)[keep].tolist()

    # Find all overlapping GALEX tiles and then read the tims.
    galex_tiles = _read_galex_tiles(targetwcs,
                                    galex_dir,
                                    log=log,
                                    verbose=verbose)

    gbands = ['n', 'f']
    nicegbands = ['NUV', 'FUV']

    zps = dict(n=20.08, f=18.82)

    coimgs, comods, coresids, coimgs_central, comods_nocentral = [], [], [], [], []
    for niceband, band in zip(nicegbands, gbands):
        J = np.flatnonzero(galex_tiles.get('has_' + band))
        print(len(J), 'GALEX tiles have coverage in band', band)

        coimg = np.zeros((H, W), np.float32)
        comod = np.zeros((H, W), np.float32)
        cowt = np.zeros((H, W), np.float32)

        comod_nocentral = np.zeros((H, W), np.float32)

        for src in srcs:
            src.setBrightness(NanoMaggies(**{band: 1}))

        for j in J:
            brick = galex_tiles[j]
            fn = os.path.join(
                galex_dir, brick.tilename.strip(),
                '%s-%sd-intbgsub.fits.gz' % (brick.brickname, band))
            #print(fn)

            gwcs = Tan(*[
                float(f) for f in [
                    brick.crval1, brick.crval2, brick.crpix1, brick.crpix2,
                    brick.cdelt1, 0., 0., brick.cdelt2, 3840., 3840.
                ]
            ])
            img = fitsio.read(fn)
            #print('Read', img.shape)

            try:
                Yo, Xo, Yi, Xi, nil = resample_with_wcs(targetwcs, gwcs, [], 3)
            except OverlapError:
                continue

            K = np.flatnonzero(img[Yi, Xi] != 0.)
            if len(K) == 0:
                continue
            Yo, Xo, Yi, Xi = Yo[K], Xo[K], Yi[K], Xi[K]

            wt = brick.get(band + 'exptime')
            coimg[Yo, Xo] += wt * img[Yi, Xi]
            cowt[Yo, Xo] += wt

            x0, x1, y0, y1 = min(Xi), max(Xi), min(Yi), max(Yi)
            subwcs = gwcs.get_subimage(x0, y0, x1 - x0 + 1, y1 - y0 + 1)
            twcs = ConstantFitsWcs(subwcs)
            timg = img[y0:y1 + 1, x0:x1 + 1]

            tie = np.ones_like(timg)  ## HACK!
            #hdr = fitsio.read_header(fn)
            #zp = hdr['']
            zp = zps[band]
            photocal = LinearPhotoCal(NanoMaggies.zeropointToScale(zp),
                                      band=band)
            tsky = ConstantSky(0.0)

            # HACK -- circular Gaussian PSF of fixed size...
            # in arcsec
            #fwhms = dict(NUV=6.0, FUV=6.0)
            # -> sigma in pixels
            #sig = fwhms[band] / 2.35 / twcs.pixel_scale()
            sig = 6.0 / np.sqrt(8 * np.log(2)) / twcs.pixel_scale()
            tpsf = NCircularGaussianPSF([sig], [1.])

            tim = Image(data=timg,
                        inverr=tie,
                        psf=tpsf,
                        wcs=twcs,
                        sky=tsky,
                        photocal=photocal,
                        name='GALEX ' + band + brick.brickname)

            ## Build the model image with and without the central galaxy model.
            tractor = Tractor([tim], srcs)
            mod = tractor.getModelImage(0)
            tractor.freezeParam('images')
            tractor.optimize_forced_photometry(priors=False,
                                               shared_params=False)
            mod = tractor.getModelImage(0)

            srcs_nocentral = np.array(srcs)[keep].tolist()
            #srcs_nocentral = np.array(srcs)[nocentral].tolist()
            tractor_nocentral = Tractor([tim], srcs_nocentral)
            mod_nocentral = tractor_nocentral.getModelImage(0)

            comod[Yo, Xo] += wt * mod[Yi - y0, Xi - x0]
            comod_nocentral[Yo, Xo] += wt * mod_nocentral[Yi - y0, Xi - x0]

        coimg /= np.maximum(cowt, 1e-18)
        comod /= np.maximum(cowt, 1e-18)
        comod_nocentral /= np.maximum(cowt, 1e-18)

        coresid = coimg - comod

        # Subtract the model image which excludes the central (comod_nocentral)
        # from the data (coimg) to isolate the light of the central
        # (coimg_central).
        coimg_central = coimg - comod_nocentral

        coimgs.append(coimg)
        comods.append(comod)
        coresids.append(coresid)

        comods_nocentral.append(comod_nocentral)
        coimgs_central.append(coimg_central)

        # Write out the final images with and without the central, making sure
        # to apply the zeropoint to go from counts/s to AB nanomaggies.
        # https://asd.gsfc.nasa.gov/archive/galex/FAQ/counts_background.html
        for thisimg, imtype in zip((coimg, comod, comod_nocentral),
                                   ('image', 'model', 'model-nocentral')):
            fitsfile = os.path.join(
                output_dir, '{}-{}-{}.fits'.format(galaxy, imtype, niceband))
            if verbose:
                print('Writing {}'.format(fitsfile))
            fitsio.write(fitsfile,
                         thisimg * 10**(-0.4 * (zp - 22.5)),
                         clobber=True)

    # Build a color mosaic (but note that the images here are in units of
    # background-subtracted counts/s).

    #_galex_rgb = _galex_rgb_moustakas
    #_galex_rgb = _galex_rgb_dstn
    _galex_rgb = _galex_rgb_official

    for imgs, imtype in zip(
        (coimgs, comods, coresids, comods_nocentral, coimgs_central),
        ('image', 'model', 'resid', 'model-nocentral', 'image-central')):
        rgb = _galex_rgb(imgs)
        jpgfile = os.path.join(output_dir,
                               '{}-{}-FUVNUV.jpg'.format(galaxy, imtype))
        if verbose:
            print('Writing {}'.format(jpgfile))
        imsave_jpeg(jpgfile, rgb, origin='lower')

    return 1
Exemple #9
0
 if False:
     from legacypipe.survey import RexGalaxy
     from tractor import RaDecPos, NanoMaggies, PixPos
     from tractor import ScalarParam
     from tractor import Image, GaussianMixturePSF, LinearPhotoCal
     from legacypipe.survey import LogRadius
     rex = RexGalaxy(
         PixPos(1., 2.),
         NanoMaggies(r=3.),
         LogRadius(0.))
     print('Rex:', rex)
     print('Rex params:', rex.getParams())
     print('Rex nparams:', rex.numberOfParams())
     H,W = 100,100
     tim = Image(data=np.zeros((H,W), np.float32),
                 inverr=np.ones((H,W), np.float32),
                 psf=GaussianMixturePSF(1., 0., 0., 4., 4., 0.),
                 photocal=LinearPhotoCal(1., band='r'))
     derivs = rex.getParamDerivatives(tim)
     print('Derivs:', len(derivs))
     print('Rex params:', rex.getParamNames())
 
     import pylab as plt
     from astrometry.util.plotutils import PlotSequence
     ps = PlotSequence('rex')
 
     for d,nm in zip(derivs, rex.getParamNames()):
         plt.clf()
         plt.imshow(d.patch, interpolation='nearest', origin='lower')
         plt.title('Derivative %s' % nm)
         ps.savefig()
     
Exemple #10
0
def get_unwise_tractor_image(basedir,
                             tile,
                             band,
                             bandname=None,
                             masked=True,
                             **kwargs):
    '''
    masked: read "-m" images, or "-u"?

    bandname: PhotoCal band name to use: default: "w%i" % band
    '''

    if bandname is None:
        bandname = 'w%i' % band

    mu = 'm' if masked else 'u'

    # Allow multiple colon-separated unwise-coadd directories.
    basedirs = basedir.split(':')
    foundFiles = False
    for basedir in basedirs:
        thisdir = get_unwise_tile_dir(basedir, tile)
        base = os.path.join(thisdir, 'unwise-%s-w%i-' % (tile, band))

        imfn = base + 'img-%s.fits' % mu
        ivfn = base + 'invvar-%s.fits.gz' % mu
        # ppfn = base + 'std-%s.fits.gz'    % mu
        nifn = base + 'n-%s.fits.gz' % mu
        nufn = base + 'n-u.fits.gz'

        if not os.path.exists(imfn):
            print('Does not exist:', imfn)
            continue
        print('Reading', imfn)
        wcs = Tan(imfn)
        twcs = ConstantFitsWcs(wcs)

        F = fitsio.FITS(imfn)
        img = F[0]
        hdr = img.read_header()
        H, W = img.get_info()['dims']
        H, W = int(H), int(W)

        roi = interpret_roi(twcs, (H, W), **kwargs)
        if roi is None:
            # No overlap with ROI
            return None
        # interpret_roi returns None or a tuple; drop the second element in the tuple.
        roi, nil = roi
        (x0, x1, y0, y1) = roi

        wcs = wcs.get_subimage(x0, y0, x1 - x0, y1 - y0)
        twcs = ConstantFitsWcs(wcs)
        roislice = (slice(y0, y1), slice(x0, x1))
        img = img[roislice]

        if not os.path.exists(ivfn) and os.path.exists(
                ivfn.replace('.fits.gz', '.fits')):
            ivfn = ivfn.replace('.fits.gz', '.fits')
        if not os.path.exists(nifn) and os.path.exists(
                nifn.replace('.fits.gz', '.fits')):
            nifn = nifn.replace('.fits.gz', '.fits')
        if not os.path.exists(nufn) and os.path.exists(
                nufn.replace('.fits.gz', '.fits')):
            nufn = nufn.replace('.fits.gz', '.fits')

        if not (os.path.exists(ivfn) and os.path.exists(nifn)
                and os.path.exists(nufn)):
            print('Files do not exist:', ivfn, nifn, nufn)
            continue

        foundFiles = True
        break

    if not foundFiles:
        raise IOError('unWISE files not found in ' + str(basedirs) +
                      ' for tile ' + tile)

    print('Reading', ivfn)
    invvar = fitsio.FITS(ivfn)[0][roislice]

    if band == 4:
        # due to upsampling, effective invvar is smaller (the pixels
        # are correlated)
        invvar *= 0.25

    # print 'Reading', ppfn
    #pp = fitsio.FITS(ppfn)[0][roislice]
    print('Reading', nifn)
    nims = fitsio.FITS(nifn)[0][roislice]

    if nufn == nifn:
        nuims = nims
    else:
        print('Reading', nufn)
        nuims = fitsio.FITS(nufn)[0][roislice]

    # print 'Median # ims:', np.median(nims)
    good = (nims > 0)
    invvar[np.logical_not(good)] = 0.
    sig1 = 1. / np.sqrt(np.median(invvar[good]))

    # Load the average PSF model (generated by wise_psf.py)
    psffn = os.path.join(os.path.dirname(__file__), 'wise-psf-avg.fits')
    print('Reading', psffn)
    P = fits_table(psffn, hdu=band)
    psf = GaussianMixturePSF(P.amp, P.mean, P.var)

    sky = 0.
    tsky = ConstantSky(sky)

    # if opt.errfrac > 0:
    #     nz = (iv > 0)
    #     iv2 = np.zeros_like(invvar)
    #     iv2[nz] = 1./(1./invvar[nz] + (img[nz] * opt.errfrac)**2)
    #     print 'Increasing error estimate by', opt.errfrac, 'of image flux'
    #     invvar = iv2

    tim = Image(data=img,
                invvar=invvar,
                psf=psf,
                wcs=twcs,
                sky=tsky,
                photocal=LinearPhotoCal(1., band=bandname),
                name='unWISE %s W%i' % (tile, band))
    tim.sig1 = sig1
    tim.roi = roi
    tim.nims = nims
    tim.nuims = nuims
    tim.hdr = hdr

    if 'MJDMIN' in hdr and 'MJDMAX' in hdr:
        from tractor.tractortime import TAITime
        tim.mjdmin = hdr['MJDMIN']
        tim.mjdmax = hdr['MJDMAX']
        tim.time = TAITime(None, mjd=(tim.mjdmin + tim.mjdmax) / 2.)

    return tim
Exemple #11
0
def scan_dchisq(seeing, target_dchisq, ps, e1=0.):
    pixscale = 0.262
    psfsigma = seeing / pixscale / 2.35
    print('PSF sigma:', psfsigma, 'pixels')
    psf = GaussianMixturePSF(1., 0., 0., psfsigma**2, psfsigma**2, 0.)

    sig1 = 0.01
    psfnorm = 1./(2. * np.sqrt(np.pi) * psfsigma)
    detsig1 = sig1 / psfnorm

    sz = 50
    cd = pixscale / 3600.
    wcs = Tan(0., 0., float(sz/2), float(sz/2), -cd, 0., 0., cd,
              float(sz), float(sz))
    band = 'r'

    tim = Image(data=np.zeros((sz,sz)), inverr=np.ones((sz,sz)) / sig1,
                psf=psf,
                wcs = ConstantFitsWcs(wcs),
                photocal = LinearPhotoCal(1., band=band))
    
    re_vals = np.logspace(-1., 0., 50)
    
    all_runs = []

    mods = []
    
    for i,re in enumerate(re_vals):
        true_src = ExpGalaxy(RaDecPos(0., 0.),
                             NanoMaggies(**{band: 1.}),
                             EllipseE(re, e1, 0.))
        print('True source:', true_src)
        tr = Tractor([tim], [true_src])
        tr.freezeParams('images')
        true_mod = tr.getModelImage(0)

        dchisq_none = np.sum((true_mod * tim.inverr)**2)
        scale = np.sqrt(target_dchisq / dchisq_none)

        true_src.brightness.setParams([scale])

        true_mod = tr.getModelImage(0)
        dchisq_none = np.sum((true_mod * tim.inverr)**2)

        mods.append(true_mod)
        
        tim.data = true_mod
        
        exp_src = true_src.copy()
        psf_src = PointSource(true_src.pos.copy(), true_src.brightness.copy())
        simp_src = SimpleGalaxy(true_src.pos.copy(), true_src.brightness.copy())

        dchisqs = []
        #for src in [psf_src, simp_src, exp_src]:
        for src in [psf_src, simp_src]:
            src.freezeParam('pos')
            #print('Fitting source:', src)
            #src.printThawedParams()
            tr.catalog[0] = src
            tr.optimize_loop()
            #print('Fitted:', src)
            mod = tr.getModelImage(0)
            dchisqs.append(dchisq_none - np.sum(((true_mod - mod) * tim.inverr)**2))
            #print('dchisq:', dchisqs[-1])
        dchisqs.append(dchisq_none)
        
        all_runs.append([re,] + dchisqs)

    all_runs = np.array(all_runs)

    re = all_runs[:,0]
    dchi_psf  = all_runs[:,1]
    dchi_simp = all_runs[:,2]
    dchi_exp  = all_runs[:,3]

    dchi_ps = np.maximum(dchi_psf, dchi_simp)
    dchi_cut1 = dchi_ps + 3+9
    dchi_cut2 = dchi_ps + dchi_psf * 0.02
    dchi_cut3 = dchi_ps + dchi_psf * 0.008
    
    plt.clf()
    plt.plot(re, dchi_psf, 'k-', label='PSF')
    plt.plot(re, dchi_simp, 'b-', label='SIMP')
    plt.plot(re, dchi_exp, 'r-', label='EXP')

    plt.plot(re, dchi_cut2, 'm--', alpha=0.5, lw=2, label='Cut: 2%')
    plt.plot(re, dchi_cut3, 'm:',  alpha=0.5, lw=2, label='Cut: 0.08%')
    plt.plot(re, dchi_cut1, 'm-',  alpha=0.5, lw=2, label='Cut: 12')

    plt.xlabel('True r_e (arcsec)')
    plt.ylabel('dchisq')
    #plt.legend(loc='lower left')
    plt.legend(loc='upper right')
    tt = 'Seeing = %g arcsec, S/N ~ %i' % (seeing, int(np.round(np.sqrt(target_dchisq))))
    if e1 != 0.:
        tt += ', Ellipticity %g' % e1
    plt.title(tt)
    plt.ylim(0.90 * target_dchisq, 1.05 * target_dchisq)

    # aspect = 1.2
    # ax = plt.axis()
    # dre  = (ax[1]-ax[0]) / 20 / aspect
    # dchi = (ax[3]-ax[2]) / 20
    # I = np.linspace(0, len(re_vals)-1, 8).astype(int)
    # for mod,re in [(mods[i], re_vals[i]) for i in I]:
    #     print('extent:', [re-dre, re+dre, ax[2], ax[2]+dchi])
    #     plt.imshow(mod, interpolation='nearest', origin='lower', aspect='auto',
    #                extent=[re-dre, re+dre, ax[2], ax[2]+dchi], cmap='gray')
    # plt.axis(ax)
        
    ps.savefig()
Exemple #12
0
    Nother= np.zeros_like(Nexp)

    np.random.seed(42)

    sz = 50
    cd = pixscale / 3600.
    wcs = Tan(0., 0., float(sz/2), float(sz/2), -cd, 0., 0., cd,
              float(sz), float(sz))
    band = 'r'

    #all_dchisqs = []

    all_runs = []

    tim = Image(data=np.zeros((sz,sz)), inverr=np.ones((sz,sz)) / sig1,
                psf=psf,
                wcs = ConstantFitsWcs(wcs),
                photocal = LinearPhotoCal(1., band=band))
    
    for i,sn in enumerate(sn_vals):
        for j,re in enumerate(re_vals):
            ## HACK -- this is the flux required for a PSF to be
            ## detected at target S/N... adjust for galaxy?
            flux = sn * detsig1
            # Create round EXP galaxy
            #PixPos(sz/2, sz/2),
            true_src = ExpGalaxy(RaDecPos(0., 0.),
                                 NanoMaggies(**{band: flux}),
                                 EllipseE(re, 0., 0.))
            
            tr = Tractor([tim], [true_src])
            tr.freezeParams('images')
Exemple #13
0
        '''Set step sizes when taking derivatives of the parameters of the mixture of Gaussians.'''
        return [0.01]*self.K*2

#################### (end of second way)

    
if __name__ == '__main__':
    h,w = 100,100
    from tractor.galaxy import ExpGalaxy
    from tractor import Image, GaussianMixturePSF, LinearPhotoCal
    from tractor import PixPos, Flux, EllipseE, Tractor, ModelMask
    import pylab as plt

    # Create a Tractor Image that works in pixel space (WCS not specified).
    tim = Image(data=np.zeros((h,w)), inverr=np.ones((h,w)),
                psf=GaussianMixturePSF(1., 0., 0., 3., 3., 0.),
                photocal=LinearPhotoCal(1.))

    # Create a plain Exp galaxy to generate a postage stamp that we'll try to fit with
    # the MogGalaxy model.
    gal = ExpGalaxy(PixPos(w//2, h//2), Flux(1000.),
                    EllipseE(10., 0.5, 0.3))

    # Get the model
    tractor = Tractor([tim], [gal])
    mod = tractor.getModelImage(0)

    #mog = gal._getAffineProfile(tim, w//2, h//2)
    #print('Exp galaxy profile:', str(mog))

    # Plot the model
Exemple #14
0
def make_depth_cut(survey, ccds, bands, targetrd, brick, W, H, pixscale,
                   plots, ps, splinesky, gaussPsf, pixPsf, normalizePsf, do_calibs,
                   gitver, targetwcs, old_calibs_ok, get_depth_maps=False, margin=0.5,
                   use_approx_wcs=False):
    if plots:
        import pylab as plt

    # Add some margin to our DESI depth requirements
    target_depth_map = dict(g=24.0 + margin, r=23.4 + margin, z=22.5 + margin)

    # List extra (redundant) target percentiles so that increasing the depth at
    # any of these percentiles causes the image to be kept.
    target_percentiles = np.array(list(range(2, 10)) +
                                  list(range(10, 30, 5)) +
                                  list(range(30, 101, 10)))
    target_ddepths = np.zeros(len(target_percentiles), np.float32)
    target_ddepths[target_percentiles < 10] = -0.3
    target_ddepths[target_percentiles <  5] = -0.6
    #print('Target percentiles:', target_percentiles)
    #print('Target ddepths:', target_ddepths)

    cH,cW = H//10, W//10
    coarsewcs = targetwcs.scale(0.1)
    coarsewcs.imagew = cW
    coarsewcs.imageh = cH

    # Unique pixels in this brick (U: cH x cW boolean)
    U = find_unique_pixels(coarsewcs, cW, cH, None,
                           brick.ra1, brick.ra2, brick.dec1, brick.dec2)
    pixscale = 3600. * np.sqrt(np.abs(ccds.cd1_1*ccds.cd2_2 - ccds.cd1_2*ccds.cd2_1))
    seeing = ccds.fwhm * pixscale

    # Compute the rectangle in *coarsewcs* covered by each CCD
    slices = []
    overlapping_ccds = np.zeros(len(ccds), bool)
    for i,ccd in enumerate(ccds):
        wcs = survey.get_approx_wcs(ccd)
        hh,ww = wcs.shape
        rr,dd = wcs.pixelxy2radec([1,ww,ww,1], [1,1,hh,hh])
        ok,xx,yy = coarsewcs.radec2pixelxy(rr, dd)
        y0 = int(np.round(np.clip(yy.min(), 0, cH-1)))
        y1 = int(np.round(np.clip(yy.max(), 0, cH-1)))
        x0 = int(np.round(np.clip(xx.min(), 0, cW-1)))
        x1 = int(np.round(np.clip(xx.max(), 0, cW-1)))
        if y0 == y1 or x0 == x1:
            slices.append(None)
            continue
        # Check whether this CCD overlaps the unique area of this brick...
        if not np.any(U[y0:y1+1, x0:x1+1]):
            info('No overlap with unique area for CCD', ccd.expnum, ccd.ccdname)
            slices.append(None)
            continue
        overlapping_ccds[i] = True
        slices.append((slice(y0, y1+1), slice(x0, x1+1)))

    keep_ccds = np.zeros(len(ccds), bool)
    depthmaps = []

    for band in bands:
        # scalar
        target_depth = target_depth_map[band]
        # vector
        target_depths = target_depth + target_ddepths

        depthiv = np.zeros((cH,cW), np.float32)
        depthmap = np.zeros_like(depthiv)
        depthvalue = np.zeros_like(depthiv)
        last_pcts = np.zeros_like(target_depths)
        # indices of CCDs we still want to look at in the current band
        b_inds = np.where(ccds.filter == band)[0]
        info(len(b_inds), 'CCDs in', band, 'band')
        if len(b_inds) == 0:
            continue
        b_inds = np.array([i for i in b_inds if slices[i] is not None])
        info(len(b_inds), 'CCDs in', band, 'band overlap target')
        if len(b_inds) == 0:
            continue
        # CCDs that we will try before searching for good ones -- CCDs
        # from the same exposure number as CCDs we have chosen to
        # take.
        try_ccds = set()

        # Try DECaLS data first!
        Idecals = np.where(ccds.propid[b_inds] == '2014B-0404')[0]
        if len(Idecals):
            try_ccds.update(b_inds[Idecals])
        debug('Added', len(try_ccds), 'DECaLS CCDs to try-list')

        plot_vals = []

        if plots:
            plt.clf()
            for i in b_inds:
                sy,sx = slices[i]
                x0,x1 = sx.start, sx.stop
                y0,y1 = sy.start, sy.stop
                plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'b-', alpha=0.5)
            plt.title('CCDs overlapping brick: %i in %s band' % (len(b_inds), band))
            ps.savefig()

            nccds = np.zeros((cH,cW), np.int16)
            plt.clf()
            for i in b_inds:
                nccds[slices[i]] += 1
            plt.imshow(nccds, interpolation='nearest', origin='lower', vmin=0)
            plt.colorbar()
            plt.title('CCDs overlapping brick: %i in %s band (%i / %i / %i)' %
                      (len(b_inds), band, nccds.min(), np.median(nccds), nccds.max()))

            ps.savefig()
            #continue

        while len(b_inds):
            if len(try_ccds) == 0:
                # Choose the next CCD to look at in this band.

                # A rough point-source depth proxy would be:
                # metric = np.sqrt(ccds.extime[b_inds]) / seeing[b_inds]
                # If we want to put more weight on choosing good-seeing images, we could do:
                #metric = np.sqrt(ccds.exptime[b_inds]) / seeing[b_inds]**2

                # depth would be ~ 1 / (sig1 * seeing); we privilege good seeing here.
                metric = 1. / (ccds.sig1[b_inds] * seeing[b_inds]**2)

                # This metric is *BIG* for *GOOD* ccds!

                # Here, we try explicitly to include CCDs that cover
                # pixels that are still shallow by the largest amount
                # for the largest number of percentiles of interest;
                # note that pixels with no coverage get depth 0, so
                # score high in this metric.
                #
                # The value is the depth still required to hit the
                # target, summed over percentiles of interest
                # (for pixels unique to this brick)
                depthvalue[:,:] = 0.
                active = (last_pcts < target_depths)
                for d in target_depths[active]:
                    depthvalue += U * np.maximum(0, d - depthmap)
                ccdvalue = np.zeros(len(b_inds), np.float32)
                for j,i in enumerate(b_inds):
                    #ccdvalue[j] = np.sum(depthvalue[slices[i]])
                    # mean -- we want the most bang for the buck per pixel?
                    ccdvalue[j] = np.mean(depthvalue[slices[i]])
                metric *= ccdvalue

                # *ibest* is an index into b_inds
                ibest = np.argmax(metric)
                # *iccd* is an index into ccds.
                iccd = b_inds[ibest]
                ccd = ccds[iccd]
                debug('Chose best CCD: seeing', seeing[iccd], 'exptime', ccds.exptime[iccd], 'with value', ccdvalue[ibest])

            else:
                iccd = try_ccds.pop()
                ccd = ccds[iccd]
                debug('Popping CCD from use_ccds list')

            # remove *iccd* from b_inds
            b_inds = b_inds[b_inds != iccd]

            im = survey.get_image_object(ccd)
            debug('Band', im.band, 'expnum', im.expnum, 'exptime', im.exptime, 'seeing', im.fwhm*im.pixscale, 'arcsec, propid', im.propid)

            im.check_for_cached_files(survey)
            debug(im)

            if do_calibs:
                kwa = dict(git_version=gitver, old_calibs_ok=old_calibs_ok)
                if gaussPsf:
                    kwa.update(psfex=False)
                if splinesky:
                    kwa.update(splinesky=True)
                im.run_calibs(**kwa)

            if use_approx_wcs:
                debug('Using approximate (TAN) WCS')
                wcs = survey.get_approx_wcs(ccd)
            else:
                debug('Reading WCS from', im.imgfn, 'HDU', im.hdu)
                wcs = im.get_wcs()

            x0,x1,y0,y1,slc = im.get_image_extent(wcs=wcs, radecpoly=targetrd)
            if x0==x1 or y0==y1:
                debug('No actual overlap')
                continue
            wcs = wcs.get_subimage(int(x0), int(y0), int(x1-x0), int(y1-y0))

            if 'galnorm_mean' in ccds.get_columns():
                galnorm = ccd.galnorm_mean
                debug('Using galnorm_mean from CCDs table:', galnorm)
            else:
                psf = im.read_psf_model(x0, y0, gaussPsf=gaussPsf, pixPsf=pixPsf,
                                        normalizePsf=normalizePsf)
                psf = psf.constantPsfAt((x1-x0)//2, (y1-y0)//2)
                # create a fake tim to compute galnorm
                from tractor import PixPos, Flux, ModelMask, Image, NullWCS
                from legacypipe.survey import SimpleGalaxy

                h,w = 50,50
                gal = SimpleGalaxy(PixPos(w//2,h//2), Flux(1.))
                tim = Image(data=np.zeros((h,w), np.float32),
                            psf=psf, wcs=NullWCS(pixscale=im.pixscale))
                mm = ModelMask(0, 0, w, h)
                galmod = gal.getModelPatch(tim, modelMask=mm).patch
                galmod = np.maximum(0, galmod)
                galmod /= galmod.sum()
                galnorm = np.sqrt(np.sum(galmod**2))
            detiv = 1. / (im.sig1 / galnorm)**2
            galdepth = -2.5 * (np.log10(5. * im.sig1 / galnorm) - 9.)
            debug('Galnorm:', galnorm, 'sig1:', im.sig1, 'galdepth', galdepth)

            # Add this image the the depth map...
            from astrometry.util.resample import resample_with_wcs, OverlapError
            try:
                Yo,Xo,_,_,_ = resample_with_wcs(coarsewcs, wcs)
                debug(len(Yo), 'of', (cW*cH), 'pixels covered by this image')
            except OverlapError:
                debug('No overlap')
                continue
            depthiv[Yo,Xo] += detiv

            # compute the new depth map & percentiles (including the proposed new CCD)
            depthmap[:,:] = 0.
            depthmap[depthiv > 0] = 22.5 - 2.5*np.log10(5./np.sqrt(depthiv[depthiv > 0]))
            depthpcts = np.percentile(depthmap[U], target_percentiles)

            for i,(p,d,t) in enumerate(zip(target_percentiles, depthpcts, target_depths)):
                info('  pct % 3i, prev %5.2f -> %5.2f vs target %5.2f %s' % (p, last_pcts[i], d, t, ('ok' if d >= t else '')))

            keep = False
            # Did we increase the depth of any target percentile that did not already exceed its target depth?
            if np.any((depthpcts > last_pcts) * (last_pcts < target_depths)):
                keep = True

            # Add any other CCDs from this same expnum to the try_ccds list.
            # (before making the plot)
            I = np.where(ccd.expnum == ccds.expnum[b_inds])[0]
            try_ccds.update(b_inds[I])
            debug('Adding', len(I), 'CCDs with the same expnum to try_ccds list')

            if plots:
                cc = '1' if keep else '0'
                xx = [Xo.min(), Xo.min(), Xo.max(), Xo.max(), Xo.min()]
                yy = [Yo.min(), Yo.max(), Yo.max(), Yo.min(), Yo.min()]
                plot_vals.append(((xx,yy,cc),(last_pcts,depthpcts,keep),im.ccdname))

            if plots and (
                (len(try_ccds) == 0) or np.all(depthpcts >= target_depths)):
                plt.clf()

                plt.subplot2grid((2,2),(0,0))
                plt.imshow(depthvalue, interpolation='nearest', origin='lower',
                           vmin=0)
                plt.xticks([]); plt.yticks([])
                plt.colorbar()
                plt.title('heuristic value')

                plt.subplot2grid((2,2),(0,1))
                plt.imshow(depthmap, interpolation='nearest', origin='lower',
                           vmin=target_depth - 2, vmax=target_depth + 0.5)
                ax = plt.axis()
                for (xx,yy,cc) in [p[0] for p in plot_vals]:
                    plt.plot(xx,yy, '-', color=cc, lw=3)
                plt.axis(ax)
                plt.xticks([]); plt.yticks([])
                plt.colorbar()
                plt.title('depth map')

                plt.subplot2grid((2,2),(1,0), colspan=2)
                ax = plt.gca()
                plt.plot(target_percentiles, target_depths, 'ro', label='Target')
                plt.plot(target_percentiles, target_depths, 'r-')
                for (lp,dp,k) in [p[1] for p in plot_vals]:
                    plt.plot(target_percentiles, lp, 'k-',
                             label='Previous percentiles')
                for (lp,dp,k) in [p[1] for p in plot_vals]:
                    cc = 'b' if k else 'r'
                    plt.plot(target_percentiles, dp, '-', color=cc,
                             label='Depth percentiles')
                ccdnames = ','.join([p[2] for p in plot_vals])
                plot_vals = []

                plt.ylim(target_depth - 2, target_depth + 0.5)
                plt.xscale('log')
                plt.xlabel('Percentile')
                plt.ylabel('Depth')
                plt.title('depth percentiles')
                plt.suptitle('%s %i-%s, exptime %.0f, seeing %.2f, band %s' %
                             (im.camera, im.expnum, ccdnames, im.exptime,
                              im.pixscale * im.fwhm, band))
                ps.savefig()

            if keep:
                info('Keeping this exposure')
            else:
                info('Not keeping this exposure')
                depthiv[Yo,Xo] -= detiv
                continue

            keep_ccds[iccd] = True
            last_pcts = depthpcts

            if np.all(depthpcts >= target_depths):
                info('Reached all target depth percentiles for band', band)
                break

        if get_depth_maps:
            if np.any(depthiv > 0):
                depthmap[:,:] = 0.
                depthmap[depthiv > 0] = 22.5 -2.5*np.log10(5./np.sqrt(depthiv[depthiv > 0]))
                depthmap[np.logical_not(U)] = np.nan
                depthmaps.append((band, depthmap.copy()))

        if plots:
            I = np.where(ccds.filter == band)[0]
            plt.clf()
            plt.plot(seeing[I], ccds.exptime[I], 'k.')
            # which CCDs from this band are we keeping?
            kept, = np.nonzero(keep_ccds)
            if len(kept):
                kept = kept[ccds.filter[kept] == band]
                plt.plot(seeing[kept], ccds.exptime[kept], 'ro')
            plt.xlabel('Seeing (arcsec)')
            plt.ylabel('Exptime (sec)')
            plt.title('CCDs kept for band %s' % band)
            plt.ylim(0, np.max(ccds.exptime[I]) * 1.1)
            ps.savefig()

    if get_depth_maps:
        return (keep_ccds, overlapping_ccds, depthmaps)
    return keep_ccds, overlapping_ccds
Exemple #15
0
    wcs = ConstantFitsWcs(
        Tan(ra, dec, (1. + W) / 2., (1. + H) / 2., pscale, 0., 0., pscale, W,
            H))

    # an arbitrary name for this image's bandpass; if we used Flux
    # rather than NanoMaggies as the brightness class we wouldn't need this
    # (but in SDSS we'll be using multi-band NanoMaggies)
    band = 'r'
    # image sensitivity:
    photocal = LinearPhotoCal(10., band=band)

    # flat sky
    sky = ConstantSky(0.)

    # Create tractor.Image object
    tim = Image(data, iv, psf=psf, wcs=wcs, sky=sky, photocal=photocal)

    def brightness(x):
        return NanoMaggies(**{band: x})

    # Create some sources
    ptsrc = PointSource(RaDecPos(ra, dec), brightness(10.))

    gal1 = ExpGalaxy(RaDecPos(ra - 10 * pscale, dec), brightness(50.),
                     GalaxyShape(5., 0.5, 45.))

    gal2 = DevGalaxy(RaDecPos(ra + 10 * pscale, dec), brightness(50.),
                     GalaxyShape(5., 0.25, 135.))

    gal3 = FixedCompositeGalaxy(
        RaDecPos(ra, dec + 10 * pscale),