def makeTelluricModel(lsf, airmass, pwv, flux_offset, wave_offset, data, deg=2, niter=None): """ Make a continuum-corrected telluric model as a function of LSF, airmass, pwv, and flux and wavelength offsets. The model assumes a second-order polynomail for the continuum. """ data2 = copy.deepcopy(data) data2.wave = data2.wave + wave_offset telluric_model = convolveTelluric(lsf, airmass, pwv, data2) model = smart.continuum(data=data2, mdl=telluric_model, deg=deg) if niter is not None: for i in range(niter): model = smart.continuum(data=data2, mdl=model, deg=deg) model.flux += flux_offset return model
def bestParams2(theta, data): i, alpha, c2, c0, c1 = theta data2 = copy.deepcopy(data) data2.wave = data2.wave * c1 + c0 telluric_model = smart.convolveTelluric(i, data2, alpha=alpha) model = smart.continuum(data=data2, mdl=telluric_model) return np.sum(data.flux - (model.flux + c2))**2
def getLSF2(telluric_data, continuum=True, test=False, save_path=None): """ Return a best LSF value from a telluric data. """ data = copy.deepcopy(telluric_data) def bestParams(data, i, alpha, c2, c0): data2 = copy.deepcopy(data) data2.wave = data2.wave + c0 telluric_model = smart.convolveTelluric(i, data2, alpha=alpha) model = smart.continuum(data=data2, mdl=telluric_model) #plt.figure(2) #plt.plot(model.wave, model.flux+c2, 'r-', alpha=0.5) #plt.plot(data.wave*c1+c0, data.flux, 'b-', alpha=0.5) #plt.close() #plt.show() #sys.exit() return model.flux + c2 def bestParams2(theta, data): i, alpha, c2, c0, c1 = theta data2 = copy.deepcopy(data) data2.wave = data2.wave * c1 + c0 telluric_model = smart.convolveTelluric(i, data2, alpha=alpha) model = smart.continuum(data=data2, mdl=telluric_model) return np.sum(data.flux - (model.flux + c2))**2 from scipy.optimize import curve_fit, minimize popt, pcov = curve_fit(bestParams, data, data.flux, p0=[4.01, 1.01, 0.01, 1.01], maxfev=1000000, epsfcn=0.1) #nll = lambda *args: bestParams2(*args) #results = minimize(nll, [3., 1., 0.1, -10., 1.], args=(data)) #popt = results['x'] data.wave = data.wave + popt[3] telluric_model = smart.convolveTelluric(popt[0], data, alpha=popt[1]) model = smart.continuum(data=data, mdl=telluric_model) #model.flux * np.e**(-popt[2]) + popt[3] model.flux + popt[2] return popt[0]
def bestParams(data, i, alpha, c2, c0): data2 = copy.deepcopy(data) data2.wave = data2.wave + c0 telluric_model = smart.convolveTelluric(i, data2, alpha=alpha) model = smart.continuum(data=data2, mdl=telluric_model) #plt.figure(2) #plt.plot(model.wave, model.flux+c2, 'r-', alpha=0.5) #plt.plot(data.wave*c1+c0, data.flux, 'b-', alpha=0.5) #plt.close() #plt.show() #sys.exit() return model.flux + c2
def makeTelluricModel(lsf, alpha, flux_offset, wave_offset, data=data, pwv=pwv, airmass=airmass, deg=cont_deg): """ Make a telluric model as a function of LSF, alpha, and flux offset. ## Note: The function "convolveTelluric " used is from the model_fit.py, not in the tellurics!s """ niter = 5 # continuum iteration data2 = copy.deepcopy(data) data2.wave = data2.wave + wave_offset #data2.wave = data2.wave * (1 + wave_offset1) + wave_offset telluric_model = smart.convolveTelluric(lsf, data2, alpha=alpha, pwv=pwv) #if data.order == 35: # from scipy.optimize import curve_fit # data_flux_avg = np.average(data2.flux) # popt, pcov = curve_fit(smart.voigt_profile,data2.wave[0:-10], data2.flux[0:-10], # p0=[21660,data_flux_avg,0.1,0.1,0.01,0.1,10000,1000], maxfev=10000) # #model = smart.continuum(data=data2, mdl=telluric_model, deg=2) # model = telluric_model # max_model_flux = np.max(smart.voigt_profile(data2.wave, *popt)) # model.flux *= smart.voigt_profile(data2.wave, *popt)/max_model_flux # model = smart.continuum(data=data2, mdl=model, deg=deg) #else: model = smart.continuum(data=data2, mdl=telluric_model, deg=deg) for i in range(niter): model = smart.continuum(data=data2, mdl=model, deg=deg) model.flux += flux_offset return model
truths=[lsf_mcmc[0], alpha_mcmc[0], A_mcmc[0], B_mcmc[0]], quantiles=[0.16, 0.84], label_kwargs={"fontsize": 20}) plt.minorticks_on() fig.savefig(save_to_path + '/triangle.png', dpi=300, bbox_inches='tight') #plt.show() plt.close() deg = cont_deg niter = 5 data2 = copy.deepcopy(data) data2.wave = data2.wave + B_mcmc[0] telluric_model = smart.convolveTelluric(lsf_mcmc[0], data, alpha=alpha_mcmc[0]) model, pcont = smart.continuum(data=data, mdl=telluric_model, deg=deg, tell=True) polyfit = np.polyval(pcont, model.wave) for i in range(niter): model, pcont2 = smart.continuum(data=data2, mdl=model, deg=deg, tell=True) polyfit2 = np.polyval(pcont2, model.wave) polyfit *= polyfit2 polyfit += A_mcmc[0] model.flux += A_mcmc[0] plt.tick_params(labelsize=20) fig = plt.figure(figsize=(20, 8)) ax1 = fig.add_subplot(111) ax1.plot(model.wave, model.flux, c='C3', ls='-', alpha=0.5)
def makeModel(teff, logg=5, metal=0, vsini=1, rv=0, tell_alpha=1.0, airmass=1.0, pwv=0.5, wave_offset=0, flux_offset=0, **kwargs): """ Return a forward model. Parameters ---------- teff : effective temperature data : an input science data used for continuum correction Optional Parameters ------------------- Returns ------- model: a synthesized model """ # read in the parameters order = kwargs.get('order', '33') modelset = kwargs.get('modelset', 'btsettl08') instrument = kwargs.get('instrument', 'nirspec') veiling = kwargs.get('veiling', 0) # flux veiling parameter lsf = kwargs.get('lsf', 4.5) # instrumental LSF if instrument == 'apogee': try: import apogee_tools as ap except ImportError: print( 'Need to install the package "apogee_tools" (https://github.com/jbirky/apogee_tools) \n' ) xlsf = kwargs.get('xlsf', np.linspace(-7., 7., 43)) # APOGEE instrumental LSF sampling wave_off1 = kwargs.get('wave_off1') # wavelength offset for chip a wave_off2 = kwargs.get('wave_off2') # wavelength offset for chip b wave_off3 = kwargs.get('wave_off3') # wavelength offset for chip c c0_1 = kwargs.get('c0_1') # constant flux offset for chip a c0_2 = kwargs.get('c0_2') # linear flux offset for chip a c1_1 = kwargs.get('c1_1') # constant flux offset for chip b c1_2 = kwargs.get('c1_2') # linear flux offset for chip b c2_1 = kwargs.get('c2_1') # constant flux offset for chip c c2_2 = kwargs.get('c2_2') # linear flux offset for chip c tell = kwargs.get('tell', True) # apply telluric #tell_alpha = kwargs.get('tell_alpha', 1.0) # Telluric alpha power binary = kwargs.get('binary', False) # make a binary model # assume the secondary has the same metallicity if binary: teff2 = kwargs.get('teff2') logg2 = kwargs.get('logg2') rv2 = kwargs.get('rv2') vsini2 = kwargs.get('vsini2') flux_scale = kwargs.get('flux_scale', 0.8) data = kwargs.get('data', None) # for continuum correction and resampling output_stellar_model = kwargs.get('output_stellar_model', False) if data is not None and instrument == 'nirspec': order = data.order # read in a model #print('teff ',teff,'logg ',logg, 'z', z, 'order', order, 'modelset', modelset) #print('teff ',type(teff),'logg ',type(logg), 'z', type(z), 'order', type(order), 'modelset', type(modelset)) model = smart.Model(teff=teff, logg=logg, metal=metal, order=str(order), modelset=modelset, instrument=instrument) #elif data is not None and instrument == 'apogee': elif instrument == 'apogee': model = smart.Model(teff=teff, logg=logg, metal=metal, modelset=modelset, instrument=instrument) # Dirty fix here model.wave = model.wave[np.where(model.flux != 0)] model.flux = model.flux[np.where(model.flux != 0)] # apply vmicro vmicro = 2.478 - 0.325 * logg model.flux = smart.broaden(wave=model.wave, flux=model.flux, vbroad=vmicro, rotate=False, gaussian=True) elif data is None and instrument == 'nirspec': model = smart.Model(teff=teff, logg=logg, metal=metal, order=str(order), modelset=modelset, instrument=instrument) # wavelength offset #model.wave += wave_offset # apply vsini model.flux = smart.broaden(wave=model.wave, flux=model.flux, vbroad=vsini, rotate=True, gaussian=False) # apply rv (including the barycentric correction) model.wave = rvShift(model.wave, rv=rv) # flux veiling model.flux += veiling ## if binary is True: make a binary model if binary: model2 = smart.Model(teff=teff2, logg=logg2, metal=metal, order=str(order), modelset=modelset, instrument=instrument) # apply vsini model2.flux = smart.broaden(wave=model2.wave, flux=model2.flux, vbroad=vsini2, rotate=True, gaussian=False) # apply rv (including the barycentric correction) model2.wave = rvShift(model2.wave, rv=rv2) # linearly interpolate the model2 onto the model1 grid fit = interp1d(model2.wave, model2.flux) select_wavelength = np.where((model.wave < model2.wave[-1]) & (model.wave > model2.wave[0])) model.flux = model.flux[select_wavelength] model.wave = model.wave[select_wavelength] # combine the models together and scale the secondary flux model.flux += flux_scale * fit(model.wave) if output_stellar_model: stellar_model = copy.deepcopy(model) if binary: model2.flux = flux_scale * fit(model.wave) # apply telluric if tell is True: model = smart.applyTelluric(model=model, tell_alpha=tell_alpha, airmass=airmass, pwv=pwv) # instrumental LSF if instrument == 'nirspec': model.flux = smart.broaden(wave=model.wave, flux=model.flux, vbroad=lsf, rotate=False, gaussian=True) elif instrument == 'apogee': model.flux = ap.apogee_hack.spec.lsf.convolve(model.wave, model.flux, lsf=lsf, xlsf=xlsf).flatten() model.wave = ap.apogee_hack.spec.lsf.apStarWavegrid() # Remove the NANs model.wave = model.wave[~np.isnan(model.flux)] model.flux = model.flux[~np.isnan(model.flux)] if output_stellar_model: stellar_model.flux = smart.broaden(wave=stellar_model.wave, flux=stellar_model.flux, vbroad=lsf, rotate=False, gaussian=True) if binary: model2.flux = smart.broaden(wave=model2.wave, flux=model2.flux, vbroad=lsf, rotate=False, gaussian=True) # add a fringe pattern to the model #model.flux *= (1+amp*np.sin(freq*(model.wave-phase))) # wavelength offset model.wave += wave_offset if output_stellar_model: stellar_model.wave += wave_offset if binary: model2.wave = stellar_model.wave # integral resampling if data is not None: if instrument == 'nirspec': model.flux = np.array( smart.integralResample(xh=model.wave, yh=model.flux, xl=data.wave)) model.wave = data.wave if output_stellar_model: stellar_model.flux = np.array( smart.integralResample(xh=stellar_model.wave, yh=stellar_model.flux, xl=data.wave)) stellar_model.wave = data.wave if binary: model2.flux = np.array( smart.integralResample(xh=model2.wave, yh=model2.flux, xl=data.wave)) model2.wave = data.wave # contunuum correction if data.instrument == 'nirspec': niter = 5 # continuum iteration if output_stellar_model: model, cont_factor = smart.continuum(data=data, mdl=model, prop=True) for i in range(niter): model, cont_factor2 = smart.continuum(data=data, mdl=model, prop=True) cont_factor *= cont_factor2 stellar_model.flux *= cont_factor if binary: model2.flux *= cont_factor else: model = smart.continuum(data=data, mdl=model) for i in range(niter): model = smart.continuum(data=data, mdl=model) elif data.instrument == 'apogee': ## set the order in the continuum fit deg = 5 ## because of the APOGEE bands, continuum is corrected from three pieces of the spectra data0 = copy.deepcopy(data) model0 = copy.deepcopy(model) # wavelength offset model0.wave += wave_off1 range0 = np.where((data0.wave >= data.oriWave0[0][-1]) & (data0.wave <= data.oriWave0[0][0])) data0.wave = data0.wave[range0] data0.flux = data0.flux[range0] if data0.wave[0] > data0.wave[-1]: data0.wave = data0.wave[::-1] data0.flux = data0.flux[::-1] model0.flux = np.array( smart.integralResample(xh=model0.wave, yh=model0.flux, xl=data0.wave)) model0.wave = data0.wave model0 = smart.continuum(data=data0, mdl=model0, deg=deg) # flux corrections model0.flux = (model0.flux + c0_1) * np.e**(-c0_2) data1 = copy.deepcopy(data) model1 = copy.deepcopy(model) # wavelength offset model1.wave += wave_off2 range1 = np.where((data1.wave >= data.oriWave0[1][-1]) & (data1.wave <= data.oriWave0[1][0])) data1.wave = data1.wave[range1] data1.flux = data1.flux[range1] if data1.wave[0] > data1.wave[-1]: data1.wave = data1.wave[::-1] data1.flux = data1.flux[::-1] model1.flux = np.array( smart.integralResample(xh=model1.wave, yh=model1.flux, xl=data1.wave)) model1.wave = data1.wave model1 = smart.continuum(data=data1, mdl=model1, deg=deg) # flux corrections model1.flux = (model1.flux + c1_1) * np.e**(-c1_2) data2 = copy.deepcopy(data) model2 = copy.deepcopy(model) # wavelength offset model2.wave += wave_off3 range2 = np.where((data2.wave >= data.oriWave0[2][-1]) & (data2.wave <= data.oriWave0[2][0])) data2.wave = data2.wave[range2] data2.flux = data2.flux[range2] if data2.wave[0] > data2.wave[-1]: data2.wave = data2.wave[::-1] data2.flux = data2.flux[::-1] model2.flux = np.array( smart.integralResample(xh=model2.wave, yh=model2.flux, xl=data2.wave)) model2.wave = data2.wave model2 = smart.continuum(data=data2, mdl=model2, deg=deg) # flux corrections model2.flux = (model2.flux + c2_1) * np.e**(-c2_2) ## scale the flux to be the same as the data #model0.flux *= (np.std(data0.flux)/np.std(model0.flux)) #model0.flux -= np.median(model0.flux) - np.median(data0.flux) #model1.flux *= (np.std(data1.flux)/np.std(model1.flux)) #model1.flux -= np.median(model1.flux) - np.median(data1.flux) #model2.flux *= (np.std(data2.flux)/np.std(model2.flux)) #model2.flux -= np.median(model2.flux) - np.median(data2.flux) model.flux = np.array( list(model2.flux) + list(model1.flux) + list(model0.flux)) model.wave = np.array( list(model2.wave) + list(model1.wave) + list(model0.wave)) if instrument == 'nirspec': # flux offset model.flux += flux_offset if output_stellar_model: stellar_model.flux += flux_offset if binary: model2.flux += flux_offset #model.flux **= (1 + flux_exponent_offset) if output_stellar_model: if not binary: return model, stellar_model else: return model, stellar_model, model2 else: return model
fig = corner.corner( triangle_samples, labels=ylabels, truths=[lsf_mcmc[0], airmass_mcmc[0], pwv_mcmc[0], A_mcmc[0], B_mcmc[0]], quantiles=[0.16, 0.84], label_kwargs={"fontsize": 20}) plt.minorticks_on() fig.savefig(save_to_path + '/triangle.png', dpi=300, bbox_inches='tight') #plt.show() plt.close() data2 = copy.deepcopy(data) data2.wave = data2.wave + B_mcmc[0] telluric_model = tellurics.convolveTelluric(lsf_mcmc[0], airmass_mcmc[0], pwv_mcmc[0], data) model, pcont = smart.continuum(data=data, mdl=telluric_model, deg=2, tell=True) model.flux += A_mcmc[0] plt.tick_params(labelsize=20) fig = plt.figure(figsize=(20, 8)) ax1 = fig.add_subplot(111) ax1.plot(model.wave, model.flux, c='C3', ls='-', alpha=0.5) ax1.plot(model.wave, np.polyval(pcont, model.wave) + A_mcmc[0], c='C1', ls='-', alpha=0.5) ax1.plot(data.wave, data.flux, 'k-', alpha=0.5) ax1.plot(data.wave, data.flux - (model.flux + A_mcmc[0]), 'k-', alpha=0.5) ax1.minorticks_on() plt.figtext(0.89,