def read_spec(ispec): '''Parse spectrum out of the input Parameters: ----------- ispec: Spectrum1D, str, list of files (ordered blue to red), or tuple of arrays Returns: ----------- spec: XSpectrum1D spec_file: str ''' from specutils.spectrum1d import Spectrum1D from astropy.nddata import StdDevUncertainty from linetools.spectra import xspectrum1d as lsx from linetools.spectra import io as lsi from xastropy.stats import basic as xsb # if isinstance(ispec,basestring): spec_fil = ispec spec = lsx.XSpectrum1D.from_file(spec_fil) elif isinstance(ispec,Spectrum1D): spec = ispec spec_fil = spec.filename # Grab from Spectrum1D elif isinstance(ispec,tuple): spec = lsx.XSpectrum1D.from_tuple(ispec) spec_fil = 'none' elif isinstance(ispec,list): # Multiple file names # Loop on the files for kk,ispecf in enumerate(ispec): jspec = lsx.XSpectrum1D.from_file(ispecf) if kk == 0: spec = jspec xper1 = xsb.perc(spec.flux, per=0.9) else: # Scale flux for convenience of plotting (sig is not scaled) xper2 = xsb.perc(jspec.flux, per=0.9) scl = xper1[1]/xper2[1] # Splice spec = spec.splice(jspec,scale=scl) # Filename spec_fil = ispec[0] spec.filename=spec_fil else: raise ValueError('Bad input to read_spec') # Return return spec, spec_fil
def xq100_example(outfil='fig_xq100_example.pdf'): # Load spectrum spec_fil = os.getenv('DROPBOX_DIR') + '/XQ-100/data/J0030-5159_uvb.fits' spec = load_spectrum(spec_fil) # Start the plot if outfil is not None: pp = PdfPages(outfil) plt.figure(figsize=(8, 5)) plt.clf() gs = gridspec.GridSpec(1, 1) fsz = 17. # Read and plot full spectrum ax_full = plt.subplot(gs[0]) # Limits wvmnx = [3500., 7000.] gdpix = np.where(spec.dispersion < wvmnx[1] * u.AA)[0] perc = xsb.perc(spec.flux[gdpix]) ax_full.set_xlim(wvmnx) #ax_full.set_ylim(-0.05*perc[1], 1.1*perc[1]) ax_full.set_ylim(-1e-18, 7e-17) # Plot ax_full.plot(spec.dispersion, spec.flux, color='black', lw=1.0) ax_full.plot(wvmnx, [0., 0.], '--', color='green') # Label ax_full.set_xlabel('Wavelength') ax_full.set_ylabel('Relative Flux') ax_full.text(0.05, 0.9, 'XQ100 J0030-5159', transform=ax_full.transAxes, color='black', size='x-large', ha='left', va='center', bbox={'facecolor': 'white'}) # Font size xputils.set_fontsize(ax_full, fsz) # Finish page plt.tight_layout(pad=0.2, h_pad=0.3, w_pad=0.0) pp.savefig() plt.close() print('Wrote: {:s}'.format(outfil)) # Finish pp.close()
def desi_qso_templates(z_wind=0.2, zmnx=(0.4,4.), outfil=None, Ntempl=500, boss_pca_fil=None, wvmnx=(3500., 10000.), sdss_pca_fil=None, no_write=False): ''' Generate 9000 templates for DESI from z=0.4 to 4 Parameters ---------- z_wind: float (0.2) Window for sampling zmnx: tuple ( (0.5,4) ) Min/max for generation Ntempl: int (500) Number of draws per redshift window ''' # Cosmology from astropy import cosmology cosmo = cosmology.core.FlatLambdaCDM(70., 0.3) # PCA values if boss_pca_fil is None: boss_pca_fil = 'BOSS_DR10Lya_PCA_values_nocut.fits.gz' hdu = fits.open(boss_pca_fil) boss_pca_coeff = hdu[1].data if sdss_pca_fil is None: sdss_pca_fil = 'SDSS_DR7Lya_PCA_values_nocut.fits.gz' hdu2 = fits.open(sdss_pca_fil) sdss_pca_coeff = hdu2[1].data # Eigenvectors eigen, eigen_wave = fbq.read_qso_eigen() npix = len(eigen_wave) chkpix = np.where((eigen_wave > 900.) & (eigen_wave < 5000.) )[0] lambda_912 = 911.76 pix912 = np.argmin( np.abs(eigen_wave-lambda_912) ) # Open the BOSS catalog file boss_cat_fil = os.environ.get('BOSSPATH')+'/DR10/BOSSLyaDR10_cat_v2.1.fits.gz' bcat_hdu = fits.open(boss_cat_fil) t_boss = bcat_hdu[1].data boss_zQSO = t_boss['z_pipe'] # Open the SDSS catalog file sdss_cat_fil = os.environ.get('SDSSPATH')+'/DR7_QSO/dr7_qso.fits.gz' scat_hdu = fits.open(sdss_cat_fil) t_sdss = scat_hdu[1].data sdss_zQSO = t_sdss['z'] if len(sdss_pca_coeff) != len(sdss_zQSO): print('Need to finish running the SDSS models!') sdss_zQSO = sdss_zQSO[0:len(sdss_pca_coeff)] # Outfil if outfil is None: outfil = 'DESI_QSO_Templates_v1.1.fits' # Loop on redshift z0 = np.arange(zmnx[0],zmnx[1],z_wind) z1 = z0 + z_wind pca_list = ['PCA0', 'PCA1', 'PCA2', 'PCA3'] PCA_mean = np.zeros(4) PCA_sig = np.zeros(4) PCA_rand = np.zeros( (4,Ntempl*2) ) final_spec = np.zeros( (npix, Ntempl * len(z0)) ) final_wave = np.zeros( (npix, Ntempl * len(z0)) ) final_z = np.zeros( Ntempl * len(z0) ) seed = -1422 for ii in range(len(z0)): # BOSS or SDSS? if z0[ii] > 1.99: zQSO = boss_zQSO pca_coeff = boss_pca_coeff else: zQSO = sdss_zQSO pca_coeff = sdss_pca_coeff # Random z values and wavelengths zrand = np.random.uniform( z0[ii], z1[ii], Ntempl*2) wave = np.outer(eigen_wave, 1+zrand) # MFP (Worseck+14) mfp = 37. * ( (1+zrand)/5. )**(-5.4) # Physical Mpc # Grab PCA mean + sigma idx = np.where( (zQSO >= z0[ii]) & (zQSO < z1[ii]) )[0] print('Making z=({:g},{:g}) with {:d} input quasars'.format(z0[ii],z1[ii],len(idx))) # Get PCA stats and random values for ipca in pca_list: jj = pca_list.index(ipca) if jj == 0: # Use bounds for PCA0 [avoids negative values] xmnx = xstat_b.perc( pca_coeff[ipca][idx], per=0.95 ) PCA_rand[jj,:] = np.random.uniform( xmnx[0], xmnx[1], Ntempl*2) else: PCA_mean[jj] = np.mean(pca_coeff[ipca][idx]) PCA_sig[jj] = np.std(pca_coeff[ipca][idx]) # Draws PCA_rand[jj,:] = np.random.uniform( PCA_mean[jj] - 2*PCA_sig[jj], PCA_mean[jj] + 2*PCA_sig[jj], Ntempl*2) # Generate the templates (2*Ntempl) spec = np.dot(eigen.T,PCA_rand) # Take first good Ntempl # Truncate, MFP, Fill ngd = 0 for kk in range(2*Ntempl): # Any zero values? mn = np.min(spec[chkpix,kk]) if mn < 0.: continue # MFP if z0[ii] > 2.39: z912 = wave[0:pix912,kk]/lambda_912 - 1. phys_dist = np.fabs( cosmo.lookback_distance(z912) - cosmo.lookback_distance(zrand[kk]) ) # Mpc spec[0:pix912,kk] = spec[0:pix912,kk] * np.exp(-phys_dist.value/mfp[kk]) # Write final_spec[:, ii*Ntempl+ngd] = spec[:,kk] final_wave[:, ii*Ntempl+ngd] = wave[:,kk] final_z[ii*Ntempl+ngd] = zrand[kk] ngd += 1 if ngd == Ntempl: break if ngd != Ntempl: print('Did not make enough!') xdb.set_trace() if no_write is True: # Mainly for plotting return final_wave, final_spec, final_z # Rebin light = 2.99792458e5 # [km/s] velpixsize = 10. # [km/s] pixsize = velpixsize/light/np.log(10) # [pixel size in log-10 A] minwave = np.log10(wvmnx[0]) # minimum wavelength [log10-A] maxwave = np.log10(wvmnx[1]) # maximum wavelength [log10-A] r_npix = np.round((maxwave-minwave)/pixsize+1) log_wave = minwave+np.arange(r_npix)*pixsize # constant log-10 spacing totN = Ntempl * len(z0) rebin_spec = np.zeros((r_npix, totN)) from scipy.interpolate import interp1d for ii in range(totN): # Interpolate (in log space) f1d = interp1d(np.log10(final_wave[:,ii]), final_spec[:,ii]) rebin_spec[:,ii] = f1d(log_wave) #xdb.xplot(final_wave[:,ii], final_spec[:,ii], xtwo=10.**log_wave, ytwo=rebin_spec[:,ii]) #xdb.set_trace() # Transpose for consistency out_spec = np.array(rebin_spec.T, dtype='float32') # Write hdu = fits.PrimaryHDU(out_spec) hdu.header.set('PROJECT', 'DESI QSO TEMPLATES') hdu.header.set('VERSION', '1.1') hdu.header.set('OBJTYPE', 'QSO') hdu.header.set('DISPAXIS', 1, 'dispersion axis') hdu.header.set('CRPIX1', 1, 'reference pixel number') hdu.header.set('CRVAL1', minwave, 'reference log10(Ang)') hdu.header.set('CDELT1', pixsize, 'delta log10(Ang)') hdu.header.set('LOGLAM', 1, 'log10 spaced wavelengths?') hdu.header.set('AIRORVAC', 'vac', ' wavelengths in vacuum (vac) or air') hdu.header.set('VELSCALE', velpixsize, ' pixel size in km/s') hdu.header.set('WAVEUNIT', 'Angstrom', ' wavelength units') hdu.header.set('BUNIT', '1e-17 erg/s/cm2/A', ' flux unit') idval = range(totN) col0 = fits.Column(name='TEMPLATEID',format='K', array=idval) col1 = fits.Column(name='Z',format='E',array=final_z) cols = fits.ColDefs([col0, col1]) tbhdu = fits.BinTableHDU.from_columns(cols) tbhdu.header.set('EXTNAME','METADATA') hdulist = fits.HDUList([hdu, tbhdu]) hdulist.writeto(outfil, clobber=True) return final_wave, final_spec, final_z
def xq100_plls_ex(outfil='fig_xq100_plls_ex.pdf'): # Load spectrum spec_fil = os.getenv('DROPBOX_DIR') + '/XQ-100/data/J0030-5159_uvb.fits' spec = load_spectrum(spec_fil) # Generate model model_file = os.getenv( 'DROPBOX_DIR') + '/XQ-100/LLS/convg_J0030-5159_llsfit.json' with open(model_file) as data_file: lls_dict = json.load(data_file) # Continuum basec = Quantity(lls_dict['conti']) telfer_spec = XSpectrum1D.from_tuple((spec.dispersion.value, basec.value)) # Start the plot if outfil is not None: pp = PdfPages(outfil) plt.figure(figsize=(8, 4)) plt.clf() gs = gridspec.GridSpec(1, 1) fsz = 17. # Read and plot full spectrum ax_full = plt.subplot(gs[0]) # Limits wvmnx = [3600., 5000.] gdpix = np.where(spec.dispersion < wvmnx[1] * u.AA)[0] perc = xsb.perc(spec.flux[gdpix]) ax_full.set_xlim(wvmnx) #ax_full.set_ylim(-0.05*perc[1], 1.1*perc[1]) ax_full.set_ylim(-1e-18, 4e-17) # Plot ax_full.plot(spec.dispersion, spec.flux, color='black', lw=1.0) ax_full.plot(wvmnx, [0., 0.], '--', color='green') # Label ax_full.set_xlabel('Wavelength') ax_full.set_ylabel('Relative Flux') ax_full.text(0.05, 0.9, 'XQ100 J0030-5159', transform=ax_full.transAxes, color='black', size='x-large', ha='left', va='center', bbox={'facecolor': 'white'}) all_ills = [] all_lls = [] all_zlls = [] for key in lls_dict['LLS'].keys(): new_sys = LLSSystem(NHI=lls_dict['LLS'][key]['NHI']) new_sys.zabs = lls_dict['LLS'][key]['z'] new_sys.fill_lls_lines(bval=lls_dict['LLS'][key]['bval'] * u.km / u.s) # all_ills.append(new_sys) all_lls.append(new_sys) all_zlls.append(new_sys.zabs) # Model norm_flux = lls_model(spec.dispersion, all_ills, smooth=lls_dict['smooth']) continuum = telfer_spec.flux * lls_dict['conti_model']['Norm'] * ( spec.dispersion.value / lls_dict['conti_model']['piv_wv'])**lls_dict['conti_model']['tilt'] # Model ax_full.plot(spec.dispersion, continuum * norm_flux) # Font size xputils.set_fontsize(ax_full, fsz) # Finish page plt.tight_layout(pad=0.2, h_pad=0.3, w_pad=0.0) pp.savefig() plt.close() print('Wrote: {:s}'.format(outfil)) # Finish pp.close()