def sanity_tests(self): """ Checking sanity of 'instrBroadGaussFast' """ from PyAstronomy import pyasl import numpy as np # Set up an input spectrum x = np.linspace(5000.0,5100.0,1000) y = np.zeros(x.size) # Introduce some delta-peaked lines y[165] = 0.7 y[187] = 0.3 y[505] = 0.1 y[610] = 0.1 y[615] = 0.7 # Apply Gaussian instrumental broadening. resolution = 12700. r, fwhm = pyasl.instrBroadGaussFast(x, y, resolution, edgeHandling=None, fullout=True) self.assertAlmostEqual(fwhm, np.mean(x)/resolution, 6, "FWHM does not match") s1 = y.sum() s2 = r.sum() self.assertAlmostEqual(s1, s2, 6, "EW in spectrum did change")
def instrumental_profile(x, y, resolution): ''' Inputs ----- x, y : The abscissa and ordinate of the data. sigma : The width (i.e., standard deviation) of the Gaussian profile used in the convolution. edgeHandling : None, "firstlast". Determines the way edges will be handled. If None, nothing will be done about it. If set to "firstlast", the spectrum will be extended by using the first and last value at the start or end. Note that this is not necessarily appropriate. The default is None. maxsig : The extent of the broadening kernel in terms of standrad deviations. By default, the Gaussian broadening kernel will be extended over the entire given spectrum, which can cause slow evaluation in the case of large spectra. A reasonable choice could, e.g., be five. Output ----- y_inst : convolved flux ''' # Deal with zero or None values seperately if (resolution is None) or (resolution == 0): y_inst = y else: y_inst = pyasl.instrBroadGaussFast(x, y, resolution, edgeHandling="firstlast", fullout=False, maxsig=None) return y_inst
def main(): # Read in the needed values from the command line arguments = parseArguments() # Read in the spectrum try: wlc, flux = np.loadtxt(arguments.fileName, unpack=True, skiprows=1) except IOError: print("Input spectrum " + arguments.fileName + " not found!") exit() # Resample the input spectrum to even wavelength bins of <binSize> Angstrom newWlc = np.arange(wlc[0] + binSize, wlc[-1] - binSize, binSize) flux = np.interp(newWlc, wlc, flux) wlc = newWlc # Apply instrumental broadening flux = instrBroadGaussFast(wlc, flux, arguments.res, maxsig=5.0, edgeHandling="firstlast") # Apply rotational broadening flux = rotBroad(wlc, flux, limbDark, arguments.vrot) # Apply macroturbulent broadening if arguments.vmacro != -1: flux = macroBroad(wlc, flux, arguments.vmacro) # Resample to <finalBins> Angstrom if finalBins != binSize: newWlc = np.arange(wlc[0] + finalBins, wlc[-1] - finalBins, finalBins) flux = np.interp(newWlc, wlc, flux) # Write output file out_f = open(arguments.fileName + ".fin", 'w') out_f.write("#" + str(len(wlc)) + "\t" + "#0 \n") for i in range(len(wlc) - 1): out_f.write(str(wlc[i]) + "\t" + str(flux[i]) + "\n") out_f.close() exit()
def sanity_example(self): """ Checking sanity of 'instrBroadGaussFast' example. """ from PyAstronomy import pyasl import matplotlib.pylab as plt import numpy as np # Set up an input spectrum x = np.linspace(5000.0,5100.0,1000) y = np.ones(x.size) # Introduce some delta-peaked lines y[165] = 0.7 y[187] = 0.3 y[505] = 0.1 y[610] = 0.1 y[615] = 0.7 # Apply Gaussian instrumental broadening, setting the resolution to 10000. r, fwhm = pyasl.instrBroadGaussFast(x, y, 10000, edgeHandling="firstlast", fullout=True) print "FWHM used for the Gaussian kernel: ", fwhm, " A" # Plot the output plt.plot(x,r, 'r--p') plt.plot(x,y, 'b-')
def broaden(even_wl, modelspec_interp, res, vsini=0, limb=0, plot=False): """Adds resolution, vsin(i) broadening, taking into account limb darkening. Args: even_wl (list): evenly spaced model wavelength vector modelspec_interp (list): model spectrum vector res (float): desired spectral resolution vsini (float): star vsin(i) limb (float): the limb darkening coeffecient plot (boolean): if True, plots the full input spectrum and the broadened output. Defaults to False. Returns: a tuple containing an evenly spaced wavelength vector spanning the width of the original wavelength range, and a corresponding flux vector """ #regrid by finding the smallest wavelength step mindiff = np.inf for n in range(1, len(even_wl)): if even_wl[n] - even_wl[n - 1] < mindiff: mindiff = even_wl[n] - even_wl[n - 1] #interpolate the input values it = interp1d(even_wl, modelspec_interp) #make a new wavelength array that's evenly spaced with the smallest wavelength spacing in the input wl array w = np.arange(min(even_wl), max(even_wl), mindiff) sp = it(w) #do the instrumental broadening and truncate the ends because they get messy broad = pyasl.instrBroadGaussFast(w, sp, res, maxsig=5) broad[0:5] = broad[5] broad[len(broad) - 10:len(broad)] = broad[len(broad) - 11] #if I want to impose stellar parameters of v sin(i) and limb darkening, do that here if vsini != 0 and limb != 0: rot = pyasl.rotBroad(w, broad, limb, vsini) #, edgeHandling='firstlast') #otherwise just move on else: rot = broad #Make a plotting option just in case I want to double check that this is doing what it's supposed to if plot == True: plt.figure() plt.plot(w, sp, label='model') plt.plot(w, broad, label='broadened') plt.plot(w, rot, label='rotation') plt.legend(loc='best') plt.xlabel('wavelength (angstroms)') plt.ylabel('normalized flux') plt.savefig('rotation.pdf') #return the wavelength array and the broadened flux array return w, rot
def convolve_data(fname, R_conv, resonumber): flux = fits.getdata(fname) hdr = fits.getheader(fname) w0, dw, N = hdr['CRVAL1'], hdr['CDELT1'], hdr['NAXIS1'] wavelength = w0 + dw * np.arange(N) newflux = pyasl.instrBroadGaussFast(wavelength, flux, R_conv, edgeHandling="firstlast", fullout=False, maxsig=None) fits.writeto(fname.replace('.fits', '')+'conv'+resonumber+'.fits', newflux, hdr, overwrite=True)
def GaussianBroadening(self, **kwargs): ''' This function broadens the spectrum using a given Gaussian kernel. :param: resolution - float, The spectral resolution. ''' resolution = kwargs["resolution"] if 'wv' and 'sp' in kwargs: flux = pyasl.instrBroadGaussFast( np.reshape(kwargs["wv"][0], (1, -1))[0], kwargs["sp"][0], resolution) else: flux = pyasl.instrBroadGaussFast( np.reshape(self.model.wv[0], (1, -1))[0], self.model.sp[0], resolution) flux = np.reshape(flux, (1, -1)) self.model.sp = flux return flux
def sanity_instrumentalResolution(self): """ Checking integrity of instrumental resolution in VoigtAstroP """ import numpy as np from PyAstronomy import modelSuite as ms from PyAstronomy import pyasl v = ms.VoigtAstroP() w0 = 10830 for R in [2500, 5000, 80000]: v["w0"] = w0 v["b"] = 10. v["gamma"] = 1e-8 v["f"] = 100.0 v["R"] = 0 dw = 40.0 w = np.linspace(w0 - dw, w0 + dw, 4000) m = v.evaluate(w) v["R"] = R m2 = v.evaluate(w) fb = pyasl.instrBroadGaussFast(w, m, R, edgeHandling=None, fullout=False, maxsig=None) d = 1000 self.assertAlmostEqual( np.max(np.abs(fb[d:-d] - m2[d:-d]) / m2[d:-d]), 0.0, delta=1e-10, msg="VoigtAstroP instrumental broadening broken for R = " + str(R))
def broaden(even_wl, modelspec_interp, res, vsini, limb, plot=False): """Adds resolution, vsin(i) broadening, taking into account limb darkening. Args: even_wl (list): evenly spaced model wavelength vector modelspec_interp (list): model spectrum vector res (float): desired spectral resolution vsini (float): star vsin(i) limb (float): the limb darkening coeffecient plot (boolean): if True, plots the full input spectrum and the broadened output. Defaults to False. Returns: a tuple containing an evenly spaced wavelength vector spanning the width of the original wavelength range, and a corresponding flux vector """ #sig = np.mean(even_wl)/res broad = pyasl.instrBroadGaussFast(even_wl, modelspec_interp, res, maxsig=5) if vsini != 0 and limb != 0: rot = pyasl.rotBroad(even_wl, broad, limb, vsini) #, edgeHandling='firstlast') else: rot = broad #modelspec_interp = [(modelspec_interp[n] / max(modelspec_interp)) for n in range(len(modelspec_interp))] #broad = [broad[n]/max(broad) for n in range(len(broad))] #rot = [(rot[n]/max(rot)) for n in range(len(rot))] if plot == True: plt.figure() plt.plot(even_wl, modelspec_interp, label='model') plt.plot(even_wl, broad, label='broadened') plt.plot(even_wl, rot, label='rotation') plt.legend(loc='best') plt.xlabel('wavelength (angstroms)') plt.ylabel('normalized flux') plt.savefig('rotation.pdf') return even_wl, rot
dz = np.diff(zlist) zdeltaz = dz * (zcent + R0) Rplam2 = np.square(R0) + 2.0 * (1.0 - np.exp(-tautilde)).transpose().dot(zdeltaz) Rscgs2 = np.square(Rs * const.R_sun.to(u.m).value) trspec = 1.0 - Rplam2 / Rscgs2 trspecall.append(trspec) wvlair = vac2air(wvl_) flux = trspec stepsize = 0.015 wvlair_hires = np.arange(wvlair[0], wvlair[-1], stepsize) tck = interpolate.splrep(wvlair, flux) flx = interpolate.splev(wvlair_hires, tck, der=0) rflx_hds = pyasl.instrBroadGaussFast(wvlair_hires, flx, 115000, edgeHandling="firstlast") h5f_spec.create_dataset("spec_" + str(name[i]), data=rflx_hds, compression="gzip", compression_opts=9) h5f_spec.create_dataset("wavelength", data=wvlair_hires, compression="gzip", compression_opts=9) h5f_spec.close() h5f_cc.close()
xs = np.loadtxt('kurucz.list', unpack=True, dtype=str) name = [] for i in range(len(xs)): name.append(xs[i][18:-4]) h5f_harps = h5py.File('kelt20b-iso-2500K-trans-kurucz-nohmin.h5', 'r') h5f_carm = h5py.File('kelt20b-iso-2500K-trans-kurucz-nohmin-carmenes.h5', 'w') wvharsp = h5f_harps["wavelength"][:] for i in tqdm(range(len(name))): spec = h5f_harps["spec_" + str(name[i])][:] rflx_hds = pyasl.instrBroadGaussFast(wvharsp, spec, 94600, edgeHandling="firstlast") h5f_carm.create_dataset("spec_" + str(name[i]), data=rflx_hds, compression="gzip", compression_opts=9) h5f_carm.create_dataset("wavelength", data=wvlair_hires, compression="gzip", compression_opts=9) h5f_carm.close() h5f_harps.close()
if __name__ == '__main__': resolution = 100000 w0, w1 = 10060, 23310 wpath = os.path.expanduser( '~/.plotfits/WAVE_PHOENIX-ACES-AGSS-COND-2011.fits') w = get_wavelength(wpath) idx = (w0 <= w) & (w <= w1) w = w[idx] for fname in sorted(glob('lte*.fits'))[3:]: fout = params_to_name(fname, resolution) print fout y = fits.getdata(fname) y = y[idx] w_new, y_new = same_w_grid(w, y) print 'Convolving...' y_new = pyasl.instrBroadGaussFast(w_new, y_new, resolution, edgeHandling="firstlast", fullout=False, maxsig=None) crval1, cdelt1, naxis1 = header_information(w_new) hdr = fits.Header() hdr["NAXIS1"] = naxis1 hdr["CDELT1"] = cdelt1 hdr["CRVAL1"] = crval1 fits.writeto(fout, y_new, hdr, overwrite=True)
def make_simulation(template_data, uservals, detectorconfig, telescopeconfig,instrumentconfig):#template_data,resolution,wlr,t_aperture,sky_aperture,template_wl_norm,ab,airmass,npix,Instrument,aper_sampl,dit,eff_opt,seeing,atm_dif_ref): #################################################################### #Set dispersion axis cen_wav=(instrumentconfig['wlr'][1]+instrumentconfig['wlr'][0])/2.0*1.0e3 wav_range_length=(instrumentconfig['wlr'][1]-instrumentconfig['wlr'][0])*1.0e3 pix_arr=np.arange(0,detectorconfig['npix'],1) outputwl = instrumentconfig['wlr'][0]*1.0e4+pix_arr*detectorconfig['disp'] #FWHM for kernel fwhm_kernel=np.sqrt((cen_wav/instrumentconfig['resolution'])**2-(cen_wav/template_data['respow'])**2) respow_kernel=cen_wav/fwhm_kernel #################################################################### #################################################################### #obtain Sky spectrum from template (either provided or ESO sky_calc) oh_f=get_sky_model(uservals['sky_template'], uservals['airmass_fl']) rdwl=oh_f['rdwl'] rwl0=oh_f['rwl0'] # wavelength of sky model in Angstroms rfn0=oh_f['rfn0']*math.pi*(telescopeconfig['t_aperture']*1.e2/2.0)**2*rdwl #Photons/s/arcsec2 per pixel of the OH grid atmtr0=oh_f['atmtr'] # atmospheric transmission atmwl0=oh_f['atmwl'] tol = (instrumentconfig['wlr'][1]-instrumentconfig['wlr'][0])*0.05 min_wl=(instrumentconfig['wlr'][0]-tol)*1.0e4 max_wl=(instrumentconfig['wlr'][1]+tol)*1.0e4 iok_sky = np.where((rwl0 > min_wl) & (rwl0 < max_wl))[0] iok_atm = np.where((atmwl0 > min_wl) & (atmwl0 < max_wl))[0] rfn = rfn0[iok_sky] # flux of OH spectrum rwl = rwl0[iok_sky] # wave of OH spectrum atmwl=atmwl0[iok_atm] atmtr=atmtr0[iok_atm] rfn_sky = (rfn)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2 # Photons/s/pix of the OH spectrum ALONE #################################################################### #################################################################### #Prepare the input template fl_tpl_in=template_data['flux'] wl_tpl_in=template_data['wave'] setup_range_tpl=np.where((wl_tpl_in>min_wl) & (wl_tpl_in<max_wl))[0] fl_tpl=fl_tpl_in[setup_range_tpl] wl_tpl=wl_tpl_in[setup_range_tpl] # normalising the template source spectrum to the magnitude i = np.where(wl_tpl >= instrumentconfig['template_wl_norm']*1.0e4)[0] templ_fl_ref = fl_tpl[i[0]] fl_tpl_normalized_to_one = fl_tpl/templ_fl_ref # template photon flux per A in cgs assuming a telescope effective diameter templ_phot_fl = fl_tpl_normalized_to_one*3.63e3*10.0**(-(uservals['ab']+57.5)/2.5)*math.pi*(telescopeconfig['t_aperture']*1.0e2/2.0)**2/(wl_tpl*6.626e-27) # template photon flux per PER SPECTRAL PIXEL OF THE TEMPLATE templ_phot_fl_pix = templ_phot_fl*template_data['cdelt']#*rdwl npix_y=detectorconfig['ypix_fwhm']*2.0 #################################################################### #################################################################### # Modelling Fibre Injection #Obtain Image Quality in corresponding band from seeing provided (seeing defined in zenith at 500nm) fwhm_iq=seeing_to_ImageQ(uservals['seeing'],cen_wav,uservals['airmass_fl']) uservals['seeing']=fwhm_iq fib_frac=1.0 # allowing for tuning of fraction loss manually, keep as 1.0 for no additional loss #Calculate atmospheric difraction effect Lambda=np.arange(0.5,1.9,0.1) atm_diff=get_diffraction(Lambda, uservals['airmass_fl'], uservals['atm_dif_ref']) atm_diff_oh=np.interp(wl_tpl,Lambda*1.0e4,atm_diff) seeing_arr=np.sqrt(uservals['seeing']**2+atm_diff_oh**2) #Co-added effect of seeing and atm_diff offset. seeing_cor_flux= (1.0-1.0/np.exp( (np.sqrt(math.log(2.0)) * instrumentconfig['sky_aperture']/seeing_arr)**2))*templ_phot_fl_pix sp_conv_src = fib_frac*seeing_cor_flux sp_conv_sky=rfn_sky #################################################################### #resampling to detector pixels, conserving total flux #transmission: atminterp_res, fwhm = pyasl.instrBroadGaussFast(atmwl, atmtr, respow_kernel,edgeHandling="firstlast", fullout=True) atminterp = np.interp(outputwl,atmwl,atminterp_res)# resample atmospheric transmission to detector pixels # #source: sp_conv_src_res, fwhm = pyasl.instrBroadGaussFast(wl_tpl, sp_conv_src, respow_kernel ,edgeHandling="firstlast", fullout=True) sp_det_src = np.interp(outputwl,wl_tpl,sp_conv_src_res) inband = np.where((wl_tpl >= outputwl[0]) & (wl_tpl <= outputwl[detectorconfig['npix']-1]))[0] sp_conv_src_sum=sp_conv_src_res[inband].sum() sp_det_src_sum=sp_det_src.sum() renorm=sp_conv_src_sum/sp_det_src_sum sp_det_src_rn = sp_det_src*renorm if (uservals['set_line_profile']=='YES'): line_profile_file='IP_HIRES_m68_wave17834.1A.txt' print(' ') print('Applying line profile convolution') print('Extracting line profile from file: ',line_profile_file) sp_det_src_rn=get_line_profile(line_profile_file,outputwl,sp_det_src_rn,detectorconfig['disp']) else: print('No LSF provided, adopting Gaussian kernel convolution') print(' ') # #sky emission: sp_conv_sky_res, fwhm = pyasl.instrBroadGaussFast(rwl, sp_conv_sky, respow_kernel,edgeHandling="firstlast", fullout=True) sp_det_sky = np.interp(outputwl,rwl,sp_conv_sky_res) inband = np.where((rwl >= outputwl[0]) & (rwl <= outputwl[detectorconfig['npix']-1]))[0] sp_conv_sky_sum=sp_conv_sky_res[inband].sum() sp_det_sky_sum=sp_det_sky.sum() renorm_sky=sp_conv_sky_sum/sp_det_sky_sum sp_det_sky_rn = sp_det_sky*renorm_sky # for sky only if (uservals['set_line_profile']=='YES'): line_profile_file='IP_HIRES_m68_wave17834.1A.txt' sp_det_sky_rn=get_line_profile(line_profile_file,outputwl,sp_det_sky_rn,detectorconfig['disp']) #################################################################### #################################################################### #Modelling overall efficiency (not currently enabled!) eff=get_efficiency(outputwl,min_wl,max_wl) #Calculate telescope and instrument emissivity (not critical for H band) ThBK=283.00 EBK=0.00 #36.0*selector #selector matching temperature of the telescope ThBK_ins=283.00 EBK_ins=0.10 #36.0*selector #selector matching temperature of the telescope t_em=1.4*10.0**12*EBK*np.exp(-14388.0/(outputwl/1.0e4*ThBK))/((outputwl/1.0e4)**3/instrumentconfig['resolution'])*detectorconfig['disp'] ins_em=1.4*10.0**12*EBK_ins*np.exp(-14388.0/(outputwl/1.0e4*ThBK_ins))/((outputwl/1.0e4)**3/instrumentconfig['resolution'])*detectorconfig['disp'] NBK_tel=(t_em)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2 NBK_ins=(ins_em)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2 NBK=NBK_tel+NBK_ins #print("Thermal background emissivity Telescope [e-/s]: ",str(round(np.max(NBK_tel*eff),3))) #print("Thermal background emissivity Instrument [e-/s]: ",str(round(np.max(NBK_ins*eff),3))) #sp_det_sky_rn=sp_det_sky_rn+NBK commented out for the moment. #################################################################### #Modelling detector influx sp_det = sp_det_src_rn+sp_det_sky_rn # total detector flux from both sky and source sp_eff=sp_det*eff*atminterp sp_eff_src = sp_det_src_rn*eff*atminterp sp_eff_sky = sp_det_sky_rn*eff*atminterp # number of pixels COLLAPSED ALONG Y DIRECTION for MOS #sp_dk = sp_eff+DKsec*npix_y # from total insident flux # sp_dk_sky = sp_eff_sky+DKsec*npix_y #from only sky # scale by integration time spec_total = sp_eff*uservals['dit'] spec_2d_peak_intensity=get_PeakIntensity(spec_total,npix_y,instrumentconfig['DKsec']*uservals['dit']) # the following is for the sky only spec_sky = sp_eff_sky*uservals['dit'] # the following is for the source alone spec_source = sp_eff_src*uservals['dit'] #calculate total noise ##################################################### # Add stray light contribution stray=1.0 # 1% difusse stray light contribution as per latest optical modelling total_stray=spec_sky.sum()*uservals['N_dit']*500.0/detectorconfig['npix']**2 spec_stray=total_stray*float(stray)/100.0*npix_y #detector NOISE: noisedet=np.sqrt(npix_y*(uservals['N_dit']*instrumentconfig['RON']**2+instrumentconfig['DKsec']*uservals['dit']*uservals['N_dit'])) #background NOISE (including stray): noiseback=np.sqrt(spec_sky*uservals['N_dit']+spec_stray) #Add residual sky subtraction (optional, if you want then change skyres to percentage): if ((uservals['sky_residual'] >= 0) & (uservals['sky_residual'] <= 100)): skyres=uservals['sky_residual'] else: if (uservals['sky_residual'] == -1): print('Simulation with sky-subtraction OFF') print(' ') skyres=0 else: print(' Not a valid sky residual value (0-100). Adopting 0.00 percent') print(' ') skyres=0 noiseskyres=float(skyres)/100.0*spec_sky #total NOISE: comment out when necessary noisetot=np.sqrt(noiseback**2+noisedet**2+spec_source*uservals['N_dit']) #noise_sim_withsky=np.sqrt(noiseback**2+noisedet**2+spec_source*uservals['N_dit']) outnoise=noisetot+noiseskyres #outnoise = np.sqrt(outspec+outspec_sky+RON**2*npix_y*2.) sn_cont_all = spec_source/outnoise*uservals['N_dit'] sn_cont = np.median(sn_cont_all) cent_range=np.where((outputwl >= (cen_wav-wav_range_length*0.1)*10.0) & (outputwl <= (cen_wav+wav_range_length*0.1)*10.0))[0] sn_central=sn_cont_all[cent_range].max() print("**** S/N at central wavelength = %.2f ****"%sn_central) print(" ") count_level=spec_2d_peak_intensity*instrumentconfig['gain'] saturated=get_saturation(count_level,instrumentconfig['saturation_level']) if saturated: print('WARNING!!! Counts above saturation/linearity regime!!!') #Get figure with summary of results #SNR figure f=plt.figure(figsize=(10,8),dpi=100) ax1=f.add_subplot(221) ax1.plot(outputwl/1.0e4, sn_cont_all,label='SNR per pixel') ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], sn_cont_all.min(), sn_cont_all.max()]) ax1.set_xlabel('Wavelength [um]') ax1.set_ylabel('SNR (/pix)') plt.legend(loc='upper right',prop={'size':8}, numpoints=1) #Sky spectrum ax1=f.add_subplot(222) ax1.plot(outputwl/1.0e4, spec_2d_peak_intensity,label='Peak Intensity') ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], spec_2d_peak_intensity.min(), spec_2d_peak_intensity.max()]) if saturated: ax1.plot(outputwl/1.0e4,spec_2d_peak_intensity*0.0+instrumentconfig['saturation_level']/instrumentconfig['gain'],color='red',label='Saturation') plt.legend(loc='upper right',prop={'size':8}, numpoints=1) ax1.set_xlabel('Wavelength [um]') ax1.set_ylabel('Counts (e-)') #atmospheric transmission ax1=f.add_subplot(223) ax1.plot(outputwl/1.0e4, atminterp,label='Atmospheric transmission') ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], atminterp.min(), atminterp.max()]) ax1.set_xlabel('Wavelength [um]') ax1.set_ylabel('Transmission fraction') plt.legend(loc='lower left',prop={'size':8}, numpoints=1) #Simulated spectrum ax1=f.add_subplot(224) normnoise=np.random.random((detectorconfig['npix']))*2.0-1.0 res_noise=normnoise*outnoise nores_noise=normnoise*noisetot sim_spectrum={} if uservals['sky_residual']==-1: sim_spectrum['flux']=spec_total*uservals['N_dit']+nores_noise else: sim_spectrum['flux']=spec_source*uservals['N_dit']+res_noise if uservals['telluric']==1: print('Telluric correction applied (idealistic)') print(' ') sim_spectrum['flux']=sim_spectrum['flux']/atminterp else: sim_spectrum['flux']=sim_spectrum['flux'] sim_spectrum['wave']=outputwl sim_spectrum['cdelt']=detectorconfig['disp'] sim_spectrum['crval']=outputwl[0] ax1.plot(outputwl/1.0e4, sim_spectrum['flux'],label='Sim spectrum') ax1.plot(outputwl/1.0e4, spec_source*uservals['N_dit'],label='Object (no noise)',alpha=0.6) ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], sim_spectrum['flux'].min(), sim_spectrum['flux'].max()]) ax1.set_xlabel('Wavelength [um]') ax1.set_ylabel('Counts (e-)') plt.legend(loc='upper right',prop={'size':8}, numpoints=1) plt.tight_layout() f.savefig("SIM_results.pdf", bbox_inches='tight') plt.close() return sim_spectrum
def main(fname, lines=False, linelist=False, model=False, telluric=False, sun=False, rv=False, rv1=False, rv2=False, ccf='none', ftype='1D', fitsext='0', order='77', convert=False, resolution=False, nolines=False): """Plot a fits file with extensive options :fname: Input spectra :lines: Absorption lines :linelist: A file with the lines :model: Model spectrum :telluric: Telluric spectrum :sun: Solar spectrum :rv: RV of input spectrum :rv1: RV of Solar/model spectrum :rv2: RV of telluric spectrum :ccf: Calculate CCF (sun, model, telluric, both) :ftype: Type of fits file (1D, CRIRES, GIANO) :fitsext: Slecet fits extention to use (0,1,2,3,4) :returns: RV if CCF have been calculated """ print('\n-----------------------------------') path = os.path.expanduser('~/.plotfits/') pathsun = os.path.join(path, 'solarspectrum_01.fits') pathtel = os.path.join(path, 'telluric_NIR.fits') pathwave = os.path.join(path, 'WAVE_PHOENIX-ACES-AGSS-COND-2011.fits') pathGIANO = os.path.join(path, 'wavelength_GIANO.dat') if not os.path.isdir(path): os.mkdir(path) print('Created: %s' % path) if sun and (not os.path.isfile(pathsun)): print('Downloading solar spectrum...') _download_spec(pathsun) if telluric and (not os.path.isfile(pathtel)): print('Downloading telluric spectrum...') _download_spec(pathtel) if model and (not os.path.isfile(pathwave)): print('Downloading wavelength vector for model...') import urllib url = 'ftp://phoenix.astro.physik.uni-goettingen.de/HiResFITS//WAVE_PHOENIX-ACES-AGSS-COND-2011.fits' urllib.urlretrieve(url, pathwave) fitsext = int(fitsext) order = int(order) if ftype == '1D': I = fits.getdata(fname) hdr = fits.getheader(fname) w = get_wavelength(hdr, convert=convert) elif ftype == 'CRIRES': d = fits.getdata(fname, fitsext) hdr = fits.getheader(fname, fitsext) I = d['Extracted_OPT'] w = d['Wavelength']*10 elif ftype == 'GIANO': d = fits.getdata(fname) I = d[order - 32] # 32 is the first order wd = np.loadtxt(pathGIANO) w0, w1 = wd[wd[:, 0] == order][0][1:] w = np.linspace(w0, w1, len(I), endpoint=True) elif ftype == 'UVES': raise NotImplementedError('Please be patient. Not quite there yet') # d = fits.getdata(fname) # I = d[''] if np.median(I) != 0: I /= np.median(I) else: I /= I.max() # Normalization (use first 50 points below 1.2 as constant continuum) maxes = I[(I < 1.2)].argsort()[-50:][::-1] I /= np.median(I[maxes]) I[I<0] = 0 dw = 10 # Some extra coverage for RV shifts if rv: I, w = dopplerShift(wvl=w, flux=I, v=rv) w0, w1 = w[0] - dw, w[-1] + dw if sun and not model: I_sun = fits.getdata(pathsun) hdr = fits.getheader(pathsun) w_sun = get_wavelength(hdr) i = (w_sun > w0) & (w_sun < w1) w_sun = w_sun[i] I_sun = I_sun[i] if len(w_sun) > 0: I_sun /= np.median(I_sun) if ccf in ['sun', 'both'] and rv1: print('Warning: RV set for Sun. Calculate RV with CCF') if rv1 and ccf not in ['sun', 'both']: I_sun, w_sun = dopplerShift(wvl=w_sun, flux=I_sun, v=rv1) else: print('Warning: Solar spectrum not available in wavelength range.') sun = False elif sun and model: print('Warning: Both solar spectrum and a model spectrum are selected. Using model spectrum.') sun = False if model: I_mod = fits.getdata(model) hdr = fits.getheader(model) if 'WAVE' in hdr.keys(): w_mod = fits.getdata(pathwave) else: w_mod = get_wavelength(hdr) w_mod = vac2air(w_mod) # Correction for vacuum to air (ground based) i = (w_mod > w0) & (w_mod < w1) w_mod = w_mod[i] I_mod = I_mod[i] if len(w_mod) > 0: if resolution: I_mod = pyasl.instrBroadGaussFast(w_mod, I_mod, resolution, edgeHandling="firstlast", fullout=False, maxsig=None) # https://phoenix.ens-lyon.fr/Grids/FORMAT # I_mod = 10 ** (I_mod-8.0) I_mod /= np.median(I_mod) # Normalization (use first 50 points below 1.2 as continuum) maxes = I_mod[(I_mod < 1.2)].argsort()[-50:][::-1] I_mod /= np.median(I_mod[maxes]) if ccf in ['model', 'both'] and rv1: print('Warning: RV set for model. Calculate RV with CCF') if rv1 and ccf not in ['model', 'both']: I_mod, w_mod = dopplerShift(wvl=w_mod, flux=I_mod, v=rv1) else: print('Warning: Model spectrum not available in wavelength range.') model = False if telluric: I_tel = fits.getdata(pathtel) hdr = fits.getheader(pathtel) w_tel = get_wavelength(hdr) i = (w_tel > w0) & (w_tel < w1) w_tel = w_tel[i] I_tel = I_tel[i] if len(w_tel) > 0: I_tel /= np.median(I_tel) if ccf in ['telluric', 'both'] and rv2: print('Warning: RV set for telluric, Calculate RV with CCF') if rv2 and ccf not in ['telluric', 'both']: I_tel, w_tel = dopplerShift(wvl=w_tel, flux=I_tel, v=rv2) else: print('Warning: Telluric spectrum not available in wavelength range.') telluric = False rvs = {} if ccf != 'none': if ccf in ['sun', 'both'] and sun: # remove tellurics from the Solar spectrum if telluric and sun: print('Correcting solar spectrum for tellurics...') print('Calculating CCF for the Sun...') rv1, r_sun, c_sun, x_sun, y_sun = ccf_astro((w, -I + 1), (w_sun, -I_sun + 1)) if rv1 != 0: print('Shifting solar spectrum...') I_sun, w_sun = dopplerShift(w_sun, I_sun, v=rv1) rvs['sun'] = rv1 print('DONE\n') if ccf in ['model', 'both'] and model: print('Calculating CCF for the model...') rv1, r_mod, c_mod, x_mod, y_mod = ccf_astro((w, -I + 1), (w_mod, -I_mod + 1)) if rv1 != 0: print('Shifting model spectrum...') I_mod, w_mod = dopplerShift(w_mod, I_mod, v=rv1) rvs['model'] = rv1 print('DONE\n') if ccf in ['telluric', 'both'] and telluric: print('Calculating CCF for the model...') rv2, r_tel, c_tel, x_tel, y_tel = ccf_astro((w, -I + 1), (w_tel, -I_tel + 1)) if rv2 != 0: print('Shifting telluric spectrum...') I_tel, w_tel = dopplerShift(w_tel, I_tel, v=rv2) rvs['telluric'] = rv2 print('DONE\n') if len(rvs) == 0: ccf = 'none' if ccf != 'none': from matplotlib.gridspec import GridSpec fig = plt.figure(figsize=(16, 5)) gs = GridSpec(1, 5) if len(rvs) == 1: gs.update(wspace=0.25, hspace=0.35, left=0.05, right=0.99) ax1 = plt.subplot(gs[:, 0:-1]) ax2 = plt.subplot(gs[:, -1]) ax2.set_yticklabels([]) elif len(rvs) == 2: gs.update(wspace=0.25, hspace=0.35, left=0.01, right=0.99) ax1 = plt.subplot(gs[:, 1:4]) ax2 = plt.subplot(gs[:, 0]) ax3 = plt.subplot(gs[:, -1]) ax2.set_yticklabels([]) ax3.set_yticklabels([]) else: fig = plt.figure(figsize=(16, 5)) ax1 = fig.add_subplot(111) # Start in pan mode with these two lines # manager = plt.get_current_fig_manager() # manager.toolbar.pan() # Use nice numbers on x axis (y axis is normalized)... x_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False) ax1.xaxis.set_major_formatter(x_formatter) if sun and not model: ax1.plot(w_sun, I_sun, '-C2', lw=1, alpha=0.6, label='Sun') if telluric: ax1.plot(w_tel, I_tel, '-C3', lw=1, alpha=0.6, label='Telluric') if model: ax1.plot(w_mod, I_mod, '-C2', lw=1, alpha=0.6, label='Model') ax1.plot(w, I, '-k', lw=1, label='Star') # Add crosshair xlim = ax1.get_xlim() cursor = Cursor(ax1) plt.connect('motion_notify_event', cursor.mouse_move) ax1.set_xlim(xlim) if (linelist or lines) and lineidImport and not nolines: try: lines, elements = np.loadtxt(linelist, usecols=(0, 1), skiprows=1, unpack=True) idx = (lines <= max(w)) & (lines >= min(w)) lines = lines[idx] elements = elements[idx] Fe1Lines, Fe2Lines, otherLines = [], [], [] for line, element in zip(lines, elements): if np.allclose(element, 26.0): Fe1Lines.append('FeI: {}'.format(line)) elif np.allclose(element, 26.1): Fe2Lines.append('FeII: {}'.format(line)) else: otherLines.append('{}: {}'.format(element, line)) lines = lines*(1.0 + rv1 / 299792.458) if rv1 else lines*1 if len(Fe1Lines): lineid_plot.plot_line_ids(w, I, lines[elements==26.0], Fe1Lines, ax=ax1, add_label_to_artists=False) if len(Fe2Lines): pk = lineid_plot.initial_plot_kwargs() pk['color'] = 'red' lineid_plot.plot_line_ids(w, I, lines[elements==26.1], Fe2Lines, ax=ax1, add_label_to_artists=False, plot_kwargs=pk) except IOError: pass ax1.set_ylim(min(I)-0.05*min(I), 1.05*max(I)) ax1.set_xlabel('Wavelength') ax1.set_ylabel('"Normalized" flux') if len(rvs) == 1: if 'sun' in rvs.keys(): ax2.plot(r_sun, c_sun, '-k', alpha=0.9, lw=2) ax2.plot(x_sun, y_sun, '--C1', lw=2) ax2.set_title('CCF (sun)') if 'model' in rvs.keys(): ax2.plot(r_mod, c_mod, '-k', alpha=0.9, lw=2) ax2.plot(x_mod, y_mod, '--C1', lw=2) ax2.set_title('CCF (mod)') if 'telluric' in rvs.keys(): ax2.plot(r_tel, c_tel, '-k', alpha=0.9, lw=2) ax2.plot(x_tel, y_tel, '--C1', lw=2) ax2.set_title('CCF (tel)') ax2.set_xlabel('RV [km/s]') elif len(rvs) == 2: if 'sun' in rvs.keys(): ax2.plot(r_sun, c_sun, '-k', alpha=0.9, lw=2) ax2.plot(x_sun, y_sun, '--C1', lw=2) ax2.set_title('CCF (sun)') if 'model' in rvs.keys(): ax2.plot(r_mod, c_mod, '-k', alpha=0.9, lw=2) ax2.plot(x_mod, y_mod, '--C1', lw=2) ax2.set_title('CCF (mod)') ax3.plot(r_tel, c_tel, '-k', alpha=0.9, lw=2) ax3.plot(x_tel, y_tel, '--C1', lw=2) ax3.set_title('CCF (tel)') ax2.set_xlabel('RV [km/s]') ax3.set_xlabel('RV [km/s]') if rv: ax1.set_title('%s\nRV correction: %s km/s' % (fname, int(rv))) elif rv1 and rv2: ax1.set_title('%s\nSun/model: %s km/s, telluric: %s km/s' % (fname, int(rv1), int(rv2))) elif rv1 and not rv2: ax1.set_title('%s\nSun/model: %s km/s' % (fname, int(rv1))) elif not rv1 and rv2: ax1.set_title('%s\nTelluric: %s km/s' % (fname, int(rv2))) elif ccf == 'model': ax1.set_title('%s\nModel(CCF): %s km/s' % (fname, int(rv1))) elif ccf == 'sun': ax1.set_title('%s\nSun(CCF): %s km/s' % (fname, int(rv1))) elif ccf == 'telluric': ax1.set_title('%s\nTelluric(CCF): %s km/s' % (fname, int(rv2))) elif ccf == 'both': ax1.set_title('%s\nSun/model(CCF): %s km/s, telluric(CCF): %s km/s' % (fname, int(rv1), int(rv2))) else: ax1.set_title(fname) if sun or telluric or model: ax1.legend(loc=3, frameon=False) plt.show() return rvs