1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """Classes for writing Helas calls. HelasCallWriter is the base class."""
16
17 import madgraph.core.base_objects as base_objects
18 import madgraph.core.helas_objects as helas_objects
19 import madgraph.loop.loop_helas_objects as loop_helas_objects
20 import models.check_param_card as check_param_card
21 import aloha.aloha_writers as aloha_writers
22 import aloha
23 from madgraph import MadGraph5Error
26 """Class for the error of this module """
27 pass
28
33 """Language independent base class for writing Helas calls. The
34 calls are stored in two dictionaries, wavefunctions and
35 amplitudes, with entries being a mapping from a set of spin,
36 incoming/outgoing states and Lorentz structure to a function which
37 writes the corresponding wavefunction/amplitude call (taking a
38 HelasWavefunction/HelasAmplitude as argument)."""
39
40
41
42 mother_dict = {1: 'S', 2: 'O', -2: 'I', 3: 'V', 5: 'T', 4:'OR', -4:'IR',
43 99:'P'}
44
46
47 self['model'] = base_objects.Model()
48 self['wavefunctions'] = {}
49 self['amplitudes'] = {}
50
51 - def filter(self, name, value):
82
84 """Return process property names as a nicely sorted list."""
85
86 return ['model', 'wavefunctions', 'amplitudes']
87
106
107 - def get_sqso_target_skip_code(self, number_checked, sqso_target_numbers,
108 continue_label, split_orders, squared_orders, comment):
109 """Treat the optimization for the squared order target so that
110 unnecessary computations can be skipped. This function returns the lines
111 of codes for doing so, based on the number_checked (typically amplitude number)
112 to be checked and the list of squared order contributions
113 sqso_target_numbers specifying for each of them the maximum contributing
114 number. The continue_label informs where the code must 'goto' if indeed
115 the rest of this part of the computation must be skipped.
116 The split_orders and squared_orders values lists, as well as the string
117 comment template is just for printing out a nice comment in the fortran
118 code explaining what is going on."""
119
120 res = []
121 for sqso_index, target in enumerate(sqso_target_numbers):
122 if target!=number_checked:
123 continue
124 sqso_name = ' '.join(['%s=%d'%(split_orders[i],val) for i, \
125 val in enumerate(squared_orders[sqso_index][0])])
126 sqso_identifier = "(%s), i.e. of split order ID=%d,"\
127 %(sqso_name, sqso_index)
128 res.append(comment%sqso_identifier)
129 res.append("IF(FILTER_SO.AND.SQSO_TARGET."+\
130 "EQ.%d) GOTO %d"%(sqso_index+1,continue_label))
131 return res
132
135 """Return a two lists of strings, the first corresponding to the Helas
136 calls for building the non-loop wavefunctions, the born and CT (only if
137 include_CT=True). The second correspond to the Helas calls for the
138 UVCT amplitudes only. The squared_orders can provide the information of
139 what is the maximum contributing CT amp number."""
140
141 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
142 "%s not valid argument for get_born_ct_helas_calls" % \
143 repr(matrix_element)
144
145 res = []
146
147 sqso_max_uvctamp = [sqso[1][0] for sqso in squared_orders]
148 sqso_max_ctamp = [sqso[1][1] for sqso in squared_orders]
149
150 for diagram in matrix_element.get_born_diagrams():
151 res.extend([ self.get_wavefunction_call(wf) for \
152 wf in diagram.get('wavefunctions') ])
153 res.append("# Amplitude(s) for born diagram with ID %d" % \
154 diagram.get('number'))
155 for amplitude in diagram.get('amplitudes'):
156 res.append(self.get_amplitude_call(amplitude))
157
158 for diagram in matrix_element.get_loop_diagrams():
159 res.extend([ self.get_wavefunction_call(wf) for \
160 wf in diagram.get('wavefunctions') ])
161 if diagram.get_ct_amplitudes() and include_CT:
162 res.append("# Counter-term amplitude(s) for loop diagram number %d" % \
163 diagram.get('number'))
164 for ctamp in diagram.get_ct_amplitudes():
165 res.append(self.get_amplitude_call(ctamp))
166 res.extend(self.get_sqso_target_skip_code(ctamp.get('number'),
167 sqso_max_ctamp, 2000, split_orders, squared_orders,
168 "# At this point, all CT amps needed for %s are computed."))
169
170 if not include_CT:
171 return res, []
172
173 res_UVCT = []
174 for diagram in matrix_element.get_loop_UVCT_diagrams():
175 res_UVCT.extend([ self.get_wavefunction_call(wf) for \
176 wf in diagram.get('wavefunctions') ])
177 res_UVCT.append("# Amplitude(s) for UVCT diagram with ID %d" % \
178 diagram.get('number'))
179 for ctamp in diagram.get('amplitudes'):
180 res_UVCT.append(self.get_amplitude_call(ctamp))
181 res_UVCT.extend(self.get_sqso_target_skip_code(ctamp.get('number'),
182 sqso_max_uvctamp, 3000, split_orders, squared_orders,
183 "# At this point, all UVCT amps needed for %s are computed."))
184
185 return res, res_UVCT
186
188 """Return a list of strings, corresponding to the Helas calls
189 for the loop matrix element"""
190
191 res_born_CT, res_UVCT = self.get_born_ct_helas_calls(loop_matrix_element)
192 res = res_born_CT + res_UVCT + \
193 self.get_loop_amp_helas_calls(loop_matrix_element)
194 return res
195
196
222
234
236 """Return a list of strings, corresponding to the Helas calls
237 for the matrix element"""
238
239 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
240 "%s not valid argument for get_matrix_element_calls" % \
241 repr(matrix_element)
242
243 res = []
244 for diagram in matrix_element.get('diagrams'):
245 res.append("# Amplitude(s) for diagram number %d" % \
246 diagram.get('number'))
247 for amplitude in diagram.get('amplitudes'):
248 res.append(self.get_amplitude_call(amplitude))
249
250 return res
251
253 """Return the function for writing the wavefunction
254 corresponding to the key"""
255
256 try:
257 call = self["wavefunctions"][wavefunction.get_call_key()](\
258 wavefunction)
259 return call
260 except KeyError:
261 return ""
262
264 """Return the function for writing the amplitude
265 corresponding to the key"""
266
267 try:
268 call = self["amplitudes"][amplitude.get_call_key()](amplitude)
269 return call
270 except KeyError, error:
271 return ""
272
274 """Set the function for writing the wavefunction
275 corresponding to the key"""
276
277 assert isinstance(key, tuple), \
278 "%s is not a valid tuple for wavefunction key" % key
279
280 assert callable(function), \
281 "%s is not a valid function for wavefunction string" % function
282
283 self.get('wavefunctions')[key] = function
284 return True
285
287 """Set the function for writing the amplitude
288 corresponding to the key"""
289
290 assert isinstance(key, tuple), \
291 "%s is not a valid tuple for amplitude key" % str(key)
292
293 assert callable(function), \
294 "%s is not a valid function for amplitude string" % str(function)
295
296
297 self.get('amplitudes')[key] = function
298 return True
299
301 """Return the model name"""
302 return self['model'].get('name')
303
304
305
315
320 """The class for writing Helas calls in Fortran, starting from
321 HelasWavefunctions and HelasAmplitudes.
322
323 Includes the function generate_helas_call, which automatically
324 generates the Fortran Helas call based on the Lorentz structure of
325 the interaction."""
326
327
328
329 self_dict = {1: 'H', 2: 'F', -2: 'F', 3: 'J', 5: 'U'}
330
331 sort_wf = {'O': 0, 'I': 1, 'S': 2, 'T': 3, 'V': 4}
332 sort_amp = {'S': 0, 'V': 2, 'T': 1, 'O': 3, 'I': 4}
333
335 """Set up special Helas calls (wavefunctions and amplitudes)
336 that can not be done automatically by generate_helas_call"""
337
338 super(FortranHelasCallWriter, self).default_setup()
339
340
341
342
343
344
345 key = ((3, 3, 5, 3), ('A',))
346 call = lambda wf: \
347 "CALL UVVAXX(W(1,%d),W(1,%d),%s,zero,zero,zero,W(1,%d))" % \
348 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
349 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
350 wf.get('coupling')[0],
351 wf.get('me_id'))
352 self.add_wavefunction(key, call)
353
354 key = ((3, 5, 3, 1), ('A',))
355 call = lambda wf: \
356 "CALL JVTAXX(W(1,%d),W(1,%d),%s,zero,zero,W(1,%d))" % \
357 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
358 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
359 wf.get('coupling')[0],
360 wf.get('me_id'))
361 self.add_wavefunction(key, call)
362
363 key = ((3, 3, 5), ('A',))
364 call = lambda amp: \
365 "CALL VVTAXX(W(1,%d),W(1,%d),W(1,%d),%s,zero,AMP(%d))" % \
366 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
367 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
368 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
369 amp.get('coupling')[0],
370 amp.get('number'))
371 self.add_amplitude(key, call)
372
373
374
375 key = ((3, 3, 3, 3, 1), ('gggg3',))
376 call = lambda wf: \
377 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
378 (FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
379 FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
380 FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
381 wf.get('coupling')[0],
382 wf.get('me_id'))
383 self.add_wavefunction(key, call)
384 key = ((3, 3, 3, 3), ('gggg1',))
385 call = lambda amp: \
386 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
387 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
388 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
389 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
390 FortranHelasCallWriter.sorted_mothers(amp)[3].get('me_id'),
391 amp.get('coupling')[0],
392 amp.get('number'))
393 self.add_amplitude(key, call)
394 key = ((3, 3, 3, 3, 1), ('gggg2',))
395 call = lambda wf: \
396 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
397 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
398 FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
399 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
400 wf.get('coupling')[0],
401 wf.get('me_id'))
402 self.add_wavefunction(key, call)
403 key = ((3, 3, 3, 3), ('gggg2',))
404 call = lambda amp: \
405 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
406 (FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
407 FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
408 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
409 FortranHelasCallWriter.sorted_mothers(amp)[3].get('me_id'),
410 amp.get('coupling')[0],
411 amp.get('number'))
412 self.add_amplitude(key, call)
413 key = ((3, 3, 3, 3, 1), ('gggg1',))
414 call = lambda wf: \
415 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
416 (FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
417 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
418 FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
419 wf.get('coupling')[0],
420 wf.get('me_id'))
421 self.add_wavefunction(key, call)
422 key = ((3, 3, 3, 3), ('gggg3',))
423 call = lambda amp: \
424 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
425 (FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
426 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
427 FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
428 FortranHelasCallWriter.sorted_mothers(amp)[3].get('me_id'),
429 amp.get('coupling')[0],
430 amp.get('number'))
431 self.add_amplitude(key, call)
432
433
434
435 key = ((1, 3, 3, 3, 3), ('',))
436 call = lambda wf: \
437 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
438 (wf.get('mothers')[0].get('me_id'),
439 wf.get('mothers')[1].get('me_id'),
440 wf.get('mothers')[2].get('me_id'),
441 wf.get('coupling')[0],
442 wf.get('mass'),
443 wf.get('width'),
444 wf.get('me_id'))
445 self.add_wavefunction(key, call)
446
447 key = ((3, 3, 3, 1, 4), ('',))
448 call = lambda wf: \
449 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
450 (wf.get('mothers')[0].get('me_id'),
451 wf.get('mothers')[1].get('me_id'),
452 wf.get('mothers')[2].get('me_id'),
453 wf.get('coupling')[0],
454 wf.get('mass'),
455 wf.get('width'),
456 wf.get('me_id'))
457 self.add_wavefunction(key, call)
458
459 key = ((1, 3, 3, 3), ('',))
460 call = lambda amp: \
461 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \
462 (amp.get('mothers')[0].get('me_id'),
463 amp.get('mothers')[1].get('me_id'),
464 amp.get('mothers')[2].get('me_id'),
465 amp.get('mothers')[3].get('me_id'),
466 amp.get('coupling')[0],
467 amp.get('number'))
468 self.add_amplitude(key, call)
469
470
471
472 key = ((1, 3, 3, 3, 1), ('',))
473 call = lambda wf: \
474 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
475 (wf.get('mothers')[0].get('me_id'),
476 wf.get('mothers')[1].get('me_id'),
477 wf.get('mothers')[2].get('me_id'),
478 wf.get('coupling')[0],
479 wf.get('mass'),
480 wf.get('width'),
481 wf.get('me_id'))
482 self.add_wavefunction(key, call)
483
484 key = ((3, 3, 3, 1, 4), ('',))
485 call = lambda wf: \
486 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
487 (wf.get('mothers')[0].get('me_id'),
488 wf.get('mothers')[1].get('me_id'),
489 wf.get('mothers')[2].get('me_id'),
490 wf.get('coupling')[0],
491 wf.get('mass'),
492 wf.get('width'),
493 wf.get('me_id'))
494 self.add_wavefunction(key, call)
495
496 key = ((1, 3, 3, 3), ('',))
497 call = lambda amp: \
498 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \
499 (amp.get('mothers')[0].get('me_id'),
500 amp.get('mothers')[1].get('me_id'),
501 amp.get('mothers')[2].get('me_id'),
502 amp.get('mothers')[3].get('me_id'),
503 amp.get('coupling')[0],
504 amp.get('number'))
505 self.add_amplitude(key, call)
506
507
508 key = ((-2, 2, 5), ('',))
509 call = lambda amp: \
510 "CALL IOTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
511 (amp.get('mothers')[0].get('me_id'),
512 amp.get('mothers')[1].get('me_id'),
513 amp.get('mothers')[2].get('me_id'),
514 amp.get('coupling')[0],
515 amp.get('mothers')[0].get('mass'),
516 amp.get('number'))
517 self.add_amplitude(key, call)
518
519 key = ((-2, 2, 5, 3), ('',))
520 call = lambda wf: \
521 "CALL UIOXXX(W(1,%d),W(1,%d),%s,%s,%s,%s,W(1,%d))" % \
522 (wf.get('mothers')[0].get('me_id'),
523 wf.get('mothers')[1].get('me_id'),
524 wf.get('coupling')[0],
525 wf.get('mothers')[0].get('mass'),
526 wf.get('mass'),
527 wf.get('width'),
528 wf.get('me_id'))
529 self.add_wavefunction(key, call)
530
531 key = ((3,3,3,5),('',))
532 call = lambda amp: \
533 "CALL VVVTXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),1d0,%s,AMP(%d))" % \
534 (amp.get('mothers')[0].get('me_id'),
535 amp.get('mothers')[1].get('me_id'),
536 amp.get('mothers')[2].get('me_id'),
537 amp.get('mothers')[3].get('me_id'),
538 amp.get('coupling')[0],
539 amp.get('number'))
540 self.add_amplitude(key, call)
541
542 key = ((3,3,5),('',))
543 call = lambda amp: \
544 "CALL VVTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
545 (amp.get('mothers')[0].get('me_id'),
546 amp.get('mothers')[1].get('me_id'),
547 amp.get('mothers')[2].get('me_id'),
548 amp.get('coupling')[0],
549 amp.get('mothers')[0].get('mass'),
550 amp.get('number'))
551 self.add_amplitude(key, call)
552
553
555 """Return the function for writing the wavefunction
556 corresponding to the key. If the function doesn't exist,
557 generate_helas_call is called to automatically create the
558 function."""
559
560 if wavefunction.get('spin') == 1 and \
561 wavefunction.get('interaction_id') != 0:
562
563
564
565
566 wavefunction.set_scalar_coupling_sign(self['model'])
567
568 val = super(FortranHelasCallWriter, self).get_wavefunction_call(wavefunction)
569
570 if val:
571 return val
572
573
574
575 if len(wavefunction.get('mothers')) > 3:
576 raise self.PhysicsObjectError, \
577 """Automatic generation of Fortran wavefunctions not
578 implemented for > 3 mothers"""
579
580 self.generate_helas_call(wavefunction)
581 return super(FortranHelasCallWriter, self).get_wavefunction_call(\
582 wavefunction)
583
585 """Return the function for writing the amplitude corresponding
586 to the key. If the function doesn't exist, generate_helas_call
587 is called to automatically create the function."""
588
589 val = super(FortranHelasCallWriter, self).get_amplitude_call(amplitude)
590
591 if val:
592 return val
593
594
595
596 if len(amplitude.get('mothers')) > 4:
597 raise self.PhysicsObjectError, \
598 """Automatic generation of Fortran amplitudes not
599 implemented for > 4 mothers"""
600
601 self.generate_helas_call(amplitude)
602 return super(FortranHelasCallWriter, self).get_amplitude_call(amplitude)
603
605 """Routine for automatic generation of Fortran Helas calls
606 according to just the spin structure of the interaction.
607
608 First the call string is generated, using a dictionary to go
609 from the spin state of the calling wavefunction and its
610 mothers, or the mothers of the amplitude, to letters.
611
612 Then the call function is generated, as a lambda which fills
613 the call string with the information of the calling
614 wavefunction or amplitude. The call has different structure,
615 depending on the spin of the wavefunction and the number of
616 mothers (multiplicity of the vertex). The mother
617 wavefunctions, when entering the call, must be sorted in the
618 correct way - this is done by the sorted_mothers routine.
619
620 Finally the call function is stored in the relevant
621 dictionary, in order to be able to reuse the function the next
622 time a wavefunction with the same Lorentz structure is needed.
623 """
624
625 if not isinstance(argument, helas_objects.HelasWavefunction) and \
626 not isinstance(argument, helas_objects.HelasAmplitude):
627 raise self.PhysicsObjectError, \
628 "get_helas_call must be called with wavefunction or amplitude"
629
630 call = "CALL "
631
632 call_function = None
633
634 if isinstance(argument, helas_objects.HelasAmplitude) and \
635 argument.get('interaction_id') == 0:
636 call = "#"
637 call_function = lambda amp: call
638
639 self.add_amplitude(argument.get_call_key(), call_function)
640 return
641
642 if isinstance(argument, helas_objects.HelasWavefunction) and \
643 not argument.get('mothers'):
644
645 call = call + HelasCallWriter.mother_dict[\
646 argument.get_spin_state_number()]
647
648 call = call + 'X' * (11 - len(call))
649 call = call + "(P(0,%d),"
650 if argument.get('spin') != 1:
651
652 call = call + "%s,NHEL(%d),"
653 call = call + "%+d*IC(%d),W(1,%d))"
654 if argument.get('spin') == 1:
655 call_function = lambda wf: call % \
656 (wf.get('number_external'),
657
658 (-1) ** (wf.get('state') == 'initial'),
659 wf.get('number_external'),
660 wf.get('me_id'))
661 elif argument.is_boson():
662 call_function = lambda wf: call % \
663 (wf.get('number_external'),
664 wf.get('mass'),
665 wf.get('number_external'),
666
667 (-1) ** (wf.get('state') == 'initial'),
668 wf.get('number_external'),
669 wf.get('me_id'))
670 else:
671 call_function = lambda wf: call % \
672 (wf.get('number_external'),
673 wf.get('mass'),
674 wf.get('number_external'),
675
676 - (-1) ** wf.get_with_flow('is_part'),
677 wf.get('number_external'),
678 wf.get('me_id'))
679 else:
680
681 if isinstance(argument, helas_objects.HelasWavefunction):
682 call = call + \
683 FortranHelasCallWriter.self_dict[\
684 argument.get_spin_state_number()]
685
686 mother_letters = FortranHelasCallWriter.sorted_letters(argument)
687
688
689
690 lor_name = argument.get('lorentz')[0]
691
692
693 if len(lor_name) > 3 and lor_name[:2] == "WW":
694 if lor_name[:4] == "WWWW":
695 mother_letters = "WWWW"[:len(mother_letters)]
696 if lor_name[:4] == "WWVV":
697 mother_letters = "W3W3"[:len(mother_letters)]
698 lor_name = lor_name[4:]
699
700 call = call + mother_letters
701 call = call + lor_name
702
703
704 if argument.needs_hermitian_conjugate():
705 call = call + 'C'
706
707 assert len(call) < 12, "Call to Helas routine %s should be maximum 6 chars" \
708 % call[5:]
709
710
711 call = call + 'X' * (11 - len(call)) + '('
712
713 call = call + "W(1,%d)," * len(argument.get('mothers'))
714
715 call = call + "%s,"
716
717
718 if isinstance(argument, helas_objects.HelasWavefunction):
719
720 if argument.get('lorentz') == ['WWVV']:
721
722 call = call + "1D0,"
723 elif argument.get('lorentz') == ['WWWW']:
724
725 call = call + "0D0,"
726 elif argument.get('spin') == 3 and \
727 [wf.get('spin') for wf in argument.get('mothers')] == \
728 [3, 3, 3]:
729
730
731 call = call + "DUM0,"
732
733 call = call + "%s,%s,"
734
735 call = call + "W(1,%d))"
736 else:
737
738
739 if argument.get('lorentz') == ['WWVV']:
740
741 call = call + "1D0,"
742 elif argument.get('lorentz') == ['WWWW']:
743
744 call = call + "0D0,"
745 elif [wf.get('spin') for wf in argument.get('mothers')] == \
746 [3, 3, 3, 3]:
747
748
749 call = call + "DUM0,"
750
751 call = call + "AMP(%d))"
752
753 if isinstance(argument, helas_objects.HelasWavefunction):
754
755 if len(argument.get('mothers')) == 2:
756 call_function = lambda wf: call % \
757 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
758 get('me_id'),
759 FortranHelasCallWriter.sorted_mothers(wf)[1].\
760 get('me_id'),
761 ','.join(wf.get_with_flow('coupling')),
762 wf.get('mass'),
763 wf.get('width'),
764 wf.get('me_id'))
765 else:
766 call_function = lambda wf: call % \
767 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
768 get('me_id'),
769 FortranHelasCallWriter.sorted_mothers(wf)[1].\
770 get('me_id'),
771 FortranHelasCallWriter.sorted_mothers(wf)[2].\
772 get('me_id'),
773 ','.join(wf.get_with_flow('coupling')),
774 wf.get('mass'),
775 wf.get('width'),
776 wf.get('me_id'))
777 else:
778
779 if len(argument.get('mothers')) == 3:
780 call_function = lambda amp: call % \
781 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
782 get('me_id'),
783 FortranHelasCallWriter.sorted_mothers(amp)[1].\
784 get('me_id'),
785 FortranHelasCallWriter.sorted_mothers(amp)[2].\
786 get('me_id'),
787
788 ','.join(amp.get('coupling')),
789 amp.get('number'))
790 else:
791 call_function = lambda amp: call % \
792 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
793 get('me_id'),
794 FortranHelasCallWriter.sorted_mothers(amp)[1].\
795 get('me_id'),
796 FortranHelasCallWriter.sorted_mothers(amp)[2].\
797 get('me_id'),
798 FortranHelasCallWriter.sorted_mothers(amp)[3].\
799 get('me_id'),
800 ','.join(amp.get('coupling')),
801 amp.get('number'))
802
803
804 if isinstance(argument, helas_objects.HelasWavefunction):
805 self.add_wavefunction(argument.get_call_key(), call_function)
806 else:
807 self.add_amplitude(argument.get_call_key(), call_function)
808
809
810
811 @staticmethod
829
830 @staticmethod
832 """Gives a list of mother wavefunctions sorted according to
833 1. The order of the particles in the interaction
834 2. Cyclic reordering of particles in same spin group
835 3. Fermions ordered IOIOIO... according to the pairs in
836 the interaction."""
837
838 assert isinstance(arg, (helas_objects.HelasWavefunction, helas_objects.HelasAmplitude)), \
839 "%s is not a valid HelasWavefunction or HelasAmplitude" % repr(arg)
840
841 if not arg.get('interaction_id'):
842 return arg.get('mothers')
843 my_pdg_code = 0
844 my_spin = 0
845 if isinstance(arg, helas_objects.HelasWavefunction):
846 my_pdg_code = arg.get_anti_pdg_code()
847 my_spin = arg.get_spin_state_number()
848
849 sorted_mothers, my_index = arg.get('mothers').sort_by_pdg_codes(\
850 arg.get('pdg_codes'), my_pdg_code)
851
852
853 partner = None
854 if isinstance(arg, helas_objects.HelasWavefunction) and arg.is_fermion():
855
856 if my_index % 2 == 0:
857
858 partner_index = my_index
859 else:
860
861 partner_index = my_index - 1
862 partner = sorted_mothers.pop(partner_index)
863
864 if partner.get_spin_state_number() > 0:
865 my_index = partner_index
866 else:
867 my_index = partner_index + 1
868
869
870 for i in range(0, len(sorted_mothers), 2):
871 if sorted_mothers[i].is_fermion():
872
873 if sorted_mothers[i].get_spin_state_number() > 0 and \
874 sorted_mothers[i + 1].get_spin_state_number() < 0:
875
876 sorted_mothers = sorted_mothers[:i] + \
877 [sorted_mothers[i+1], sorted_mothers[i]] + \
878 sorted_mothers[i+2:]
879 elif sorted_mothers[i].get_spin_state_number() < 0 and \
880 sorted_mothers[i + 1].get_spin_state_number() > 0:
881
882 pass
883 else:
884
885 break
886
887
888 if partner:
889 sorted_mothers.insert(partner_index, partner)
890
891 same_spin_mothers = []
892 if isinstance(arg, helas_objects.HelasWavefunction):
893
894 same_spin_index = -1
895 i=0
896 while i < len(sorted_mothers):
897 if abs(sorted_mothers[i].get_spin_state_number()) == \
898 abs(my_spin):
899 if same_spin_index < 0:
900
901 same_spin_index = i
902 same_spin_mothers.append(sorted_mothers.pop(i))
903 else:
904 i += 1
905
906
907 if same_spin_mothers:
908 same_spin_mothers = same_spin_mothers[my_index - same_spin_index:] \
909 + same_spin_mothers[:my_index - same_spin_index]
910
911
912 sorted_mothers = sorted_mothers[:same_spin_index] + \
913 same_spin_mothers + sorted_mothers[same_spin_index:]
914
915
916 return helas_objects.HelasWavefunctionList(sorted_mothers)
917
923 """The class for writing Helas calls in Fortran, starting from
924 HelasWavefunctions and HelasAmplitudes.
925
926 Includes the function generate_helas_call, which automatically
927 generates the Fortran Helas call based on the Lorentz structure of
928 the interaction."""
929
930
951
964
965
967 """Create a suitable string for the factor of the form
968 (fraction, is_imaginary?)."""
969 imag_dict = {True: "IMAG1", False: "ONE"}
970 return str(factor[0]*factor[1]) + "*" + imag_dict[factor[2]]
971
976 """The class for writing Helas calls in Fortran, starting from
977 HelasWavefunctions and HelasAmplitudes.
978
979 Includes the function generate_helas_call, which automatically
980 generates the Fortran Helas call based on the Lorentz structure of
981 the interaction."""
982
983 mp_prefix = check_param_card.ParamCard.mp_prefix
984
985 - def __init__(self, argument={}, hel_sum = False):
986 """Allow generating a HelasCallWriter from a Model.The hel_sum argument
987 specifies if amplitude and wavefunctions must be stored specifying the
988 helicity, i.e. W(1,i) vs W(1,i,H).
989 """
990 self.hel_sum = hel_sum
991 super(FortranUFOHelasCallWriter, self).__init__(argument)
992
1001
1017
1018
1019
1021 """ Routine for automatic generation of a call to CutTools for loop
1022 amplitudes."""
1023
1024 call = "LOOP%(numLoopLines)s"
1025 if (len(loopamp.get('pairing')) != len(loopamp.get('mothers'))):
1026 call += "%(numMotherWfs)s%(numCouplings)s(%(numeratorNumber)d,"
1027 for i in range(len(loopamp.get('pairing'))):
1028 call = call + "%(Pairing{0})d,".format(i)
1029 else:
1030 call += "%(numCouplings)s(%(numeratorNumber)d,"
1031 for i in range(len(loopamp.get('mothers'))):
1032 call = call + "%(MotherID{0})d,".format(i+1)
1033 for i in range(len(loopamp.get('wavefunctions'))-2):
1034 call = call + \
1035 "DCMPLX(%(LoopMass{0})s),CMPLX({1}%(LoopMass{0})s,KIND=16),"\
1036 .format(i+1,self.mp_prefix)
1037 for i in range(len(loopamp.get('coupling'))):
1038 call = call + \
1039 "%(LoopCoupling{0})s,%(MPLoopCoupling{0})s,".format(i+1)
1040 call = call + "%(LoopRank)d,"
1041 call = call + "%(LoopSymmetryFactor)d,"
1042 call = call + "%(ampNumber)d,AMPL(1,%(ampNumber)d),S(%(ampNumber)d))"
1043
1044 def create_loop_amp(amplitude):
1045 helas_dict = amplitude.get_helas_call_dict()
1046
1047
1048
1049 for i in range(len(loopamp.get('coupling'))):
1050 coupl = helas_dict['LoopCoupling%i'%(i+1)]
1051 helas_dict['MPLoopCoupling%i'%(i+1)]= \
1052 '-%s%s'%(self.mp_prefix,coupl[1:]) if coupl.startswith('-') \
1053 else '%s%s'%(self.mp_prefix,coupl)
1054
1055 return 'CALL %(proc_prefix)s'+call%helas_dict
1056
1057 self.add_amplitude(loopamp.get_call_key(), create_loop_amp)
1058 return
1059
1092
1094 """ Generate an external wavefunction """
1095
1096 call="CALL "
1097 call_function = None
1098 if argument.get('is_loop'):
1099 call=call+"LCUT_%(conjugate)s%(lcutspinletter)s(Q(0),I,WL(1,%(number)d))"
1100 else:
1101
1102 call = call + HelasCallWriter.mother_dict[\
1103 argument.get_spin_state_number()]
1104
1105 call = call + 'X' * (11 - len(call))
1106 call = call + "(P(0,%(number_external)d),"
1107 if argument.get('spin') != 1:
1108
1109 call = call + "%(mass)s,NHEL(%(number_external)d),"
1110 call = call + "%(state_id)+d*IC(%(number_external)d),{0})".format(\
1111 self.format_helas_object('W(1,','%(me_id)d'))
1112
1113 call_function = lambda wf: call % wf.get_external_helas_call_dict()
1114 self.add_wavefunction(argument.get_call_key(), call_function)
1115
1117 """ Generate all the helas objects for which no special handlers was
1118 placed in generate_helas_call """
1119
1120
1121 if isinstance(argument, helas_objects.HelasWavefunction):
1122 outgoing = argument.find_outgoing_number()
1123 else:
1124 outgoing = 0
1125
1126
1127
1128 l = [str(l) for l in argument.get('lorentz')]
1129 flag = []
1130 if argument.needs_hermitian_conjugate():
1131 flag = ['C%d' % i for i in \
1132 argument.get_conjugate_index()]
1133 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1134 argument.get('is_loop') or \
1135 (isinstance(argument, helas_objects.HelasAmplitude) and \
1136 argument.get('type')=='loop')):
1137 flag.insert(0,"L")
1138
1139
1140 call = 'CALL %(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s)'
1141
1142 arg = {'routine_name': aloha_writers.combine_name(\
1143 '%s' % l[0], l[1:], outgoing, flag, True),
1144 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1145 tuple(range(len(argument.get('coupling'))))
1146 }
1147
1148
1149 if (isinstance(argument,helas_objects.HelasWavefunction) \
1150 and argument.get('is_loop')) or \
1151 ((isinstance(argument,helas_objects.HelasAmplitude) \
1152 and argument['type']=='loop')):
1153 base_wf = "W%(WF{0})s,"
1154 else:
1155 base_wf = self.format_helas_object('W(1,','%({0})d')+','
1156
1157
1158 wf = ''
1159 for i in range(len(argument.get('mothers'))):
1160 wf += base_wf.format(i)
1161 arg['wf'] = wf
1162
1163
1164
1165
1166 if isinstance(argument, helas_objects.HelasWavefunction):
1167 if argument['is_loop']:
1168 arg['out'] = 'WL(1,%(out)d)'
1169 if aloha.complex_mass:
1170 arg['mass'] = "ML(%(out)d),"
1171 else:
1172 arg['mass'] = "ML(%(out)d),ZERO,"
1173 else:
1174 arg['out']=self.format_helas_object('W(1,','%(out)d')
1175 if aloha.complex_mass:
1176 arg['mass'] = "DCMPLX(%(CM)s),"
1177 else:
1178 arg['mass'] = "%(M)s,%(W)s,"
1179
1180 elif argument['type'] == 'base':
1181 arg['mass'] = ''
1182 arg['out'] = self.format_helas_object('AMP(','%(out)d')
1183
1184 elif argument['type'] == 'loop':
1185 arg['mass'] = ''
1186 arg['out'] = 'BUFF(I)'
1187
1188 else:
1189 arg['mass'] = ''
1190 ampl = "AMPL({0},%(out)d)".format(argument.get_epsilon_order()+1)
1191 arg['out'] = '%s' % ampl
1192 if isinstance(argument,loop_helas_objects.LoopHelasUVCTAmplitude)\
1193 and argument.get_UVCT_couplings()!='1.0d0':
1194
1195 call += "\n %(second_line)s "
1196 arg['second_line'] = ampl+"="+ampl+"*(%(uvct)s)"
1197
1198
1199
1200 call = call % arg
1201
1202 call_function = lambda wf: call % wf.get_helas_call_dict(\
1203 OptimizedOutput=False, specifyHel=self.hel_sum)
1204
1205
1206 if isinstance(argument, helas_objects.HelasWavefunction):
1207 self.add_wavefunction(argument.get_call_key(), call_function)
1208 else:
1209 self.add_amplitude(argument.get_call_key(), call_function)
1210
1212 """ Returns a list of strings corresponding to the Helas calls for each
1213 loop amplitude of this loop matrix element. This function is placed in
1214 this class and not in HelasWriter, because it contains fortran-specific
1215 code."""
1216
1217 res = []
1218 loopHelasAmpNumberTreated=[]
1219 for ldiag in loop_matrix_element.get_loop_diagrams():
1220 for lamp in ldiag.get_loop_amplitudes():
1221 if lamp.get('number') in loopHelasAmpNumberTreated:
1222 continue
1223 else:
1224 loopHelasAmpNumberTreated.append(lamp.get('number'))
1225 lcutpart=self['model'].get_particle(lamp['type'])
1226 res.append("ELSEIF (ID.EQ.%d) THEN"%lamp.get('number'))
1227 res.append("#Loop diagram number %d (might be others, just an example)"\
1228 %ldiag.get('number'))
1229 if lcutpart.get('spin')==1:
1230 res.append("DO I=1,1")
1231 elif lcutpart.get('spin')==2 or lcutpart.get('spin')==3:
1232 res.append("DO I=1,4")
1233 else:
1234 raise self.PhysicsObjectError, \
1235 "The L-cut particle type is not supported"
1236
1237
1238
1239
1240
1241 externalWfNumber=1
1242 originalNumbers=[]
1243 couplingNumber=1
1244 originalCouplings=[]
1245 for lwf in lamp.get('wavefunctions'):
1246 if lwf.get('coupling')!=['none']:
1247 originalCouplings.append(lwf.get('coupling'))
1248 couplings=[]
1249 for coup in lwf.get('coupling'):
1250 couplings.append("LC(%d)"%couplingNumber)
1251 couplingNumber=couplingNumber+1
1252 lwf.set('coupling',couplings)
1253 for mother in lwf.get('mothers'):
1254 if not mother.get('is_loop'):
1255 originalNumbers.append(mother.get('number'))
1256 mother.set('me_id',externalWfNumber)
1257 externalWfNumber=externalWfNumber+1
1258
1259 res.append(self.get_wavefunction_call(\
1260 lamp.get_starting_loop_wavefunction()))
1261
1262 res.extend([ self.get_wavefunction_call(wf) for \
1263 wf in lamp.get('wavefunctions') if wf.get('mothers')])
1264
1265
1266
1267 for lwf in lamp.get('amplitudes')[0].get('mothers'):
1268 if lwf.get('mothers'):
1269 last_lwf_number=lwf.get('number')
1270 break
1271 res.append('BUFF(I)=WL(I+4,%d)'%last_lwf_number)
1272
1273 indexMothers=0
1274 indexWfs=0
1275 for lwf in lamp.get('wavefunctions'):
1276 if lwf.get('coupling')!=['none']:
1277 lwf.set('coupling',originalCouplings[indexWfs])
1278 indexWfs=indexWfs+1
1279 for mother in lwf.get('mothers'):
1280 if not mother.get('is_loop'):
1281 mother.set('me_id',originalNumbers[indexMothers])
1282 indexMothers=indexMothers+1
1283 res.append('ENDDO')
1284 if lcutpart.get('spin')==1:
1285 res.append("CALL CLOSE_1(BUFF(1),RES)")
1286 elif lcutpart.get('spin')==2 or lcutpart.get('spin')==3:
1287 res.append("CALL CLOSE_4(BUFF(1),RES)")
1288
1289 res[0]=res[0][4:]
1290
1291 res.append('ENDIF')
1292
1293 return res
1294
1299 """ Version of FortranUFOHelasCallWriter meeting the needs of the optimized
1300 output for loop processes """
1301
1303 """ We overwrite this function here because in the optimized mode one
1304 does not need to call the function set_octet_majorana_coupling_sign
1305 for the wavefunctions of the loop amplitudes. So we directly call
1306 the mother of the mother, namely UFOHelasCallWriter. """
1307
1308 return super(FortranUFOHelasCallWriter, self).get_amplitude_call(
1309 *args,**opts)
1310
1319
1322 """ Return the calls to the helas routines to construct the coefficients
1323 of the polynomial representation of the loop numerator (i.e. Pozzorini
1324 method). Group the coefficients of the loop with same denominator
1325 together if group_loops is set True. The squared_orders can provide the
1326 information of what is the maximum contributing loop amp number."""
1327
1328 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
1329 "%s not valid argument for get_coef_construction_calls" % \
1330 repr(matrix_element)
1331
1332 res = []
1333 sqso_max_lamp = [sqso[1][2] for sqso in squared_orders]
1334
1335 i=0
1336 for ldiag in matrix_element.get_loop_diagrams():
1337 res.append("# Coefficient construction for loop diagram with ID %d"\
1338 %ldiag.get('number'))
1339 for lwf in ldiag.get('loop_wavefunctions'):
1340 res.append(self.get_wavefunction_call(lwf))
1341 for lamp in ldiag.get_loop_amplitudes():
1342
1343
1344 if not group_loops:
1345 lamp.set('loop_group_id',i)
1346 i=i+1
1347 create_coef=[
1348 'CREATE_LOOP_COEFS(WL(1,0,1,%(number)d)',
1349 '%(loop_rank)d','%(lcut_size)d',
1350 '%(loop_number)d','%(LoopSymmetryFactor)d',
1351 '%(amp_number)d,H)']
1352 res.append('CALL %(proc_prefix)s'+','.join(create_coef)%{\
1353 'number':lamp.get_final_loop_wavefunction().get('number'),
1354 'loop_rank':lamp.get_analytic_info('wavefunction_rank'),
1355 'lcut_size':lamp.get_lcut_size(),
1356
1357
1358
1359 'loop_number':(lamp.get('loop_group_id')+1),
1360 'amp_number':lamp.get('amplitudes')[0].get('number'),
1361 'LoopSymmetryFactor':lamp.get('loopsymmetryfactor')})
1362 res.extend(self.get_sqso_target_skip_code(
1363 lamp.get('amplitudes')[0].get('number'),
1364 sqso_max_lamp, 4000, split_orders, squared_orders,
1365 "# At this point, all loop coefficients needed"+
1366 " for %s are computed."))
1367
1368 coef_merge=['C Grouping of loop diagrams now done directly when '+\
1369 'creating the LOOPCOEFS.']
1370
1371 return res, coef_merge
1372
1373 - def get_loop_CT_calls(self, matrix_element, group_loops=True,
1374 squared_orders=[], split_orders=[]):
1375 """ Return the calls to CutTools interface routines to launch the
1376 computation of the contribution of one loop group. The squared_orders
1377 can provide the information of the maximum reference loop group ID for
1378 each contributing squared loop orders."""
1379
1380 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
1381 "%s not valid argument for get_loop_CT_calls" % \
1382 repr(matrix_element)
1383
1384 res = []
1385
1386 sqso_max_lgroup_refs = [sqso[1][3] for sqso in squared_orders]
1387
1388
1389
1390
1391 if group_loops and matrix_element.get('processes')[0].get('has_born'):
1392
1393 loop_group_refs=[(lamps[1][0],lamps[1][1:]) for lamps in \
1394 matrix_element.get('loop_groups')]
1395 max_loop_group_ref = max([lg[0].get('loop_group_id') for lg in \
1396 loop_group_refs])
1397 for (lamp_ref, lamps) in loop_group_refs:
1398 res.append("# CutTools call for loop numbers %s"%\
1399 ','.join(['%d'%lamp_ref.get('number'),]+\
1400 ['%d'%lamp.get('number') for lamp in lamps]))
1401 res.append(self.get_amplitude_call(lamp_ref))
1402 res.extend(self.get_sqso_target_skip_code(
1403 lamp_ref.get('loop_group_id'), sqso_max_lgroup_refs, 5000,
1404 split_orders, squared_orders,
1405 "# At this point, all reductions needed for %s are computed."))
1406 else:
1407 for ldiag in matrix_element.get_loop_diagrams():
1408 res.append("# CutTools call for loop # %d"%ldiag.get('number'))
1409 for lamp in ldiag.get_loop_amplitudes():
1410 res.append(self.get_amplitude_call(lamp))
1411
1412 return res
1413
1427
1429 """ Routine for automatic generation of a call to CutTools for loop
1430 amplitudes for the optimized output."""
1431
1432 call = "LOOP%(numLoopLines)s"
1433 if (len(loopamp.get('pairing')) != len(loopamp.get('mothers'))):
1434 call += "%(numMotherWfs)s("
1435 for i in range(len(loopamp.get('pairing'))):
1436 call = call + "%(Pairing{0})d,".format(i)
1437 else:
1438 call += "("
1439 for i in range(len(loopamp.get('mothers'))):
1440 call = call + "%(MotherID{0})d,".format(i+1)
1441 for i in range(len(loopamp.get('wavefunctions'))-2):
1442 call = call + \
1443 "DCMPLX(%(LoopMass{0})s),".format(i+1)
1444 call = call + "%(LoopRank)d,"
1445 call = call + "I_SO,%(loop_group_id)d)"
1446
1447
1448 call_function = lambda amp: 'CALL %(proc_prefix)s'+\
1449 call % amp.get_helas_call_dict(OptimizedOutput=True)
1450 self.add_amplitude(loopamp.get_call_key(), call_function)
1451 return
1452
1454 """ Generate all the helas objects for which no special handlers was
1455 placed in generate_helas_call """
1456
1457 if isinstance(argument, helas_objects.HelasWavefunction):
1458 outgoing = argument.find_outgoing_number()
1459 else:
1460 outgoing = 0
1461
1462 if isinstance(argument, helas_objects.HelasAmplitude) and \
1463 argument.get('type')=='loop':
1464 raise MadGraph5Error, 'There should not be any helas call '+\
1465 'associated with helas amplitudes of type loop.'
1466
1467
1468 l = [str(l) for l in argument.get('lorentz')]
1469 flag = []
1470 if argument.needs_hermitian_conjugate():
1471 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1472
1473 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1474 argument.get('is_loop')):
1475 flag.insert(0,"L%d"%argument.get_loop_index())
1476
1477
1478 call = 'CALL %(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s)'
1479
1480 arg = {'routine_name': aloha_writers.combine_name(\
1481 '%s' % l[0], l[1:], outgoing, flag, True),
1482 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1483 tuple(range(len(argument.get('coupling'))))
1484 }
1485
1486
1487 if (isinstance(argument,helas_objects.HelasWavefunction) \
1488 and argument.get('is_loop')):
1489 base_wf = "%(WF{0})s,"
1490 else:
1491 base_wf = self.format_helas_object('W(1,','%({0})d')+','
1492
1493
1494 wf = ''
1495 for i in range(len(argument.get('mothers'))):
1496 wf += base_wf.format(i)
1497 arg['wf'] = wf
1498
1499
1500
1501
1502 if isinstance(argument, helas_objects.HelasWavefunction):
1503 if argument['is_loop']:
1504 arg['out'] = 'PL(0,%(out)d),COEFS'
1505 else:
1506 arg['out']=self.format_helas_object('W(1,','%(out)d')
1507 if aloha.complex_mass:
1508 arg['mass'] = "DCMPLX(%(CM)s),"
1509 else:
1510 arg['mass'] = "%(M)s,%(W)s,"
1511
1512 elif argument['type'] == 'base':
1513 arg['mass'] = ''
1514 arg['out'] = self.format_helas_object('AMP(','%(out)d')
1515
1516 else:
1517 arg['mass'] = ''
1518 ampl = "AMPL({0},%(out)d)".format(argument.get_epsilon_order()+1)
1519 arg['out'] = '%s' % ampl
1520 if isinstance(argument,loop_helas_objects.LoopHelasUVCTAmplitude)\
1521 and argument.get_UVCT_couplings()!='1.0d0':
1522
1523 call += "\n %(second_line)s "
1524 arg['second_line'] = ampl+"="+ampl+"*(%(uvct)s)"
1525
1526
1527
1528 call = call % arg
1529 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1530 argument.get('is_loop')):
1531
1532 call += "\nCALL {0}UPDATE_WL_%(loop_mother_rank)d_%(vertex_rank)d("
1533 call += "WL(1,0,1,%(loop_mother_number)d),%(lcut_size)d,COEFS,"
1534 call += "%(in_size)d,%(out_size)d,WL(1,0,1,%(out)d))"
1535
1536 call_function = lambda wf:\
1537 (call%wf.get_helas_call_dict(OptimizedOutput=True,
1538 specifyHel=self.hel_sum)).format('%(proc_prefix)s')
1539
1540
1541 if isinstance(argument, helas_objects.HelasWavefunction):
1542 self.add_wavefunction(argument.get_call_key(), call_function)
1543 else:
1544 self.add_amplitude(argument.get_call_key(), call_function)
1545
1550 """The class for writing Helas calls in C++, starting from
1551 HelasWavefunctions and HelasAmplitudes.
1552
1553 Includes the function generate_helas_call, which automatically
1554 generates the C++ Helas call based on the Lorentz structure of
1555 the interaction."""
1556
1558 """Routine for automatic generation of C++ Helas calls
1559 according to just the spin structure of the interaction.
1560
1561 First the call string is generated, using a dictionary to go
1562 from the spin state of the calling wavefunction and its
1563 mothers, or the mothers of the amplitude, to difenrentiate wich call is
1564 done.
1565
1566 Then the call function is generated, as a lambda which fills
1567 the call string with the information of the calling
1568 wavefunction or amplitude. The call has different structure,
1569 depending on the spin of the wavefunction and the number of
1570 mothers (multiplicity of the vertex). The mother
1571 wavefunctions, when entering the call, must be sorted in the
1572 correct way - this is done by the sorted_mothers routine.
1573
1574 Finally the call function is stored in the relevant
1575 dictionary, in order to be able to reuse the function the next
1576 time a wavefunction with the same Lorentz structure is needed.
1577 """
1578
1579 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1580 not isinstance(argument, helas_objects.HelasAmplitude):
1581 raise self.PhysicsObjectError, \
1582 "get_helas_call must be called with wavefunction or amplitude"
1583
1584 call = ""
1585
1586 call_function = None
1587
1588 if isinstance(argument, helas_objects.HelasAmplitude) and \
1589 argument.get('interaction_id') == 0:
1590 call = "#"
1591 call_function = lambda amp: call
1592 self.add_amplitude(argument.get_call_key(), call_function)
1593 return
1594
1595 if isinstance(argument, helas_objects.HelasWavefunction) and \
1596 not argument.get('mothers'):
1597
1598 call = call + HelasCallWriter.mother_dict[\
1599 argument.get_spin_state_number()].lower()
1600
1601 call = call + 'x' * (6 - len(call))
1602
1603 call = call + "(p[perm[%d]],"
1604 if argument.get('spin') != 1:
1605
1606 call = call + "mME[%d],hel[%d],"
1607 call = call + "%+d,w[%d]);"
1608 if argument.get('spin') == 1:
1609 call_function = lambda wf: call % \
1610 (wf.get('number_external')-1,
1611
1612 (-1) ** (wf.get('state') == 'initial'),
1613 wf.get('me_id')-1)
1614 elif argument.is_boson():
1615 call_function = lambda wf: call % \
1616 (wf.get('number_external')-1,
1617 wf.get('number_external')-1,
1618 wf.get('number_external')-1,
1619
1620 (-1) ** (wf.get('state') == 'initial'),
1621 wf.get('me_id')-1)
1622 else:
1623 call_function = lambda wf: call % \
1624 (wf.get('number_external')-1,
1625 wf.get('number_external')-1,
1626 wf.get('number_external')-1,
1627
1628 - (-1) ** wf.get_with_flow('is_part'),
1629 wf.get('me_id')-1)
1630 else:
1631 if isinstance(argument, helas_objects.HelasWavefunction):
1632 outgoing = argument.find_outgoing_number()
1633 else:
1634 outgoing = 0
1635
1636
1637 l = [str(l) for l in argument.get('lorentz')]
1638 flag = []
1639 if argument.needs_hermitian_conjugate():
1640 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1641
1642
1643
1644 call = '%(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s);'
1645
1646 arg = {'routine_name': aloha_writers.combine_name(\
1647 '%s' % l[0], l[1:], outgoing, flag,True),
1648 'wf': ("w[%%(%d)d]," * len(argument.get('mothers'))) % \
1649 tuple(range(len(argument.get('mothers')))),
1650 'coup': ("pars->%%(coup%d)s," * len(argument.get('coupling'))) % \
1651 tuple(range(len(argument.get('coupling'))))
1652 }
1653 if isinstance(argument, helas_objects.HelasWavefunction):
1654 arg['out'] = 'w[%(out)d]'
1655 if aloha.complex_mass:
1656 arg['mass'] = "pars->%(CM)s,"
1657 else:
1658 arg['mass'] = "pars->%(M)s,pars->%(W)s,"
1659 else:
1660 arg['out'] = 'amp[%(out)d]'
1661 arg['mass'] = ''
1662
1663 call = call % arg
1664
1665 call_function = lambda wf: self.format_coupling(
1666 call % wf.get_helas_call_dict(index=0))
1667
1668
1669 if isinstance(argument, helas_objects.HelasWavefunction):
1670 self.add_wavefunction(argument.get_call_key(), call_function)
1671 else:
1672 self.add_amplitude(argument.get_call_key(), call_function)
1673
1674 @staticmethod
1679
1685 """The class for writing Helas calls in Python, starting from
1686 HelasWavefunctions and HelasAmplitudes.
1687
1688 Includes the function generate_helas_call, which automatically
1689 generates the Python Helas call based on the Lorentz structure of
1690 the interaction."""
1691
1693 """Return a list of strings, corresponding to the Helas calls
1694 for the matrix element"""
1695
1696 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
1697 "%s not valid argument for get_matrix_element_calls" % \
1698 repr(matrix_element)
1699
1700 me = matrix_element.get('diagrams')
1701 matrix_element.reuse_outdated_wavefunctions(me)
1702
1703 res = []
1704 for diagram in matrix_element.get('diagrams'):
1705 wfs = diagram.get('wavefunctions')
1706 if gauge_check and diagram.get('number') == 1:
1707 gauge_check_wfs = [wf for wf in wfs if not wf.get('mothers') \
1708 and wf.get('spin') == 3 \
1709 and wf.get('mass').lower() == 'zero']
1710 if not gauge_check_wfs:
1711 raise HelasWriterError, \
1712 'no massless spin one particle for gauge check'
1713 gauge_check_wf = wfs.pop(wfs.index(gauge_check_wfs[0]))
1714 res.append(self.generate_helas_call(gauge_check_wf, True)(\
1715 gauge_check_wf))
1716 res.extend([ self.get_wavefunction_call(wf) for wf in wfs ])
1717 res.append("# Amplitude(s) for diagram number %d" % \
1718 diagram.get('number'))
1719 for amplitude in diagram.get('amplitudes'):
1720 res.append(self.get_amplitude_call(amplitude))
1721
1722 return res
1723
1724
1725
1727 """Routine for automatic generation of Python Helas calls
1728 according to just the spin structure of the interaction.
1729 """
1730
1731 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1732 not isinstance(argument, helas_objects.HelasAmplitude):
1733 raise self.PhysicsObjectError, \
1734 "get_helas_call must be called with wavefunction or amplitude"
1735
1736 call_function = None
1737
1738 if isinstance(argument, helas_objects.HelasAmplitude) and \
1739 argument.get('interaction_id') == 0:
1740 call = "#"
1741 call_function = lambda amp: call
1742 self.add_amplitude(argument.get_call_key(), call_function)
1743 return
1744
1745 if isinstance(argument, helas_objects.HelasWavefunction) and \
1746 not argument.get('mothers'):
1747
1748 call = "w[%d] = "
1749
1750 call = call + HelasCallWriter.mother_dict[\
1751 argument.get_spin_state_number()].lower()
1752
1753 call = call + 'x' * (14 - len(call))
1754 call = call + "(p[%d],"
1755 if argument.get('spin') != 1:
1756
1757 if gauge_check and argument.get('spin') == 3 and \
1758 argument.get('mass') == 'ZERO':
1759 call = call + "%s, 4,"
1760 else:
1761 call = call + "%s,hel[%d],"
1762 call = call + "%+d)"
1763 if argument.get('spin') == 1:
1764 call_function = lambda wf: call % \
1765 (wf.get('me_id')-1,
1766 wf.get('number_external')-1,
1767
1768 (-1)**(wf.get('state') == 'initial'))
1769 elif argument.is_boson():
1770 if not gauge_check or argument.get('mass') != 'ZERO':
1771 call_function = lambda wf: call % \
1772 (wf.get('me_id')-1,
1773 wf.get('number_external')-1,
1774 wf.get('mass'),
1775 wf.get('number_external')-1,
1776
1777 (-1)**(wf.get('state') == 'initial'))
1778 else:
1779 call_function = lambda wf: call % \
1780 (wf.get('me_id')-1,
1781 wf.get('number_external')-1,
1782 'ZERO',
1783
1784 (-1)**(wf.get('state') == 'initial'))
1785 else:
1786 call_function = lambda wf: call % \
1787 (wf.get('me_id')-1,
1788 wf.get('number_external')-1,
1789 wf.get('mass'),
1790 wf.get('number_external')-1,
1791
1792 -(-1)**wf.get_with_flow('is_part'))
1793 else:
1794
1795
1796 if isinstance(argument, helas_objects.HelasWavefunction):
1797 outgoing = argument.find_outgoing_number()
1798 else:
1799 outgoing = 0
1800
1801
1802 l = [str(l) for l in argument.get('lorentz')]
1803 flag = []
1804 if argument.needs_hermitian_conjugate():
1805 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1806
1807
1808
1809 call = '%(out)s= %(routine_name)s(%(wf)s%(coup)s%(mass)s)'
1810
1811 arg = {'routine_name': aloha_writers.combine_name(\
1812 '%s' % l[0], l[1:], outgoing, flag, True),
1813 'wf': ("w[%%(%d)d]," * len(argument.get('mothers'))) % \
1814 tuple(range(len(argument.get('mothers')))),
1815 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1816 tuple(range(len(argument.get('coupling'))))
1817 }
1818
1819 if isinstance(argument, helas_objects.HelasWavefunction):
1820 arg['out'] = 'w[%(out)d]'
1821 if aloha.complex_mass:
1822 arg['mass'] = "%(CM)s"
1823 else:
1824 arg['mass'] = "%(M)s,%(W)s"
1825 else:
1826 arg['coup'] = arg['coup'][:-1]
1827 arg['out'] = 'amp[%(out)d]'
1828 arg['mass'] = ''
1829
1830 call = call % arg
1831
1832 call_function = lambda wf: call % wf.get_helas_call_dict(index=0)
1833
1834 routine_name = aloha_writers.combine_name(
1835 '%s' % l[0], l[1:], outgoing, flag)
1836
1837
1838 if isinstance(argument, helas_objects.HelasWavefunction):
1839 if not gauge_check:
1840 self.add_wavefunction(argument.get_call_key(), call_function)
1841 else:
1842 self.add_amplitude(argument.get_call_key(), call_function)
1843
1844 return call_function
1845