Esempio n. 1
0
    def get_phot_dict(self, ra, dec):
        """
        
        """
        from collections import OrderedDict
        try:
            from .. import utils
        except:
            from grizli import utils

        icat = utils.GTable()
        icat['ra'] = [ra]
        icat['dec'] = [dec]

        rdcat = utils.GTable()
        rdcat['ra'] = self.ra_cat
        rdcat['dec'] = self.dec_cat

        ix, dr = rdcat.match_to_catalog_sky(icat)

        phot = OrderedDict()
        phot['flam'] = self.flam[ix[0], :] * 1.e-19
        phot['eflam'] = self.eflam[ix[0], :] * 1.e-19
        phot['filters'] = self.filters
        phot['tempfilt'] = self.tempfilt
        return phot, ix[0], dr[0]
Esempio n. 2
0
    def get_phot_dict(self, ra, dec):
        """
        Return catalog info for nearest object to supplied coordinates
        
        Returns:
        
        phot - photometry dictionary
        ix   - index in catalog of nearest match
        dr   - distance to nearest match
        """
        from collections import OrderedDict
        try:
            from .. import utils
        except:
            from grizli import utils

        icat = utils.GTable()
        icat['ra'] = [ra]
        icat['dec'] = [dec]

        rdcat = utils.GTable()
        rdcat['ra'] = self.ra_cat
        rdcat['dec'] = self.dec_cat

        ix, dr = rdcat.match_to_catalog_sky(icat)

        phot = OrderedDict()
        apcorr_i = self.apcorr[ix[0]]

        try:
            phot['source'] = self.source_text
        except:
            phot['source'] = 'unknown'

        phot['flam'] = self.flam[ix[0], :] * 1.e-19 * apcorr_i
        phot['eflam'] = self.eflam[ix[0], :] * 1.e-19 * apcorr_i
        phot['filters'] = self.filters
        phot['tempfilt'] = self.tempfilt

        try:
            phot['ext_corr'] = self.ext_corr
        except:
            phot['ext_corr'] = 1

        if self.include_pz & (self.pz is not None):
            pz = (self.zgrid, self.pz[ix[0], :].flatten())
        else:
            pz = None

        phot['pz'] = pz
        try:
            phot['z_spec'] = self.z_spec[ix[0]]
        except:
            phot['z_spec'] = -1

        if not self.include_photometry:
            phot['flam'] = None

        return phot, ix[0], dr[0]
Esempio n. 3
0
def single_pixel_table(mask, start_id=0):
    
    """
    Get individual pixels
    
    """
    
    from grizli import utils
    import numpy as np
    
    sh = mask.shape
    yp,xp = np.indices(sh)
    n_obj = mask.sum()
    
    # id, bin, xmin, xmax, ymin, ymax, npix
    
    tab = utils.GTable()
    tab['id'] = start_id+np.arange(n_obj,dtype=int)
    tab['bin'] = 1
    tab['xmin'] = xp[mask]
    tab['xmax'] = tab['xmin']+1
    tab['ymin'] = yp[mask]
    tab['ymax'] = tab['ymin']+1
    tab['npix'] = 1
    
    return tab
Esempio n. 4
0
def make_visit_fits():
    import glob
    import numpy as np
    from grizli import utils

    visit_files = glob.glob('[egu]*visits.npy')
    visit_files.sort()
    all_visits = []
    products = []
    for file in visit_files:
        visits, groups, info = np.load(file)
        for v in visits:
            has_fp = ('footprints' in v)
            if not has_fp:
                print('No footprint: {0}'.format(v['product']))

            if has_fp & (v['product'] not in products):
                all_visits.append(v)
                products.append(v['product'])

    # WFC3/IR copied to "Exposures" paths
    for visit in all_visits:
        visit['filter'] = visit['product'].split('-')[-1]

    for v in all_visits:
        if v['filter'].startswith('f0') | v['filter'].startswith('f1'):
            #print(v['product'])
            v['awspath'] = [
                'grizli-v1/Exposures/{0}/{1}'.format(f[:4],
                                                     f.split('_')[0])
                for f in v['files']
            ]

    tab = utils.GTable()

    for k in ['product', 'filter']:
        tab[k] = [visit[k] for visit in all_visits]

    coo = np.array([
        np.array(visit['footprint'].centroid.xy).flatten()
        for visit in all_visits
    ])
    tab['ra'] = coo[:, 0]
    tab['dec'] = coo[:, 1]
    tab['nexp'] = [len(visit['files']) for visit in all_visits]

    root = 'candels-july2019'
    root = 'candels-sep2019'

    tab.write(root + '_visits.fits', overwrite=True)
    np.save(root + '_visits.npy', [all_visits])

    os.system(
        'echo "# In https://s3.amazonaws.com/grizli-v1/Mosaics/" > candels-july2019.files.txt; ls candels-july2019* |grep -v files.txt >>  candels-july2019.files.txt'
    )
    os.system(
        'aws s3 sync --exclude "*" --include "candels-july2019*" ./ s3://grizli-v1/Mosaics/ --acl public-read'
    )
Esempio n. 5
0
    def _get_wcs_from_hdrtab(drz_file):
        """
        Read tabulated exposure WCS info from the HDRTAB
        extension of an AstroDrizzle output file
        """
        from shapely.geometry import Polygon, Point
        drz = pyfits.open(drz_file)
        if 'HDRTAB' not in drz:
            print('No HDRTAB extension found in {0}'.format(file))
            return None

        hdr = utils.GTable(drz['HDRTAB'].data)
        wcs = OrderedDict()
        footprint = OrderedDict()

        flt_keys = []
        N = len(hdr)

        if 'CCDCHIP' in hdr.colnames:
            ext_key = 'CCDCHIP'
        else:
            ext_key = 'EXTNAME'

        for i in range(N):
            h = pyfits.Header()
            for c in hdr.colnames:
                try:
                    h[c] = hdr[c][i]
                except:
                    h[c] = 1

            key = (h['ROOTNAME'], h[ext_key])
            flt_keys.append(key)
            wcs[key] = pywcs.WCS(h, relax=True)
            wcs[key].pscale = utils.get_wcs_pscale(wcs[key])

            if 'EXPTIME' in h:
                wcs[key].expweight = h['EXPTIME']
            else:
                wcs[key].expweight = 1

            footprint[key] = Polygon(wcs[key].calc_footprint())

        return flt_keys, wcs, footprint
Esempio n. 6
0
def make_summary_html(output_table='grizli_aws.html', verbose=True):
    import os
    from grizli import utils
    import boto3

    s3 = boto3.resource('s3')

    bucket = s3.Bucket('aws-grivam')

    roots, dates = get_roots(verbose=verbose)

    # Table
    tab = utils.GTable()
    tab['root'] = roots
    tab['modified'] = dates

    tab['Full'] = [
        '<a href=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}/Extractions/{0}-full.html?chinu_max=2&bic_diff_min=30&zwidth1_max=0.01>Full</a>'
        .format(root.replace('+', '%2B')) for root in roots
    ]

    #tab['Best'] = ['<a href=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}/Extractions/{0}-fit.zq.html>Best</a>'.format(root.replace('+','%2B')) for root in roots]

    #tab['footprint'] = ['<a href=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}_footprint.pdf> <img width=400 src=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}_footprint.pdf></a>'.format(root.replace('+','%2B')) for root in roots]

    tab['footprint'] = [
        '<a href=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}_footprint.png> <img height=300 src=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}_footprint.png></a>'
        .format(root.replace('+', '%2B')) for root in roots
    ]

    tab['zhist'] = [
        '<a href=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}/Extractions/{0}_zhist.png> <img height=300 src=https://s3.amazonaws.com/aws-grivam/Pipeline/{0}/Extractions/{0}_zhist.png></a>'
        .format(root.replace('+', '%2B')) for root in roots
    ]

    tab.write_sortable_html(output_table, localhost=False, max_lines=10000)
    print("""
Done: {0}

Sync to s3: aws s3 cp {0} s3://aws-grivam/Pipeline/ --acl public-read
""".format(output_table))

    return tab
