def cost_func(plist): """ chisq of kernel_to - convl(kernel_from, kernel_via) in kernel space. """ gamma, alpha = plist k = ac.Moffat2DKernel(gamma, alpha, x_size=nx, y_size=ny) arr_out_predict = ac.convolve(arr_in, k) arr_out_fit, arr_out_predict_fit = match_dimension( arr_out, arr_out_predict) diff = (arr_out_fit - arr_out_predict_fit) * scale_factor return np.sum(diff**2) / diff.size
def get_convolving_moffat_kernel(arr_in, arr_out, nx=43, ny=43, scale_factor=10000., tolerance=1.e-3): """ find k such that convolve(arr_in, k) = arr_out Params ------ arr_in arr_out Return ------ k: convolving kernel """ def cost_func(plist): """ chisq of kernel_to - convl(kernel_from, kernel_via) in kernel space. """ gamma, alpha = plist k = ac.Moffat2DKernel(gamma, alpha, x_size=nx, y_size=ny) arr_out_predict = ac.convolve(arr_in, k) arr_out_fit, arr_out_predict_fit = match_dimension( arr_out, arr_out_predict) diff = (arr_out_fit - arr_out_predict_fit) * scale_factor return np.sum(diff**2) / diff.size bounds = ((1.e-2, np.inf), (-np.inf, np.inf)) plist_init = (3., 1.) res = so.minimize(cost_func, plist_init, bounds=bounds) gamma_via, alpha_via = res.x avg_diff = np.sqrt(res.fun) / scale_factor if avg_diff > tolerance: warnings.warn( "[psfmatch.deconvl_moffat_fast] best fit worse than tolerance. ", UserWarning) k = ac.Moffat2DKernel(gamma_via, alpha_via, x_size=nx, y_size=ny) return k
def test_match_psf(): """ test that match_psf can infer the simulated moffat kernel """ band = b0 img = fits.getdata(dir_obj + 'stamp-{}.fits'.format(band)) psf = fits.getdata(dir_obj + 'psf-{}.fits'.format(band)) kernel = ac.Moffat2DKernel(gamma=5., alpha=3., x_size=43, y_size=43) psfto = ac.convolve(psf, kernel) img_cnvled_veri = ac.convolve(img, kernel) img_cnvled, psf_cnvled, kernel_cnvl = matchpsf.match_psf(img, psf, psfto) assert two_kernels_are_similar(kernel_cnvl, kernel) assert two_kernels_are_similar(psf_cnvled, psfto) assert two_kernels_are_similar(img_cnvled, img_cnvled_veri)
def convolve(map, fwhm, pow=4.7, size=5, kernel='moff'): map = np.ma.filled(map, fill_value=np.nan) print 'convolve: map shape=', np.shape(map) if kernel is 'moff': sig = fwhm / (2 * np.sqrt(2 ** (1. / pow) - 1.)) elif kernel is 'gauss': sig = gf2s * fwhm size = int(np.round(size * sig)) if size % 2 == 0: size += 1 print 'convolve: fwhm, sig, total size, phys_res=', fwhm, sig, size, fwhm * 26. / np.shape(map)[0] if kernel is 'moff': kernel = con.Moffat2DKernel(sig, pow, x_size=size, y_size=size) elif kernel is 'gauss': kernel = con.Gaussian2DKernel(sig, x_size=size, y_size=size) result = con.convolve_fft(map, kernel, normalize_kernel=True) median = np.median(np.ma.compressed(np.ma.masked_where(map <= 0, map))) result[np.log10(np.abs(median)) - np.log10(np.abs( result)) > 10.] = 0. # discarding any resulting pixel that is more than O(10) lower than input data, to avoid round off error pixels return result
def make_smeared(self, imgtag='OIII5008_I', gamma=3., alpha=1., nx=43, ny=43, overwrite=True): """ make image convolved by moffat psf kernel. Params ------ self, imgtag='OIII5008_I', gamma=3., alpha=1., nx=43, ny=43, overwrite=True Return ------ status (bool) Write Output ------------ e.g., stamp-OIII5008_I_smeared-moffatg2a1.fits psf-OIII5008_I_smeared-moffatg2a1.fits """ tag_smeared = self.get_tag_smeared(gamma=gamma, alpha=alpha) fn = self.get_fp_stamp_img(imgtag=imgtag+tag_smeared) if not os.path.isfile(fn) or overwrite: d = self._get_decomposer() fn_psf = d.get_fp_psf(fn) fn_stamp_in = self.get_fp_stamp_img(imgtag=imgtag) fn_psf_in = d.get_fp_psf(fn_stamp_in) img = fits.getdata(fn_stamp_in) psf = fits.getdata(fn_psf_in) kernel = ac.Moffat2DKernel(gamma, alpha, x_size=nx, y_size=ny) img_smeared = ac.convolve(img, kernel) psf_smeared = ac.convolve(psf, kernel) comment = 'PSF smeared by moffat kernel with gamma {} alpha {}'.format(str(gamma), str(alpha)) matchpsf.replace_img_in_fits(fn_stamp_in, fn, img_smeared, comment=comment, overwrite=overwrite) fits.PrimaryHDU(psf_smeared).writeto(fn_psf, overwrite=overwrite) else: print("[simulator] skip making smeared image a file exists") return os.path.isfile(fn)
def get_AOPSF(args): # diameter = telescope aperture in metres, for Airy kernel # arcsec_per_pixel = arcseconds per pixel, for Moffat and Gaussian kernels # size = truncation size of all kernels in pixel mode = 'integral' # if the kernels are normalised to peak intensity = 1 ('peak') or integrated area = 1 ('integral') arcsec_per_pixel = args.arcsec_per_pixel size = args.size diameter = 2 * args.rad # -----computing Airy Disk-------------- wave = 6.5e-7 # Ha narrow-band wavelength in metres radius = 1.22 * wave / diameter # radius of first dark band, in radian radius_arcsec = radius * 180. * 3600. / np.pi # radius in arcseconds radius_pix = radius_arcsec / arcsec_per_pixel # radius in pixel units airy_kernel = con.AiryDisk2DKernel(radius_pix, x_size=size, y_size=size) # already normalised airy_kernel.normalize(mode=mode) # normalise such that peak = 1 # -----computing Moffat profile--------- moffat_kernel = con.Moffat2DKernel(gamma=args.sig, alpha=args.pow, x_size=size, y_size=size) moffat_kernel.normalize(mode=mode) # normalise such that peak = 1 fwhm_arcsec = args.sig * ( 2 * np.sqrt(2**(1. / args.pow) - 1.)) * arcsec_per_pixel # --------computing Gaussian profile---------- gaussian_blur_arcsec = 0.1 # Gaussian blur in arcseconds (FWHM) gaussian_blur_pix = ( gaussian_blur_arcsec / 2.355 ) / arcsec_per_pixel # Gaussian blur in pixel units (std dev, hence factor of 2.355) gaussian_kernel = con.Gaussian2DKernel(gaussian_blur_pix, x_size=size, y_size=size) gaussian_kernel.normalize( mode=mode) # normalise such that peak = 1, just for plotting # ------adding kernels---------- added_kernel = args.strehl * airy_kernel + ( 1 - args.strehl ) * moffat_kernel # both kernels had peak intensity = 1, which will now = 0.3, and 0.7, giving Strehl ratio=0.3 # ------Gaussian smoothing for tip-tilt uncertainties---------- final_kernel = con.convolve(added_kernel, gaussian_kernel, normalize_kernel=True) # -----computing fiducial Moffat profile--------- fid_pow, fid_size = 4.7, 5 sigma = args.sig * (2 * np.sqrt(2**(1. / args.pow) - 1.)) / ( 2 * np.sqrt(2**(1. / fid_pow) - 1.)) fid_size = int((sigma * fid_size) // 2 * 2 + 1) fiducial_moffat_kernel = con.Moffat2DKernel(gamma=sigma, alpha=fid_pow, x_size=fid_size, y_size=fid_size) fiducial_moffat_kernel.normalize(mode=mode) # normalise such that peak = 1 fiducial_fwhm_arcsec = args.sig * ( 2 * np.sqrt(2**(1. / args.pow) - 1.)) * arcsec_per_pixel #print_master('Areas final=%0.4F, gaussian=%0.4F, added=%0.4F, airy=%0.4F, moffat=%0.4F, fiducial_moffat=%0.4F'%(np.sum(final_kernel), np.sum(gaussian_kernel), np.sum(added_kernel), np.sum(airy_kernel), np.sum(moffat_kernel), np.sum(fiducial_moffat_kernel)), args) if args.plot_1dkernel and MPI.COMM_WORLD.rank == 0: # ------plotting 1D cross-sections of the 2D kernels---------- fraction_to_plot = 0.7 # fraction of kernel to plot, before it becomes practically flat portion = int(fraction_to_plot * (size / 2)) + 1 fig, ax = plt.subplots(figsize=(8, 4)) # figure for 1D plots fig.subplots_adjust(top=0.95, right=0.98, left=0.1, bottom=0.15) ax.plot(np.arange(portion), airy_kernel.array[size / 2][size / 2:size / 2 + portion], c='r', lw=1, label='Airy (%.2F")' % radius_arcsec) ax.plot(np.arange(portion), moffat_kernel.array[size / 2][size / 2:size / 2 + portion], c='brown', lw=1, label=r'Moffat (%.2F", $\alpha$=%.1F)' % (fwhm_arcsec, args.pow)) ax.plot(np.arange(portion), added_kernel.array[size / 2][size / 2:size / 2 + portion], c='gray', lw=1, label='Airy + Moffat', linestyle='--') ax.plot(np.arange(portion), gaussian_kernel.array[size / 2][size / 2:size / 2 + portion], c='g', lw=1, label='Gaussian (%.2F")' % gaussian_blur_arcsec) ax.plot(np.arange(portion), final_kernel.array[size / 2][size / 2:size / 2 + portion], c='b', label='Convolved: Strehl %.1F' % args.strehl) ax.plot(np.arange(portion), fiducial_moffat_kernel.array[size / 2][size / 2:size / 2 + portion], c='goldenrod', label=r'Fiducial Moffat (%.2F", $\alpha$=%.1F))' % (fiducial_fwhm_arcsec, fid_pow)) ax.legend() ax.set_xlim(0, portion - 1) ax.set_xticklabels([ '%.2F' % (float(item) * arcsec_per_pixel) for item in ax.get_xticks() ]) ax.set_xlabel('Arcseconds') ax.set_ylabel('Intensity') ax.set_ylim( 0, 2 * np.max(fiducial_moffat_kernel.array[size / 2][size / 2:size / 2 + portion])) if args.saveplot: outfile = os.path.dirname( args.H2R_cubename ) + '/PSF_comparison_res=%.1F"_Strehl=%.1F.eps' % (fwhm_arcsec, args.strehl) fig.savefig(outfile) print_master('PSF figure saved as ' + outfile, args) plt.show(block=True) return final_kernel
logbook.exptime = float(args.exptime) logbook.final_pix_size = float(args.final_pix_size) logbook.fitsname = args.fitsname logbook.intermediate_pix_size = float(args.intermediate_pix_size) rebinned_shape = (int(args.galsize / logbook.intermediate_pix_size), int(args.galsize / logbook.intermediate_pix_size)) cube = fits.open(args.H2R_cubename)[0].data nslice = np.shape(cube)[2] if args.ker == 'gauss': kernel = con.Gaussian2DKernel(args.sig, x_size=args.size, y_size=args.size) elif args.ker == 'moff': kernel = con.Moffat2DKernel(args.sig, args.pow, x_size=args.size, y_size=args.size) elif args.ker == 'AOPSF': kernel = get_AOPSF(args) #sys.exit() # comm = MPI.COMM_WORLD ncores = comm.size rank = comm.rank print_master( 'Total number of MPI ranks = ' + str(ncores) + '. Starting at: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()), args) convolved_cube_local = np.zeros( (int(args.galsize / logbook.final_pix_size), int(args.galsize / logbook.final_pix_size), np.shape(cube)[2]
if band == 'K': wave = 2.2e-6 # K band wavelength in metres elif band == 'J': wave = 1.25e-6 # K band wavelength in metres elif band == 'optical': wave = 6.5e-7 # NII/Ha narrow-band wavelength in metres radius = 1.22 * wave / diameter # radius of first dark band, in radian radius_arcsec = radius * 180. * 3600. /np.pi # radius in arcseconds radius_pix = radius_arcsec / arcsec_per_pixel # radius in pixel units airy_kernel = con.AiryDisk2DKernel(radius_pix, x_size=size, y_size=size) # already normalised airy_kernel.normalize(mode=mode) # normalise such that peak = 1 if plot2d: fig = plot_kernel(airy_kernel, 'Airy (%.2F")'%radius_arcsec, radius=radius_pix) # -----computing Moffat profile--------- fwhm_arcsec =.5 # seeing in arcseconds fwhm_pix = fwhm_arcsec / arcsec_per_pixel # seeing in pixel units beta = 2.5 # power law index width = fwhm_pix/(2 * np.sqrt(np.power(2, 1./beta) - 1)) # core width in pixels moffat_kernel = con.Moffat2DKernel(gamma=width, alpha=beta, x_size=size, y_size=size) moffat_kernel.normalize(mode=mode) # normalise such that peak = 1 if plot2d: fig = plot_kernel(moffat_kernel, 'Moffat (%.2F")'%fwhm_arcsec, radius=fwhm_pix) # --------computing Gaussian profile---------- gaussian_blur_arcsec = 0.1 # Gaussian blur in arcseconds (FWHM) gaussian_blur_pix = (gaussian_blur_arcsec/2.355) / arcsec_per_pixel # Gaussian blur in pixel units (std dev, hence factor of 2.355) gaussian_kernel = con.Gaussian2DKernel(gaussian_blur_pix, x_size=size, y_size=size) gaussian_kernel.normalize(mode=mode) # normalise such that peak = 1, just for plotting if plot2d: fig = plot_kernel(gaussian_kernel, 'Gaussian (%.2F")'%gaussian_blur_arcsec, radius=gaussian_blur_pix) # ------adding kernels---------- added_kernel = strehl * airy_kernel + (1 - strehl) * moffat_kernel # both kernels had peak intensity = 1, which will now = 0.3, and 0.7, giving Strehl ratio=0.3 if plot2d: fig = plot_kernel(added_kernel, 'Added') # ------Gaussian smoothing for tip-tilt uncertainties----------