示例#1
0
def voronoi_binning(image, obj_name, targetSN = 50,  largest_bin = 5, smallest_bin = 0, minimumSN = 7, quiet=True, plot=True):
    
    """
    Function to bin an image using the Voronoi binning method by Cappellari & Copin (2003)
    
    Input as 'image' the target with the filter where S/N is highest
    
    """
    import numpy as np
    import astropy.io.fits as pyfits
    from grizli import utils
    from grizli import prep
    import matplotlib.pyplot as plt
    from astropy.table import vstack

    im = pyfits.open(image)
    
    sci = np.cast[np.float32](im['SCI'].data)
    sh = sci.shape
    
    ivar = np.cast[np.float32](im['WHT'].data)
    var = 1/ivar
    
    orig_mask = (ivar > 0)
    sci[~orig_mask] = 0
    var[~orig_mask] = 0
    orig_var = var*1
    
    # Simple background
    bkg = np.median(sci[orig_mask])
    sci -= bkg*orig_mask
    
    cps = sci*im[0].header['EXPTIME']
    shot_err = np.sqrt(np.maximum(cps, 4))/im[0].header['EXPTIME']
    var2 = var + shot_err**2
    var = var2
    
    full_bin_seg = np.zeros(sh, dtype=np.int)-1
    
    yp, xp = np.indices(sci.shape)
    
    xpf = xp.flatten()
    ypf = yp.flatten()
    
    # Initialize mask
    mask = orig_mask & True
    bin_min = 1
    full_image = sci*0.
    full_err = sci*0.
        
    idx = np.arange(sci.size, dtype=np.int) 
    full_image = full_image.flatten()
    full_err = full_err.flatten()
        
    # id, bin, xmin, xmax, ymin, ymax, npix
    full_bin_data = []
    
    SKIP_LAST = False
    
    bin_iter = 0
    bin_factor = largest_bin
    
    NO_NEWLINE = '\x1b[1A\x1b[1M'
    
    for bin_iter, bin_factor in enumerate(range(largest_bin+1)[::-1]):
        bin = 2**bin_factor
       
        if bin_factor < smallest_bin:
            break
        
        if (bin_factor == 0) & SKIP_LAST:
            continue
            
        ypb = yp[mask] // bin
        xpb = xp[mask] // bin
            
        if bin_factor > 0:
            binned_sci = np.zeros((sh[0]//bin+1, sh[1]//bin+1))
            binned_npix = binned_sci*0
            binned_var = binned_sci*0

            ypi, xpi = np.indices(binned_sci.shape)
            
            # Only consider unmasked bins
            ij = np.unique(xpb + sh[0]//bin*ypb)
            yarr = ij // (sh[0]//bin)
            xarr = ij - (sh[0]//bin)*yarr
            
            for xi, yi in zip(xarr, yarr):
                if not quiet:
                    print(NO_NEWLINE+'{0} {1}/{2} {3}/{4}'.format(bin_factor, 
                                               xi, xarr.max(), 
                                               yi, yarr.max()))
                slx = slice(xi*bin, xi*bin+bin)
                sly = slice(yi*bin, yi*bin+bin)
                mslice = mask[sly, slx]
                # Straight average
                binned_sci[yi, xi] = sci[sly, slx][mslice].sum()
                binned_npix[yi, xi] = mslice.sum()
                binned_var[yi, xi] = var[sly, slx][mslice].sum()
            
            binned_err = np.sqrt(binned_var) / binned_npix       
            binned_avg = binned_sci / binned_npix
            
            mask_i = (binned_npix > 0) & (binned_avg/binned_err > minimumSN)
            xpi = xpi[mask_i]
            ypi = ypi[mask_i]
            binned_avg = binned_avg[mask_i]
            binned_err = binned_err[mask_i]
            binned_npix = binned_npix[mask_i]
            
        else:
            mask_i = mask_j
            xpi = xp[mask]
            ypi = yp[mask]
            binned_avg = sci[mask]
            binned_err = np.sqrt(var)[mask]
            binned_npix = mask[mask]*1
        
        if True:         
            
            # Mask pixels in that don't satisfy S/N cutoff as they are 
            # unreliable for vorbin
            clip_mask = mask < 0
            for xi, yi in zip(xpi, ypi):
                slx = slice(xi*bin, xi*bin+bin)
                sly = slice(yi*bin, yi*bin+bin)
                clip_mask[sly, slx] = True

            mask &= clip_mask
               
            # Identify blobs (usually the main central galaxies) and 
            # only consider blobs larger than 20% of the largest blob
            if bin_factor == largest_bin:
                                
                label_image = label(mask)
                label_ids = np.unique(label_image)[1:]
                label_sizes = np.array([(label_image == id_i).sum() for id_i in label_ids])
                
                keep_ids = label_ids[label_sizes > 0.2*label_sizes.max()]
                keep_mask = mask < -1
                for i in keep_ids:
                    keep_mask |= label_image == i
                
                mask &= keep_mask
                
                # In binned_coords
                in_blob = keep_mask[ypi*bin, xpi*bin]
                msg = 'Drop {0} bins not in main blob'
                
                print(msg.format((~in_blob).sum()))
                xpi = xpi[in_blob]
                ypi = ypi[in_blob]
                binned_avg = binned_avg[in_blob]
                binned_err = binned_err[in_blob]
                binned_npix = binned_npix[in_blob]
                
            ypb = yp[mask] // bin
            xpb = xp[mask] // bin
                          
        print('Run voronoi_2d_binning, bin_factor={0}'.format(bin_factor))
                
        res = voronoi_2d_binning(xpi, ypi, binned_avg, binned_err, targetSN,
                                 quiet=True, plot=False, pixelsize=0.1*bin,
                                 cvt=True, wvt=True)
            
        binNum, xBin, yBin, xBar, yBar, sn, nPixels, scale = res
    
        # Put Voronoi bins with nPixels > 1 back in the original image
        NBINS = len(nPixels)
        
        if (bin_factor == smallest_bin) & (smallest_bin > 0):
            valid_bins = nPixels > 0
        else:
            valid_bins = nPixels > 1
    
        large_bin_ids = np.arange(NBINS)[valid_bins]
        
        # Put bin in original 2D array and store info
        for b0, bin_id in enumerate(large_bin_ids):
            m_i = binNum == bin_id
            xi_bin = xpi[m_i]
            yi_bin = ypi[m_i]
            for xi, yi in zip(xi_bin, yi_bin):
                slx = slice(xi*bin, xi*bin+bin)
                sly = slice(yi*bin, yi*bin+bin)
                mslice = mask[sly, slx]
                full_bin_seg[sly, slx][mslice] = b0+bin_min
            
            # Bin properties
            id_i = b0+bin_min
            xmin = xi_bin.min()*bin-1
            xmax = xi_bin.max()*bin+1
            ymin = yi_bin.min()*bin-1
            ymax = yi_bin.max()*bin+1
            npix = m_i.sum()*bin**2
            bin_data_i = [id_i, bin, xmin, xmax, ymin, ymax, npix]
            full_bin_data.append(bin_data_i)
            
        # Update the mask
        not_in_a_bin = full_bin_seg == -1
        mask &= not_in_a_bin
        
        bin_min = full_bin_data[-1][0]+1
        if not quiet:
            print('\n\n\n\n\n bin_factor: {0}, bin_min: {1}\n\n\n\n'.format(bin_factor, bin_min))
    
    ## Bin information
    bin_data = np.array(full_bin_data)
    # bin_data_i = [id_i, bin, xmin, xmax, ymin, ymax, npix]
    tab = utils.GTable()
    for i, c in enumerate(['id', 'bin', 'xmin', 'xmax', 'ymin', 'ymax', 'npix']):
        tab[c] = bin_data[:,i]
        if 'min' in c:
            tab[c] -= tab['bin']
        elif 'max' in c:
            tab[c] += tab['bin']  
    
    # Make a table for the individual pixels
    if mask.sum() > 0:
        single_table = single_pixel_table(mask,start_id=1+tab['id'].max())
        full_bin_seg[mask] = single_table['id']
        tab = vstack([tab,single_table])
    
    tab['flux'], tab['err'], tab['area'] = prep.get_seg_iso_flux(sci, full_bin_seg, tab, err=np.sqrt(var))
    
    binned_flux = prep.get_seg_iso_flux(sci, full_bin_seg, tab, fill=tab['flux']/tab['area'])
    binned_err = prep.get_seg_iso_flux(sci, full_bin_seg, tab, fill=tab['err']/tab['area'])
    binned_area = prep.get_seg_iso_flux(sci, full_bin_seg, tab, fill=tab['area'])
    binned_bin = prep.get_seg_iso_flux(sci, full_bin_seg, tab, fill=tab['bin'])
    
    binned_flux[mask] = sci[mask]
    binned_err[mask] = np.sqrt(var)[mask]
    binned_area[mask] = 1
    binned_bin[mask] = 1
    
    if plot:
        plt.figure(figsize=(12,12))
        plt.imshow(binned_flux,vmin=-0.5,vmax=2)
        
    # Save output into image fits file
    primary_extn = pyfits.PrimaryHDU()
    sci_extn = pyfits.ImageHDU(data=binned_flux.astype(np.float32),name='SCI')
    err_extn = pyfits.ImageHDU(data=binned_err.astype(np.float32),name='ERR') 
    hdul = pyfits.HDUList([primary_extn, sci_extn, err_extn])
    for ext in [0,1]:
        for k in im[ext].header:
                if k not in hdul[ext].header:
                    if k in ['COMMENT','HISTORY','']:
                        continue
                    hdul[ext].header[k] = im[ext].header[k]
    hdul.writeto('binned_{0}_image.fits'.format(obj_name), output_verify='fix', overwrite=True)
    
    tab.write('binned_{0}_table.fits'.format(obj_name), overwrite=True)
    pyfits.writeto('binned_{0}_seg.fits'.format(obj_name),data = full_bin_seg, overwrite=True)
    pyfits.writeto('binned_{0}_mask.fits'.format(obj_name),data = mask*1, overwrite=True)
    
    return tab, full_bin_seg, mask
示例#2
0
def eazy_fitting(catalog_file='catalog.fits',
                 target='galaxy',
                 im='image.fits',
                 seg_im='seg.fits',
                 mw_ebv=0.0375,
                 plot=False,
                 image_space=False,
                 zsp=0.004556):
    """
    Function fitting the input target and obtain physical parameters.

    INPUTS:
     catalog_file: Catalog file with the fluxes and errors to be fitted.
           target: The name of the target, to be used in the output files.
               im: Image to be used as reference to convert output from
                   table space into image space. [optional]
           seg_im: Segmentation image. [optional]
           mw_ebv: Galactic extinction. Value can be found here:
                   https://irsa.ipac.caltech.edu/applications/DUST/
       
    KEYWORDS:
         PLOT: Set this keyword to produce a plot of the two-dimensional
               continuum subtracted image.   
  IMAGE_SPACE: Set this keyword to produce the output in image space.
         
    OUTPUTS:
         EAZY derived physical parameters.

    """

    import os
    import numpy as np
    import matplotlib.pyplot as plt
    import eazy
    import warnings
    from grizli import prep
    from astropy.utils.exceptions import AstropyWarning
    import astropy.io.fits as pyfits
    from astropy.table import Table
    from astropy.cosmology import WMAP9
    from astropy import units as u

    np.seterr(all='ignore')
    warnings.simplefilter('ignore', category=AstropyWarning)

    # Parameters
    params = {}
    params['CATALOG_FILE'] = catalog_file
    params['MAIN_OUTPUT_FILE'] = target + '.eazypy'

    # Galactic extinction
    params['MW_EBV'] = mw_ebv
    params['SYS_ERR'] = 0.05

    params['Z_STEP'] = 0.0002
    params['Z_MIN'] = np.maximum(zsp - 10 * params['Z_STEP'] * (1 + zsp), 0)
    params['Z_MAX'] = zsp + 10 * params['Z_STEP'] * (1 + zsp)

    params['PRIOR_ABZP'] = 23.9
    params['PRIOR_FILTER'] = 241  # K
    params['PRIOR_FILE'] = 'templates/prior_K_TAO.dat'
    params['TEMPLATES_FILE'] = 'templates/fsps_full/tweak_fsps_QSF_12_v3.param'
    params['FIX_ZSPEC'] = True

    #translate_file = 'zphot.translate'
    translate_file = os.path.join(os.getenv('EAZYCODE'),
                                  'inputs/zphot.translate')
    self = eazy.photoz.PhotoZ(param_file=None,
                              translate_file=translate_file,
                              zeropoint_file=None,
                              params=params,
                              load_prior=True,
                              load_products=False)

    # Now fit the whole catalog
    # Turn off error corrections derived above
    self.efnu = self.efnu_orig * 1

    # Full catalog
    sample = np.isfinite(self.cat['z_spec'])
    t = self.cat
    # sel = (t['xmin']>(x0-size))&(t['ymin']>(y0-size))&(t['xmax']<(x0+size))&(t['ymax']<(y0+size))
    # sample = sel
    self.fit_parallel(self.idx[sample], n_proc=8)

    # Derived parameters (z params, RF colors, masses, SFR, etc.)
    zout, hdu = self.standard_output(rf_pad_width=0.5,
                                     rf_max_err=2,
                                     prior=False,
                                     beta_prior=False,
                                     extra_rf_filters=[272, 273, 274])

    # 'zout' also saved to [MAIN_OUTPUT_FILE].zout.fits

    if plot:
        # Show UVJ diagram
        uv = -2.5 * np.log10(zout['restU'] / zout['restV'])
        vj = -2.5 * np.log10(zout['restV'] / zout['restJ'])
        ssfr = zout['SFR'] / zout['mass']

        plt.scatter(vj,
                    uv,
                    c=np.log10(ssfr),
                    cmap='Spectral',
                    vmin=-13,
                    vmax=-8,
                    alpha=0.5)
        plt.colorbar()
        plt.xlabel(r'$(V-J)_0$')
        plt.ylabel(r'$(U-V)_0$')

        t['x'] = (t['xmin'] + t['xmax']) / 2
        t['y'] = (t['ymin'] + t['ymax']) / 2

        # Av
        fig = plt.figure(figsize=(10, 8))
        plt.scatter(t['x'],
                    t['y'],
                    marker='.',
                    alpha=0.5,
                    c=zout['Av'],
                    cmap='Spectral_r',
                    vmin=0,
                    vmax=3)
        ax = plt.gca()
        ax.set_aspect(1)
        plt.colorbar()

        # sSFR
        fig = plt.figure(figsize=(10, 8))
        plt.scatter(t['x'],
                    t['y'],
                    marker='.',
                    alpha=0.5,
                    c=np.log10(ssfr),
                    cmap='Spectral',
                    vmin=-12,
                    vmax=-8)
        ax = plt.gca()
        ax.set_aspect(1)
        plt.colorbar()

        plt.show()

    if image_space:
        image = pyfits.open(im)
        sci = np.cast[np.float32](image['SCI'].data)
        seg = pyfits.open(seg_im)[0].data
        tab = Table.read(catalog_file)

        # Av
        flux_Av = prep.get_seg_iso_flux(sci, seg, tab, fill=zout['Av'])
        fig = plt.figure(figsize=(10, 8))
        plt.imshow(flux_Av, cmap='Spectral_r', origin='lower')
        ax = plt.gca()
        ax.set_aspect(1)
        plt.colorbar()

        primary_extn = pyfits.PrimaryHDU()
        sci_extn = pyfits.ImageHDU(data=flux_Av,
                                   name='SCI',
                                   header=image[1].header)
        hdul = pyfits.HDUList([primary_extn, sci_extn])
        hdul.writeto('Av_{0}.fits'.format(target), overwrite=True)

        # ssfr
        flux_ssfr = prep.get_seg_iso_flux(sci, seg, tab, fill=np.log10(ssfr))
        fig = plt.figure(figsize=(10, 8))
        plt.imshow(flux_ssfr, cmap='Spectral', origin='lower')
        ax = plt.gca()
        ax.set_aspect(1)
        plt.colorbar()

        primary_extn = pyfits.PrimaryHDU()
        sci_extn = pyfits.ImageHDU(data=flux_ssfr,
                                   name='SCI',
                                   header=image[1].header)
        hdul = pyfits.HDUList([primary_extn, sci_extn])
        hdul.writeto('sSFR_{0}.fits'.format(target), overwrite=True)

        plt.show()

    return zout
示例#3
0
def bin_image(im, tab_in, seg_in, mask_in, bkg_in=None, bg_mask_in=None):
    
    """
    Apply 2D bins specified in "seg_in" to a new image
    
    """ 
    
    from grizli import utils
    from grizli import prep
    import numpy as np
    
    sci_data = im['SCI'].data*1
    var_data = 1/im['WHT'].data
    wht_mask = im['WHT'].data > 0
    
    IS_ACS = sci_data.shape[0] == 2*seg_in.shape[0]
    
    if IS_ACS:
        # ACS
        to_flam = im[1].header['PHOTFLAM']
        to_fnu = 1. #im[1].header['PHOTFNU']
        tab = utils.GTable()
        for c in tab_in.colnames:
            if c[:2] in ['xm', 'ym']:
                tab[c] = 2*tab_in[c]
            else:
                tab[c] = tab_in[c]
        
        sh = sci_data.shape
        mask = np.zeros(sh, dtype=bool)
        seg = np.zeros(sh, dtype=np.int)
        for i in [0,1]:
            for j in [0,1]:
                mask[j::2, i::2] = mask_in
                seg[j::2, i::2] = seg_in
        
    else:
        to_flam = im[0].header['PHOTFLAM']
        to_fnu = im[0].header['PHOTFNU']
        
        tab = tab_in
        mask = mask_in
        seg = seg_in

    if bg_mask_in is None:
        bg_mask = (~mask) & wht_mask & (seg <= 0)
    else:
        bg_mask = bg_mask_in
        
    if bkg_in is None:
        bkg = np.median(sci_data[bg_mask])
    else:
        bkg = bkg_in
        
    sci_data -= bkg
    
    var_data[~wht_mask] = 0
    
    bin_flux, bin_err, bin_area = prep.get_seg_iso_flux(sci_data, seg, tab, err=np.sqrt(var_data))

    image_flux = prep.get_seg_iso_flux(sci_data, seg, tab, fill=bin_flux/bin_area)
    image_err = prep.get_seg_iso_flux(sci_data, seg, tab, fill=bin_err/bin_area)

    image_flux[mask] = sci_data[mask]*1
    image_err[mask] = np.sqrt(var_data)[mask]
    
    res = {}
    res['bin_flux'] = bin_flux
    res['bin_err'] = bin_err
    res['bin_area'] = bin_area
    
    if IS_ACS:
        res['to_flam'] = to_flam
        res['to_fnu'] = to_fnu
        res['image_flux'] = image_flux[0::2, 0::2]*4
        res['image_err'] = image_err[0::2, 0::2]*4
    else:
        res['to_flam'] = to_flam
        res['to_fnu'] = to_fnu
        res['image_flux'] = image_flux
        res['image_err'] = image_err

    res['bkg'] = bkg
    res['bg_mask'] = bg_mask
    
    data_tab = {}
    data_tab['sci'] = sci_data
    data_tab['err'] = np.sqrt(var_data)
    data_tab['mask'] = mask
    
    return res, data_tab