line_labels['mn'] = r'$\mathrm{Mn\kern 0.1em I}$' line_labels['s'] = r'$\mathrm{S\kern 0.1em I}$' line_labels['v'] = r'$\mathrm{V\kern 0.1em I}$' line_labels['cob'] = r'$\mathrm{Co\kern 0.1em I}$' line_labels['cu'] = r'$\mathrm{Cu\kern 0.1em I}$' line_labels['oh'] = r'$\mathrm{OH}$' line_labels['co'] = r'$^{12}\!\mathrm{CO}$' line_labels['cn'] = r'$\mathrm{CN}$' line_labels['13co'] = r'$^{13}\!\mathrm{CO}$' line_labels['hbrpi'] = r'$\mathrm{Br-}\pi$' line_labels['hbrla'] = r'$\mathrm{Br-}\lambda$' line_labels['hbr'] = r'$\mathrm{H[Br]}$' line_labels['dib'] = r'$\mathrm{DIB}$' # From Table 2 in Smith et al. (2013) _FEI_lines = [ air2vac(l) for l in [ 15194.492, 15207.526, 15395.718, 15490.339, 15648.510, 15964.867, 16040.657, 16153.247, 16165.032 ] ] _FEI_lines.append(16697.635) # one more from Shetrone # From Table 5 _MGI_lines = [ air2vac(l) for l in [15740.716, 15748.9, 15765.8, 15879.5, 15886.2, 15954.477] ] _ALI_lines = [air2vac(l) for l in [16718.957, 16750.564286, 16763.359]] _SII_lines = [ air2vac(l) for l in [ 15361.161, 15376.831, 15833.602, 15960.063, 16060.009, 16094.787, 16215.670, 16680.770, 16828.159
line_labels['na']= r'$\mathrm{Na\kern 0.1em I}$' line_labels['mn']= r'$\mathrm{Mn\kern 0.1em I}$' line_labels['s']= r'$\mathrm{S\kern 0.1em I}$' line_labels['v']= r'$\mathrm{V\kern 0.1em I}$' line_labels['cob']= r'$\mathrm{Co\kern 0.1em I}$' line_labels['cu']= r'$\mathrm{Cu\kern 0.1em I}$' line_labels['oh']= r'$\mathrm{OH}$' line_labels['co']= r'$^{12}\!\mathrm{CO}$' line_labels['cn']= r'$\mathrm{CN}$' line_labels['13co']= r'$^{13}\!\mathrm{CO}$' line_labels['hbrpi']= r'$\mathrm{Br-}\pi$' line_labels['hbrla']= r'$\mathrm{Br-}\lambda$' line_labels['hbr']= r'$\mathrm{H[Br]}$' line_labels['dib']= r'$\mathrm{DIB}$' # From Table 2 in Smith et al. (2013) _FEI_lines= [air2vac(l) for l in [15194.492,15207.526,15395.718,15490.339, 15648.510,15964.867,16040.657,16153.247, 16165.032]] _FEI_lines.append(16697.635) # one more from Shetrone # From Table 5 _MGI_lines= [air2vac(l) for l in [15740.716,15748.9,15765.8,15879.5, 15886.2,15954.477]] _ALI_lines= [air2vac(l) for l in [16718.957,16750.564286,16763.359]] _SII_lines= [air2vac(l) for l in [15361.161,15376.831,15833.602,15960.063, 16060.009,16094.787,16215.670,16680.770, 16828.159]] _KI_lines= [air2vac(l) for l in [15163.067,15168.376]] _CAI_lines= [air2vac(l) for l in [16136.823,16150.763,16155.236,16157.364]] _TII_lines= [air2vac(l) for l in [15543.756,15602.842,15698.979,15715.573, 16635.161]] _VI_lines= [air2vac(15925.)]
def synth(*args,**kwargs): """ NAME: synth PURPOSE: Generate model APOGEE spectra using Turbospectrum: this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'turbosynth' for a direct interface to Turbospectrum INPUT ARGUMENTS: lists with abundances differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros): [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N] [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N] ... [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N] INPUT KEYWORDS: LSF: lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web Either: xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo' dxlsf= (None) spacing of pixel offsets vmacro= (6.) macroturbulence to apply CONTINUUM: cont= ('aspcap') continuum-normalization to apply: None: no continuum normalization 'true': Use the true continuum 'aspcap': Use the continuum normalization method of ASPCAP DR12 'cannon': Normalize using continuum pixels derived from the Cannon SYNTHESIS: air= (True) if True, perform the synthesis in air wavelengths (output is still in vacuum); set to False at your own risk, as Turbospectrum expects the linelist in air wavelengths!) Hlinelist= (None) Hydrogen linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist; if None, then we first search for the Hlinedata.vac in the APOGEE linelist directory (if air=False) or we use the internal Turbospectrum Hlinelist (if air=True) linelist= (None) molecular and atomic linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist, or lists of such files; if a single filename is given, the code will first search for files with extensions '.atoms', '.molec' or that start with 'turboatoms.' and 'turbomolec.' wmin, wmax, dw= (15000.000, 17000.000, 0.10000000) spectral synthesis limits and step costheta= (1.) cosine of the viewing angle lib= ('kurucz_filled') spectral library MODEL ATMOSPHERE PARAMETERS: Specify one of the following: (a) modelatm= (None) model-atmosphere instance (b) parameters of a KURUCZ model atmosphere: (1) teff= (4500) Teff logg= (2.5) logg metals= (0.) metallicity cm= (0.) carbon-enhancement am= (0.) alpha-enhancement (2) fparam= standard ASPCAP output format lib= ('kurucz_filled') model atmosphere library vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam) MISCELLANEOUS: dr= return the path corresponding to this data release OUTPUT: spectra (nspec,nwave) HISTORY: 2015-04-16 - Written - Bovy (IAS) """ # Check that we have the LSF and store the relevant keywords lsf= kwargs.pop('lsf','all') if isinstance(lsf,str): xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf) dxlsf= None else: xlsf= kwargs.pop('xlsf',None) dxlsf= kwargs.pop('dxlsf',None) if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array') vmacro= kwargs.pop('vmacro',6.) # Parse continuum-normalization keywords cont= kwargs.pop('cont','aspcap') # Setup the model atmosphere modelatm= kwargs.pop('modelatm',None) # Parse fparam, if present fparam= kwargs.pop('fparam',None) if not fparam is None: kwargs['teff']= fparam[paramIndx('TEFF')] kwargs['logg']= fparam[paramIndx('LOGG')] kwargs['metals']= fparam[paramIndx('METALS')] kwargs['am']= fparam[paramIndx('ALPHA')] kwargs['cm']= fparam[paramIndx('C')] kwargs['vmicro']= 10.**fparam[paramIndx('LOG10VDOP')] # Need to pass a model atmosphere instance to turbosynth (needs to be made # more efficient, because now turbosynth always write the atmosphere if modelatm is None: # Setup a model atmosphere modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.), logg=kwargs.get('logg',2.5), metals=kwargs.get('metals',0.), am=kwargs.get('am',0.), cm=kwargs.get('cm',0.), dr=kwargs.get('dr',None)) if isinstance(modelatm,str) and os.path.exists(modelatm): raise ValueError('modelatm= input is an existing filename, but you need to give an Atmosphere object instead') elif isinstance(modelatm,str): raise ValueError('modelatm= input needs to be an Atmosphere instance') # Check temperature if modelatm._teff > 7000.: warnings.warn('Turbospectrum does not include all necessary physics to model stars hotter than about 7000 K; proceed with caution',RuntimeWarning) kwargs['modelatm']= modelatm try: # Run turbosynth for all abundances if len(args) == 0: #special case that there are *no* differences args= ([26,0.],) nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))]) nsynth= numpy.amax(nsynths) #Take the longest abundance list nturbowav= int((kwargs.get('wmax',_WMAX_DEFAULT)\ -kwargs.get('wmin',_WMIN_DEFAULT))\ /kwargs.get('dw',_DW_DEFAULT)+1) out= numpy.empty((nsynth,nturbowav)) for ii in range(nsynth): newargs= () for jj in range(len(args)): tab= [args[jj][0]] if len(args[jj]) > ii+1: tab.append(args[jj][ii+1]) newargs= newargs+(tab,) tmpOut= turbosynth(*newargs,**kwargs) out[ii]= tmpOut[2] # incl. continuum # wavelength grid from final one mwav= tmpOut[0] except: raise # If the synthesis was done in air, convert wavelength array if kwargs.get('air',True): mwav= numpy.array([air2vac(w) for w in list(mwav)]) # Now convolve with the LSF out= aplsf.convolve(mwav,out, lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro) # Now continuum-normalize if cont.lower() == 'true': # Get the true continuum on the apStar wavelength grid apWave= apStarWavegrid() baseline= numpy.polynomial.Polynomial.fit(mwav,tmpOut[2]/tmpOut[1],4) ip= interpolate.InterpolatedUnivariateSpline(mwav, tmpOut[2]/tmpOut[1]\ /baseline(mwav), k=3) cflux= baseline(apWave)*ip(apWave) # Divide it out out/= numpy.tile(cflux,(nsynth,1)) elif not cont is None: cflux= apcont.fit(out,numpy.ones_like(out),type=cont) out[cflux > 0.]/= cflux[cflux > 0.] out[cflux <= 0.]= numpy.nan return out
def windows(*args,**kwargs): """ NAME: windows PURPOSE: Generate model APOGEE spectra using Turbospectrum in selected wavelength windows (but the whole APOGEE spectral range is returned): this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'turbosynth' for a direct interface to Turbospectrum INPUT ARGUMENTS: Windows specification: Provide one of (1) Element string: the APOGEE windows for this element will be loaded (2) startindxs, endindxs= start and end indexes of the windows on the apStar wavelength grid (3) startlams, endlams= start and end wavelengths in \AA lists with abundance differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros): [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N] [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N] ... [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N] INPUT KEYWORDS: BASELINE: you can specify the baseline spectrum and the continuous opacity to not always re-compute it baseline= baseline c-normalized spectrum on Turbospectrum wavelength grid (obtained from turbosynth) mwav= Turbospectrum wavelength grid (obtained from turbosynth) cflux= continuum flux from Turbospectrum modelopac= (None) (a) if set to an existing filename: assume babsma_lu has already been run and use this continuous opacity in bsyn_lu (b) if set to a non-existing filename: store the continuous opacity in this file Typically, you can obtain these three keywords by doing (kwargs are the keywords you provide to this function as well, and includes modelopac='SOME FILENAME') >>> baseline= turbosynth(**kwargs) >>> mwav= baseline[0] >>> cflux= baseline[2]/baseline[1] >>> baseline= baseline[1] LSF: lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web Either: xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo' dxlsf= (None) spacing of pixel offsets vmacro= (6.) macroturbulence to apply CONTINUUM: cont= ('aspcap') continuum-normalization to apply: None: no continuum normalization 'true': Use the true continuum 'aspcap': Use the continuum normalization method of ASPCAP DR12 'cannon': Normalize using continuum pixels derived from the Cannon SYNTHESIS: air= (True) if True, perform the synthesis in air wavelengths (output is still in vacuum); set to False at your own risk, as Turbospectrum expects the linelist in air wavelengths!) Hlinelist= (None) Hydrogen linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist; if None, then we first search for the Hlinedata.vac in the APOGEE linelist directory (if air=False) or we use the internal Turbospectrum Hlinelist (if air=True) linelist= (None) molecular and atomic linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist, or lists of such files; if a single filename is given, the code will first search for files with extensions '.atoms', '.molec' or that start with 'turboatoms.' and 'turbomolec.' wmin, wmax, dw= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG) costheta= (1.) cosine of the viewing angle MODEL ATMOSPHERE PARAMETERS: Specify one of the following: (a) modelatm= (None) model-atmosphere instance (b) parameters of a KURUCZ model atmosphere: (1) teff= (4500) Teff logg= (2.5) logg metals= (0.) metallicity cm= (0.) carbon-enhancement am= (0.) alpha-enhancement (2) fparam= standard ASPCAP output format lib= ('kurucz_filled') model atmosphere library vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam) MISCELLANEOUS: dr= return the path corresponding to this data release raw= (False) if True, return the raw turbosynth output OUTPUT: spectra (nspec,nwave) (wavelengths,cont-norm. spectrum, spectrum (nwave)) if raw == True HISTORY: 2015-04-17 - Written - Bovy (IAS) """ # Pop some kwargs baseline= kwargs.pop('baseline',None) mwav= kwargs.pop('mwav',None) cflux= kwargs.pop('cflux',None) raw= kwargs.pop('raw',False) # Check that we have the LSF and store the relevant keywords lsf= kwargs.pop('lsf','all') if isinstance(lsf,str): xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf) dxlsf= None else: xlsf= kwargs.pop('xlsf',None) dxlsf= kwargs.pop('dxlsf',None) if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array') vmacro= kwargs.pop('vmacro',6.) # Parse continuum-normalization keywords cont= kwargs.pop('cont','aspcap') # Parse the wavelength regions apWave= apStarWavegrid() if isinstance(args[0],str): #element string given si,ei= apwindow.waveregions(args[0],pad=3,asIndex=True) args= args[1:] else: if isinstance(args[0][0],int): # assume index si,ei= args[0], args[1] else: # assume wavelengths in \AA sl,el= args[0], args[1] # Convert to index si, ei= [], [] for s,e in zip(sl,el): # Find closest index into apWave si.append(numpy.argmin(numpy.fabs(s-apWave))) ei.append(numpy.argmin(numpy.fabs(e-apWave))) args= args[2:] # Setup the model atmosphere modelatm= kwargs.pop('modelatm',None) # Parse fparam, if present fparam= kwargs.pop('fparam',None) if not fparam is None: kwargs['teff']= fparam[0,paramIndx('TEFF')] kwargs['logg']= fparam[0,paramIndx('LOGG')] kwargs['metals']= fparam[0,paramIndx('METALS')] kwargs['am']= fparam[0,paramIndx('ALPHA')] kwargs['cm']= fparam[0,paramIndx('C')] kwargs['vmicro']= 10.**fparam[0,paramIndx('LOG10VDOP')] # Need to pass a model atmosphere instance to turbosynth (needs to be made # more efficient, because now turbosynth always write the atmosphere if modelatm is None: # Setup a model atmosphere modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.), logg=kwargs.get('logg',2.5), metals=kwargs.get('metals',0.), am=kwargs.get('am',0.), cm=kwargs.get('cm',0.), dr=kwargs.get('dr',None)) if isinstance(modelatm,str) and os.path.exists(modelatm): raise ValueError('modelatm= input is an existing filename, but you need to give an Atmosphere object instead') elif isinstance(modelatm,str): raise ValueError('modelatm= input needs to be an Atmosphere instance') # Check temperature if modelatm._teff > 7000.: warnings.warn('Turbospectrum does not include all necessary physics to model stars hotter than about 7000 K; proceed with caution',RuntimeWarning) kwargs['modelatm']= modelatm try: rmModelopac= False if not 'modelopac' in kwargs: rmModelopac= True kwargs['modelopac']= tempfile.mktemp('mopac') # Make sure opacity is first calculated over the full wav. range kwargs['babsma_wmin']= 15000. kwargs['babsma_wmax']= 17000. elif 'modelopac' in kwargs and not isinstance(kwargs['modelopac'],str): raise ValueError('modelopac needs to be set to a filename') # Run synth for the whole wavelength range as a baseline if baseline is None or mwav is None or cflux is None: baseline= turbosynth(**kwargs) mwav= baseline[0] cflux= baseline[2]/baseline[1] baseline= baseline[1] elif isinstance(baseline,tuple): #probably accidentally gave the entire output of turbosynth mwav= baseline[0] cflux= baseline[2]/baseline[1] baseline= baseline[1] # Convert the apStarWavegrid windows to turboWavegrid regions sm,em= [], [] for start,end in zip(si,ei): if kwargs.get('air',True): sm.append(numpy.argmin(numpy.fabs(vac2air(apWave[start])-mwav))) em.append(numpy.argmin(numpy.fabs(vac2air(apWave[end])-mwav))) else: sm.append(numpy.argmin(numpy.fabs(apWave[start]-mwav))) em.append(numpy.argmin(numpy.fabs(apWave[end]-mwav))) # Run Turbospectrum synth for all abundances and all windows if len(args) == 0: #special case that there are *no* differences args= ([26,0.],) nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))]) nsynth= numpy.amax(nsynths) #Take the longest abundance list out= numpy.tile(baseline,(nsynth,1)) # Run all windows for start, end in zip(sm,em): kwargs['wmin']= mwav[start] kwargs['wmax']= mwav[end]+0.001 for ii in range(nsynth): newargs= () for jj in range(len(args)): tab= [args[jj][0]] if len(args[jj]) > ii+1: tab.append(args[jj][ii+1]) newargs= newargs+(tab,) tmpOut= turbosynth(*newargs,**kwargs) if numpy.isnan(tmpOut[1][-1]): # NaN returned for reasons that I don't understand out[ii,start:end]= tmpOut[1][:-1] else: out[ii,start:end+1]= tmpOut[1] except: raise finally: if rmModelopac and os.path.exists(kwargs['modelopac']): os.remove(kwargs['modelopac']) kwargs.pop('modelopac') # Now multiply each continuum-normalized spectrum with the continuum out*= numpy.tile(cflux,(nsynth,1)) if raw: return (mwav,out/numpy.tile(cflux,(nsynth,1)),out) # If the synthesis was done in air, convert wavelength array if kwargs.get('air',True): mwav= numpy.array([air2vac(w) for w in list(mwav)]) # Now convolve with the LSF out= aplsf.convolve(mwav,out, lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro) # Now continuum-normalize if cont.lower() == 'true': # Get the true continuum on the apStar wavelength grid apWave= apStarWavegrid() baseline= numpy.polynomial.Polynomial.fit(mwav,cflux,4) ip= interpolate.InterpolatedUnivariateSpline(mwav, cflux/baseline(mwav), k=3) cflux= baseline(apWave)*ip(apWave) # Divide it out out/= numpy.tile(cflux,(nsynth,1)) elif not cont is None: cflux= apcont.fit(out,numpy.ones_like(out),type=cont) out[cflux > 0.]/= cflux[cflux > 0.] out[cflux <= 0.]= numpy.nan return out
15958.836] _ALI_lines= [16723.524,16767.938] _SII_lines= [15365.359,15381.033,15837.928,15964.424,16064.397,16099.184, 16220.100,16685.327,16832.756] _KI_lines= [15167.211,15172.521] _CAI_lines= [16155.176,16159.650,16161.778] _TII_lines= [15548.003,15607.106,15703.269,15719.867,16639.705] _CRI_lines= [15684.348,15864.548,15470.129] _NII_lines= [15609.944,15636.926,16588.970,16593.827,16678.266,16820.064, 16823.354] _NAI_lines= [16378.346633274852,16393.340725803333] _MNI_lines= [15221.569] #_MNI_lines= [15677.437,16712.565,15163,15221] _SI_lines= [15406.540,15426.490,15474.043,15482.712] _VI_lines= [15929.2] _OH_lines= [air2vac(l) for l in [15279.5,15391.,15505.5,15570.5]] _CO_lines= [air2vac(l) for l in [15582.,15780.5,15988.,16189.5]] _CN_lines= [air2vac(l) for l in [15260.,15322.,15397.,15332.,15410., 15447.,15466.,15472.,15482.]] _13CO_lines= [air2vac(l) for l in [16122.5,16743.5]] _DIB_lines= [15272.42] #from Zasowski et al. (2014) def bovy_metallicity_gradient(plotfilename,savefilename,largewave=False): # First read the RC catalog and cut it to stars near the plane data= apread.rcsample() if _HIZ: indx= (numpy.fabs(data['RC_GALZ']) > 0.6)*(data['METALS'] > -1000.) else: indx= (numpy.fabs(data['RC_GALZ']) < 0.25)*(data['METALS'] > -1000.) data= data[indx] # Now go through bins in R Rmin, Rmax, dR= 5.5, 13., 0.1