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