def lnlike(theta, data=data): """ Log-likelihood, computed from chi-squared. Parameters ---------- theta data Returns ------- -0.5 * chi-square + sum of the log of the noise """ ## Parameters MCMC lsf, airmass, pwv, A, B = theta model = tellurics.makeTelluricModel(lsf, airmass, pwv, A, B, data=data, deg=2, niter=None) chisquare = smart.chisquare(data, model) return -0.5 * (chisquare + np.sum(np.log(2 * np.pi * data.noise**2)))
def lnlike(theta, data, lsf): """ Log-likelihood, computed from chi-squared. Parameters ---------- theta lsf data Returns ------- -0.5 * chi-square + sum of the log of the noise """ ## Parameters MCMC teff, logg, vsini, rv, teff2, logg2, vsini2, rv2, flsc, am, pwv, A, B, N = theta #N noise prefactor #teff, logg, vsini, rv, , am, pwv, A, B, freq, amp, phase = theta model = model_fit.makeModel(teff=teff, logg=logg, metal=0.0, vsini=vsini, rv=rv, teff2=teff2, logg2=logg2, vsini2=vsini2, rv2=rv2, flux_scale=flsc, tell_alpha=1.0, wave_offset=B, flux_offset=A, lsf=lsf, order=data.order, data=data, modelset=modelset, airmass=am, pwv=pwv, binary=True) chisquare = smart.chisquare(data, model) / N**2 return -0.5 * (chisquare + np.sum(np.log(2 * np.pi * (data.noise * N)**2)))
def telluric_mask(data, sigma=2.5, lsf=4.8, pwv=None, pixel_start=10, pixel_end=-30, outlier_rejection=2.5, diagnostic=True, save_to_path='./'): """ Routine to generate a mask for tellurics as the MCMC initialization. Parameters ---------- sigma : float; default 2.5 The sigma-clipping method to reject the outliers. lsf : float; default 4.8 The value of line spread function. The default is the normal value of LSF for Keck/NIRSPEC. pwv : float; default None precitable water vapor. The default is to run the chi2 grids of pwv to obtain the best pwv. pixel_start : int; default 10 The starting pixel to compute the mask. pixel_end : int; default -30 The ending pixel to compute the mask. outlier_rejection : float; default 2.5 The value for number * sigma to reject outliers diagnostic : bool; default True Generate the diagnostic plots for pwv-ch2 and model-data before/after masks save_to_path : str; default the current working directory Returns ------- mask : numpy array pwv : float airmass : float Example ------- >>> from smart.forward_model import mask >>> tell_mask, pwv, airmass = mask.telluric_mask(data, diagnostic=False) """ data.flux = data.flux[pixel_start:pixel_end] data.wave = data.wave[pixel_start:pixel_end] data.noise = data.noise[pixel_start:pixel_end] data0 = copy.deepcopy(data) # take the closest airmass from the header airmass = float(round(data.header['AIRMASS']*2)/2) if airmass > 3.0: airmass = 3.0 # simple chi2 comparison with different pwv if pwv is None: pwvs = [0.5, 1.0, 1.5, 2.5, 3.5, 5.0, 7.5, 10.0, 20.0] pwv_chi2 = [] for pwv in pwvs: data_tmp = copy.deepcopy(data) #data_tmp = smart.continuumTelluric(data=data_tmp, model=model_tmp) model_tmp = tellurics.makeTelluricModel(lsf=lsf, airmass=airmass, pwv=pwv, flux_offset=0, wave_offset=0, data=data_tmp, deg=10) model_tmp.flux = np.array(smart.integralResample(xh=model_tmp.wave, yh=model_tmp.flux, xl=data_tmp.wave)) model_tmp.wave = data_tmp.wave #plt.plot(data_tmp.wave, data_tmp.flux, 'k-') #plt.plot(model_tmp.wave, model_tmp.flux, 'r-') #plt.show() #plt.close() pwv_chi2.append(smart.chisquare(data_tmp, model_tmp)) # find the pwv with minimum chisquare pwv_chi2_array = np.array(pwv_chi2) if diagnostic: plt.plot(pwvs, pwv_chi2) plt.xlabel('pwv (mm)', fontsize=15) plt.ylabel('$\chi^2$', fontsize=15) plt.tight_layout() plt.savefig(save_to_path+'pwv_chi2.png') #plt.show() plt.close() pwv_min_index = np.where(pwv_chi2_array == np.min(pwv_chi2_array))[0][0] pwv = pwvs[pwv_min_index] data_tmp = copy.deepcopy(data) model = tellurics.makeTelluricModel(lsf=lsf, airmass=airmass, pwv=pwv, flux_offset=0, wave_offset=0, data=data_tmp) model_0 = copy.deepcopy(model) # generate the mask based on sigma clipping pixel = np.delete(np.arange(len(data.oriWave)), data.mask)[pixel_start: pixel_end] #pixel = np.delete(np.arange(len(data_tmp.oriWave)),data_tmp.mask) mask = pixel[np.where(np.abs(data_tmp.flux-model.flux) > outlier_rejection*np.std(data_tmp.flux-model.flux))] #plt.plot(data_tmp.wave, data_tmp.flux, 'k-') #plt.plot(model.wave, model.flux, 'r-') #plt.show() #plt.close() data_tmp.mask_custom(mask) data_tmp.flux = data_tmp.flux[pixel_start:pixel_end] data_tmp.wave = data_tmp.wave[pixel_start:pixel_end] data_tmp.noise = data_tmp.noise[pixel_start:pixel_end] #plt.plot(data_tmp.wave, data_tmp.flux, 'k-') #plt.plot(model.wave, model.flux, 'r-') #plt.show() #plt.close() # use curve_fit def tell_model_fit(wave, airmass, pwv, flux_offset, wave_offset): model = tellurics.makeTelluricModel(lsf=lsf, airmass=airmass, pwv=pwv, flux_offset=flux_offset, wave_offset=wave_offset, data=data_tmp) return model.flux print('initial airmass and pwv', airmass, pwv) flux_med = np.median(data_tmp.flux) p0 = [airmass, pwv, 0, 0] bounds = ([airmass-0.5, pwv-0.5, -flux_med*0.05, -0.05], [airmass+0.5, pwv+0.5, flux_med*0.05, 0.05]) popt, pcov = curve_fit(tell_model_fit, data_tmp.wave, data_tmp.flux, p0=p0, bounds=bounds) airmass, pwv, flux_offset, wave_offset = popt[0], popt[1], popt[2], popt[3] print('best-fit airmass, pwv, flux_offset, wave_offset', airmass, pwv, flux_offset, wave_offset) model = tellurics.makeTelluricModel(lsf=lsf, airmass=airmass, pwv=pwv, flux_offset=0, wave_offset=0, data=data_tmp) print('old telluric mask', mask) pixel = np.delete(np.arange(len(data_tmp.oriWave)), mask)[pixel_start: pixel_end] #print('len pixel, data, model', len(pixel), len(data_tmp.wave), len(model.wave)) mask = pixel[np.where(np.abs(data_tmp.flux-model.flux) > outlier_rejection*np.std(data_tmp.flux-model.flux))] # combine the masks mask = np.union1d(mask,np.array(data_tmp.mask)) print('new telluric mask', mask) data.mask_custom(mask) data.flux = data.flux[pixel_start:pixel_end] data.wave = data.wave[pixel_start:pixel_end] data.noise = data.noise[pixel_start:pixel_end] print(data.mask) #plt.plot(data.wave, data.flux, 'k-') #plt.plot(model.wave, model.flux, 'r-') #plt.plot(model_0.wave, model_0.flux, 'b-', alpha=0.5) #plt.show() #plt.close() if diagnostic: data.flux = data.flux[pixel_start:pixel_end] data.wave = data.wave[pixel_start:pixel_end] data.noise = data.noise[pixel_start:pixel_end] model = tellurics.makeTelluricModel(lsf=lsf, airmass=airmass, pwv=pwv, flux_offset=0, wave_offset=0, data=data) plt.plot(data0.wave, data0.flux, 'k-', label='original data', alpha=0.5) plt.plot(data.wave, data.flux, 'k-', label='masked data') plt.plot(model.wave, model.flux, 'r-', alpha=0.7) plt.plot(data.wave, data.flux-model.flux, 'r-') plt.xlabel('$\lambda (\AA)$') plt.ylabel('$F_{\lambda}$') plt.savefig(save_to_path+'telluric_data_model_mask.png') #plt.show() plt.close() return mask.tolist(), pwv, airmass
plt.figtext(0.89,0.83,"${0}^{{+{1}}}_{{-{2}}}/{3}^{{+{4}}}_{{-{5}}}/{6}^{{+{7}}}_{{-{8}}}$".format(\ round(lsf_mcmc[0],2), round(lsf_mcmc[1],2), round(lsf_mcmc[2],2), round(alpha_mcmc[0],2), round(alpha_mcmc[1],2), round(alpha_mcmc[2],2), round(B_mcmc[0],2), round(B_mcmc[1],2), round(B_mcmc[2],2)), color='r', horizontalalignment='right', verticalalignment='center', fontsize=12) plt.figtext(0.89,0.80,r"$\chi^2$ = {}, DOF = {}".format(\ round(smart.chisquare(data,model)), round(len(data.wave-ndim)/3)), color='k', horizontalalignment='right', verticalalignment='center', fontsize=12) plt.fill_between(data.wave, -data.noise, data.noise, alpha=0.5) plt.tick_params(labelsize=15) plt.ylabel('Flux (counts/s)', fontsize=15) plt.xlabel('Wavelength ($\AA$)', fontsize=15) ax2 = ax1.twiny() ax2.plot(pixel, data.flux, color='w', alpha=0) ax2.set_xlabel('Pixel', fontsize=15) ax2.tick_params(labelsize=15) ax2.set_xlim(pixel[0], pixel[-1]) ax2.minorticks_on()
def initModelFit(sci_data, lsf, modelset='btsettl08'): """ Conduct simple chisquare fit to obtain the initial parameters for the forward modeling MCMC. The function would calculate the chisquare for teff, logg, vini, rv, and alpha. Parameters ---------- data : spectrum object input science data lsf : float line spread function for the NIRSPEC Returns ------- best_params_dic : dic a dictionary that stores the best parameters for teff, logg, vsini, rv, and alpha chisquare : int minimum chisquare """ data = copy.deepcopy(sci_data) ## set up the parameter grid for chisquare computation teff_array = np.arange(1200, 3001, 100) logg_array = np.arange(3.5, 5.51, 0.5) vsini_array = np.arange(10, 101, 10) rv_array = np.arange(-200, 201, 50) alpha_array = np.arange(0.5, 2.01, 0.5) chisquare_array = np.empty(len(teff_array)*len(logg_array)*len(vsini_array)*len(rv_array)*len(alpha_array))\ .reshape(len(teff_array),len(logg_array),len(vsini_array),len(rv_array),len(alpha_array)) time1 = time.time() for i, teff in enumerate(teff_array): for j, logg in enumerate(logg_array): for k, vsini in enumerate(vsini_array): for l, rv in enumerate(rv_array): for m, alpha in enumerate(alpha_array): model = smart.makeModel(teff, logg, 0.0, vsini, rv, alpha, 0, 0, lsf=lsf, order=str(data.order), data=data, modelset=modelset) chisquare_array[i, j, k, l, m] = smart.chisquare(data, model) time2 = time.time() print("total time:", time2 - time1) ind = np.unravel_index(np.argmin(chisquare_array, axis=None), chisquare_array.shape) print("ind ", ind) chisquare = chisquare_array[ind] best_params_dic = { 'teff': teff_array[ind[0]], 'logg': logg_array[ind[1]], 'vsini': vsini_array[ind[2]], 'rv': rv_array[ind[3]], 'alpha': alpha_array[ind[4]] } print(best_params_dic, chisquare) return best_params_dic, chisquare
def getAlpha(telluric_data, lsf, continuum=True, test=False, save_path=None): """ Return a best alpha value from a telluric data. """ alpha_list = [] test_alpha = np.arange(0.1, 7, 0.1) data = copy.deepcopy(telluric_data) if continuum is True: data = smart.continuumTelluric(data=data) for i in test_alpha: telluric_model = smart.convolveTelluric(lsf, data, alpha=i) #telluric_model.flux **= i if data.order == 59: # mask hydrogen absorption feature data2 = copy.deepcopy(data) tell_mdl = copy.deepcopy(telluric_model) mask_pixel = 450 data2.wave = data2.wave[mask_pixel:] data2.flux = data2.flux[mask_pixel:] data2.noise = data2.noise[mask_pixel:] tell_mdl.wave = tell_mdl.wave[mask_pixel:] tell_mdl.flux = tell_mdl.flux[mask_pixel:] chisquare = smart.chisquare(data2, tell_mdl) else: chisquare = smart.chisquare(data, telluric_model) alpha_list.append([chisquare, i]) if test is True: plt.plot(telluric_model.wave, telluric_model.flux + i * 10, 'k-', alpha=0.5) if test is True: plt.plot(telluric_data.wave, telluric_data.flux, 'r-', alpha=0.5) plt.rc('font', family='sans-serif') plt.title("Test Alpha", fontsize=15) plt.xlabel("Wavelength ($\AA$)", fontsize=12) plt.ylabel("Transmission + Offset", fontsize=12) plt.minorticks_on() if save_path is not None: plt.savefig(save_path+\ "/{}_O{}_alpha_data_mdl.png"\ .format(telluric_data.name, telluric_data.order)) plt.show() plt.close() fig, ax = plt.subplots() plt.rc('font', family='sans-serif') for i in range(len(alpha_list)): ax.plot(alpha_list[i][1], alpha_list[i][0], 'k.', alpha=0.5) ax.plot(min(alpha_list)[1], min(alpha_list)[0], 'r.', label="best alpha {}".format(min(alpha_list)[1])) ax.set_xlabel(r"$\alpha$", fontsize=12) ax.set_ylabel("$\chi^2$", fontsize=12) plt.minorticks_on() plt.legend(fontsize=10) if save_path is not None: plt.savefig(save_path+\ "/{}_O{}_alpha_chi2.png"\ .format(telluric_data.name, telluric_data.order)) plt.show() plt.close() alpha = min(alpha_list)[1] return alpha
def getLSF(telluric_data, alpha=1.0, continuum=True, test=False, save_path=None): """ Return a best LSF value from a telluric data. """ lsf_list = [] test_lsf = np.arange(3.0, 13.0, 0.1) data = copy.deepcopy(telluric_data) if continuum is True: data = smart.continuumTelluric(data=data) data.flux **= alpha for i in test_lsf: telluric_model = smart.convolveTelluric(i, data) if telluric_data.order == 59: telluric_model.flux **= 3 # mask hydrogen absorption feature data2 = copy.deepcopy(data) tell_mdl = copy.deepcopy(telluric_model) mask_pixel = 450 data2.wave = data2.wave[mask_pixel:] data2.flux = data2.flux[mask_pixel:] data2.noise = data2.noise[mask_pixel:] tell_mdl.wave = tell_mdl.wave[mask_pixel:] tell_mdl.flux = tell_mdl.flux[mask_pixel:] chisquare = smart.chisquare(data2, tell_mdl) else: chisquare = smart.chisquare(data, telluric_model) lsf_list.append([chisquare, i]) if test is True: plt.plot(telluric_model.wave, telluric_model.flux + (i - 3) * 10 + 1, 'r-', alpha=0.5) if test is True: plt.plot(data.wave, data.flux, 'k-', label='telluric data', alpha=0.5) plt.title("Test LSF", fontsize=15) plt.xlabel("Wavelength ($\AA$)", fontsize=12) plt.ylabel("Transmission + Offset", fontsize=12) plt.minorticks_on() if save_path is not None: plt.savefig(save_path+\ "/{}_O{}_lsf_data_mdl.png"\ .format(data.name, data.order)) #plt.show() plt.close() fig, ax = plt.subplots() for i in range(len(lsf_list)): ax.plot(lsf_list[i][1], lsf_list[i][0], 'k.', alpha=0.5) ax.plot(min(lsf_list)[1], min(lsf_list)[0], 'r.', label="best LSF {} km/s".format(min(lsf_list)[1])) ax.set_xlabel("LSF (km/s)", fontsize=12) ax.set_ylabel("$\chi^2$", fontsize=11) plt.minorticks_on() plt.legend(fontsize=10) if save_path is not None: plt.savefig(save_path+\ "/{}_O{}_lsf_chi2.png"\ .format(data.name, data.order)) #plt.show() plt.close() lsf = min(lsf_list)[1] if telluric_data.order == 61 or telluric_data.order == 62 \ or telluric_data.order == 63: #or telluric_data.order == 64: lsf = 5.5 print("The LSF is obtained from orders 60 and 65 (5.5 km/s).") return lsf