def main(field, subtraction_path, epoch, instrument, instrument_template, show): comparison_name = f'{field}_{epoch}' params = p.object_params_frb(field) burst_ra = params['burst_ra'] burst_dec = params['burst_dec'] burst_err_a, burst_err_b, theta = am.calculate_error_ellipse(frb=params, error='systematic') hg_ra = params['hg_ra'] hg_dec = params['hg_dec'] burst_err_theta = 0.0 # params['burst_err_theta'] # comparison_params = p.object_params_instrument(comparison_name, instrument) # comparison_outputs = p.object_output_params(comparison_name, instrument) subtraction_path = f'{params["data_dir"]}subtraction/{subtraction_path}' filters = params['filters'] folders = list(filter(lambda file: os.path.isdir(subtraction_path + file), os.listdir(subtraction_path))) folders.sort() output_table = table.Table(names=['name'], dtype=[f'S{len(folders[-1])}']) first = True sextractor_names = p.sextractor_names() print(subtraction_path) for i, folder in enumerate(folders): print() print(folder) subtraction_path_spec = subtraction_path + folder + '/' output_table.add_row() output_table['name'][i] = folder for f in filters: print() print(f) f_0 = f[0] destination_path_filter = f'{subtraction_path_spec}{f}/' template_epoch = params['template_epoch_' + instrument_template.lower()] template_name = f'{field}_{template_epoch}' print(destination_path_filter) print('Finding files...') cats = list(filter(lambda file: file[-15:] == '_comparison.csv', os.listdir(f'{destination_path_filter}'))) comparisons = list(filter(lambda file: file[-24:] == '_comparison_aligned.fits', os.listdir(f'{destination_path_filter}'))) differences = list(filter(lambda file: file[-16:] == '_difference.fits', os.listdir(f'{destination_path_filter}'))) if cats: # If the generated catalogue was successfully copied. print('Loading generated table...') cat_generated_file = cats[0] cat_generated_path = f'{destination_path_filter}{cat_generated_file}' cat_generated = table.Table.read(cat_generated_path, format='ascii.csv') if comparisons and differences: # If the subtraction was successful. comparison_image_file = comparisons[0] difference_image_file = differences[0] print('Loading SExtractor table...') cat_sextractor_path = f'{destination_path_filter}difference.cat' comparison_image_path = f'{destination_path_filter}{comparison_image_file}' difference_image_path = f'{destination_path_filter}{difference_image_file}' cat_sextractor = table.Table(np.genfromtxt(cat_sextractor_path, names=sextractor_names)) if len(cat_sextractor) > 0: difference_image = fits.open(difference_image_path) comparison_image = fits.open(comparison_image_path) comparison_header = comparison_image[0].header exp_time = comparison_header['EXPTIME'] print('Selecting zeropoint...') comparison_zeropoint, _, airmass, _, comparison_extinction, _ = ph.select_zeropoint( comparison_name, f, instrument=instrument) print('Matching coordinates...') match_ids_generated, match_ids_sextractor, match_distances = u.match_cat( x_cat=cat_sextractor['ra'], y_cat=cat_sextractor[ 'dec'], x_match=cat_generated[ 'ra'], y_match=cat_generated[ 'dec'], tolerance=2 / 3600, world=True, return_dist=True) matches_sextractor = cat_sextractor[match_ids_sextractor] matches_generated = cat_generated[match_ids_generated] w = wcs.WCS(header=difference_image[0].header) hg_x, hg_y = w.all_world2pix(hg_ra, hg_dec, 0) # norm = plotting.nice_norm(difference_image[0].data) # print('Generating full-image plot...') # plt.figure(figsize=(30, 20)) # plt.imshow(difference_image[0].data, norm=norm, origin='lower') # plotting.plot_all_params(image=difference_image, cat=cat_sextractor, show=False) # # plt.legend() # plt.savefig(f'{destination_path_filter}recovered_all.png') # if show: # plt.show() # plt.close() plt.figure(figsize=(6, 8)) print('Generating cutout plot...') cutout = ff.trim(difference_image, int(hg_x) - 20, int(hg_x) + 20, int(hg_y) - 20, int(hg_y) + 20) plotting.plot_all_params(image=difference_image, cat=matches_sextractor, show=False) plotting.plot_gal_params(hdu=difference_image, ras=[burst_ra], decs=[burst_dec], a=[burst_err_a], b=[burst_err_b], theta=[burst_err_theta], colour='blue', show_centre=True, label='Burst') norm = plotting.nice_norm(cutout[0].data) plt.imshow(cutout[0].data, norm=norm, origin='lower') plt.scatter(hg_x - (int(hg_x) - 20), hg_y - (int(hg_y) - 20), c='orange', label='Galaxy centroid') for obj in matches_generated: plt.scatter(obj['x_0'] - (int(hg_x) - 20), obj['y_0'] - (int(hg_y) - 20), c='white', label='Generated') plt.legend() plt.savefig(f'{destination_path_filter}recovered.png') if show: plt.show() plt.close() matches_sextractor['mag_sextractor'], _, _ = ph.magnitude_complete( flux=matches_sextractor['flux_auto'], exp_time=exp_time, airmass=airmass, zeropoint=comparison_zeropoint, ext=comparison_extinction) matches = table.hstack([matches_generated, matches_sextractor], table_names=['generated', 'sextracted']) matches['delta_mag'] = matches['mag_sextractor'] - matches['mag'] delta_mag = np.median(matches['delta_mag']) matches.write( f'{destination_path_filter}{field}_{epoch}-{template_epoch}_difference_matched_sources.csv', format='ascii.csv', overwrite=True) print(f'{len(matches)} matches / {len(cat_generated)} generated = ' f'{100 * len(matches) / len(cat_generated)} % ') # TODO: Will need to rewrite this if you want to insert more than one synthetic. output_table = table_setup(f, first, output_table, cat_generated) output_table[f + '_subtraction_successful'][i] = True if len(matches) > 0: print(f'Faintest recovered: {max(matches["mag"])} generated; ' f'{max(matches_sextractor["mag_sextractor"])} sextracted') print('Median delta mag:', delta_mag) if show: plt.scatter(matches['mag'], matches['delta_mag']) plt.show() arg_faintest = np.argmax(matches["mag"]) output_table[f + '_mag_generated'][i] = cat_generated["mag"][arg_faintest] output_table[f + '_mag_recovered'][i] = matches['mag_sextractor'][arg_faintest] output_table[f + '_difference'][i] = delta_mag output_table[f + '_matching_distance_arcsec'][i] = match_distances[arg_faintest] * 3600 output_table[f + '_nuclear_offset_pix_x'][i] = matches['x'][arg_faintest] - hg_x output_table[f + '_nuclear_offset_pix_y'][i] = matches['y'][arg_faintest] - hg_y for col in cat_generated.colnames: output_table[f + '_' + col][i] = cat_generated[col][arg_faintest] else: # If there were no matches output_table[f + '_mag_generated'][i] = cat_generated["mag"][0] output_table[f + '_mag_recovered'][i] = np.nan output_table[f + '_difference'][i] = np.nan output_table[f + '_matching_distance_arcsec'][i] = np.nan output_table[f + '_nuclear_offset_pix_x'][i] = np.nan output_table[f + '_nuclear_offset_pix_y'][i] = np.nan for col in cat_generated.colnames: output_table[f + '_' + col][i] = cat_generated[col][0] else: # If SExtractor was not successful, probably because of a blank difference image output_table = table_setup(f, first, output_table, cat_generated) output_table[f + '_mag_generated'][i] = cat_generated["mag"][0] output_table[f + '_subtraction_successful'][i] = False output_table[f + '_mag_recovered'][i] = np.nan output_table[f + '_difference'][i] = np.nan output_table[f + '_matching_distance_arcsec'][i] = np.nan output_table[f + '_nuclear_offset_pix_x'][i] = np.nan output_table[f + '_nuclear_offset_pix_y'][i] = np.nan for col in cat_generated.colnames: output_table[f + '_' + col][i] = cat_generated[col][0] else: # If the subtraction was not successful. output_table = table_setup(f, first, output_table, cat_generated) output_table[f + '_mag_generated'][i] = cat_generated["mag"][0] output_table[f + '_subtraction_successful'][i] = False output_table[f + '_mag_recovered'][i] = np.nan output_table[f + '_difference'][i] = np.nan output_table[f + '_matching_distance_arcsec'][i] = np.nan output_table[f + '_nuclear_offset_pix_x'][i] = np.nan output_table[f + '_nuclear_offset_pix_y'][i] = np.nan for col in cat_generated.colnames: output_table[f + '_' + col][i] = cat_generated[col][0] else: # If the generated catalogue was not successfully copied. output_table[f + '_mag_generated'][i] = np.nan output_table[f + '_subtraction_successful'][i] = True output_table[f + '_mag_recovered'][i] = np.nan output_table[f + '_mag_generated'][i] = np.nan output_table[f + '_difference'][i] = np.nan output_table[f + '_matching_distance_arcsec'][i] = np.nan output_table[f + '_nuclear_offset_pix_x'][i] = np.nan output_table[f + '_nuclear_offset_pix_y'][i] = np.nan first = False plt.close() for f in filters: plt.scatter(output_table[f + '_mag_generated'], output_table[f + '_mag_recovered'], label=f) plt.plot([min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], [min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], c='red', linestyle=':') plt.ylim(20, 30) plt.savefig(subtraction_path + 'genvrecovered_' + f + '.png') plt.close() plt.scatter(output_table[f + '_mag_generated'], output_table[f + '_mag_recovered'] - output_table[f + '_mag_generated'], label=f) plt.plot([min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], [0, 0], c='red', linestyle=':') plt.xlim(20, 30) plt.savefig(subtraction_path + 'residuals_' + f + '.png') plt.close() for f in filters: plt.scatter(output_table[f + '_mag_generated'], output_table[f + '_mag_recovered'] - output_table[f + '_mag_generated'], label=f) plt.plot([min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], [0, 0], c='red', linestyle=':') plt.xlim(20, 30) plt.ylabel('Recovered magnitudes') plt.legend() plt.savefig(subtraction_path + 'residuals.png') if show: plt.show() plt.close() for f in filters: plt.scatter(output_table[f + '_mag_generated'], output_table[f + '_mag_recovered'], label=f) plt.plot([min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], [min(output_table[f + '_mag_generated']), max(output_table[f + '_mag_generated'])], c='red', linestyle=':') plt.xlim(20, 30) plt.ylim(20, 30) plt.xlabel('Generated magnitudes') plt.ylabel('Recovered magnitudes') plt.legend() plt.savefig(subtraction_path + 'genvrecovered.png') if show: plt.show() plt.close() output_table.write(subtraction_path + 'recovery_table.csv', format='ascii.csv', overwrite=True)
def stack(files: list, output: str = None, directory: str = '', stack_type: str = 'median', inherit: bool = True, show: bool = False, normalise: bool = False): accepted_stack_types = ['mean', 'median', 'add'] if stack_type not in accepted_stack_types: raise ValueError('stack_type must be in ' + str(accepted_stack_types)) if directory != '' and directory[-1] != '/': directory = directory + '/' data = [] template = None print('Stacking:') for f in files: # Extract image data and append to list. if type(f) is str: f = u.sanitise_file_ext(f, 'fits') print(' ' + f) f = fits.open(directory + f) if type(f) is fits.hdu.hdulist.HDUList: data_append = f[0].data if template is None and inherit: # Get a template file to use for output. # TODO: Refine this - keep a record of which files went in in the header. template = f.copy() elif type(f) is CCDData: data_append = f.data else: raise TypeError( 'files must contain only strings, HDUList or CCDData objects.') if normalise: data_append = data_append / np.nanmedian( data_append[np.isfinite(data_append)]) if show: norm = pl.nice_norm(data_append) plt.imshow(data_append, origin='lower', norm=norm) plt.show() data.append(data_append) data = np.array(data) if stack_type == 'mean': stacked = np.mean(data, axis=0) elif stack_type == 'median': stacked = np.median(data, axis=0) else: stacked = np.sum(data, axis=0) if show: norm = pl.nice_norm(stacked) plt.imshow(stacked, origin='lower', norm=norm) plt.show() if inherit: template[0].data = stacked else: template = fits.PrimaryHDU(stacked) template = fits.HDUList([template]) add_log(template, f'Stacked.') if output is not None: print('Writing stacked image to', output) template[0].header['BZERO'] = 0 template.writeto(output, overwrite=True, output_verify='warn') return template
def main(data_title: str, show: bool = False): properties = p.object_params_xshooter(data_title) path = properties['data_dir'] master_path = path + '/1-master_calibs/' reduced_path = path + '/2-reduced/' defringed_path = path + '/3-defringed/' u.mkdir_check(defringed_path) # Define fringe measurement points. # high_xs = [267, 267, 267, 267, 267, 267, 267, 267] # high_ys = [279, 279, 279, 279, 279, 279, 279, 279] # low_xs = [266, 266, 266, 267, 267, 270, 274, 273] # low_ys = [293, 295, 298, 301, 303, 305, 303, 292] high_xs = [219, 380, 426, 515, 156, 495, 310] high_ys = [166, 369, 185, 33, 59, 195, 70] low_xs = [219, 380, 424, 474, 160, 500, 315] low_ys = [120, 342, 213, 39, 34, 160, 35] # n_random = 1000 # # high_xs = np.random.random(n_random) # high_xs *= 507 # high_xs += 29 # high_xs = np.round(high_xs) # high_xs = high_xs.astype(int) # # high_ys = np.random.random(n_random) # high_ys *= 200 # high_ys += 20 # high_ys = np.round(high_ys) # high_ys = high_ys.astype(int) # # low_xs = np.random.random(n_random) # low_xs *= 507 # low_xs += 29 # low_xs = np.round(low_xs) # low_xs = low_xs.astype(int) # # low_ys = np.random.random(n_random) # low_ys *= 200 # low_ys += 20 # low_ys = np.round(low_ys) # low_ys = low_ys.astype(int) filters = filter(lambda f: os.path.isdir(reduced_path + f), os.listdir(reduced_path)) for f in filters: print('Constructing fringe map for', f) filter_path = reduced_path + f + '/' defringed_filter_path = defringed_path + f + '/' master_filter_path = master_path + f + '/' u.mkdir_check(defringed_filter_path) files = list( filter(lambda file: file[-5:] == '.fits', os.listdir(filter_path))) # Construct fringe map by median-combining science images. fringe_map = ff.stack(files, directory=filter_path, output=master_filter_path + 'fringe_map.fits', stack_type='median', inherit=False, show=show, normalise=True) fringe_map = fringe_map[0].data map_differences = [] for i in range(len(high_xs)): # Take high_y = high_ys[i] high_x = high_xs[i] high_cut = fringe_map[high_y - 1:high_y + 1, high_x - 1:high_x + 1] high = np.nanmedian(high_cut) low_y = low_ys[i] low_x = low_xs[i] low_cut = fringe_map[low_y - 1:low_y + 1, low_x - 1:low_x + 1] low = np.nanmedian(low_cut) map_differences.append(high - low) for file in os.listdir(filter_path): print(file) hdu = fits.open(filter_path + file) data = hdu[0].data image_differences = [] factors = [] for i in range(len(high_xs)): high_y = high_ys[i] high_x = high_xs[i] high_cut = data[high_y - 2:high_y + 2, high_x - 2:high_x + 2] high = np.nanmedian(high_cut) low_y = low_ys[i] low_x = low_xs[i] low_cut = data[low_y - 2:low_y + 2, low_x - 2:low_x + 2] low = np.nanmedian(low_cut) difference = high - low image_differences.append(difference) factor = difference / map_differences[i] factors.append(factor) used_factor = np.nanmedian(factors) adjusted_map = fringe_map * used_factor data = data - adjusted_map hdu[0].data = data norm = pl.nice_norm(data) if show: plt.imshow(data, norm=norm, origin='lower') plt.show() hdu.writeto(defringed_filter_path + file, overwrite=True) if show: norm = pl.nice_norm(fringe_map) plt.imshow(fringe_map, norm=norm, origin='lower') plt.scatter(high_xs, high_ys) plt.scatter(low_xs, low_ys) plt.show() copyfile(reduced_path + data_title + ".log", defringed_path + data_title + ".log") u.write_log(path=defringed_path + data_title + ".log", action='Edges trimmed using 4-trim.py\n')
def main(field, subtraction_path, epoch, instrument): comparison_name = f'{field}_{epoch}' params = p.object_params_frb(field) # comparison_params = p.object_params_instrument(comparison_name, instrument) subtraction_path = f'{params["data_dir"]}subtraction/{subtraction_path}' filters = params['filters'] burst_ra = params['burst_ra'] burst_dec = params['burst_dec'] hg_ra = params['hg_ra'] hg_dec = params['hg_dec'] burst_err_a = params['burst_err_stat_a'] / 3600 burst_err_b = params['burst_err_stat_b'] / 3600 burst_err_theta = params['burst_err_theta'] for f in filters: print() print(f) f_0 = f[0] destination_path_filter = f'{subtraction_path}{f}/' # This relies on there only being one file with these suffixes in each directory, which, if previous scripts # ran correctly, should be true. comparison_image_file = filter( lambda file: file[-24:] == '_comparison_aligned.fits', os.listdir(f'{destination_path_filter}')).__next__() difference_image_file = filter( lambda file: file[-16:] == '_difference.fits', os.listdir(f'{destination_path_filter}')).__next__() cat_sextractor_path = f'{destination_path_filter}difference.cat' comparison_image_path = f'{destination_path_filter}{comparison_image_file}' difference_image_path = f'{destination_path_filter}{difference_image_file}' cat_sextractor = table.Table( np.genfromtxt(cat_sextractor_path, names=p.sextractor_names())) difference_image = fits.open(difference_image_path) comparison_image = fits.open(comparison_image_path) comparison_header = comparison_image[0].header exp_time = comparison_header['EXPTIME'] comparison_zeropoint, _, airmass, _, comparison_extinction, _ = ph.select_zeropoint( comparison_name, f, instrument=instrument) cat_sextractor['mag'], _, _ = ph.magnitude_complete( flux=cat_sextractor['flux_aper'], exp_time=exp_time, airmass=airmass, zeropoint=comparison_zeropoint, ext=comparison_extinction) cat_sextractor['mag_auto'], _, _ = ph.magnitude_complete( flux=cat_sextractor['flux_auto'], exp_time=exp_time, airmass=airmass, zeropoint=comparison_zeropoint, ext=comparison_extinction) wcs_info = wcs.WCS(comparison_header) hg_x, hg_y = wcs_info.all_world2pix(hg_ra, hg_dec, 0) # norm = plotting.nice_norm(difference_image[0].data) # print('Generating full-image plot...') # plt.figure(figsize=(30, 20)) # plt.imshow(difference_image[0].data, norm=norm, origin='lower') # plotting.plot_all_params(image=difference_image, cat=cat_sextractor, show=False) # # plt.legend() # plt.savefig(f'{destination_path_filter}recovered_all.pdf') # plt.close() closest_index, distance = u.find_object(burst_ra, burst_dec, cat_sextractor['ra'], cat_sextractor['dec']) closest = cat_sextractor[closest_index] x = closest['x'] y = closest['y'] print(closest) print('Magnitude:', closest['mag']) print('Threshold:', closest['threshold']) print('Flux max:', closest['flux_max']) print('RA:', closest['ra'], '; DEC:', closest['dec']) print('X:', x, '; Y:', y) print('Offset from HG (pixels):', np.sqrt((x - hg_x)**2 + (y - hg_y)**2)) x = int(x) y = int(y) norm = plotting.nice_norm(difference_image[0].data) print('Generating full-image plot...') plt.figure(figsize=(30, 20)) plt.imshow(difference_image[0].data, norm=norm, origin='lower') print(min(cat_sextractor['ra']), min(cat_sextractor['dec'])) plotting.plot_all_params(image=difference_image, cat=cat_sextractor, show=False) # plt.legend() plt.savefig(f'{destination_path_filter}recovered_all.png') plt.close() print('Generating cutout plots...') plt.imshow(difference_image[0].data, norm=norm, origin='lower') # plt.legend() plotting.plot_gal_params(hdu=difference_image, ras=[burst_ra], decs=[burst_dec], a=[burst_err_a], b=[burst_err_b], theta=[burst_err_theta], colour='blue', show_centre=True, label='Burst') plt.scatter(hg_x, hg_y, c='orange', label='Galaxy centroid') plotting.plot_all_params(image=difference_image, cat=cat_sextractor, show=False) plt.xlim(hg_x - 50, hg_x + 50) plt.ylim(hg_y - 50, hg_y + 50) plt.legend() plt.savefig(f'{destination_path_filter}recovered_hg_cutout.png') plt.close() cutout_source = difference_image[0].data[y - 50:y + 50, x - 50:x + 50] plt.imshow(cutout_source, origin='lower') plt.savefig(f'{destination_path_filter}nearest_source_cutout.png') plt.show() plt.close() cutout_hg = ff.trim(difference_image, int(hg_x) - 20, int(hg_x) + 20, int(hg_y) - 20, int(hg_y) + 20) cutout_hg_data = cutout_hg[0].data midpoint = int(cutout_hg_data.shape[0] / 2) xx = np.arange(-midpoint, midpoint) data_slice = cutout_hg_data[midpoint, :] plt.plot(xx, data_slice) plt.savefig(f'{destination_path_filter}hg_x_slice.png') plt.show() plt.close() print() x_misalignment = np.argmax(data_slice) - np.argmin(data_slice) print('x peak - trough:', x_misalignment) midpoint = int(cutout_hg_data.shape[0] / 2) yy = np.arange(-midpoint, midpoint) data_slice = cutout_hg_data[:, midpoint] plt.plot(yy, data_slice) plt.savefig(f'{destination_path_filter}hg_y_slice.png') plt.show() plt.close() y_misalignment = np.argmax(data_slice) - np.argmin(data_slice) print('y peak - trough:', y_misalignment) print() print('Mean false positive mag:', np.nanmean(cat_sextractor['mag'])) print('Median false positive mag:', np.nanmedian(cat_sextractor['mag'])) plt.figure(figsize=(6, 8)) sextractor_cutout = cat_sextractor[ (cat_sextractor['x'] > int(hg_x) - 20) & (cat_sextractor['x'] < int(hg_x) + 20) & (cat_sextractor['y'] > int(hg_y) - 20) & (cat_sextractor['y'] < int(hg_y) + 20)] plotting.plot_all_params(image=difference_image, cat=sextractor_cutout, show=False) plotting.plot_gal_params(hdu=difference_image, ras=[burst_ra], decs=[burst_dec], a=[burst_err_a], b=[burst_err_b], theta=[burst_err_theta], colour='blue', show_centre=True, label='Burst') norm = plotting.nice_norm(cutout_hg[0].data) plt.imshow(cutout_hg[0].data, norm=norm, origin='lower') plt.scatter(hg_x - (int(hg_x) - 20), hg_y - (int(hg_y) - 20), c='orange', label='Galaxy centroid') plt.legend() plt.savefig(f'{destination_path_filter}residuals_hg.png') plt.show() plt.close()
def main(image, cat_path_1, cat_path_2, cat_name_1, cat_name_2, offset_x, offset_y, psf): if cat_name_1 == 'DES': ra_name_1 = 'RA' dec_name_1 = 'DEC' else: ra_name_1 = 'ra' dec_name_1 = 'dec' if cat_name_2 == 'DES': ra_name_2 = 'RA' dec_name_2 = 'DEC' else: ra_name_2 = 'ra' dec_name_2 = 'dec' if psf: names = p.sextractor_names_psf() else: names = p.sextractor_names() if cat_name_1 == 'SExtractor': cat_1 = table.Table(np.genfromtxt(cat_path_1, names=names)) else: cat_1 = table.Table() cat_1 = cat_1.read(cat_path_1, format='ascii.csv') if cat_name_2 == 'SExtractor': cat_2 = table.Table(np.genfromtxt(cat_path_2, names=names)) else: cat_2 = table.Table() cat_2 = cat_2.read(cat_path_2, format='ascii.csv') param_dict = {} image = fits.open(image) header = image[0].header data = image[0].data wcs_info = wcs.WCS(header=header) cat_1['x'], cat_1['y'] = wcs_info.all_world2pix(cat_1[ra_name_1], cat_1[dec_name_1], 0) cat_2['x'], cat_2['y'] = wcs_info.all_world2pix(cat_2[ra_name_2], cat_2[dec_name_2], 0) norm = pl.nice_norm(data) plt.subplot(projection=wcs_info) plt.imshow(data, norm=norm, origin='lower', cmap='viridis') plt.scatter(cat_1['x'], cat_1['y'], label=cat_name_1, c='violet') plt.scatter(cat_2['x'], cat_2['y'], label=cat_name_2, c='red') plt.legend() plt.show() scale_ra, scale_dec = ff.get_pixel_scale(image) ra_corrected = cat_2[ra_name_2] + offset_x * scale_ra dec_corrected = cat_2[dec_name_2] + offset_y * scale_ra x, y = wcs_info.all_world2pix(ra_corrected, dec_corrected, 0) norm = pl.nice_norm(data) plt.subplot(projection=wcs_info) plt.imshow(data, norm=norm, origin='lower', cmap='viridis') plt.scatter(cat_1['x'], cat_1['y'], label=cat_name_1, c='violet') plt.scatter(x, y, label=cat_name_2, c='red') plt.legend() plt.show() image.close()
def tweak(sextractor_path: str, destination: str, image_path: str, cat_path: str, cat_name: str, tolerance: float = 10., show: bool = False, stars_only: bool = False, manual: bool = False, offset_x: float = None, offset_y: float = None, offsets_world: bool = False, psf: bool = True, specific_star: bool = False, star_ra: float = None, star_dec: float = None ): """ For tweaking the astrometric solution of a fits image using a catalogue; either matches as many stars as possible and uses the median offset, uses a single star at a specified position (specific_star=True) or a manual offset. :param sextractor_path: Path to SExtractor-generated catalogue. :param destination: Directory to write tweaked image to. :param image_path: Path to image FITS file :param cat_path: Path to file containing catalogue. :param cat_name: Name of catalogue used. :param tolerance: Tolerance, in pixels, within which matches will be accepted. :param show: Plot matches onscreen? :param stars_only: Only match using stars, determined using SExtractor's 'class_star' output. :param manual: Use manual offset? :param offset_x: Offset in x to use; only if 'manual' is set to True. :param offset_y: Offset in y to use; only if 'manual' is set to True. :param offsets_world: If True, interprets the offsets as being given in World Coordinates (RA and DEC) :param psf: Use the PSF-fitting position? :param specific_star: Use a specific star to tweak? This means, instead of finding the closest matches for many stars, alignment is attempted with a single star nearest the given position. :param star_ra: Right Ascension of star for single-star alignment. :param star_dec: Declination of star for single-star alignment. :return: None """ param_dict = {} print(image_path) image = fits.open(image_path) header = image[0].header data = image[0].data wcs_info = wcs.WCS(header=header) # Set the appropriate column names depending on the format of the catalogue to use. if cat_name == 'DES': ra_name = 'RA' dec_name = 'DEC' elif cat_name == 'Gaia' or cat_name == 'SDSS': ra_name = 'ra' dec_name = 'dec' else: if psf: ra_name = 'ra_psf' dec_name = 'dec_psf' else: ra_name = 'ra' dec_name = 'dec' if psf: names = p.sextractor_names_psf() sextractor_ra_name = 'ra_psf' sextractor_dec_name = 'dec_psf' else: names = p.sextractor_names() sextractor_ra_name = 'ra' sextractor_dec_name = 'dec' if show or not manual: if cat_name == 'SExtractor': cat = table.Table(np.genfromtxt(cat_path, names=names)) else: cat = table.Table() cat = cat.read(cat_path, format='ascii.csv') sextracted = table.Table(np.genfromtxt(sextractor_path, names=names)) if stars_only: sextracted = sextracted[sextracted['class_star'] > 0.9] cat['x'], cat['y'] = wcs_info.all_world2pix(cat[ra_name], cat[dec_name], 0) x, y = wcs_info.all_world2pix(sextracted[sextractor_ra_name], sextracted[sextractor_dec_name], 0) norm = pl.nice_norm(data) if show: # plt.subplot(projection=wcs_info) plt.imshow(data, norm=norm, origin='lower', cmap='viridis') plt.scatter(x, y, label='SExtractor', c='violet') plt.scatter(cat['x'], cat['y'], label=cat_name, c='red') plt.legend() plt.title('Pre-Correction') plt.show() if manual: if offset_x is not None and offset_y is not None: if not offsets_world: scale_ra, scale_dec = ff.get_pixel_scale(image) offset_ra = -offset_x * abs(scale_ra) offset_dec = -offset_y * abs(scale_dec) print(offset_x, offset_y) else: offset_ra = offset_x offset_dec = offset_y else: print('Set offsets in epoch .yaml file') offset_ra = offset_dec = None elif specific_star: if star_ra is not None and star_dec is not None: print(star_ra, star_dec) star_cat, d = u.find_object(x=star_ra, y=star_dec, x_search=cat[ra_name], y_search=cat[dec_name]) print('MD:', d) star_cat = cat[star_cat] star_sex, d = u.find_object(x=star_ra, y=star_dec, x_search=sextracted[sextractor_ra_name], y_search=sextracted[sextractor_dec_name]) print('MD:', d) star_sex = sextracted[star_sex] offset_ra = (star_sex[sextractor_ra_name] - star_cat[ra_name]) offset_dec = (star_sex[sextractor_dec_name] - star_cat[dec_name]) else: raise ValueError('If doing specific_star, must specify star_ra and star_dec') else: match_ids, match_ids_cat = u.match_cat(x_match=sextracted['x'], y_match=sextracted['y'], x_cat=cat['x'], y_cat=cat['y'], tolerance=tolerance) sextracted = sextracted[match_ids] cat = cat[match_ids_cat] offsets_ra = sextracted[sextractor_ra_name] - cat[ra_name] offsets_dec = sextracted[sextractor_dec_name] - cat[dec_name] offset_ra = np.nanmedian(offsets_ra) offset_dec = np.nanmedian(offsets_dec) # TODO: This is quick and dirty and will only work if the image is approximately oriented along x=RA # and y=DEC (CROTA ~ 0) if offset_ra is not None and offset_dec is not None: param_dict['offset_ra'] = float(offset_ra) param_dict['offset_dec'] = float(offset_dec) image = offset_astrometry(hdu=image, offset_ra=offset_ra, offset_dec=offset_dec, output=destination) if show and not manual: wcs_info = wcs.WCS(header=header) cat['x'], cat['y'] = wcs_info.all_world2pix(cat[ra_name], cat[dec_name], 0) x, y = wcs_info.all_world2pix(sextracted[sextractor_ra_name] - offset_ra, sextracted[sextractor_dec_name] - offset_dec, 0) if show: plt.subplot(projection=wcs_info) plt.imshow(data, norm=norm, origin='lower', cmap='viridis') plt.scatter(x, y, label='SExtractor', c='violet') plt.scatter(cat['x'], cat['y'], label=cat_name, c='red') plt.legend() plt.title('Post-Correction') plt.show() image.close() return param_dict