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
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
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
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
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
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)
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
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)
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