Esempio n. 7
0
def get_external_catalog(
        phot,
        filter_file='/usr/local/share/eazy-photoz/filters/FILTER.RES.latest',
        ZP=23.9,
        sys_err=0.3,
        verbose=True,
        external_limits=3,
        timeout=300):
    """
    Fetch photometry from vizier
    """
    import numpy as np

    import astropy.units as u

    try:
        from .. import utils
    except:
        from grizli import utils

    from eazy.filters import FilterFile
    res = FilterFile(filter_file)

    vizier_catalog = list(utils.VIZIER_VEGA.keys())

    ra = np.median(phot['ra'])
    dec = np.median(phot['dec'])
    dr = np.sqrt((phot['ra'] - ra)**2 * np.cos(phot['dec'] / 180 * np.pi)**2 +
                 (phot['dec'] - dec)**2) * 60

    radius = 1.5 * dr.max()  # arcmin
    tabs = utils.get_Vizier_photometry(ra,
                                       dec,
                                       templates=None,
                                       radius=radius * 60,
                                       vizier_catalog=vizier_catalog,
                                       filter_file=filter_file,
                                       MW_EBV=0,
                                       convert_vega=False,
                                       raw_query=True,
                                       verbose=True,
                                       timeout=timeout)

    extern_phot = utils.GTable()
    N = len(phot)

    for t_i in tabs:

        # Match
        if 'RAJ2000' in t_i.colnames:
            other_radec = ('RAJ2000', 'DEJ2000')
        elif 'RA_ICRS' in t_i.colnames:
            other_radec = ('RA_ICRS', 'DE_ICRS')
        else:
            other_radec = ('ra', 'dec')

        idx, dr = phot.match_to_catalog_sky(t_i, other_radec=other_radec)
        if (dr < 2 * u.arcsec).sum() == 0:
            continue

        tab = t_i[dr < 2 * u.arcsec]
        idx = idx[dr < 2 * u.arcsec]

        # Downweight PS1 if have SDSS
        # if (tab.meta['name'] == PS1_VIZIER) & (SDSS_DR12_VIZIER in viz_tables):
        #     continue
        #     err_scale = 1
        # else:
        #     err_scale = 1
        err_scale = 1

        if (tab.meta['name'] == utils.UKIDSS_LAS_VIZIER):
            flux_scale = 1.33
        else:
            flux_scale = 1.

        convert_vega = utils.VIZIER_VEGA[tab.meta['name']]
        bands = utils.VIZIER_BANDS[tab.meta['name']]

        #if verbose:
        #    print(tab.colnames)

        #filters += [res.filters[res.search(b, verbose=False)[0]] for b in bands]

        to_flam = 10**(-0.4 * (48.6)) * 3.e18  # / pivot(Ang)**2

        for ib, b in enumerate(bands):
            f_number = res.search(b, verbose=False)[0] + 1
            filt = res.filters[f_number - 1]
            #filters.append(filt)

            if convert_vega:
                to_ab = filt.ABVega()
            else:
                to_ab = 0.

            fcol, ecol = bands[b]
            #pivot.append(filt.pivot())
            fnu = 10**(-0.4 * (tab[fcol] + to_ab - ZP))
            efnu = tab[ecol] * np.log(10) / 2.5 * fnu * err_scale

            efnu = np.sqrt(efnu**2 + (sys_err * fnu)**2)

            fnu.fill_value = -99
            efnu.fill_value = -99

            comment = 'Filter {0} from {1} (N={2})'.format(
                bands[b][0], t_i.meta['name'], len(idx))
            if verbose:
                print(comment)

            if ((~efnu.mask).sum() > 4) & (external_limits > 0):
                fill = np.percentile(efnu.data[~efnu.mask], [90])
                efill = external_limits * fill
            else:
                fill = -99
                efill = -99

            extern_phot.meta['F{0}'.format(f_number)] = b, comment
            extern_phot['F{0}'.format(f_number)] = fill * np.ones(N)
            extern_phot['F{0}'.format(f_number)][idx] = fnu.filled()

            extern_phot['E{0}'.format(f_number)] = efill * np.ones(N)
            extern_phot['E{0}'.format(f_number)][idx] = efnu.filled()

    return extern_phot
Esempio n. 8
0
def summary_table(tabs=None, output='overlap_summary'):
    import glob
    from collections import OrderedDict
    from astropy.table import Table
    import astropy.table

    try:
        from grizli import utils
        HAS_GRIZLI = True
    except:
        HAS_GRIZLI = False

    if tabs is None:
        tabs = [Table.read(file) for file in glob.glob('*footprint.fits')]

    # for tab in tabs:
    #     tab.remove_column('moving_target')
    # #
    # for tab in tabs:
    #     prop = np.cast[int](tab['proposal_id'])
    #     tab.remove_column('proposal_id')
    #     tab['proposal_id'] = prop

    names, props = parse_overlap_table(tabs[0])
    props = []
    pdict = OrderedDict()
    for name in names:
        pdict[name] = []

    for i in range(len(tabs)):
        print('Parse table ', i)
        n_i, p_i = parse_overlap_table(tabs[i])
        for name in names:
            if name in n_i:
                pdict[name].append(p_i[n_i.index(name)])
            else:
                pdict[name].append('---')

    mtab = Table(pdict)  #rows=props, names=names)
    mtab['RA'].format = '.5f'
    mtab['DEC'].format = '.5f'
    mtab.rename_column('MW_EBV', 'E(B-V)')

    mtab['EclLat'].format = '.1f'
    mtab['EclLon'].format = '.1f'

    mtab['GalLat'].format = '.1f'
    mtab['GalLon'].format = '.1f'

    mtab['AreaG102'].format = '.1f'
    mtab['AreaG141'].format = '.1f'

    mtab['TexpG102'].format = '.1f'
    mtab['TexpG141'].format = '.1f'

    mtab['TperG102'].format = '.1f'
    mtab['TperG141'].format = '.1f'

    # Links
    mast_link = [
        '<a href=https://archive.stsci.edu/hst/search.php?RA={0}&DEC={1}&radius=3.&max_records=5000&sci_aec=S&action=Search>MAST</a>'
        .format(t['RA'], t['DEC']) for t in mtab
    ]
    mtab['MAST'] = mast_link

    fp_link = [
        '<a href={0}_footprint.pdf>Footprint</a>'.format(t['NAME'])
        for t in mtab
    ]
    mtab['Footprint'] = fp_link

    mtab.write('{0}.fits'.format(output), overwrite=True)

    if HAS_GRIZLI:
        gtab = utils.GTable(mtab)
        gtab.write_sortable_html('{0}.html'.format(output),
                                 replace_braces=True,
                                 localhost=False,
                                 max_lines=len(mtab) + 10,
                                 table_id=None,
                                 table_class='display compact',
                                 css=None)

    return gtab
