Example #1
0
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
Example #2
0
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.)]
Example #3
0
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
Example #4
0
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
Example #5
0
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.)]
             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