def pyfxcor(inspec, template, vmin=-200., vmax=200., res=3, rej=1000): rv, cc = pyasl.crosscorrRV(inspec[0], inspec[1], template[0], template[1], vmin, vmax, res, skipedge=rej) cen_gs = np.argmax(cc) perfx, perfy = rv[cen_gs - 5:cen_gs + 6], cc[cen_gs - 5:cen_gs + 6] try: gauss = ConstantModel() + GaussianModel() pars = gauss.make_params() pars['center'].set(value=rv[np.argmax(cc)], vary=True) pars['amplitude'].set(value=max(cc), vary=True) pars['sigma'].set(vary=True) pars['c'].set(value=0, vary=True) out = gauss.fit(perfy, pars, x=perfx) ct = out.best_values['center'] cterr = out.params['center'].stderr except: return 'error', '' return ct, cterr
def cross_correlate_order(wave, flux, template, ap=200): mask = template[:, 0] > min(wave) - 1000 * median(wave) / c mask *= template[:, 0] < max(wave) + 1000 * median(wave) / c flux = normalise(flux, deg=4) template_flux = normalise(template[:, 1][mask], deg=0) #template_flux = template[:,1][mask] ### do some more normalisation against the template fit = interpolate.splrep(template[:, 0][mask], template_flux) fit = interpolate.splev(wave, fit) diff = flux / fit diffmask = diff - median(diff) < 0.2 diffmask *= diff - median(diff) > -0.6 try: fit = polyfit(wave[diffmask], diff[diffmask], 10) fit = polyval(fit, wave) flux /= fit except: print "Bad normalisation" flux = -1 * (flux - 1) template_flux = -1 * (template_flux - 1) #flux = apodize(flux,ap=ap) #template_flux = apodize(template_flux,ap=ap) drv, cc = pyasl.crosscorrRV(wave, flux, template[:, 0][mask], template_flux, -300, +300, 0.01, mode='doppler', skipedge=0, edgeTapering=None) # plt.subplot(211) # plt.plot(wave,flux) # plt.plot(template[:,0][mask],template_flux) # plt.subplot(212) # plt.plot(drv,cc) # plt.show() try: #epos = pyasl.quadExtreme(drv, cc, mode='max', dp=(50, 50), exInd=None, fullOutput=False, fullPoint=False)[0] dp = len(cc[cc > 0.5 * nanmax(cc)]) / 2 print "len of cc peak find", dp epos = fitquad(drv, cc, dp=dp) print "rv", epos except: epos = nan return epos, drv, cc
def sanity_ShiftedGaussian(self): """ Checking the shift of a single Gaussian. """ from PyAstronomy import pyasl import numpy as np # Create the template tw = np.linspace(5000,5010,1000) tf = np.exp(-(tw-5004.0)**2/(2.*0.1**2)) # Create data, which are not that well sampled dw = np.linspace(5000,5010,200) df = np.exp(-(dw-5004.0)**2/(2.*0.1**2)) rv1, cc1 = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 60./100., skipedge=20, mode="doppler") rv2, cc2 = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 60./100., skipedge=20, mode="lin") m1 = np.argmax(cc1) m2 = np.argmax(cc2) self.assertAlmostEqual(rv1[m1], rv2[m2], delta=1e-10) accu = 60./100. for dwl in np.linspace(-0.2,0.2,20): # Create the template tw = np.linspace(5000,5010,1000) tf = np.exp(-(tw-5004.0)**2/(2.*0.1**2)) # Create data, which are not that well sampled dw = np.linspace(5000,5010,200) df = np.exp(-(dw-(5004.0+dwl))**2/(2.*0.1**2)) rv1, cc1 = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 60./100., skipedge=20, mode="doppler") rv2, cc2 = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 60./100., skipedge=20, mode="lin") m1 = np.argmax(cc1) m2 = np.argmax(cc2) rv = dwl/np.mean(tw) * 299792.458 self.assertAlmostEqual(rv1[m1], rv2[m2], delta=accu) self.assertAlmostEqual(rv1[m1], rv, delta=accu) self.assertAlmostEqual(rv2[m1], rv, delta=accu)
def get_rv(shifted_flux_of_star, shifted_wavelength_of_star, flux_of_star, wavelength_of_star): rv, cc = pyasl.crosscorrRV(wavelength_of_star, flux_of_star, wavelength_of_star, shifted_flux_of_star, -300., 300., 5., skipedge=40) return rv[np.argmax(cc)]
def velocity_shift(dw, df, tw, tf): '''Carry out the cross-correlation. The RV-range is -30 - +30 km/s in steps of 0.6 km/s. The first and last 20 points of the data are skipped.''' rv, cc = pyasl.crosscorrRV(dw, df, tw, tf, -40., 40., 0.01, skipedge=100) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) print("Cross-correlation function is maximized at dRV = ", rv[maxind], " km/s") #plt.plot(rv, cc, 'bp-') #plt.plot(rv[maxind], cc[maxind], 'ro') #plt.show() return rv[maxind]
def rv_correct(temp_lam, temp_spec, obs_lam, obs_spec): # Plot template and data #plt.title("Template (blue) and data (red)") #plt.plot(temp_lam, temp_spec, 'b.-') #plt.plot(obs_lam, obs_spec, 'r.-') #plt.show() ############################################################### #### Carry out the cross-correlation. #### ####The RV-range is -30 - +30 km/s in steps of 0.6 km/s. #### #### The first and last 20 points of the data are skipped. #### ############################################################### rv, cc = pyasl.crosscorrRV(obs_lam, obs_spec, temp_lam, temp_spec, -30., 30., 30. / 50., skipedge=20) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) print "Cross-correlation function is maximized at dRV = ", rv[ maxind], " km/s" if rv[maxind] > 0.0: print " A red-shift with respect to the template" if rv[maxind] < 0.0: print " A blue-shift with respect to the template" if rv[maxind] < 1e-10: print "No shift" #plt.plot(rv, cc, 'bp-') #plt.plot(rv[maxind], cc[maxind], 'ro') #plt.show() c = 3.0 * 10**5 #speed of light RV_wavelength = obs_lam * (1. - rv[maxind] / c) try: f = interpolate.interp1d(RV_wavelength, obs_spec, kind='linear') return f(obs_lam) except ValueError: f = interpolate.interp1d(RV_wavelength, obs_spec, kind='linear', bounds_error=False, fill_value=1) return f(obs_lam)
def ccf(wave, flux, mask='G2', rvmin=-300, rvmax=300, drv=0.1): """Compute the CCF of a spectrum. Based on PyAstronomy implementation of the cross-correlation. Parameters ---------- wave: array_like The input wavelength array. flux: array_like The input flux array. mask: str The binary mask to use for the CCF. Options are G2, K0, K5 and M2 rvmin: float, optional The minimum radial velocity to inspect in km/s. Default is -300 km/s rvmax: float, optional The maximum radial velocity to inspect in km/s. Default is 300 km/s drv: float, optional The radial velocity step. Default is 0.1 km/s Returns ------- rvs: array_like The rv axis of the CCF. cc: array_like The median normalized CCF """ # read mask, call crosscorr x1 = sp.arange(wave[0] - 200, wave[0], wave[1] - wave[0]) x2 = sp.arange(wave[-1], wave[-1] + 200, wave[-1] - wave[-2]) wtem = sp.hstack([x1, wave, x2]) lines1, lines2, flux_l = sp.loadtxt('masks/' + mask + '.mas', unpack=True) ilines = sp.where((lines1 > wave[0]) & (lines2 < wave[-1]))[0] lines1_new = lines1[ilines] lines2_new = lines2[ilines] flux_l_new = flux_l[ilines] ftem = sp.zeros(wtem.size) for i in range(len(flux_l_new)): indices = sp.where((wtem >= lines1_new[i]) & (wtem <= lines2_new[i])) if indices[0].size > 0: ftem[indices[0]] = flux_l_new[i] del indices rvs, cc = pyasl.crosscorrRV(wave, flux, wtem, ftem, rvmin, rvmax, drv) return rvs, cc / sp.median(cc)
def deconv_RL(f_tpl, w_tpl, bb=4): # Deconvolution of f_tpl using Richardson Lucy algorithm # needed for CRIRES data psf = np.ones((1, bb)) / bb f2 = f_tpl + 0. f_tpl1 = np.reshape(f_tpl, (1, -1)) deconv_RL = restoration.richardson_lucy(f_tpl1 / np.max(f_tpl1) / 2., psf, iterations=30)[0] f_tpl = deconv_RL * np.max(f_tpl1) * 2 rv, ccc = pyasl.crosscorrRV(w_tpl[200:-200], f_tpl[200:-200], w_tpl[200:-200], f2[200:-200], -10., 10., 0.01, skipedge=20) pol = (np.poly1d(np.polyfit(rv, ccc, 15)))(rv) shift = rv[np.argmax(pol)] print('shift RL: ', shift, rv[np.argmax(ccc)]) # there seems to appear a shift in the spectra after the deconvolution # why ??? # correction ??? # more testing needed, or another way of deconvolution plot_RL = 0 if plot_RL: gplot(rv, ccc, 'w l,', rv, pol, 'w l') # gplot(w_tpl, f2, 'w l,', w_tpl /(1+shift/3e5),f_tpl,'w l') pause() # w_tpl /= (1+shift/3e5) ''' bo = 10 f_tpl = f_tpl[bo:-bo] w_tpl = w_tpl[bo:-bo] f_ok = f_ok[bo:-bo] w_ok = w_ok[bo:-bo] x_ok = x_ok[bo:-bo] ''' return f_tpl, w_tpl
def errfunc(x0, return_ccf=False): wave = polyval(x0, xpos) spec_i = -1 * (spec - 1) wave_template = arange(min(wave) - 150, max(wave) + 150, abs(x0[0])) template_i = interpolate.splev( wave_template, template_interp, ext=1) ### interpolate the template spectrum template_i = normalise( template_i ) ### comment out this step if using normalised template spectrum template_i = -1 * (template_i - 1) #spec_i /= max(spec_i) #template_i /= max(template_i) mask = wave_template == wave_template drv, cc = pyasl.crosscorrRV(wave, spec_i, wave_template[mask], template_i[mask], -5000, +5000, 1, mode='doppler', skipedge=0, edgeTapering=None) peak_loc = drv[argmax(cc)] mask = abs(drv - peak_loc) > 1000 fit = polyfit(drv[mask], cc[mask], 2) fit = polyval(fit, drv) cc -= fit snr = (max(cc) - median(cc[mask])) / std(cc[mask]) if return_ccf: return drv, cc else: print(x0, snr) #return -1*max(cc) return -1 * snr
def measure_rv(wdnum, spT, files): from PyAstronomy import pyasl ## define paramters for cross-correlation c = 2.99792458e5 ## speed of light in km/s box = 10. ## size of moving "box" for correlation bbox = 10*box ## size of window to CC ccRange = np.arange(5850.,6750.,bbox/2.) ## start of CC region -- 5850:6750 nCC = np.size(ccRange) maxRV = 200 ## maximum possible value of RV -- absolute value # read the list of the spectra for that WD #wdnum = 'WD2350-081' #spT = 'K5V' # read the template spectra appropriate for that MS temWave, temFlux = readtem(spT) for fname in files: obsdate = fname[fname.find('_')+1 : fname.find('.fits')] wave, flux, hdr = readSpec(fname) # read the object spectrum helio_corr = wave_helio(wave, hdr) # correction to heliocentric velocity for j in np.arange(nCC-1): ind = (wave > ccRange[j]) & (wave < (ccRange[j] + bbox)) # select wave range if wave[ind].size > 1: c = 2.99792458e5 # speed of light in km/s R = wave[ind][0] / (wave[ind][1] - wave[ind][0]) dv = c / R ## velocity resolution per pixel in km/s rv, cc = pyasl.crosscorrRV(wave[ind], flux[ind], temWave, temFlux, -1.*maxRV, maxRV, dv, mode='doppler') # Find the index of maximum cross-correlation function maxind = np.argmax(cc) if abs(rv[maxind]) < maxRV: print('%12s %3s %10s %.2f %i--%i %.2f %.2f' %(wdnum, spT, obsdate, helio_corr, ccRange[j], (ccRange[j]+bbox), dv, rv[maxind]+helio_corr))
def sanity_randomDIstribution(self): """ Checking the shift with random numbers. """ from PyAstronomy import pyasl import numpy as np # Create the template tw = np.linspace(10000,10010,100) tf = np.random.normal(0.0, 1.0, len(tw)) dw = tw df = np.roll(tf, 2) rv1, cc1 = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 60./1000., skipedge=20, mode="doppler") m1 = np.argmax(cc1) rv = (tw[2] - tw[0])/np.mean(tw) * 299792.458 accu = 60./1000. self.assertAlmostEqual(rv1[m1], rv, delta=accu)
def read_tapas(file_tapas, wl, flux, rvshift=False): raw_wl, raw_trans = np.loadtxt(file_tapas, skiprows=38, unpack=True) wl_tapas = raw_wl[::-1] trans_tapas = raw_trans[::-1] if rvshift: print('Doppler shift TAPAS transmission') rv, cc = pyasl.crosscorrRV(wl, flux, wl_tapas, trans_tapas, rvmin=-60., rvmax=60.0, drv=0.1, mode='doppler', skipedge=50) maxind = np.argmax(cc) print("CCF is maximized at dRV = ", rv[maxind], " km/s") wlcorr_tapas = wl_tapas * (1. + rv[maxind] / 299792.) return wlcorr_tapas, trans_tapas else: return wl_tapas, trans_tapas
def find_rv(wavelength, flux, mask_lines=[ 5371.50, 5394.64, 5397.10, 5405.80, 5409.80, 5429.70, 5432.55, 5434.52, 5446.90, 5535.50, 6090.20, 6102.72, 6119.52, 6122.22 ], delta_rv=200): wave_mask = np.arange(mask_lines[0] - 5., mask_lines[-1] + 5., 0.01) flux_mask = 1. + wave_mask * 0.0 for line in mask_lines: flux_mask -= gaussian(wave_mask, line, 0.1) ind_wi = np.where(wavelength < wave_mask[0])[0][-1] ind_wf = np.where(wavelength > wave_mask[-1])[0][0] wave_t = wavelength[ind_wi:ind_wf] flux_t = flux[ind_wi:ind_wf] rv, cc = pyasl.crosscorrRV(wave_t, flux_t, wave_mask, flux_mask, -delta_rv, delta_rv, 0.1, skipedge=500) maxind = np.argmax(cc) # plt.figure(1) # plt.plot(wave_t,flux_t/np.median(flux_t)) # plt.plot(wave_mask,flux_mask) # plt.figure(2) # plt.plot(rv, cc) # plt.show() # plt.plot(rv, cc, 'bp-') # plt.plot(rv[maxind], cc[maxind], 'ro') # plt.show() return rv[maxind]
def pyfxcor(inspec, template, obj, vmin=-400., vmax=400., res=3, rej=200): rv, cc = pyasl.crosscorrRV(inspec[0], inspec[1], template[0], template[1], vmin, vmax, res, skipedge=rej) cen_gs = np.argmax(cc) perfx, perfy = rv[cen_gs-5:cen_gs+6], cc[cen_gs-5:cen_gs+6] try: gauss = ConstantModel() + GaussianModel() pars = gauss.make_params() pars['center'].set(value=rv[np.argmax(cc)], vary=True) pars['amplitude'].set(value=max(cc), vary=True) pars['sigma'].set(vary=True) pars['c'].set(value=0, vary=True) out = gauss.fit(perfy, pars, x=perfx) ct = out.best_values['center'] cterr = out.params['center'].stderr except: plt.plot(inspec[0], inspec[1]) plt.savefig(obj+'.png', dpi=300) pl.clf() return 'error', '' plt.subplot(311) plt.plot(rv, cc) curraxlim = plt.axis() out.plot_fit(numpoints=100) plt.axis(curraxlim) plt.subplot(312) plt.plot(obj[1][0], obj[1][1], 'r-', linewidth=0.5) plt.subplot(313) plt.plot(inspec[0], inspec[1], 'b-', linewidth=0.5) plt.savefig(obj[0]+'.png', dpi=300) plt.clf() return ct, cterr
def atm_model(w, f, berv, o): # divides spectra by atmosphere model # much more testing needed ! modelfile = 'inst/CRIRES_atm/stdAtmos_crires_airmass1.fits' hdu = fits.open(modelfile, ignore_blank=True) atm_model = hdu[1].data w_atm2 = atm_model.field(0).astype(np.float64) f_atm2 = atm_model.field(1).astype(np.float64) # file_obs2 = "data/CRIRES/210220_PiOri/cr2res_obs_nodding_extracted_combined.fits" file_obs2 = "/data/jana/VIPER/210220_tetVir/K2166/cr2res_obs_nodding_extracted_combined.fits" x2, w_atm, f_atm, bp2, bjd2, berv2 = Spectrum(file_obs2, o=o) bw = (np.load('wave_solution_tetvir.npy'))[o - 1] w_atm = np.poly1d(bw[::-1])(x2) # bb = [-0.457193, 314.784913, 5675608.219445] ba = (np.load("lib/CRIRES/blaze_K2166.npy"))[o - 1] bandp = np.poly1d(ba)(x2) lmin = w[0] lmax = w[-1] lmin = max(w[0], w_atm[0]) lmax = min(w[-1], w_atm[-1]) smo = slice(*np.searchsorted(w_atm, [lmin, lmax])) w_atm1 = w_atm[smo] f_atm1 = f_atm[smo] smo = slice(*np.searchsorted(w, [lmin, lmax])) w = w[smo] f = f[smo] bandp = bandp[smo] gplot(w_atm, f_atm / np.nanmean(f_atm), 'w l t "tell",', w, f / np.nanmean(f), 'w l t "data",', w, bandp / np.mean(bandp) * 0.9, 'w l t "bandp"') #, w_atm1,f_atm1/np.nanmean(f_atm1),'w l') pause() # correction of shift between model and observed data rv, ccc = pyasl.crosscorrRV(w, f, w_atm1, f_atm1, -5., 5., 0.005, skipedge=20) pol = (np.poly1d(np.polyfit(rv, ccc, 15)))(rv) shift = rv[np.argmax(pol)] print('shift atmmod: ', shift) print(w, w_atm1) w_atm /= (1 + shift / 3e5) smo = slice(*np.searchsorted(w_atm, [lmin, lmax])) w_atm1 = w_atm[smo] f_atm1 = f_atm[smo] print(w, w_atm1) f_atm1 = np.interp(w, w_atm1, f_atm1) # f_div = f/np.nanmean(f)/(f_atm1/np.mean(f_atm1)) f_div = f / f_atm1 print('mean', np.nanmean(abs(f / np.mean(f) - f_div / np.mean(f_div)))) i_flag = np.where( abs(f_div) <= (np.median(f_div) + 2 * np.std(abs(f_div))))[0] # i_flag = np.where(abs(f/np.nanmean(f)-f_div/np.nanmean(f_div)) <= 0.2)[0] # f_div[f_div<=0] = 1000 # i_flag = np.where(abs(f_div) <= (np.median(f_div)*1.5))[0] w1 = w * 1. w = w[i_flag] f = f[i_flag] f_div = f_div[i_flag] #*np.median(f) plot_tell = 1 if plot_tell: print('mean', np.nanmean(abs(f / np.mean(f) - f_div / np.mean(f_div)))) # gplot(w,f/np.mean(f),'w l,', w,f_atm1/np.mean(f_atm1),'w l') gplot(w, f / np.mean(f), 'w l t "data",', w, f_div / np.mean(f_div), 'w l t "div data",', w1, f_atm1 / np.mean(f_atm1), 'w l t "tell",', w, abs(f / np.nanmean(f) - f_div / np.nanmean(f_div)), 'w p pt 7 ps 0.4 t "res"') pause() return w, f_div, i_flag #f_atm
def resolution(wave, flux, err, waverange, filter): # determines spectral resolution from PyAstronomy.pyasl import crosscorrRV import numpy as np from scipy.optimize import curve_fit from scipy.signal import savgol_filter # gaussian for fitting CC to find width def gauss(x, a, b, x0, sigma): return a * np.exp(-(x - x0)**2 / (2 * sigma**2)) + b wave_temp_low = 0.97 # minimum wavelength in microns rvmin = -300. # RV range rvmax = 300 drv = 2. # increment of RV c = 3.0e5 # speed of light in km/s minsr = 100 # minimum SNR nsmooth = 51 resmin = 2000. # minimum expected resolution max_wave = np.max(waverange) * (1 + 2 * rvmax / c) min_wave = np.min(waverange) * (1 + 2 * rvmin / c) which = ((wave > min_wave) & (wave < max_wave)) wave_template = wave[which] flux_template = flux[which] err_template = err[which] smooth_template = savgol_filter(flux_template, nsmooth, 2) flux_template = flux_template / smooth_template err_template = err_template / smooth_template which = ((wave > np.min(waverange)) & (wave < np.max(waverange))) wave_target = wave[which] flux_target = flux[which] err_target = err[which] smooth_target = savgol_filter(flux_target, nsmooth, 2) flux_target = flux_target / smooth_target err_target = err_target / smooth_target rv, cc = crosscorrRV(wave_target, flux_target, wave_template, flux_template, rvmin, rvmax, drv, mode='doppler') mean = sum(rv * cc) / sum(cc) sigma = np.sqrt(sum(cc * (rv - mean)**2) / sum(cc)) base = np.min(cc) amp = np.max(cc) - base popt, pcov = curve_fit(gauss, rv, cc, p0=[amp, base, mean, sigma]) sigma = popt[3] res = c / popt[3] print('Inferred SpeX resolution =', res) #import matplotlib.pyplot as plt #plt.plot(rv,cc,'k') #plt.plot(rv,gauss(rv,popt[0],popt[1],popt[2],popt[3]),'r') #plt.show(block='True') # return resolution and piece of spectrum to use to compare with models if (res < resmin): print('Setting resolution to minimum =', resmin) res = resmin res = 2 * res # this is fudge-factor based on eye return res, wave_target, flux_target
def plot_retrieved_rotbroad(samples, dRV_data, CC_data, wlen, flux, config, output_dir='', fontsize=15): rvmin, rvmax, drv = min(dRV_data), max(dRV_data), abs(dRV_data[1] - dRV_data[0]) skipping = {} for key in wlen.keys(): wvl_stepsize = max([ wlen[key][i + 1] - wlen[key][i] for i in range(len(wlen[key]) - 1) ]) ds_max = max([ abs(wlen[key][-1] * rvmin * 1000 / cst.c), abs(wlen[key][-1] * rvmax * 1000 / cst.c) ]) skipping[key] = int(ds_max / wvl_stepsize) + 1 if skipping[key] / len(wlen[key]) >= 0.25: print( 'WARNING: NEED TO SKIP {p:.2f} % OF TEMPLATE SPECTRUM TO INVESTIGATE ALL DOPPLER-SHIFT DURING CROSS-CORRELATION' .format(p=skipping[key] / len(wlen[key]))) skipedge = int(max([skipping[key] for key in skipping.keys()]) * 1.5) nb_positions = len(samples) nb_params = len(samples[0]) assert (nb_params == 1) quantiles = {} for param_i, param in config['PARAMS_NAMES']: quantiles[param] = np.quantile(samples[param_i][0], q=[0.16, 0.5, 0.84]) wlen_temp, flux_temp = {}, {} for key in wlen.keys(): wlen_temp[key], flux_temp[key] = wlen[key], flux[key] plt.figure() for quant_i, quant in enumerate([0.16, 0.5, 0.84]): CC_range_i = {} for key_i, key in enumerate(wlen.keys()): print('Progress: {p:.2f} %'.format(p=int(100 * (key_i + 1) / len(wlen.keys())))) if 'radial_vel' in config['PARAMS_NAMES'] and quant == 0.5: wlen_temp[key], flux_temp[key] = doppler_shift( wlen_temp[key], flux_temp[key], quantiles['radial_vel'][quant_i]) if 'spin_vel' in config['PARAMS_NAMES']: flux_temp[key] = fastRotBroad(wlen_temp[key], flux_temp[key], 0, quantiles['spin_vel'][quant_i]) dRV, CC_range_i[key] = crosscorrRV(wlen[key], flux[key], wlen_temp[key], flux_temp, rvmin=rvmin, rvmax=rvmax, drv=drv, skipedge=skipedge) CC = np.array([ sum([CC_range_i[key][drv_i] for key in CC_range_i.keys()]) for drv_i in range(len(dRV)) ]) CC = CC / max(CC) RV_max_i = np.argmax(CC_data) if quant_i == 1: median_str, q2_str, q1_str = {}, {}, {} for param in config['PARAMS_NAMES']: median_str[param] = '{median:.2f}'.format( median=quantiles[param][1]) q2_str[param] = '{q2:.2f}'.format(q2=quantiles[param][2] - quantiles[param][1]) q1_str[param] = '{q1:.2f}'.format(q1=quantiles[param][1] - quantiles[param][0]) plt.plot(dRV, CC, 'k', label='Retrieved v$_{spin}$ = ' + median_str['spin_vel'] + '$^{+' + q2_str['spin_vel'] + '}_{-' + q1_str['spin_vel'] + '}$ km$s^{-1}$') plt.axvline(quantiles['radial_vel'][1], color='g', label='Retrieved RV: ' + median_str['radial_vel'] + '$^{+' + q2_str['radial_vel'] + '}_{-' + q1_str['radial_vel'] + '}$ km$s^{-1}$') else: plt.plot(dRV, CC, 'k--') plt.axvline(quantiles['radial_vel'][quant_i], color='g', ls='--') plt.axvline(quantiles['radial_vel'][quant_i], color='g', ls='--') CC_data = CC_data / max(CC_data) if 'spin_vel' in config['PARAMS_NAMES']: plt.plot(dRV_data, CC_data, 'r', label='True v$_{spin}$: ' + str(config['DATA_PARAMS']['spin_vel']) + ' km$s^{-1}$') else: plt.plot(dRV_data, CC_data, 'r') if 'radial_vel' in config['PARAMS_NAMES']: plt.axvline(config['DATA_PARAMS']['radial_vel'], color='r', ls='--') plt.legend(fontsize=fontsize) plt.xlabel('Radial velocity [kms$^{-1}$]') plt.ylabel('Normalised CCF') plt.savefig(output_dir + 'retrieved_rot_broad.png', dpi=300)
# Create the template tw = np.linspace(5000,5010,1000) tf = np.exp(-(tw-5004.0)**2/(2.*0.1**2)) # Create data, which are not that well sampled dw = np.linspace(5000,5010,200) df = np.exp(-(dw-5004.17)**2/(2.*0.1**2)) # Plot template and data plt.title("Template (blue) and data (red)") plt.plot(tw, tf, 'b.-') plt.plot(dw, df, 'r.-') plt.show() # Carry out the cross-correlation. # The RV-range is -30 - +30 km/s in steps of 0.6 km/s. # The first and last 20 points of the data are skipped. rv, cc = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 30./50., skipedge=20) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) print "Cross-correlation function is maximized at dRV = ", rv[maxind], " km/s" if rv[maxind] > 0.0: print " A red-shift with respect to the template" else: print " A blue-shift with respect to the template" plt.plot(rv, cc, 'bp-') plt.plot(rv[maxind], cc[maxind], 'ro') plt.show()
def calc_log_likelihood(self,param): # param is spin velocity investigated spin_vel,radial_vel = param log_prior = 0. log_likelihood = 0. self.function_calls += 1 # check priors log_prior += self.log_prior(spin_vel,'spin_vel') log_prior += self.log_prior(radial_vel,'radial_vel') if log_prior == -np.inf: return -np.inf wlen,flux={},{} for key in self.t_wvl.keys(): wlen[key],flux[key] = self.t_wvl[key],self.t_flux[key] # Doppler shift if 'radial_vel' in self.params_names: for key in wlen.keys(): wlen[key],flux[key] = doppler_shift(wlen[key],flux[key],radial_vel) # rot. broad. spectrum if 'spin_vel' in self.params_names: for key in self.t_wvl.keys(): if self.algo == 'fast': flux[key] = pyasl.fastRotBroad(wlen[key],flux[key],0,spin_vel) else: # 'slow' flux[key] = pyasl.rotBroad(wlen[key],flux[key],0,spin_vel) # make sure that we have same wvl coverage as data for key in wlen.keys(): wlen[key],flux[key] = np.transpose([[wlen[key][i],flux[key][i]] for i in range(len(wlen[key])) if wlen[key][i] >= self.d_wvl[key][0] and wlen[key][i] <= self.d_wvl[key][-1]]) # calculate CCF between template and rot. broadened template CC_range_i = {} for key in self.t_wvl.keys(): dRV,CC_range_i[key] = pyasl.crosscorrRV(wlen[key],flux[key], self.t_wvl[key],self.t_flux[key], rvmin=self.rvmin,rvmax=self.rvmax,drv=self.drv, skipedge=self.skipedge ) CC = np.array([sum([CC_range_i[key][drv_i] for key in CC_range_i.keys()]) for drv_i in range(len(dRV))]) drv_max_i = np.argmax(CC) drv_max = dRV[drv_max_i] # normalise CCF CC_max = CC[drv_max_i] CC = CC/CC_max """ # the problem of just shifting the CCF by some RV value is that is doesnt account for the fact that the doppler shift also stretches the spectrum CCF_new = CC if 'radial_vel' in self.params_names: CCF_f = interp1d(dRV + radial_vel,CC,fill_value = 0) CCF_new = CCF_f(self.CCF_dRV) """ CC_final = [CC[i] for i in range(len(CC)) if dRV[i] >= self.CCF_dRV[0] and dRV[i] <= self.CCF_dRV[-1]] assert(len(CC_final)==len(self.CCF_CC)) for rv_i in range(len(self.CCF_dRV)): log_likelihood += -0.5*((CC_final[rv_i]-self.CCF_CC[rv_i])/self.std_CCF)**2 if self.function_calls%self.write_threshold == 0: hours = (time() - self.start_time)/3600.0 info_list = [self.function_calls, log_likelihood, hours] with open(self.diag_file,'a') as f: for i in np.arange(len(info_list)): if (i == len(info_list) - 1): f.write(str(info_list[i]).ljust(15) + "\n") else: f.write(str(info_list[i]).ljust(15) + " ") if self.function_calls%(self.write_threshold) == 0: plt.figure() plt.plot(self.CCF_dRV,self.CCF_CC,'r',label='CCF with data') plt.plot(dRV,CC,'k',label='CCF with template') plt.legend() plt.savefig(self.output_dir + 'model/CCF_'+str(self.function_calls)+'.png') print(log_prior + log_likelihood) print("--> ", self.function_calls) return log_prior + log_likelihood
def dopp_signatures(templates, signals, axis, phase_fmt='int'): ### ----- LOAD DATA ----- ### templates = sorted(glob.glob(templates)) signals = sorted(glob.glob(signals)) phases = np.zeros(len(templates) + 1) RVs = np.zeros(len(templates) + 1) axis.set_xlim([-9, 9]) axis.set_ylim([0, 10.6]) # list of colors colors = np.linspace(0, 1, len(templates)) # keep track of color and offset color_idx = 0 offset = 0 for i in range(len(templates)): # save orbital if phase_fmt == 'int': phase = int(templates[i][-7:-4]) elif phase_fmt == 'float': phase = float(templates[i][-10:-4]) else: print('ERROR\n Unrecognized phase format.') exit() print(phase) phases[i] = phase tw, tf = np.loadtxt(templates[i], unpack=True) dw, df = np.loadtxt(signals[i], unpack=True) #print(np.sum(tf)) # Carry out the cross-correlation. # The RV-range is -10 to +10 km/s in steps of 0.1 km/s. # The first and last 200 points of the data are skipped. rv, cc = pyasl.crosscorrRV(dw, df, tw, tf, -10., 10., 0.1, mode='lin', skipedge=200) # normalize cc function cc = (cc - min(cc)) / (max(cc) - min(cc)) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) # define Gaussian function def gaussian(x, a, x0, sigma): return a * np.exp(-(x - x0) * (x - x0) / (2 * sigma * sigma)) # fit Guassian to peak region of cc function rv_range = rv[maxind - 20:maxind + 20] cc_range = cc[maxind - 20:maxind + 20] popt, pcov = curve_fit(gaussian, rv_range, cc_range, p0=[1, 0, 1]) # calculate best fit guassian rv_fit = np.linspace(rv[maxind - 20], rv[maxind + 20], 1000) cc_fit = gaussian(rv_fit, *popt) # index of maximum of Gaussian max_gauss = np.argmax(cc_fit) # save radial velocity RVs[i] = rv_fit[max_gauss] # plot CCFs axis.plot(rv, cc + offset, lw=1.5, color=my_colors(colors[color_idx])) axis.plot(rv_fit[max_gauss], cc_fit[max_gauss] + offset, '.', ms=8, color=my_colors(colors[color_idx])) offset += 0.4 color_idx += 1 phases[-1] = 360 RVs[-1] = RVs[0] return RVs, phases
test_rv = -15.205 # km/s template_spectrum = Spectrum(xaxis=w_mod, flux=i_star, calibrated=True) template_spectrum.wav_select(2100, 2200) obs_spectrum = Spectrum(xaxis=w_mod, flux=i_star, calibrated=True) obs_spectrum.doppler_shift(test_rv) obs_spectrum.wav_select(2100, 2200) print(len(obs_spectrum.xaxis)) rv, cc = pyasl.crosscorrRV(obs_spectrum.xaxis, obs_spectrum.flux, template_spectrum.xaxis, template_spectrum.flux, rvmin=-60., rvmax=60.0, drv=0.1, mode='doppler', skipedge=2000) maxind = np.argmax(cc) print("Cross-correlation function is maximized at dRV = ", rv[maxind], " km/s") # Test xcorr in spectrum rv2, cc2 = obs_spectrum.crosscorr_rv(template_spectrum, rvmin=-60., rvmax=60.0, drv=0.1, mode='doppler', skipedge=2000)
wav_band, R, flux_S, flux_T, flux_P, template_wav, template_flux, sigma_w=1e-3, I=1_000, N=10, ): P_obs = get_P_obs() # Compute v_max rv, cc = pyasl.crosscorrRV(wav, P_obs, template_wav, template_flux, -30, 30, 0.5) maxind = np.argmax(cc) v_max = rv[maxind] res = { "rv": rv, "cc": cc, "v_max": v_max, "wav": wav, "P_obs": P_obs, "C_in": C_in, "C_out": C_out, "sigma_w": sigma_w, "template_wav": template_wav, "template_flux": template_flux, "in_transit_samples": in_transit_samples, "out_of_transit_samples": out_of_transit_samples,
plt.title("Spectrum (red) and the template (blue)") plt.plot(spwl, spfl, 'r.-') plt.plot(tpwl, tpfl, 'b.-') plt.show() # Carry out the cross-correlation. # The RV-range is -rvmin to rvmax km/s in steps of rvstep # The first and last skipedge points of the data are skipped. rv, cc = pyasl.crosscorrRV(spwl, spfl, tpwl, tpfl, rvmin, rvmax, rvstep, mode='doppler', skipedge=skip) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) print("Cross-correlation function is maximized at relative RV = ", rv[maxind], " (km/s)") if rv[maxind] > 0.0: print(" This is a red-shift with respect to the template.") else: print(" This is a blue-shift with respect to the template.")
def build_grid(gridfile, nbest, res, wave, ebv, flux, err, filter, wave_rv, flux_rv, feh, feh_err): # build the comparison grid of models import matplotlib.pyplot as plt import numpy as np from scipy.interpolate import interp1d from astropy.convolution import convolve, Gaussian1DKernel from scipy.signal import savgol_filter from PyAstronomy.pyasl import crosscorrRV from PyAstronomy.pyasl import vactoair2 as vactoair from extinction import fm07, apply from astropy.io import fits print('Building the Grid....') nn = 10 rvmax = 400 rvmin = -400 drv = 2. c = 3.0e5 gauss_kernel = Gaussian1DKernel(nn) # load the grid f = fits.open('../Grid/' + gridfile) g = f[1].data #header = g['HEADER'][0] modelspec = g['SPECTRUM'][0] teff = np.array(g['TEFF'][0]) logg = np.array(g['LOGG'][0]) metal = np.array(g['METAL'][0]) a_fe = np.array(g['A_FE'][0]) #junk = header[8] #junk = np.array(junk.split()) #nlambda = int(np.asscalar((junk[2]))) #junk = header[9] #junk = np.array(junk.split()) #lambda0 = float(np.asscalar(junk[1])) #junk = header[10] #junk = np.array(junk.split()) #dlambda = float(np.asscalar(junk[1])) #modelwave = lambda0 + dlambda*np.arange(nlambda) # for original PHOENIX modelwave = np.array(g['WAVE'][0]) # for Goettingen PHOENIX nwave, nmodels = modelspec.shape nwave = int(nwave) nmodels = int(nmodels) model_vac = np.array( modelwave) # convert wavelengths from vacuum to air and to microns model_vac2 = model_vac.compress(model_vac > 2000.) model_wave = vactoair(model_vac2, mode='edlen53') / 10000. # convert to air npts = nn * res * np.log(np.max(model_wave) / np.min(model_wave)) wave_log = np.min(model_wave) * np.exp( np.arange(npts) / (1. * npts) * np.log(np.max(model_wave) / np.min(model_wave))) av = ebv * 3.1 #extinct_all = extinction.fm07(wave*10000.,av)/av_ref # approximate extinction per unit magnitude #extinct = extinct_all.compress(filter==1) #model_compare = [] rvbest = [] chisq = [] #avmodels = [] #av_max = 4. #av_values = av_max*np.arange(100)/100. for imodel in np.arange(nmodels): model_spec = np.array( modelspec[:, imodel]) * 1.0e-8 # convert from per cm to per A model_spec = model_spec.compress(model_vac > 2000.) #model_spec = model_spec*10**(-0.4*extinction.fm07(model_vac,av)) # apply extinction (EXPERIMENTAL) # interpolation function model_interp = interp1d(model_wave, model_spec, kind='linear', bounds_error=False, fill_value=0.) model_prelim = model_interp(wave) model_prelim = apply(fm07(wave * 10000, ebv, 3.1), model_prelim) fr = flux.compress(filter == 1.) / model_prelim.compress(filter == 1) # here we need to determine best-fit extinction #x = [] #for av_val in av_values: # x1 = np.sum(fr*10**(-0.4*extinct*av_val))/np.sum(10**(-0.8*extinct*av_val)) # x2 = np.sum(extinct*fr*10**(-0.4*extinct*av_val))/np.sum(extinct*10**(-0.8*extinct*av_val)) # x.append(abs(x1/x2-1.)) #av_best = av_values[np.argmin(x)] #avmodels.append(av_best) #ratval = np.sum(fr*10**(-0.4*extinct*av_best))/np.sum(10**(-0.8*extinct*av_best))*10**(-0.4*extinct*av_best) ratval = np.median(fr) model_prelim = model_prelim.compress(filter == 1) * ratval sig = (flux.compress(filter == 1) - model_prelim) / err.compress(filter == 1) #plt.plot(wave.compress(filter==1),err.compress(filter==1)) #plt.show(block=True) chisqval = np.sum(sig**2) * (1 + ( (feh - metal[imodel]) / feh_err)**2) # disabled for now chisq.append(chisqval) print('Model params =', teff[imodel], logg[imodel], metal[imodel], av_best, chisqval) indices = np.argsort(chisq) bestmodels = indices[0:nbest] chisq = np.array(chisq) teffbest = np.sort(np.unique(teff[bestmodels])) loggbest = np.sort(np.unique(logg[bestmodels])) metalbest = np.sort(np.unique(metal[bestmodels])) #avmodels = np.array(avmodels) #avbest = np.sort(np.unique(avmodels[bestmodels])) #print('Best Av = ',avmodels[indices[0]]) bestparams = [teff[indices[0]], logg[indices[0]], metal[indices[0]]] print('Best parameters = ', bestparams) plt.pause(5) teffmin = np.min(teffbest) teffmax = np.max(teffbest) loggmin = np.min(loggbest) loggmax = np.max(loggbest) metalmin = np.min(metalbest) metalmax = np.max(metalbest) if teffmin == teffmax: teffmin = teffmin - 100. teffmax = teffmax + 100. if loggmin == loggmax: loggmin = loggmin - 0.5 loggmax = loggmax + 0.5 if metalmin == metalmax: metalmin = metalmin - 0.5 metalmax = metalmax + 0.5 gridmodels = np.arange(nmodels).compress((teff >= teffmin) & (teff <= teffmax) & (logg >= loggmin) & (logg <= loggmax) & (metal >= metalmin) & (metal <= metalmax)) grid = np.zeros((len(teffbest), len(loggbest), len(metalbest), len(wave))) print('Creating subgrid with ', len(gridmodels), ' models') for imodel in gridmodels: model_spec = np.array( modelspec[:, imodel]) * 1.0e-8 # convert from per cm to per A model_spec = model_spec.compress(model_vac > 2000.) # interpolate model spectrum to logarithmic wavelengths model_interp = interp1d(model_wave, model_spec, kind='linear', bounds_error=False, fill_value=0.) model_log = model_interp(wave_log) model_conv = convolve(model_log, gauss_kernel) # convolve model with Gaussian smooth_model = savgol_filter(model_conv, 501, 2) model_norm = model_conv / smooth_model wavelim = wave_log.compress((wave_log < 1.01 * np.max(wave_rv)) & (wave_log > 0.99 * np.min(wave_rv))) modellim = model_norm.compress((wave_log < 1.01 * np.max(wave_rv)) & (wave_log > 0.99 * np.min(wave_rv))) # find Doppler shift of model rv, cc = crosscorrRV(wave_rv, flux_rv, wavelim, modellim, rvmin, rvmax, drv, mode='doppler') index = np.argmax(cc) rvbest.append(rv[index]) wave_shift = wave_log * (1 + rv[index] / c) model_interp = interp1d(wave_shift, model_conv, kind='linear', bounds_error=False, fill_value=0.) i = np.arange(len(teffbest)).compress(teff[imodel] == teffbest) j = np.arange(len(loggbest)).compress(logg[imodel] == loggbest) k = np.arange(len(metalbest)).compress(metal[imodel] == metalbest) #gridflux = model_interp(wave)*10**(-0.4*extinct_all*np.asscalar(avmodels[imodel])) # apply extinction at this step for consistency with the chi-squared minimization gridflux = model_interp(wave) grid[i, j, k, :] = gridflux return teffbest, loggbest, metalbest, grid, rvbest, bestparams
path_dump = PCA._path + dump PCA.setup(dump, PCA.lambda_polar, Resolution, "synspec") lst_size = len(lst) ii = 0 for i in lst: print str(ii + 1) + "/" + str(np.size(lst)) star = lst[ii][12:] spec = np.loadtxt(i) noise = der_snr.DER_SNR(spec[:, 1]) radialv, cc = pyasl.crosscorrRV(spec[:, 0], spec[:, 1], temp[:, 0], temp[:, 1], -200., 200., 0.1, skipedge=200) maxind = np.argmax(cc) print "Cross-correlation function is maximized at dRV = ", radialv[ maxind], " km/s for", str(star), "with a noise of", round(noise, 4) spec_rvcor = PCA.rv_cor(spec[:, 1], spec[:, 0], float(radialv[maxind])) index_c, specc = PCA.inversion(spec_rvcor, cont=True) # In case we want to save the spectra with the corrected normalization and the best fit np.savetxt("corrected_gaz/" + str(star) + "_polar", np.array([PCA.wavelength, specc, PCA.getspec(index_c)]).T)
def calc_log_L_CC(self, wlen, flux, temp_params, data_wlen, data_flux, data_N, data_sf2): log_L_CC = 0 # get data wlen_data, flux_data = data_wlen, data_flux N = data_N s_f2 = data_sf2 # cut what I don't need to improve speed #wlen_cut,flux_cut = trim_spectrum(wlen,flux,wlen_data,threshold=5000,keep=1000) wlen_removed, flux_removed, sgfilter, wlen_rebin, flux_rebin = rebin_to_CC( wlen, flux, wlen_data, win_len=self.config['WIN_LEN'], method='linear', filter_method='only_gaussian', convert=self.config['CONVERT_SINFONI_UNITS'], log_R=temp_params['log_R'], distance=self.config['DISTANCE']) if sum(np.isnan(flux_rebin)) > 0: self.NaN_spectRES += 1 log_L_CC += -np.inf assert (len(wlen_removed) == len(flux_removed)) if sum(np.isnan(flux_removed)) > 0: self.NaN_savgolay += 1 log_L_CC += -np.inf # cross-correlation dRV, CC = crosscorrRV(wlen_data, flux_data, wlen_removed, flux_removed, rvmin=self.config['RVMIN'], rvmax=self.config['RVMAX'], drv=self.config['DRV']) if sum(np.isnan(CC) > 0): self.NaN_crosscorrRV += 1 log_L_CC += -np.inf CC = CC / N RV_max_i = np.argmax(CC) CC_max = CC[RV_max_i] if self.plotting: if (self.function_calls % self.config['PLOTTING_THRESHOLD'] == 0): plt.figure() plt.plot(dRV, CC) plt.axvline(dRV[RV_max_i], color='r', label='Max CC at RV={rv}'.format(rv=dRV[RV_max_i])) plt.legend() plt.title('C-C ' + str( int(self.function_calls / self.config['PLOTTING_THRESHOLD']))) plt.savefig(self.output_path + 'model/CC_fct_' + str( int(self.function_calls / self.config['PLOTTING_THRESHOLD'])) + '.png', dpi=100) # need to doppler shift the model to the argmax of the CC-function. For that, we need to go back to high-resolution spectrum out of petitRADTRAS wlen_removed, flux_removed = wlen, flux if abs(dRV[RV_max_i]) < max(abs(self.config['RVMIN']), abs(self.config['RVMAX'])) * 0.75: wlen_removed, flux_removed = doppler_shift(wlen, flux, dRV[RV_max_i]) else: print('Cant Dopplershift too much') self.nb_failed_DS += 1 wlen_removed, flux_removed, sgfilter, wlen_rebin, flux_rebin = rebin_to_CC( wlen_removed, flux_removed, wlen_data, win_len=self.config['WIN_LEN'], method='datalike', filter_method='only_gaussian', convert=self.config['CONVERT_SINFONI_UNITS'], log_R=temp_params['log_R'], distance=self.config['DISTANCE']) assert (len(wlen_removed) == len(wlen_data)) s_g2 = 1. / len(flux_removed) * np.sum(flux_removed**2) if (s_f2 - 2 * CC_max + s_g2) <= 0: self.NaN_crosscorrRV += 1 log_L_CC += -np.inf print('Negative values inside logarithm') log_L_CC += -N * np.log(s_f2 - 2 * CC_max + s_g2) / 2 return log_L_CC, wlen_removed, flux_removed, sgfilter
def dopp_signatures(templates, signals, phase_fmt='int'): ### ----- LOAD DATA ----- ### templates = sorted(glob.glob(templates)) signals = sorted(glob.glob(signals)) phases = np.zeros(len(templates) + 1) RVs = np.zeros(len(templates) + 1) # set up CCF figure font = {'size': 14, 'family': 'serif'} plt.rc('font', **font) CCF_fig, ax = plt.subplots(1, 1, figsize=(10, 10)) ax.set_ylabel('Doppler shift [km s$^{-1}$]') ax.set_xlabel('Phase angle [degrees]') ax.set_ylim([-10, 10]) ax.set_xlim([-75, 360]) ax_cc = ax.twiny() ax_cc.set_ylim([-5, 5]) ax_cc.set_xlim([0, 5.8]) ax_cc.set_xlabel('Cross correlation + constant') # add colorbar sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, norm=plt.Normalize(vmin=0, vmax=1)) sm._A = [] cbar = plt.colorbar(sm) cbar.ax.set_ylabel('Orbital phase') # list of colors colors = np.linspace(0, 1, len(templates)) # keep track of color and offset color_idx = 0 offset = 0 for i in range(len(templates)): # save orbital if phase_fmt == 'int': phase = int(templates[i][-7:-4]) elif phase_fmt == 'float': phase = float(templates[i][-10:-4]) else: print('ERROR\n Unrecognized phase format.') exit() print(phase) phases[i] = phase tw, tf = np.loadtxt(templates[i], unpack=True) dw, df = np.loadtxt(signals[i], unpack=True) ''' # Plot template and data in real time plt.plot(tw, tf, 'b-', label='Rest-frame (template)') plt.plot(dw, df, 'r-', label='Shifted') plt.legend() plt.xlim([2.311e-6, 2.313e-6]) plt.ylim([0, 5e-9]) plt.title(f'$\\varphi=${phase}') plt.plot() plt.show(block=False) plt.pause(0.01) plt.close() ''' # Carry out the cross-correlation. # The RV-range is -10 to +10 km/s in steps of 0.1 km/s. # The first and last 200 points of the data are skipped. rv, cc = pyasl.crosscorrRV(dw, df, tw, tf, -10., 10., 0.1, mode='lin', skipedge=200) # normalize cc function cc = (cc - min(cc)) / (max(cc) - min(cc)) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) # define Gaussian function def gaussian(x, a, x0, sigma): return a * np.exp(-(x - x0) * (x - x0) / (2 * sigma * sigma)) # fit Guassian to peak region of cc function rv_range = rv[maxind - 20:maxind + 20] cc_range = cc[maxind - 20:maxind + 20] popt, pcov = curve_fit(gaussian, rv_range, cc_range, p0=[1, 0, 1]) # calculate best fit guassian rv_fit = np.linspace(rv[maxind - 20], rv[maxind + 20], 1000) cc_fit = gaussian(rv_fit, *popt) # index of maximum of Gaussian max_gauss = np.argmax(cc_fit) # save radial velocity RVs[i] = rv_fit[max_gauss] # plot CCFs ax_cc.plot(cc + offset, rv, lw=2, color=plt.cm.jet(colors[color_idx])) ax_cc.plot(cc[maxind] + offset, rv[maxind], 'x', color=plt.cm.jet(colors[color_idx])) ax_cc.plot(cc_fit + offset, rv_fit, 'k-', alpha=0.5) ax_cc.plot(cc_fit[max_gauss] + offset, rv_fit[max_gauss], 'kx', alpha=0.5) offset += 0.1 color_idx += 1 ''' # print stuff and plot print("Cross-correlation function is maximized at dRV = ", rv_fit[max_gauss], " km/s") if rv_fit[max_gauss] > 0.0: print(" A red-shift with respect to the template") else: print(" A blue-shift with respect to the template") plt.plot(rv, cc, 'b-') plt.plot(rv[maxind], cc[maxind], 'bx') plt.plot(rv_fit, cc_fit, 'r-') plt.plot(rv_fit[max_gauss], cc_fit[max_gauss], 'rx') plt.title(f'$\\varphi$ = {phase}') plt.xlabel('Doppler shift [km/s]') plt.ylabel('Cross correlation') plt.show() ''' phases[-1] = 360 RVs[-1] = RVs[0] # plot RV line ax.set_zorder(2) ax.patch.set_visible(False) ax.plot(phases, RVs, 'r', lw=2) ax.plot(phases - 360, RVs, 'r', lw=2) # horizontal line ax.axhline(0, color='k', lw=1, ls='--', zorder=0) #plt.show() #CCF_fig.savefig(savefile, bbox_inches='tight', dpi=300) return phases, RVs
def fit_echelle_solution_recc(initial_solutions, norders, spectrum, wshift=0): fit_w0, sigma = echelle_equation_fit_sigclip(initial_solutions[:, 0], initial_solutions[:, 2]) print(fit_w0) fit_deltaA = median(initial_solutions[:, 1] / echelle_equation(fit_w0, initial_solutions[:, 0])) print(fit_deltaA) initial_solutions = transpose( array([ arange(0, norders), echelle_equation(fit_w0, arange(0, norders)), fit_deltaA * echelle_equation(fit_w0, arange(0, norders)) ])) for order in range(len(initial_solutions)): x0 = initial_solutions[order] spec = spectrum[order] xpos = arange(len(spec)) - len(spec) / 2 mask = xpos > min(xpos) + 10 mask *= xpos < max(xpos) - 10 spec -= min(spec) spec = normalise(spec[mask], deg=10) xpos = xpos[mask] wave = polyval([x0[2], x0[1]], xpos) spec_i = -1 * (spec - 1) wave_template = arange(min(wave) - 150, max(wave) + 150, abs(x0[2])) template_i = interpolate.splev( wave_template, template_interp, ext=1) ### interpolate the template spectrum template_i = normalise( template_i ) ### comment out this step if using normalised template spectrum template_i = -1 * (template_i - 1) #spec_i /= max(spec_i) #template_i /= max(template_i) mask = wave_template == wave_template try: drv, cc = pyasl.crosscorrRV(wave, spec_i, wave_template[mask], template_i[mask], -5000, +5000, 1, mode='doppler', skipedge=0, edgeTapering=None) epos = pyasl.quadExtreme(drv, cc, mode='max', dp=(10, 10), exInd=None, fullOutput=False, fullPoint=False)[0] epos -= wshift wcenter = x0[1] - epos * x0[1] / c except: print("Could not cross correlate order", order) print(wcenter, x0[1]) initial_solutions[order, 1] = wcenter fit_w0, sigma = echelle_equation_fit_sigclip(initial_solutions[:, 0], initial_solutions[:, 1]) print(fit_w0) fit_deltaA = median(initial_solutions[:, 2] / echelle_equation(fit_w0, initial_solutions[:, 0])) print(fit_deltaA) initial_solutions = transpose( array([ arange(0, norders), echelle_equation(fit_w0, arange(0, norders)), fit_deltaA * echelle_equation(fit_w0, arange(0, norders)) ])) # plt.subplot(221) # plt.scatter(initial_solutions[:,0],initial_solutions[:,2]) # plt.plot(arange(0,norders),echelle_equation(fit_w0,arange(0,norders))) # plt.subplot(222) # plt.scatter(initial_solutions[:,0],initial_solutions[:,2]-echelle_equation(fit_w0,initial_solutions[:,0])) # plt.subplot(223) # plt.scatter(initial_solutions[:,0],initial_solutions[:,1]) # plt.plot(arange(0,norders),fit_deltaA*echelle_equation(fit_w0,arange(0,norders))) # plt.subplot(224) # plt.scatter(initial_solutions[:,0],initial_solutions[:,1]-fit_deltaA*initial_solutions[:,2]) # #plt.savefig("echelle_equation_fit.pdf") # #plt.show() return initial_solutions
""" test = radial_velocity(dw, df, de, # spectral data on your target (uncertainty is NOT SNR) tw, tf, te, # spectral data on a star with known RV, in the same (or at least overlapping) wavelength region 'HR_4521', 'HR_260', # their names, for the plots (see point 2 below for details) 0.3, 0.01, # the radial velocity of the standard, for the plots 1, # for the plots. Should be the same for both. 200, # set to 200 for 'default', see point 3 below for what this means 0, 0, 0) # set all to zero by default. See point 4 below for what this means print(test) """ # Carry out the cross-correlation. # The RV-range is -30 - +30 km/s in steps of 0.6 km/s. # The first and last 20 points of the data are skipped. # rv, cc = pyasl.crosscorrRV(dw, df, tw, tf, -30., 30., 30./50., skipedge=20) rv, cc = pyasl.crosscorrRV(dw_cut, df_cut, tw, tf, -100., 100., 30./50, skipedge=20) # Find the index of maximum cross-correlation function maxind = np.argmax(cc) print("Cross-correlation function is maximized at dRV = ", rv[maxind], " km/s") if rv[maxind] > 0.0: print(" A red-shift with respect to the template") else: print(" A blue-shift with respect to the template") plt.plot(rv, cc, 'bp-') plt.plot(rv[maxind], cc[maxind], 'ro') plt.show()