Esempio n. 9
0
def make_visit_fits():
    import glob
    import numpy as np
    from grizli import utils

    visit_files = glob.glob('[egu]*visits.npy')
    visit_files.sort()

    indiv_files = glob.glob('j*visits.npy')
    indiv_files.sort()

    visit_files += indiv_files

    for p in ['grizli-v1-19.12.04_visits.npy', 'grizli-v1-19.12.05_visits.npy', 'grizli-cosmos-v2_visits.npy']:
        if p in visit_files:
            visit_files.pop(visit_files.index(p))

    all_visits = []
    products = []

    for extra in ['candels-july2019_visits.npy', 'grizli-cosmos-v2_visits.npy']:

        extra_visits = np.load(extra)[0]
        extra_products = [v['product'] for v in extra_visits]
        for i, p in enumerate(extra_products):
            if p not in products:
                parent = p.split('_')[0]
                print(parent, p)
                v = extra_visits[i]
                v['parent'] = parent
                v['parent_file'] = extra  # 'candels-july2019_visits.npy'
                all_visits.append(v)
                products.append(p)

    # COSMOS footprint
    cosmos_fp = None
    for i, v in enumerate(extra_visits):
        if v['product'].endswith('f814w'):
            print(v['product'])
            if cosmos_fp is None:
                cosmos_fp = v['footprint'].buffer(1.e-6)
            else:
                cosmos_fp = cosmos_fp.union(v['footprint'])

    for i, file in enumerate(visit_files):
        visits, groups, info = np.load(file)
        print(file, len(visits))
        for v in visits:
            has_fp = ('footprints' in v)
            if not has_fp:
                print('No footprint: {0}'.format(v['product']))

            if has_fp & (v['product'] not in products):
                all_visits.append(v)
                v['parent'] = file.split("_visits")[0].split('-')[-1]
                v['first'] = v['files'][0]
                v['parent_file'] = file
                products.append(v['product'])

    for v in all_visits:
        v['filter'] = v['product'].split('-')[-1]
        v['first'] = v['files'][0]

    # File dictionary
    all_files = []
    file_products = []

    for v in all_visits:
        all_files.extend(v['files'])
        file_products.extend([v['product']]*len(v['files']))

    # duplicates?? seem to be in GOODS-S.
    # Exclude them in all but the first product that contains them for now
    if True:
        _un = np.unique(all_files, return_counts=True, return_index=True, return_inverse=True)
        un_file, un_index, un_inv, un_count = _un
        dup = un_count > 1
        dup_files = un_file[dup]
        for file in dup_files:
            prods = list(np.array(file_products)[np.array(all_files) == file])
            for prod in prods[1:]:
                i = products.index(prod)
                v = all_visits[i]
                j = v['files'].index(file)
                print(file, v['parent'], prod, i, j)
                pj = all_visits[i]['files'].pop(j)
                pj = all_visits[i]['footprints'].pop(j)
                if 'awspath' in all_visits[i]:
                    pj = all_visits[i]['awspath'].pop(j)

            #print(file, prods[-1])

    # WFC3/IR copied to "Exposures" paths in CANDELS fields
    for v in all_visits:
        if v['parent_file'] == 'grizli-cosmos-v2_visits.npy':
            continue

        if v['parent_file'].startswith('j'):
            v['awspath'] = ['grizli-v1/Pipeline/{0}/Prep'.format(v['parent']) for f in v['files']]

        if v['filter'].startswith('f0') | v['filter'].startswith('f1'):
            # print(v['product'])
            v['awspath'] = ['grizli-v1/Exposures/{0}/{1}'.format(f[:4], f.split('_')[0]) for f in v['files']]

    # Empty visits, seems to be from duplicates above and mostly in CANDELS
    nexp = np.array([len(visit['files']) for visit in all_visits])
    for i in np.where(nexp == 0)[0][::-1]:
        v_i = all_visits.pop(i)
        print(i, v_i['product'])
        products.pop(i)

    tab = utils.GTable()

    for k in ['parent', 'product', 'filter', 'first']:
        tab[k] = [visit[k] for visit in all_visits]

    coo = np.array([np.array(visit['footprint'].centroid.xy).flatten() for visit in all_visits])
    tab['ra'] = coo[:, 0]
    tab['dec'] = coo[:, 1]
    tab['nexp'] = [len(visit['files']) for visit in all_visits]
    tab['bounds'] = [np.array(v['footprint'].bounds) for v in all_visits]

    root = 'candels-july2019'
    root = 'candels-sep2019'
    root = 'grizli-v1-19.12.04'
    root = 'grizli-v1-19.12.05'

    tab.write(root+'_visits.fits', overwrite=True)
    np.save(root+'_visits.npy', [all_visits])

    # os.system('echo "# In https://s3.amazonaws.com/grizli-v1/Mosaics/" > candels-july2019.files.txt; ls candels-july2019* |grep -v files.txt >>  candels-july2019.files.txt')
    #os.system('aws s3 sync --exclude "*" --include "candels-july2019*" --include "grizli-v1-19.12.04*" ./ s3://grizli-v1/Mosaics/ --acl public-read')
    os.system('echo "# In https://s3.amazonaws.com/grizli-v1/Mosaics/" > {0}.files.txt; ls {0}* |grep -v files.txt >>  {0}.files.txt'.format(root))

    os.system('aws s3 sync --exclude "*" --include "{0}*" ./ s3://grizli-v1/Mosaics/ --acl public-read'.format(root))

    if False:
        from shapely.geometry import Point
        candels = utils.column_values_in_list(tab['parent'], ['j141956p5255', 'j123656p6215', 'j033236m2748', 'j021732m0512', 'j100012p0210'])
        cosmos = np.array([v['footprint'].intersection(cosmos_fp).area > 0 for v in all_visits])

        extra = candels
        extra = ~(candels | cosmos)

        # Area
        filter_polys = {}

        filt = 'f160w'
        for filt in np.unique(tab['filter']):
            print(filt)
            if filt in filter_polys:
                print(filt)
                continue

            poly = None
            count = 0

            # Dec strips
            di = np.arange(-90, 91, 5)
            strips = []
            for i in range(len(di)-1):
                strip = (tab['dec'] > di[i]) & (tab['dec'] <= di[i+1]) & (tab['filter'] == filt)
                strip &= extra

                if strip.sum() == 0:
                    continue

                indices = np.arange(len(tab))[strip]

                poly = None
                for j in indices:
                    v = all_visits[j]
                    if v['filter'] != filt:
                        continue

                    # for fp in v['footprints']:
                    for fp in [v['footprint']]:
                        count += 1
                        #print(i, v['product'], count)
                        if poly is None:
                            poly = fp.buffer(1.e-6)
                        else:
                            poly = poly.union(fp.buffer(1.e-6))

                poly.dec = di[i]+2.5
                strips.append(poly)

            if len(strips) == 0:
                filter_polys[filt] = Point(0, 0).buffer(1.e-6)
                continue

            full = strips[0].buffer(1.e-6)
            for strip in strips[1:]:
                full = full.union(strip.buffer(1.e-6))

            filter_polys[filt] = full

        optical = filter_polys['f606w'].union(filter_polys['f814w'])
        optical = optical.union(filter_polys['f850lp'])
        optical = optical.union(filter_polys['f775w'])

        yband = filter_polys['f098m'].union(filter_polys['f105w'])

        visy = optical.union(yband)

        jband = filter_polys['f125w']
        jband = jband.union(filter_polys['f110w'])

        hband = filter_polys['f140w'].union(filter_polys['f160w'])

        filter_polys[r'$\mathrm{opt} = i_{775} | i_{814} | z_{850}$'] = optical
        filter_polys[r'$\mathrm{opty} = \mathrm{opt} | Y$'] = visy
        filter_polys[r'$Y = y_{098 } | y_{105}$'] = yband
        filter_polys[r'$J = j_{110} | j_{125}$'] = jband
        filter_polys[r'$H = h_{140} | h_{160}$'] = hband

        ydrop = visy.intersection(jband)
        ydrop = ydrop.intersection(hband)
        filter_polys[r'$Y-\mathrm{drop} = (\mathrm{opt} | Y) + J + H$'] = ydrop

        yj = yband.union(jband)
        jdrop = yj.intersection(hband)
        filter_polys[r'$J-\mathrm{drop} = (Y | J) + H$'] = jdrop

        for filt in filter_polys:
            full = filter_polys[filt]
            try:
                areas = [f.area*np.cos(np.array(f.centroid.xy).flatten()[1]/180*np.pi) for f in full]
            except:
                try:
                    areas = [f.area*np.cos(np.array(f.centroid.xy).flatten()[1]/180*np.pi) for f in [full]]
                except:
                    areas = [0]

            full.total_area = np.sum(areas)
            print(filt, filter_polys[filt].total_area)

        ta = utils.GTable()
        ta['filter'] = [f.upper() for f in filter_polys]
        ta['area'] = [filter_polys[f].total_area*3600 for f in filter_polys]
        ta['area'].format = '.0f'

        # Compare areas
        h = fields['a_wfc3_ir_f160w'] > 0
        for root, aa in zip(fields['field_root'][h], fields['a_wfc3_ir_f160w'][h]):
            sel = (tab['filter'] == 'f160w') & (tab['parent'] == root)
            if sel.sum() > 0:
                indices = np.where(sel)[0]
                a = all_visits[indices[0]]['footprint'].buffer(1.e-6)
                for i in indices:
                    a = a.union(all_visits[i]['footprint'])

                a_i = a.area*3600*np.cos(tab['dec'][indices[0]]/180*np.pi)
                print(root, aa, a_i, a_i/aa)
