def test_name_to_ion(): Zion = ions.name_ion('Si II') assert Zion == (14,2) # bad input with pytest.raises(ValueError): aux = ions.name_ion(4) # not a string # Deuterium aux = ions.name_ion('DI')
def peroux06b(): """Peroux, C. et al. 2006b, A&A, 450, 53 SDSS J1323-0021 Metal rich Metal columns copied by JXP from Table 1 Total NHI from damping wings """ # Setup radec = '132323.78-002155.2' # SDSS Name lls = LLSSystem(name='SDSSJ1323-0021_z0.716', radec=radec, zem=1.390, zabs=0.716, vlim=[-200., 200.]*u.km/u.s, NHI=20.21, sig_NHI=np.array([0.20,0.20])) # Parse table file tab_fil = pyigm_path+"/data/LLS/Literature/peroux06b.tb1.ascii" with open(tab_fil,'r') as f: flines = f.readlines() ion_dict = {} for iline in flines: isplit = iline.split('\t') if len(isplit[0]) == 0: # Grab ions and init ions = isplit[3:10] for ion in ions: Zion = ltai.name_ion(ion) ion_dict[ion] = dict(clm=0., sig_clm=0.,flg_clm=1,Z=Zion[0],ion=Zion[1]) continue # Column or sigma? if isplit[0][0] == 'N': # Column for kk,iis in enumerate(isplit[3:10]): ion = ions[kk] if iis[0] == '>': ion_dict[ion]['flg_clm'] = 2 ion_dict[ion]['clm'] += float(iis[1:]) elif iis[0] == '<': pass elif iis[0] == '.': pass else: ion_dict[ion]['clm'] += float(iis) else: # Sigma for kk,iis in enumerate(isplit[3:10]): ion = ions[kk] if iis[0] == '.': pass else: ion_dict[ion]['sig_clm'] += float(iis)**2 # Convert to log for ion in ions: N = ion_dict[ion]['clm'] sig = np.sqrt(ion_dict[ion]['sig_clm']) # ion_dict[ion]['clm'] = np.log10(N) if ion_dict[ion]['flg_clm'] == 2: ion_dict[ion]['sig_clm'] = 0. else: ion_dict[ion]['sig_clm'] = sig/N/np.log(10) # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Prx06b') return lls
def main(args=None): pargs = parser(options=args) if pargs.inp is None and pargs.all is False: print("No option selected. Use -h for Help") return # Setup from astropy import units as u from astropy.table import Column from linetools.lists.linelist import LineList from linetools.abund import ions as ltai import numpy as np cols = ['name', 'wrest', 'f', 'A'] # LineList llist = LineList(pargs.llist) # Redshift? if float(pargs.redshift) != 0.: z = llist._data['wrest']*(1+float(pargs.redshift)) llist._data.add_column(Column(z, name='z')) cols += ['z'] # All? if pargs.all: llist._data[cols].pprint(99999) return # Grab line(s) if ustr(pargs.inp[0]).isdecimal(): # Input rest wavelength wrest = float(pargs.inp)*u.AA mtch = np.abs(wrest-llist.wrest) < pargs.toler*u.AA llist._data[cols][mtch].pprint(99999) else: # Either ion or transition istrans = False for jj,char in enumerate(pargs.inp): if char.isdigit(): istrans = True i0 = jj break if istrans: trans = pargs.inp[0:i0]+' '+pargs.inp[i0:] tdict = llist[trans] for key,value in tdict.items(): if key in cols: print('{:s}: {}'.format(key,value)) else: # Ion Zion = ltai.name_ion(pargs.inp) mtion = (llist.Z == Zion[0]) & (llist.ion == Zion[1]) llist._data[cols][mtion].pprint(99999)
def dict_to_ions(idict): """ Manipulate dict into an ion astropy Table Will likely be deprecated Parameters ---------- idict : dict Returns ------- table : astropy.Table """ # Could probably use add_row or dict instantiation table = None for ion in idict.keys(): Zion = ltai.name_ion(ion) if table is None: tkeys = idict[ion].keys() lst = [[idict[ion][tkey]] for tkey in tkeys] table = Table(lst, names=tkeys) # Extra columns if 'Z' not in tkeys: table.add_column(Column([Zion[0]], name='Z')) table.add_column(Column([Zion[1]], name='ion')) else: tdict = idict[ion] tkeys = idict[ion].keys() if 'Z' not in tkeys: tdict['Z'] = Zion[0] tdict['ion'] = Zion[1] # Add table.add_row(tdict) # Finish try: # Historical keys table.rename_column('clm', 'logN') except: pass else: table.rename_column('sig_clm', 'sig_logN') table.rename_column('flg_clm', 'flag_N') # Return return table
def tumlinson11(): """Tumlinson, J. et al. 2011, ApJ, 733, 111 J1009+0713 HST/COS Metal columns parsed from Table 1 NHI from LL+Lyman series (uncertain) """ # Grab ASCII file from ApJ tab_fil = pyigm_path+"/data/LLS/Literature/tumlinson11.tb1.ascii" url = 'http://iopscience.iop.org/0004-637X/733/2/111/suppdata/apj388927t1_ascii.txt' chk_fil = glob.glob(tab_fil) if len(chk_fil) > 0: tab_fil = chk_fil[0] else: print('LLSSurvey: Grabbing table file from {:s}'.format(url)) f = urllib2.urlopen(url) with open(tab_fil, "wb") as code: code.write(f.read()) # Setup radec = '100902.06+071343.8' # From paper lls = LLSSystem(name='J1009+0713_z0.356', radec=radec, zem=0.456, zabs=0.3558, vlim=[-200., 250.]*u.km/u.s, NHI=18.4, sig_NHI=np.array([0.41,0.41])) # Columns # Start with Table 3 (VPFIT) with open(tab_fil,'r') as f: flines1 = f.readlines() # Trim flines1 = flines1[18:] # ion_dict = {} line_dict = dict(OI='1302',OVI='1038',MgII='2803^b',SiII='1190', CaII='3934',FeII='2586') ion = None for iline in flines1: isplit = iline.split('\t') if ion=='FeIII': # Last line break # Ion is2 = isplit[0].split(' ') ion = is2[0]+is2[1] try: gdl = line_dict[ion] except: pass #print('Taking {:s}'.format(isplit[0])) else: if is2[2] != gdl: continue Zion = ltai.name_ion(ion) ion_dict[ion] = dict(logN=0., sig_logN=0., flag_N=0, Z=Zion[0],ion=Zion[1]) # Combine components [could replace with SubSystems some day] for iis in isplit[1:-1]: # Upper limit if (iis.strip()[0] == '<') & (ion_dict[ion]['flag_N']==0): ion_dict[ion]['flag_N']=3 ion_dict[ion]['logN']=float(iis[1:]) elif (iis.strip()[0] == '>'): # Saturated ion_dict[ion]['flag_N']=2 ion_dict[ion]['logN']=log_sum([ion_dict[ion]['logN'],float(iis[1:5])]) elif iis.strip()[0] in ['.','<']: pass else: if ion_dict[ion]['flag_N']==2: # Add to saturated ion_dict[ion]['logN']=log_sum([ion_dict[ion]['logN'],float(iis[0:4])]) else: ion_dict[ion]['flag_N']=1 obj = dict(logN=float(iis[0:4]),sig_logN=float(iis[-4:]), flag_N=1) # Add flag,N,sig = ltaa.sum_logN(ion_dict[ion],obj) ion_dict[ion]['logN']=N ion_dict[ion]['sig_logN']=sig # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Tum11') return lls
def jenkins2005(): """Jenkins, E. et al. 2005, ApJ, 2005, 623, 767 PHL 1811 HST/STIS, FUSE Metals parsed from Table 1 OI taken from text Had to input error on columns by hand (JXP) Total NHI from Lyman series. see Fig 3 M/H from O/H """ # Grab ASCII file from ApJ tab_fil = pyigm_path+"/data/LLS/Literature/jenkins2005.tb1.ascii" chk_fil = glob.glob(tab_fil) if len(chk_fil) > 0: tab_fil = chk_fil[0] else: url = 'http://iopscience.iop.org/0004-637X/623/2/767/fulltext/61520.tb1.txt' print('LLSSurvey: Grabbing table file from {:s}'.format(url)) f = urllib2.urlopen(url) with open(tab_fil, "wb") as code: code.write(f.read()) # Setup radec = '215501.5152-092224.688' # SIMBAD lls = LLSSystem(name='PHL1811_z0.081', radec=radec, zem=0.192, zabs=0.080923, vlim=[-100., 100.]*u.km/u.s, NHI=17.98, ZH=-0.19, sig_NHI=np.array([0.05,0.05])) lls.lines = [] # Probably not used # AbsLines ism = LineList('ISM') Nsig = {'C IV': 0.4, 'N II': 0.4, 'Si II': 0.05, 'Si IV': 0.25, 'S II': 0.2, 'Fe II': 0.12, 'H I': 0.05, 'S III': 0.06} # Parse Table with open(tab_fil,'r') as f: flines = f.readlines() ion_dict = {} for iline in flines: iline = iline.strip() if (len(iline) == 0): continue # Split on tabs isplit = iline.split('\t') # Offset? ioff = 0 if isplit[0][0] in ['1','2']: ioff = -1 # Catch bad lines if (isplit[1+ioff][0:6] in ['1442.0','1443.7','1120.9']): # Skip goofy CII line and CII* continue if len(isplit[2+ioff]) == 0: continue # Ion if (len(isplit[0].strip()) > 0) & (isplit[0][0] not in ['1','2']): ionc = isplit[0].strip() try: Zion = ltai.name_ion(ionc) except KeyError: pdb.set_trace() # Generate the Line try: newline = AbsLine(float(isplit[2+ioff])*u.AA,linelist=ism, closest=True) except ValueError: pdb.set_trace() newline.attrib['z'] = lls.zabs # Spectrum newline.analy['datafile'] = 'STIS' if 'S' in isplit[1] else 'FUSE' # EW try: EWvals = isplit[4+ioff].split(' ') except IndexError: pdb.set_trace() newline.attrib['EW'] = float(EWvals[0])*u.AA/1e3 newline.attrib['sig_EW'] = float(EWvals[2])*u.AA/1e3 newline.attrib['flag_EW'] = 1 if len(isplit) < (5+ioff+1): continue # Colm? #xdb.set_trace() newline.attrib['sig_logN'] = 0. if (len(isplit[5+ioff].strip()) > 0) & (isplit[5+ioff].strip() != '\\ldots'): if isplit[5+ioff][0] == '\\': ipos = isplit[5+ioff].find(' ') newline.attrib['logN'] = float(isplit[5+ioff][ipos+1:]) newline.attrib['flag_N'] = 2 elif isplit[5+ioff][0] == '<': ipos = 0 newline.attrib['logN'] = float(isplit[5+ioff][ipos+1:]) newline.attrib['flag_N'] = 3 elif isplit[5+ioff][0] == '1': try: newline.attrib['logN'] = float(isplit[5+ioff][0:5]) except ValueError: pdb.set_trace() newline.attrib['flag_N'] = 1 try: newline.attrib['sig_logN'] = Nsig[ionc] except KeyError: print('No error for {:s}'.format(ionc)) else: raise ValueError('Bad character') # ion_dict ion_dict[ionc] = dict(clm=newline.attrib['logN'], sig_clm=newline.attrib['sig_logN'], flg_clm=newline.attrib['flag_N'], Z=Zion[0], ion=Zion[1]) # Append lls.lines.append(newline) # Fix NI, OI ion_dict['O I']['clm'] = 14.47 ion_dict['O I']['sig_clm'] = 0.05 ion_dict['N I']['flg_clm'] = 3 lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Jen05') # Return return lls
def dessauges09(): '''Dessauges-Zavadsky et al. 2009, MNRAS, 396, L96 SLLS with UVES Zn,Fe abundances from Table 1 from astro-ph (LateX) by JXP [AODM] Taken from the Zn/H and Fe/H assuming *no* ionization corrections RA/DEC from the 'other' name ''' # Solar abundances eZn = 4.63 eFe = 7.45 sol = [eFe,eZn] # all_lls = [] # Table 1 tab_fil = pyigm_path+"/data/LLS/Literature/dessauges09.tb1.ascii" with open(tab_fil,'r') as f: flines1 = f.readlines() # Trim the first few lines flines1 = flines1[3:] for iline in flines1: # Parse isplit = iline.split('&') # QSO if iline[0:2] == 'QS': # QSO, RA/DEC, zem qso = isplit[0][4:].strip() radec = isplit[1].strip()[1:].replace('$','') zem = float(isplit[3].strip()) # NHI, zabs zabs = float(isplit[4].strip()) is2 = isplit[6].strip() NHI = float(is2[1:6]) sigNHI = np.array([float(is2[10:14])]*2) # name name = qso+'z_{:.3f}'.format(zabs) lls = LLSSystem(name=name, radec=radec, vlim=[-500,500]*u.km/u.s, zem=zem, zabs=zabs, NHI=NHI, sig_NHI=sigNHI) # ADOM Columns ion_dict = {} for kk,ion in enumerate(['Fe II','Zn II']): Zion = ltai.name_ion(ion) is2 = isplit[7+kk].strip() if is2[0:2] == '$>': ion_dict[ion] = dict(sig_clm=0.,flg_clm=2,Z=Zion[0],ion=Zion[1]) ion_dict[ion]['clm'] = float(is2[2:7]) + NHI - 12 + sol[kk] elif is2[0:2] == '$<': ion_dict[ion] = dict(sig_clm=0.,flg_clm=3,Z=Zion[0],ion=Zion[1]) ion_dict[ion]['clm'] = float(is2[2:7]) + NHI - 12 + sol[kk] elif is2[0:2] == '..': pass else: ion_dict[ion] = dict(flg_clm=1,Z=Zion[0],ion=Zion[1]) ion_dict[ion]['clm'] = float(is2[1:6]) + NHI - 12 + sol[kk] ion_dict[ion]['sig_clm'] = float(is2[10:14]) #xdb.set_trace() # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('DZ09') all_lls.append(lls) # Return SLLS only fin_slls = [ills for ills in all_lls if ills.NHI < 20.3] return fin_slls
def meiring09(): '''Meiring et al. 2009, MNRAS, 393, 1513 SLLS with Magellan Abundances from Table 3 from astro-ph (LateX) by JXP [AODM] RA/DEC from Table 1 ''' all_lls = [] # Table 1 tab_fil = pyigm_path+"/data/LLS/Literature/meiring09.tb1.ascii" with open(tab_fil,'r') as f: flines1 = f.readlines() # Grab RA/DEC qso_dict = {} for iline in flines1: if iline[0:3] in [' QS','\hl','$\\c', ' J2', ' ']: continue # Parse isplit = iline.split('&') #xdb.set_trace() if '$' in isplit[3].strip(): isplit[3] = '-'+(isplit[3].strip())[3:] radec = isplit[2].strip()+isplit[3].strip() radec = radec.replace(':','') # zem zem = float(isplit[5].strip()) # Save qso_dict[isplit[0].strip()] = dict(radec=radec,zem=zem, vlim=[-500,500.]*u.km/u.s) # Abundances (AODM) # Table 3 tab_fil = pyigm_path+"/data/LLS/Literature/meiring09.tb3.ascii" with open(tab_fil,'r') as f: flines3 = f.readlines() # for iline in flines3: if iline[0:2] in ['\h',' ']: continue # Parse isplit = iline.split('&') # Ions if iline[0:2] == 'QS': ioncs = [] Zions = [] for iis in isplit[3:-1]: # Skipping HI # Parse #is2 = iis.split('\\') #ip2 = is2[2].find('}') ionc = iis.strip() # Zion Zion = ltai.name_ion(ionc) # Append ioncs.append(ionc) Zions.append(Zion) continue if iline[0] == 'Q': # QSO qso = isplit[0].strip() if qso[-1] in ['A','B','C']: qso = qso[0:-1] # zabs and name zabs = float(isplit[1].strip()) qso_dict[qso]['name']=qso+'z_{:.3f}'.format(zabs) qso_dict[qso]['zabs']=zabs # NHI is2 = isplit[2].strip() if is2[0] == '$': qso_dict[qso]['NHI'] = 99.99 # THROW OUT Q1436-0051B qso_dict[qso]['sig_NHI'] = np.array([0.,0.]) else: qso_dict[qso]['NHI'] = float(is2[0:5]) qso_dict[qso]['sig_NHI'] = np.array([float(is2[10:])]*2) #if qso_dict[qso]['NHI'] >= 20.3: # print('Uh oh. DLA') # Generate LLS lls = LLSSystem(**qso_dict[qso]) continue else: # ADOM Columns ion_dict = {} for kk,iis in enumerate(isplit[3:-1]): is2 = iis.strip() if is2[0:3] == '$>$': ion_dict[ioncs[kk]] = dict(sig_clm=0.,flg_clm=2,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[3:]) elif is2[0:3] == '$<$': ion_dict[ioncs[kk]] = dict(sig_clm=0.,flg_clm=3,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[3:]) elif len(is2) == 0: pass else: ion_dict[ioncs[kk]] = dict(flg_clm=1,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[0:5]) ion_dict[ioncs[kk]]['sig_clm'] = float(is2[10:]) # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Mei09') all_lls.append(lls) # Return SLLS only fin_slls = [ills for ills in all_lls if ills.NHI < 20.3] return fin_slls
def meiring07(): """Meiring et al. 2007, MNRAS, 376, 557 SLLS with Magellan Abundances from Table 11 from astro-ph (LateX) by JXP [AODM] RA/DEC from Table 1 """ all_lls = [] # Table 1 tab_fil = pyigm_path+"/data/LLS/Literature/meiring07.tb1.ascii" with open(tab_fil,'r') as f: flines1 = f.readlines() # Grab RA/DEC qso_dict = {} for iline in flines1: if iline[0:2] in ['QS','\h','$\\', 'J2']: continue # Parse isplit = iline.split('&') if '-' not in isplit[3]: sgn = '+' else: sgn = '' radec = isplit[2].strip()+sgn+isplit[3].strip() radec = radec.replace(':','') # zem if isplit[0].strip() != 'Q0826-2230': zem = float(isplit[5].strip()) else: zem = 0.911 # Save qso_dict[isplit[0].strip()] = dict(radec=radec, zem=zem, vlim=[-500.,500]*u.km/u.s) # Abundances (AODM) # Table 11 tab_fil = pyigm_path+"/data/LLS/Literature/meiring07.tb11.ascii" with open(tab_fil,'r') as f: flines11 = f.readlines() # for iline in flines11: if iline[0:2] in ['\h',' ']: continue # Parse isplit = iline.split('&') # Ions if iline[0:2] == 'QS': ioncs = [] Zions = [] for iis in isplit[3:-1]: # Skipping HI # Parse is2 = iis.split('\\') ip2 = is2[2].find('}') ionc = is2[1][2:].strip()+' '+is2[2][0:ip2].strip() # Zion Zion = ltai.name_ion(ionc) # Append ioncs.append(ionc) Zions.append(Zion) continue if iline[0] == 'Q': # QSO qso = isplit[0].strip() # zabs and name zabs = float(isplit[1].strip()) qso_dict[qso]['name']=qso+'z_{:.3f}'.format(zabs) qso_dict[qso]['zabs']=zabs # NHI is2 = isplit[2].strip() qso_dict[qso]['NHI'] = float(is2[0:5]) #if qso_dict[qso]['NHI'] >= 20.3: # print('Uh oh. DLA') qso_dict[qso]['sig_NHI'] = np.array([float(is2[10:])]*2) # Generate LLS lls = LLSSystem(**qso_dict[qso]) continue else: # ADOM Columns ion_dict = {} for kk,iis in enumerate(isplit[3:-1]): is2 = iis.strip() if is2[0:3] == '$>$': ion_dict[ioncs[kk]] = dict(sig_clm=0.,flg_clm=2,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[3:]) elif is2[0:3] == '$<$': ion_dict[ioncs[kk]] = dict(sig_clm=0.,flg_clm=3,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[3:]) elif len(is2) == 0: pass else: ion_dict[ioncs[kk]] = dict(flg_clm=1,Z=Zions[kk][0],ion=Zions[kk][1]) ion_dict[ioncs[kk]]['clm'] = float(is2[0:5]) ion_dict[ioncs[kk]]['sig_clm'] = float(is2[10:]) # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Mei07') all_lls.append(lls) # Return SLLS only fin_slls = [ills for ills in all_lls if ills.NHI < 20.3] return fin_slls
def fig_sngl_cldy_model(sys, dpath=os.getenv('COSHALOS_DATA')+'/Cloudy/', ax=None, outfil=None, lsz=15., show_sys=False): """ Compare columns between model and data """ # Read fh5 = h5py.File(dpath+sys+'_emcee.hd5', 'r') ions = fh5['inputs']['ions'].value data = fh5['inputs']['data'].value fit = fh5['outputs']['best_fit'].value fh5.close() # IP values IPs = np.zeros(len(ions)) for ii,ion in enumerate(ions): Zion = lai.name_ion(ion) elm = ELEMENTS[Zion[0]] IPs[ii] = elm.ionenergy[Zion[1]-1] #xdb.set_trace() resid = data[:,1].astype(float) - fit # Start the plot if outfil is not None: pp = PdfPages(outfil) plt.figure(figsize=(7, 7)) plt.clf() gs = gridspec.GridSpec(1, 1) ax = plt.subplot(gs[0]) # Axes #wvmnx = awvmnx[iuvq['instr']] #ax.yaxis.set_major_locator(plt.MultipleLocator(1.)) ax.minorticks_on() xlim = (5., np.max(IPs)+4) ax.set_xlim(xlim) ylim = (-1., 1.) ax.set_ylim(ylim) # Labels ax.set_xlabel('IP (eV)', size=lsz) ax.set_ylabel(r'$\Delta \, \log \, N$', size=lsz) ax.xaxis.set_major_locator(plt.MultipleLocator(10.)) # Values gdv = np.where(data[:,3].astype(int) == 0)[0] if len(gdv) > 0: ax.errorbar(IPs[gdv],resid[gdv], xerr=0, linestyle='None', yerr=data[:,2].astype(float)[gdv], color='blue', marker='o') # Limits limsz = 50. ulim = np.where(data[:,3].astype(int) == -1)[0] ax.scatter(IPs[ulim],resid[ulim], color='red', marker='v', s=limsz) llim = np.where(data[:,3].astype(int) == -2)[0] ax.scatter(IPs[llim],resid[llim], color='green', marker='^', s=limsz) # Label for kk,ion in enumerate(ions): if (resid[kk] < ylim[1]) & (resid[kk] > ylim[0]): ax.text(IPs[kk]+1, resid[kk], ion, color='k', size=lsz) # Only if on page if show_sys: ax.text(0.04, 0.04, sys, transform=ax.transAxes, size=lsz-1, ha='left') #bbox={'facecolor':'white'}) #legend = plt.legend(loc='upper right', scatterpoints=1, borderpad=0.3, # handletextpad=0.3, fontsize='small', numpoints=1) ax.plot(xlim, [0.,0.], 'g:') # End xputils.set_fontsize(ax,lsz) if outfil is not None: print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2,h_pad=0.,w_pad=0.1) pp.savefig() pp.close() plt.close()
def fig_sngl_cldy_model(sys, dpath=os.getenv('COSHALOS_DATA') + '/Cloudy/', ax=None, outfil=None, lsz=15., show_sys=False): """ Compare columns between model and data """ # Read fh5 = h5py.File(dpath + sys + '_emcee.hd5', 'r') ions = fh5['inputs']['ions'].value data = fh5['inputs']['data'].value fit = fh5['outputs']['best_fit'].value fh5.close() # IP values IPs = np.zeros(len(ions)) for ii, ion in enumerate(ions): Zion = lai.name_ion(ion) elm = ELEMENTS[Zion[0]] IPs[ii] = elm.ionenergy[Zion[1] - 1] #xdb.set_trace() resid = data[:, 1].astype(float) - fit # Start the plot if outfil is not None: pp = PdfPages(outfil) plt.figure(figsize=(7, 7)) plt.clf() gs = gridspec.GridSpec(1, 1) ax = plt.subplot(gs[0]) # Axes #wvmnx = awvmnx[iuvq['instr']] #ax.yaxis.set_major_locator(plt.MultipleLocator(1.)) ax.minorticks_on() xlim = (5., np.max(IPs) + 4) ax.set_xlim(xlim) ylim = (-1., 1.) ax.set_ylim(ylim) # Labels ax.set_xlabel('IP (eV)', size=lsz) ax.set_ylabel(r'$\Delta \, \log \, N$', size=lsz) ax.xaxis.set_major_locator(plt.MultipleLocator(10.)) # Values gdv = np.where(data[:, 3].astype(int) == 0)[0] if len(gdv) > 0: ax.errorbar(IPs[gdv], resid[gdv], xerr=0, linestyle='None', yerr=data[:, 2].astype(float)[gdv], color='blue', marker='o') # Limits limsz = 50. ulim = np.where(data[:, 3].astype(int) == -1)[0] ax.scatter(IPs[ulim], resid[ulim], color='red', marker='v', s=limsz) llim = np.where(data[:, 3].astype(int) == -2)[0] ax.scatter(IPs[llim], resid[llim], color='green', marker='^', s=limsz) # Label for kk, ion in enumerate(ions): if (resid[kk] < ylim[1]) & (resid[kk] > ylim[0]): ax.text(IPs[kk] + 1, resid[kk], ion, color='k', size=lsz) # Only if on page if show_sys: ax.text(0.04, 0.04, sys, transform=ax.transAxes, size=lsz - 1, ha='left') #bbox={'facecolor':'white'}) #legend = plt.legend(loc='upper right', scatterpoints=1, borderpad=0.3, # handletextpad=0.3, fontsize='small', numpoints=1) ax.plot(xlim, [0., 0.], 'g:') # End xputils.set_fontsize(ax, lsz) if outfil is not None: print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2, h_pad=0., w_pad=0.1) pp.savefig() pp.close() plt.close()
def complist_from_table(table): """ Returns a list of AbsComponents from an input astropy.Table. Parameters ---------- table : Table Table with component information (each row must correspond to a component). Each column is expecting a unit when appropriate. Returns ------- complist : list List of AbsComponents defined from the input table. Notes ----- Mandatory column names: 'RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax' These column are required. Special column names: 'name', 'comment', 'logN', 'sig_logN', 'flag_logN' These columns will fill internal attributes when corresponding. In order to fill in the Ntuple attribute all three 'logN', 'sig_logN', 'flag_logN' must be present. For convenience 'logN' and 'sig_logN' are expected to be floats corresponding to their values in np.log10(1/cm^2). Other columns: 'any_column_name' These will be added as attributes within the AbsComponent.attrib dictionary, with their respective units if given. """ # Convert to QTable to handle units in individual entries more easily table = QTable(table) # mandatory and optional columns min_columns = ['RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax'] special_columns = ['name', 'comment', 'logN', 'sig_logN', 'flag_logN'] for colname in min_columns: if colname not in table.keys(): raise IOError( '{} is a mandatory column. Please make sure your input table has it.' .format(colname)) #loop over rows complist = [] for row in table: # mandatory coord = SkyCoord(row['RA'].to('deg').value, row['DEC'].to('deg').value, unit='deg') # RA y DEC must both come with units Zion = name_ion(row['ion_name']) zcomp = row['z_comp'] vlim = [row['vmin'].to('km/s').value, row['vmax'].to('km/s').value ] * u.km / u.s # units are expected here too # special columns try: Ntuple = (row['flag_logN'], row['logN'], row['sig_logN'] ) # no units expected except KeyError: Ntuple = None try: comment = row['comment'] except KeyError: comment = '' try: name = row['name'] except KeyError: name = None # define the component comp = AbsComponent(coord, Zion, zcomp, vlim, Ntup=Ntuple, comment=comment, name=name) # other columns will be filled in comp.attrib dict for colname in table.keys(): if (colname not in special_columns) and (colname not in min_columns): kms_cols = ['b', 'sig_b'] if colname in kms_cols: # check units for parameters expected in velocity units try: val_aux = row[colname].to('km/s').value * u.km / u.s except u.UnitConversionError: raise IOError( 'If `{}` column is present, it must have velocity units.' .format(colname)) comp.attrib[colname] = val_aux # parameters we do not care about units much else: comp.attrib[colname] = row[colname] # append complist += [comp] return complist
def test_name_to_ion(): Zion = ions.name_ion('Si II') assert Zion == (14,2)
def battisti12(): '''Battisti, A. et al. 2012, ApJ, 744, 93 HST/COS QSO info from Table 1 Metal columns parsed from Table 3 NHI from Lya ''' all_lls = [] # Grab ASCII files from ApJ tab_fils = [pyigm_path+"/data/LLS/Literature/battisti12.tb1.ascii", pyigm_path+"/data/LLS/Literature/battisti12.tb3.ascii"] urls = ['http://iopscience.iop.org/0004-637X/744/2/93/suppdata/apj413924t1_ascii.txt', 'http://iopscience.iop.org/0004-637X/744/2/93/suppdata/apj413924t3_ascii.txt'] for jj,tab_fil in enumerate(tab_fils): chk_fil = glob.glob(tab_fil) if len(chk_fil) > 0: tab_fil = chk_fil[0] else: url = urls[jj] print('LLSSurvey: Grabbing table file from {:s}'.format(url)) f = urllib2.urlopen(url) with open(tab_fil, "wb") as code: code.write(f.read()) # QSO info with open(tab_fils[0],'r') as f: flines1 = f.readlines() # Grab RA/DEC all_idict = [] for iline in flines1: if iline[0:2] != 'SD': continue # Parse isplit = iline.split('\t') name = isplit[0].split(' ')[1] radec = name[1:] zem = float(isplit[1].strip()) zabs = float(isplit[2].strip()) NHI = float(isplit[3].strip()[0:4]) sigNHI = np.array([float(isplit[3].strip()[11:])]*2) # Save lls = LLSSystem(name=name,radec=radec,zem=zem, zabs=zabs,NHI=NHI,sig_NHI=sigNHI, vlim=[-500,500]*u.km/u.s) # all_lls.append(lls) all_idict.append({}) # Abundances with open(tab_fils[1],'r') as f: flines3 = f.readlines() flines3 = flines3[5:] ion = None for iline in flines3: if ion == 'Ni II': break isplit = iline.split('\t') if isplit[0] == 'C II*': # Skipping CII* continue # ion ipos = -1 while (isplit[0][ipos] not in ['I','V']): ipos -= 1 ion = isplit[0][0:ipos+1+len(isplit[0])] Zion = ltai.name_ion(ion) # Loop on systems for kk,iis in enumerate(isplit[1:-1]): if iis.strip()[0] == '.': continue all_idict[kk][ion] = dict(Z=Zion[0], ion=Zion[1],sig_clm=0.) if iis[0] == '>': all_idict[kk][ion]['flg_clm'] = 2 all_idict[kk][ion]['clm'] = float(iis[1:6]) elif iis[0] == '<': all_idict[kk][ion]['flg_clm'] = 3 all_idict[kk][ion]['clm'] = float(iis[1:]) else: all_idict[kk][ion]['flg_clm'] = 1 all_idict[kk][ion]['clm'] = float(iis[0:5]) all_idict[kk][ion]['sig_clm'] = float(iis[-4:]) # Return SLLS only for kk,lls in enumerate(all_lls): try: lls._ionN = pyiau.dict_to_ions(all_idict[kk]) except ValueError: pdb.set_trace() lls.Refs.append('Bat12') fin_slls = [ills for ills in all_lls if ills.NHI < 20.3] return fin_slls
def complist_from_table(table): """ Returns a list of AbsComponents from an input Table. Parameters ---------- table : QTable Table with component information (each row must correspond to a component). Each column is expecting a unit when appropriate. Returns ------- complist : list List of AbsComponents defined from the input table. Notes ----- Mandatory column names: 'RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax' These column are required. Special column names: 'name', 'comment', 'logN', 'sig_logN', 'flag_logN' These columns will fill internal attributes when corresponding. In order to fill in the Ntuple attribute all three 'logN', 'sig_logN', 'flag_logN' must be present. For convenience 'logN' and 'sig_logN' are expected to be floats corresponding to their values in np.log10(1/cm^2). Other columns: 'any_column_name' These will be added as attributes within the AbsComponent.attrib dictionary, with their respective units if given. """ # mandatory and optional columns min_columns = ['RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax'] special_columns = ['name', 'comment', 'logN', 'sig_logN', 'flag_logN'] for colname in min_columns: if colname not in table.keys(): raise IOError('{} is a mandatory column. Please make sure your input table has it.'.format(colname)) #loop over rows complist = [] for row in table: # mandatory coord = SkyCoord(row['RA'].to('deg').value, row['DEC'].to('deg').value, unit='deg') # RA y DEC must both come with units Zion = name_ion(row['ion_name']) zcomp = row['z_comp'] vlim =[row['vmin'].to('km/s').value, row['vmax'].to('km/s').value] * u.km / u.s # units are expected here too # special columns try: Ntuple = (row['flag_logN'], row['logN'], row['sig_logN']) # no units expected except KeyError: Ntuple = None try: comment = row['comment'] except KeyError: comment = '' try: name = row['name'] except KeyError: name = None # define the component comp = AbsComponent(coord, Zion, zcomp, vlim, Ntup=Ntuple, comment=comment, name=name) # other columns will be filled in comp.attrib dict for colname in table.keys(): if (colname not in special_columns) and (colname not in min_columns): kms_cols = ['b', 'sig_b'] if colname in kms_cols: # check units for parameters expected in velocity units try: val_aux = row[colname].to('km/s').value * u.km / u.s except u.UnitConversionError: raise IOError('If `{}` column is present, it must have velocity units.'.format(colname)) comp.attrib[colname] = val_aux # parameters we do not care about units much else: comp.attrib[colname] = row[colname] # append complist += [comp] return complist
def tripp2005(): '''Tripp, T. et al. 2005, ApJ, 2005, 619, 714 PG 1216+069 (LLS in Virgo) HST/STIS, FUSE Metal columns parsed from Tables 2 and 3 Total NHI from damping wings M/H from O/H ''' # Grab ASCII files from ApJ tab_fils = [pyigm_path+"/data/LLS/tripp2005.tb3.ascii", pyigm_path+"/data/LLS/tripp2005.tb2.ascii"] urls = ['http://iopscience.iop.org/0004-637X/619/2/714/fulltext/60797.tb3.txt', 'http://iopscience.iop.org/0004-637X/619/2/714/fulltext/60797.tb2.txt'] for jj,tab_fil in enumerate(tab_fils): chk_fil = glob.glob(tab_fil) if len(chk_fil) > 0: tab_fil = chk_fil[0] else: url = urls[jj] print('LLSSurvey: Grabbing table file from {:s}'.format(url)) f = urllib2.urlopen(url) with open(tab_fil, "wb") as code: code.write(f.read()) # Setup radec = '121920.9320+063838.476' # SIMBAD lls = LLSSystem(name='PG1216+069_z0.006', radec=radec, zem=0.3313, zabs=0.00632, vlim=[-100., 100.]*u.km/u.s, NHI=19.32, ZH=-1.6, sig_NHI=np.array([0.03, 0.03])) # Columns # Start with Table 3 (VPFIT) with open(tab_fils[0],'r') as f: flines3 = f.readlines() ion_dict = {} for iline in flines3: if (len(iline.strip()) == 0): continue isplit = iline.split('\t') # Ion flg = 2 if (len(isplit[0].strip()) > 0):# & (isplit[0][0] not in ['1','2']): ipos = isplit[0].find('1') ionc = isplit[0][0:ipos-1].strip() try: Zion = ltai.name_ion(ionc) except KeyError: pdb.set_trace() flg = 1 # Column csplit = isplit[3].split(' ') clm = float(csplit[0]) sig = float(csplit[2]) if flg == 1: ion_dict[ionc] = dict(logN=clm, sig_logN=sig, flag_N=1, Z=Zion[0], ion=Zion[1]) else: # Add it in tmp_dict = dict(logN=clm, sig_logN=sig, flag_N=1, Z=Zion[0], ion=Zion[1]) flagN, logN, siglogN = ltaa.sum_logN(ion_dict[ionc], tmp_dict) ion_dict[ionc]['logN'] = logN ion_dict[ionc]['sig_logN'] = siglogN ions = ion_dict.keys() # Now Table 2 for the extras with open(tab_fils[1],'r') as f: flines2 = f.readlines() # Trim the first 10 lines flines2 = flines2[10:] # Loop for iline in flines2: isplit = iline.split('\t') # ionc = isplit[0].strip() if (len(ionc) == 0) or (ionc in ions): continue # Zion = ltai.name_ion(ionc) ion_dict[ionc] = dict(Z=Zion[0], ion=Zion[1], sig_logN=0.) if isplit[4][0] == '<': ion_dict[ionc]['logN'] = float(isplit[4][1:]) ion_dict[ionc]['flag_N'] = 3 else: raise ValueError('Should not get here') # Finish lls._ionN = pyiau.dict_to_ions(ion_dict) lls.Refs.append('Tri05') return lls
def available_transitions(self, wvlims, n_max=None, n_max_tuple=None, min_strength=1.): """ Find the strongest transitions in a wavelength interval. For a given wavelength range, wvlims = (wv_min, wv_max), this function retrieves the n_max_tuple strongest transitions per each ion species in the LineList available at such a wavelength range and having strength larger than min_strength. Strength is defined as log10(wrest * fosc * abundance). The output is sorted by strength of the strongest available transition per ion species. Parameters ---------- wvlims : tuple of Quantity Wavelength range, e.g. wvlims = (1100 * u.AA, 3200 * u.AA) n_max : int, optional Maximum number of transitions retrieved when given, otherwise recover all of them n_max_tuple : int, optional Maximum number of transitions in a given ion species to retrieve. e.g., if Lyman series are all available, it will retrieve only up to Lyman gamma if n_max_tuple = 3. Otherwise it returns all of them min_strength : float, optional Minimum strength calculated from log10(wrest * fosc * abundance) In this way HI 1215 has 14.7 by definition. Returns ------- dict (if only 1 transition found) or QTable (if > 1 transitions are found) or None (if no transition is found) """ # Init from linetools.abund.solar import SolarAbund from linetools.abund import ions as laions solar = SolarAbund() if all((isinstance(n, int) or (n is None)) for n in [n_max, n_max_tuple]): if (n_max is not None) and (n_max < 1): return None else: raise SyntaxError( 'Both n_max and n_max_tuple must be integers when given!') if isinstance(min_strength, (float,int)): pass else: raise SyntaxError('min_strength must be a float value') # Identify unique ion_names (e.g. HI, CIV, CIII) # unique_ion_names = list(set([name.split(' ')[0] for name in self._data['name']])) # unique_ion_names = np.array(unique_ion_names) unique_ion_names = np.unique( [name.split(' ')[0] for name in self._data['name']]) # obtain the strongest transition of a given unique ion species ion_name = [] strength = [] for ion in unique_ion_names: # This loop is necessary to have a non trivial but convinient order in the final output # Abundance Zion = laions.name_ion(ion) if ion == 'DI': abundance = 12. - 4.8 # Approximate for Deuterium else: abundance = solar[Zion[0]] aux = self.strongest_transitions( ion, wvlims, n_max=1) # only the strongest if aux is not None: if isinstance(aux, dict): # this should always be True given n_max=1 name = aux['name'] else: name = aux['name'][0] ion_name += [name] strength += [np.log10(aux['wrest'].value * aux['f']) + abundance] if len(ion_name) == 0: # no matches return None # create Table unique = Table() unique.add_column(Column(data=ion_name, name='name')) unique.add_column(Column(data=strength, name='strength')) # get rid of those below the min_strength threshold cond = unique['strength'] >= min_strength unique = unique[cond] if len(unique) < 1: return None # sort by strength unique.sort(['strength']) unique.reverse() # Table unique is now sorted by strength, with only # 1 entry per ion species # Create output data adding up to n_max_tuple per ion species for i, row in enumerate(unique): name = row['name'] aux = self.strongest_transitions(name, wvlims, n_max=n_max_tuple) # need to deal with dict vs QTable format now if isinstance(aux, dict): aux = self.from_dict_to_qtable(aux) if i == 0: # convert to Table because QTable does not like vstack output = Table(aux) else: # vstack is only supported for Table() output = vstack([output, Table(aux)]) # if len==1 return dict if len(output) == 1: name = output['name'][0] return self.__getitem__(name) else: # n_max>1 if n_max > 1: output = output[:n_max] if len(output) == 1: # return dictionary name = output['name'][0] return self.__getitem__(name) else: return QTable(output)
def get_ions(self, use_Nfile=False, idict=None, update_zvlim=True, linelist=None): """Parse the ions for each Subsystem And put them together for the full system Fills ._ionN with a QTable Parameters ---------- idict : dict, optional dict containing the IonClms info use_Nfile : bool, optional Parse ions from a .clm file (JXP historical) update_zvlim : bool, optional Update zvlim from lines in .clm (as applicable) linelist : LineList """ if idict is not None: # Manipulate for astropy Table # Could probably use add_row or dict instantiation table = None for ion in idict.keys(): Zion = ltai.name_ion(ion) if table is None: tkeys = idict[ion].keys() lst = [[idict[ion][tkey]] for tkey in tkeys] table = Table(lst, names=tkeys) # Extra columns if 'Z' not in tkeys: table.add_column(Column([Zion[0]], name='Z')) table.add_column(Column([Zion[1]], name='ion')) else: tdict = idict[ion] tkeys = idict[ion].keys() if 'Z' not in tkeys: tdict['Z'] = Zion[0] tdict['ion'] = Zion[1] # Add table.add_row(tdict) # Finish try: # Historical keys table.rename_column('clm', 'logN') except: pass else: table.rename_column('sig_clm', 'sig_logN') table.rename_column('flg_clm', 'flag_N') self._ionN = table elif use_Nfile: # Subsystems if self.nsub > 0: # This speeds things up (but is rarely used) linelist = LineList('ISM') for lbl in self.subsys.keys(): clm_fil = self.tree+self.subsys[lbl]._datdict['clm_file'] # Parse .clm file self.subsys[lbl]._clmdict = igmau.read_clmfile(clm_fil, linelist=linelist) # Build components from lines components = igmau.build_components_from_abslines([], clmdict=self.subsys[lbl]._clmdict, coord=self.coord) # Update z, vlim if update_zvlim: vmin,vmax = 9999., -9999. for component in components: vmin = min(vmin, component.vlim[0].value) vmax = max(vmax, component.vlim[1].value) self.subsys[lbl].zabs = self.subsys[lbl]._clmdict['zsys'] self.subsys[lbl].vlim = [vmin, vmax]*u.km/u.s # Read .ion file and fill in components ion_fil = self.tree+self.subsys[lbl]._clmdict['ion_fil'] self.subsys[lbl]._indiv_ionclms = igmau.read_ion_file(ion_fil, components) # Parse .all file all_file = ion_fil.split('.ion')[0]+'.all' self.subsys[lbl].all_file=all_file #MF: useful to have _ = igmau.read_all_file(all_file, components=components) # Build table self.subsys[lbl]._ionN = igmau.iontable_from_components(components,ztbl=self.subsys[lbl].zabs) # Add to IGMSystem for comp in components: self.add_component(comp) # Combine if self.nsub == 1: self._ionN = self.subsys['A']._ionN self._clmdict = self.subsys['A']._clmdict #xdb.set_trace() elif self.nsub == 0: raise ValueError('lls_utils.get_ions: Cannot have 0 subsystems..') else: self._ionN = self.subsys['A']._ionN self._clmdict = self.subsys['A']._clmdict warnings.warn('lls_utils.get_ions: Need to update multiple subsystems!! Taking A.') else: raise ValueError("Need an option in get_ions")