Beispiel #1
0
def modelAtmosphere(lib='kurucz_filled',teff=4500,logg=2.5,metals=0.,
                    cfe=0.,nfe=0.,afe=0.,vmicro=2.,dr=None,spider=False):
    """
    NAME:
       modelAtmosphere
    PURPOSE:
       download a model atmosphere
    INPUT:
       lib= ('kurucz_filled') model atmosphere library
       teff= (4500) grid-point Teff
       logg= (2.5) grid-point logg
       metals= (0.) grid-point metallicity
       cfe= (0.) grid-point carbon-enhancement
       afe= (0.) grid-point alpha-enhancement
       vmicro= (2.) grid-point microturbulence
       dr= return the path corresponding to this data release
       spider= (False) if True, run wget as a spider (doesn't download)
    OUTPUT:
       (none; just downloads)
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    if dr is None: dr= 'current'
    # First make sure the file doesn't exist
    filePath= path.modelAtmospherePath(lib=lib,teff=teff,logg=logg,
                                       metals=metals,cfe=cfe,afe=afe,
                                       vmicro=2.,dr=dr)
    if os.path.exists(filePath): return None
    # Create the file path
    downloadPath= filePath.replace(os.path.join(path._APOGEE_DATA,
                                                _dr_string(dr)),
                                   _base_url(dr=dr))
    _download_file(downloadPath,filePath,dr,spider=spider)
    return None
Beispiel #2
0
def modelAtmosphere(lib='kurucz_filled',teff=4500,logg=2.5,metals=0.,
                    cfe=0.,nfe=0.,afe=0.,vmicro=2.,dr=None,spider=False):
    """
    NAME:
       modelAtmosphere
    PURPOSE:
       download a model atmosphere
    INPUT:
       lib= ('kurucz_filled') model atmosphere library
       teff= (4500) grid-point Teff
       logg= (2.5) grid-point logg
       metals= (0.) grid-point metallicity
       cfe= (0.) grid-point carbon-enhancement
       afe= (0.) grid-point alpha-enhancement
       vmicro= (2.) grid-point microturbulence
       dr= return the path corresponding to this data release
       spider= (False) if True, run wget as a spider (doesn't download)
    OUTPUT:
       (none; just downloads)
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    if dr is None: dr= 'current'
    # First make sure the file doesn't exist
    filePath= path.modelAtmospherePath(lib=lib,teff=teff,logg=logg,
                                       metals=metals,cfe=cfe,afe=afe,
                                       vmicro=2.,dr=dr)
    if os.path.exists(filePath): return None
    # Create the file path    
    downloadPath= filePath.replace(os.path.join(path._APOGEE_DATA,
                                                _dr_string(dr)),
                                   _base_url(dr=dr))
    _download_file(downloadPath,filePath,dr,spider=spider)
    return None
Beispiel #3
0
 def _loadGridPoint(self):
     """Load the model corresponding to this grid point"""
     filePath = appath.modelAtmospherePath(lib='kurucz_filled',
                                           teff=self._teff,
                                           logg=self._logg,
                                           metals=self._metals,
                                           cfe=self._cm,
                                           afe=self._am,
                                           dr=self._dr)
     # Download if necessary
     if not os.path.exists(filePath):
         apdownload.modelAtmosphere(lib='kurucz_filled',
                                    teff=self._teff,
                                    logg=self._logg,
                                    metals=self._metals,
                                    cfe=self._cm,
                                    afe=self._am,
                                    dr=self._dr)
     atContent = readAtlas9(filePath)
     # Unpack
     self._first4lines = atContent[0]
     self._abscale = atContent[1]
     self._abchanges = atContent[2]
     self._deck = atContent[3]
     self._pradk = atContent[4]
     self._nlayers = self._deck.shape[0]
     return None
Beispiel #4
0
def convert_modelAtmosphere(**kwargs):
    """
    NAME:
       convert_modelAtmosphere
    PURPOSE:
       Convert a model atmosphere to MOOG format
    INPUT:
       Either:
          (a) modelatm= (None) can be set to the filename of a model atmosphere
          (b) specify the stellar parameters for a grid point in model atm by
              - lib= ('kurucz_filled') spectral library
              - teff= (4500) grid-point Teff
              - logg= (2.5) grid-point logg
              - metals= (0.) grid-point metallicity
              - cfe= (0.) grid-point carbon-enhancement
              - afe= (0.) grid-point alpha-enhancement
              - dr= return the path corresponding to this data release
       vmicro= (2.) microturbulence (km/s) (only used if the MOOG-formatted atmosphere file doesn't already exist)
    OUTPUT:
       (none; just converts and caches the model atmosphere
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
       2015-03-21 - Adjusted to also work for off-grid atmosphers - Bovy (IAS)
    """
    # Get the filename of the model atmosphere
    modelatm = kwargs.pop('modelatm', None)
    if not modelatm is None:
        if isinstance(modelatm, str) and os.path.exists(modelatm):
            modelfilename = modelatm
        elif isinstance(modelatm, str):
            raise ValueError('modelatm= input is a non-existing filename')
        else:  # model atmosphere instance
            raise ValueError(
                'modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename = appath.modelAtmospherePath(**kwargs)
    modeldirname = os.path.dirname(modelfilename)
    modelbasename = os.path.basename(modelfilename)
    outname = modelbasename.replace('.mod', '.org')
    if os.path.exists(os.path.join(modeldirname, outname)): return None
    shutil.copy(
        os.path.join(os.path.dirname(os.path.realpath(__file__)),
                     'scripts/makemoogmodel.awk'), modeldirname)
    try:
        stdout = open(os.path.join(modeldirname, outname), 'w')
        stderr = open('/dev/null', 'w')
        subprocess.check_call([
            'awk', '-f', 'makemoogmodel.awk',
            'vmicro=%.1f' % kwargs.get('vmicro', 2.), modelfilename
        ],
                              cwd=modeldirname,
                              stdout=stdout,
                              stderr=stderr)
        stdout.close()
        stderr.close()
    except:
        raise
    finally:
        os.remove(os.path.join(modeldirname, 'makemoogmodel.awk'))
    return None
Beispiel #5
0
def convert_modelAtmosphere(**kwargs):
    """
    NAME:
       convert_modelAtmosphere
    PURPOSE:
       Convert a model atmosphere to MOOG format
    INPUT:
       Either:
          (a) modelatm= (None) can be set to the filename of a model atmosphere
          (b) specify the stellar parameters for a grid point in model atm by
              - lib= ('kurucz_filled') spectral library
              - teff= (4500) grid-point Teff
              - logg= (2.5) grid-point logg
              - metals= (0.) grid-point metallicity
              - cfe= (0.) grid-point carbon-enhancement
              - afe= (0.) grid-point alpha-enhancement
              - dr= return the path corresponding to this data release
       vmicro= (2.) microturbulence (km/s) (only used if the MOOG-formatted atmosphere file doesn't already exist)
    OUTPUT:
       (none; just converts and caches the model atmosphere
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
       2015-03-21 - Adjusted to also work for off-grid atmosphers - Bovy (IAS)
    """
    # Get the filename of the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    if not modelatm is None:
        if isinstance(modelatm,str) and os.path.exists(modelatm):
            modelfilename= modelatm
        elif isinstance(modelatm,str):
            raise ValueError('modelatm= input is a non-existing filename')
        else: # model atmosphere instance
            raise ValueError('modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename= appath.modelAtmospherePath(**kwargs)
    modeldirname= os.path.dirname(modelfilename)
    modelbasename= os.path.basename(modelfilename)
    outname= modelbasename.replace('.mod','.org')
    if os.path.exists(os.path.join(modeldirname,outname)): return None
    shutil.copy(os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             'scripts/makemoogmodel.awk'),modeldirname)
    try:
        stdout= open(os.path.join(modeldirname,outname),'w')
        stderr= open('/dev/null','w')
        subprocess.check_call(['awk','-f','makemoogmodel.awk',
                               'vmicro=%.1f' % kwargs.get('vmicro',2.),
                               modelfilename],
                              cwd=modeldirname,
                              stdout=stdout,stderr=stderr)
        stdout.close()
        stderr.close()
    except: raise
    finally:
        os.remove(os.path.join(modeldirname,'makemoogmodel.awk'))
    return None
Beispiel #6
0
 def _loadGridPoint(self):
     """Load the model corresponding to this grid point"""
     filePath= appath.modelAtmospherePath(lib='kurucz_filled',
                                          teff=self._teff,logg=self._logg,
                                          metals=self._metals,
                                          cfe=self._cm,afe=self._am,
                                          dr=self._dr)
     # Download if necessary
     if not os.path.exists(filePath):
         apdownload.modelAtmosphere(lib='kurucz_filled',
                                    teff=self._teff,logg=self._logg,
                                    metals=self._metals,
                                    cfe=self._cm,afe=self._am,dr=self._dr)
     atContent= readAtlas9(filePath)
     # Unpack
     self._first4lines= atContent[0]
     self._abscale= atContent[1]
     self._abchanges= atContent[2]
     self._deck= atContent[3]
     self._pradk= atContent[4]
     self._nlayers= self._deck.shape[0]
     return None
Beispiel #7
0
def moogsynth(*args,**kwargs):
    """
    NAME:
       moogsynth
    PURPOSE:
       Run a MOOG synthesis (direct interface to the MOOG code; use 'synth' for a general routine that generates the non-continuum-normalized spectrum, convolves withe LSF and macrotubulence, and optionally continuum normalizes the output)
    INPUT ARGUMENTS:
       lists with abundances (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]
    SYNTHEIS KEYWORDS:
       isotopes= ('solar') use 'solar' or 'arcturus' isotope ratios; can also be a dictionary with isotope ratios (e.g., isotopes= {'108.00116':'1.001','606.01212':'1.01'})
       wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
       doflux= (False) if True, calculate the continuum flux instead
    LINELIST KEYWORDS:
       linelist= (None) linelist to use; if this is None, the code looks for a weed-out version of the linelist appropriate for the given model atmosphere; otherwise can be set to the path of a linelist file or to the name of an APOGEE linelist
    ATMOSPHERE KEYWORDS:
       Either:
          (a) modelatm= (None) can be set to the filename of a model atmosphere (needs to end in .mod)
          (b) specify the stellar parameters for a grid point in model atm by
              - lib= ('kurucz_filled') spectral library
              - teff= (4500) grid-point Teff
              - logg= (2.5) grid-point logg
              - metals= (0.) grid-point metallicity
              - cm= (0.) grid-point carbon-enhancement
              - am= (0.) grid-point alpha-enhancement
              - dr= return the path corresponding to this data release
       vmicro= (2.) microturbulence (km/s) (only used if the MOOG-formatted atmosphere file doesn't already exist)
    OUTPUT:
       (wavelengths,spectra (nspec,nwave)) for synth driver
       (wavelengths,continuum spectr (nwave)) for doflux driver     
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    doflux= kwargs.pop('doflux',False)
    # Get the spectral synthesis limits
    wmin= kwargs.pop('wmin',_WMIN_DEFAULT)
    wmax= kwargs.pop('wmax',_WMAX_DEFAULT)
    dw= kwargs.pop('dw',_DW_DEFAULT)
    width= kwargs.pop('width',_WIDTH_DEFAULT)
    linelist= kwargs.pop('linelist',None)
    # Parse isotopes
    isotopes= kwargs.pop('isotopes','solar')
    if isinstance(isotopes,str) and isotopes.lower() == 'solar':
        isotopes= {'108.00116':'1.001',
                   '606.01212':'1.01',
                   '606.01213':'90',
                   '606.01313':'180',
                   '607.01214':'1.01',
                   '607.01314':'90',
                   '607.01215':'273',
                   '608.01216':'1.01',
                   '608.01316':'90',
                   '608.01217':'1101',
                   '608.01218':'551',
                   '114.00128':'1.011',
                   '114.00129':'20',
                   '114.00130':'30',
                   '101.00101':'1.001',
                   '101.00102':'1000',
                   '126.00156':'1.00'}
    elif isinstance(isotopes,str) and isotopes.lower() == 'arcturus':
        isotopes= {'108.00116':'1.001',
                   '606.01212':'0.91',
                   '606.01213':'8',
                   '606.01313':'81',
                   '607.01214':'0.91',
                   '607.01314':'8',
                   '607.01215':'273',
                   '608.01216':'0.91',
                   '608.01316':'8',
                   '608.01217':'1101',
                   '608.01218':'551',
                   '114.00128':'1.011',
                   '114.00129':'20',
                   '114.00130':'30',
                   '101.00101':'1.001',
                   '101.00102':'1000',
                   '126.00156':'1.00'}
    elif not isinstance(isotopes,dict):
        raise ValueError("'isotopes=' input not understood, should be 'solar', 'arcturus', or a dictionary")
    # Get the filename of the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    if not modelatm is None:
        if isinstance(modelatm,str) and os.path.exists(modelatm):
            modelfilename= modelatm
        elif isinstance(modelatm,str):
            raise ValueError('modelatm= input is a non-existing filename')
        else:
            raise ValueError('modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename= appath.modelAtmospherePath(**kwargs)
    # Check whether a MOOG version exists
    if not os.path.exists(modelfilename.replace('.mod','.org')):
        # Convert to MOOG format
        convert_modelAtmosphere(modelatm=modelfilename,**kwargs)
    modeldirname= os.path.dirname(modelfilename)
    modelbasename= os.path.basename(modelfilename)
    # Get the name of the linelist
    if linelist is None:
        linelistfilename= modelbasename.replace('.mod','.lines')
        if not os.path.exists(os.path.join(modeldirname,linelistfilename)):
            raise IOError('No linelist given and no weed-out version found for this atmosphere; either specify a linelist or run weedout first')
        linelistfilename= os.path.join(modeldirname,linelistfilename)
    elif os.path.exists(linelist):
        linelistfilename= linelist
    else:
        linelistfilename= appath.linelistPath(linelist,
                                              dr=kwargs.get('dr',None))
    # We will run in a subdirectory of the relevant model atmosphere
    tmpDir= tempfile.mkdtemp(dir=modeldirname)
    shutil.copy(linelistfilename,tmpDir)
    # Cut the linelist to the desired wavelength range
    with open(os.path.join(tmpDir,'cutlines.awk'),'w') as awkfile:
        awkfile.write('$1>%.3f && $1<%.3f\n' %(wmin-width,wmax+width))
    keeplines= open(os.path.join(tmpDir,'lines.tmp'),'w')
    stderr= open('/dev/null','w')
    try:
        subprocess.check_call(['awk','-f','cutlines.awk',
                               os.path.basename(linelistfilename)],
                              cwd=tmpDir,stdout=keeplines,stderr=stderr)
        keeplines.close()
        shutil.copy(os.path.join(tmpDir,'lines.tmp'),
                    os.path.join(tmpDir,os.path.basename(linelistfilename)))
    except subprocess.CalledProcessError:
        print("Removing unnecessary linelist entries failed ...")
    finally:
        os.remove(os.path.join(tmpDir,'cutlines.awk'))
        os.remove(os.path.join(tmpDir,'lines.tmp'))
        stderr.close()
    # Also copy the strong lines
    stronglinesfilename= appath.linelistPath('stronglines.vac',
                                             dr=kwargs.get('dr',None))
    if not os.path.exists(stronglinesfilename):
        download.linelist('stronglines.vac',dr=kwargs.get('dr',None))
    shutil.copy(stronglinesfilename,tmpDir)
    # Now write the script file
    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
    if nsynth > 5:
        raise ValueError("MOOG only allows five syntheses to be run at the same time; please reduce the number of abundance values in the apogee.modelspec.moog.moogsynth input")
    nabu= len(args)
    with open(os.path.join(tmpDir,'synth.par'),'w') as parfile:
        if doflux:
            parfile.write('doflux\n')
        else:
            parfile.write('synth\n')
        parfile.write('terminal x11\n')
        parfile.write('plot 1\n')
        parfile.write("standard_out std.out\n")
        parfile.write("summary_out '../synth.out'\n")
        parfile.write("smoothed_out '/dev/null'\n")
        parfile.write("strong 1\n")
        parfile.write("damping 0\n")
        parfile.write("stronglines_in stronglines.vac\n")
        parfile.write("model_in '../%s'\n" % modelbasename.replace('.mod','.org'))
        parfile.write("lines_in %s\n" % os.path.basename(linelistfilename))
        parfile.write("atmosphere 1\n")
        parfile.write("molecules 2\n")
        parfile.write("lines 1\n")
        parfile.write("flux/int 0\n")
        # Write the isotopes
        niso= len(isotopes)
        parfile.write("isotopes %i %i\n" % (niso,nsynth))
        for iso in isotopes:
            isotopestr= iso
            for ii in range(nsynth):
                isotopestr+= ' '+isotopes[iso]
            parfile.write(isotopestr+'\n')
        # Abundances
        parfile.write("abundances %i %i\n" % (nabu,nsynth))
        for ii in range(nabu):
            abustr= '%i' % args[ii][0]
            for jj in range(nsynth):
                try:
                    abustr+= ' %.3f' % args[ii][jj+1]
                except IndexError:
                    abustr+= ' 0.0'
            parfile.write(abustr+"\n")
        # Synthesis limits
        parfile.write("synlimits\n") # Add 0.001 to make sure wmax is included
        parfile.write("%.3f  %.3f  %.3f  %.3f\n" % (wmin,wmax+0.001,dw,width))
    # Now run synth
    sys.stdout.write('\r'+"Running MOOG synth ...\r")
    sys.stdout.flush()
    try:
        p= subprocess.Popen(['moogsilent'],
                            cwd=tmpDir,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
        p.stdin.write('synth.par\n')
        stdout, stderr= p.communicate()
    except subprocess.CalledProcessError:
        print("Running synth failed ...")
    finally:
        if os.path.exists(os.path.join(tmpDir,'synth.par')):
            os.remove(os.path.join(tmpDir,'synth.par'))
        if os.path.exists(os.path.join(tmpDir,'std.out')):
            os.remove(os.path.join(tmpDir,'std.out'))
        if os.path.exists(os.path.join(tmpDir,
                                       os.path.basename(linelistfilename))):
            os.remove(os.path.join(tmpDir,os.path.basename(linelistfilename)))
        if os.path.exists(os.path.join(tmpDir,'stronglines.vac')):
            os.remove(os.path.join(tmpDir,'stronglines.vac'))
        os.rmdir(tmpDir)
        sys.stdout.write('\r'+download._ERASESTR+'\r')
        sys.stdout.flush()        
    # Now read the output
    wavs= numpy.arange(wmin,wmax+dw,dw)
    if wavs[-1] > wmax+dw/2.: wavs= wavs[:-1]
    if doflux:
        contdata= numpy.loadtxt(os.path.join(modeldirname,'synth.out'),
                                converters={0:lambda x: x.replace('D','E'),
                                            1:lambda x: x.replace('D','E')},
                                usecols=[0,1])
        # Wavelength in summary file appears to be wrong from comparing to 
        # the standard output file
        out= contdata[:,1]
        out/= numpy.nanmean(out) # Make the numbers more manageable
    else:
        with open(os.path.join(modeldirname,'synth.out')) as summfile:
            out= numpy.empty((nsynth,len(wavs)))
            for ii in range(nsynth):
                # Skip to beginning of synthetic spectrum
                while True:
                    line= summfile.readline()
                    if line[0] == 'M': break
                summfile.readline()
                tout= []
                while True:
                    line= summfile.readline()
                    if not line or line[0] == 'A': break
                    tout.extend([float(s) for s in line.split()])
                out[ii]= numpy.array(tout)
    os.remove(os.path.join(modeldirname,'synth.out'))
    if doflux:
        return (wavs,out)
    else:
        return (wavs,1.-out)
Beispiel #8
0
def weedout(**kwargs):
    """
    NAME:
       weedout
    PURPOSE:
       Weed-out unnecessary lines from the linelist for a given atmosphere
    INPUT:
       linelist= (None) linelist to use; can be set to the path of a linelist file or to the name of an APOGEE linelist
       keepratio= (0.00001) Eliminate lines weaker than keepratio where keepratio = kapnu/kaplam at the approximate line wavelength, calculated at a continuue optical depth of 0.5
       wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere (needs to end in .mod)
             ( b) parameters of a KURUCZ model atmosphere:
                  teff= (4500) Teff
                  logg= (2.5) logg
                  metals= (0.) metallicity
                  cm= (0.) carbon-enhancement
                  am= (0.) alpha-enhancement
                  lib= ('kurucz_filled') model atmosphere library
                  dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found)
    OUTPUT:
       (none; just weeds out lines)
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    # Get the name of the linelist
    linelist= kwargs.pop('linelist','moog.201312161124.vac')
    if os.path.exists(linelist):
        linelistfilename= linelist
    else:
        linelistfilename= appath.linelistPath(linelist,
                                              dr=kwargs.get('dr',None))
    # Get the spectral synthesis limits
    wmin= kwargs.pop('wmin',_WMIN_DEFAULT)
    wmax= kwargs.pop('wmax',_WMAX_DEFAULT)
    dw= kwargs.pop('dw',_DW_DEFAULT)
    width= kwargs.pop('width',_WIDTH_DEFAULT)
    # Ratio of lines to keep
    keepratio= kwargs.pop('keepratio',0.00001)
    # Get the filename of the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    if not modelatm is None:
        if isinstance(modelatm,str) and os.path.exists(modelatm):
            modelfilename= modelatm
        elif isinstance(modelatm,str):
            raise ValueError('modelatm= input is a non-existing filename')
        else:
            raise ValueError('modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename= appath.modelAtmospherePath(**kwargs)
    # Check whether a MOOG version exists
    if not os.path.exists(modelfilename.replace('.mod','.org')):
        # Convert to MOOG format
        convert_modelAtmosphere(modelatm=modelfilename,**kwargs)
    modeldirname= os.path.dirname(modelfilename)
    modelbasename= os.path.basename(modelfilename)
    outname= modelbasename.replace('.mod','.lines')
    # We will run in a subdirectory of the relevant model atmosphere
    tmpDir= tempfile.mkdtemp(dir=modeldirname)
    shutil.copy(linelistfilename,tmpDir)
    # Now write the script file
    with open(os.path.join(tmpDir,'weedout.par'),'w') as parfile:
        parfile.write('weedout\n')
        parfile.write('terminal x11\n')
        parfile.write('plot 0\n')
        parfile.write("standard_out '/dev/null'\n")
        parfile.write("keeplines_out  '../%s'\n" % outname)
        parfile.write("tosslines_out 'toss.out'\n")
        parfile.write("summary_out '/dev/null'\n")
        parfile.write("smoothed_out '/dev/null'\n")
        parfile.write("damping 0\n")
        parfile.write("model_in '../%s'\n" % modelbasename.replace('.mod','.org'))
        parfile.write("lines_in %s\n" % os.path.basename(linelistfilename))
        parfile.write("atmosphere 1\n")
        parfile.write("molecules 2\n")
        parfile.write("lines 1\n")
        parfile.write("flux/int 0\n")
        parfile.write("synlimits\n")
        parfile.write("%.3f  %.3f  %.3f  %.3f\n" % (wmin,wmax,dw,width))
    # Now run weedout
    sys.stdout.write('\r'+"Running MOOG weedout ...\r")
    sys.stdout.flush()
    try:
        p= subprocess.Popen(['moogsilent'],
                            cwd=tmpDir,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
        p.stdin.write('weedout.par\n')
        p.stdin.write('%g\n' % keepratio)
        stdout, stderr= p.communicate()
    except subprocess.CalledProcessError:
        print("Running weedout failed ...")
    finally:
        if os.path.exists(os.path.join(tmpDir,'weedout.par')):
            os.remove(os.path.join(tmpDir,'weedout.par'))
        if os.path.exists(os.path.join(tmpDir,'toss.out')):
            os.remove(os.path.join(tmpDir,'toss.out'))
        if os.path.exists(os.path.join(tmpDir,
                                       os.path.basename(linelistfilename))):
            os.remove(os.path.join(tmpDir,os.path.basename(linelistfilename)))
        os.rmdir(tmpDir)
        sys.stdout.write('\r'+"Running MOOG weedout ...\r")
        sys.stdout.flush()
    return None
Beispiel #9
0
def moogsynth(*args, **kwargs):
    """
    NAME:
       moogsynth
    PURPOSE:
       Run a MOOG synthesis (direct interface to the MOOG code; use 'synth' for a general routine that generates the non-continuum-normalized spectrum, convolves withe LSF and macrotubulence, and optionally continuum normalizes the output)
    INPUT ARGUMENTS:
       lists with abundances (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]
    SYNTHEIS KEYWORDS:
       isotopes= ('solar') use 'solar' or 'arcturus' isotope ratios; can also be a dictionary with isotope ratios (e.g., isotopes= {'108.00116':'1.001','606.01212':'1.01'})
       wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
       doflux= (False) if True, calculate the continuum flux instead
    LINELIST KEYWORDS:
       linelist= (None) linelist to use; if this is None, the code looks for a weed-out version of the linelist appropriate for the given model atmosphere; otherwise can be set to the path of a linelist file or to the name of an APOGEE linelist
    ATMOSPHERE KEYWORDS:
       Either:
          (a) modelatm= (None) can be set to the filename of a model atmosphere (needs to end in .mod)
          (b) specify the stellar parameters for a grid point in model atm by
              - lib= ('kurucz_filled') spectral library
              - teff= (4500) grid-point Teff
              - logg= (2.5) grid-point logg
              - metals= (0.) grid-point metallicity
              - cm= (0.) grid-point carbon-enhancement
              - am= (0.) grid-point alpha-enhancement
              - dr= return the path corresponding to this data release
       vmicro= (2.) microturbulence (km/s) (only used if the MOOG-formatted atmosphere file doesn't already exist)
    OUTPUT:
       (wavelengths,spectra (nspec,nwave)) for synth driver
       (wavelengths,continuum spectr (nwave)) for doflux driver     
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    doflux = kwargs.pop('doflux', False)
    # Get the spectral synthesis limits
    wmin = kwargs.pop('wmin', _WMIN_DEFAULT)
    wmax = kwargs.pop('wmax', _WMAX_DEFAULT)
    dw = kwargs.pop('dw', _DW_DEFAULT)
    width = kwargs.pop('width', _WIDTH_DEFAULT)
    linelist = kwargs.pop('linelist', None)
    # Parse isotopes
    isotopes = kwargs.pop('isotopes', 'solar')
    if isinstance(isotopes, str) and isotopes.lower() == 'solar':
        isotopes = {
            '108.00116': '1.001',
            '606.01212': '1.01',
            '606.01213': '90',
            '606.01313': '180',
            '607.01214': '1.01',
            '607.01314': '90',
            '607.01215': '273',
            '608.01216': '1.01',
            '608.01316': '90',
            '608.01217': '1101',
            '608.01218': '551',
            '114.00128': '1.011',
            '114.00129': '20',
            '114.00130': '30',
            '101.00101': '1.001',
            '101.00102': '1000',
            '126.00156': '1.00'
        }
    elif isinstance(isotopes, str) and isotopes.lower() == 'arcturus':
        isotopes = {
            '108.00116': '1.001',
            '606.01212': '0.91',
            '606.01213': '8',
            '606.01313': '81',
            '607.01214': '0.91',
            '607.01314': '8',
            '607.01215': '273',
            '608.01216': '0.91',
            '608.01316': '8',
            '608.01217': '1101',
            '608.01218': '551',
            '114.00128': '1.011',
            '114.00129': '20',
            '114.00130': '30',
            '101.00101': '1.001',
            '101.00102': '1000',
            '126.00156': '1.00'
        }
    elif not isinstance(isotopes, dict):
        raise ValueError(
            "'isotopes=' input not understood, should be 'solar', 'arcturus', or a dictionary"
        )
    # Get the filename of the model atmosphere
    modelatm = kwargs.pop('modelatm', None)
    if not modelatm is None:
        if isinstance(modelatm, str) and os.path.exists(modelatm):
            modelfilename = modelatm
        elif isinstance(modelatm, str):
            raise ValueError('modelatm= input is a non-existing filename')
        else:
            raise ValueError(
                'modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename = appath.modelAtmospherePath(**kwargs)
    # Check whether a MOOG version exists
    if not os.path.exists(modelfilename.replace('.mod', '.org')):
        # Convert to MOOG format
        convert_modelAtmosphere(modelatm=modelfilename, **kwargs)
    modeldirname = os.path.dirname(modelfilename)
    modelbasename = os.path.basename(modelfilename)
    # Get the name of the linelist
    if linelist is None:
        linelistfilename = modelbasename.replace('.mod', '.lines')
        if not os.path.exists(os.path.join(modeldirname, linelistfilename)):
            raise IOError(
                'No linelist given and no weed-out version found for this atmosphere; either specify a linelist or run weedout first'
            )
        linelistfilename = os.path.join(modeldirname, linelistfilename)
    elif os.path.exists(linelist):
        linelistfilename = linelist
    else:
        linelistfilename = appath.linelistPath(linelist,
                                               dr=kwargs.get('dr', None))
    if not os.path.exists(linelistfilename):
        raise RuntimeError(
            "Linelist %s not found; download linelist w/ apogee.tools.download.linelist (if you have access)"
            % linelistfilename)
    # We will run in a subdirectory of the relevant model atmosphere
    tmpDir = tempfile.mkdtemp(dir=modeldirname)
    shutil.copy(linelistfilename, tmpDir)
    # Cut the linelist to the desired wavelength range
    with open(os.path.join(tmpDir, 'cutlines.awk'), 'w') as awkfile:
        awkfile.write('$1>%.3f && $1<%.3f\n' % (wmin - width, wmax + width))
    keeplines = open(os.path.join(tmpDir, 'lines.tmp'), 'w')
    stderr = open('/dev/null', 'w')
    try:
        subprocess.check_call(
            ['awk', '-f', 'cutlines.awk',
             os.path.basename(linelistfilename)],
            cwd=tmpDir,
            stdout=keeplines,
            stderr=stderr)
        keeplines.close()
        shutil.copy(os.path.join(tmpDir, 'lines.tmp'),
                    os.path.join(tmpDir, os.path.basename(linelistfilename)))
    except subprocess.CalledProcessError:
        print("Removing unnecessary linelist entries failed ...")
    finally:
        os.remove(os.path.join(tmpDir, 'cutlines.awk'))
        os.remove(os.path.join(tmpDir, 'lines.tmp'))
        stderr.close()
    # Also copy the strong lines
    stronglinesfilename = appath.linelistPath('stronglines.vac',
                                              dr=kwargs.get('dr', None))
    if not os.path.exists(stronglinesfilename):
        try:
            download.linelist('stronglines.vac', dr=kwargs.get('dr', None))
        except:
            raise RuntimeError(
                "Linelist stronglines.vac not found or downloading failed; download linelist w/ apogee.tools.download.linelist (if you have access)"
            )
        finally:
            if os.path.exists(os.path.join(tmpDir, 'synth.par')):
                os.remove(os.path.join(tmpDir, 'synth.par'))
            if os.path.exists(os.path.join(tmpDir, 'std.out')):
                os.remove(os.path.join(tmpDir, 'std.out'))
            if os.path.exists(
                    os.path.join(tmpDir, os.path.basename(linelistfilename))):
                os.remove(
                    os.path.join(tmpDir, os.path.basename(linelistfilename)))
            if os.path.exists(os.path.join(tmpDir, 'stronglines.vac')):
                os.remove(os.path.join(tmpDir, 'stronglines.vac'))
            os.rmdir(tmpDir)
    shutil.copy(stronglinesfilename, tmpDir)
    # Now write the script file
    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
    if nsynth > 5:
        raise ValueError(
            "MOOG only allows five syntheses to be run at the same time; please reduce the number of abundance values in the apogee.modelspec.moog.moogsynth input"
        )
    nabu = len(args)
    with open(os.path.join(tmpDir, 'synth.par'), 'w') as parfile:
        if doflux:
            parfile.write('doflux\n')
        else:
            parfile.write('synth\n')
        parfile.write('terminal x11\n')
        parfile.write('plot 1\n')
        parfile.write("standard_out std.out\n")
        parfile.write("summary_out '../synth.out'\n")
        parfile.write("smoothed_out '/dev/null'\n")
        parfile.write("strong 1\n")
        parfile.write("damping 0\n")
        parfile.write("stronglines_in stronglines.vac\n")
        parfile.write("model_in '../%s'\n" %
                      modelbasename.replace('.mod', '.org'))
        parfile.write("lines_in %s\n" % os.path.basename(linelistfilename))
        parfile.write("atmosphere 1\n")
        parfile.write("molecules 2\n")
        parfile.write("lines 1\n")
        parfile.write("flux/int 0\n")
        # Write the isotopes
        niso = len(isotopes)
        parfile.write("isotopes %i %i\n" % (niso, nsynth))
        for iso in isotopes:
            isotopestr = iso
            for ii in range(nsynth):
                isotopestr += ' ' + isotopes[iso]
            parfile.write(isotopestr + '\n')
        # Abundances
        parfile.write("abundances %i %i\n" % (nabu, nsynth))
        for ii in range(nabu):
            abustr = '%i' % args[ii][0]
            for jj in range(nsynth):
                try:
                    abustr += ' %.3f' % args[ii][jj + 1]
                except IndexError:
                    abustr += ' 0.0'
            parfile.write(abustr + "\n")
        # Synthesis limits
        parfile.write("synlimits\n")  # Add 0.001 to make sure wmax is included
        parfile.write("%.3f  %.3f  %.3f  %.3f\n" %
                      (wmin, wmax + 0.001, dw, width))
    # Now run synth
    sys.stdout.write('\r' + "Running MOOG synth ...\r")
    sys.stdout.flush()
    try:
        p = subprocess.Popen(['moogsilent'],
                             cwd=tmpDir,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        p.stdin.write('synth.par\n')
        stdout, stderr = p.communicate()
    except subprocess.CalledProcessError:
        print("Running synth failed ...")
    finally:
        if os.path.exists(os.path.join(tmpDir, 'synth.par')):
            os.remove(os.path.join(tmpDir, 'synth.par'))
        if os.path.exists(os.path.join(tmpDir, 'std.out')):
            os.remove(os.path.join(tmpDir, 'std.out'))
        if os.path.exists(
                os.path.join(tmpDir, os.path.basename(linelistfilename))):
            os.remove(os.path.join(tmpDir, os.path.basename(linelistfilename)))
        if os.path.exists(os.path.join(tmpDir, 'stronglines.vac')):
            os.remove(os.path.join(tmpDir, 'stronglines.vac'))
        os.rmdir(tmpDir)
        sys.stdout.write('\r' + download._ERASESTR + '\r')
        sys.stdout.flush()
    # Now read the output
    wavs = numpy.arange(wmin, wmax + dw, dw)
    if wavs[-1] > wmax + dw / 2.: wavs = wavs[:-1]
    if doflux:
        contdata = numpy.loadtxt(os.path.join(modeldirname, 'synth.out'),
                                 converters={
                                     0: lambda x: x.replace('D', 'E'),
                                     1: lambda x: x.replace('D', 'E')
                                 },
                                 usecols=[0, 1])
        # Wavelength in summary file appears to be wrong from comparing to
        # the standard output file
        out = contdata[:, 1]
        out /= numpy.nanmean(out)  # Make the numbers more manageable
    else:
        with open(os.path.join(modeldirname, 'synth.out')) as summfile:
            out = numpy.empty((nsynth, len(wavs)))
            for ii in range(nsynth):
                # Skip to beginning of synthetic spectrum
                while True:
                    line = summfile.readline()
                    if line[0] == 'M': break
                summfile.readline()
                tout = []
                while True:
                    line = summfile.readline()
                    if not line or line[0] == 'A': break
                    tout.extend([float(s) for s in line.split()])
                out[ii] = numpy.array(tout)
    os.remove(os.path.join(modeldirname, 'synth.out'))
    if doflux:
        return (wavs, out)
    else:
        return (wavs, 1. - out)
Beispiel #10
0
def weedout(**kwargs):
    """
    NAME:
       weedout
    PURPOSE:
       Weed-out unnecessary lines from the linelist for a given atmosphere
    INPUT:
       linelist= (None) linelist to use; can be set to the path of a linelist file or to the name of an APOGEE linelist
       keepratio= (0.00001) Eliminate lines weaker than keepratio where keepratio = kapnu/kaplam at the approximate line wavelength, calculated at a continuue optical depth of 0.5
       wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere (needs to end in .mod)
             ( b) parameters of a KURUCZ model atmosphere:
                  teff= (4500) Teff
                  logg= (2.5) logg
                  metals= (0.) metallicity
                  cm= (0.) carbon-enhancement
                  am= (0.) alpha-enhancement
                  lib= ('kurucz_filled') model atmosphere library
                  dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found)
    OUTPUT:
       (none; just weeds out lines)
    HISTORY:
       2015-02-13 - Written - Bovy (IAS)
    """
    # Get the name of the linelist
    linelist = kwargs.pop('linelist', 'moog.201312161124.vac')
    if os.path.exists(linelist):
        linelistfilename = linelist
    else:
        linelistfilename = appath.linelistPath(linelist,
                                               dr=kwargs.get('dr', None))
    if not os.path.exists(linelistfilename):
        raise RuntimeError(
            "Linelist %s not found; download linelist w/ apogee.tools.download.linelist (if you have access)"
            % linelistfilename)
    # Get the spectral synthesis limits
    wmin = kwargs.pop('wmin', _WMIN_DEFAULT)
    wmax = kwargs.pop('wmax', _WMAX_DEFAULT)
    dw = kwargs.pop('dw', _DW_DEFAULT)
    width = kwargs.pop('width', _WIDTH_DEFAULT)
    # Ratio of lines to keep
    keepratio = kwargs.pop('keepratio', 0.00001)
    # Get the filename of the model atmosphere
    modelatm = kwargs.pop('modelatm', None)
    if not modelatm is None:
        if isinstance(modelatm, str) and os.path.exists(modelatm):
            modelfilename = modelatm
        elif isinstance(modelatm, str):
            raise ValueError('modelatm= input is a non-existing filename')
        else:
            raise ValueError(
                'modelatm= in moogsynth should be set to the name of a file')
    else:
        modelfilename = appath.modelAtmospherePath(**kwargs)
    # Check whether a MOOG version exists
    if not os.path.exists(modelfilename.replace('.mod', '.org')):
        # Convert to MOOG format
        convert_modelAtmosphere(modelatm=modelfilename, **kwargs)
    modeldirname = os.path.dirname(modelfilename)
    modelbasename = os.path.basename(modelfilename)
    outname = modelbasename.replace('.mod', '.lines')
    # We will run in a subdirectory of the relevant model atmosphere
    tmpDir = tempfile.mkdtemp(dir=modeldirname)
    shutil.copy(linelistfilename, tmpDir)
    # Now write the script file
    with open(os.path.join(tmpDir, 'weedout.par'), 'w') as parfile:
        parfile.write('weedout\n')
        parfile.write('terminal x11\n')
        parfile.write('plot 0\n')
        parfile.write("standard_out '/dev/null'\n")
        parfile.write("keeplines_out  '../%s'\n" % outname)
        parfile.write("tosslines_out 'toss.out'\n")
        parfile.write("summary_out '/dev/null'\n")
        parfile.write("smoothed_out '/dev/null'\n")
        parfile.write("damping 0\n")
        parfile.write("model_in '../%s'\n" %
                      modelbasename.replace('.mod', '.org'))
        parfile.write("lines_in %s\n" % os.path.basename(linelistfilename))
        parfile.write("atmosphere 1\n")
        parfile.write("molecules 2\n")
        parfile.write("lines 1\n")
        parfile.write("flux/int 0\n")
        parfile.write("synlimits\n")
        parfile.write("%.3f  %.3f  %.3f  %.3f\n" % (wmin, wmax, dw, width))
    # Now run weedout
    sys.stdout.write('\r' + "Running MOOG weedout ...\r")
    sys.stdout.flush()
    try:
        p = subprocess.Popen(['moogsilent'],
                             cwd=tmpDir,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        p.stdin.write('weedout.par\n')
        p.stdin.write('%g\n' % keepratio)
        stdout, stderr = p.communicate()
    except subprocess.CalledProcessError:
        print("Running weedout failed ...")
    finally:
        if os.path.exists(os.path.join(tmpDir, 'weedout.par')):
            os.remove(os.path.join(tmpDir, 'weedout.par'))
        if os.path.exists(os.path.join(tmpDir, 'toss.out')):
            os.remove(os.path.join(tmpDir, 'toss.out'))
        if os.path.exists(
                os.path.join(tmpDir, os.path.basename(linelistfilename))):
            os.remove(os.path.join(tmpDir, os.path.basename(linelistfilename)))
        os.rmdir(tmpDir)
        sys.stdout.write('\r' + "Running MOOG weedout ...\r")
        sys.stdout.flush()
    return None