Esempio n. 10
0
def full_hawki_query(rd=None, query_result=None, eso=None):
    """
    Query all HAWKI observations....
    """
    import os
    import numpy as np
    import matplotlib.pyplot as plt

    from shapely.geometry import Polygon, Point
    from descartes import PolygonPatch
    from shapely import affinity

    from grizli import utils
    from mastquery import query, overlaps

    if eso is None:
        eso = get_eso()

    if query_result is None:
        _, kwargs, res = full_query(eso=eso)
    else:
        kwargs, res = query_result

    # surveys = 092.A-0472

    # CHArGE fields
    from grizli.aws import db
    import astropy.units as u
    from astropy.coordinates import SkyCoord

    engine = db.get_db_engine()
    if rd is None:
        ch = db.from_sql(
            "SELECT field_root, field_ra as ra, field_dec as dec, log FROM charge_fields where log LIKE '%%Finish%%'",
            engine)
    else:
        ra, dec = rd
        ch = utils.GTable()
        ch['ra'] = [ra]
        ch['dec'] = [dec]

        ch['field_root'] = [
            utils.radec_to_targname(
                ra=ra,
                dec=dec,
                round_arcsec=(4, 60),
                precision=2,
                targstr='j{rah}{ram}{ras}{sign}{ded}{dem}',
                header=None,
            )
        ]

    idx, dr = ch.match_to_catalog_sky(res)

    has_hawki = dr < 10 * u.arcmin

    import scipy.spatial
    ch_rd = SkyCoord(ch['ra'], ch['dec'], unit='deg')
    ch_xyz = ch_rd.cartesian.get_xyz().value
    ctree = scipy.spatial.cKDTree(ch_xyz.T)

    hawki_rd = SkyCoord(res['RA'], res['DEC'], unit='deg')
    hawki_xyz = hawki_rd.cartesian.get_xyz().value
    htree = scipy.spatial.cKDTree(hawki_xyz.T)

    r = 30. / 60 / 360. * 2

    tr = ctree.query_ball_tree(htree, r)
    n_hawki = np.array([len(t) for t in tr])

    # Figures
    idx = np.where(n_hawki > 0)[0]

    xsize = 5
    px, py = 0.45, 0.2

    for i in idx:
        field = ch['field_root'][i]
        print(i, field)
        if os.path.exists(f'{field}_hawki.png'):
            continue

        field = ch['field_root'][i]

        #tab = utils.read_catalog(f'../FieldsSummary/{field}_footprint.fits')
        if os.path.exists(f'{field}_footprint.fits'):
            tab = utils.read_catalog(f'{field}_footprint.fits')
            meta = tab.meta

            xr = (meta['XMIN'], meta['XMAX'])
            yr = (meta['YMIN'], meta['YMAX'])
            ra, dec = meta['BOXRA'], meta['BOXDEC']

            cosd = np.cos(dec / 180 * np.pi)
            dx = (xr[1] - xr[0]) * cosd * 60
            dy = (yr[1] - yr[0]) * 60

            box_width = np.maximum(dx, dy)
            #query_size = np.maximum(min_size, box_width/2)/60.

            p_hst = None
            p_ir = None

            for j, fph in enumerate(tab['footprint']):
                ps, is_bad, poly = query.instrument_polygon(tab[j])
                if not hasattr(ps, '__len__'):
                    ps = [ps]

                for p in ps:
                    p_j = Polygon(p).buffer(0.001)
                    if p_hst is None:
                        p_hst = p_j
                    else:
                        p_hst = p_hst.union(p_j)

                    if tab['instrument_name'][j] == 'WFC3/IR':
                        if p_ir is None:
                            p_ir = p_j
                        else:
                            p_ir = p_ir.union(p_j)
        else:
            cosd = np.cos(dec / 180 * np.pi)
            p_hst = None
            p_ir = None

        ##############################
        fig = plt.figure(figsize=[6, 6])

        ax = fig.add_subplot(111)
        ax.scatter(ra, dec, zorder=1000, marker='+', color='k')

        # HAWKI
        h_p = None
        for j in tr[i]:
            p = Point(res['RA'][j], res['DEC'][j]).buffer(4.1 / 60)
            p = affinity.scale(p, xfact=1. / cosd)

            # ax.add_patch(PolygonPatch(p, color='r', alpha=0.1))
            x, y = p.boundary.xy
            ax.plot(x, y, color=utils.MPL_COLORS['r'], alpha=0.05)

            if h_p is None:
                h_p = p
            else:
                h_p = h_p.union(p)

        # If overlap between hawki and HST, query all exposures
        if p_hst is not None:
            hawki_overlap = h_p.intersection(p_hst)
            hawki_un = h_p.union(p_hst)

            if not hasattr(p_hst, '__len__'):
                p_hst = [p_hst]

            if not hasattr(h_p, '__len__'):
                h_p = [h_p]

            for p in p_hst:
                #ax.add_patch(PolygonPatch(p, color='k', alpha=0.2))
                if not hasattr(p.boundary, '__len__'):
                    bs = [p.boundary]
                else:
                    bs = p.boundary

                for b in bs:
                    x, y = b.xy
                    ax.plot(x, y, color=utils.MPL_COLORS['gray'], alpha=0.3)
        else:
            hawki_overlap = h_p
            if not hasattr(h_p, '__len__'):
                h_p = [h_p]

        if p_ir is not None:
            if not hasattr(p_ir, '__len__'):
                p_ir = [p_ir]

            for p in p_ir:
                ax.add_patch(
                    PolygonPatch(p, color=utils.MPL_COLORS['gray'], alpha=0.2))
                x, y = p.boundary.xy
                ax.plot(x, y, color=utils.MPL_COLORS['gray'], alpha=0.3)

        for p in h_p:
            ax.add_patch(
                PolygonPatch(p, color=utils.MPL_COLORS['r'], alpha=0.2))

        targets = [
            '{0}  {1}'.format(res['ProgId'][j], res['Object'][j])
            for j in tr[i]
        ]
        for j, targ in enumerate(np.unique(targets)):
            ixj = np.where(np.array(targets) == targ)[0]
            expt = res['DET NDIT'] * res['DET DIT'] * res['TPL NEXP']

            ax.text(0.02,
                    0.98 - j * 0.03,
                    '{0} {1:.1f}'.format(targ, expt[tr[i]][ixj].sum() / 3600.),
                    ha='left',
                    va='top',
                    transform=ax.transAxes,
                    fontsize=7)

        ax.set_aspect(1. / cosd)
        ax.set_title(field)
        ax.grid()

        #xsize = 4

        dx = np.diff(ax.get_xlim())[0] * cosd * 60
        dy = np.diff(ax.get_ylim())[0] * 60

        fig.set_size_inches(xsize * np.clip(dx / dy, 0.2, 5) + px, xsize + py)
        ax.set_xlim(ax.get_xlim()[::-1])
        overlaps.draw_axis_labels(ax=ax, nlabel=3)

        fig.tight_layout(pad=0.5)
        fig.savefig(f'{field}_hawki.png', dpi=120)
        plt.close('all')

        if (hawki_overlap.area >
                0.0) & (not os.path.exists(f'{field}_hawki.fits')):

            kws = {}
            for k in kwargs:
                kws[k] = kwargs[k].copy()

            kws['column_filters'].pop('tpl_nexp')
            kws['column_filters'].pop('tpl_expno')

            _res = eso.query_instrument('hawki',
                                        pi_coi_name='PI_only',
                                        coord1=ra,
                                        coord2=dec,
                                        box='00 30 00',
                                        **kws)

            if len(_res) > 0:
                print('{0} datasets'.format(len(_res)))
                _res['PI'] = [p.split('/')[0].strip() for p in _res['PI/CoI']]
                _res.write(f'{field}_hawki.fits', overwrite=True)
