Package ComboCode :: Package cc :: Package modeling :: Package codes :: Module ALI
[hide private]
[frames] | no frames]

Source Code for Module ComboCode.cc.modeling.codes.ALI

  1  # -*- coding: utf-8 -*- 
  2   
  3  """ 
  4  Running ALI iteratively with the EnergyBalance. 
  5   
  6  Author: R. Lombaert 
  7   
  8  """ 
  9   
 10  import os 
 11  import subprocess       
 12   
 13  import cc.path 
 14  from cc.tools.io import DataIO 
 15  from cc.modeling.physics import EnergyBalance as EB 
 16   
 17   
 18   
19 -def runEB_ALI(afn,ai=0,ei=0,iTmax=200,iter_conv=0,ALI_args=[],iterT_kwargs={},\ 20 runALIinit=0,iter_texguess=0.9,eb=None,*args,**kwargs):
21 22 ''' 23 Run the energy balance module concurrently with the ALI RT code. 24 25 The method iterates between EB and ALI, updating the temperature profile 26 and level populations between different iterations. 27 28 ALI always starts first, so that the EB always has level populations to work 29 with. Make sure the inputfile for ALI and for EB have the same initial T 30 profile. 31 32 If more than one molecule is requested, ALI is ran for each molecule, then 33 EB takes into account all molecules in one go, after which the method goes 34 back to ALI for one molecule at a time. 35 36 Automatically updates the ALI inputfile with filename for the temperature 37 input. Adds '_iter' to the ALI input filename 38 and the level populations as well as temperature output files to help 39 differentiate between the initial calculation and the iterations. Note that 40 the .pop file is used by the EB, while ALI works with the .popiter file 41 (that doesn't change name at all). They should give the same populations 42 between iterations. The .popiter file is the one given in the ALI inputfile, 43 while the .pop file is based on the inputfilename and is created at the end 44 of an ALI run. The .pop filenames (one for every molecule) are the input for 45 EB's pop keyword and must be set by the user in either an EB inputfile or as 46 keyword in kwargs. 47 48 Input includes 49 - ALI input filename 50 - Number of iterations to run in ALI and EB (0 if convergence is needed) 51 - Less strict ALI convergence criterion for iterations 1 up to n-1 52 - Additional arguments for the ALI execution 53 - Additional keyword arguments for the temperature iteration (iterT) 54 - Additional args/kwargs for the EnergyBalance object initialisation 55 56 The EB input template is MCP by default, but a different template can be 57 passed to kwargs. Anything defined in the EB input template can be redefined 58 in args and kwargs as well as by passing fn to this function call, which 59 points to the EB inputfile (not the template!). 60 61 Note that ALI iterations do not share information, while the EB keeps track 62 of all previous iterations. At the end of the method, the EB object is 63 returned in case you want to use it to check the different iterations after 64 the calculation is done, including temperature, level populations, heating 65 and cooling terms, etc. 66 67 In terms of initial populations, the user can specify whether to use 68 TexGuess = -1 or TexGuess = 0.9, i.e. start from the pops calculated in the 69 previous iteration (keep_pop on), or start from the standard initial 70 conditions. 71 72 If you have an EnergyBalance object from a previous iteration or call to 73 this function, you can also pass this, and the method will continue with 74 that object instead. Make sure to adapt your iTmax and such to this object. 75 76 @param afn: The inputfile name for ALI. One filename given as a string in 77 case of one molecule, multiple filenames given as strings in a 78 list in case of multiple molecules. 79 @type afn: str/list[str] 80 81 @keyword ai: The amount of iterations to do in the ALI calculation. Set to 82 the default of 0 if you wish to let ALI converge to whatever 83 convergence criterion set in the ALI input OR by the iter_conv 84 keyword. This is not applicable to the first run of ALI. 85 86 (default: 0) 87 @type ai: int 88 @keyword ei: The amount of iterations to do in the temperature calculation 89 during the energy balance. Set to the default of 0 if you wish 90 to let the energy balance converge to whatever convergence 91 criterion is determined for/by iterT. This is not applicable to 92 the first run of EB (use imax in iterT_kwargs in that case). 93 Cannot be 1. 94 95 (default: 0) 96 @type ei: int 97 @keyword iTmax: The maximum total number of iterations allowed for the EB. 98 This is the sum of all iterations between ALI and EB, and so 99 is different from imax in EB.iterT! It is primarily used to 100 put an upper limit on the while loop of the ALI vs EB 101 iteration. 102 103 (default: 200) 104 @type iTmax: int 105 @keyword iter_conv: The convergence criterion to use in ALI during iteration 106 with the energy balance. Reverts to the requested value 107 in the ALI inputfile at the end of the iteration. If 108 more strict than the criterion given in the ALI 109 inputfile this keyword is ignored. Default in case the 110 same convergence criterion should be used as in the ALI 111 inputfile during the iteration. 112 113 (default: 0) 114 @type iter_conv: float 115 @keyword runALIinit: Run the initial iteration of ALI. In some cases, this 116 model is already calculated, in which case the code 117 starts from the existing files. 118 119 (default: 0) 120 @type runALIinit: bool 121 @keyword iter_texguess: The TexGuess value for the iterations (ie not the 122 first calculation, in which case the value is given 123 in the inputfile). Typically this is 0.9 for 124 standard initial conditions, but alternative could 125 be -1 to start off from the populations calculated 126 in the previous iteration. 127 128 (default: 0.9) 129 @type iter_texguess: float 130 @keyword ALI_args: Additional arguments that are appended to the execute 131 command separated by spaces. If a single string is given, 132 only that string is added to the command. Default if no 133 extra arguments are needed. 134 135 (default: []) 136 @type ALI_args: list[str] 137 @keyword iterT_kwargs: Additional arguments for the energy balance 138 temperature iteration. See method iterT in 139 EnergyBalance for more information. 140 141 (default: {}) 142 @type iterT_kwargs: dict 143 @keyword eb: An EnergyBalance object from a previous call. The method will 144 simply continue with this object rather than making a new one. 145 By default runALIinit will be off. 146 147 (default: None) 148 @type eb: EnergyBalance() 149 150 @return: The EnergyBalance object is returned with all its properties. 151 @rtype: EnergyBalance() 152 153 ''' 154 155 #-- 1) Calculate the zeroth ALI iteration for initial level populations 156 #-- 2) Set up the EnergyBalance object 157 #-- 3) Calculate the first EB iteration and create new input for ALI 158 #-- 4) Run ALI with the new input. 159 #-- 5) Rinse and repeat until converged. 160 161 #-- Step 1: Calculate ALI given the pre-defined inputfile for all molecules 162 if isinstance(afn,str): afn = [afn] 163 if not eb is None: runALIinit = 0 164 if runALIinit: 165 print('--------------------------------------------') 166 print('Running first guess for ALI.') 167 print('--------------------------------------------') 168 for ifn in afn: execALI(ifn,args=ALI_args) 169 170 #-- Step 2: Set up the EnergyBalance object. 171 if eb is None: 172 pars = {'template': 'mcp'} 173 pars.update(kwargs) 174 eb = EB.EnergyBalance(*args,**pars) 175 176 #-- Remember the maximum requested iterations if it is present. Otherwise, 177 # set it to the default in the EnergyBalance. 178 ei = int(ei) 179 imax = iterT_kwargs['imax'] if iterT_kwargs.has_key('imax') else 50 180 if eb is None: 181 iterT_kwargs['imax'] = ei if int(ei) else imax 182 else: 183 iterT_kwargs['imax'] = eb.i + ei if int(ei) else eb.i+imax 184 185 #-- Step 3: Run the EnergyBalance 186 m = 'next' if not eb is None else 'first' 187 print('--------------------------------------------') 188 print('Running {} guess of EnergyBalance (EB).'.format(m)) 189 print('--------------------------------------------') 190 eb.iterT(**iterT_kwargs) 191 192 #-- Prep step 4: Create new filenames for ALI input and Tkin 193 fnT = afn[0].replace('.inp','_iter.temp') 194 fn_new = [ifn.replace('.inp','_iter.inp') for ifn in afn] 195 196 #-- Step 4: Iterate between steps 2 and 3 until the temperature iteration 197 # needs only 1 step to converge. Note that ei cannot be 1 for this 198 # to work. 199 ei = 2 if int(ei) == 1 else int(ei) 200 i, iT, iter_texguess = 1, -2, float(iter_texguess) 201 while eb.i != iT + 1 and eb.i <= iTmax: 202 print('--------------------------------------------') 203 print('Running iteration {} of ALI + EB. Current EB'.format(i) + \ 204 ' iteration index: {}.'.format(eb.i)) 205 print('--------------------------------------------') 206 207 #-- Remember the current temperature iteration 208 iT = eb.i 209 210 #-- Step 2': 211 #-- Update the ALI inputfiles and run. This overwrites the previous temp 212 # and pop files. You have access to both pops and temps of all 213 # iterations through eb.pop[i] and eb.T_iter[i], respectively, with i 214 # the iteration. Also sets the (maybe) new convergence criterion, new 215 # Tkin/pop filename, and TexGuess to -1. 216 DataIO.writeCols(filename=fnT,cols=[eb.r,eb.T.eval()]) 217 for ifn,ifn_new in zip(afn,fn_new): 218 updateInputfile(fn=ifn,fnT=fnT,ai=ai,conv=iter_conv,\ 219 texguess=iter_texguess,fn_new=ifn_new) 220 execALI(ifn_new,args=ALI_args) 221 222 #-- Step 3': 223 #-- Update the level populations for all molecules. 224 for m,ifn_new in zip(eb.molecules,fn_new): 225 eb.updatePop(m=m,fn=ifn_new.replace('.inp','.pop')) 226 227 #-- Only if ei is not zero, limit the maximum amount of iterations. 228 # Otherwise set it to imax or the default of imax, in addition to the 229 # current iteration 230 iterT_kwargs['imax'] = eb.i+ei if int(ei) else eb.i+imax 231 eb.iterT(**iterT_kwargs) 232 233 #-- Increase the EB+ALI iteration index. 234 i += 1 235 236 #-- If the temperature iteration reaches convergence, run the original ALI 237 # inputfile again, with updated T and pop files (ie with the original 238 # convergence criterion and number of iterations. 239 print('--------------------------------------------') 240 print('Running final ALI iteration.') 241 print('--------------------------------------------') 242 DataIO.writeCols(filename=fnT,cols=[eb.r,eb.T.eval()]) 243 for ifn,ifn_new in zip(afn,fn_new): 244 updateInputfile(fn=ifn,fnT=fnT,texguess=iter_texguess,fn_new=ifn_new) 245 execALI(ifn_new,args=ALI_args) 246 247 return eb
248 249 250
251 -def updateInputfile(fn,fnT,ai=0,conv=0,texguess=0.9,fn_new=None):
252 253 ''' 254 Update the ALI inputfile with new information for the next iteration. 255 256 @param fn: The full original ALI inputfilename 257 @type fn: str 258 @param fnT: The full filename of the temperature profile 259 @type fnT: str 260 261 @keyword ai: The amount of iterations to do in the ALI calculation. Set to 262 the default of 0 if you wish to let ALI converge to whatever 263 convergence criterion set in the ALI input OR by the iter_conv 264 keyword. 265 266 (default: 0) 267 @type ai: int 268 @keyword conv: The convergence criterion to use in ALI during iteration 269 with the energy balance. If 270 more strict than the criterion given in the ALI 271 inputfile this keyword is ignored. Default in case the 272 same convergence criterion should be used as in the ALI 273 inputfile during the iteration. 274 275 (default: 0) 276 @type conv: float 277 @keyword texguess: The TexGuess value for the iterations. Typically this is 278 0.9 for standard initial conditions, but alternative 279 could be -1 to start off from the populations calculated 280 in the previous iteration. 281 282 (default: 0.9) 283 @type texguess: float 284 @keyword fn_new: The new (full) ALI inputfile name. Default if original is 285 to be updated. 286 287 (default: None) 288 @type fn_new: str 289 290 ''' 291 292 ai, conv, tex_guess = int(ai), float(conv), float(texguess) 293 294 #-- Change T and pop filenames 295 data = changeKey(fn=fn,k='Tkin',v='I {} 1.0'.format(fnT)) 296 297 #-- Set the TexGuess to -1 so ALI reads the population filename 298 tex_line = getKey(data=data,k='PassBand').split() 299 tex_line[1] = str(texguess) 300 data = changeKey(data=data,k='PassBand',v=' '.join(tex_line)) 301 302 #-- Set the number of maximum iterations if full convergence is not needed, 303 # or alternatively change the convergence criterion 304 if ai or conv: 305 conv_line = getKey(data=data,k='MaxIter').split() 306 if ai: conv_line[0] = str(ai) 307 if conv and float(conv_line[5]) < conv: conv_line[5] = str(conv) 308 data = changeKey(data=data,k='MaxIter',v=' '.join(conv_line)) 309 310 #-- Save the inputfile 311 DataIO.writeFile(input_lines=data,filename=fn if fn_new is None else fn_new)
312 313 314
315 -def execALI(fn,args=[]):
316 317 ''' 318 Call the ALI executable for a given filename. 319 320 Note that the filename should be located in the ALI home folder (given in 321 usr/Path.dat), and that the ouput of the code will given there as well. 322 323 This method changes the working directory to the ALI home folder. 324 325 @param fn: The full ALI inputfilename. 326 @type fn: str 327 328 @keyword args: Additional arguments that are appended to the execute command 329 separated by spaces. If a single string is given, only that 330 string is added to the command. Default if no extra arguments 331 are needed. 332 333 (default: []) 334 @type args: list[str] 335 336 ''' 337 338 if isinstance(args,str): args = [args] 339 os.chdir(cc.path.ali) 340 fncut = os.path.split(fn.replace('.inp',''))[1] 341 subprocess.call(['./ali {}'.format(fncut)+' '.join(args)],shell=True)
342 343 344
345 -def getKey(k,data=None,fn=None):
346 347 ''' 348 Retrieve data from an ALI inputfile. 349 350 Returns the line following the line that contains the given key. 351 352 @param k: The unique input key word for which the ALI inputfile is 353 searched. 354 @type k: str 355 356 @keyword data: The data, ie a file read by readFile with delimiter set to '' 357 A filename must be given if data is None. 358 359 (default: None) 360 @type data: list[str] 361 @keyword fn: The ALI input filename. Only used if data is None. 362 363 (default: None) 364 @type fn: str 365 366 @return: The line following the line that contains given key 367 @rtype: str 368 369 ''' 370 371 if data is None: 372 data = DataIO.readFile(filename=fn,delimiter=None,replace_spaces=0) 373 i = DataIO.findKey(0,data,k) 374 return data[i+1].replace('\n','')
375 376 377
378 -def changeKey(k,v,data=None,fn=None):
379 380 ''' 381 Update an ALI inputfile with new information. 382 383 Takes an input key and value. The file is searched for the key, and the 384 value is inserted on the next line. 385 386 The content is then returned. This method does not save the file. 387 388 @param k: The unique input key word for which the ALI inputfile is 389 searched. 390 @type k: str 391 @param v: The value inserted on the next line after key. Must be a 392 formatted string; no formatting is done here. 393 @type v: str 394 395 @keyword data: The data, ie a file read by readFile with delimiter set to '' 396 A filename must be given if data is None. 397 398 (default: None) 399 @type data: list[str] 400 @keyword fn: The ALI input filename. Only used if data is None. 401 402 (default: None) 403 @type fn: str 404 405 @return: The data as read from a file or as adapted from the original 406 @rtype: list[str] 407 408 ''' 409 410 if data is None: 411 data = DataIO.readFile(filename=fn,delimiter=None,replace_spaces=0) 412 data = [line.replace('\n','') for line in data] 413 i = DataIO.findKey(0,data,k) 414 data[i+1] = v 415 return data
416 417 418 419 if __name__ == "__main__": 420 421 tests = {1: 'ad', 2: 'drift', 3: 'dg', 4: 'dt', 5: 'a', 6: 'pe', 7: 'h2'} 422 423 try: 424 plot = int(sys.argv[1]) 425 except IndexError: 426 plot = 0 427 428 test = [int(argi) for argi in sys.argv[2:]] 429 430 if not test: test = range(1,len(tests)+1) 431 432 for t in test: 433 tests[t](int(plot)) 434