Пример #1
0
 def write_color_image(self, survey, brickname, coimgs, comods):
     from legacypipe.survey import imsave_jpeg
     # W1/W2 color jpeg
     rgb = _unwise_to_rgb(coimgs[:2])
     with survey.write_output('wise-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
     rgb = _unwise_to_rgb(comods[:2])
     with survey.write_output('wisemodel-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
Пример #2
0
 def write_color_image(self, survey, brickname, coimgs, comods):
     from legacypipe.survey import imsave_jpeg
     rgbfunc = _galex_rgb_moustakas
     # W1/W2 color jpeg
     rgb = rgbfunc(coimgs)
     with survey.write_output('galex-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
     rgb = rgbfunc(comods)
     with survey.write_output('galexmodel-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
Пример #3
0
 def finish(self, survey, brickname, version_header):
     from legacypipe.survey import imsave_jpeg
     for band, co, n, com, coiv in zip([1, 2, 3, 4], self.unwise_co,
                                       self.unwise_con, self.unwise_com,
                                       self.unwise_coiv):
         hdr = fitsio.FITSHDR()
         for r in version_header.records():
             hdr.add_record(r)
         hdr.add_record(dict(name='TELESCOP', value='WISE'))
         hdr.add_record(
             dict(name='FILTER', value='W%i' % band, comment='WISE band'))
         self.unwise_wcs.add_to_header(hdr)
         hdr.delete('IMAGEW')
         hdr.delete('IMAGEH')
         hdr.add_record(dict(name='EQUINOX', value=2000.))
         hdr.add_record(
             dict(name='MAGZERO', value=22.5,
                  comment='Magnitude zeropoint'))
         hdr.add_record(
             dict(name='MAGSYS',
                  value='Vega',
                  comment='This WISE image is in Vega fluxes'))
         co /= np.maximum(n, 1)
         com /= np.maximum(n, 1)
         with survey.write_output('image',
                                  brick=brickname,
                                  band='W%i' % band,
                                  shape=co.shape) as out:
             out.fits.write(co, header=hdr)
         with survey.write_output('model',
                                  brick=brickname,
                                  band='W%i' % band,
                                  shape=com.shape) as out:
             out.fits.write(com, header=hdr)
         with survey.write_output('invvar',
                                  brick=brickname,
                                  band='W%i' % band,
                                  shape=co.shape) as out:
             out.fits.write(coiv, header=hdr)
     # W1/W2 color jpeg
     rgb = _unwise_to_rgb(self.unwise_co[:2])
     with survey.write_output('wise-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
     rgb = _unwise_to_rgb(self.unwise_com[:2])
     with survey.write_output('wisemodel-jpeg', brick=brickname) as out:
         imsave_jpeg(out.fn, rgb, origin='lower')
         info('Wrote', out.fn)
Пример #4
0
def main():
    survey = LegacySurveyData()

    brickname = '2351p137'
    # RA,Dec = 235.0442, 13.7125
    bx, by = 3300, 1285
    sz = 50
    bbox = [bx - sz, bx + sz, by - sz, by + sz]
    objid = 1394
    bands = ['g', 'r', 'z']

    from legacypipe.runbrick import stage_tims, _get_mod, rgbkwargs, rgbkwargs_resid
    from legacypipe.survey import get_rgb, imsave_jpeg
    from legacypipe.coadds import make_coadds
    from astrometry.util.multiproc import multiproc
    from astrometry.util.fits import fits_table
    from legacypipe.catalog import read_fits_catalog

    # brick = survey.get_brick_by_name(brickname)
    # # Get WCS object describing brick
    # targetwcs = wcs_for_brick(brick)
    # (x0,x1,y0,y1) = bbox
    # W = x1-x0
    # H = y1-y0
    # targetwcs = targetwcs.get_subimage(x0, y0, W, H)
    # H,W = targetwcs.shape

    mp = multiproc()
    P = stage_tims(brickname=brickname,
                   survey=survey,
                   target_extent=bbox,
                   pixPsf=True,
                   hybridPsf=True,
                   depth_cut=False,
                   mp=mp)
    print('Got', P.keys())

    tims = P['tims']
    targetwcs = P['targetwcs']
    H, W = targetwcs.shape

    # Read Tractor catalog
    fn = survey.find_file('tractor', brick=brickname)
    print('Trying to read catalog', fn)
    cat = fits_table(fn)
    print('Read', len(cat), 'sources')
    ok, xx, yy = targetwcs.radec2pixelxy(cat.ra, cat.dec)
    I = np.flatnonzero((xx > 0) * (xx < W) * (yy > 0) * (yy < H))
    cat.cut(I)
    print('Cut to', len(cat), 'sources within box')

    I = np.flatnonzero(cat.objid != objid)
    cat.cut(I)
    print('Cut to', len(cat), 'sources with objid !=', objid)

    #cat.about()
    # Convert FITS catalog into tractor source objects
    print('Creating tractor sources...')

    srcs = read_fits_catalog(cat, fluxPrefix='')
    print('Sources:')
    for src in srcs:
        print(' ', src)

    print('Rendering model images...')
    mods = [_get_mod((tim, srcs)) for tim in tims]

    print('Producing coadds...')
    C = make_coadds(tims, bands, targetwcs, mods=mods, mp=mp)
    print('Coadds:', dir(C))

    coadd_list = [('image', C.coimgs, rgbkwargs),
                  ('model', C.comods, rgbkwargs),
                  ('resid', C.coresids, rgbkwargs_resid)]
    #C.coimgs, C.comods, C.coresids
    for name, ims, rgbkw in coadd_list:
        rgb = get_rgb(ims, bands, **rgbkw)
        kwa = {}
        #with survey.write_output(name + '-jpeg', brick=brickname) as out:
        #    imsave_jpeg(out.fn, rgb, origin='lower', **kwa)
        #    print('Wrote', out.fn)
        outfn = name + '.jpg'
        imsave_jpeg(outfn, rgb, origin='lower', **kwa)
        del rgb
Пример #5
0
def _tractor_coadds(galaxycat,
                    targetwcs,
                    tims,
                    mods,
                    version_header,
                    objid=None,
                    brickname=None,
                    survey=None,
                    mp=None,
                    verbose=False,
                    bands=['g', 'r', 'z']):
    """Generate individual-band FITS and color coadds for each central using
    Tractor.

    """
    from legacypipe.coadds import make_coadds, write_coadd_images
    from legacypipe.runbrick import rgbkwargs, rgbkwargs_resid
    from legacypipe.survey import get_rgb, imsave_jpeg

    if brickname is None:
        brickname = galaxycat['brickname']

    if verbose:
        print('Producing coadds...')
    C = make_coadds(tims,
                    bands,
                    targetwcs,
                    mods=mods,
                    mp=mp,
                    callback=write_coadd_images,
                    callback_args=(survey, brickname, version_header, tims,
                                   targetwcs))

    # Move (rename) the coadds into the desired output directory.
    for suffix in ('chi2', 'image', 'invvar', 'model'):
        for band in bands:
            oldfile = os.path.join(
                survey.output_dir, 'coadd', brickname[:3], brickname,
                'legacysurvey-{}-{}-{}.fits.fz'.format(brickname, suffix,
                                                       band))
            newfile = os.path.join(
                survey.output_dir,
                '{}-{}-{}.fits.fz'.format(objid, suffix, band))
            shutil.copy(oldfile, newfile)

    if True:
        shutil.rmtree(os.path.join(survey.output_dir, 'coadd'))

    # Build png postage stamps of the coadds.
    coadd_list = [('image', C.coimgs, rgbkwargs),
                  ('model', C.comods, rgbkwargs),
                  ('resid', C.coresids, rgbkwargs_resid)]

    for name, ims, rgbkw in coadd_list:
        rgb = get_rgb(ims, bands, **rgbkw)
        kwa = {}
        outfn = os.path.join(survey.output_dir,
                             '{}-{}.jpg'.format(objid, name))
        if verbose:
            print('Writing {}'.format(outfn))
        imsave_jpeg(outfn, rgb, origin='lower', **kwa)
        del rgb
Пример #6
0
def unwise_coadds(onegal,
                  galaxy=None,
                  radius_mosaic=30,
                  radius_mask=None,
                  pixscale=2.75,
                  ref_pixscale=0.262,
                  output_dir=None,
                  unwise_dir=None,
                  verbose=False,
                  log=None,
                  centrals=True):
    '''Generate custom unWISE cutouts.
    
    radius_mosaic and radius_mask in arcsec
    
    pixscale: WISE pixel scale in arcsec/pixel; make this smaller than 2.75
    to oversample.

    '''
    import fitsio
    import matplotlib.pyplot as plt

    from astrometry.util.util import Tan
    from astrometry.util.fits import fits_table
    from astrometry.libkd.spherematch import match_radec
    from astrometry.util.resample import resample_with_wcs, ResampleError
    from wise.forcedphot import unwise_tiles_touching_wcs
    from wise.unwise import get_unwise_tractor_image
    from tractor import Tractor, Image, NanoMaggies

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

    if galaxy is None:
        galaxy = 'galaxy'

    if output_dir is None:
        output_dir = '.'

    if unwise_dir is None:
        unwise_dir = os.environ.get('UNWISE_COADDS_DIR')

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

    # Initialize the WCS object.
    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),
              flush=True,
              file=log)
        return 0
    primhdr = fitsio.read_header(tractorfile)

    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()
    cat_nocentral = cat[keep]

    ## Find and remove all the objects within XX arcsec of the target
    ## coordinates.
    #m1, m2, d12 = match_radec(T.ra, T.dec, onegal['RA'], onegal['DEC'], 5/3600.0, nearest=False)
    #if len(d12) == 0:
    #    print('No matching galaxies found -- probably not what you wanted.')
    #    #raise ValueError
    #    nocentral = np.ones(len(T)).astype(bool)
    #else:
    #    nocentral = ~np.isin(T.objid, T[m1].objid)
    #T_nocentral = T[nocentral]

    # Find and read the overlapping unWISE tiles.  Assume the targetwcs is
    # axis-aligned and that the edge midpoints yield the RA, Dec limits (true
    # for TAN).  Note: the way the roiradec box is used, the min/max order
    # doesn't matter.
    r, d = targetwcs.pixelxy2radec(np.array([1, W, W / 2, W / 2]),
                                   np.array([H / 2, H / 2, 1, H]))
    roiradec = [r[0], r[1], d[2], d[3]]

    tiles = unwise_tiles_touching_wcs(targetwcs)

    wbands = [1, 2, 3, 4]
    wanyband = 'w'
    vega_to_ab = dict(w1=2.699, w2=3.339, w3=5.174, w4=6.620)

    # Convert the AB WISE fluxes in the Tractor catalog to Vega nanomaggies so
    # they're consistent with the coadds, below.
    for band in wbands:
        f = cat.get('flux_w{}'.format(band))
        e = cat.get('flux_ivar_w{}'.format(band))
        print('Setting negative fluxes equal to zero!')
        f[f < 0] = 0
        #f[f/e < 3] = 0
        f *= 10**(0.4 * vega_to_ab['w{}'.format(band)])

    coimgs = [np.zeros((H, W), np.float32) for b in wbands]
    comods = [np.zeros((H, W), np.float32) for b in wbands]
    comods_nocentral = [np.zeros((H, W), np.float32) for b in wbands]
    con = [np.zeros((H, W), np.uint8) for b in wbands]

    for iband, band in enumerate(wbands):
        for ii, src in enumerate(srcs):
            src.setBrightness(
                NanoMaggies(
                    **{wanyband: cat.get('flux_w{}'.format(band))[ii]}))
        srcs_nocentral = np.array(srcs)[keep].tolist()
        #srcs_nocentral = np.array(srcs)[nocentral].tolist()

        # The tiles have some overlap, so for each source, keep the fit in the
        # tile whose center is closest to the source.
        for tile in tiles:
            #print('Reading tile {}'.format(tile.coadd_id))
            tim = get_unwise_tractor_image(unwise_dir,
                                           tile.coadd_id,
                                           band,
                                           bandname=wanyband,
                                           roiradecbox=roiradec)
            if tim is None:
                print('Actually, no overlap with tile {}'.format(
                    tile.coadd_id))
                continue
            print('Read image {} with shape {}'.format(tile.coadd_id,
                                                       tim.shape))

            def _unwise_mod(tim, use_cat, use_srcs, margin=10):
                # Select sources in play.
                wisewcs = tim.wcs.wcs
                timH, timW = tim.shape
                ok, x, y = wisewcs.radec2pixelxy(use_cat.ra, use_cat.dec)
                x = (x - 1.).astype(np.float32)
                y = (y - 1.).astype(np.float32)
                I = np.flatnonzero((x >= -margin) * (x < timW + margin) *
                                   (y >= -margin) * (y < timH + margin))
                #print('Found {} sources within the image + margin = {} pixels'.format(len(I), margin))

                subcat = [use_srcs[i] for i in I]
                tractor = Tractor([tim], subcat)
                mod = tractor.getModelImage(0)
                return mod

            mod = _unwise_mod(tim, cat, srcs)
            mod_nocentral = _unwise_mod(tim, cat_nocentral, srcs_nocentral)

            try:
                Yo, Xo, Yi, Xi, nil = resample_with_wcs(targetwcs, tim.wcs.wcs)
            except ResampleError:
                continue
            if len(Yo) == 0:
                continue

            # The models are already in AB nanomaggies, but the tiles / tims are
            # in Vega nanomaggies, so convert them here.
            coimgs[iband][Yo, Xo] += tim.getImage()[Yi, Xi]
            comods[iband][Yo, Xo] += mod[Yi, Xi]
            comods_nocentral[iband][Yo, Xo] += mod_nocentral[Yi, Xi]
            con[iband][Yo, Xo] += 1

        ## Convert back to nanomaggies.
        #vega2ab = vega_to_ab['w{}'.format(band)]
        #coimgs[iband] *= 10**(-0.4 * vega2ab)
        #comods[iband] *= 10**(-0.4 * vega2ab)
        #comods_nocentral[iband] *= 10**(-0.4 * vega2ab)

    for img, mod, mod_nocentral, n in zip(coimgs, comods, comods_nocentral,
                                          con):
        img /= np.maximum(n, 1)
        mod /= np.maximum(n, 1)
        mod_nocentral /= np.maximum(n, 1)

    coresids = [img - mod for img, mod in list(zip(coimgs, comods))]

    # Subtract the model image which excludes the central (comod_nocentral)
    # from the data (coimg) to isolate the light of the central
    # (coimg_central).
    coimgs_central = [
        img - mod for img, mod in list(zip(coimgs, comods_nocentral))
    ]

    # Write out the final images with and without the central and converted into
    # AB nanomaggies.
    for coadd, imtype in zip((coimgs, comods, comods_nocentral),
                             ('image', 'model', 'model-nocentral')):
        for img, band in zip(coadd, wbands):
            vega2ab = vega_to_ab['w{}'.format(band)]
            fitsfile = os.path.join(
                output_dir, '{}-{}-W{}.fits'.format(galaxy, imtype, band))
            if verbose:
                print('Writing {}'.format(fitsfile))
            fitsio.write(fitsfile, img * 10**(-0.4 * vega2ab), clobber=True)

    # Generate color WISE images.
    kwa = dict(mn=-1, mx=100, arcsinh=0.5)
    #kwa = dict(mn=-0.05, mx=1., arcsinh=0.5)
    #kwa = dict(mn=-0.1, mx=2., arcsinh=None)

    for imgs, imtype in zip(
        (coimgs, comods, coresids, comods_nocentral, coimgs_central),
        ('image', 'model', 'resid', 'model-nocentral', 'image-central')):
        rgb = _unwise_to_rgb(imgs[:2], **kwa)  # W1, W2
        jpgfile = os.path.join(output_dir,
                               '{}-{}-W1W2.jpg'.format(galaxy, imtype))
        if verbose:
            print('Writing {}'.format(jpgfile))
        imsave_jpeg(jpgfile, rgb, origin='lower')

    return 1
Пример #7
0
def _tractor_coadds(sample,
                    targetwcs,
                    tims,
                    mods,
                    version_header,
                    objid=None,
                    brickname=None,
                    survey=None,
                    mp=None,
                    log=None,
                    bands=['g', 'r', 'z']):
    """Generate individual-band FITS and color coadds for each central using
    Tractor.

    """
    from legacypipe.coadds import make_coadds, write_coadd_images
    #from legacypipe.runbrick import rgbkwargs, rgbkwargs_resid
    from legacypipe.survey import get_rgb, imsave_jpeg

    if brickname is None:
        brickname = sample['brickname']

    print('Producing coadds...', flush=True, file=log)
    if log:
        with redirect_stdout(log), redirect_stderr(log):
            C = make_coadds(tims,
                            bands,
                            targetwcs,
                            mods=mods,
                            mp=mp,
                            callback=write_coadd_images,
                            callback_args=(survey, brickname, version_header,
                                           tims, targetwcs))
    else:
        C = make_coadds(tims,
                        bands,
                        targetwcs,
                        mods=mods,
                        mp=mp,
                        callback=write_coadd_images,
                        callback_args=(survey, brickname, version_header, tims,
                                       targetwcs))

    # Move (rename) the coadds into the desired output directory.
    for suffix in np.atleast_1d('model'):
        for band in bands:
            shutil.copy(
                os.path.join(
                    survey.output_dir, 'coadd', brickname[:3], brickname,
                    'legacysurvey-{}-{}-{}.fits.fz'.format(
                        brickname, suffix, band)),
                os.path.join(
                    survey.output_dir,
                    '{}-{}-nocentral-{}.fits.fz'.format(objid, suffix, band)))

    if True:
        shutil.rmtree(os.path.join(survey.output_dir, 'coadd'))

    # Build png postage stamps of the coadds.
    rgbkwargs = dict(mnmx=(-1, 100), arcsinh=1)
    #rgbkwargs_resid = dict(mnmx=(0.1, 2), arcsinh=1)
    rgbkwargs_resid = dict(mnmx=(-1, 100), arcsinh=1)

    #coadd_list = [('image-central', C.coimgs,   rgbkwargs),
    #              ('model-central', C.comods,   rgbkwargs),
    #              ('resid-central', C.coresids, rgbkwargs_resid)]
    coadd_list = [('model-nocentral', C.comods, rgbkwargs),
                  ('image-central', C.coresids, rgbkwargs_resid)]

    for name, ims, rgbkw in coadd_list:
        rgb = get_rgb(ims, bands, **rgbkw)
        kwa = {}
        outfn = os.path.join(survey.output_dir,
                             '{}-{}.jpg'.format(objid, name))
        print('Writing {}'.format(outfn), flush=True, file=log)
        imsave_jpeg(outfn, rgb, origin='lower', **kwa)
        del rgb
Пример #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
Пример #9
0
def ubercal_skysub(tims,
                   targetwcs,
                   survey,
                   brickname,
                   bands,
                   mp,
                   subsky_radii=None,
                   plots=False,
                   plots2=False,
                   ps=None,
                   verbose=False):
    """With the ubercal option, we (1) read the full-field mosaics ('bandtims') for
    a given bandpass and put them all on the same 'system' using the overlapping
    pixels; (2) apply the derived corrections to the in-field 'tims'; (3) build
    the coadds (per bandpass) from the 'tims'; and (4) subtract the median sky
    from the mosaic (after aggressively masking objects and reference sources).

    """
    from tractor.sky import ConstantSky
    from legacypipe.reference import get_reference_sources, get_reference_map
    from legacypipe.coadds import make_coadds
    from legacypipe.survey import get_rgb, imsave_jpeg
    from astropy.stats import sigma_clipped_stats

    if plots or plots2:
        import os
        import matplotlib.pyplot as plt

    if plots:
        plt.figure(figsize=(8, 6))
        mods = []
        for tim in tims:
            imcopy = tim.getImage().copy()
            tim.sky.addTo(imcopy, -1)
            mods.append(imcopy)
        C = make_coadds(tims,
                        bands,
                        targetwcs,
                        mods=mods,
                        callback=None,
                        mp=mp)
        imsave_jpeg(os.path.join(survey.output_dir, 'metrics', 'cus',
                                 '{}-pipelinesky.jpg'.format(ps.basefn)),
                    get_rgb(C.comods, bands),
                    origin='lower')

    skydict = {}
    if subsky_radii is not None:
        skydict.update(
            {'NSKYANN': (len(subsky_radii) // 2, 'number of sky annuli')})
        for irad, (rin, rout) in enumerate(
                zip(subsky_radii[0::2], subsky_radii[1::2])):
            skydict.update({
                'SKYRIN{:02d}'.format(irad):
                (np.float32(rin), 'inner sky radius {} [arcsec]'.format(irad))
            })
            skydict.update({
                'SKYROT{:02d}'.format(irad):
                (np.float32(rout), 'outer sky radius {} [arcsec]'.format(irad))
            })

    allbands = np.array([tim.band for tim in tims])

    # we need the full-field mosaics if doing annular sky-subtraction
    if subsky_radii is not None:
        allbandtims = []
    else:
        allbandtims = None

    for band in sorted(set(allbands)):
        print('Working on band {}'.format(band))
        I = np.where(allbands == band)[0]

        bandtims = [
            tims[ii].imobj.get_tractor_image(gaussPsf=True,
                                             pixPsf=False,
                                             subsky=False,
                                             dq=True,
                                             apodize=False) for ii in I
        ]

        # Derive the ubercal correction and then apply it.
        x = coadds_ubercal(bandtims,
                           coaddtims=[tims[ii] for ii in I],
                           plots=plots,
                           plots2=plots2,
                           ps=ps,
                           verbose=True)
        for ii, corr in zip(I, x):
            skydict.update({
                'SKCCD{:03d}'.format(ii):
                (tims[ii].name, 'ubersky CCD {:03d}'.format(ii))
            })
            skydict.update({
                'SKCOR{:03d}'.format(ii):
                (corr, 'ubersky corr CCD {:03d}'.format(ii))
            })

        # Apply the correction and return the tims
        for jj, (correction, ii) in enumerate(zip(x, I)):
            tims[ii].data += correction
            tims[ii].sky = ConstantSky(0.0)
            # Also correct the full-field mosaics
            bandtims[jj].data += correction
            bandtims[jj].sky = ConstantSky(0.0)

        ## Check--
        #for jj, correction in enumerate(x):
        #    fulltims[jj].data += correction
        #newcorrection = coadds_ubercal(fulltims)
        #print(newcorrection)

        if allbandtims is not None:
            allbandtims = allbandtims + bandtims

    # Estimate the sky background from an annulus surrounding the object
    # (assumed to be at the center of the mosaic, targetwcs.crval).
    if subsky_radii is not None:
        from astrometry.util.util import Tan

        # the inner and outer radii / annuli are nested in subsky_radii
        allrin = subsky_radii[0::2]
        allrout = subsky_radii[1::2]

        pixscale = targetwcs.pixel_scale()
        bigH = float(np.ceil(2 * np.max(allrout) / pixscale))
        bigW = bigH

        # if doing annulur sky-subtraction we need a bigger mosaic
        bigtargetwcs = Tan(targetwcs.crval[0], targetwcs.crval[1],
                           bigW / 2. + 0.5, bigH / 2. + 0.5,
                           -pixscale / 3600.0, 0., 0., pixscale / 3600.0,
                           float(bigW), float(bigH))

        C = make_coadds(allbandtims,
                        bands,
                        bigtargetwcs,
                        callback=None,
                        sbscale=False,
                        mp=mp)

        _, x0, y0 = bigtargetwcs.radec2pixelxy(bigtargetwcs.crval[0],
                                               bigtargetwcs.crval[1])
        xcen, ycen = np.round(x0 - 1).astype('int'), np.round(y0 -
                                                              1).astype('int')
        ymask, xmask = np.ogrid[-ycen:bigH - ycen, -xcen:bigW - xcen]

        refs, _ = get_reference_sources(survey,
                                        bigtargetwcs,
                                        bigtargetwcs.pixel_scale(), ['r'],
                                        tycho_stars=True,
                                        gaia_stars=True,
                                        large_galaxies=True,
                                        star_clusters=True)
        refmask = get_reference_map(bigtargetwcs, refs) == 0  # True=skypix

        for coimg, coiv, band in zip(C.coimgs, C.cowimgs, bands):
            skypix = _build_objmask(coimg, coiv, refmask * (coiv > 0))

            for irad, (rin, rout) in enumerate(zip(allrin, allrout)):
                inmask = (xmask**2 + ymask**2) <= (rin / pixscale)**2
                outmask = (xmask**2 + ymask**2) <= (rout / pixscale)**2
                skymask = (outmask * 1 - inmask * 1) == 1  # True=skypix

                # Find and mask objects, then get the sky.
                skypix_annulus = np.logical_and(skypix, skymask)
                #import matplotlib.pyplot as plt ; plt.imshow(skypix_annulus, origin='lower') ; plt.savefig('junk3.png')
                #import pdb ; pdb.set_trace()

                if np.sum(skypix_annulus) == 0:
                    raise ValueError('No pixels in sky!')
                _skymean, _skymedian, _skysig = sigma_clipped_stats(
                    coimg, mask=np.logical_not(skypix_annulus), sigma=3.0)

                skydict.update({
                    '{}SKYMN{:02d}'.format(band.upper(), irad):
                    (np.float32(_skymean),
                     'mean {} sky in annulus {}'.format(band, irad))
                })
                skydict.update({
                    '{}SKYMD{:02d}'.format(band.upper(), irad):
                    (np.float32(_skymedian),
                     'median {} sky in annulus {}'.format(band, irad))
                })
                skydict.update({
                    '{}SKYSG{:02d}'.format(band.upper(), irad):
                    (np.float32(_skysig),
                     'sigma {} sky in annulus {}'.format(band, irad))
                })
                skydict.update({
                    '{}SKYNP{:02d}'.format(band.upper(), irad):
                    (np.sum(skypix_annulus),
                     'npix {} sky in annulus {}'.format(band, irad))
                })

                # the reference annulus is the first one
                if irad == 0:
                    skymean, skymedian, skysig = _skymean, _skymedian, _skysig
                    skypix_mask = skypix_annulus

            I = np.where(allbands == band)[0]
            for ii in I:
                tims[ii].data -= skymedian
                #print('Tim', tims[ii], 'after subtracting skymedian: median', np.median(tims[ii].data))

    else:
        # regular mosaic
        C = make_coadds(tims,
                        bands,
                        targetwcs,
                        callback=None,
                        sbscale=False,
                        mp=mp)

        refs, _ = get_reference_sources(survey,
                                        targetwcs,
                                        targetwcs.pixel_scale(), ['r'],
                                        tycho_stars=True,
                                        gaia_stars=True,
                                        large_galaxies=True,
                                        star_clusters=True)
        refmask = get_reference_map(targetwcs, refs) == 0  # True=skypix

        for coimg, coiv, band in zip(C.coimgs, C.cowimgs, bands):
            skypix = refmask * (coiv > 0)
            skypix_mask = _build_objmask(coimg, coiv, skypix)
            skymean, skymedian, skysig = sigma_clipped_stats(
                coimg, mask=np.logical_not(skypix_mask), sigma=3.0)

            skydict.update({
                '{}SKYMN00'.format(band.upper(), irad):
                (np.float32(_skymean), 'mean {} sky'.format(band))
            })
            skydict.update({
                '{}SKYMD00'.format(band.upper(), irad):
                (np.float32(_skymedian), 'median {} sky'.format(band))
            })
            skydict.update({
                '{}SKYSG00'.format(band.upper(), irad):
                (np.float32(_skysig), 'sigma {} sky'.format(band))
            })
            skydict.update({
                '{}SKYNP00'.format(band.upper(), irad):
                (np.sum(skypix_mask), 'npix {} sky'.format(band))
            })

            I = np.where(allbands == band)[0]
            for ii in I:
                tims[ii].data -= skymedian
            # print('Tim', tims[ii], 'after subtracting skymedian: median', np.median(tims[ii].data))

            #print('Band', band, 'Coadd sky:', skymedian)
            if plots2:
                plt.clf()
                plt.hist(coimg.ravel(), bins=50, range=(-3, 3), density=True)
                plt.axvline(skymedian, color='k')
                for ii in I:
                    #print('Tim', tims[ii], 'median', np.median(tims[ii].data))
                    plt.hist((tims[ii].data - skymedian).ravel(),
                             bins=50,
                             range=(-3, 3),
                             histtype='step',
                             density=True)
                plt.title('Band %s: tim pix & skymedian' % band)
                ps.savefig()

                # Produce skymedian-subtracted, masked image for later RGB plot
                coimg -= skymedian
                coimg[~skypix_mask] = 0.
                #coimg[np.logical_not(skymask * (coiv > 0))] = 0.

    if plots2:
        plt.clf()
        plt.imshow(get_rgb(C.coimgs, bands),
                   origin='lower',
                   interpolation='nearest')
        ps.savefig()

        for band in bands:
            for tim in tims:
                if tim.band != band:
                    continue
                plt.clf()
                C = make_coadds([tim],
                                bands,
                                targetwcs,
                                callback=None,
                                sbscale=False,
                                mp=mp)
                plt.imshow(get_rgb(C.coimgs, bands).sum(axis=2),
                           cmap='gray',
                           interpolation='nearest',
                           origin='lower')
                plt.title('Band %s: tim %s' % (band, tim.name))
                ps.savefig()

    if plots:
        import pylab as plt
        import matplotlib.patches as patches

        # skysub QA
        C = make_coadds(tims, bands, targetwcs, callback=None, mp=mp)
        imsave_jpeg(os.path.join(survey.output_dir, 'metrics', 'cus',
                                 '{}-customsky.jpg'.format(ps.basefn)),
                    get_rgb(C.coimgs, bands),
                    origin='lower')

        # ccdpos QA
        refs, _ = get_reference_sources(survey,
                                        targetwcs,
                                        targetwcs.pixel_scale(), ['r'],
                                        tycho_stars=False,
                                        gaia_stars=False,
                                        large_galaxies=True,
                                        star_clusters=False)

        pixscale = targetwcs.pixel_scale()
        width = targetwcs.get_width() * pixscale / 3600  # [degrees]
        bb, bbcc = targetwcs.radec_bounds(), targetwcs.radec_center(
        )  # [degrees]
        pad = 0.5 * width  # [degrees]

        delta = np.max((np.diff(bb[0:2]), np.diff(bb[2:4]))) / 2 + pad / 2
        xlim = bbcc[0] - delta, bbcc[0] + delta
        ylim = bbcc[1] - delta, bbcc[1] + delta

        plt.clf()
        _, allax = plt.subplots(1,
                                3,
                                figsize=(12, 5),
                                sharey=True,
                                sharex=True)
        for ax, band in zip(allax, ('g', 'r', 'z')):
            ax.set_xlabel('RA (deg)')
            ax.text(0.9,
                    0.05,
                    band,
                    ha='center',
                    va='bottom',
                    transform=ax.transAxes,
                    fontsize=18)

            if band == 'g':
                ax.set_ylabel('Dec (deg)')
            ax.get_xaxis().get_major_formatter().set_useOffset(False)

            # individual CCDs
            these = np.where([tim.band == band for tim in tims])[0]
            col = plt.cm.Set1(np.linspace(0, 1, len(tims)))
            for ii, indx in enumerate(these):
                tim = tims[indx]
                #wcs = tim.subwcs
                wcs = tim.imobj.get_wcs()
                cc = wcs.radec_bounds()
                ax.add_patch(
                    patches.Rectangle((cc[0], cc[2]),
                                      cc[1] - cc[0],
                                      cc[3] - cc[2],
                                      fill=False,
                                      lw=2,
                                      edgecolor=col[these[ii]],
                                      label='ccd{:02d}'.format(these[ii])))
            ax.legend(ncol=2, frameon=False, loc='upper left', fontsize=10)

            # output mosaic footprint
            cc = targetwcs.radec_bounds()
            ax.add_patch(
                patches.Rectangle((cc[0], cc[2]),
                                  cc[1] - cc[0],
                                  cc[3] - cc[2],
                                  fill=False,
                                  lw=2,
                                  edgecolor='k'))

            if subsky_radii is not None:
                racen, deccen = targetwcs.crval
                for rad in subsky_radii:
                    ax.add_patch(
                        patches.Circle((racen, deccen),
                                       rad / 3600,
                                       fill=False,
                                       edgecolor='black',
                                       lw=2))
            else:
                for gal in refs:
                    ax.add_patch(
                        patches.Circle((gal.ra, gal.dec),
                                       gal.radius,
                                       fill=False,
                                       edgecolor='black',
                                       lw=2))

            ax.set_ylim(ylim)
            ax.set_xlim(xlim)
            ax.invert_xaxis()
            ax.set_aspect('equal')

        plt.subplots_adjust(bottom=0.12,
                            wspace=0.05,
                            left=0.12,
                            right=0.97,
                            top=0.95)
        plt.savefig(
            os.path.join(survey.output_dir, 'metrics', 'cus',
                         '{}-ccdpos.jpg'.format(ps.basefn)))

    if plots2:
        plt.clf()
        for coimg, band in zip(C.coimgs, bands):
            plt.hist(coimg.ravel(),
                     bins=50,
                     range=(-0.5, 0.5),
                     histtype='step',
                     label=band)
        plt.legend()
        plt.title('After adjustment: coadds (sb scaled)')
        ps.savefig()

    return tims, skydict