Esempio n. 11
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
Esempio n. 12
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
Esempio n. 13
0
def spline_sfh():
    """
    Generate a template set with spline-basis SFHs
    """
    import os

    import numpy as np
    import matplotlib.pyplot as plt

    from grizli.utils import bspline_templates
    import eazy.sps

    # Grid encompassing FSPS.log_age
    step = 0.022
    ages = 10**np.arange(np.log10(3.e-4), np.log10(14.12) + step, step)

    ages = np.arange(3.e-4, 14.127, 0.001)

    # Spline range between tmin, tmax
    tmin, tmax, Ns = 0.02, 8, 7

    # For Grid
    tmin, tmax, Ns = 0.03, 9, 21

    spl = bspline_templates(ages,
                            get_matrix=True,
                            log=True,
                            df=Ns,
                            clip=0.,
                            minmax=(np.log(tmin), np.log(tmax)))

    Na = len(ages)

    # Log-normals
    centers = [0.03, 0.1, 0.3, 0.8, 1.4, 3., 8.]
    widths = [0.21, 0.21, 0.21, 0.08, 0.08, 0.21, 0.21]

    centers = [0.03, 0.10, 0.25, 0.50, 0.8, 1.6, 4.]
    widths = [0.17, 0.17, 0.17, 0.09, 0.09, 0.17, 0.17]

    # For grid
    if 0:
        centers = [
            0.03, 0.065, 0.1, 0.2, 0.3, 0.55, 0.8, 1.1, 1.4, 2.2, 3., 5., 8.
        ]
        widths = np.diff(np.log10(centers)) / 2.35
        widths = np.append([widths[0]], widths)

    Ng = len(centers)
    gau = np.zeros((Na, Ng))
    for i in range(Ng):
        log_age = np.log10(ages / centers[i])
        w = widths[i]
        gau[:, i] = 1. / np.sqrt(2 * np.pi * w**2) * np.exp(
            -log_age**2 / 2 / w**2)

    spl = gau

    age100 = ages <= 0.1

    sp = eazy.sps.ExtendedFsps(logzsol=0,
                               zcontinuous=True,
                               add_neb_emission=True,
                               sfh=4)

    sp.set_fir_template()
    #sp.set_dust(dust_obj_type='KC13')
    #sp.params['dust_index'] = 0. #-0.3
    sp.set_dust(dust_obj_type='WG00x')
    sp.params['imf_type'] = 1.
    sp.get_spectrum(tage=0.1)

    N = spl.shape[1]
    vband = ["v"]
    ssfr = np.zeros(N)

    logz = np.array([-1., -0.5, 0., 0., 0., 0., 0.])
    logu = np.array([-1.5, -2.0, -2.5, -2.5, -2.5, -2.5, -2.5])
    dusts = [[0.02, 0.5], [0.02, 0.5, 1.0, 2.0, 3.0, 5.], [0.02, 1., 2.0],
             [0.02, 1., 2.0], [0.02], [0.02], [0.02]]

    # for i in [0,1,2,3,4]:
    #     dusts[i] = list(np.arange(0.2, 3.05-0.25*i, 0.1))

    # Full grid
    if N > 7:
        dusts = [[
            0.02, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4., 5., 6., 7., 8., 10., 12
        ]] * N
        logz = np.zeros(N)
        logu = np.zeros(N) - 2.5
        logz[:2] = -1.
        logu[:2] = -1.5

    bands = ['u', 'v', '2mass_j', 'i1500', 'i2800']
    uvj_mags = np.zeros((N, len(bands)))
    band_ages = np.zeros((N, len(bands)))

    _ = sp.get_spectrum()
    fsps_ages = 10**(sp.log_age - 9)
    from grizli.utils_c.interp import interp_conserve_c

    norm_sfh = spl.T * 0.
    ysfh = np.ones((N, len(fsps_ages)))

    # 30 Myr
    t0 = 0.03
    end_age = np.zeros(N)
    end_clip = 1.e-3

    sfh_interp = norm_sfh * 0.

    for i in range(N):
        sfh = spl.T[i, :] * 1.
        sfh_t0 = np.interp(t0, ages, sfh)
        #sfh[ages < t0] = sfh_t0
        sfh_i = sfh / np.trapz(sfh, ages * 1.e9)

        # Evaluate tage where sfr is down by some factor from the max
        if sfh[-1] / sfh.max() > end_clip:
            tstart = ages[-1]
        else:
            tstart = ages[sfh / sfh.max() > end_clip].max()

        end_age[i] = tstart
        #end_age[i] = 14.12 #ages.max()

        # Constant SFR below t0 (30 Myr)
        sfr0 = np.interp(t0, ages, sfh_i)
        sfh_i[ages < t0] = sfr0
        sfr_min = sfh_i.max() / 1000.
        imax = np.argmax(sfh_i)
        sfh_i[(sfh_i < sfr_min) & (ages < ages[imax])] = sfr_min

        if 1:
            # Now evaluate SFH in "forward" direction,rather than lookback
            tforward = end_age[i] - ages[::-1]
            clip = tforward > 0
            sfh_i[~clip[::-1]] = sfr_min
            norm_sfh[i, :] = sfh_i * 1.

            sfh = np.interp(ages,
                            tforward,
                            norm_sfh[i, ::-1],
                            left=0.,
                            right=sfr0)  #, integrate=0)
            sfh[sfh == 0] = sfr_min
            sfh_interp[i, :] = sfh
            plt.plot(ages, sfh)
        else:
            sfh_interp[i, :] = sfh_i[::-1]
            norm_sfh[i, :] = sfh_i * 1.
            plt.plot(ages, sfh_i)

        sp.params['sfh'] = 3
        sp.set_tabular_sfh(ages, sfh_interp[i, :])
        sp.params['logzsol'] = logz[i]
        sp.params['gas_logz'] = logz[i]
        sp.params['gas_logu'] = logu[i]

        sp.params['compute_light_ages'] = True
        band_ages[i, :] = sp.get_mags(tage=end_age[i], bands=bands)

        sp.params['compute_light_ages'] = False
        uvj_mags[i, :] = sp.get_mags(tage=end_age[i], bands=bands)
        ssfr[i] = sp.sfr100 / sp.stellar_mass

    if False:
        #plt.figure()
        plt.plot(uvj_mags[:, 1] - uvj_mags[:, 2],
                 uvj_mags[:, 0] - uvj_mags[:, 1],
                 color='w',
                 alpha=1.,
                 zorder=100)
        plt.plot(uvj_mags[:, 1] - uvj_mags[:, 2],
                 uvj_mags[:, 0] - uvj_mags[:, 1],
                 color='0.5',
                 alpha=0.5,
                 zorder=101)
        plt.scatter(uvj_mags[:, 1] - uvj_mags[:, 2],
                    uvj_mags[:, 0] - uvj_mags[:, 1],
                    c=np.log10(np.maximum(ssfr, 1.e-12)),
                    vmin=-12,
                    vmax=-8,
                    zorder=1000,
                    marker='s',
                    s=100,
                    edgecolor='w')

    ### Make all templates
    res = eazy.filters.FilterFile('FILTER.RES.latest')
    uvj_res = [res[153], res[155], res[161]]
    breakme = False

    templates = []
    sp.params['dust2'] = 0.
    sp.params['sfh'] = 3.
    sp.params['compute_light_ages'] = False
    kwargs = {'scale_lyman_series': 0.1}

    plt.figure()

    for i in range(N):
        #sp.set_tabular_sfh(ages, sfh_interp[i,:])
        sp.set_tabular_sfh(ages, sfh_interp[i, :])

        sp.params['logzsol'] = logz[i]
        sp.params['gas_logz'] = logz[i]
        sp.params['gas_logu'] = logu[i]

        ssfr_i = sp.sfr100 / sp.stellar_mass

        for Av in dusts[i]:
            templ = sp.get_full_spectrum(tage=end_age[i],
                                         Av=Av,
                                         get_template=True,
                                         set_all_templates=False,
                                         **kwargs)

            templ.ageV = band_ages[i, 1]
            jflux = templ.integrate_filter(uvj_res[2], flam=True)
            templates.append(templ)
            plt.plot(templ.wave,
                     templ.flux / jflux,
                     label=templ.name,
                     alpha=0.8)

        if (i == 0) & breakme:
            break

    plt.loglog()

    fig = plt.figure()
    plt.scatter(vj[sel],
                uv[sel],
                c=np.log10(zout['SFR'] / zout['mass'])[sel],
                vmin=-12,
                vmax=-8)
    uvj = np.array(
        [templ.integrate_filter_list(uvj_res) for templ in templates])
    ssfr_temp = np.array([
        templ.meta['sfr100'] / templ.meta['stellar_mass']
        for templ in templates
    ])
    plt.scatter(-2.5 * np.log10(uvj[:, 1] / uvj[:, 2]),
                -2.5 * np.log10(uvj[:, 0] / uvj[:, 1]),
                c=np.log10(ssfr_temp),
                vmin=-12,
                vmax=-8,
                marker='s',
                edgecolor='w',
                s=100)

    # Try NMF decomposition
    if False:
        from sklearn.decomposition import NMF
        model = NMF(n_components=5,
                    init='nndsvda',
                    random_state=0,
                    verbose=True,
                    solver='cd',
                    tol=1.e-6,
                    alpha=0.01,
                    beta_loss='frobenius',
                    max_iter=100000)
        clip = (templ.wave > 2500) & (templ.wave < 1.6e4)
        X = [
            templ.flux / (uvj[i, 1] * 3.e18 / 5500**2)
            for i, templ in enumerate(templates)
        ]
        dust_array = np.hstack(dusts)
        ix = np.array([1, 3, 4, 5, 6, 9, 10, 12, 13])
        ix = np.where((dust_array > 0.1) & (dust_array < 4))[0]

        W = model.fit_transform(np.array(X)[ix, clip].T)
        H = model.components_
        uvjr = H.dot((uvj.T / uvj[:, 1]).T[ix, :])

        plt.scatter(-2.5 * np.log10(uvj[ix, 1] / uvj[ix, 2]),
                    -2.5 * np.log10(uvj[ix, 0] / uvj[ix, 1]),
                    c=np.log10(ssfr_temp)[ix],
                    vmin=-12,
                    vmax=-8,
                    marker='s',
                    edgecolor='r',
                    s=100)
        plt.scatter(-2.5 * np.log10(uvjr[:, 1] / uvjr[:, 2]),
                    -2.5 * np.log10(uvjr[:, 0] / uvjr[:, 1]),
                    vmin=-12,
                    vmax=-8,
                    marker='v',
                    edgecolor='w',
                    s=100,
                    alpha=0.8)

    # Write templates
    if N > 8:
        param_file = 'templates/spline_templates/spline.grid.param'
    else:
        param_file = 'templates/spline_templates/spline.param'

    fp = open(param_file, 'w')
    for i, templ in enumerate(templates):
        tab = templ.to_table()
        tab.meta['ageV'] = templ.ageV
        name = 'spline_age{0:4.2f}_av{1:3.1f}'.format(tab.meta['ageV'],
                                                      tab.meta['Av'])
        line = f'{i+1} templates/spline_templates/{name}.fits 1.0'
        print(line)
        fp.write(line + '\n')
        tab.write(f'templates/spline_templates/{name}.fits', overwrite=True)

    fp.close()

    # Metadata
    cols = ('file', 'Av', 'mass', 'Lv', 'sfr', 'LIR', 'energy_abs', 'ageV')
    rows = []
    for i, templ in enumerate(templates):
        vflux = templ.integrate_filter(uvj_res[1], flam=False)
        Lv = vflux * 3.e18 / uvj_res[1].pivot
        tab = templ.to_table()
        name = 'spline_age{0:4.2f}_av{1:3.1f}'.format(templ.ageV,
                                                      templ.meta['Av'])
        row = [
            name, templ.meta['Av'], templ.meta['stellar_mass'], Lv,
            templ.meta['sfr100'], templ.meta['energy_absorbed'],
            templ.meta['energy_absorbed'], templ.ageV
        ]
        rows.append(row)

    par = utils.GTable(names=cols, rows=rows)
    for line in ['Ha', 'O3', 'Hb', 'O2', 'Lya']:
        par['line_flux_' + line] = 0.
        par['line_C_' + line] = 0.
        par['line_EW_' + line] = 0.

    par.write(param_file + '.fits', overwrite=True)

    # color space spanned by random draws
    NT = len(templates)
    rnd = 10**(np.random.rand(1000 * NT, NT) - 3)
    for i in range(NT):
        rnd[i * 1000:(i + 1) * 1000, i] = 1.

    uvjr = rnd.dot((uvj.T / uvj[:, 0]).T)
    plt.scatter(-2.5 * np.log10(uvjr[:, 1] / uvjr[:, 2]),
                -2.5 * np.log10(uvjr[:, 0] / uvjr[:, 1]),
                c='k',
                marker='.',
                alpha=0.1)

    # Interpolation not working?
    for i in range(N):
        sp.set_tabular_sfh(ages, sfh_interp[i, :])

        #sp.set_tabular_sfh(fsps_ages, ysfh[i,:])
        _ = sp.get_spectrum()

        if 0:
            # Show in lookback time
            plt.plot(ages, norm_sfh[i, :], color='r', alpha=0.5)
            plt.plot(end_age[i] - 10**(sp.log_age - 9),
                     sp.sfr,
                     color='k',
                     alpha=0.5)
            plt.plot(end_age[i] - 10**(sp.log_age - 9),
                     ysfh[i, :],
                     color='g',
                     alpha=0.5)
            plt.vlines(end_age[i], 1.e-30, 10, color='b', alpha=0.5)
            sp.get_spectrum(tage=end_age[i], zmet=None)
            plt.scatter(0.01, sp.sfr, marker='o', color='b')
        else:
            _ = sp.get_spectrum()
            plt.plot(10**(sp.log_age - 9), sp.sfr, color='k', alpha=0.5)
            plt.plot(end_age[i] - ages, norm_sfh[i, :], color='r', alpha=0.5)
            plt.vlines(end_age[i], 1.e-30, 10, color='b', alpha=0.5)
            sp.get_spectrum(tage=end_age[i], zmet=None)
            plt.scatter(end_age[i], sp.sfr, marker='o', color='b')

            #_ = sp.get_spectrum()
            #plt.plot(10**(sp.log_age-9), sp.sfr/np.interp(end_age[i], fsps_ages, sp.sfr)*np.interp(end_age[i], end_age[i]-ages[::-1], norm_sfh[i,::-1]), alpha=0.5)

    #####################
    # Do light-weighted ages add linearly? - YES!
    ij = [1, 3]
    coeffs = np.array([0.2, 0.5])

    sfh = sfh_i * 0.
    for k in range(len(ij)):
        i = ij[k]
        sfh += coeffs[k] * spl.T[i, :] / np.trapz(spl.T[i, :], ages * 1.e9)

    sp.set_tabular_sfh(13 - ages[::-1], sfh[::-1])
    sp.params['compute_light_ages'] = True
    combined_age = sp.get_mags(tage=13, bands=vband)

    vflux = 10**(-0.4 * uvj_mags[ij, 1])
    c_norm = (coeffs * vflux)
    c_norm /= c_norm.sum()
    coeffs_age = vband_ages[ij].dot(c_norm)
    print(combined_age, coeffs_age)
