1
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
156
157
158
159
160
161
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
171 if eb is None:
172 pars = {'template': 'mcp'}
173 pars.update(kwargs)
174 eb = EB.EnergyBalance(*args,**pars)
175
176
177
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
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
193 fnT = afn[0].replace('.inp','_iter.temp')
194 fn_new = [ifn.replace('.inp','_iter.inp') for ifn in afn]
195
196
197
198
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
208 iT = eb.i
209
210
211
212
213
214
215
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
223
224 for m,ifn_new in zip(eb.molecules,fn_new):
225 eb.updatePop(m=m,fn=ifn_new.replace('.inp','.pop'))
226
227
228
229
230 iterT_kwargs['imax'] = eb.i+ei if int(ei) else eb.i+imax
231 eb.iterT(**iterT_kwargs)
232
233
234 i += 1
235
236
237
238
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
312
313
314
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
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