def waterFraction1StepProfiler(model_id,path_gastronoom,fraction,rfrac): ''' Create a 1-step fractional profile for water. The original water abundance profile is taken from the output of the original model without fractional abundances. These fraction profiles can be used for CHANGE_ABUNDANCE_FRACTION in mline @param model_id: The model id of the original cooling model @type model_id: string @param path_gastronoom: The model subfolder in ~/GASTRoNOoM/ @type path_gastronoom: string @param fraction: the fraction used @type fraction: float @param rfrac: the radius at the step to the fractional abundance [cm] @type rfrac: float ''' rfrac = float(rfrac) fraction = float(fraction) filename = os.path.join(cc.path.gastronoom,path_gastronoom,'models',\ model_id,'coolfgr_all%s.dat'%model_id) rad = Gastronoom.getGastronoomOutput(filename=filename,keyword='RADIUS',\ return_array=1) fraction_profile = np.ones(len(rad)) step_index = np.argmin(abs(rad-rfrac)) fraction_profile[step_index:] = fraction output_filename = os.path.join(cc.path.gastronoom,path_gastronoom,\ 'profiles',\ 'water_fractions_%s_%.2f_r%.3e.dat'\ %(model_id,fraction,rfrac)) DataIO.writeCols(output_filename,[rad,fraction_profile])
def waterFraction1StepProfiler(model_id, path_gastronoom, fraction, rfrac): ''' Create a 1-step fractional profile for water. The original water abundance profile is taken from the output of the original model without fractional abundances. These fraction profiles can be used for CHANGE_ABUNDANCE_FRACTION in mline @param model_id: The model id of the original cooling model @type model_id: string @param path_gastronoom: The model subfolder in ~/GASTRoNOoM/ @type path_gastronoom: string @param fraction: the fraction used @type fraction: float @param rfrac: the radius at the step to the fractional abundance [cm] @type rfrac: float ''' rfrac = float(rfrac) fraction = float(fraction) filename = os.path.join(cc.path.gastronoom,path_gastronoom,'models',\ model_id,'coolfgr_all%s.dat'%model_id) rad = Gastronoom.getGastronoomOutput(filename=filename,keyword='RADIUS',\ return_array=1) fraction_profile = np.ones(len(rad)) step_index = np.argmin(abs(rad - rfrac)) fraction_profile[step_index:] = fraction output_filename = os.path.join(cc.path.gastronoom,path_gastronoom,\ 'profiles',\ 'water_fractions_%s_%.2f_r%.3e.dat'\ %(model_id,fraction,rfrac)) DataIO.writeCols(output_filename, [rad, fraction_profile])
def combineRedLaw(ofn, chiar_curve='ism', power=-1.8): ''' A method to combine the Fitzpatrick 2004 and Chiar & Tielens 2006 reddening laws as well as to extrapolate Chiar and Tielens 2006 to longer wavelengths. The result is saved in a file and used by the IvS repository as a valid reddening law. @param ofn: The output filename with path @type ofn: str @keyword chiar_curve: The curve type for Chiar & Tielens 2004. Either 'gc' or 'ism'. (default: 'ism') @type chiar_curve: str @keyword power: The power for the power law extrapolation. Default is taken from Chiar and Tielens 2006, as a typical value for local ISM between 2 and 5 micron. gc may require different value but not very important. (default: -1.8) @type power: float ''' chiar_curve = chiar_curve.lower() #-- Extract the two relevant extinction laws. xchiar, a_ak_chiar = red.get_law('chiar2006',norm='Ak',wave_units='micron',\ curve=chiar_curve) xfitz, a_ak_fitz = red.get_law('fitzpatrick2004',norm='Ak',\ wave_units='micron') #-- Define a power law for the extrapolation def power_law(x, scale, power): return scale * (x)**power #-- Determine the scaling factor from specific chiar/tielens law scale = a_ak_chiar[-1] / (xchiar[-1]**power) #-- Create an x grid for longer wavelengths. xlong = np.linspace(xchiar[-1] + 0.1, 1000, 1000) a_ak_long = power_law(xlong, scale, power) #-- Combine the three sections xcom = hstack([xfitz[xfitz < xchiar[0]], xchiar, xlong]) a_ak_com = hstack([a_ak_fitz[xfitz < xchiar[0]], a_ak_chiar, a_ak_long]) #-- Write the result to a file comments = '#-- wavelength (micron) A_lambda/A_k\n' DataIO.writeCols(filename=ofn, cols=[[comments]]) DataIO.writeCols(filename=ofn, cols=[xcom, a_ak_com], mode='a')
def combineRedLaw(ofn, chiar_curve="ism", power=-1.8): """ A method to combine the Fitzpatrick 2004 and Chiar & Tielens 2006 reddening laws as well as to extrapolate Chiar and Tielens 2006 to longer wavelengths. The result is saved in a file and used by the IvS repository as a valid reddening law. @param ofn: The output filename with path @type ofn: str @keyword chiar_curve: The curve type for Chiar & Tielens 2004. Either 'gc' or 'ism'. (default: 'ism') @type chiar_curve: str @keyword power: The power for the power law extrapolation. Default is taken from Chiar and Tielens 2006, as a typical value for local ISM between 2 and 5 micron. gc may require different value but not very important. (default: -1.8) @type power: float """ chiar_curve = chiar_curve.lower() # -- Extract the two relevant extinction laws. xchiar, a_ak_chiar = red.get_law("chiar2006", norm="Ak", wave_units="micron", curve=chiar_curve) xfitz, a_ak_fitz = red.get_law("fitzpatrick2004", norm="Ak", wave_units="micron") # -- Define a power law for the extrapolation def power_law(x, scale, power): return scale * (x) ** power # -- Determine the scaling factor from specific chiar/tielens law scale = a_ak_chiar[-1] / (xchiar[-1] ** power) # -- Create an x grid for longer wavelengths. xlong = np.linspace(xchiar[-1] + 0.1, 1000, 1000) a_ak_long = power_law(xlong, scale, power) # -- Combine the three sections xcom = hstack([xfitz[xfitz < xchiar[0]], xchiar, xlong]) a_ak_com = hstack([a_ak_fitz[xfitz < xchiar[0]], a_ak_chiar, a_ak_long]) # -- Write the result to a file comments = "#-- wavelength (micron) A_lambda/A_k\n" DataIO.writeCols(filename=ofn, cols=[[comments]]) DataIO.writeCols(filename=ofn, cols=[xcom, a_ak_com], mode="a")
def mergeOpacity(species,lowres='nom_res',highres='high_res'): ''' Merge high-res opacities into a grid of low-res opacities. The wavelength range of the inserted high res opacities is taken from the given high res grid. @param species: The dust species for which this is done. This is also the name of the folder in ~/MCMax/DustOpacities/ that contains the data files. @type species: string @keyword lowres: The subfolder in ~/MCMax/DustOpacities/species containing the low resolution datafiles. (default: low_res) @type lowres: string @keyword highres: The subfolder in ~/MCMax/DustOpacities/species containing the high resolution datafiles. (default: high_res) @type highres: string ''' path = os.path.join(cc.path.mopac,species) lowres_files = [f for f in glob(os.path.join(path,lowres,'*')) if f[-5:] == '.opac'] highres_files = [f for f in glob(os.path.join(path,highres,'*')) if f[-5:] == '.opac'] files = set([os.path.split(f)[1] for f in lowres_files] + \ [os.path.split(f)[1] for f in highres_files]) for f in files: hdfile = os.path.join(path,highres,f) ldfile = os.path.join(path,lowres,f) if os.path.isfile(ldfile) and os.path.isfile(hdfile): hd = DataIO.readCols(hdfile) ld = DataIO.readCols(ldfile) hdw = hd[0] ldw = ld[0] wmin = hdw[0] wmax = hdw[-1] ld_low = [list(col[ldw<wmin]) for col in ld] ld_high = [list(col[ldw>wmax]) for col in ld] hd = [list(col) for col in hd] merged = [ld_low[i] + hd[i] + ld_high[i] for i in range(len(hd))] DataIO.writeCols(filename=os.path.join(path,f),cols=merged)
def writeChi2(self,fn,sort=1,parameters=[]): ''' Write the Chi^2 values to a file. Lists the model id in the first column with the chi^2 value in the second. The chi^2 values can be requested to be sorted. Parameters from the Star() objects can be added as additional columns. Given parameters must be valid. @param fn: The output filename @type fn: str @keyword sort: Sort the star_grid according to the chi^2 values from lowest to highest. Requires calcChi2 to be ran first. (default: 1) @type sort: bool @keyword parameters: The additional model parameters to be added as columns in the file. (default: []) @type parameters: list(str) ''' #-- If no chi^2 was calculated, do nothing if not self.chi2.size: return #-- Write the header comments = ['# '] + ['ID','RedChi^2'] + parameters + ['\n'] DataIO.writeFile(filename=fn,input_lines=comments,delimiter='\t') #-- Define the columns cols = [[s['LAST_MCMAX_MODEL'] for s in self.getStarGrid(sort=sort)]] if sort: isort = np.argsort(self.chi2) cols.append(self.chi2[isort]) else: cols.append(self.chi2) #-- Add additional model parameters if requested for par in parameters: cols.append([s[par] for s in self.getStarGrid(sort=sort)]) #-- Append the columns to the file after the header DataIO.writeCols(filename=fn,cols=cols,mode='a')
def prepInput(star,path,repl_str=''): ''' Prepare inputfiles for LIME from a GASTRoNOoM and MCMax model. Input is taken from the model ouput and written into files. The output folder can be chosen. The model_id tag can be replaced with an arbitrary string. Input is converted to SI units, except opacities, which are in cm2/g. @param star: The model object including the GASTRoNOoM and MCMax model ids. @type star: Star() @param path: The target folder for the files. @type path: str @keyword repl_str: Replacement string for the model_id tag. (default: '') @type repl_str: str ''' #-- First opacities and t_dust, which are not part of the GASTRoNOoM output mcmid = star['LAST_MCMAX_MODEL'] fnopac = os.path.join(path,'opac_%s.dat'%(repl_str and repl_str or mcmid)) DataIO.writeCols(fnopac,star.getWeightedKappas()) #-- Write dust temperature to a file. fntd = os.path.join(path,'td_%s.dat'%(repl_str and repl_str or mcmid)) rad = star.getDustRad(unit='m') td = star.getDustTemperature() DataIO.writeCols(fntd,[rad,td]) #-- Finally the gas properties if not repl_str: repl_str = star['LAST_GASTRONOOM_MODEL'] #-- Radius for nh2 and vel rad = star.getGasRad(unit='m',ftype='fgr_all') if rad.size > 10000: icutoff = np.argmin(abs(rad-1e14)) rad = Data.reduceArray(rad,20,1e14,'remove') else: icutoff = None #-- h2 number density nh2 = star.getGasNumberDensity(ftype='fgr_all') nh2 = nh2*10**6 if not icutoff is None: nh2 = Data.reduceArray(nh2,20,nh2[icutoff],'remove') fnnh2 = os.path.join(path,'nh2_%s.dat'%repl_str) DataIO.writeCols(fnnh2,[rad,nh2]) #-- Velocity profile vel = star.getGasVelocity(ftype='fgr_all') vel = vel*10**-2 if not icutoff is None: vel = Data.reduceArray(vel,20,vel[icutoff],'remove') fnvel = os.path.join(path,'vg_%s.dat'%repl_str) DataIO.writeCols(fnvel,[rad,vel]) #-- CO abundance rad = star.getGasRad(ftype='1',mstr='12C16O',unit='m') nh2 = star.getGasNumberDensity(ftype='1',mstr='12C16O') nco = star.getGasNumberDensity(ftype='1',mstr='12C16O',molecule=1) aco = nco/nh2 fnaco = os.path.join(path,'aco_%s.dat'%repl_str) DataIO.writeCols(fnaco,[rad,aco])
def __convolveSphinx(self,star): ''' Check if sphinx output has already been convolved (pacs db) and do so if not. @param star: The parameter set @type star: Star() ''' #- check for which filenames the convolution has already been done finished_conv_filenames = self.checkStarDb(star) finished_conv_filenames = [this_f for this_f in finished_conv_filenames if this_f in [os.path.split(f)[1] for f in self.data_filenames]] #- if after db check pacs id is undefined, then there is no pacs model, #- and the convolution will be done anyway if self.redo_convolution and star['LAST_PACS_MODEL']: for filename in finished_conv_filenames: ori = os.path.join(cc.path.gout,'stars',self.star_name,\ 'PACS_results',star['LAST_PACS_MODEL'],\ '_'.join(['sphinx',filename])) backup = os.path.join(cc.path.gout,'stars',self.star_name,\ 'PACS_results',star['LAST_PACS_MODEL'],\ '_'.join(['backup','sphinx',filename])) subprocess.call(['mv %s %s'%(ori,backup)],shell=True) self.db[star['LAST_PACS_MODEL']]['filenames'] = [] finished_conv_filenames = [] filenames_to_do = [this_f for this_f in [os.path.split(f)[1] for f in self.data_filenames] if this_f not in finished_conv_filenames] #-Get sphinx model output and merge, for all star models in star_grid if filenames_to_do: #- if list is not empty, some filenames still need a convolution print '* Reading Sphinx model and merging.' merged = star['LAST_GASTRONOOM_MODEL'] \ and self.mergeSphinx(star) \ or [[],[]] sphinx_wave = merged[0] sphinx_flux = merged[1] if not sphinx_wave: print '* No Sphinx data found.' return #- convolve the model fluxes with a gaussian at central wavelength #- from data_wave_list for every star, and appropriate sigma print '* Convolving Sphinx model, after correction for v_lsr.' if not self.data_delta_list: self.setDataResolution() for filename in filenames_to_do: i_file = [os.path.split(f)[1] for f in self.data_filenames].index(filename) if not star['LAST_PACS_MODEL']: star['LAST_PACS_MODEL'] = \ 'pacs_%.4i-%.2i-%.2ih%.2i-%.2i-%.2i'\ %(gmtime()[0],gmtime()[1],gmtime()[2],\ gmtime()[3],gmtime()[4],gmtime()[5]) self.db[star['LAST_PACS_MODEL']] = \ dict([('filenames',[]),\ ('trans_list',star.getTransList(dtype='PACS')),\ ('cooling_id',star['LAST_GASTRONOOM_MODEL'])]) DataIO.testFolderExistence(\ os.path.join(cc.path.gout,'stars',self.star_name,\ 'PACS_results',star['LAST_PACS_MODEL'])) #-- Correct for the v_lsr of the central source sphinx_wave_corr = array(sphinx_wave)*(1./(1-self.vlsr/self.c)) sph_conv = Data.doConvolution(\ x_in=sphinx_wave_corr,\ y_in=sphinx_flux,\ x_out=self.data_wave_list[i_file],\ widths=self.data_delta_list[i_file],\ oversampling=self.oversampling) sph_fn = os.path.join(cc.path.gout,'stars',self.star_name,\ 'PACS_results',star['LAST_PACS_MODEL'],\ '_'.join(['sphinx',filename])) DataIO.writeCols(filename=sph_fn,\ cols=[self.data_wave_list[i_file],sph_conv]) self.db[star['LAST_PACS_MODEL']]['filenames'].append(filename) self.db.addChangedKey(star['LAST_PACS_MODEL'])
def runEB_ALI(afn,ai=0,ei=0,iTmax=200,iter_conv=0,ALI_args=[],iterT_kwargs={},\ runALIinit=0,iter_texguess=0.9,eb=None,*args,**kwargs): ''' Run the energy balance module concurrently with the ALI RT code. The method iterates between EB and ALI, updating the temperature profile and level populations between different iterations. ALI always starts first, so that the EB always has level populations to work with. Make sure the inputfile for ALI and for EB have the same initial T profile. If more than one molecule is requested, ALI is ran for each molecule, then EB takes into account all molecules in one go, after which the method goes back to ALI for one molecule at a time. Automatically updates the ALI inputfile with filename for the temperature input. Adds '_iter' to the ALI input filename and the level populations as well as temperature output files to help differentiate between the initial calculation and the iterations. Note that the .pop file is used by the EB, while ALI works with the .popiter file (that doesn't change name at all). They should give the same populations between iterations. The .popiter file is the one given in the ALI inputfile, while the .pop file is based on the inputfilename and is created at the end of an ALI run. The .pop filenames (one for every molecule) are the input for EB's pop keyword and must be set by the user in either an EB inputfile or as keyword in kwargs. Input includes - ALI input filename - Number of iterations to run in ALI and EB (0 if convergence is needed) - Less strict ALI convergence criterion for iterations 1 up to n-1 - Additional arguments for the ALI execution - Additional keyword arguments for the temperature iteration (iterT) - Additional args/kwargs for the EnergyBalance object initialisation The EB input template is MCP by default, but a different template can be passed to kwargs. Anything defined in the EB input template can be redefined in args and kwargs as well as by passing fn to this function call, which points to the EB inputfile (not the template!). Note that ALI iterations do not share information, while the EB keeps track of all previous iterations. At the end of the method, the EB object is returned in case you want to use it to check the different iterations after the calculation is done, including temperature, level populations, heating and cooling terms, etc. In terms of initial populations, the user can specify whether to use TexGuess = -1 or TexGuess = 0.9, i.e. start from the pops calculated in the previous iteration (keep_pop on), or start from the standard initial conditions. If you have an EnergyBalance object from a previous iteration or call to this function, you can also pass this, and the method will continue with that object instead. Make sure to adapt your iTmax and such to this object. @param afn: The inputfile name for ALI. One filename given as a string in case of one molecule, multiple filenames given as strings in a list in case of multiple molecules. @type afn: str/list[str] @keyword ai: The amount of iterations to do in the ALI calculation. Set to the default of 0 if you wish to let ALI converge to whatever convergence criterion set in the ALI input OR by the iter_conv keyword. This is not applicable to the first run of ALI. (default: 0) @type ai: int @keyword ei: The amount of iterations to do in the temperature calculation during the energy balance. Set to the default of 0 if you wish to let the energy balance converge to whatever convergence criterion is determined for/by iterT. This is not applicable to the first run of EB (use imax in iterT_kwargs in that case). Cannot be 1. (default: 0) @type ei: int @keyword iTmax: The maximum total number of iterations allowed for the EB. This is the sum of all iterations between ALI and EB, and so is different from imax in EB.iterT! It is primarily used to put an upper limit on the while loop of the ALI vs EB iteration. (default: 200) @type iTmax: int @keyword iter_conv: The convergence criterion to use in ALI during iteration with the energy balance. Reverts to the requested value in the ALI inputfile at the end of the iteration. If more strict than the criterion given in the ALI inputfile this keyword is ignored. Default in case the same convergence criterion should be used as in the ALI inputfile during the iteration. (default: 0) @type iter_conv: float @keyword runALIinit: Run the initial iteration of ALI. In some cases, this model is already calculated, in which case the code starts from the existing files. (default: 0) @type runALIinit: bool @keyword iter_texguess: The TexGuess value for the iterations (ie not the first calculation, in which case the value is given in the inputfile). Typically this is 0.9 for standard initial conditions, but alternative could be -1 to start off from the populations calculated in the previous iteration. (default: 0.9) @type iter_texguess: float @keyword ALI_args: Additional arguments that are appended to the execute command separated by spaces. If a single string is given, only that string is added to the command. Default if no extra arguments are needed. (default: []) @type ALI_args: list[str] @keyword iterT_kwargs: Additional arguments for the energy balance temperature iteration. See method iterT in EnergyBalance for more information. (default: {}) @type iterT_kwargs: dict @keyword eb: An EnergyBalance object from a previous call. The method will simply continue with this object rather than making a new one. By default runALIinit will be off. (default: None) @type eb: EnergyBalance() @return: The EnergyBalance object is returned with all its properties. @rtype: EnergyBalance() ''' #-- 1) Calculate the zeroth ALI iteration for initial level populations #-- 2) Set up the EnergyBalance object #-- 3) Calculate the first EB iteration and create new input for ALI #-- 4) Run ALI with the new input. #-- 5) Rinse and repeat until converged. #-- Step 1: Calculate ALI given the pre-defined inputfile for all molecules if isinstance(afn,str): afn = [afn] if not eb is None: runALIinit = 0 if runALIinit: print('--------------------------------------------') print('Running first guess for ALI.') print('--------------------------------------------') for ifn in afn: execALI(ifn,args=ALI_args) #-- Step 2: Set up the EnergyBalance object. if eb is None: pars = {'template': 'mcp'} pars.update(kwargs) eb = EB.EnergyBalance(*args,**pars) #-- Remember the maximum requested iterations if it is present. Otherwise, # set it to the default in the EnergyBalance. ei = int(ei) imax = iterT_kwargs['imax'] if iterT_kwargs.has_key('imax') else 50 if eb is None: iterT_kwargs['imax'] = ei if int(ei) else imax else: iterT_kwargs['imax'] = eb.i + ei if int(ei) else eb.i+imax #-- Step 3: Run the EnergyBalance m = 'next' if not eb is None else 'first' print('--------------------------------------------') print('Running {} guess of EnergyBalance (EB).'.format(m)) print('--------------------------------------------') eb.iterT(**iterT_kwargs) #-- Prep step 4: Create new filenames for ALI input and Tkin fnT = afn[0].replace('.inp','_iter.temp') fn_new = [ifn.replace('.inp','_iter.inp') for ifn in afn] #-- Step 4: Iterate between steps 2 and 3 until the temperature iteration # needs only 1 step to converge. Note that ei cannot be 1 for this # to work. ei = 2 if int(ei) == 1 else int(ei) i, iT, iter_texguess = 1, -2, float(iter_texguess) while eb.i != iT + 1 and eb.i <= iTmax: print('--------------------------------------------') print('Running iteration {} of ALI + EB. Current EB'.format(i) + \ ' iteration index: {}.'.format(eb.i)) print('--------------------------------------------') #-- Remember the current temperature iteration iT = eb.i #-- Step 2': #-- Update the ALI inputfiles and run. This overwrites the previous temp # and pop files. You have access to both pops and temps of all # iterations through eb.pop[i] and eb.T_iter[i], respectively, with i # the iteration. Also sets the (maybe) new convergence criterion, new # Tkin/pop filename, and TexGuess to -1. DataIO.writeCols(filename=fnT,cols=[eb.r,eb.T.eval()]) for ifn,ifn_new in zip(afn,fn_new): updateInputfile(fn=ifn,fnT=fnT,ai=ai,conv=iter_conv,\ texguess=iter_texguess,fn_new=ifn_new) execALI(ifn_new,args=ALI_args) #-- Step 3': #-- Update the level populations for all molecules. for m,ifn_new in zip(eb.molecules,fn_new): eb.updatePop(m=m,fn=ifn_new.replace('.inp','.pop')) #-- Only if ei is not zero, limit the maximum amount of iterations. # Otherwise set it to imax or the default of imax, in addition to the # current iteration iterT_kwargs['imax'] = eb.i+ei if int(ei) else eb.i+imax eb.iterT(**iterT_kwargs) #-- Increase the EB+ALI iteration index. i += 1 #-- If the temperature iteration reaches convergence, run the original ALI # inputfile again, with updated T and pop files (ie with the original # convergence criterion and number of iterations. print('--------------------------------------------') print('Running final ALI iteration.') print('--------------------------------------------') DataIO.writeCols(filename=fnT,cols=[eb.r,eb.T.eval()]) for ifn,ifn_new in zip(afn,fn_new): updateInputfile(fn=ifn,fnT=fnT,texguess=iter_texguess,fn_new=ifn_new) execALI(ifn_new,args=ALI_args) return eb