Esempio n. 14
0
def irac_mosaics(root='j000308m3303', home='/GrizliImaging/', pixfrac=0.2, kernel='square', initial_pix=1.0, final_pix=0.5, pulldown_mag=15.2, sync_xbcd=True, skip_fetch=False, radec=None, mosaic_pad=2.5, drizzle_ref_file='', run_alignment=True, assume_close=True, bucket='grizli-v1', aor_query='r*', mips_ext='[_e]bcd.fits', channels=['ch1','ch2','ch3','ch4','mips1'], drz_query='r*', sync_results=True, ref_seg=None, min_frame={'irac':5, 'mips':1.0}, med_max_size=500e6, stop_at='', make_psf=True, **kwargs):
    """
    stop_at: preprocess, make_compact
    
    """
    
    from grizli import utils

    from . import irac
    from .utils import get_wcslist, fetch_irac
    
    PATH = os.path.join(home, root)
    try:
        os.mkdir(PATH)
    except:
        pass

    os.chdir(PATH)
        
    if not skip_fetch:
        # Fetch IRAC bcds
        if not os.path.exists(f'{root}_ipac.fits'):
            os.system(f'wget https://s3.amazonaws.com/{bucket}/IRAC/{root}_ipac.fits')
    
        res = fetch_irac(root=root, path='./', channels=channels)
        
        if res in [False, None]:
            # Nothing to do
            make_html(root, bucket=bucket)

            print(f'### Done: \n https://s3.amazonaws.com/{bucket}/Pipeline/{root}/IRAC/{root}.irac.html')

            utils.log_comment(f'/tmp/{root}.success', 'Done!', 
                              verbose=True, show_date=True)
            return True
            
    # Sync CHArGE HST images
    os.system(f'aws s3 sync s3://{bucket}/Pipeline/{root}/Prep/ ./ '
              f' --exclude "*" --include "{root}*seg.fits*"'
              f' --include "{root}-ir_drz*fits*"'
              f' --include "{root}*psf.fits*"'
              f' --include "{root}-f[01]*_drz*fits.gz"'
              f' --include "{root}*phot.fits"')
    
    # Drizzle properties of the preliminary mosaic
    #pixfrac, pix, kernel = 0.2, 1.0, 'square'       
    
    # Define an output WCS aligned in pixel phase to the HST mosaic ()

    if not os.path.exists('ref_hdu.fits'):
        wcslist = get_wcslist(skip=-500)
        out_hdu = utils.make_maximal_wcs(wcslist, pixel_scale=initial_pix, theta=0, pad=5, get_hdu=True, verbose=True)

        # Make sure pixels align
        ref_file = glob.glob('{0}-f[01]*_drz_sci.fits*'.format(root))
        if len(ref_file) == 0:
            os.system(f'aws s3 sync s3://{bucket}/Pipeline/{root}/Prep/ ./ '
                      f' --exclude "*"'
                      f' --include "{root}-f[678]*_dr*fits.gz"')
            
            ref_file = glob.glob('{0}-f[678]*_dr*_sci.fits*'.format(root))
        
        ref_file = ref_file[-1]

        print(f'\nHST reference image: {ref_file}\n')

        ref_hdu = pyfits.open(ref_file)[0].header
        ref_filter = utils.get_hst_filter(ref_hdu).lower()

        ref_wcs = pywcs.WCS(ref_hdu)
        ref_rd = ref_wcs.all_pix2world(np.array([[-0.5, -0.5]]), 0).flatten()
        target_phase = np.array([0.5, 0.5])#/(pix/0.1)
        for k in ['RADESYS', 'LATPOLE', 'LONPOLE']:
            out_hdu.header[k] = ref_hdu[k]

        # Shift CRVAL to same tangent point
        out_wcs = pywcs.WCS(out_hdu.header)
        out_xy = out_wcs.all_world2pix(np.array([ref_wcs.wcs.crval]), 1).flatten()
        out_hdu.header['CRVAL1'], out_hdu.header['CRVAL2'] = tuple(ref_wcs.wcs.crval)
        out_hdu.header['CRPIX1'], out_hdu.header['CRPIX2'] = tuple(out_xy)

        # Align integer pixel phase
        out_wcs = pywcs.WCS(out_hdu.header)
        out_xy = out_wcs.all_world2pix(np.array([ref_rd]), 0).flatten()
        xy_phase = out_xy - np.floor(out_xy)
        new_crpix = out_wcs.wcs.crpix - (xy_phase - target_phase)
        out_hdu.header['CRPIX1'], out_hdu.header['CRPIX2'] = tuple(new_crpix)
        out_wcs = pywcs.WCS(out_hdu.header)

        out_hdu.writeto('ref_hdu.fits', output_verify='Fix')

    else:
        out_hdu = pyfits.open('ref_hdu.fits')[1]
    
    ########
    
    files = []
    for ch in channels:
        if 'mips' in ch:
            mc = ch.replace('mips','ch')
            files += glob.glob(f'{aor_query}/{mc}/bcd/SPITZER_M*{mips_ext}')
            files += glob.glob(f'{aor_query}/{mc}/bcd/SPITZER_M*xbcd.fits.gz')
        else:
            files += glob.glob(f'{aor_query}/{ch}/bcd/SPITZER_I*cbcd.fits')
            files += glob.glob(f'{aor_query}/{ch}/bcd/SPITZER_I*xbcd.fits.gz')
            
    files.sort()

    roots = np.array([file.split('/')[0] for file in files])
    with_channels = np.array([file.split('_')[1] for file in files])
    all_roots = np.array(['{0}-{1}'.format(r, c.replace('I','ch').replace('M', 'mips')) for r, c in zip(roots, with_channels)])

    tab = {'aor':[], 'N':[], 'channel':[]}
    for r in np.unique(all_roots):
        tab['aor'].append(r.split('-')[0])
        tab['N'].append((all_roots == r).sum())
        tab['channel'].append(r.split('-')[1])

    aors = utils.GTable(tab)
    print(aors)
    
    ########
    SKIP = True          # Don't regenerate finished files
    delete_group = False # Delete intermediate products from memory
    zip_outputs = False    # GZip intermediate products

    aors_ch = {}
    
    ########
    # Process mosaics by AOR
    # Process in groups, helps for fields like HFF with dozens/hundreds of AORs!
    for ch in channels:
            
        aor = aors[(aors['channel'] == ch) & (aors['N'] > 5)]
        if len(aor) == 0:
            continue

        #aors_ch[ch] = []

        if ch in ['ch1','ch2']:
            NPER, instrument = 500, 'irac'
        if ch in ['ch3','ch4']:
            NPER, instrument = 500, 'irac'
        elif ch in ['mips1']:
            NPER, instrument = 400, 'mips'
        
        min_frametime = min_frame[instrument]
        
        nsort = np.cumsum(aor['N']/NPER)
        NGROUP = int(np.ceil(nsort.max()))

        count = 0

        for g in range(NGROUP):
            root_i = root+'-{0:02d}'.format(g)

            gsel = (nsort > g) & (nsort <= g+1)
            aor_ids = list(aor['aor'][gsel])
            print('{0}-{1}   N_AOR = {2:>2d}  N_EXP = {3:>4d}'.format(root_i, ch,  len(aor_ids), aor['N'][gsel].sum()))
            count += gsel.sum()

            files = glob.glob('{0}-{1}*'.format(root_i, ch))
            if (len(files) > 0) & (SKIP): 
                print('Skip {0}-{1}'.format(root_i, ch))
                continue
            
            with open('{0}-{1}.log'.format(root_i, ch),'w') as fp:
                fp.write(time.ctime())
                
            # Do internal alignment to GAIA.  
            # Otherwise, set `radec` to the name of a file that has two columns with 
            # reference ra/dec.
            #radec = None 

            # Pipeline
            if instrument == 'mips':
                aors_ch[ch] = irac.process_all(channel=ch.replace('mips','ch'), output_root=root_i, driz_scale=initial_pix, kernel=kernel, pixfrac=pixfrac, wcslist=None, pad=0, out_hdu=out_hdu, aor_ids=aor_ids, flat_background=False, two_pass=True, min_frametime=min_frametime, instrument=instrument, align_threshold=0.15, radec=radec, run_alignment=False, mips_ext=mips_ext, ref_seg=ref_seg, global_mask=root+'_mask.reg')
            else:
                aors_ch[ch] = irac.process_all(channel=ch, output_root=root_i, driz_scale=initial_pix, kernel=kernel, pixfrac=pixfrac, wcslist=None, pad=0, out_hdu=out_hdu, aor_ids=aor_ids, flat_background=False, two_pass=True, min_frametime=min_frametime, instrument=instrument, radec=radec, run_alignment=run_alignment, assume_close=assume_close, ref_seg=ref_seg, global_mask=root+'_mask.reg', med_max_size=med_max_size)

            if len(aors_ch[ch]) == 0:
                continue

            # PSFs
            plt.ioff()

            if (instrument != 'mips') & make_psf:
                ch_num = int(ch[-1])
                segmask=True

                # psf_size=20
                # for p in [0.1, final_pix]:
                #     irac.mosaic_psf(output_root=root_i, target_pix=p, channel=ch_num, aors=aors_ch[ch], kernel=kernel, pixfrac=pixfrac, size=psf_size, native_orientation=False, instrument=instrument, subtract_background=False, segmentation_mask=segmask, max_R=10)
                #     plt.close('all')

                psf_size=30
                p = 0.1
                irac.mosaic_psf(output_root=root_i, target_pix=p, channel=ch_num, aors=aors_ch[ch], kernel=kernel, pixfrac=pixfrac, size=psf_size, native_orientation=True, subtract_background=False, segmentation_mask=segmask, max_R=10)

                plt.close('all')

            if delete_group:
                del(aors_ch[ch])

            print('Done {0}-{1}, gzip products'.format(root_i, ch))

            if zip_outputs:
                os.system('gzip {0}*-{1}_drz*fits'.format(root_i, ch))
        
        # PSFs
        if (instrument != 'mips') & make_psf:
            # Average PSF
            p = 0.1
            files = glob.glob('*{0}-{1:.1f}*psfr.fits'.format(ch, p))
            if len(files) == 0:
                continue
                
            files.sort()
            avg = None
            for file in files: 
                im = pyfits.open(file)
                if avg is None:
                    wht = im[0].data != 0
                    avg = im[0].data*wht
                else:
                    wht_i = im[0].data != 0
                    avg += im[0].data*wht_i
                    wht += wht_i
                
                im.close()
                
            avg = avg/wht
            avg[wht == 0] = 0

            # Window
            from photutils import (HanningWindow, TukeyWindow, 
                                   CosineBellWindow,
                                   SplitCosineBellWindow, TopHatWindow)

            coswindow = CosineBellWindow(alpha=1)
            avg *= coswindow(avg.shape)**0.05
            avg /= avg.sum()

            pyfits.writeto('{0}-{1}-{2:0.1f}.psfr_avg.fits'.format(root, ch, p), data=avg, header=im[0].header, overwrite=True)
    
    ####
    ## Show the initial product
    plt.ioff()
    for i in range(10):
        files = glob.glob(f'{root}-{i:02d}-ch*sci.fits')
        if len(files) > 0:
            break
            
    files.sort()
    
    if len(files) == 1:
        subs = 1,1
        fs = [7,7]
    elif len(files) == 2:
        subs = 1,2
        fs = [14,7]
    elif len(files) == 3:
        subs = 2,2
        fs = [14,14]
    else:
        subs = 2,2
        fs = [14,14]
        
    fig = plt.figure(figsize=fs)
    for i, file in enumerate(files[:4]):
        im = pyfits.open(file)
        print('{0} {1} {2:.1f} s'.format(file, im[0].header['FILTER'], im[0].header['EXPTIME']))
        ax = fig.add_subplot(subs[0], subs[1], 1+i)
        ax.imshow(im[0].data, vmin=-0.1, vmax=1, cmap='gray_r', origin='lower')
        ax.text(0.05, 0.95, file, ha='left', va='top', color='k', 
                transform=ax.transAxes)
        
        im.close()
        
    if len(files) > 1:
        fig.axes[1].set_yticklabels([])
    
    if len(files) > 2:
        fig.axes[0].set_xticklabels([])
        fig.axes[1].set_xticklabels([])
    
    if len(files) > 3:
        fig.axes[3].set_yticklabels([])
        
    fig.tight_layout(pad=0.5)
    fig.savefig(f'{root}.init.png')
    plt.close('all')
    
    if stop_at == 'preprocess':
        return True
        
    #######
    # Make more compact individual exposures and clean directories
    wfiles = []
    for ch in channels:
        if 'mips' in ch:
            chq = ch.replace('mips','ch')
            wfiles += glob.glob(f'{aor_query}/{chq}/bcd/SPITZER_M*wcs.fits')
        else:
            wfiles += glob.glob(f'{aor_query}/{ch}/bcd/SPITZER_I*wcs.fits')

    #wfiles = glob.glob('r*/*/bcd/*_I[1-4]_*wcs.fits')
    #wfiles += glob.glob('r*/*/bcd/*_M[1-4]_*wcs.fits')
    wfiles.sort()

    for wcsfile in wfiles:
        outfile = wcsfile.replace('_wcs.fits', '_xbcd.fits.gz')
        if os.path.exists(outfile):
            print(outfile)
        else:
            irac.combine_products(wcsfile)
            print('Run: ', outfile)

        if os.path.exists(outfile):
            remove_files = glob.glob('{0}*fits'.format(wcsfile.split('_wcs')[0]))
            for f in remove_files:
                print('   rm ', f)
                os.remove(f)
 
    if stop_at == 'make_compact':
        return True
                                   
    #############
    # Drizzle final mosaics
    # Make final mosaic a bit bigger than the HST image
    pad = mosaic_pad

    # Pixel scale of final mosaic.
    # Don't make too small if not many dithers available as in this example.
    # But for well-sampled mosaics like RELICS / HFF, can push this to perhaps 0.3" / pix
    pixscale = final_pix #0.5

    # Again, if have many dithers maybe can use more aggressive drizzle parameters,
    # like a 'point' kernel or smaller pixfrac (a 'point' kernel is pixfrac=0)
    #kernel, pixfrac = 'square', 0.2

    # Correction for bad columns near bright stars
    #pulldown_mag = 15.2 

    ##############
    # Dilation for CR rejection
    dil = np.ones((3,3))
    driz_cr = [7, 4]
    blot_interp = 'poly5'
    bright_fmax = 0.5
    
    ### Drizzle
    for ch in channels: #[:2]:
        ###########
        # Files and reference image for extra CR rejection
        if ch == 'mips1':
            files = glob.glob('{0}/ch1/bcd/SPITZER_M1_*xbcd.fits*'.format(drz_query, ch))
            files.sort()
            pulldown_mag = -10
            pixscale = 1.
            kernel = 'point'
        else:
            files = glob.glob('{0}/{1}/bcd/*_I?_*xbcd.fits*'.format(drz_query, ch))
            files.sort()

        #ref = pyfits.open('{0}-00-{1}_drz_sci.fits'.format(root, ch))
        #ref_data = ref[0].data.astype(np.float32)

        ref_files = glob.glob(f'{root}-??-{ch}*sci.fits')
        if len(ref_files) == 0:
            continue

        num = None
        for ref_file in ref_files:
            ref = pyfits.open(ref_file)
            wht = pyfits.open(ref_file.replace('_sci.fits', '_wht.fits'))
            if num is None:
                num = ref[0].data*wht[0].data
                den = wht[0].data
            else:
                num += ref[0].data*wht[0].data
                den += wht[0].data

        ref_data = (num/den).astype(np.float32)
        ref_data[den <= 0] = 0

        ref_wcs = pywcs.WCS(ref[0].header, relax=True) 
        ref_wcs.pscale = utils.get_wcs_pscale(ref_wcs) 
        if (not hasattr(ref_wcs, '_naxis1')) & hasattr(ref_wcs, '_naxis'):
            ref_wcs._naxis1, ref_wcs._naxis2 = ref_wcs._naxis

        ##############
        # Output WCS based on HST footprint
        if drizzle_ref_file == '':
            try:
                hst_im = pyfits.open(glob.glob('{0}-f[01]*_drz_sci.fits*'.format(root))[-1])
            except:
                hst_im = pyfits.open(glob.glob('{0}-f[578]*_dr*sci.fits*'.format(root))[-1])
            
    
            hst_wcs = pywcs.WCS(hst_im[0])
            hst_wcs.pscale = utils.get_wcs_pscale(hst_wcs) 

            try:
                size = (np.round(np.array([hst_wcs._naxis1, hst_wcs._naxis2])*hst_wcs.pscale*pad/pixscale)*pixscale)
            except:
                size = (np.round(np.array([hst_wcs._naxis[0], hst_wcs._naxis[1]])*hst_wcs.pscale*pad/pixscale)*pixscale)
            
            hst_rd = hst_wcs.calc_footprint().mean(axis=0)
            _x = utils.make_wcsheader(ra=hst_rd[0], dec=hst_rd[1],
                                      size=size, 
                                      pixscale=pixscale, 
                                      get_hdu=False, theta=0)
            
            out_header, out_wcs = _x
        else:
            driz_ref_im = pyfits.open(drizzle_ref_file)
            out_wcs = pywcs.WCS(driz_ref_im[0].header, relax=True)
            out_wcs.pscale = utils.get_wcs_pscale(out_wcs) 
            
            out_header = utils.to_header(out_wcs)
        
        if (not hasattr(out_wcs, '_naxis1')) & hasattr(out_wcs, '_naxis'):
            out_wcs._naxis1, out_wcs._naxis2 = out_wcs._naxis
            
        ##############
        # Bright stars for pulldown correction
        cat_file = glob.glob(f'{root}-[0-9][0-9]-{ch}.cat.fits')[0]
        ph = utils.read_catalog(cat_file) 
        bright = (ph['mag_auto'] < pulldown_mag) # & (ph['flux_radius'] < 3)
        ph = ph[bright]

        ##############
        # Now do the drizzling
        yp, xp = np.indices((256, 256))
        orig_files = []

        out_header['DRIZ_CR0'] = driz_cr[0]
        out_header['DRIZ_CR1'] = driz_cr[1]
        out_header['KERNEL'] = kernel
        out_header['PIXFRAC'] = pixfrac
        out_header['NDRIZIM'] = 0
        out_header['EXPTIME'] = 0
        out_header['BUNIT'] = 'microJy'
        out_header['FILTER'] = ch

        med_root = 'xxx'
        N = len(files)

        for i, file in enumerate(files):#[:100]):

            print('{0}/{1} {2}'.format(i, N, file))

            if file in orig_files:
                continue

            im = pyfits.open(file)
            ivar = 1/im['CBUNC'].data**2    
            msk = (~np.isfinite(ivar)) | (~np.isfinite(im['CBCD'].data))
            im['CBCD'].data[msk] = 0
            ivar[msk] = 0

            wcs = pywcs.WCS(im['WCS'].header, relax=True)
            wcs.pscale = utils.get_wcs_pscale(wcs)
            if (not hasattr(wcs, '_naxis1')) & hasattr(wcs, '_naxis'):
                wcs._naxis1, wcs._naxis2 = wcs._naxis
            
            fp = Path(wcs.calc_footprint())

            med_root_i = im.filename().split('/')[0]
            if med_root != med_root_i:
                print('\n Read {0}-{1}_med.fits \n'.format(med_root_i, ch))
                med = pyfits.open('{0}-{1}_med.fits'.format(med_root_i, ch))
                med_data = med[0].data.astype(np.float32)
                med_root = med_root_i
                med.close()
                
                try:
                    gaia_rd = utils.read_catalog('{0}-{1}_gaia.radec'.format(med_root_i, ch))
                    ii, rr = gaia_rd.match_to_catalog_sky(ph)
                    gaia_rd = gaia_rd[ii][rr.value < 2]
                    gaia_pts = np.array([gaia_rd['ra'].data, 
                                         gaia_rd['dec'].data]).T
                except:
                    gaia_rd = []

            #data = im['CBCD'].data - aor_med[0].data

            # Change output units to uJy / pix
            if ch == 'mips1':
                # un = 1*u.MJy/u.sr
                # #to_ujy_px = un.to(u.uJy/u.arcsec**2).value*(out_wcs.pscale**2)
                # to_ujy_px = un.to(u.uJy/u.arcsec**2).value*(native_scale**2)
                to_ujy_px = 146.902690
            else:
                # native_scale = 1.223
                # un = 1*u.MJy/u.sr
                # #to_ujy_px = un.to(u.uJy/u.arcsec**2).value*(out_wcs.pscale**2)
                # to_ujy_px = un.to(u.uJy/u.arcsec**2).value*(native_scale**2)
                to_ujy_px = 35.17517196810

            blot_data = ablot.do_blot(ref_data, ref_wcs, wcs, 1, coeffs=True, 
                                      interp=blot_interp, 
                                      sinscl=1.0, stepsize=10, 
                                      wcsmap=None)/to_ujy_px

            # mask for bright stars
            eblot = 1-np.clip(blot_data, 0, bright_fmax)/bright_fmax

            # Initial CR
            clean = im[0].data - med_data - im['WCS'].header['PEDESTAL']
            dq = (clean - blot_data)*np.sqrt(ivar)*eblot > driz_cr[0]

            # Adjacent CRs
            dq_dil = binary_dilation(dq, selem=dil)
            dq |= ((clean - blot_data)*np.sqrt(ivar)*eblot > driz_cr[1]) & (dq_dil)

            # Very negative pixels
            dq |= clean*np.sqrt(ivar) < -4

            original_dq = im['WCS'].data - (im['WCS'].data & 1)
            dq |= original_dq > 0

            # Pulldown correction for bright stars
            if len(gaia_rd) > 0:       
                mat = fp.contains_points(gaia_pts) 
                if mat.sum() > 0:
                    xg, yg = wcs.all_world2pix(gaia_rd['ra'][mat], gaia_rd['dec'][mat], 0)
                    sh = dq.shape
                    mat = (xg > 0) & (xg < sh[1]) & (yg > 0) & (yg < sh[0])
                    if mat.sum() > 0:
                        for xi, yi in zip(xg[mat], yg[mat]):
                            dq |= (np.abs(xp-xi) < 2) & (np.abs(yp-yi) > 10)

            if i == 0:
                res = utils.drizzle_array_groups([clean], [ivar*(dq == 0)], [wcs], outputwcs=out_wcs, kernel=kernel, pixfrac=pixfrac, data=None, verbose=False)
                # Copy header keywords
                wcs_header = utils.to_header(wcs)
                for k in im[0].header:
                    if (k not in ['', 'HISTORY', 'COMMENT']) & (k not in out_header) & (k not in wcs_header):
                        out_header[k] = im[0].header[k]

            else:
                _ = utils.drizzle_array_groups([clean], [ivar*(dq == 0)], [wcs], outputwcs=out_wcs, kernel=kernel, pixfrac=pixfrac, data=res[:3], verbose=False)

            out_header['NDRIZIM'] += 1
            out_header['EXPTIME'] += im[0].header['EXPTIME']
            
            im.close()
            
        # Pixel scale factor for weights
        wht_scale = (out_wcs.pscale/wcs.pscale)**-4

        # Write final images
        pyfits.writeto('{0}-{1}_drz_sci.fits'.format(root, ch), data=res[0]*to_ujy_px, header=out_header, 
                       output_verify='fix', overwrite=True)
        pyfits.writeto('{0}-{1}_drz_wht.fits'.format(root, ch), data=res[1]*wht_scale/to_ujy_px**2, 
                       header=out_header, output_verify='fix', overwrite=True)
    
    ##########
    ## Show the final drizzled images
    plt.ioff()
    files = glob.glob(f'{root}-ch*sci.fits')
    files.sort()
    
    if len(files) == 1:
        subs = 1,1
        fs = [7,7]
    elif len(files) == 2:
        subs = 1,2
        fs = [14,7]
    elif len(files) == 3:
        subs = 2,2
        fs = [14,14]
    else:
        subs = 2,2
        fs = [14,14]
        
    fig = plt.figure(figsize=fs)
    for i, file in enumerate(files[:4]):
        im = pyfits.open(file)
        print('{0} {1} {2:.1f} s'.format(file, im[0].header['FILTER'], im[0].header['EXPTIME']))
        ax = fig.add_subplot(subs[0], subs[1], 1+i)
        scl = (final_pix/initial_pix)**2
        ax.imshow(im[0].data, vmin=-0.1*scl, vmax=1*scl, cmap='gray_r', origin='lower')
        ax.text(0.05, 0.95, file, ha='left', va='top', color='k', 
                transform=ax.transAxes)
        
        im.close()
        
    if len(files) > 1:
        fig.axes[1].set_yticklabels([])
    
    if len(files) > 2:
        fig.axes[0].set_xticklabels([])
        fig.axes[1].set_xticklabels([])
    
    if len(files) > 3:
        fig.axes[3].set_yticklabels([])
        
    fig.tight_layout(pad=0.5)
    fig.savefig(f'{root}.final.png')
    plt.close('all')
    
    if sync_results:
        print('gzip mosaics')
        os.system(f'gzip -f {root}-ch*_drz*fits {root}-mips*_drz*fits')
    
        ######## Sync
        ## Sync
        print(f's3://{bucket}/Pipeline/{root}/IRAC/')
    
        make_html(root, bucket=bucket)
    
        os.system(f'aws s3 sync ./ s3://{bucket}/Pipeline/{root}/IRAC/'
                  f' --exclude "*" --include "{root}-ch*drz*fits*"'
                  f' --include "{root}-mips*drz*fits*"'
                  f' --include "{root}.*png"'
                  ' --include "*-ch*psf*" --include "*log.fits"' 
                  ' --include "*wcs.[lp]*"'
                  ' --include "*html" --include "*fail*"'
                  ' --acl public-read')
    
        if sync_xbcd:
            aor_files = glob.glob('r*-ch*med.fits')
            for aor_file in aor_files:
                aor = aor_file.split('-ch')[0]
                os.system(f'aws s3 sync ./{aor}/ s3://{bucket}/IRAC/AORS/{aor}/ --exclude "*" --include "ch*/bcd/*xbcd.fits.gz" --acl public-read')
                os.system(f'aws s3 cp {aor_file} s3://{bucket}/IRAC/AORS/ --acl public-read')
                
    msg = f'### Done: \n    https://s3.amazonaws.com/{bucket}/Pipeline/{root}/IRAC/{root}.irac.html'
       
    utils.log_comment(f'/tmp/{root}.success', msg, verbose=True, show_date=True)