1 try:
2 import madgraph.iolibs.file_writers as writers
3 except:
4 import aloha.file_writers as writers
5
6 import os
7 import re
8 from numbers import Number
11 """ Generic writing functions """
12
13 power_symbol = '**'
14 change_var_format = str
15 change_number_format = str
16 extension = ''
17 type_to_variable = {2:'F',3:'V',5:'T',1:'S'}
18 type_to_size = {'S':3, 'T':18, 'V':6, 'F':6}
19
20
21 - def __init__(self, abstract_routine, dirpath):
22
23
24 name = get_routine_name(abstract = abstract_routine)
25 if dirpath:
26 self.dir_out = dirpath
27 self.out_path = os.path.join(dirpath, name + self.extension)
28 else:
29 self.out_path = None
30 self.dir_out = None
31
32 self.obj = abstract_routine.expr
33 self.particles = [self.type_to_variable[spin] for spin in \
34 abstract_routine.spins]
35 self.namestring = name
36 self.abstractname = abstract_routine.name
37 self.comment = abstract_routine.infostr
38 self.offshell = abstract_routine.outgoing
39
40 self.symmetries = abstract_routine.symmetries
41 self.tag = abstract_routine.tag
42
43 self.outgoing = self.offshell
44 if 'C%s' %((self.outgoing + 1) // 2) in self.tag:
45
46 self.outgoing = self.outgoing + self.outgoing % 2 - (self.outgoing +1) % 2
47
48
49
50
51
52
53 self.collect_variables()
54 self.make_all_lists()
55
56
57
58
59
61 """find the Fortran HELAS position for the list of index"""
62
63
64 if len(indices) == 1:
65 return indices[0] + start
66
67 ind_name = self.obj.numerator.lorentz_ind
68 if ind_name == ['I3', 'I2']:
69 return 4 * indices[1] + indices[0] + start
70 elif len(indices) == 2:
71 return 4 * indices[0] + indices[1] + start
72 else:
73 raise Exception, 'WRONG CONTRACTION OF LORENTZ OBJECT for routine %s: %s' \
74 % (self.namestring, indices)
75
77 """Collects Momenta,Mass,Width into lists"""
78
79 MomentaList = set()
80 OverMList = set()
81 for elem in self.obj.tag:
82 if elem.startswith('P'):
83 MomentaList.add(elem)
84 elif elem.startswith('O'):
85 OverMList.add(elem)
86
87 MomentaList = list(MomentaList)
88 OverMList = list(OverMList)
89
90 self.collected = {'momenta':MomentaList, 'om':OverMList}
91
92 return self.collected
93
95 """ Prototype for language specific header"""
96 pass
97
98 - def define_content(self):
99 """Prototype for language specific body"""
100 pass
101
105
107 """Routine for making a string out of indices objects"""
108
109 text = 'output(%s)' % indices
110 return text
111
130
132 """Turn a multvariable into a string"""
133 mult_list = [self.write_obj(factor) for factor in obj]
134 text = '('
135 if obj.prefactor != 1:
136 if obj.prefactor != -1:
137 text = self.change_number_format(obj.prefactor) + '*' + text
138 else:
139 text = '-' + text
140 return text + '*'.join(mult_list) + ')'
141
154
155
167
169 """ Make all the list for call ordering, conservation impulsion,
170 basic declaration"""
171
172 DeclareList = self.make_declaration_list()
173 CallList = self.make_call_list()
174 MomentumConserve = self.make_momentum_conservation()
175
176 self.calllist = {'CallList':CallList,'DeclareList':DeclareList, \
177 'Momentum':MomentumConserve}
178
179
181 """find the way to write the call of the functions"""
182
183 if outgoing is None:
184 outgoing = self.offshell
185
186 call_arg = []
187
188 conjugate = [2*(int(c[1:])-1) for c in self.tag if c[0] == 'C']
189
190 for index,spin in enumerate(self.particles):
191 if self.offshell == index + 1:
192 continue
193
194 if index in conjugate:
195 index2, spin2 = index+1, self.particles[index+1]
196 call_arg.append('%s%d' % (spin2, index2 +1))
197
198 elif index-1 in conjugate:
199 index2, spin2 = index-1, self.particles[index-1]
200 call_arg.append('%s%d' % (spin2, index2 +1))
201 else:
202 call_arg.append('%s%d' % (spin, index +1))
203
204 return call_arg
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
222 """ compute the sign for the momentum conservation """
223
224 if not self.offshell:
225 return []
226
227 sign_dict = {1: '+', -1: '-'}
228
229 momentum_conserve = []
230 nb_fermion =0
231
232
233 if not self.offshell % 2 and self.particles[self.offshell -1] == 'F':
234 global_sign = 1
235 else:
236 global_sign = -1
237
238 flipped = [2*(int(c[1:])-1) for c in self.tag if c.startswith('C')]
239
240
241
242
243
244
245
246
247
248 for index, spin in enumerate(self.particles):
249 assert(spin in ['S','F','V','T'])
250
251
252 if spin != 'F':
253 sign = -1 * global_sign
254 elif nb_fermion % 2 == 0:
255 sign = global_sign
256 nb_fermion += 1
257 if index in flipped:
258 sign *= -1
259 else:
260 sign = -1 * global_sign
261 nb_fermion += 1
262 if index-1 in flipped:
263 sign *= -1
264
265 if index == self.outgoing -1:
266 continue
267
268
269 momentum_conserve.append('%s%s%d' % (sign_dict[sign], spin, \
270 index + 1))
271
272
273 if momentum_conserve[0][0] == '+':
274 momentum_conserve[0] = momentum_conserve[0][1:]
275
276 return momentum_conserve
277
279 """ make the list of declaration nedded by the header """
280
281 declare_list = []
282
283
284 for index, spin in enumerate(self.particles):
285
286 declare_list.append(self.declare_dict[spin] % (index + 1) )
287
288 return declare_list
289
292 """routines for writing out Fortran"""
293
294 extension = '.f'
295 declare_dict = {'S':'double complex S%d(*)',
296 'F':'double complex F%d(*)',
297 'V':'double complex V%d(*)',
298 'T':'double complex T%s(*)'}
299
301 """Define the Header of the fortran file. This include
302 - function tag
303 - definition of variable
304 """
305
306 if not name:
307 name = self.namestring
308
309 Momenta = self.collected['momenta']
310 OverM = self.collected['om']
311
312 CallList = self.calllist['CallList']
313 declare_list = self.calllist['DeclareList']
314 if 'double complex COUP' in declare_list:
315 alredy_update = True
316 else:
317 alredy_update = False
318
319 if not alredy_update:
320 declare_list.append('double complex COUP')
321
322
323 if not self.offshell:
324 str_out = 'subroutine %(name)s(%(args)s,vertex)\n' % \
325 {'name': name,
326 'args': ','.join(CallList+ ['COUP']) }
327 if not alredy_update:
328 declare_list.append('double complex vertex')
329 else:
330 if not alredy_update:
331 declare_list.append('double complex denom')
332 declare_list.append('double precision M%(id)d, W%(id)d' %
333 {'id': self.outgoing})
334 call_arg = '%(args)s, COUP, M%(id)d, W%(id)d, %(spin)s%(id)d' % \
335 {'args': ', '.join(CallList),
336 'spin': self.particles[self.offshell -1],
337 'id': self.outgoing}
338 str_out = ' subroutine %s(%s)\n' % (name, call_arg)
339
340
341 str_out += 'implicit none \n'
342
343
344 for elem in declare_list:
345 str_out += elem + '\n'
346 if len(OverM) > 0:
347 str_out += 'double complex ' + ','.join(OverM) + '\n'
348 if len(Momenta) > 0:
349 str_out += 'double precision ' + '(0:3),'.join(Momenta) + '(0:3)\n'
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 return str_out
366
368 """Define the Header of the fortran file. This include
369 - momentum conservation
370 -definition of the impulsion"""
371
372
373 momenta = self.collected['momenta']
374 overm = self.collected['om']
375 momentum_conservation = self.calllist['Momentum']
376
377 str_out = ''
378
379 if self.offshell:
380 offshelltype = self.particles[self.offshell -1]
381 offshell_size = self.type_to_size[offshelltype]
382
383 for i in range(-1,1):
384 str_out += '%s%d(%d)= ' % (offshelltype, self.outgoing, \
385 offshell_size + i)
386
387 pat=re.compile(r'^[-+]?(?P<spin>\w)')
388 for elem in momentum_conservation:
389 spin = pat.search(elem).group('spin')
390 str_out += '%s(%d)' % (elem, self.type_to_size[spin] + i)
391 str_out += '\n'
392
393
394 for mom in momenta:
395
396 index = int(mom[1:])
397 type = self.particles[index - 1]
398 energy_pos = self.type_to_size[type] -1
399 sign = 1
400 if self.offshell == index and type in ['V','S']:
401 sign = -1
402 if 'C%s' % ((index +1) // 2) in self.tag:
403 if index == self.outgoing:
404 pass
405 elif index % 2 and index -1 != self.outgoing:
406 pass
407 elif index % 2 == 1 and index + 1 != self.outgoing:
408 pass
409 else:
410 sign *= -1
411
412 if sign == -1 :
413 sign = '-'
414 else:
415 sign = ''
416
417 str_out += '%s(0) = %s dble(%s%d(%d))\n' % (mom, sign, type, index, energy_pos)
418 str_out += '%s(1) = %s dble(%s%d(%d))\n' % (mom, sign, type, index, energy_pos + 1)
419 str_out += '%s(2) = %s dimag(%s%d(%d))\n' % (mom, sign, type, index, energy_pos + 1)
420 str_out += '%s(3) = %s dimag(%s%d(%d))\n' % (mom, sign, type, index, energy_pos)
421
422
423
424 for elem in overm:
425
426 index = int(elem[2:])
427 str_out += 'OM%d = 0d0\n' % (index)
428 str_out += 'if (M%d .ne. 0d0) OM%d' % (index, index) + '=1d0/M%d**2\n' % (index)
429
430
431 return str_out
432
433
435 """Formatting the variable name to Fortran format"""
436
437 if '_' in name:
438 name = name.replace('_', '(', 1) + ')'
439
440 return name
441
442 zero_pattern = re.compile(r'''0+$''')
451
452 if isinteger(number):
453 out = str(int(number))
454 elif isinstance(number, complex):
455 if number.imag:
456 out = '(%s, %s)' % (self.change_number_format(number.real) , \
457 self.change_number_format(number.imag))
458 else:
459 out = self.change_number_format(number.real)
460 else:
461 out = '%.9f' % number
462 out = self.zero_pattern.sub('', out)
463 return out
464
465
467 OutString = ''
468 if not self.offshell:
469 for ind in self.obj.listindices():
470 string = 'Vertex = COUP*' + self.write_obj(self.obj.get_rep(ind))
471 string = string.replace('+-', '-')
472 string = re.sub('\((?P<num>[+-]*[0-9])(?P<num2>[+-][0-9])[Jj]\)\.', '(\g<num>d0,\g<num2>d0)', string)
473 string = re.sub('(?P<num>[0-9])[Jj]\.', '\g<num>.*(0d0,1d0)', string)
474 OutString = OutString + string + '\n'
475 else:
476 OffShellParticle = '%s%d' % (self.particles[self.offshell-1],\
477 self.outgoing)
478 numerator = self.obj.numerator
479 denominator = self.obj.denominator
480 for ind in denominator.listindices():
481 denom = self.write_obj(denominator.get_rep(ind))
482 string = 'denom =' + '1d0/(' + denom + ')'
483 string = string.replace('+-', '-')
484 string = re.sub('\((?P<num>[+-]*[0-9])\+(?P<num2>[+-][0-9])[Jj]\)\.', '(\g<num>d0,\g<num2>d0)', string)
485 string = re.sub('(?P<num>[0-9])[Jj]\.', '\g<num>*(0d0,1d0)', string)
486 OutString = OutString + string + '\n'
487 for ind in numerator.listindices():
488 string = '%s(%d)= COUP*denom*' % (OffShellParticle, self.pass_to_HELAS(ind, start=1))
489 string += self.write_obj(numerator.get_rep(ind))
490 string = string.replace('+-', '-')
491 string = re.sub('\((?P<num>[+-][0-9])\+(?P<num2>[+-][0-9])[Jj]\)\.', '(\g<num>d0,\g<num2>d0)', string)
492 string = re.sub('(?P<num>[0-9])[Jj]\.', '\g<num>*(0d0,1d0)', string)
493 OutString = OutString + string + '\n'
494 return OutString
495
497 number = self.offshell
498 calls = self.calllist['CallList']
499
500 Outstring = 'call '+self.namestring+'('+','.join(calls)+',COUP,M%s,W%s,%s%s)\n' \
501 %(number,number,self.particles[number-1],number)
502 return Outstring
503
506
507 - def write(self, mode='self'):
508
509
510 text = self.define_header()+'\n'
511 text += self.define_momenta()+'\n'
512 text += self.define_expression()
513 text += self.define_foot()
514
515 sym_text = []
516 for elem in self.symmetries:
517 symmetryhead = self.define_header().replace( \
518 self.namestring,self.namestring[0:-1]+'%s' %(elem))
519 symmetrybody = self.define_symmetry(elem)
520
521 sym_text.append(symmetryhead + symmetrybody + self.define_foot())
522
523
524 if self.out_path:
525 writer = writers.FortranWriter(self.out_path)
526 writer.downcase = False
527 commentstring = 'This File is Automatically generated by ALOHA \n'
528 commentstring += 'The process calculated in this file is: \n'
529 commentstring += self.comment + '\n'
530 writer.write_comments(commentstring)
531 writer.writelines(text)
532 for text in sym_text:
533 writer.write_comments('\n%s\n' % ('#'*65))
534 writer.writelines(text)
535 else:
536 for stext in sym_text:
537 text += '\n\n' + stext
538
539 return text + '\n'
540
542 """Write routine for combine ALOHA call (more than one coupling)"""
543
544
545 if offshell is None:
546 sym = 1
547 offshell = self.offshell
548 else:
549 sym = None
550
551 name = combine_name(self.abstractname, lor_names, offshell, self.tag)
552
553
554
555 header = self.define_header(name=name)
556 new_couplings = ['COUP%s' % (i+1) for i in range(len(lor_names)+1)]
557 text = header.replace('COUP', ','.join(new_couplings))
558
559 if not offshell:
560 text += ' double complex TMP\n'
561 else:
562 spin = self.particles[offshell -1]
563 text += ' double complex TMP(%s)\n integer i' % self.type_to_size[spin]
564
565
566 addon = ''.join(self.tag) + '_%s' % self.offshell
567
568
569
570
571
572
573
574
575
576
577
578
579
580 if not offshell:
581 main = 'vertex'
582 call_arg = '%(args)s, %(COUP)s, %(LAST)s' % \
583 {'args': ', '.join(self.calllist['CallList']),
584 'COUP':'COUP%d',
585 'spin': self.particles[self.offshell -1],
586 'LAST': '%s'}
587 else:
588 main = '%(spin)s%(id)d' % \
589 {'spin': self.particles[offshell -1],
590 'id': self.outgoing}
591 call_arg = '%(args)s, %(COUP)s, M%(id)d, W%(id)d, %(LAST)s' % \
592 {'args': ', '.join(self.calllist['CallList']),
593 'COUP':'COUP%d',
594 'id': self.outgoing,
595 'LAST': '%s'}
596
597
598 line = " CALL %s%s("+call_arg+")\n"
599 text += '\n\n' + line % (self.namestring, '', 1, main)
600
601
602 for i,lor in enumerate(lor_names):
603 text += line % (lor, addon, i+2, 'TMP')
604 if not offshell:
605 text += ' vertex = vertex + tmp\n'
606 else:
607 size = self.type_to_size[spin] -2
608 text += """ do i=1,%(id)d
609 %(main)s(i) = %(main)s(i) + tmp(i)
610 enddo\n""" % {'id': size, 'main':main}
611
612
613 text += self.define_foot()
614
615
616 if sym:
617 for elem in self.symmetries:
618 text += self.write_combined(lor_names, mode, elem)
619
620
621 if self.out_path:
622
623 path = os.path.join(os.path.dirname(self.out_path), name+'.f')
624 writer = writers.FortranWriter(path)
625 writer.downcase = False
626 commentstring = 'This File is Automatically generated by ALOHA \n'
627 writer.write_comments(commentstring)
628 writer.writelines(text)
629
630 return text
631
633 """ build the name of the aloha function """
634
635 assert (name and outgoing) or abstract
636
637 if tag is None:
638 tag = abstract.tag
639
640 if name is None:
641 name = abstract.name + ''.join(tag)
642
643 if outgoing is None:
644 outgoing = abstract.outgoing
645
646
647 return '%s_%s' % (name, outgoing)
648
650 """ build the name for combined aloha function """
651
652
653
654
655 p=re.compile('^(?P<type>[FSVT]+)(?P<id>\d+)')
656 routine = ''
657 if p.search(name):
658 base, id = p.search(name).groups()
659 if tag is not None:
660 routine = name + ''.join(tag)
661 else:
662 routine = name
663 for s in other_names:
664 try:
665 base2,id2 = p.search(s).groups()
666 except:
667 routine = ''
668 break
669 if base != base2:
670 routine = ''
671 break
672 else:
673 routine += '_%s' % id2
674 if routine:
675 return routine +'_%s' % outgoing
676
677 if tag is not None:
678 addon = ''.join(tag)
679 else:
680 addon = ''
681 if 'C' in name:
682 short_name, addon = name.split('C',1)
683 try:
684 addon = 'C' + str(int(addon))
685 except:
686 addon = ''
687 else:
688 name = short_name
689
690 return '_'.join((name,) + tuple(other_names)) + addon + '_%s' % outgoing
691
694 """Routines for writing out helicity amplitudes as C++ .h and .cc files."""
695
696 declare_dict = {'S':'double complex S%d[3]',
697 'F':'double complex F%d[6]',
698 'V':'double complex V%d[6]',
699 'T':'double complex T%s[18]'}
700
702 """Define the headers for the C++ .h and .cc files. This include
703 - function tag
704 - definition of variable
705 - momentum conservation
706 """
707
708 if name is None:
709 name = self.namestring
710
711
712
713
714 CallList = self.calllist['CallList'][:]
715
716 local_declare = []
717 OffShell = self.offshell
718 OffShellParticle = OffShell -1
719
720 for i, call in enumerate(CallList):
721 CallList[i] = "complex<double> %s[]" % call
722
723
724
725
726
727
728 if not OffShell:
729 str_out = 'void %(name)s(%(args)s, complex<double>& vertex)' % \
730 {'name': name,
731 'args': ','.join(CallList + ['complex<double> COUP'])}
732 else:
733 str_out = 'void %(name)s(%(args)s, double M%(number)d, double W%(number)d, complex<double>%(out)s%(number)d[])' % \
734 {'name': name,
735 'args': ','.join(CallList+ ['complex<double> COUP']),
736 'out': self.particles[self.outgoing - 1],
737 'number': self.outgoing
738 }
739
740 h_string = str_out + ";\n\n"
741 cc_string = str_out + "{\n"
742
743 return {'h_header': h_string, 'cc_header': cc_string}
744
746 """Write the expressions for the momentum of the outgoing
747 particle."""
748
749 momenta = self.collected['momenta']
750 overm = self.collected['om']
751 momentum_conservation = self.calllist['Momentum']
752
753 str_out = ''
754
755 if self.offshell:
756 str_out += 'complex<double> denom;\n'
757 if len(overm) > 0:
758 str_out += 'complex<double> %s;\n' % ','.join(overm)
759 if len(momenta) > 0:
760 str_out += 'double %s[4];\n' % '[4],'.join(momenta)
761
762
763 if self.offshell:
764 offshelltype = self.particles[self.offshell -1]
765 offshell_size = self.type_to_size[offshelltype]
766
767 for i in range(-2,0):
768 str_out += '%s%d[%d]= ' % (offshelltype, self.outgoing,
769 offshell_size + i)
770
771 pat=re.compile(r'^[-+]?(?P<spin>\w)')
772 for elem in momentum_conservation:
773 spin = pat.search(elem).group('spin')
774 str_out += '%s[%d]' % (elem, self.type_to_size[spin] + i)
775 str_out += ';\n'
776
777
778 for mom in momenta:
779
780 index = int(mom[1:])
781
782 type = self.particles[index - 1]
783 energy_pos = self.type_to_size[type] - 2
784 sign = 1
785 if self.offshell == index and type in ['V', 'S']:
786 sign = -1
787 if 'C%s' % ((index +1) // 2) in self.tag:
788 if index == self.outgoing:
789 pass
790 elif index % 2 and index -1 != self.outgoing:
791 pass
792 elif index %2 == 1 and index + 1 != self.outgoing:
793 pass
794 else:
795 sign *= -1
796
797 if sign == -1 :
798 sign = '-'
799 else:
800 sign = ''
801
802 str_out += '%s[0] = %s%s%d[%d].real();\n' % (mom, sign, type, index, energy_pos)
803 str_out += '%s[1] = %s%s%d[%d].real();\n' % (mom, sign, type, index, energy_pos + 1)
804 str_out += '%s[2] = %s%s%d[%d].imag();\n' % (mom, sign, type, index, energy_pos + 1)
805 str_out += '%s[3] = %s%s%d[%d].imag();\n' % (mom, sign, type, index, energy_pos)
806
807
808 for elem in overm:
809
810 index = int(elem[2:])
811 str_out += 'OM%d = 0;\n' % (index)
812 str_out += 'if (M%d != 0) OM%d' % (index, index) + '= 1./pow(M%d,2);\n' % (index)
813
814
815 return str_out
816
817
819 """Format the variable name to C++ format"""
820
821 if '_' in name:
822 name = name.replace('_','[',1) +']'
823 outstring = ''
824 counter = 0
825 for elem in re.finditer('[FVTSfvts][0-9]\[[0-9]\]',name):
826 outstring += name[counter:elem.start()+2]+'['+str(int(name[elem.start()+3:elem.start()+4])-1)+']'
827 counter = elem.end()
828 outstring += name[counter:]
829
830 return outstring
831
848
850 """Write the helicity amplitude in C++ format"""
851 OutString = ''
852 if not self.offshell:
853 for ind in self.obj.listindices():
854 string = 'vertex = COUP*' + self.write_obj(self.obj.get_rep(ind))
855 string = string.replace('+-', '-')
856 OutString = OutString + string + ';\n'
857 else:
858 OffShellParticle = self.particles[self.offshell-1]+'%s'%(self.outgoing)
859 numerator = self.obj.numerator
860 denominator = self.obj.denominator
861 for ind in denominator.listindices():
862 denom = self.write_obj(denominator.get_rep(ind))
863 string = 'denom =' + '1./(' + denom + ')'
864 string = string.replace('+-', '-')
865 OutString = OutString + string + ';\n'
866 for ind in numerator.listindices():
867 string = '%s[%d]= COUP*denom*' % (OffShellParticle, self.pass_to_HELAS(ind))
868 string += self.write_obj(numerator.get_rep(ind))
869 string = string.replace('+-', '-')
870 OutString = OutString + string + ';\n'
871 OutString = re.sub('(?P<variable>[A-Za-z]+[0-9]\[*[0-9]*\]*)\*\*(?P<num>[0-9])','pow(\g<variable>,\g<num>)',OutString)
872 return OutString
873
874 remove_double = re.compile('complex<double> (?P<name>[\w]+)\[\]')
876 """Write the call for symmetric routines"""
877 calls = self.calllist['CallList']
878
879 for i, call in enumerate(calls):
880 if self.remove_double.match(call):
881 calls[i] = self.remove_double.match(call).group('name')
882
883
884
885
886 number = self.offshell
887 Outstring = self.namestring+'('+','.join(calls)+',COUP,M%s,W%s,%s%s);\n' \
888 %(number,number,self.particles[self.offshell-1],number)
889 return Outstring
890
895
896 - def write_h(self, header, compiler_cmd=True):
897 """Return the full contents of the .h file"""
898
899 h_string = ''
900 if compiler_cmd:
901 h_string = '#ifndef '+ self.namestring + '_guard\n'
902 h_string += '#define ' + self.namestring + '_guard\n'
903 h_string += '#include <complex>\n'
904 h_string += 'using namespace std;\n\n'
905
906 h_header = header['h_header']
907
908 h_string += h_header
909
910 for elem in self.symmetries:
911 symmetryhead = h_header.replace( \
912 self.namestring,self.namestring[0:-1]+'%s' %(elem))
913 h_string += symmetryhead
914
915 if compiler_cmd:
916 h_string += '#endif\n\n'
917
918 return h_string
919
921 """Return the content of the .h file linked to multiple lorentz call."""
922
923 name = combine_name(self.abstractname, lor_names, offshell, self.tag)
924 text= ''
925 if compiler_cmd:
926 text = '#ifndef '+ name + '_guard\n'
927 text += '#define ' + name + '_guard\n'
928 text += '#include <complex>\n'
929 text += 'using namespace std;\n\n'
930
931
932 header = self.define_header(name=name)
933 h_header = header['h_header']
934 new_couplings = ['COUP%s' % (i+1) for i in range(len(lor_names)+1)]
935 h_string = h_header.replace('COUP', ', complex <double>'.join(new_couplings))
936 text += h_string
937
938 for elem in self.symmetries:
939 text += h_string.replace(name, name[0:-1]+str(elem))
940
941 if compiler_cmd:
942 text += '#endif'
943
944 return text
945
946 - def write_cc(self, header, compiler_cmd=True):
947 """Return the full contents of the .cc file"""
948
949 cc_string = ''
950 if compiler_cmd:
951 cc_string = '#include \"%s.h\"\n\n' % self.namestring
952 cc_header = header['cc_header']
953 cc_string += cc_header
954 cc_string += self.define_momenta()
955 cc_string += self.define_expression()
956 cc_string += self.define_foot()
957
958 for elem in self.symmetries:
959 symmetryhead = cc_header.replace( \
960 self.namestring,self.namestring[0:-1]+'%s' %(elem))
961 symmetrybody = self.define_symmetry(elem)
962 cc_string += symmetryhead
963 cc_string += symmetrybody
964 cc_string += self.define_foot()
965
966 return cc_string
967
969 "Return the content of the .cc file linked to multiple lorentz call."
970
971
972 if offshell is None:
973 offshell = self.offshell
974
975 name = combine_name(self.abstractname, lor_names, offshell, self.tag)
976
977 text = ''
978 if compiler_cmd:
979 text += '#include "%s.h"\n\n' % name
980
981
982 header = self.define_header(name=name)['cc_header']
983 new_couplings = ['COUP%s' % (i+1) for i in range(len(lor_names)+1)]
984 text += header.replace('COUP', ', complex<double>'.join(new_couplings))
985
986 if not offshell:
987 text += 'complex<double> tmp;\n'
988 else:
989 spin = self.particles[offshell -1]
990 text += 'complex<double> tmp[%s];\n int i = 0;' % self.type_to_size[spin]
991
992
993 addon = ''
994 if 'C' in self.namestring:
995 short_name, addon = name.split('C',1)
996 if addon.split('_')[0].isdigit():
997 addon = 'C' +self.namestring.split('C',1)[1]
998 elif all([n.isdigit() for n in addon.split('_')[0].split('C')]):
999 addon = 'C' +self.namestring.split('C',1)[1]
1000 else:
1001 addon = '_%s' % self.offshell
1002 else:
1003 addon = '_%s' % self.offshell
1004
1005
1006 if not offshell:
1007 main = 'vertex'
1008 call_arg = '%(args)s, %(COUP)s, %(LAST)s' % \
1009 {'args': ', '.join(self.calllist['CallList']),
1010 'COUP':'COUP%d',
1011 'spin': self.particles[self.offshell -1],
1012 'LAST': '%s'}
1013 else:
1014 main = '%(spin)s%(id)d' % \
1015 {'spin': self.particles[self.offshell -1],
1016 'id': self.outgoing}
1017 call_arg = '%(args)s, %(COUP)s, M%(id)d, W%(id)d, %(LAST)s' % \
1018 {'args': ', '.join(self.calllist['CallList']),
1019 'COUP':'COUP%d',
1020 'id': self.outgoing,
1021 'LAST': '%s'}
1022
1023
1024 line = "%s%s("+call_arg+");\n"
1025 text += '\n\n' + line % (self.namestring, '', 1, main)
1026
1027
1028 for i,lor in enumerate(lor_names):
1029 text += line % (lor, addon, i+2, 'tmp')
1030 if not offshell:
1031 text += ' vertex = vertex + tmp;\n'
1032 else:
1033 size = self.type_to_size[spin] -2
1034 text += """ while (i < %(id)d)
1035 {
1036 %(main)s[i] = %(main)s[i] + tmp[i];
1037 i++;
1038 }\n""" % {'id': size, 'main':main}
1039
1040
1041 text += self.define_foot()
1042
1043 if sym:
1044 for elem in self.symmetries:
1045 text += self.write_combined_cc(lor_names, elem,
1046 compiler_cmd=compiler_cmd,
1047 sym=False)
1048
1049
1050 if self.out_path:
1051
1052 path = os.path.join(os.path.dirname(self.out_path), name+'.f')
1053 writer = writers.FortranWriter(path)
1054 writer.downcase = False
1055 commentstring = 'This File is Automatically generated by ALOHA \n'
1056 writer.write_comments(commentstring)
1057 writer.writelines(text)
1058
1059 return text
1060
1061
1062
1063 - def write(self, mode='self', **opt):
1064 """Write the .h and .cc files"""
1065
1066
1067
1068 header = self.define_header()
1069 h_text = self.write_h(header, **opt)
1070 cc_text = self.write_cc(header, **opt)
1071
1072
1073 if self.out_path:
1074 writer_h = writers.CPPWriter(self.out_path + ".h")
1075 writer_cc = writers.CPPWriter(self.out_path + ".cc")
1076 commentstring = 'This File is Automatically generated by ALOHA \n'
1077 commentstring += 'The process calculated in this file is: \n'
1078 commentstring += self.comment + '\n'
1079 writer_h.write_comments(commentstring)
1080 writer_cc.write_comments(commentstring)
1081 writer_h.writelines(h_text)
1082 writer_cc.writelines(cc_text)
1083
1084 return h_text, cc_text
1085
1086
1087
1088 - def write_combined(self, lor_names, mode='self', offshell=None, **opt):
1089 """Write the .h and .cc files associated to the combined file"""
1090
1091
1092 if offshell is None:
1093 offshell = self.offshell
1094
1095 name = combine_name(self.abstractname, lor_names, offshell, self.tag)
1096
1097 h_text = self.write_combined_h(lor_names, offshell, **opt)
1098 cc_text = self.write_combined_cc(lor_names, offshell, sym=True, **opt)
1099
1100 if self.out_path:
1101
1102 path = os.path.join(os.path.dirname(self.out_path), name)
1103 commentstring = 'This File is Automatically generated by ALOHA \n'
1104
1105 writer_h = writers.CPPWriter(path + ".h")
1106 writer_h.write_comments(commentstring)
1107 writer_h.writelines(h_text)
1108
1109 writer_cc = writers.CPPWriter(path + ".cc")
1110 writer_cc.write_comments(commentstring)
1111 writer_cc.writelines(cc_text)
1112 else:
1113 return h_text, cc_text
1114
1115 return h_text, cc_text
1116
1118 """ A class for returning a file/a string for python evaluation """
1119
1120 extension = '.py'
1121
1122 - def __init__(self, abstract_routine, dirpath=None):
1123 """ standard init but if dirpath is None the write routine will
1124 return a string (which can be evaluated by an exec"""
1125
1126 WriteALOHA.__init__(self, abstract_routine, dirpath)
1127 self.outname = '%s%s' % (self.particles[self.offshell -1], \
1128 self.outgoing)
1129
1130 @staticmethod
1139
1140
1142 """Formatting the variable name to Python format
1143 start to count at zero"""
1144
1145 def shift_indices(match):
1146 """shift the indices for non impulsion object"""
1147 if match.group('var').startswith('P'):
1148 shift = 0
1149 else:
1150 shift = -1
1151
1152 return '%s[%s]' % (match.group('var'), \
1153 int(match.group('num')) + shift)
1154
1155
1156 name = re.sub('(?P<var>\w*)_(?P<num>\d+)$', shift_indices , name)
1157 return name
1158
1160 """Define the functions in a 100% way """
1161
1162 OutString = ''
1163 if not self.offshell:
1164 for ind in self.obj.listindices():
1165 string = 'vertex = COUP*' + self.write_obj(self.obj.get_rep(ind))
1166 string = string.replace('+-', '-')
1167 OutString = OutString + string + '\n'
1168 else:
1169 OffShellParticle = '%s%d' % (self.particles[self.offshell-1],\
1170 self.offshell)
1171 numerator = self.obj.numerator
1172 denominator = self.obj.denominator
1173 for ind in denominator.listindices():
1174 denom = self.write_obj(denominator.get_rep(ind))
1175 string = 'denom =' + '1.0/(' + denom + ')'
1176 string = string.replace('+-', '-')
1177 OutString += string + '\n'
1178 for ind in numerator.listindices():
1179 string = '%s[%d]= COUP*denom*' % (self.outname, self.pass_to_HELAS(ind))
1180 string += self.write_obj(numerator.get_rep(ind))
1181 string = string.replace('+-', '-')
1182 OutString += string + '\n'
1183 return OutString
1184
1190
1191
1193 """Define the Header of the fortran file. This include
1194 - function tag
1195 - definition of variable
1196 """
1197 if name is None:
1198 name = self.namestring
1199
1200 Momenta = self.collected['momenta']
1201 OverM = self.collected['om']
1202
1203 CallList = self.calllist['CallList']
1204
1205 str_out = ''
1206
1207 if not self.offshell:
1208 str_out += 'def %(name)s(%(args)s):\n' % \
1209 {'name': name,
1210 'args': ','.join(CallList+ ['COUP']) }
1211 else:
1212 str_out += 'def %(name)s(%(args)s, COUP, M%(id)d, W%(id)d):\n' % \
1213 {'name': name,
1214 'args': ', '.join(CallList),
1215 'id': self.outgoing}
1216 return str_out
1217
1219 """ make the list of declaration nedded by the header """
1220 return []
1221
1223 """Define the Header of the fortran file. This include
1224 - momentum conservation
1225 - definition of the impulsion"""
1226
1227
1228 momenta = self.collected['momenta']
1229 overm = self.collected['om']
1230 momentum_conservation = self.calllist['Momentum']
1231
1232 str_out = ''
1233
1234
1235 if self.offshell:
1236 offshelltype = self.particles[self.offshell -1]
1237 offshell_size = self.type_to_size[offshelltype]
1238 str_out += '%s = wavefunctions.WaveFunction(size=%s)\n' % \
1239 (self.outname, offshell_size)
1240
1241 if self.offshell:
1242
1243 for i in range(-2,0):
1244 str_out += '%s[%d] = ' % (self.outname, offshell_size + i)
1245
1246 pat=re.compile(r'^[-+]?(?P<spin>\w)')
1247 for elem in momentum_conservation:
1248 spin = pat.search(elem).group('spin')
1249 str_out += '%s[%d]' % (elem, self.type_to_size[spin] + i)
1250 str_out += '\n'
1251
1252
1253 for mom in momenta:
1254
1255 index = int(mom[1:])
1256 type = self.particles[index - 1]
1257 energy_pos = self.type_to_size[type] -2
1258 sign = 1
1259 if self.offshell == index and type in ['V','S']:
1260 sign = -1
1261
1262 if 'C%s' % ((index +1) // 2) in self.tag:
1263 if index == self.outgoing:
1264 pass
1265 elif index % 2 and index -1 != self.outgoing:
1266 pass
1267 elif index %2 == 1 and index + 1 != self.outgoing:
1268 pass
1269 else:
1270 sign *= -1
1271
1272 if sign == -1 :
1273 sign = '- '
1274 else:
1275 sign = ''
1276
1277 str_out += '%s = [%scomplex(%s%d[%d]).real, \\\n' % (mom, sign, type, index, energy_pos)
1278 str_out += ' %scomplex(%s%d[%d]).real, \\\n' % ( sign, type, index, energy_pos + 1)
1279 str_out += ' %scomplex(%s%d[%d]).imag, \\\n' % ( sign, type, index, energy_pos + 1)
1280 str_out += ' %scomplex(%s%d[%d]).imag]\n' % ( sign, type, index, energy_pos)
1281
1282
1283 for elem in overm:
1284
1285 index = int(elem[2:])
1286 str_out += 'OM%d = 0.0\n' % (index)
1287 str_out += 'if (M%d): OM%d' % (index, index) + '=1.0/M%d**2\n' % (index)
1288
1289
1290 return str_out
1291
1293 number = self.offshell
1294 calls = self.calllist['CallList']
1295 Outstring = 'return '+self.namestring+'('+','.join(calls)+',COUP,M%s,W%s)\n' \
1296 %(number,number)
1297 return Outstring
1298
1299 - def write(self,mode='self'):
1300
1301
1302 if mode == 'mg5':
1303 text = 'import aloha.template_files.wavefunctions as wavefunctions\n'
1304 else:
1305 text = 'import wavefunctions\n'
1306 text += self.define_header()
1307 content = self.define_momenta()
1308 content += self.define_expression()
1309 content += self.define_foot()
1310
1311
1312 text += ' ' +content.replace('\n','\n ')
1313
1314 for elem in self.symmetries:
1315 text +='\n' + self.define_header().replace( \
1316 self.namestring,self.namestring[0:-1]+'%s' %(elem))
1317 text += ' ' +self.define_symmetry(elem)
1318
1319
1320 if self.out_path:
1321 ff = open(self.out_path,'w').write(text)
1322
1323 return text + '\n'
1324
1326 """Write routine for combine ALOHA call (more than one coupling)"""
1327
1328
1329 if offshell is None:
1330 sym = 1
1331 offshell = self.offshell
1332 else:
1333 sym = None
1334 name = combine_name(self.abstractname, lor_names, offshell, self.tag)
1335
1336
1337 text = ''
1338
1339
1340
1341
1342
1343
1344
1345 header = self.define_header(name=name)
1346 new_couplings = ['COUP%s' % (i+1) for i in range(len(lor_names)+1)]
1347 header = header.replace('COUP', ','.join(new_couplings))
1348
1349 text += header
1350
1351
1352 addon = ''.join(self.tag) + '_%s' % self.offshell
1353
1354
1355 if not offshell:
1356 main = 'vertex'
1357 call_arg = '%(args)s, %(COUP)s' % \
1358 {'args': ', '.join(self.calllist['CallList']),
1359 'COUP':'COUP%d',
1360 'spin': self.particles[self.offshell -1]}
1361 else:
1362 main = '%(spin)s%(id)d' % \
1363 {'spin': self.particles[self.offshell -1],
1364 'id': self.outgoing}
1365 call_arg = '%(args)s, %(COUP)s, M%(id)d, W%(id)d' % \
1366 {'args': ', '.join(self.calllist['CallList']),
1367 'COUP':'COUP%d',
1368 'id': self.outgoing}
1369
1370
1371 line = " %s = %s%s("+call_arg+")\n"
1372 text += '\n\n' + line % (main, self.namestring, '', 1)
1373
1374
1375 for i,name in enumerate(lor_names):
1376 text += line % ('tmp',name, addon, i+2)
1377 if not offshell:
1378 text += ' vertex += tmp\n'
1379 else:
1380 size = self.type_to_size[self.particles[offshell -1]] -2
1381 text += " for i in range(%(id)d):\n" % {'id': size}
1382 text += " %(main)s[i] += tmp[i]\n" %{'main': main}
1383
1384 text += ' '+self.define_foot()
1385
1386
1387 if sym:
1388 for elem in self.symmetries:
1389 text += self.write_combined(lor_names, mode, elem)
1390
1391 return text
1392