Example #1
0
def photometry(data,
               mywcs,
               regs,
               beam,
               alphamap=None,
               alphaerrmap=None,
               parsuffix=''):
    results = {}
    for ii, reg in enumerate(regs):
        if 'text' not in reg.meta:
            name = str(ii)
        else:
            name = reg.meta['text'].strip("{}")

        # all regions are points: convert them to 0.5" circles
        phot_reg = regions.CircleSkyRegion(center=reg.center,
                                           radius=0.5 * u.arcsec)
        pixreg = phot_reg.to_pixel(mywcs)

        bgreg = regions.CircleSkyRegion(center=reg.center,
                                        radius=1.5 * u.arcsec).to_pixel(mywcs)

        log.info("Name={0} color={1}".format(name, reg.visual['color']))

        mask = pixreg.to_mask()
        cutout = mask.cutout(data) * mask.data

        # how do I make an annulus?
        bgmask = bgreg.to_mask()

        # manualannulus
        diff = bgmask.shape[0] - mask.shape[0]
        bgm = bgmask.data.astype('bool')
        bgm[int(diff / 2):-int(diff / 2),
            int(diff / 2):-int(diff / 2)] ^= mask.data.astype('bool')
        assert bgm.sum() == bgmask.data.sum() - mask.data.sum()

        bgcutout = bgmask.cutout(data) * bgm

        results[name] = {
            'peak' + parsuffix: cutout.max(),
            'sum' + parsuffix: cutout.sum(),
            'bgrms' + parsuffix: bgcutout.std(),
            'bgmad' + parsuffix: mad_std(bgcutout),
            'npix' + parsuffix: mask.data.sum(),
            'beam_area' + parsuffix: beam.sr,
            'RA' + parsuffix: reg.center.ra[0],
            'Dec' + parsuffix: reg.center.dec[0],
            'color' + parsuffix: reg.visual['color'],
        }

        if alphamap is not None and alphaerrmap is not None:
            alphacutout = mask.cutout(alphamap) * mask.data
            alphaerrcutout = mask.cutout(alphaerrmap) * mask.data
            argmax = np.unravel_index(cutout.argmax(), cutout.shape)
            results[name]['alpha'] = alphacutout[argmax]
            results[name]['alphaerror'] = alphaerrcutout[argmax]

    return results
Example #2
0
def regions_from_sources(source_list):
    region_list = []
    for source in source_list:
        l = source['Glon']
        b = source['Glat']
        r = Angle(source['radius'], 'arcsec')
        center = SkyCoord(l, b, unit='deg', frame='galactic')
        region_list.append(regions.CircleSkyRegion(center, r))
    return region_list
Example #3
0
def ppcat_to_regions(cat, frame):
    center = coordinates.SkyCoord(cat['x_cen'],
                                  cat['y_cen'],
                                  unit=(u.deg, u.deg),
                                  frame=frame)
    rad = cat['radius'].quantity
    regs = [regions.CircleSkyRegion(cen, rr) for cen, rr in zip(center, rad)]
    for reg, row in zip(regs, cat):
        if row['rejected']:
            reg.visual['color'] = 'red'
        else:
            reg.visual['color'] = 'green'
    return regs
Example #4
0
    def _parseExReg(self, filename):

        with open(filename, 'r') as f:
            lines = f.readlines()

        reglist = []

        for line in lines:
            if not line.startswith('#'):
                if line.startswith('circle'):
                    baseLine = line.partition('# color=green pos=')
                    x, y, r = baseLine[0][baseLine[0].find('(') +
                                          1:baseLine[0].find(')')].split(',')
                    ra, dec = baseLine[-1][baseLine[-1].find('(') +
                                           1:baseLine[-1].find(')')].split(',')
                    circ = regions.CircleSkyRegion(
                        center=SkyCoord(np.float(ra),
                                        np.float(dec),
                                        unit='deg'),
                        radius=Angle(.265 * np.float(r), 'arcsec'))
                    reglist.append(circ)

                elif line.startswith('box'):
                    baseLine = line.partition('# color=green ')
                    x, y, w, h = baseLine[0][baseLine[0].find('(') +
                                             1:baseLine[0].find(')')].split(
                                                 ',')
                    ra, dec = baseLine[-1].rstrip().split()
                    ra = np.float(ra[3:])
                    dec = np.float(dec[4:])
                    rec = regions.RectangleSkyRegion(
                        center=SkyCoord(ra, dec, unit='deg'),
                        width=Angle(.265 * np.float(w), 'arcsec'),
                        height=Angle(.265 * np.float(h), 'arcsec'),
                        angle=Angle(270, 'deg'))
                    reglist.append(rec)

        return reglist
