MoDeNa  1.0
Software framework facilitating sequential multi-scale modelling
predici_2_modena.py
1 
2 
7 
8 import sys
9 import time
10 
11 # The following lists are required to replace built-in Predici functions by corresponding fluent functions
12 
13 predici_command_list=['gettemp','getmass','getvol','getco','cpol','getmmlow']
14 predici_command_arg_list=[0,0,0,2,2,2]
15 predici_command_type_list=['double','double','double','double','double','double']
16 predici_command_replace_list=['my_temp','my_cell_mass','my_cell_volume','my_conc[MY_NEW_INDEX]','my_conc[MY_NEW_INDEX]','my_molma[MY_NEW_INDEX]']
17 fluent_command_replace_list=['C_T(c,t)','C_VOLUME(c,t)*C_R(c,t)','C_VOLUME(c,t)','my_conc[MY_NEW_INDEX]','C_UDSI(c,t,MY_NEW_INDEX)','my_molma[MY_NEW_INDEX]']
18 fluent_command_array_size_list=['0','0','0','40','40','40']
19 target_list=['Openfoam','Fluent']
20 
21 # Function types
22 
23 func_type_list=['void','bool','int','long','double','float','char']
24 
25 #===================================================================================================================================================================
26 # Definition of a method through a class which applied to a string and which has a substring list as argument.
27 # The method returns the substring in the list which is found first together with the position of the first occurence of the substring in the string
28 
29 def firststring(stringname,string_list):
30  myindex = -1
31  myname = ''
32  for index in range(len(string_list)):
33  index_sstr = stringname.find(string_list[index])
34  if index_sstr >= 0:
35  if myindex == -1:
36  myindex = index_sstr
37  myname = string_list[index]
38  else:
39  if myindex > index_sstr:
40  myindex = index_sstr
41  myname = string_list[index]
42  return myname, myindex
43 
44 #================================================================================================================================================================================
45 #
46 # Routine tests if a substring can be a function name
47 # Therefore it checks wether the characters before and behind substring in string are suitable
48 #
49 # Arguments:
50 # str1: String in which substring is checked as a possible function name
51 # substr1: The substring in string which is checked as possible function name
52 # i1: The position of the first character of substring in string (this is required since substr1 could occur several times
53 
54 
55 def check_func_name(str1,sub_str1,i1):
56  stra = str1[:i1]
57  strb = str1[i1+len(sub_str1):]
58 
59  stra = stra.replace('\n',' ')
60  stra = stra.replace('\t',' ')
61  strb = strb.replace('\t',' ')
62  strb = strb.replace('\n',' ')
63  strb = strb.lstrip()
64 
65  if len(stra) == 0:
66  icheck1 = 1
67  elif stra[len(stra)-1:len(stra)] == ' ':
68  icheck1 = 1
69  else:
70  icheck1 = 0
71 
72  if len(strb) == 0:
73  icheck2 = 1
74  elif strb[0:1] == '(':
75  icheck2 = 1
76  else:
77  icheck2 = 0
78 
79  if (icheck1 == 1) and (icheck2 == 1):
80  return 1
81  else:
82  return 0
83  return 0
84 
85 
86 #================================================================================================================================================================================
87 # Routine finds a corresponding bracket in a string
88 #
89 # Arguments:
90 # str1: String in which correspoinding bracket is searched for
91 # str2: Starting bracket type
92 # i1: Index of the starting bracket in the string
93 
94 def corresponding_bracket_index(str1,str2,i1):
95  index = i1+1
96  if str2 not in ['(','{','[']:
97  print 'Error in function corresponding_bracket_index. str2 is not an opening bracket'
98  raise SystemExit
99  else:
100  if str2 == '(':
101  str3 = ')'
102  if str2 == '{':
103  str3 = '}'
104  if str2 == '[':
105  str3 = ']'
106 
107  count_bracket = 1
108  while index < len(str1) and count_bracket > 0:
109  while str1[index:].find(str2)>=0 or str1[index:].find(str3)>=0:
110  index_b1 = str1[index:].find(str2)
111  index_b2 = str1[index:].find(str3)
112  if (index_b1 == -1) and (index_b2 >=0):
113  count_bracket -= 1
114  index = index+index_b2+1
115  if count_bracket <= 0:
116  return index-1
117  else:
118  print 'Unbalanced bracket'
119  raise SystemExit
120  if (index_b2 == -1) and (index_b1 >=0):
121  print 'Unbalanced bracket'
122  raise SystemExit
123  if (index_b1 < index_b2):
124  count_bracket += 1
125  index = index+index_b1+1
126  elif (index_b2 < index_b1):
127  count_bracket -= 1
128  index = index+index_b2+1
129  if count_bracket <= 0:
130  return index-1
131  print 'Error in function corresponding_bracket_index. Wrong syntax of interpreted source code'
132  raise SystemExit
133  return index-1
134 
135 #==================================================================================================================================
136 # Function converts a function of type func_type into a void function. It removes therefore all return values
137 
138 def func_2_voidfunc(code_string,func_type):
139  itype = len(func_type)
140  while code_string.find(func_type) >= 0:
141  ibool = code_string.find(func_type)
142  temp_string1 = code_string[:ibool+itype]
143  temp_string1 = temp_string1.replace(func_type,'void')
144  temp_string2 = code_string[ibool+itype:]
145  first_string, first_index = firststring(temp_string2,['(',';','='])
146  if first_string == '(':
147  # Function definition - Find enclosing curlibrackets of function body and remove return variable after return statement
148  temp_string1 += temp_string2[:first_index]
149  temp_string2 = temp_string2[first_index:]
150  sc_index = temp_string2.find('{')
151  ec_index = corresponding_bracket_index(temp_string2,'{',sc_index)
152  temp_string1 += temp_string2[:sc_index]
153  temp_string3 = temp_string2[ec_index:]
154  temp_string2 = temp_string2[sc_index:ec_index]
155  while temp_string2.find('return') >= 0:
156  index1 = temp_string2.find('return')
157  temp_string1 += temp_string2[:index1+6]
158  temp_string2 = temp_string2[index1+6:]
159  if temp_string2[0] == ' ':
160  index2 = temp_string2.find(';')
161  temp_string1 += temp_string2[index2]
162  temp_string2 = temp_string2[index2+1:]
163  temp_string1 += temp_string2+temp_string3
164  temp_string2 = ''
165  temp_string3 = ''
166  code_string = temp_string1+temp_string2
167 
168  return code_string
169 
170 #================================================================================================================================================================================
171 # Routine identifies whether a function occurs in a string or not
172 # It returns the position of the first character of the function name in the string and the position of the closing bracket ')'. The closing bracket must be in the same string!
173 # If the function is not found in the string it returns -1,-1
174 #
175 # Arguments:
176 # str1: String in which the function name is searched
177 # str2: Function name
178 #
179 # Results:
180 # index_start: Position of the first character of the function name in the string
181 # index_end: Position of the closing bracket ')' in the string
182 
183 def my_find_func( str1, str2 ):
184  index4 = str1.find(str2)
185 
186  if index4 == -1:
187  return -1,-1
188 
189  bindex = str1.find('(',index4+len(str2))
190  if bindex == -1:
191  return -1,-1
192  else:
193  str3 = str1[index4+len(str2):bindex]
194  str3 = str3.lstrip()
195  if len(str3) > 1:
196  return -1,-1
197 
198  pchar=''
199  if index4 > 0:
200  pchar = str1[index4-1]
201  if pchar not in [' ','=','>','<','*','+','-','/','(',',']:
202  return -1,-1
203  index_start = index4
204  index4 = bindex
205  index5 = str1.find(')',index4,)
206  while str1.find('(',index4+1) > -1 and str1.find('(',index4+1) < index5:
207  index5 = str1.find(')',index5+1)
208  index4_ = str1.find('(',index4+1)
209  index_end = index5
210 
211  return index_start, index_end
212 
213 
214 
215 
216 #================================================================================================================================================================================
217 # This functions returns the argument list of a function call as a string
218 #
219 # Arguments:
220 # str: The string which contains the function call together with the argument list
221 # i1: The position of the first character of the function name in the string str
222 # i2: The position of the closing bracket ')' of the argument list
223 #
224 # Results:
225 # arg_string: string of the argument list of a function including ',' separators
226 #
227 # Basically the function checks for the opening bracket '(' and returns the substring between the position of '(' and the corresponding closing bracket ')'
228 
229 
230 def get_arg_list(str,i1,i2):
231  indexb = str.find('(',i1,i2)
232 
233  arg_string = str[indexb:i2]
234 
235  return arg_string
236 
237 
238 
239 
240 #================================================================================================================================================================================
241 # This function splits a string 'str1' into a list of strings. The split string is 'str2'. From the created list the entry 'i1' is returned
242 #
243 # Arguments:
244 # str1: The string which is split
245 # str2: The separator string
246 # i1: The entry of the generated list that shall be returned
247 #
248 # Results:
249 # arg_string: The string of the i1 argument in the argument list
250 
251 def get_list_entry(str1,str2,i1):
252  arg_list = str1.split(str2)
253  arg_string = arg_list[i1-1]
254 
255  return arg_string
256 
257 #================================================================================================================================================================================
258 # This function deletes the body of a C or C++ function (definition)
259 #
260 # Arguments:
261 # my_list: Contains the lines of the C/C++ code
262 # i1: Is the line in which the function starts with the function name
263 #
264 # Results:
265 # None
266 #
267 # Everything furtheron is deleted until a ';' or a '{' sign are found. Then there are two scenarios
268 # (1) If a ';' is found first it is also deleted and the deletion then stops.
269 # (2) If a '{' is found first everything until and including the corresponding '}' is deleted. Then the deletion process stops
270 
271 def delete_func(code_string):
272  my_delete_list =['exp','power']
273 
274  new_code = ''
275  while len(code_string) > 0:
276  functype,itype = firststring(code_string,func_type_list)
277  funcname,ifunc = firststring(code_string,my_delete_list)
278  if itype < 0 or ifunc < 0:
279  new_code += code_string
280  code_string = ''
281  else:
282  if ifunc < itype:
283  new_code += code_string[:itype]
284  code_string = code_string[itype:]
285  else:
286  test_string = code_string[itype+len(functype):ifunc]
287  test_string = test_string.strip()
288  if test_string == '':
289  istart,iend = my_find_func(code_string,funcname)
290  new_code += code_string[:itype]
291  code_string = code_string[iend:]
292  mystring,myindex=firststring(code_string,[';','{'])
293  if mystring == ';':
294  code_string = code_string[myindex:]
295  else:
296  iend = corresponding_bracket_index(code_string,'{',myindex)
297  code_string = code_string[iend+1:]
298  else:
299  new_code += code_string[:itype+len(functype)]
300  code_string = code_string[itype+len(functype):]
301  return new_code
302 
303 #=================================================================================
304 # Function finds the position of a the first for-loop in a string
305 #
306 # Arguments: 1
307 #
308 # str1 = The string in which the for loop is searched
309 #
310 # Results: 1
311 #
312 # index = The position of the first for-loop in the string
313 #
314 
315 def find_loop(str1):
316  index = 0
317  while index < len(str1):
318  index = str1[index:].find('for')+index
319  if index >=0:
320  str2 = str1[index+3:]
321  str2 = str2.lstrip()
322  if str2[0:1] == '(':
323  if index == 0:
324  return index
325  elif str1[index-1:index] in [' ',';','}','{']:
326  return index
327  else:
328  index += 3
329  else:
330  index += 3
331  else:
332  return -1
333 
334  return -1
335 
336 #================================================================================================
337 # Function modifies a for-loop in a string which is located at a given position in the string if
338 # it contains an internal declaration of the loop counter:
339 # First it is checked whether an internal declaration exists in this for-loop.
340 # If yes, the internal declaration is removed and an external declaration is added in front of the loop
341 #
342 # Arguments: 2
343 # str1 = String which contains the for-loop
344 # i1 = Starting position of the for-loop in the string
345 #
346 # Results: 1
347 # str3 = String that is returned. If no internal counter declaration was found, str3 is the same as the input string str1
348 
349 def remove_loop_int_declaration(str1,i1):
350  index=i1+str1[i1:].find('(')
351  str2 = str1[index+1:]
352  str2 = str2.lstrip()
353  if str2.find('int ') == 0:
354  index_start = str1[index:].find('int ')+index
355  index_end = index_start+4
356  str2=str2[4:].lstrip()
357  str2=str2[:str2.find('=')]
358  str2=str2.rstrip()
359  str3 = str1[:i1]+'int '+str2+';'+str1[i1:index_start]+str1[index_end:]
360  else:
361  str3 = str1
362 
363  return str3
364 
365 #================================================================================================
366 # Function modifies all those for-loops in a string that contain an internal declaration of the
367 # loop counter
368 #
369 # Arguments: 1
370 # str1 = String in which the for-loops shall be changed
371 #
372 # Results: 1
373 # new_code = Return string in which all for-loops which internal counter declaration have been c
374 # changed
375 
376 def remove_all_loop_int_dec(str1):
377  new_code =''
378  while len(str1) > 0:
379  iloop = find_loop(str1)
380  str2 = remove_loop_int_declaration(str1,iloop)
381  new_code += str2[:iloop+3]
382  str1 = str2[iloop+3:]
383  return new_code
384 
385 #==================================================================================================
386 # function removes unnecessary semicolons
387 #
388 # Arguments: 1
389 # str1 = Input string which potentially contains unnecessary semicolons
390 #
391 # Results: 1
392 # str2 = Return string which contains only necessary semicolons
393 
394 def remove_semicolon(str1):
395  my_list_f1 = ['{','}']
396  my_list_f2 = ['{']
397  my_list_b1 = [';']
398  my_list_b2 = ['}']
399  str2 =''
400  while len(str1) > 0:
401  index = str1.find(';')
402  if index < 0:
403  str2 += str1
404  str1 = ''
405  else:
406  temp_string = str1[index+1:].replace(' ','')
407  if temp_string[0] in my_list_b1:
408  str3, delindex = firststring(str1[index+1:],my_list_b1)
409  str1 = str1[:index+1]+str1[index+1+delindex+1:]
410  else:
411  temp_string=str1[:index+1].replace(' ','')
412  if temp_string[len(temp_string)-2] in my_list_f1:
413  if temp_string[len(temp_string)-2] not in my_list_f2:
414  temp_string = str1[index+1:].replace(' ','')
415  if temp_string[0] in my_list_b2:
416  str1 = str1[:index]+str1[index+1:]
417  else:
418  str2 += str1[:index+1]
419  str1 = str1[index+1:]
420  else:
421  str1 = str1[:index]+str1[index+1:]
422  else:
423  temp_string=str1[:index+1].replace(' ','')
424  i1 = len(temp_string)-5
425  i2 = len(temp_string)-1
426  temp_string=temp_string[i1:i2]
427  if temp_string == 'else':
428  str1 = str1[:index]+str1[index+1:]
429  else:
430  str2 += str1[:index+1]
431  str1 = str1[index+1:]
432 
433  return str2
434 
435 #==================================================================================================
436 # function changes pass by reference to c style constructs
437 #
438 # Arguments: 1
439 # str1 = Input string wich contains the code where passing by reference has to be replaced
440 #
441 # Results: 1
442 # str2 = Return string which contains the code where passing by reference has been replaced
443 
444 def pass_by_reference_2_c(str1):
445  index = 0
446  searchstring='double& result1, double& result2'
447  replacestring ='double* results'
448  while index < len(str1):
449  deltai = str1[index:].find(searchstring)
450  if deltai < 0:
451  index = len(str1)
452  else:
453  index = index+deltai
454  icurli = index+str1[index:].find('{')
455  isemi = index+str1[index:].find(';')
456  if icurli >= 0 and (icurli < isemi or isemi < 0):
457  sub0 = str1[index:]
458  ibend = index+corresponding_bracket_index(sub0,'{',icurli-index)
459  sub1 = str1[:icurli]
460  sub2 = str1[icurli:ibend+1]
461  sub3 = str1[ibend+1:]
462  sub2 = sub2.replace('result1','results[0]')
463  sub2 = sub2.replace('result2','results[1]')
464  str1 = sub1+sub2+sub3
465  index = len(sub1)+len(sub2)
466  else:
467  index +=len(searchstring)
468  str2 =''
469  str1 = str1.replace(searchstring,replacestring)
470  while len(str1) > 0:
471  index = str1.find('k1, k2, k1, k2')
472  if index < 0:
473  str2 += str1
474  str1 = ''
475  else:
476  str2 += str1[:index-1]
477  str1 = str1[index-1:]
478  isemi = str1.find(';')
479  str1 = 'k1, k2, results); k1 = results[0]; k2 = results[1];'+str1[isemi+1:]
480 
481  index = str2.find('void F')
482  icurli = index + str2[index:].find('{')
483  sub1 = str2[:icurli+1]
484  sub2 = 'double results[2];'
485  sub3 = str2[icurli+1:]
486  str2 = sub1+sub2+sub3
487  index = str2.find('void A')
488  icurli = index + str2[index:].find('{')
489  sub1 = str2[:icurli+1]
490  sub2 = 'double results[2];'
491  sub3 = str2[icurli+1:]
492  str2 = sub1+sub2+sub3
493 
494  return str2
495 
496 #=====================================================================================
497 # Reformating code
498 
499 def reformat_code(lines):
500 
501  for index in range(len(lines)):
502  new_string = lines[index]
503  icom = new_string.find('//')
504  if icom >= 0:
505  lines[index]=new_string[0:icom]
506 
507  for index in range(len(lines)):
508  new_string = lines[index]
509  new_string = new_string.strip(' \t\r\n')
510  new_string = new_string.replace('\t',' ')
511  while new_string.find(' ') >= 0:
512  new_string = new_string.replace(' ',' ')
513  lines[index] = new_string
514 
515  code_string =''
516 
517  for index in range(len(lines)):
518  code_string+=lines[index]
519  return code_string
520 
521 
522 #===================================================================================
523 # Add new lines
524 
525 def add_newlines(code_string):
526  code_string = code_string.replace (';',';\n')
527  code_string = code_string.replace ('{','\n{\n')
528  code_string = code_string.replace ('}','}\n')
529 
530  return code_string
531 
532 #===================================================================================
533 # Add F and A calling sequence
534 
535 def add_call_FandA(mystring):
536  mystring+='void FandA(double* x, double t, double* fall){int i=0; double fx[DIM]; double dfx[DIM]; F(x,t,fx); A(x,t,dfx); for (i=0; i< DIM; i++){fall[i]=fx[i];fall[i+DIM]=dfx[i];} return;}'
537  return mystring
538 #==========================================================================================================================================================
539 # Start of main program
540 
541 def create_args(kinetics_name):
542 
543  fin = open(kinetics_name, 'r')
544  lines=fin.readlines()
545 
546  fin.close()
547 
548 #====================================================================================
549 # Reformat code
550 
551  code_string = reformat_code(lines)
552 
553 #====================================================================================
554 # Change bool functions to void function and remove return values
555 
556  code_string = func_2_voidfunc(code_string,'bool')
557 
558  code_string = delete_func(code_string)
559 
560 #====================================================================================
561 # Find and modify int definitions in loops and transfer to C99 style
562 #
563 
564  code_string = remove_all_loop_int_dec(code_string)
565 
566 #====================================================================================
567 # Insert parameter initialization in void F function
568 
569  index = code_string.find('void F')
570 
571  index1 = index+code_string[index:].find('{')
572  initcode ='if (my_global_init == -1) {SetGlobalIniParam();my_global_init=1;}'
573  code_string = code_string[:index1+1]+initcode+code_string[index1+1:]
574 
575 #=====================================================================================
576 # Remove unnecessary semicolons
577 #
578  code_string = remove_semicolon(code_string)
579 
580 #=====================================================================================
581 # Convert passing by reference to C style
582 #
583  code_string = pass_by_reference_2_c(code_string)
584 
585  code_string = add_newlines(code_string)
586 
587  new_lines = code_string.split('\n')
588 
589 #===================================================================================
590 # Include standard lib math.h in code in first line
591 
592  new_lines.insert(0,'#include <math.h>\n')
593  new_lines.insert(1,'int my_global_init = -1;\n')
594 
595  str3 = ''
596  for index in range(len(new_lines)):
597  str3+=new_lines[index]
598 
599 # ---------------------- Create predici header file ----------------------------------
600 
601  predicicode = add_call_FandA(str3)
602 
603  predicicode = add_newlines(predicicode)
604 
605  # ---------------------- Create function code ----------------------------------------
606 
607  headerfilelist=['modena.h','math.h']
608 
609  codestring =''
610 
611  for index in range(len(headerfilelist)):
612  codestring += '#include "'+headerfilelist[index]+'"\n'
613 
614  codestring += '''
615 
616 void FandA(double* x, double t, double* fall);
617 
618 
619 void predici_kinetics
620 (
621  const modena_model_t* model,
622  const double* inputs,
623  double *outputs
624 )
625 {
626  double time = inputs[0];
627  double * inputParams = (double *) (&(inputs[1]));
628  FandA(inputParams, time, outputs);
629 }
630 '''
631 
632  codestring += predicicode
633 
634  # ------------ Extract input list --------------------
635 
636  index = str3.find('XNAMES')
637  strnames=str3[index:len(str3)]
638  istart=strnames.find('{')
639  iend=strnames.find('}')
640  strnames=strnames[istart+1:iend]
641  namelist = strnames.split(',')
642  for index in range(len(namelist)):
643  namelist[index] = namelist[index].replace('"',"'")
644 
645  namelist.insert(0,"'kineticTime'");
646  returnDict = {}
647  returnDict['Ccode'] = codestring
648  returnDict['inputs'] = {}
649  returnDict['outputs'] = {}
650  returnDict['parameters'] = {}
651 
652  for index in range(len(namelist)):
653  returnDict['inputs'][namelist[index]] = \
654  {'min': -10, 'max': 9e99, 'argPos': index}
655  namelist.pop(0);
656 
657  # ------------ Extract output list --------------------
658 
659  index = str3.find('XTYPES')
660  strnames=str3[index:len(str3)]
661  istart=strnames.find('{')
662  iend=strnames.find('}')
663  strnames=strnames[istart+1:iend]
664  typelist = strnames.split(',')
665 
666  index_out = 0
667 
668  for index in range(len(namelist)):
669  source_name='source_'+namelist[index].strip("'")
670  returnDict['outputs'][source_name] = \
671  {'min': -9e99, 'max': 9e99, 'argPos': index_out}
672  index_out += 1
673 
674  for index in range(len(namelist)):
675  dsource_name='dsource_'+namelist[index].strip("'")
676  returnDict['outputs'][dsource_name] = \
677  {'min': -9e99, 'max': 9e99, 'argPos': index_out}
678  index_out += 1
679 
680  return returnDict
681 
682