def measure_fluxes(data, ref_name, img, name):

    #This function is to add another image to an already made catalog using positions from a different image. 'data' is the catalog to add measurements to, 'ref_name' is the name of the reference data set (where the positions are from), 'img' is the new image, and 'name' is the name of 'img'

    cat = Table.read(data)

    fl = fits.open(img)
    header = fl[0].header
    img_data = fl[0].data.squeeze()

    mywcs = WCS(header).celestial

    rad = Angle(1, 'arcsecond')  #radius for region list
    rad_deg = rad.to(u.degree)
    #generate region list
    regs = []

    reg_file = '/users/jotter/summer_research_2018/final_regs/' + name + '_reg_file_circle.reg'

    with open(reg_file, 'w') as fh:
        fh.write("fk5\n")
        for ind in range(len(cat)):
            reg = regions.CircleSkyRegion(center=SkyCoord(
                cat['gauss_x_' + ref_name][ind] * u.degree,
                cat['gauss_y_' + ref_name][ind] * u.degree),
                                          radius=rad,
                                          meta={'text': str(cat['D_ID'][ind])})
            reg_pix = reg.to_pixel(mywcs)
            if reg_pix.center.x > 0 and reg_pix.center.x < len(img_data[0]):
                if reg_pix.center.y > 0 and reg_pix.center.y < len(img_data):
                    regs.append(reg)
                    fh.write(
                        'circle({x_cen}, {y_cen}, {radius}) #text={{{ID}}}\n'.
                        format(x_cen=reg.center.ra.value,
                               y_cen=reg.center.dec.value,
                               radius=0.1 * rad_deg.value,
                               ID=str(cat['D_ID'][ind])))

    cat_r = Angle(0.3, 'arcsecond')  #radius in gaussian fitting
    gauss_cat = gaussfit_catalog(
        img,
        regs,
        cat_r,
        savepath='/lustre/aoc/students/jotter/gauss_diags/leaves/' +
        name)  #output is nested dictionary structure

    gauss_fit_tab = Table(
        names=('D_ID', '_idx_' + name, 'gauss_x_' + name, 'x_err_' + name,
               'gauss_y_' + name, 'y_err_' + name, 'FWHM_major_' + name,
               'major_err_' + name, 'FWHM_minor_' + name, 'minor_err_' + name,
               'position_angle_' + name, 'position_angle_err_' + name,
               'peak_flux_' + name, 'gauss_amplitude_' + name,
               'amplitude_err_' + name, 'ap_flux_' + name,
               'ap_flux_err_' + name, 'fit_goodness_' + name),
        dtype=('i4', 'i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
               'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
               'U10'))  #turn into astropy table
    for key in gauss_cat:
        gauss_fit_tab.add_row(
            (key, key, gauss_cat[key]['center_x'],
             gauss_cat[key]['e_center_x'], gauss_cat[key]['center_y'],
             gauss_cat[key]['e_center_y'], gauss_cat[key]['fwhm_major'],
             gauss_cat[key]['e_fwhm_major'], gauss_cat[key]['fwhm_minor'],
             gauss_cat[key]['e_fwhm_minor'], gauss_cat[key]['pa'],
             gauss_cat[key]['e_pa'], gauss_cat[key]['peak'],
             gauss_cat[key]['amplitude'], gauss_cat[key]['e_amplitude'],
             np.nan, np.nan, 'none'))  #fill table

    beam = radio_beam.Beam.from_fits_header(header)
    pixel_scale = np.abs(
        mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
    ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

    for row in range(len(gauss_fit_tab)):
        pix_major_fwhm = ((gauss_fit_tab['FWHM_major_' + name][row] *
                           u.arcsec).to(u.degree) / pixel_scale).decompose()
        pix_minor_fwhm = ((gauss_fit_tab['FWHM_minor_' + name][row] *
                           u.arcsec).to(u.degree) / pixel_scale).decompose()
        cutout_center = SkyCoord(gauss_fit_tab['gauss_x_' + name][row],
                                 gauss_fit_tab['gauss_y_' + name][row],
                                 frame='icrs',
                                 unit=(u.deg, u.deg))
        cutout_center_pix = cutout_center.to_pixel(mywcs)
        cutout_center_pix = regions.PixCoord(cutout_center_pix[0],
                                             cutout_center_pix[1])
        position_angle = gauss_fit_tab['position_angle_' + name][row] * u.deg
        ellipse_reg = regions.EllipsePixelRegion(cutout_center_pix,
                                                 pix_major_fwhm * 2.,
                                                 pix_minor_fwhm * 2.,
                                                 angle=position_angle)
        size = pix_major_fwhm * 2.1
        ap_mask = ellipse_reg.to_mask()
        cutout_mask = ap_mask.cutout(img_data)

        aperture_flux = np.sum(cutout_mask[ap_mask.data == 1]) / ppbeam
        gauss_fit_tab['ap_flux_' + name][row] = aperture_flux

    gauss_fit_tab.write('/lustre/aoc/students/jotter/dendro_catalogs/' + name +
                        '_dendro_catalog_ref_' + ref_name + '.fits',
                        format='fits',
                        overwrite=True)
Example #6
0
N = len(list_zen)
#print N

N = 1

for i in range(N):
    #    if i%10 ==0:
    #        print "----running observation -- ",i

    obs = list_zen[i]

    events = datastore.obs(obs.obs_id).events
    counts_image = SkyImage.empty_like(ref_image)
    counts_image.fill_events(events)

    exclusion_region = regions.CircleSkyRegion(src, 0.3 * u.deg)
    mask = counts_image.region_mask(exclusion_region)

    mask1 = copy.copy(mask)
    mask1.data = np.invert(mask.data)

    image_maker = SingleObsImageMaker(
        obs=obs,
        empty_image=ref_image,
        energy_band=energy_band,
        offset_band=offset_band,
        exclusion_mask=mask1,
    )

    image_maker.counts_image()
    counts_image = image_maker.images['counts']
nsources = len(core_phot_tbl)

print("Mass fraction M>8 = {0}".format(over8fraction))
print("Mean mass Mbar(M>8) = {0}".format(over8mean))
print("Mass of observed sources, assuming all are 8 msun = {0}".format(
    nsources * 8))
print("Total Mass estimate if all sources are 8 msun = {0}".format(
    nsources * 8 / over8fraction))
print("Total Mass estimate if Mbar={1} = {0}".format(
    nsources * over8mean / over8fraction, over8mean))

# Comparison to Schmiedeke et al, 2016 tbl 2
clusters = regions.read_ds9(paths.rpath('schmiedeke_clusters.reg'))
clusters.append(
    regions.CircleSkyRegion(clusters[0].center,
                            radius=1 * u.deg,
                            meta={'text': 'Total'}))
#this can be used to determine n_cores and n_hii in a bigger region,
#but is incompatible with something else below...
# clusters.append(regions.CircleSkyRegion(clusters[0].center,
#                                         radius=35*u.arcsec,
#                                         meta={'text':'M Bigger'})
#                )
# Cluster M Bigger: N(cores)= 52 N(HII)= 49 counted mass=   2852.28 inferred mass=  11522.81 HII-only inferred mass:   16003.53 core-inferred mass=   7042.09

# add in DePree HII regions based on whether or not their names
# are already in the table, since we didn't count the larger HII regions
hii_regions = regions.read_ds9(
    paths.rpath('SgrB2_1.3cm_hiiRegions_masked_Done.reg'))
hii_regions = Table.read(paths.tpath("Schmiedeke2016_HIIregions_tableB1.txt"),
                         format='ascii.fixed_width')
Example #8
0
def b6b7_catalog(B6_img, B6_name, B7_img, B7_name, cat_name, nonconv_B6_img=None, nonconv_B7_img=None):
    #creates catalog from one image in each band
    #B3_names, B6_names, B7_names only used for gaussian diag directory names
    
    ref_data_name = '/home/jotter/nrao/summer_research_2018/tables/ref_catalog_may21.fits'
    ref_data = Table.read(ref_data_name)
    ref_arrs = [ref_data['B6_detect'], ref_data['B7_detect']]
  
    band_imgs = [B6_img, B7_img]
    band_names = ['B6', 'B7']
    band_img_names = [B6_name, B7_name]
    band_tables = []
    for b in range(len(band_imgs)): #first loop through different bands
        name = band_names[b]
        img_name = band_img_names[b]
        img = band_imgs[b]
        fl = fits.open(img)
        header = fl[0].header
        img_data = fl[0].data.squeeze()
        img_wcs = WCS(header).celestial

        beam = radio_beam.Beam.from_fits_header(header)
        pixel_scale = np.abs(img_wcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
        ppbeam = (beam.sr/(pixel_scale**2)).decompose().value

        if name == 'B6' and nonconv_B6_img is not None:
            fl = fits.open(nonconv_B6_img)
            header = fl[0].header
            nonconv_beam = radio_beam.Beam.from_fits_header(header)
            ppbeam = (nonconv_beam.sr/(pixel_scale**2)).decompose().value
        if name == 'B7' and nonconv_B7_img is not None:
            fl = fits.open(nonconv_B7_img)
            header = fl[0].header
            nonconv_beam = radio_beam.Beam.from_fits_header(header)
            ppbeam = (nonconv_beam.sr/(pixel_scale**2)).decompose().value
            
        #now get ready to fit gaussians
        #start by setting up save directory for images
        gauss_save_dir = '/home/jotter/nrao/gauss_diags_may21/'+img_name+'/'
        if not os.path.exists(gauss_save_dir):
            os.makedirs(gauss_save_dir)
        #now make region list

        rad = Angle(1, 'arcsecond') #radius used in region list
        regs = []

        src_inds = np.where(ref_arrs[b] == True)[0]
        print(len(src_inds))

        for ind in src_inds:
            reg = regions.CircleSkyRegion(center=SkyCoord(ref_data['RA_B3'][ind]*u.degree, ref_data['DEC_B3'][ind]*u.degree), radius=rad, meta={'text':str(ref_data['B3_Seq'][ind])})
            reg_pix = reg.to_pixel(img_wcs)
            if reg_pix.center.x > 0 and reg_pix.center.x < len(img_data[0]):
                if reg_pix.center.y > 0 and reg_pix.center.y < len(img_data):
                    if np.isnan(img_data[int(reg_pix.center.x), int(reg_pix.center.y)]) == False:
                        regs.append(reg)

        cat_r = Angle(0.5, 'arcsecond')/2 #radius for gaussian fitting
        print('ok')
        gauss_cat = gaussfit_catalog(img, regs, cat_r, savepath=gauss_save_dir, max_offset_in_beams = 1, max_radius_in_beams = 5)
        #table does not have all columns yet, add others later
        img_table = Table(names=('Seq_B3', 'fwhm_maj_'+name, 'fwhm_maj_err_'+name, 'fwhm_min_'+name, 'fwhm_min_err_'+name, 'pa_'+name, 'pa_err_'+name, 'gauss_amp_'+name, 'gauss_amp_err_'+name,'RA_'+name,'RA_err_'+name, 'DEC_'+name, 'DEC_err_'+name, ), dtype=('i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8'))
        for key in gauss_cat:
            img_table.add_row((key, gauss_cat[key]['fwhm_major'], gauss_cat[key]['e_fwhm_major'], gauss_cat[key]['fwhm_minor'], gauss_cat[key]['e_fwhm_minor'], gauss_cat[key]['pa'], gauss_cat[key]['e_pa'], gauss_cat[key]['amplitude'], gauss_cat[key]['e_amplitude'], gauss_cat[key]['center_x'], gauss_cat[key]['e_center_x'], gauss_cat[key]['center_y'], gauss_cat[key]['e_center_y']))
        #now measure deconvovled sizes and aperture flux measurements for each source 
        ap_flux_arr = []
        ap_flux_err_arr = []
        fwhm_maj_deconv_arr = []
        fwhm_maj_deconv_err_arr = []
        fwhm_min_deconv_arr = []
        fwhm_min_deconv_err_arr = []
        pa_deconv_arr = []
        pa_deconv_err_arr = []
        snr_arr = []
        rms_arr = []
 
        for row in range(len(img_table)): #now loop through sources in reference data and make measurements
            ref_ind = np.where(ref_data['B3_Seq'] == img_table['Seq_B3'][row])[0]
            if len(ref_ind > 0):
                #now measuring deconvolved sizes
                measured_source_size = radio_beam.Beam(major=img_table['fwhm_maj_'+name][row]*u.arcsec, minor=img_table['fwhm_min_'+name][row]*u.arcsec, pa=(img_table['pa_'+name][row]-90)*u.degree)
                try:
                    deconv_size = measured_source_size.deconvolve(beam)
                    fwhm_maj_deconv_arr.append(deconv_size.major.value)
                    fwhm_min_deconv_arr.append(deconv_size.minor.value)
                    fwhm_maj_deconv_err_arr.append(img_table['fwhm_maj_err_'+name][row]) #same error as non deconvolved
                    fwhm_min_deconv_err_arr.append(img_table['fwhm_min_err_'+name][row])
                    pa_deconv_arr.append(deconv_size.pa.to(u.deg).value)
                    pa_deconv_err_arr.append(img_table['pa_err_'+name][row])
                except ValueError:
                    fwhm_maj_deconv_arr.append(np.nan)
                    fwhm_min_deconv_arr.append(np.nan)
                    fwhm_maj_deconv_err_arr.append(np.nan)
                    fwhm_min_deconv_err_arr.append(np.nan)
                    pa_deconv_arr.append(np.nan)
                    pa_deconv_err_arr.append(np.nan)
 

                pix_major_fwhm = ((img_table['fwhm_maj_'+name][row]*u.arcsec).to(u.degree)/pixel_scale).decompose()
                pix_minor_fwhm = ((img_table['fwhm_min_'+name][row]*u.arcsec).to(u.degree)/pixel_scale).decompose()
                center_coord = SkyCoord(img_table['RA_'+name][row], img_table['DEC_'+name][row], frame='icrs', unit=(u.deg, u.deg))
                center_coord_pix = center_coord.to_pixel(img_wcs)
                center_coord_pix_reg = regions.PixCoord(center_coord_pix[0], center_coord_pix[1])
                pos_ang = (img_table['pa_'+name][row]-90)*u.deg #must subtract 90 to be consistent

                ellipse_reg = regions.EllipsePixelRegion(center_coord_pix_reg, pix_major_fwhm.value*2, pix_minor_fwhm.value*2, angle=pos_ang)
                ap_mask = ellipse_reg.to_mask()
                cutout_mask = ap_mask.cutout(img_data)
                
                aperture_flux = np.nansum(cutout_mask[ap_mask.data==1])/ppbeam
                npix = len(cutout_mask[ap_mask.data==1])

                #now make annulus for measuring background and error
                annulus_width = 15 #pixels
                annulus_radius = img_table['fwhm_maj_'+name][row]*u.arcsecond#+0.05*u.arcsecond
                annulus_radius_pix = (annulus_radius.to(u.degree)/pixel_scale).decompose()

                #cutout image
                cutout = Cutout2D(img_data, center_coord_pix, annulus_radius*2.5, img_wcs, mode='partial')
                cutout_center = regions.PixCoord(cutout.center_cutout[0], cutout.center_cutout[1])

                #define aperture regions for SNR
                innerann_reg = regions.CirclePixelRegion(cutout_center, annulus_radius_pix.value)
                outerann_reg = regions.CirclePixelRegion(cutout_center, annulus_radius_pix.value+annulus_width)

                #Make masks from aperture regions
                annulus_mask = mask(outerann_reg, cutout) - mask(innerann_reg, cutout)

                # Calculate the SNR and aperture flux sums
                pixels_in_annulus = cutout.data[annulus_mask.astype('bool')]
                bg_rms = median_abs_deviation(pixels_in_annulus)
                print(img_table['Seq_B3'][row])
                print('BG RMS: %f' % (bg_rms))
                ap_bg_rms = bg_rms/np.sqrt(npix/ppbeam) #rms/sqrt(npix/ppbeam) - rms error per beam
                bg_median = np.nanmedian(pixels_in_annulus)

                pix_bg = bg_median*npix/ppbeam

                ap_flux_bgcorrect = aperture_flux - pix_bg
                ap_flux_correct = ap_flux_bgcorrect + ap_flux_bgcorrect*(1 - special.erf(2*np.sqrt(np.log(2)))) #flux correction for summing within 2*fwhm
                
                ap_flux_err_arr.append(ap_bg_rms)
                ap_flux_arr.append(ap_flux_correct)
                snr_arr.append(img_table['gauss_amp_'+name][row]/bg_rms)
                rms_arr.append(bg_rms)
                
        cols = ['ap_flux_'+name, 'ap_flux_err_'+name, 'fwhm_maj_deconv_'+name, 'fwhm_maj_deconv_err_'+name, 'fwhm_min_deconv_'+name, 'fwhm_min_deconv_err_'+name, 'pa_deconv_'+name, 'pa_deconv_err_'+name, 'SNR_'+name, 'RMS_'+name]
        arrs = [ap_flux_arr, ap_flux_err_arr, fwhm_maj_deconv_arr, fwhm_maj_deconv_err_arr, fwhm_min_deconv_arr, fwhm_min_deconv_err_arr, pa_deconv_arr, pa_deconv_err_arr, snr_arr, rms_arr]
        for c in range(len(cols)):
            img_table.add_column(Column(np.array(arrs[c])), name=cols[c])
        img_table.add_column(Column(np.array(fwhm_maj_deconv_arr)/np.array(fwhm_min_deconv_arr)), name='ar_deconv_'+name)
        band_tables.append(img_table) #list of tables for each image
            
    
    B6B7 = join(band_tables[0], band_tables[1], keys='Seq_B3', join_type='outer')
    B6B7.write('/home/jotter/nrao/summer_research_2018/tables/'+cat_name+'.fits',  overwrite=True)
def gauss_sizes_imgs(srcID,
                     band,
                     images,
                     directory,
                     name_start=27,
                     name_end=-21):

    #This function takes a list of image names and adds them all to a catalog with gaussian sizes. 'data' is the catalog to get positions from, 'srcID' is the D_ID of the desired source, 'band' is the band of data, 'images' is the list of image names, 'directory' is the directory where these images are.

    data = '/lustre/aoc/students/jotter/dendro_catalogs/master_500klplus_B3_ref.fits'
    cat = Table.read(data)
    ind = np.where(cat['D_ID'] == srcID)[0][0]

    img_names = [img[name_start:name_end] for img in images]
    print(img_names)

    table_names = []  #because maybe not all images in img_namse get used
    img_fwhm_maj = []  #at the end combine these lists into a table
    img_fwhm_maj_err = []
    img_fwhm_min = []
    img_fwhm_min_err = []
    img_pa = []
    img_pa_err = []

    for j, img in enumerate(images):  #loop through images and measure fwhms
        name = img_names[j]
        if len(name) > 54:
            name = name[0:53]

        fl = fits.open(directory + img)
        header = fl[0].header
        try:
            img_data = fl[0].data.squeeze()
        except TypeError:
            print("error! img: " + img)
            continue
        mywcs = WCS(header).celestial

        beam = radio_beam.Beam.from_fits_header(header)
        pixel_scale = np.abs(
            mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
        ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

        save_dir = '/lustre/aoc/students/jotter/gauss_diags/diff_imgs/src_' + str(
            srcID) + '/' + band + '/' + name
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

        rad = Angle(1, 'arcsecond')  #radius for region list
        regs = []

        reg = regions.CircleSkyRegion(center=SkyCoord(
            cat['RA_B3'][ind] * u.degree, cat['DEC_B3'][ind] * u.degree),
                                      radius=rad,
                                      meta={'text': str(cat['D_ID'][ind])})
        reg_pix = reg.to_pixel(mywcs)
        if reg_pix.center.x > 0 and reg_pix.center.x < len(img_data[0]):
            if reg_pix.center.y > 0 and reg_pix.center.y < len(img_data):
                regs.append(reg)

        cat_r = Angle(0.5, 'arcsecond')  #radius in gaussian fitting
        gauss_cat = gaussfit_catalog(
            directory + img, regs, cat_r,
            savepath=save_dir)  #output is nested dictionary structure

        table_names.append(name)
        img_fwhm_maj.append(gauss_cat[str(srcID)]['fwhm_major'].value)
        img_fwhm_maj_err.append(gauss_cat[str(srcID)]['e_fwhm_major'].value)
        img_fwhm_min.append(gauss_cat[str(srcID)]['fwhm_minor'].value)
        img_fwhm_min_err.append(gauss_cat[str(srcID)]['e_fwhm_minor'].value)
        img_pa.append(gauss_cat[str(srcID)]['pa'].value)
        img_pa_err.append(gauss_cat[str(srcID)]['e_pa'].value)

    table = Table((table_names, img_fwhm_maj, img_fwhm_maj_err, img_fwhm_min,
                   img_fwhm_min_err, img_pa, img_pa_err),
                  names=('img_name', 'fwhm_maj', 'fwhm_maj_err', 'fwhm_min',
                         'fwhm_min_err', 'pa', 'pa_err'))
    table['fwhm_maj'].unit = 'arcsec'
    table['fwhm_maj_err'].unit = 'arcsec'
    table['fwhm_min'].unit = 'arcsec'
    table['fwhm_min_err'].unit = 'arcsec'

    table.write('/lustre/aoc/students/jotter/dendro_catalogs/src' +
                str(srcID) + '_img_sizes' + band + '.fits',
                overwrite=True)
tbl.rename_column('robs', 'tmp')
tbl.rename_column('ne', 'robs')
tbl.rename_column('tmp', 'ne')
tbl['ne'].unit = 1e4 * u.cm**-3
tbl['robs'].unit = 1e3 * u.au

tbl.write(paths.tpath("Schmiedeke2016_HIIregions_tableB1.txt"),
          format='ascii.fixed_width',
          overwrite=True)

reglist = [
    regions.CircleSkyRegion(
        coordinates.SkyCoord(row['RA'],
                             row['Dec'],
                             frame='fk5',
                             unit=(u.hour, u.deg)),
        radius=(u.Quantity(float(row['robs']) * 1000, u.au) /
                (8.5 * u.kpc)).to(u.arcsec, u.dimensionless_angles()),
        meta={'text': row['ID']},
        visual={'name': row['ID']},
    ) for row in tbl if row['ID']
]

regions.write_ds9(reglist,
                  paths.rpath('Schmiedeke2016_HIIregions_tableB1.reg'))

rslt = requests.get(
    'http://www.aanda.org/articles/aa/full_html/2016/04/aa27311-15/T2.html')
soup = BeautifulSoup(rslt.text, 'html5lib')
htmltable = soup.findAll('table')[-1]

allrows = (htmltable.findAll('tr'))
def fit_source(srcID,
               img,
               img_name,
               band,
               fit_bg=False,
               bg_stddev_x=30,
               bg_stddev_y=30,
               bg_mean_x=0,
               bg_mean_y=0,
               zoom=1,
               max_offset_in_beams=1,
               max_radius_in_beams=5,
               nonconv_img=None,
               mask_size=1.5):
    #this function fits a given source, and the background
    #srcID : int
    #name of source to fit in catalogs
    #img : fits file
    #fits file with source to fit
    #img_name : str
    #name of image for the directory where the fit plots will go
    #band : str
    #band of image to fit ('B3', 'B6', or 'B7')
    #fit_bg : bool
    #if False, do not fit background gaussian
    #bg_stddev_x : float
    #eyeballed estimate of stddev of the background source in pixels
    #bg_stddev_y : float
    #same as above in y direction
    #bg_mean_x/y : float
    #pixels away from center (origin) in x/y direction for background gaussian mean guess
    #zoom : float
    #amount of zoom, values greater than 1 are zoom ins

    #ref_data_name = '/home/jotter/nrao/summer_research_2018/tables/dendro_ref_catalog_edited.fits'
    ref_data_name = '/home/jotter/nrao/summer_research_2018/tables/ref_catalog_may21_b7.fits'
    #ref_data_name = '/lustre/cv/observers/cv-12578/orion_disks/summer_research_2018/tables/ref_catalog_may21.fits'
    ref_data = Table.read(ref_data_name)

    fl = fits.open(img)
    header = fl[0].header
    img_data = fl[0].data.squeeze()
    img_wcs = WCS(header).celestial

    beam = radio_beam.Beam.from_fits_header(header)
    pixel_scale = np.abs(
        img_wcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
    ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

    if nonconv_img is not None:
        flnonconv = fits.open(nonconv_img)
        nonconv_header = flnonconv[0].header
        nonconv_beam = radio_beam.Beam.from_fits_header(nonconv_header)
        ppbeam = (nonconv_beam.sr / (pixel_scale**2)).decompose().value

    #now get ready to fit gaussians
    #start by setting up save directory for images
    gauss_save_dir = '/home/jotter/nrao/gauss_diags_may21/fitbg/' + img_name + '/'
    #gauss_save_dir = f'/lustre/cv/observers/cv-12578/orion_disks/gauss_diags_may21/{img_name}/'

    print('saving plots to ' + gauss_save_dir)
    if not os.path.exists(gauss_save_dir):
        os.makedirs(gauss_save_dir)
    #now make region
    rad = Angle(1, 'arcsecond')  #radius used in region list
    #src_ind = np.where(ref_data['D_ID']==srcID)[0]
    src_ind = np.where(ref_data['B3_Seq'] == srcID)[0]

    ra = ref_data['RA_B3'][src_ind].data[0]
    dec = ref_data['DEC_B3'][src_ind].data[0]
    center_reg = SkyCoord(ra, dec, unit='deg', frame='icrs')
    reg = regions.CircleSkyRegion(
        center=center_reg,
        radius=1 * u.arcsecond,
        meta={
            'text':
            str(ref_data['B3_Seq'][src_ind].data[0]) + '_xstddev_' +
            str(bg_stddev_x) + '_ystddev_' + str(bg_stddev_y)
        })

    region_list = []
    #valid_inds = np.where(np.isnan(ref_data[band+'_detect']) == False)[0]
    for ind in range(len(ref_data)):  #valid_inds:
        if ref_data['B3_Seq'][ind] == srcID:
            continue
        ra_i = ref_data['RA_B3'][ind]
        dec_i = ref_data['DEC_B3'][ind]
        region_i = regions.CircleSkyRegion(center=SkyCoord(ra_i,
                                                           dec_i,
                                                           unit='deg',
                                                           frame='icrs'),
                                           radius=1 * u.arcsecond)
        region_list.append(region_i)

    #print(region_list)
    #print(reg)

    cat_r = Angle(0.5, 'arcsecond') / zoom  #radius for gaussian fitting

    if fit_bg == True:
        gauss_cat, fitim_bg = bg_gaussfit(
            img,
            reg,
            region_list,
            cat_r,
            bg_stddev_x=bg_stddev_x,
            bg_stddev_y=bg_stddev_y,
            bg_mean_x=bg_mean_x,
            bg_mean_y=bg_mean_y,
            savepath=gauss_save_dir,
            max_offset_in_beams=max_offset_in_beams,
            max_offset_in_beams_bg=10,
            max_radius_in_beams=max_radius_in_beams,
            mask_size=mask_size)

        #print('gauss_cat length ',len(gauss_cat))
        #k = list(gauss_cat.keys())[0]
        #if gauss_cat[k]['success'] == False:
        #    gauss_cat = gaussfit_cutoutim(img, fitim_bg, reg, region_list, cat_r, savepath=gauss_save_dir, max_offset_in_beams = max_offset_in_beams, max_radius_in_beams = max_radius_in_beams)
        #    success = gauss_cat[k]['success']
        #    print(F'ALTERNATIVE FIT SUCCESS: {success}')

    else:
        gauss_cat = gaussfit_catalog(img, [reg],
                                     cat_r,
                                     savepath=gauss_save_dir,
                                     max_offset_in_beams=max_offset_in_beams,
                                     max_radius_in_beams=max_radius_in_beams)

    img_table = Table(names=('Seq', 'fwhm_maj_' + band, 'fwhm_maj_err_' + band,
                             'fwhm_min_' + band, 'fwhm_min_err_' + band,
                             'pa_' + band, 'pa_err_' + band,
                             'gauss_amp_' + band, 'gauss_amp_err_' + band,
                             'RA_' + band, 'RA_err_' + band, 'DEC_' + band,
                             'DEC_err_' + band),
                      dtype=('i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
                             'f8', 'f8', 'f8', 'f8', 'f8'))
    for key in gauss_cat:
        img_table.add_row(
            (srcID, gauss_cat[key]['fwhm_major'],
             gauss_cat[key]['e_fwhm_major'], gauss_cat[key]['fwhm_minor'],
             gauss_cat[key]['e_fwhm_minor'], gauss_cat[key]['pa'],
             gauss_cat[key]['e_pa'], gauss_cat[key]['amplitude'],
             gauss_cat[key]['e_amplitude'], gauss_cat[key]['center_x'],
             gauss_cat[key]['e_center_x'], gauss_cat[key]['center_y'],
             gauss_cat[key]['e_center_y']))

    #now measure deconvovled sizes and aperture flux measurements for each source
    ap_flux_arr = []
    ap_flux_err_arr = []
    fwhm_maj_deconv_arr = []
    fwhm_maj_deconv_err_arr = []
    fwhm_min_deconv_arr = []
    fwhm_min_deconv_err_arr = []
    pa_deconv_arr = []
    pa_deconv_err_arr = []
    snr_arr = []

    for row in range(
            len(img_table)
    ):  #now loop through sources in reference data and make measurements
        ref_ind = np.where(ref_data['B3_Seq'] == img_table['Seq'][row])[0]
        if True == True:  #len(ref_ind > 0):

            measured_source_size = radio_beam.Beam(
                major=img_table['fwhm_maj_' + band][row] * u.arcsec,
                minor=img_table['fwhm_min_' + band][row] * u.arcsec,
                pa=(img_table['pa_' + band][row] - 90) * u.deg)
            try:
                deconv_size = measured_source_size.deconvolve(beam)
                fwhm_maj_deconv_arr.append(deconv_size.major.value)
                fwhm_min_deconv_arr.append(deconv_size.minor.value)
                fwhm_maj_deconv_err_arr.append(img_table['fwhm_maj_err_' +
                                                         band][row])
                fwhm_min_deconv_err_arr.append(img_table['fwhm_min_err_' +
                                                         band][row])
                pa_deconv_arr.append(deconv_size.pa.value)
                pa_deconv_err_arr.append(img_table['pa_err_' + band][row])

            except ValueError:
                fwhm_maj_deconv_arr.append(np.nan)
                fwhm_min_deconv_arr.append(np.nan)
                fwhm_maj_deconv_err_arr.append(np.nan)
                fwhm_min_deconv_err_arr.append(np.nan)
                pa_deconv_arr.append(np.nan)
                pa_deconv_err_arr.append(np.nan)

            pix_major_fwhm = (
                (img_table['fwhm_maj_' + band][row] * u.arcsec).to(u.degree) /
                pixel_scale).decompose()
            pix_minor_fwhm = (
                (img_table['fwhm_min_' + band][row] * u.arcsec).to(u.degree) /
                pixel_scale).decompose()
            center_coord = SkyCoord(img_table['RA_' + band][row],
                                    img_table['DEC_' + band][row],
                                    frame='icrs',
                                    unit=(u.deg, u.deg))
            center_coord_pix = center_coord.to_pixel(img_wcs)
            center_coord_pix_reg = regions.PixCoord(center_coord_pix[0],
                                                    center_coord_pix[1])

            pos_ang = (img_table['pa_' + band][row] - 90) * u.deg

            ellipse_reg = regions.EllipsePixelRegion(center_coord_pix_reg,
                                                     pix_major_fwhm.value * 2,
                                                     pix_minor_fwhm.value * 2,
                                                     angle=pos_ang)
            size = pix_major_fwhm * 2.1
            ap_mask = ellipse_reg.to_mask()
            cutout_mask = ap_mask.cutout(img_data)

            aperture_flux = np.nansum(cutout_mask[ap_mask.data == 1]) / ppbeam
            npix = len(cutout_mask[ap_mask.data == 1])

            #now make annulus for measuring background and error
            annulus_width = 15  #pixels
            annulus_radius = img_table[
                'fwhm_maj_' + band][row] * u.arcsecond  #0.1*u.arcsecond
            annulus_radius_pix = (annulus_radius.to(u.degree) /
                                  pixel_scale).decompose()

            #cutout image
            cutout = Cutout2D(img_data,
                              center_coord_pix,
                              annulus_radius * 2.5,
                              img_wcs,
                              mode='partial')
            cutout_center = regions.PixCoord(cutout.center_cutout[0],
                                             cutout.center_cutout[1])

            #define aperture regions for SNR
            innerann_reg = regions.CirclePixelRegion(cutout_center,
                                                     annulus_radius_pix.value)
            outerann_reg = regions.CirclePixelRegion(
                cutout_center, annulus_radius_pix.value + annulus_width)

            #Make masks from aperture regions
            annulus_mask = mask(outerann_reg, cutout) - mask(
                innerann_reg, cutout)

            # Calculate the SNR and aperture flux sums
            pixels_in_annulus = cutout.data[annulus_mask.astype(
                'bool')]  #pixels within annulus
            bg_rms = median_abs_deviation(pixels_in_annulus)
            ap_bg_rms = bg_rms / np.sqrt(
                npix / ppbeam)  #rms/sqrt(npix/ppbeam) - rms error per beam
            bg_median = np.median(pixels_in_annulus)

            pix_bg = bg_median * npix / ppbeam

            #flux corrections
            ap_flux_bgcorrect = aperture_flux - pix_bg
            ap_flux_correct = ap_flux_bgcorrect + ap_flux_bgcorrect * (
                1 - special.erf(2 * np.sqrt(np.log(2)))
            )  #flux correction for summing within 2*fwhm

            print(
                f'Background: {pix_bg}, Gauss amp: {img_table["gauss_amp_"+band][row]}'
            )
            print(f'peak pixel: {np.nanmax(cutout_mask[ap_mask.data==1])}')

            ap_flux_err_arr.append(ap_bg_rms)
            ap_flux_arr.append(ap_flux_correct)
            snr_arr.append(img_table['gauss_amp_' + band][row] / bg_rms)

    cols = [
        'ap_flux_' + band, 'ap_flux_err_' + band, 'fwhm_maj_deconv_' + band,
        'fwhm_maj_deconv_err_' + band, 'fwhm_min_deconv_' + band,
        'fwhm_min_deconv_err_' + band, 'pa_deconv_' + band,
        'pa_deconv_err_' + band, 'SNR_' + band
    ]
    arrs = [
        ap_flux_arr, ap_flux_err_arr, fwhm_maj_deconv_arr,
        fwhm_maj_deconv_err_arr, fwhm_min_deconv_arr, fwhm_min_deconv_err_arr,
        pa_deconv_arr, pa_deconv_err_arr, snr_arr
    ]
    for c in range(len(cols)):
        img_table.add_column(Column(np.array(arrs[c])), name=cols[c])
    img_table.add_column(Column(img_table['fwhm_maj_deconv_' + band] /
                                img_table['fwhm_min_deconv_' + band]),
                         name='ar_deconv_' + band)

    return img_table
objects = {'north': {'center': coordinates.SkyCoord('19:23:40.054', '14:31:05.498', unit=(u.hour, u.deg), frame='fk5'),
                     'radius': 0.15*u.arcsec,
                     'filename': 'W51n_cont_uniform.image.tt0.pbcor.fits'},
           'd2': {'center': coordinates.SkyCoord('19:23:39.820', '14:31:04.866', unit=(u.hour, u.deg), frame='fk5'),
                  'radius': 0.10*u.arcsec,
                  'filename': 'W51n_cont_uniform.image.tt0.pbcor.fits'},
           'e2e': {'center': coordinates.SkyCoord('19:23:43.969', '14:30:34.525', unit=(u.hour, u.deg), frame='fk5'),
                   'radius': 0.25*u.arcsec,
                   'filename': 'W51e2_cont_uniform.image.tt0.pbcor.fits'},
           'e8': {'center': coordinates.SkyCoord('19:23:43.906', '14:30:28.269', unit=(u.hour, u.deg), frame='fk5'),
                  'radius': 0.16*u.arcsec,
                  'filename': 'W51e2_cont_uniform.image.tt0.pbcor.fits'},
          }
for key in objects:
    obj = objects[key]
    objects[key]['aperture'] = regions.CircleSkyRegion(center=obj['center'],
                                                       radius=obj['radius'])

for objname in objects:
    obj = objects[objname]
    fh = fits.open(paths.lbpath(obj['filename']))[0]
    datawcs = wcs.WCS(fh.header)
    data = fh.data
    beam = radio_beam.Beam.from_fits_header(fh.header)
    pixreg = obj['aperture'].to_pixel(datawcs)
    mask = pixreg.to_mask()
    cutout = mask.cutout(data) * mask.data

    pkflux = cutout.max() * u.Unit(fh.header['BUNIT'])
    #pkbright = pkflux.to(u.K, beam.jtok_equiv(fh.header['CRVAL3']*u.Unit(fh.header['CUNIT3'])))
    pkbright = pkflux.to(u.K, beam.jtok_equiv(225*u.GHz))
Example #13
0
def gaussfit_catalog(
    fitsfile,
    region_list,
    radius=1.0 * u.arcsec,
    max_radius_in_beams=2,
    max_offset_in_beams=1,
    background_estimator=np.nanmedian,
    noise_estimator=lambda x: mad_std(x, ignore_nan=True),
    savepath=None,
    prefix="",
    covariance='param_cov',
    raise_for_failure=False,
):
    """
    Given a FITS filename and a list of regions, fit a gaussian to each region
    with an input guess based on the beam size.

    Parameters
    ----------
    fitsfile : str
        Name of the FITS file
    region_list : list
        List of regions (see https://github.com/astropy/regions/)
    radius : angular size
        The radius of the region around the region center to extract and
        include in the fit
    max_radius_in_beams : float
        The maximum allowed source radius in units of beam major axis
        (this is a limit passed to the fitter)
    max_offset_in_beams : float
        The maximum allowed offset of the source center from the guessed
        position
    background_estimator : function
        A function to apply to the background pixels (those not within 1 beam
        HWHM of the center) to estimate the background level.  The background
        will be subtracted before fitting.
    noise_estimator : function
        Function to apply to the whole data set to determine the noise level
        and therefore the appropriate per-pixel weight to get the correct
        normalization for the covariance matrix.
    savepath : str or None
        If specified, plots will be made and saved to this directory using the
        source name from the region metadata
    prefix : str
        The prefix to append to saved source names
    covariance : 'param_cov' or 'cov_x'
        Which covariance matrix should be used to estimate the parameter
        errors?  ``param_cov`` uses the diagonal of the reduced-chi^2-scaled
        covariance matrix to compute the parameter errors, while ``cov_x`` uses
        the unscaled errors.  See http://arxiv.org/abs/1009.2755 for a
        description, and criticism, of using the scaled covariance.
    raise_for_failure : bool
        If the fit was not successful, raise an exception
    """

    # need central coordinates of each object
    coords = coordinates.SkyCoord([reg.center for reg in region_list])

    fh = fits.open(fitsfile)
    data = fh[0].data.squeeze()
    header = fh[0].header
    datawcs = wcs.WCS(header).celestial
    beam = Beam.from_fits_header(header)
    pixscale = wcs.utils.proj_plane_pixel_area(datawcs)**0.5 * u.deg
    bmmin_px = (beam.minor.to(u.deg) / pixscale).decompose()
    bmmaj_px = (beam.major.to(u.deg) / pixscale).decompose()

    noise = noise_estimator(data)

    log.info("Noise estimate is {0} for file {1}".format(noise, fitsfile))

    fit_data = {}

    pb = ProgressBar(len(region_list))

    for ii, reg in enumerate(region_list):

        phot_reg = regions.CircleSkyRegion(center=reg.center, radius=radius)
        pixreg = phot_reg.to_pixel(datawcs)
        mask = pixreg.to_mask()
        mask_cutout = mask.cutout(data)
        if mask_cutout is None:
            log.warning(
                "Skipping region {0} because it failed to produce a cutout.".
                format(reg))
            continue
        cutout = mask_cutout * mask.data
        cutout_mask = mask.data.astype('bool')

        smaller_phot_reg = regions.CircleSkyRegion(center=reg.center,
                                                   radius=beam.major /
                                                   2.)  #FWHM->HWHM
        smaller_pixreg = smaller_phot_reg.to_pixel(datawcs)
        smaller_mask = smaller_pixreg.to_mask()
        smaller_cutout = smaller_mask.cutout(data) * smaller_mask.data

        # mask out (as zeros) neighboring sources within the fitting area
        nearby_matches = phot_reg.contains(coords, datawcs)
        if any(nearby_matches):
            inds = np.where(nearby_matches)[0].tolist()
            inds.remove(ii)
            for ind in inds:
                maskoutreg = regions.EllipseSkyRegion(
                    center=region_list[ind].center,
                    width=beam.major,
                    height=beam.minor,
                    angle=beam.pa + 90 * u.deg,
                )
                mpixreg = maskoutreg.to_pixel(datawcs)
                mmask = mpixreg.to_mask()

                view, mview = slice_bbox_from_bbox(mask.bbox, mmask.bbox)
                cutout_mask[view] &= ~mmask.data.astype('bool')[mview]
                cutout = cutout * cutout_mask

        background_mask = cutout_mask.copy().astype('bool')
        background_mask[sub_bbox_slice(
            mask.bbox, smaller_mask.bbox)] &= ~smaller_mask.data.astype('bool')
        background = background_estimator(cutout[background_mask])

        sz = cutout.shape[0]
        mx = np.nanmax(smaller_cutout)
        ampguess = mx - background

        p_init = models.Gaussian2D(
            amplitude=ampguess,
            x_mean=sz / 2,
            y_mean=sz / 2,
            x_stddev=bmmaj_px / STDDEV_TO_FWHM,
            y_stddev=bmmin_px / STDDEV_TO_FWHM,
            theta=beam.pa,
            bounds={
                'x_stddev': (bmmin_px / STDDEV_TO_FWHM * 0.75,
                             bmmaj_px * max_radius_in_beams / STDDEV_TO_FWHM),
                'y_stddev': (bmmin_px / STDDEV_TO_FWHM * 0.75,
                             bmmaj_px * max_radius_in_beams / STDDEV_TO_FWHM),
                'x_mean':
                (sz / 2 - max_offset_in_beams * bmmaj_px / STDDEV_TO_FWHM,
                 sz / 2 + max_offset_in_beams * bmmaj_px / STDDEV_TO_FWHM),
                'y_mean':
                (sz / 2 - max_offset_in_beams * bmmaj_px / STDDEV_TO_FWHM,
                 sz / 2 + max_offset_in_beams * bmmaj_px / STDDEV_TO_FWHM),
                'amplitude': (ampguess * 0.9, ampguess * 1.1),
                'theta': (0, 2 * np.pi),
            })

        imtofit = np.nan_to_num((cutout - background) * mask.data)
        result, fit_info, chi2, fitter = gaussfit_image(
            image=imtofit,
            gaussian=p_init,
            weights=1 / noise**2,
            plot=savepath is not None,
        )
        if 'text' in reg.meta:
            sourcename = reg.meta['text'].strip('{}')
        elif 'label' in reg.meta:
            sourcename = reg.meta['label'].strip('{}')
        else:
            raise ValueError("Regions need to have names, either as 'text' or "
                             "'label' entries.")

        if savepath is not None:
            with warnings.catch_warnings():
                warnings.simplefilter('ignore', UserWarning)
                bmarr = beam.as_kernel(pixscale=pixscale, x_size=sz,
                                       y_size=sz).array
            assert bmarr.max() > 0
            bm_ellipse = beam.ellipse_to_plot(sz / 2, sz / 2., pixscale)
            bm_ellipse.set_facecolor('none')
            bm_ellipse.set_edgecolor('r')
            pl.gca().add_patch(bm_ellipse)
            #pl.contour(bmarr, levels=[0.317*bmarr.max()], colors=['r'])
            pl.savefig(os.path.join(savepath,
                                    '{0}{1}.png'.format(prefix, sourcename)),
                       bbox_inches='tight')

        if covariance not in fit_info or fit_info[covariance] is None:
            fit_info[covariance] = np.zeros([6, 6])
            success = False
        else:
            success = True

        cx, cy = pixreg.bounding_box.ixmin + result.x_mean, pixreg.bounding_box.iymin + result.y_mean
        clon, clat = datawcs.wcs_pix2world(cx, cy, 0)

        major, minor = (result.x_stddev * STDDEV_TO_FWHM *
                        pixscale.to(u.arcsec), result.y_stddev *
                        STDDEV_TO_FWHM * pixscale.to(u.arcsec))
        majind, minind = 3, 4
        pa = (result.theta * u.rad).to(u.deg)
        if minor > major:
            major, minor = minor, major
            majind, minind = minind, majind
            pa += 90 * u.deg
            if pa > 360 * u.deg:
                pa -= 360 * u.deg

        fitted_gaussian_as_beam = Beam(major=major, minor=minor, pa=pa)
        try:
            deconv_fit = fitted_gaussian_as_beam.deconvolve(beam)
            deconv_major, deconv_minor, deconv_pa = (deconv_fit.major,
                                                     deconv_fit.minor,
                                                     deconv_fit.pa)
        except ValueError:
            print("Could not deconvolve {0} from {1}".format(
                beam.__repr__(), fitted_gaussian_as_beam.__repr__()))
            deconv_major, deconv_minor, deconv_pa = np.nan, np.nan, np.nan

        if pa < -360 * u.deg or pa > 360 * u.deg:
            raise ValueError("PA is set incorrectly.")
        if deconv_pa < -360 * u.deg or deconv_pa > 360 * u.deg:
            raise ValueError("Deconvolved PA is set incorrectly.")

        fit_data[sourcename] = {
            'amplitude':
            result.amplitude,
            'center_x':
            float(clon) * u.deg,
            'center_y':
            float(clat) * u.deg,
            'fwhm_major':
            major,
            'fwhm_minor':
            minor,
            'pa':
            pa,
            'deconv_fwhm_major':
            deconv_major,
            'deconv_fwhm_minor':
            deconv_minor,
            'deconv_pa':
            deconv_pa,
            'chi2':
            chi2,
            'chi2/n':
            chi2 / mask.data.sum(),
            'e_amplitude':
            fit_info[covariance][0, 0]**0.5,
            'e_center_x':
            fit_info[covariance][1, 1]**0.5 * pixscale,
            'e_center_y':
            fit_info[covariance][2, 2]**0.5 * pixscale,
            'e_fwhm_major':
            fit_info[covariance][majind, majind]**0.5 * STDDEV_TO_FWHM *
            pixscale.to(u.arcsec),
            'e_fwhm_minor':
            fit_info[covariance][minind, minind]**0.5 * STDDEV_TO_FWHM *
            pixscale.to(u.arcsec),
            'e_pa':
            fit_info[covariance][5, 5]**0.5 * u.deg,
            'success':
            success,
            'ampguess':
            ampguess,
            'peak':
            mx,
            'fit_info':
            fit_info,
        }

        if raise_for_failure and not success:
            raise ValueError("Fit failed.")

        pb.update(ii)
        signal.signal(signal.SIGINT, signal_handler)

    return fit_data
def create_catalog(param_file):
    params = ascii.read(param_file)

    for row in range(len(params)):
        name = params['name'][
            row]  #contains parameters for dendrogram catalog creation
        min_val = params['min_value'][row]
        min_del = params['min_delta'][row]
        n_pix = params['n_pix'][row]
        img = params['file_name'][row]
        reg_fname = '/home/jotter/nrao/images/dendro_regions/' + name + '_reg_file.reg'
        dendro, cat = compute_regions(min_val, min_del, n_pix, img, reg_fname)
        cat['flux_err_' + name] = np.zeros(len(cat))
        if params['pbcorr'][
                row] != 'True':  #if the image is not pb corrected, measure flux from pb corrected image
            img = params['pbcorr'][row]
        cont_file = fits.open(img)
        header = cont_file[0].header
        mywcs = WCS(header).celestial
        data = cont_file[0].data.squeeze()
        beam = radio_beam.Beam.from_fits_header(header)
        pixel_scale = np.abs(
            mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
        ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

        cat.rename_column('_idx', '_idx_' + name)

        #next, measure centroids with gaussian fitting
        rad = Angle(1, 'arcsecond')  #radius for region list

        regs = []
        for ind, leaf in enumerate(
                dendro.all_structures):  #.leaves #generate region list
            regs.append(
                regions.CircleSkyRegion(
                    center=SkyCoord(cat['x_cen'][ind] * u.degree,
                                    cat['y_cen'][ind] * u.degree),
                    radius=rad,
                    meta={'text': str(cat['_idx_' + name][ind])}))
        print(len(regs))
        #if name == 'B6':
        #regs.append(regions.CircleSkyRegion(center=SkyCoord(83.81138026377482*u.degree, -5.374951161716349*u.degree), radius=rad, meta={'text':'54'}))#manually appending a source not picked up by dendrogram

        cat_r = Angle(0.3, 'arcsecond')  #radius in gaussian fitting
        gauss_cat = gaussfit_catalog(
            img,
            regs,
            cat_r,
            savepath='/home/jotter/nrao/gauss_diags/leaves/' +
            name)  #output is nested dictionary structure

        gauss_fit_tab = Table(
            names=('_idx_' + name, 'gauss_x_' + name, 'x_err_' + name,
                   'gauss_y_' + name, 'y_err_' + name, 'FWHM_major_' + name,
                   'major_err_' + name, 'FWHM_minor_' + name,
                   'minor_err_' + name, 'position_angle_' + name,
                   'position_angle_err_' + name, 'peak_flux_' + name,
                   'gauss_amplitude_' + name, 'amplitude_err_' + name,
                   'ap_flux_' + name, 'ap_flux_err_' + name,
                   'fit_goodness_' + name),
            dtype=('i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
                   'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
                   'U10'))  #turn into astropy table
        for key in gauss_cat:
            gauss_fit_tab.add_row(
                (key, gauss_cat[key]['center_x'], gauss_cat[key]['e_center_x'],
                 gauss_cat[key]['center_y'], gauss_cat[key]['e_center_y'],
                 gauss_cat[key]['fwhm_major'], gauss_cat[key]['e_fwhm_major'],
                 gauss_cat[key]['fwhm_minor'], gauss_cat[key]['e_fwhm_minor'],
                 gauss_cat[key]['pa'], gauss_cat[key]['e_pa'],
                 gauss_cat[key]['peak'], gauss_cat[key]['amplitude'],
                 gauss_cat[key]['e_amplitude'], np.nan, np.nan,
                 'none'))  #fill table

        for row in range(len(gauss_fit_tab)):
            pix_major_fwhm = ((gauss_fit_tab['FWHM_major_' + name][row] *
                               u.arcsec).to(u.degree) /
                              pixel_scale).decompose()
            pix_minor_fwhm = ((gauss_fit_tab['FWHM_minor_' + name][row] *
                               u.arcsec).to(u.degree) /
                              pixel_scale).decompose()
            cutout_center = SkyCoord(gauss_fit_tab['gauss_x_' + name][row],
                                     gauss_fit_tab['gauss_y_' + name][row],
                                     frame='icrs',
                                     unit=(u.deg, u.deg))
            cutout_center_pix = cutout_center.to_pixel(mywcs)
            cutout_center_pix = regions.PixCoord(cutout_center_pix[0],
                                                 cutout_center_pix[1])
            position_angle = gauss_fit_tab['position_angle_' +
                                           name][row] * u.deg
            ellipse_reg = regions.EllipsePixelRegion(cutout_center_pix,
                                                     pix_major_fwhm * 2.,
                                                     pix_minor_fwhm * 2.,
                                                     angle=position_angle)
            size = pix_major_fwhm * 2.1
            ap_mask = ellipse_reg.to_mask()
            cutout_mask = ap_mask.cutout(data)

            aperture_flux = np.sum(cutout_mask[ap_mask.data == 1]) / ppbeam
            gauss_fit_tab['ap_flux_' + name][row] = aperture_flux

            #NOTE: aperture flux error and background fluxes will get filled in after running `snr_rejection.py`

        full_cat = join(cat,
                        gauss_fit_tab,
                        keys='_idx_' + name,
                        join_type='outer'
                        )  #joining the gaussian centroid data with the rest
        full_cat.write('/home/jotter/nrao/tables/dendro_catalogs/' + name +
                       '_dendro_catalog_leaves.fits',
                       format='fits',
                       overwrite=True)
Example #15
0
def bg_gaussfit(
    fitsfile,
    region,
    region_list,
    radius=1.0 * u.arcsec,
    max_radius_in_beams=2,
    max_offset_in_beams=1,
    max_offset_in_beams_bg=10,
    bg_stddev_x=40,
    bg_stddev_y=40,
    bg_mean_x=0,
    bg_mean_y=0,
    mask_size=1.5,
    background_estimator=np.nanmedian,
    noise_estimator=lambda x: mad_std(x, ignore_nan=True),
    savepath=None,
    prefix="",
    covariance='param_cov',
    raise_for_failure=False,
):
    """
    Given a FITS filename and a region, fit a gaussian to the region
    with an input guess based on the beam size, and fit a gaussian to the background.

    Parameters
    ----------
    fitsfile : str
        Name of the FITS file
    region : region object
        single region from regions (see https://github.com/astropy/regions/)
    region_list : list of regions
        list of all regions - for masking out nearby sources
    radius : angular size
        The radius of the region around the region center to extract and
        include in the fit
    max_radius_in_beams : float
        The maximum allowed source radius in units of beam major axis
        (this is a limit passed to the fitter)
    max_offset_in_beams : float
        The maximum allowed offset of the source center from the guessed
        position
    max_offset_in_beams_bg : float
        same as above but for background gaussian
    bg_stddev_x : float
        Guess for standard deviation in x direction for background gaussian
    bg_stddev_y : float
        Same as above, in y direction
    bg_mean_x/y : float
        pixels away for background gaussian mean guess, with origin at center
    mask_size : float
        size in beams of mask to be applied to nearby sources
    background_estimator : function
        A function to apply to the background pixels (those not within 1 beam
        HWHM of the center) to estimate the background level.  The background
        will be subtracted before fitting.
    noise_estimator : function
        Function to apply to the whole data set to determine the noise level
        and therefore the appropriate per-pixel weight to get the correct
        normalization for the covariance matrix.
    savepath : str or None
        If specified, plots will be made and saved to this directory using the
        source name from the region metadata
    prefix : str
        The prefix to append to saved source names
    covariance : 'param_cov' or 'cov_x'
        Which covariance matrix should be used to estimate the parameter
        errors?  ``param_cov`` uses the diagonal of the reduced-chi^2-scaled
        covariance matrix to compute the parameter errors, while ``cov_x`` uses
        the unscaled errors.  See http://arxiv.org/abs/1009.2755 for a
        description, and criticism, of using the scaled covariance.
    raise_for_failure : bool
        If the fit was not successful, raise an exception
    """

    # need central coordinates of each object
    coords = coordinates.SkyCoord([reg.center for reg in region_list])

    fh = fits.open(fitsfile)
    data = fh[0].data.squeeze()
    header = fh[0].header
    datawcs = wcs.WCS(header).celestial
    beam = Beam.from_fits_header(header)
    pixscale = wcs.utils.proj_plane_pixel_area(datawcs)**0.5 * u.deg
    bmmin_px = (beam.minor.to(u.deg) / pixscale).decompose()
    bmmaj_px = (beam.major.to(u.deg) / pixscale).decompose()

    noise = noise_estimator(data)

    log.info("Noise estimate is {0} for file {1}".format(noise, fitsfile))

    fit_data = {}

    phot_reg = regions.CircleSkyRegion(center=region.center, radius=radius)
    pixreg = phot_reg.to_pixel(datawcs)
    mask = pixreg.to_mask()
    mask_cutout = mask.cutout(data)
    if mask_cutout is None:
        log.warning("The region failed to produce a cutout.".format(reg))
        return null
    cutout = mask_cutout * mask.data
    cutout_mask = mask.data.astype('bool')

    smaller_phot_reg = regions.CircleSkyRegion(center=region.center,
                                               radius=beam.major /
                                               2.)  #FWHM->HWHM
    smaller_pixreg = smaller_phot_reg.to_pixel(datawcs)
    smaller_mask = smaller_pixreg.to_mask()
    smaller_cutout = smaller_mask.cutout(data) * smaller_mask.data

    # mask out (as zeros) neighboring sources within the fitting area
    srcind = None
    for ii, reg in enumerate(region_list):
        if reg.center.ra == region.center.ra and reg.center.dec == region.center.dec:
            srcind = ii
            print(srcind)

    #print(region_list)
    #print(region)

    nearby_matches = phot_reg.contains(coords, datawcs)
    if any(nearby_matches):
        inds = np.where(nearby_matches)[0].tolist()
        print(inds)
        if srcind in inds:
            inds.remove(srcind)
        for ind in inds:
            maskoutreg = regions.EllipseSkyRegion(
                center=region_list[ind].center,
                width=mask_size * beam.major,
                height=mask_size * beam.minor,
                angle=beam.pa + 90 * u.deg,
            )
            mpixreg = maskoutreg.to_pixel(datawcs)
            mmask = mpixreg.to_mask()

            view, mview = slice_bbox_from_bbox(mask.bbox, mmask.bbox)
            cutout_mask[view] &= ~mmask.data.astype('bool')[mview]
            cutout = cutout * cutout_mask

    background_mask = cutout_mask.copy().astype('bool')
    background_mask[sub_bbox_slice(
        mask.bbox, smaller_mask.bbox)] &= ~smaller_mask.data.astype('bool')
    background = background_estimator(cutout[background_mask])

    sz = cutout.shape[0]
    mx = np.nanmax(smaller_cutout)
    ampguess = mx - background
    imtofit = np.nan_to_num((cutout - background) * mask.data)
    src_gauss = [
        ampguess, sz / 2, bmmaj_px.value, bmmin_px.value, beam.pa.value
    ]
    bg_gauss = [
        background, bg_mean_x + sz / 2, bg_mean_y + sz / 2, bg_stddev_x,
        bg_stddev_y, beam.pa.value
    ]
    bnds = [max_radius_in_beams, max_offset_in_beams, max_offset_in_beams_bg]

    result, fit_info, chi2, fitter, img_bgsub = gaussfit_image(
        image=imtofit,
        gauss_params=src_gauss,
        bg_gauss_params=bg_gauss,
        bound_params=bnds,
        weights=1 / noise**2,
        plot=savepath is not None,
    )
    sourcename = region.meta['text'].strip('{}')

    if savepath is not None:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', UserWarning)
            bmarr = beam.as_kernel(pixscale=pixscale, x_size=sz,
                                   y_size=sz).array
        assert bmarr.max() > 0
        bm_ellipse = beam.ellipse_to_plot(sz / 2, sz / 2., pixscale)
        bm_ellipse.set_facecolor('none')
        bm_ellipse.set_edgecolor('r')
        pl.gca().add_patch(bm_ellipse)
        #pl.contour(bmarr, levels=[0.317*bmarr.max()], colors=['r'])
        pl.savefig(os.path.join(savepath,
                                '{0}{1}.png'.format(prefix, sourcename)),
                   bbox_inches='tight')

    if covariance not in fit_info or fit_info[covariance] is None:
        fit_info[covariance] = np.zeros([6, 6])
        success = False
    else:
        success = True

    cx, cy = pixreg.bounding_box.ixmin + result.x_mean_0, pixreg.bounding_box.iymin + result.y_mean_0
    clon, clat = datawcs.wcs_pix2world(cx, cy, 0)

    major, minor = (result.x_stddev_0 * STDDEV_TO_FWHM * pixscale.to(u.arcsec),
                    result.y_stddev_0 * STDDEV_TO_FWHM * pixscale.to(u.arcsec))
    majind, minind = 3, 4
    pa = (result.theta_0 * u.rad).to(u.deg)
    if minor > major:
        major, minor = minor, major
        majind, minind = minind, majind
        pa += 90 * u.deg

    fitted_gaussian_as_beam = Beam(major=major, minor=minor, pa=pa)
    try:
        deconv_fit = fitted_gaussian_as_beam.deconvolve(beam)
        deconv_major, deconv_minor, deconv_pa = (deconv_fit.major,
                                                 deconv_fit.minor,
                                                 deconv_fit.pa)
        deconv_maj_err = fit_info[covariance][
            majind, majind]**0.5 * STDDEV_TO_FWHM * pixscale.to(u.arcsec)
        deconv_min_err = fit_info[covariance][
            minind, minind]**0.5 * STDDEV_TO_FWHM * pixscale.to(u.arcsec)
        deconv_pa_err = fit_info[covariance][5, 5]**0.5 * u.deg
    except ValueError:
        print("Could not deconvolve {0} from {1}".format(
            beam.__repr__(), fitted_gaussian_as_beam.__repr__()))
        deconv_major, deconv_minor, deconv_pa = np.nan, np.nan, np.nan
        deconv_maj_err, deconv_min_err, deconv_pa_err = np.nan, np.nan, np.nan
    fit_data[sourcename] = {
        'amplitude':
        result.amplitude_0,
        'center_x':
        float(clon) * u.deg,
        'center_y':
        float(clat) * u.deg,
        'fwhm_major':
        major,
        'fwhm_minor':
        minor,
        'pa':
        pa,
        'deconv_fwhm_major':
        deconv_major,
        'e_deconv_fwhm_major':
        deconv_maj_err,
        'deconv_fwhm_minor':
        deconv_minor,
        'e_deconv_fwhm_minor':
        deconv_min_err,
        'deconv_pa':
        deconv_pa,
        'e_deconv_pa':
        deconv_pa_err,
        'chi2':
        chi2,
        'chi2/n':
        chi2 / mask.data.sum(),
        'e_amplitude':
        fit_info[covariance][0, 0]**0.5,
        'e_center_x':
        fit_info[covariance][1, 1]**0.5 * pixscale,
        'e_center_y':
        fit_info[covariance][2, 2]**0.5 * pixscale,
        'e_fwhm_major':
        fit_info[covariance][majind, majind]**0.5 * STDDEV_TO_FWHM *
        pixscale.to(u.arcsec),
        'e_fwhm_minor':
        fit_info[covariance][minind, minind]**0.5 * STDDEV_TO_FWHM *
        pixscale.to(u.arcsec),
        'e_pa':
        fit_info[covariance][5, 5]**0.5 * u.deg,
        'success':
        success,
        'ampguess':
        ampguess,
        'peak':
        mx,
        'fit_info':
        fit_info,
    }

    if raise_for_failure and not success:
        raise ValueError("Fit failed.")

    signal.signal(signal.SIGINT, signal_handler)

    return fit_data, img_bgsub
def measure_fluxes_gaussfit(data,
                            directory,
                            data_name,
                            name_start=27,
                            name_end=-21,
                            ref_name='B6'):

    #This function takes a directory full of images and adds them all to a catalog with flux measurements and fits gaussians. 'data' is the catalog to get positions from, 'ref_name' is the name of the reference data (for positions), 'directory' is the directory with all the new images.

    cat = Table.read(data)
    RA_names = ['gauss_x_B3', 'gauss_x_B6', 'gauss_x_B7_hr']
    inds = []
    for fn in RA_names:
        ind = np.where(np.isnan(cat[fn]) == False)
        inds.append(ind)
    detected = reduce(
        np.intersect1d, inds
    )  #sources detected in B3, B6, B7 - only make measurements on these sources
    cat = cat[detected]

    imgs = glob.glob(directory + '*r-2.clean0.1mJy.500klplus.deepmask*')
    img_names = [img[len(directory) + name_start:name_end] for img in imgs]

    col_names = fnmatch.filter(cat.colnames, 'ap_flux_r*')
    col_names = [cn[8:] for cn in col_names]

    for j, img in enumerate(imgs):
        name = img_names[j]
        if len(name) > 54:
            name = name[0:53]
        if name not in col_names:
            fl = fits.open(img)
            header = fl[0].header
            try:
                img_data = fl[0].data.squeeze()
            except TypeError:
                print("error! img: " + img)
                continue
            mywcs = WCS(header).celestial

            beam = radio_beam.Beam.from_fits_header(header)
            pixel_scale = np.abs(
                mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
            ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

            save_dir = '/lustre/aoc/students/jotter/gauss_diags/diff_imgs/' + ref_name + '/' + name + '/'
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)

            reg_file = '/users/jotter/summer_research_2018/final_regs/' + name + '_reg_file_B6_apflux.reg'
            with open(reg_file, 'w') as fh:
                fh.write("fk5\n")
                for ind in range(len(cat)):
                    fh.write(
                        'ellipse({x_cen}, {y_cen}, {maj}, {minr}, {ang}) #text={{{ID}}}\n'
                        .format(x_cen=cat['gauss_x_' + ref_name][ind],
                                y_cen=cat['gauss_y_' + ref_name][ind],
                                maj=(cat['FWHM_major_' + ref_name][ind] *
                                     u.arcsec.to(u.degree)),
                                minr=(cat['FWHM_minor_' + ref_name][ind] *
                                      u.arcsec.to(u.degree)),
                                ang=cat['position_angle_' + ref_name][ind],
                                ID=str(cat['D_ID'][ind])))

            rad = Angle(1, 'arcsecond')  #radius for region list
            regs = []

            for ind in range(len(cat)):
                reg = regions.CircleSkyRegion(center=SkyCoord(
                    cat['gauss_x_' + ref_name][ind] * u.degree,
                    cat['gauss_y_' + ref_name][ind] * u.degree),
                                              radius=rad,
                                              meta={
                                                  'text': str(cat['D_ID'][ind])
                                              })
                reg_pix = reg.to_pixel(mywcs)
                if reg_pix.center.x > 0 and reg_pix.center.x < len(
                        img_data[0]):
                    if reg_pix.center.y > 0 and reg_pix.center.y < len(
                            img_data):
                        regs.append(reg)

            cat_r = Angle(0.5, 'arcsecond')  #radius in gaussian fitting
            gauss_cat = gaussfit_catalog(
                img, regs, cat_r,
                savepath=save_dir)  #output is nested dictionary structure

            gauss_fit_tab = Table(
                names=('D_ID', 'FWHM_major_' + name, 'major_err_' + name,
                       'FWHM_minor_' + name, 'minor_err_' + name, 'pa_' + name,
                       'pa_err_' + name, 'g_amplitude_' + name,
                       'amp_err_' + name),
                dtype=('i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8'))
            for key in gauss_cat:
                gauss_fit_tab.add_row(
                    (key, gauss_cat[key]['fwhm_major'],
                     gauss_cat[key]['e_fwhm_major'],
                     gauss_cat[key]['fwhm_minor'],
                     gauss_cat[key]['e_fwhm_minor'], gauss_cat[key]['pa'],
                     gauss_cat[key]['e_pa'], gauss_cat[key]['amplitude'],
                     gauss_cat[key]['e_amplitude']))  #fill table

            cat = join(cat, gauss_fit_tab, keys='D_ID', join_type='left')

            ap_flux_arr = []
            circ_flux_arr = []
            ap_flux_err_arr = []
            circ_flux_err_arr = []
            bg_median_arr = []
            bg_ap_arr = []
            bg_circ_arr = []

            for row in range(len(cat)):
                pix_major_fwhm = ((cat['FWHM_major_' + ref_name][row] *
                                   u.arcsec).to(u.degree) /
                                  pixel_scale).decompose()
                pix_minor_fwhm = ((cat['FWHM_minor_' + ref_name][row] *
                                   u.arcsec).to(u.degree) /
                                  pixel_scale).decompose()

                center_coord = SkyCoord(cat['gauss_x_' + ref_name][row],
                                        cat['gauss_y_' + ref_name][row],
                                        frame='icrs',
                                        unit=(u.deg, u.deg))
                center_coord_pix = center_coord.to_pixel(mywcs)
                center_coord_pix_reg = regions.PixCoord(
                    center_coord_pix[0], center_coord_pix[1])
                position_angle = cat['position_angle_' + ref_name][row] * u.deg
                print(center_coord_pix_reg, pix_major_fwhm, pix_minor_fwhm)
                ellipse_reg = regions.EllipsePixelRegion(center_coord_pix_reg,
                                                         pix_major_fwhm * 2.,
                                                         pix_minor_fwhm * 2.,
                                                         angle=position_angle)
                size = pix_major_fwhm * 2.1
                ap_mask = ellipse_reg.to_mask()
                cutout_mask = ap_mask.cutout(img_data)

                aperture_flux = np.sum(cutout_mask[ap_mask.data == 1]) / ppbeam
                npix = len(cutout_mask[ap_mask.data == 1])
                ap_flux_arr.append(aperture_flux)

                #now creating annulus around source to measure background and ap flux error
                annulus_width = 15
                annulus_radius = 0.1 * u.arcsecond
                annulus_radius_pix = (annulus_radius.to(u.degree) /
                                      pixel_scale).decompose()

                # Cutout section of the image we care about, to speed up computation time
                size = 2.5 * annulus_radius
                cutout = Cutout2D(img_data,
                                  center_coord_pix,
                                  size,
                                  mywcs,
                                  mode='partial')  #cutout of outer circle
                cutout_center = regions.PixCoord(cutout.center_cutout[0],
                                                 cutout.center_cutout[1])

                # Define the aperture regions needed for SNR
                innerann_reg = regions.CirclePixelRegion(
                    cutout_center, annulus_radius_pix)
                outerann_reg = regions.CirclePixelRegion(
                    cutout_center, annulus_radius_pix + annulus_width)

                # Make masks from aperture regions
                annulus_mask = mask(outerann_reg, cutout) - mask(
                    innerann_reg, cutout)

                # Calculate the SNR and aperture flux sums
                pixels_in_annulus = cutout.data[annulus_mask.astype(
                    'bool')]  #pixels within annulus
                bg_rms = rms(pixels_in_annulus)
                ap_bg_rms = bg_rms / np.sqrt(
                    npix / ppbeam)  #rms/sqrt(npix/ppbeam) - rms error per beam
                bg_median = np.median(pixels_in_annulus)

                pix_bg = bg_median * npix / ppbeam

                ap_flux_err_arr.append(ap_bg_rms)
                bg_median_arr.append(bg_median)
                bg_ap_arr.append(pix_bg)

                #now measure circle flux:
                radius = 0.1 * u.arcsecond
                radius_pix = annulus_radius_pix
                circle_reg = regions.CirclePixelRegion(center_coord_pix_reg,
                                                       radius_pix)
                circ_ap_mask = circle_reg.to_mask()
                circ_cutout_mask = circ_ap_mask.cutout(img_data)
                cutout_mask = ap_mask.cutout(img_data)
                circ_aperture_flux = np.sum(
                    circ_cutout_mask[circ_ap_mask.data == 1]) / ppbeam
                circ_npix = len(circ_cutout_mask[circ_ap_mask.data == 1])

                circ_bg_rms = bg_rms / np.sqrt(circ_npix / ppbeam)

                circ_flux_arr.append(circ_aperture_flux)
                circ_flux_err_arr.append(circ_bg_rms)
                bg_circ_arr.append(bg_median * circ_npix / ppbeam)

            cols = [
                'ap_flux_', 'ap_flux_err_', 'bg_median_', 'bg_ap_',
                'circ_flux_', 'circ_flux_err_', 'bg_circ_'
            ]
            arrs = [
                ap_flux_arr, ap_flux_err_arr, bg_median_arr, bg_ap_arr,
                circ_flux_arr, circ_flux_err_arr, bg_circ_arr
            ]
            for j in range(len(cols)):
                cat[cols[j] + name] = arrs[j]

    cat.write('/lustre/aoc/students/jotter/dendro_catalogs/' + data_name +
              '_500klplus_allsrcs_catalog_' + ref_name + '_ref.txt',
              format='ascii',
              overwrite=True)
new_fl = orig_fl
new_fl[0].data = fake_img
wcs = WCS(new_fl[0].header).celestial
B3beam = Beam.from_fits_header(new_fl[0].header)

B3_pixel_scale = np.abs(wcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
B3_kernel = B3beam.as_kernel(B3_pixel_scale)

convolved_img = convolve_fft(fake_img, B3_kernel)
new_fl[0].data = convolved_img
new_fl.writeto('/users/jotter/summer_research_2018/fake_conv_img.fits',
               overwrite=True)

loc = wcs.wcs_pix2world(500, 500, 1)
reg = regions.CircleSkyRegion(center=SkyCoord(loc[0], loc[1], unit='deg'),
                              radius=0.5 * u.arcsec,
                              meta={'text': 'test'})
reg_pix = reg.to_pixel(wcs)

gaussfit = gaussfit_catalog(
    '/users/jotter/summer_research_2018/fake_conv_img.fits', [reg],
    Angle(0.5, 'arcsecond'),
    savepath='/users/jotter/summer_research_2018/')

source_size = Beam(major=gaussfit['test']['fwhm_major'],
                   minor=gaussfit['test']['fwhm_minor'],
                   pa=(gaussfit['test']['pa'].value - 90) * u.degree)
try:
    deconv_size = source_size.deconvolve(B3beam)
    print('gaussfit deconv major: ' +
          str(gaussfit['test']['deconv_fwjm_major']) + ' minor: ' +
def measure_fluxes_gaussfit_allsrcs(data,
                                    img,
                                    data_name,
                                    name_start=27,
                                    name_end=-21,
                                    ref_name='B3'):

    cat = Table.read(data)
    RA_name = 'gauss_x_' + ref_name

    ind = np.where(np.isnan(cat[RA_name]) == False)
    cat = cat[ind]

    col_names = fnmatch.filter(cat.colnames, 'ap_flux_r*')
    col_names = [cn[8:] for cn in col_names]

    fl = fits.open(img)
    header = fl[0].header
    img_data = fl[0].data.squeeze()
    mywcs = WCS(header).celestial

    beam = radio_beam.Beam.from_fits_header(header)
    pixel_scale = np.abs(
        mywcs.pixel_scale_matrix.diagonal().prod())**0.5 * u.deg
    ppbeam = (beam.sr / (pixel_scale**2)).decompose().value

    save_dir = '/lustre/aoc/students/jotter/gauss_diags/diff_imgs/' + ref_name + '/' + data_name + '/'
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    reg_file = '/users/jotter/summer_research_2018/final_regs/misc_regs/' + data_name + '_reg_file_' + ref_name + '_apflux.reg'
    with open(reg_file, 'w') as fh:
        fh.write("fk5\n")
        for ind in range(len(cat)):
            fh.write(
                'ellipse({x_cen}, {y_cen}, {maj}, {minr}, {ang}) #text={{{ID}}}\n'
                .format(x_cen=cat['gauss_x_' + ref_name][ind],
                        y_cen=cat['gauss_y_' + ref_name][ind],
                        maj=(cat['FWHM_major_' + ref_name][ind] *
                             u.arcsec.to(u.degree)),
                        minr=(cat['FWHM_minor_' + ref_name][ind] *
                              u.arcsec.to(u.degree)),
                        ang=cat['position_angle_' + ref_name][ind],
                        ID=str(cat['D_ID'][ind])))

    rad = Angle(1, 'arcsecond')  #radius for region list
    regs = []

    for ind in range(len(cat)):
        reg = regions.CircleSkyRegion(center=SkyCoord(
            cat['gauss_x_' + ref_name][ind] * u.degree,
            cat['gauss_y_' + ref_name][ind] * u.degree),
                                      radius=rad,
                                      meta={'text': str(cat['D_ID'][ind])})
        reg_pix = reg.to_pixel(mywcs)
        if reg_pix.center.x > 0 and reg_pix.center.x < len(img_data[0]):
            if reg_pix.center.y > 0 and reg_pix.center.y < len(img_data):
                if np.isnan(img_data[int(reg_pix.center.x),
                                     int(reg_pix.center.y)]) == False:
                    regs.append(reg)

    cat_r = Angle(0.5, 'arcsecond')  #radius in gaussian fitting
    gauss_cat = gaussfit_catalog(
        img, regs, cat_r,
        savepath=save_dir)  #output is nested dictionary structure

    gauss_fit_tab = Table(
        names=('D_ID', 'FWHM_major_' + data_name, 'major_err_' + data_name,
               'FWHM_minor_' + data_name, 'minor_err_' + data_name,
               'pa_' + data_name, 'pa_err_' + data_name,
               'g_amplitude_' + data_name, 'amp_err_' + data_name),
        dtype=('i4', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8'))
    for key in gauss_cat:
        gauss_fit_tab.add_row(
            (key, gauss_cat[key]['fwhm_major'], gauss_cat[key]['e_fwhm_major'],
             gauss_cat[key]['fwhm_minor'], gauss_cat[key]['e_fwhm_minor'],
             gauss_cat[key]['pa'], gauss_cat[key]['e_pa'],
             gauss_cat[key]['amplitude'],
             gauss_cat[key]['e_amplitude']))  #fill table

    ap_flux_arr = []
    circ_flux_arr = []
    ap_flux_err_arr = []
    circ_flux_err_arr = []
    bg_median_arr = []
    bg_ap_arr = []
    bg_circ_arr = []
    RA = []
    DEC = []
    RA_err = []
    DEC_err = []

    for row in range(len(cat)):
        gauss_ind = np.where(gauss_fit_tab['D_ID'] == cat['D_ID'][row])[0]
        if len(gauss_ind) > 0:
            pix_major_fwhm = (
                (cat['FWHM_major_' + ref_name][row] * u.arcsec).to(u.degree) /
                pixel_scale).decompose()
            pix_minor_fwhm = (
                (cat['FWHM_minor_' + ref_name][row] * u.arcsec).to(u.degree) /
                pixel_scale).decompose()

            center_coord = SkyCoord(cat['gauss_x_' + ref_name][row],
                                    cat['gauss_y_' + ref_name][row],
                                    frame='icrs',
                                    unit=(u.deg, u.deg))
            center_coord_pix = center_coord.to_pixel(mywcs)
            center_coord_pix_reg = regions.PixCoord(center_coord_pix[0],
                                                    center_coord_pix[1])
            position_angle = cat['position_angle_' + ref_name][row] * u.deg

            ellipse_reg = regions.EllipsePixelRegion(center_coord_pix_reg,
                                                     pix_major_fwhm * 2.,
                                                     pix_minor_fwhm * 2.,
                                                     angle=position_angle)
            size = pix_major_fwhm * 2.1
            ap_mask = ellipse_reg.to_mask()
            cutout_mask = ap_mask.cutout(img_data)

            aperture_flux = np.sum(cutout_mask[ap_mask.data == 1]) / ppbeam
            npix = len(cutout_mask[ap_mask.data == 1])
            ap_flux_arr.append(aperture_flux)

            #now creating annulus around source to measure background and ap flux error
            annulus_width = 15
            annulus_radius = 0.1 * u.arcsecond
            annulus_radius_pix = (annulus_radius.to(u.degree) /
                                  pixel_scale).decompose()

            # Cutout section of the image we care about, to speed up computation time
            size = 2.5 * annulus_radius
            cutout = Cutout2D(img_data,
                              center_coord_pix,
                              size,
                              mywcs,
                              mode='partial')  #cutout of outer circle
            cutout_center = regions.PixCoord(cutout.center_cutout[0],
                                             cutout.center_cutout[1])

            # Define the aperture regions needed for SNR
            innerann_reg = regions.CirclePixelRegion(cutout_center,
                                                     annulus_radius_pix)
            outerann_reg = regions.CirclePixelRegion(
                cutout_center, annulus_radius_pix + annulus_width)

            # Make masks from aperture regions
            annulus_mask = mask(outerann_reg, cutout) - mask(
                innerann_reg, cutout)

            # Calculate the SNR and aperture flux sums
            pixels_in_annulus = cutout.data[annulus_mask.astype(
                'bool')]  #pixels within annulus
            bg_rms = rms(pixels_in_annulus)
            ap_bg_rms = bg_rms / np.sqrt(
                npix / ppbeam)  #rms/sqrt(npix/ppbeam) - rms error per beam
            bg_median = np.median(pixels_in_annulus)

            pix_bg = bg_median * npix / ppbeam

            ap_flux_err_arr.append(ap_bg_rms)
            bg_median_arr.append(bg_median)
            bg_ap_arr.append(pix_bg)

            #now measure circle flux:
            radius = 0.1 * u.arcsecond
            radius_pix = annulus_radius_pix
            circle_reg = regions.CirclePixelRegion(center_coord_pix_reg,
                                                   radius_pix)
            circ_ap_mask = circle_reg.to_mask()
            circ_cutout_mask = circ_ap_mask.cutout(img_data)
            cutout_mask = ap_mask.cutout(img_data)
            circ_aperture_flux = np.sum(
                circ_cutout_mask[circ_ap_mask.data == 1]) / ppbeam
            circ_npix = len(circ_cutout_mask[circ_ap_mask.data == 1])

            circ_bg_rms = bg_rms / np.sqrt(circ_npix / ppbeam)

            circ_flux_arr.append(circ_aperture_flux)
            circ_flux_err_arr.append(circ_bg_rms)
            bg_circ_arr.append(bg_median * circ_npix / ppbeam)

            RA.append(cat['gauss_x_' + ref_name][row])
            DEC.append(cat['gauss_y_' + ref_name][row])
            RA_err.append(cat['x_err_' + ref_name][row])
            DEC_err.append(cat['y_err_' + ref_name][row])

    cols = [
        'ap_flux_', 'ap_flux_err_', 'bg_median_', 'bg_ap_', 'circ_flux_',
        'circ_flux_err_', 'bg_circ_'
    ]
    arrs = [
        ap_flux_arr, ap_flux_err_arr, bg_median_arr, bg_ap_arr, circ_flux_arr,
        circ_flux_err_arr, bg_circ_arr
    ]
    cols2 = ['RA_', 'DEC_', 'RA_err_',
             'DEC_err_']  #seperate bc different naming
    arrs2 = [RA, DEC, RA_err, DEC_err]
    for j in range(len(cols)):
        gauss_fit_tab[cols[j] + data_name] = arrs[j]
    for c in range(len(cols2)):
        gauss_fit_tab[cols2[c] + ref_name] = arrs2[c]

    gauss_fit_tab.write('/lustre/aoc/students/jotter/dendro_catalogs/' +
                        data_name + '_500klplus_allsrcs_catalog_' + ref_name +
                        '_ref.txt',
                        format='ascii',
                        overwrite=True)
contfile_north = fits.open(
    paths.dpath('longbaseline/W51n_cont_briggsSC_tclean.image.fits'))
datanorth = u.Quantity(contfile_north[0].data.squeeze(),
                       unit=contfile_north[0].header['BUNIT'])

beam_north = radio_beam.Beam.from_fits_header(contfile_north[0].header)

wcs_north = wcs.WCS(contfile_north[0].header)

# this section repeats the analysis of dust_proerties, but it serves as a nice
# independent check since I did it 6 months later.... give or take...
beam_radius_north = ((beam_north.sr / (2 * np.pi))**0.5 *
                     masscalc.distance).to(u.pc, u.dimensionless_angles())

e2 = regions.CircleSkyRegion(coordinates.SkyCoord('19:23:43.969 +14:30:34.518',
                                                  frame='icrs',
                                                  unit=(u.hour, u.deg)),
                             radius=0.616 * u.arcsec)
e2pix = e2.to_pixel(wcs_e2e8)
e2mask = e2pix.to_mask()

e8 = regions.CircleSkyRegion(coordinates.SkyCoord('19:23:43.907 +14:30:28.267',
                                                  frame='icrs',
                                                  unit=(u.hour, u.deg)),
                             radius=0.464 * u.arcsec)
e8pix = e8.to_pixel(wcs_e2e8)
e8mask = e8pix.to_mask()

north = regions.CircleSkyRegion(coordinates.SkyCoord(
    '19:23:40.054 +14:31:05.513', frame='icrs', unit=(u.hour, u.deg)),
                                radius=0.412 * u.arcsec)
northpix = north.to_pixel(wcs_north)