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 from __future__ import absolute_import
17
18
19 import re
20 import madgraph.core.base_objects as base_objects
21 import madgraph.core.helas_objects as helas_objects
22 import madgraph.loop.loop_helas_objects as loop_helas_objects
23 import models.check_param_card as check_param_card
24 import aloha.aloha_writers as aloha_writers
25 import aloha
26 from madgraph import MadGraph5Error
27 import madgraph.various.misc as misc
28 from six.moves import range
31 """Class for the error of this module """
32 pass
33
39 """Language independent base class for writing Helas calls. The
40 calls are stored in two dictionaries, wavefunctions and
41 amplitudes, with entries being a mapping from a set of spin,
42 incoming/outgoing states and Lorentz structure to a function which
43 writes the corresponding wavefunction/amplitude call (taking a
44 HelasWavefunction/HelasAmplitude as argument)."""
45
46
47
48 mother_dict = {1: 'S', 2: 'O', -2: 'I', 3: 'V', 5: 'T', 4:'OR', -4:'IR',
49 99:'P'}
50
51 @staticmethod
53 """ Place holder for PLUGIN/...
54 (used by madevent output for small width handling)
55 """
56 return call, arg
57
58 @staticmethod
61
62
63
65
66 self['model'] = base_objects.Model()
67 self['wavefunctions'] = {}
68 self['amplitudes'] = {}
69 self.width_tchannel_set_tozero = False
70
71 - def filter(self, name, value):
99
101 """Return process property names as a nicely sorted list."""
102
103 return ['model', 'wavefunctions', 'amplitudes']
104
105
106
107
108
109
128
129 - def get_sqso_target_skip_code(self, number_checked, sqso_target_numbers,
130 continue_label, split_orders, squared_orders, comment):
131 """Treat the optimization for the squared order target so that
132 unnecessary computations can be skipped. This function returns the lines
133 of codes for doing so, based on the number_checked (typically amplitude number)
134 to be checked and the list of squared order contributions
135 sqso_target_numbers specifying for each of them the maximum contributing
136 number. The continue_label informs where the code must 'goto' if indeed
137 the rest of this part of the computation must be skipped.
138 The split_orders and squared_orders values lists, as well as the string
139 comment template is just for printing out a nice comment in the fortran
140 code explaining what is going on."""
141
142 res = []
143 for sqso_index, target in enumerate(sqso_target_numbers):
144 if target!=number_checked:
145 continue
146 sqso_name = ' '.join(['%s=%d'%(split_orders[i],val) for i, \
147 val in enumerate(squared_orders[sqso_index][0])])
148 sqso_identifier = "(%s), i.e. of split order ID=%d,"\
149 %(sqso_name, sqso_index+1)
150 res.append(comment%sqso_identifier)
151 res.append("IF(FILTER_SO.AND.SQSO_TARGET."+\
152 "EQ.%d) GOTO %d"%(sqso_index+1,continue_label))
153 return res
154
157 """Return a two lists of strings, the first corresponding to the Helas
158 calls for building the non-loop wavefunctions, the born and CT (only if
159 include_CT=True). The second correspond to the Helas calls for the
160 UVCT amplitudes only. The squared_orders can provide the information of
161 what is the maximum contributing CT amp number."""
162
163 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
164 "%s not valid argument for get_born_ct_helas_calls" % \
165 repr(matrix_element)
166
167 res = []
168
169 sqso_max_uvctamp = [sqso[1][0] for sqso in squared_orders]
170 sqso_max_ctamp = [sqso[1][1] for sqso in squared_orders]
171
172 for diagram in matrix_element.get_born_diagrams():
173 res.extend([ self.get_wavefunction_call(wf) for \
174 wf in diagram.get('wavefunctions') ])
175 res.append("# Amplitude(s) for born diagram with ID %d" % \
176 diagram.get('number'))
177 for amplitude in diagram.get('amplitudes'):
178 res.append(self.get_amplitude_call(amplitude))
179
180 for diagram in matrix_element.get_loop_diagrams():
181 res.extend([ self.get_wavefunction_call(wf) for \
182 wf in diagram.get('wavefunctions') ])
183 if diagram.get_ct_amplitudes() and include_CT:
184 res.append("# Counter-term amplitude(s) for loop diagram number %d" % \
185 diagram.get('number'))
186 for ctamp in diagram.get_ct_amplitudes():
187 res.append(self.get_amplitude_call(ctamp))
188 res.extend(self.get_sqso_target_skip_code(ctamp.get('number'),
189 sqso_max_ctamp, 2000, split_orders, squared_orders,
190 "# At this point, all CT amps needed for %s are computed."))
191
192 if not include_CT:
193 return res, []
194
195 res_UVCT = []
196 for diagram in matrix_element.get_loop_UVCT_diagrams():
197 res_UVCT.extend([ self.get_wavefunction_call(wf) for \
198 wf in diagram.get('wavefunctions') ])
199 res_UVCT.append("# Amplitude(s) for UVCT diagram with ID %d" % \
200 diagram.get('number'))
201 for ctamp in diagram.get('amplitudes'):
202 res_UVCT.append(self.get_amplitude_call(ctamp))
203 res_UVCT.extend(self.get_sqso_target_skip_code(ctamp.get('number'),
204 sqso_max_uvctamp, 3000, split_orders, squared_orders,
205 "# At this point, all UVCT amps needed for %s are computed."))
206
207 return res, res_UVCT
208
210 """Return a list of strings, corresponding to the Helas calls
211 for the loop matrix element"""
212
213 res_born_CT, res_UVCT = self.get_born_ct_helas_calls(loop_matrix_element)
214 res = res_born_CT + res_UVCT + \
215 self.get_loop_amp_helas_calls(loop_matrix_element)
216 return res
217
218
246
258
260 """Return a list of strings, corresponding to the Helas calls
261 for the matrix element"""
262
263 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
264 "%s not valid argument for get_matrix_element_calls" % \
265 repr(matrix_element)
266
267 res = []
268 for diagram in matrix_element.get('diagrams'):
269 res.append("# Amplitude(s) for diagram number %d" % \
270 diagram.get('number'))
271 for amplitude in diagram.get('amplitudes'):
272 res.append(self.get_amplitude_call(amplitude))
273
274 return res
275
277 """Return the function for writing the wavefunction
278 corresponding to the key"""
279
280 try:
281
282 call = self["wavefunctions"][wavefunction.get_call_key()](\
283 wavefunction)
284 except KeyError as error:
285 return ""
286
287 if self.options['zerowidth_tchannel'] and wavefunction.is_t_channel():
288 call, n = re.subn(',\s*fk_(?!ZERO)\w*\s*,', ', ZERO,', str(call), flags=re.I)
289 if n:
290 self.width_tchannel_set_tozero = True
291 return call
292
293
295 """Return the function for writing the amplitude
296 corresponding to the key"""
297
298 try:
299 call = self["amplitudes"][amplitude.get_call_key()]
300 except KeyError as error:
301 return ""
302 else:
303 return call(amplitude)
304
306 """Set the function for writing the wavefunction
307 corresponding to the key"""
308
309 assert isinstance(key, tuple), \
310 "%s is not a valid tuple for wavefunction key" % key
311
312 assert callable(function), \
313 "%s is not a valid function for wavefunction string" % function
314
315 self.get('wavefunctions')[key] = function
316 return True
317
319 """Set the function for writing the amplitude
320 corresponding to the key"""
321
322 assert isinstance(key, tuple), \
323 "%s is not a valid tuple for amplitude key" % str(key)
324
325 assert callable(function), \
326 "%s is not a valid function for amplitude string" % str(function)
327
328
329 self.get('amplitudes')[key] = function
330 return True
331
333 """Return the model name"""
334 return self['model'].get('name')
335
336
337
338 - def __init__(self, argument={}, options={}):
339 """Allow generating a HelasCallWriter from a Model
340 """
341
342 default_options = {'zerowidth_tchannel': True}
343
344 self.options = dict(default_options)
345 self.options.update(options)
346
347 if isinstance(argument, base_objects.Model):
348 super(HelasCallWriter, self).__init__()
349 self.set('model', argument)
350 else:
351 super(HelasCallWriter, self).__init__(argument)
352
357 """The class for writing Helas calls in Fortran, starting from
358 HelasWavefunctions and HelasAmplitudes.
359
360 Includes the function generate_helas_call, which automatically
361 generates the Fortran Helas call based on the Lorentz structure of
362 the interaction."""
363
364
365
366 self_dict = {1: 'H', 2: 'F', -2: 'F', 3: 'J', 5: 'U'}
367
368 sort_wf = {'O': 0, 'I': 1, 'S': 2, 'T': 3, 'V': 4}
369 sort_amp = {'S': 0, 'V': 2, 'T': 1, 'O': 3, 'I': 4}
370
372 """Set up special Helas calls (wavefunctions and amplitudes)
373 that can not be done automatically by generate_helas_call"""
374
375 super(FortranHelasCallWriter, self).default_setup()
376
377
378
379
380
381
382 key = ((3, 3, 5, 3,tuple()), ('A',))
383 call = lambda wf: \
384 "CALL UVVAXX(W(1,%d),W(1,%d),%s,zero,zero,zero,W(1,%d))" % \
385 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
386 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
387 wf.get('coupling')[0],
388 wf.get('me_id'))
389 self.add_wavefunction(key, call)
390
391 key = ((3, 5, 3, 1,tuple()), ('A',))
392 call = lambda wf: \
393 "CALL JVTAXX(W(1,%d),W(1,%d),%s,zero,zero,W(1,%d))" % \
394 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
395 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
396 wf.get('coupling')[0],
397 wf.get('me_id'))
398 self.add_wavefunction(key, call)
399
400 key = ((3, 3, 5), ('A',))
401 call = lambda amp: \
402 "CALL VVTAXX(W(1,%d),W(1,%d),W(1,%d),%s,zero,AMP(%d))" % \
403 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
404 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
405 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
406 amp.get('coupling')[0],
407 amp.get('number'))
408 self.add_amplitude(key, call)
409
410
411
412 key = ((3, 3, 3, 3, 1,tuple()), ('gggg3',))
413 call = lambda wf: \
414 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
415 (FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
416 FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
417 FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
418 wf.get('coupling')[0],
419 wf.get('me_id'))
420 self.add_wavefunction(key, call)
421 key = ((3, 3, 3, 3), ('gggg1',))
422 call = lambda amp: \
423 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
424 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
425 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
426 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
427 FortranHelasCallWriter.sorted_mothers(amp)[3].get('me_id'),
428 amp.get('coupling')[0],
429 amp.get('number'))
430 self.add_amplitude(key, call)
431 key = ((3, 3, 3, 3, 1 ,tuple()), ('gggg2',))
432 call = lambda wf: \
433 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
434 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
435 FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
436 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
437 wf.get('coupling')[0],
438 wf.get('me_id'))
439 self.add_wavefunction(key, call)
440 key = ((3, 3, 3, 3), ('gggg2',))
441 call = lambda amp: \
442 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
443 (FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
444 FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
445 FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
446 FortranHelasCallWriter.sorted_mothers(amp)[3].get('me_id'),
447 amp.get('coupling')[0],
448 amp.get('number'))
449 self.add_amplitude(key, call)
450 key = ((3, 3, 3, 3, 1,tuple()), ('gggg1',))
451 call = lambda wf: \
452 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
453 (FortranHelasCallWriter.sorted_mothers(wf)[2].get('me_id'),
454 FortranHelasCallWriter.sorted_mothers(wf)[1].get('me_id'),
455 FortranHelasCallWriter.sorted_mothers(wf)[0].get('me_id'),
456 wf.get('coupling')[0],
457 wf.get('me_id'))
458 self.add_wavefunction(key, call)
459 key = ((3, 3, 3, 3), ('gggg3',))
460 call = lambda amp: \
461 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
462 (FortranHelasCallWriter.sorted_mothers(amp)[1].get('me_id'),
463 FortranHelasCallWriter.sorted_mothers(amp)[2].get('me_id'),
464 FortranHelasCallWriter.sorted_mothers(amp)[0].get('me_id'),
465 FortranHelasCallWriter.sorted_mothers(amp)[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, 3,tuple()), ('',))
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,tuple()), ('',))
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
509 key = ((1, 3, 3, 3, 1,tuple()), ('',))
510 call = lambda wf: \
511 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
512 (wf.get('mothers')[0].get('me_id'),
513 wf.get('mothers')[1].get('me_id'),
514 wf.get('mothers')[2].get('me_id'),
515 wf.get('coupling')[0],
516 wf.get('mass'),
517 wf.get('width'),
518 wf.get('me_id'))
519 self.add_wavefunction(key, call)
520
521 key = ((3, 3, 3, 1, 4,tuple()), ('',))
522 call = lambda wf: \
523 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
524 (wf.get('mothers')[0].get('me_id'),
525 wf.get('mothers')[1].get('me_id'),
526 wf.get('mothers')[2].get('me_id'),
527 wf.get('coupling')[0],
528 wf.get('mass'),
529 wf.get('width'),
530 wf.get('me_id'))
531 self.add_wavefunction(key, call)
532
533 key = ((1, 3, 3, 3), ('',))
534 call = lambda amp: \
535 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \
536 (amp.get('mothers')[0].get('me_id'),
537 amp.get('mothers')[1].get('me_id'),
538 amp.get('mothers')[2].get('me_id'),
539 amp.get('mothers')[3].get('me_id'),
540 amp.get('coupling')[0],
541 amp.get('number'))
542 self.add_amplitude(key, call)
543
544
545 key = ((-2, 2, 5), ('',))
546 call = lambda amp: \
547 "CALL IOTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
548 (amp.get('mothers')[0].get('me_id'),
549 amp.get('mothers')[1].get('me_id'),
550 amp.get('mothers')[2].get('me_id'),
551 amp.get('coupling')[0],
552 amp.get('mothers')[0].get('mass'),
553 amp.get('number'))
554 self.add_amplitude(key, call)
555
556 key = ((-2, 2, 5, 3,tuple()), ('',))
557 call = lambda wf: \
558 "CALL UIOXXX(W(1,%d),W(1,%d),%s,%s,%s,%s,W(1,%d))" % \
559 (wf.get('mothers')[0].get('me_id'),
560 wf.get('mothers')[1].get('me_id'),
561 wf.get('coupling')[0],
562 wf.get('mothers')[0].get('mass'),
563 wf.get('mass'),
564 wf.get('width'),
565 wf.get('me_id'))
566 self.add_wavefunction(key, call)
567
568 key = ((3,3,3,5),('',))
569 call = lambda amp: \
570 "CALL VVVTXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),1d0,%s,AMP(%d))" % \
571 (amp.get('mothers')[0].get('me_id'),
572 amp.get('mothers')[1].get('me_id'),
573 amp.get('mothers')[2].get('me_id'),
574 amp.get('mothers')[3].get('me_id'),
575 amp.get('coupling')[0],
576 amp.get('number'))
577 self.add_amplitude(key, call)
578
579 key = ((3,3,5),('',))
580 call = lambda amp: \
581 "CALL VVTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
582 (amp.get('mothers')[0].get('me_id'),
583 amp.get('mothers')[1].get('me_id'),
584 amp.get('mothers')[2].get('me_id'),
585 amp.get('coupling')[0],
586 amp.get('mothers')[0].get('mass'),
587 amp.get('number'))
588 self.add_amplitude(key, call)
589
590
592 """Return the function for writing the wavefunction
593 corresponding to the key. If the function doesn't exist,
594 generate_helas_call is called to automatically create the
595 function."""
596
597 if wavefunction.get('spin') == 1 and \
598 wavefunction.get('interaction_id') != 0:
599
600
601
602
603 wavefunction.set_scalar_coupling_sign(self['model'])
604
605 val = super(FortranHelasCallWriter, self).get_wavefunction_call(wavefunction)
606
607 if val:
608 return val
609
610
611
612 if len(wavefunction.get('mothers')) > 3:
613 raise self.PhysicsObjectError("""Automatic generation of Fortran wavefunctions not
614 implemented for > 3 mothers""")
615
616 self.generate_helas_call(wavefunction)
617 return super(FortranHelasCallWriter, self).get_wavefunction_call(\
618 wavefunction)
619
638
640 """Routine for automatic generation of Fortran Helas calls
641 according to just the spin structure of the interaction.
642
643 First the call string is generated, using a dictionary to go
644 from the spin state of the calling wavefunction and its
645 mothers, or the mothers of the amplitude, to letters.
646
647 Then the call function is generated, as a lambda which fills
648 the call string with the information of the calling
649 wavefunction or amplitude. The call has different structure,
650 depending on the spin of the wavefunction and the number of
651 mothers (multiplicity of the vertex). The mother
652 wavefunctions, when entering the call, must be sorted in the
653 correct way - this is done by the sorted_mothers routine.
654
655 Finally the call function is stored in the relevant
656 dictionary, in order to be able to reuse the function the next
657 time a wavefunction with the same Lorentz structure is needed.
658 """
659
660 if not isinstance(argument, helas_objects.HelasWavefunction) and \
661 not isinstance(argument, helas_objects.HelasAmplitude):
662 raise self.PhysicsObjectError("get_helas_call must be called with wavefunction or amplitude")
663
664 call = "CALL "
665
666 call_function = None
667
668 if isinstance(argument, helas_objects.HelasAmplitude) and \
669 argument.get('interaction_id') == 0:
670 call = "#"
671 call_function = lambda amp: call
672
673 self.add_amplitude(argument.get_call_key(), call_function)
674 return
675
676 if isinstance(argument, helas_objects.HelasWavefunction) and \
677 not argument.get('mothers'):
678
679 call = call + HelasCallWriter.mother_dict[\
680 argument.get_spin_state_number()]
681
682 call = call + 'X' * (11 - len(call))
683 call = call + "(P(0,%d),"
684 if argument.get('spin') != 1:
685
686 call = call + "%s,NHEL(%d),"
687 call = call + "%+d*IC(%d),W(1,%d))"
688 if argument.get('spin') == 1:
689 call_function = lambda wf: call % \
690 (wf.get('number_external'),
691
692 (-1) ** (wf.get('state') == 'initial'),
693 wf.get('number_external'),
694 wf.get('me_id'))
695 elif argument.is_boson():
696 call_function = lambda wf: call % \
697 (wf.get('number_external'),
698 wf.get('mass'),
699 wf.get('number_external'),
700
701 (-1) ** (wf.get('state') == 'initial'),
702 wf.get('number_external'),
703 wf.get('me_id'))
704 else:
705 call_function = lambda wf: call % \
706 (wf.get('number_external'),
707 wf.get('mass'),
708 wf.get('number_external'),
709
710 - (-1) ** wf.get_with_flow('is_part'),
711 wf.get('number_external'),
712 wf.get('me_id'))
713 else:
714
715 if isinstance(argument, helas_objects.HelasWavefunction):
716 call = call + \
717 FortranHelasCallWriter.self_dict[\
718 argument.get_spin_state_number()]
719
720 mother_letters = FortranHelasCallWriter.sorted_letters(argument)
721
722
723
724 lor_name = argument.get('lorentz')[0]
725
726
727 if len(lor_name) > 3 and lor_name[:2] == "WW":
728 if lor_name[:4] == "WWWW":
729 mother_letters = "WWWW"[:len(mother_letters)]
730 if lor_name[:4] == "WWVV":
731 mother_letters = "W3W3"[:len(mother_letters)]
732 lor_name = lor_name[4:]
733
734 call = call + mother_letters
735 call = call + lor_name
736
737
738 if argument.needs_hermitian_conjugate():
739 call = call + 'C'
740
741 assert len(call) < 12, "Call to Helas routine %s should be maximum 6 chars" \
742 % call[5:]
743
744
745 call = call + 'X' * (11 - len(call)) + '('
746
747 call = call + "W(1,%d)," * len(argument.get('mothers'))
748
749 call = call + "%s,"
750
751
752 if isinstance(argument, helas_objects.HelasWavefunction):
753
754 if argument.get('lorentz') == ['WWVV']:
755
756 call = call + "1D0,"
757 elif argument.get('lorentz') == ['WWWW']:
758
759 call = call + "0D0,"
760 elif argument.get('spin') == 3 and \
761 [wf.get('spin') for wf in argument.get('mothers')] == \
762 [3, 3, 3]:
763
764
765 call = call + "DUM0,"
766
767 call = call + "%s,%s,"
768
769 call = call + "W(1,%d))"
770 else:
771
772
773 if argument.get('lorentz') == ['WWVV']:
774
775 call = call + "1D0,"
776 elif argument.get('lorentz') == ['WWWW']:
777
778 call = call + "0D0,"
779 elif [wf.get('spin') for wf in argument.get('mothers')] == \
780 [3, 3, 3, 3]:
781
782
783 call = call + "DUM0,"
784
785 call = call + "AMP(%d))"
786
787 if isinstance(argument, helas_objects.HelasWavefunction):
788
789 if len(argument.get('mothers')) == 2:
790 call_function = lambda wf: call % \
791 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
792 get('me_id'),
793 FortranHelasCallWriter.sorted_mothers(wf)[1].\
794 get('me_id'),
795 ','.join(wf.get_with_flow('coupling')),
796 wf.get('mass'),
797 wf.get('width'),
798 wf.get('me_id'))
799 else:
800 call_function = lambda wf: call % \
801 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
802 get('me_id'),
803 FortranHelasCallWriter.sorted_mothers(wf)[1].\
804 get('me_id'),
805 FortranHelasCallWriter.sorted_mothers(wf)[2].\
806 get('me_id'),
807 ','.join(wf.get_with_flow('coupling')),
808 wf.get('mass'),
809 wf.get('width'),
810 wf.get('me_id'))
811 else:
812
813 if len(argument.get('mothers')) == 3:
814 call_function = lambda amp: call % \
815 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
816 get('me_id'),
817 FortranHelasCallWriter.sorted_mothers(amp)[1].\
818 get('me_id'),
819 FortranHelasCallWriter.sorted_mothers(amp)[2].\
820 get('me_id'),
821
822 ','.join(amp.get('coupling')),
823 amp.get('number'))
824 else:
825 call_function = lambda amp: call % \
826 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
827 get('me_id'),
828 FortranHelasCallWriter.sorted_mothers(amp)[1].\
829 get('me_id'),
830 FortranHelasCallWriter.sorted_mothers(amp)[2].\
831 get('me_id'),
832 FortranHelasCallWriter.sorted_mothers(amp)[3].\
833 get('me_id'),
834 ','.join(amp.get('coupling')),
835 amp.get('number'))
836
837
838 if isinstance(argument, helas_objects.HelasWavefunction):
839 self.add_wavefunction(argument.get_call_key(), call_function)
840 else:
841 self.add_amplitude(argument.get_call_key(), call_function)
842
843
844
845 @staticmethod
861
862 @staticmethod
864 """Gives a list of mother wavefunctions sorted according to
865 1. The order of the particles in the interaction
866 2. Cyclic reordering of particles in same spin group
867 3. Fermions ordered IOIOIO... according to the pairs in
868 the interaction."""
869
870 assert isinstance(arg, (helas_objects.HelasWavefunction, helas_objects.HelasAmplitude)), \
871 "%s is not a valid HelasWavefunction or HelasAmplitude" % repr(arg)
872
873 if not arg.get('interaction_id'):
874 return arg.get('mothers')
875 my_pdg_code = 0
876 my_spin = 0
877 if isinstance(arg, helas_objects.HelasWavefunction):
878 my_pdg_code = arg.get_anti_pdg_code()
879 my_spin = arg.get_spin_state_number()
880
881 sorted_mothers, my_index = arg.get('mothers').sort_by_pdg_codes(\
882 arg.get('pdg_codes'), my_pdg_code)
883
884
885 partner = None
886 if isinstance(arg, helas_objects.HelasWavefunction) and arg.is_fermion():
887
888 if my_index % 2 == 0:
889
890 partner_index = my_index
891 else:
892
893 partner_index = my_index - 1
894 partner = sorted_mothers.pop(partner_index)
895
896 if partner.get_spin_state_number() > 0:
897 my_index = partner_index
898 else:
899 my_index = partner_index + 1
900
901
902 for i in range(0, len(sorted_mothers), 2):
903 if sorted_mothers[i].is_fermion():
904
905 if sorted_mothers[i].get_spin_state_number() > 0 and \
906 sorted_mothers[i + 1].get_spin_state_number() < 0:
907
908 sorted_mothers = sorted_mothers[:i] + \
909 [sorted_mothers[i+1], sorted_mothers[i]] + \
910 sorted_mothers[i+2:]
911 elif sorted_mothers[i].get_spin_state_number() < 0 and \
912 sorted_mothers[i + 1].get_spin_state_number() > 0:
913
914 pass
915 else:
916
917 break
918
919
920 if partner:
921 sorted_mothers.insert(partner_index, partner)
922
923 same_spin_mothers = []
924 if isinstance(arg, helas_objects.HelasWavefunction):
925
926 same_spin_index = -1
927 i=0
928 while i < len(sorted_mothers):
929 if abs(sorted_mothers[i].get_spin_state_number()) == \
930 abs(my_spin):
931 if same_spin_index < 0:
932
933 same_spin_index = i
934 same_spin_mothers.append(sorted_mothers.pop(i))
935 else:
936 i += 1
937
938
939 if same_spin_mothers:
940 same_spin_mothers = same_spin_mothers[my_index - same_spin_index:] \
941 + same_spin_mothers[:my_index - same_spin_index]
942
943
944 sorted_mothers = sorted_mothers[:same_spin_index] + \
945 same_spin_mothers + sorted_mothers[same_spin_index:]
946
947
948 return helas_objects.HelasWavefunctionList(sorted_mothers)
949
955 """The class for writing Helas calls in Fortran, starting from
956 HelasWavefunctions and HelasAmplitudes.
957
958 Includes the function generate_helas_call, which automatically
959 generates the Fortran Helas call based on the Lorentz structure of
960 the interaction."""
961
962
983
996
997
999 """Create a suitable string for the factor of the form
1000 (fraction, is_imaginary?)."""
1001 imag_dict = {True: "IMAG1", False: "ONE"}
1002 return str(factor[0]*factor[1]) + "*" + imag_dict[factor[2]]
1003
1008 """The class for writing Helas calls in Fortran, starting from
1009 HelasWavefunctions and HelasAmplitudes.
1010
1011 Includes the function generate_helas_call, which automatically
1012 generates the Fortran Helas call based on the Lorentz structure of
1013 the interaction."""
1014
1015 mp_prefix = check_param_card.ParamCard.mp_prefix
1016
1017 - def __init__(self, argument={}, hel_sum = False, options={}):
1018 """Allow generating a HelasCallWriter from a Model.The hel_sum argument
1019 specifies if amplitude and wavefunctions must be stored specifying the
1020 helicity, i.e. W(1,i) vs W(1,i,H).
1021 """
1022 self.hel_sum = hel_sum
1023 super(FortranUFOHelasCallWriter, self).__init__(argument, options=options)
1024
1033
1049
1050
1051
1053 """ Routine for automatic generation of a call to CutTools for loop
1054 amplitudes."""
1055
1056 call = "LOOP%(numLoopLines)s"
1057 if (len(loopamp.get('pairing')) != len(loopamp.get('mothers'))):
1058 call += "%(numMotherWfs)s%(numCouplings)s(%(numeratorNumber)d,"
1059 for i in range(len(loopamp.get('pairing'))):
1060 call = call + "%(Pairing{0})d,".format(i)
1061 else:
1062 call += "%(numCouplings)s(%(numeratorNumber)d,"
1063 for i in range(len(loopamp.get('mothers'))):
1064 call = call + "%(MotherID{0})d,".format(i+1)
1065 for i in range(len(loopamp.get('wavefunctions'))-2):
1066 call = call + \
1067 "DCMPLX(%(LoopMass{0})s),CMPLX({1}%(LoopMass{0})s,KIND=16),"\
1068 .format(i+1,self.mp_prefix)
1069 for i in range(len(loopamp.get('coupling'))):
1070 call = call + \
1071 "%(LoopCoupling{0})s,%(MPLoopCoupling{0})s,".format(i+1)
1072 call = call + "%(LoopRank)d,"
1073 call = call + "%(LoopSymmetryFactor)d,%(LoopMultiplier)d,"
1074 call = call + "%(ampNumber)d,AMPL(1,%(ampNumber)d),S(%(ampNumber)d))"
1075
1076 def create_loop_amp(amplitude):
1077 helas_dict = amplitude.get_helas_call_dict()
1078
1079
1080
1081 for i in range(len(loopamp.get('coupling'))):
1082 coupl = helas_dict['LoopCoupling%i'%(i+1)]
1083 helas_dict['MPLoopCoupling%i'%(i+1)]= \
1084 '-%s%s'%(self.mp_prefix,coupl[1:]) if coupl.startswith('-') \
1085 else '%s%s'%(self.mp_prefix,coupl)
1086
1087 return 'CALL %(proc_prefix)s'+call%helas_dict
1088
1089 self.add_amplitude(loopamp.get_call_key(), create_loop_amp)
1090 return
1091
1123
1125 """ Generate an external wavefunction """
1126
1127 call="CALL "
1128 call_function = None
1129 if argument.get('is_loop'):
1130 call=call+"LCUT_%(conjugate)s%(lcutspinletter)s(Q(0),I,WL(1,%(number)d))"
1131 else:
1132
1133 call = call + HelasCallWriter.mother_dict[\
1134 argument.get_spin_state_number()]
1135
1136 call = call + 'X' * (11 - len(call))
1137 call = call + "(P(0,%(number_external)d),"
1138 if argument.get('spin') != 1:
1139
1140 call = call + "%(mass)s,NHEL(%(number_external)d),"
1141 call = call + "%(state_id)+d*IC(%(number_external)d),{0})".format(\
1142 self.format_helas_object('W(1,','%(me_id)d'))
1143
1144 call_function = lambda wf: call % wf.get_external_helas_call_dict()
1145 self.add_wavefunction(argument.get_call_key(), call_function)
1146
1148 """ Generate all the helas objects for which no special handlers was
1149 placed in generate_helas_call """
1150
1151
1152 if isinstance(argument, helas_objects.HelasWavefunction):
1153 outgoing = argument.find_outgoing_number()
1154 else:
1155 outgoing = 0
1156
1157
1158
1159
1160 l = [str(l) for l in argument.get('lorentz')]
1161 flag = []
1162 if argument.needs_hermitian_conjugate():
1163 flag = ['C%d' % i for i in \
1164 argument.get_conjugate_index()]
1165 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1166 argument.get('is_loop') or \
1167 (isinstance(argument, helas_objects.HelasAmplitude) and \
1168 argument.get('type')=='loop')):
1169 flag.insert(0,"L")
1170
1171
1172 call = 'CALL %(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s)'
1173
1174 arg = {'routine_name': aloha_writers.combine_name(\
1175 '%s' % l[0], l[1:], outgoing, flag, True),
1176 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1177 tuple(range(len(argument.get('coupling'))))
1178 }
1179
1180
1181 if (isinstance(argument,helas_objects.HelasWavefunction) \
1182 and argument.get('is_loop')) or \
1183 ((isinstance(argument,helas_objects.HelasAmplitude) \
1184 and argument['type']=='loop')):
1185 base_wf = "W%(WF{0})s,"
1186 else:
1187 base_wf = self.format_helas_object('W(1,','%({0})d')+','
1188
1189
1190 wf = ''
1191 for i in range(len(argument.get('mothers'))):
1192 wf += base_wf.format(i)
1193 arg['wf'] = wf
1194
1195
1196
1197
1198 if isinstance(argument, helas_objects.HelasWavefunction):
1199 if argument['is_loop']:
1200 arg['out'] = 'WL(1,%(out)d)'
1201 if aloha.complex_mass:
1202 arg['mass'] = "ML(%(out)d),"
1203 else:
1204 arg['mass'] = "ML(%(out)d),ZERO,"
1205 else:
1206 arg['out']=self.format_helas_object('W(1,','%(out)d')
1207 if aloha.complex_mass:
1208 arg['mass'] = "DCMPLX(%(CM)s),"
1209 else:
1210 arg['mass'] = "%(M)s,%(W)s,"
1211
1212 elif argument['type'] == 'base':
1213 arg['mass'] = ''
1214 arg['out'] = self.format_helas_object('AMP(','%(out)d')
1215
1216 elif argument['type'] == 'loop':
1217 arg['mass'] = ''
1218 arg['out'] = 'BUFF(I)'
1219
1220 else:
1221 arg['mass'] = ''
1222 ampl = "AMPL({0},%(out)d)".format(argument.get_epsilon_order()+1)
1223 arg['out'] = '%s' % ampl
1224 if isinstance(argument,loop_helas_objects.LoopHelasUVCTAmplitude)\
1225 and argument.get_UVCT_couplings()!='1.0d0':
1226
1227 call += "\n %(second_line)s "
1228 arg['second_line'] = ampl+"="+ampl+"*(%(uvct)s)"
1229
1230
1231 call, arg = HelasCallWriter.customize_argument_for_all_other_helas_object(call, arg)
1232
1233 call = call % arg
1234
1235 call_function = lambda wf: call % wf.get_helas_call_dict(\
1236 OptimizedOutput=False, specifyHel=self.hel_sum)
1237
1238
1239 if isinstance(argument, helas_objects.HelasWavefunction):
1240 self.add_wavefunction(argument.get_call_key(), call_function)
1241 else:
1242 self.add_amplitude(argument.get_call_key(), call_function)
1243
1244
1245
1247 """ Returns a list of strings corresponding to the Helas calls for each
1248 loop amplitude of this loop matrix element. This function is placed in
1249 this class and not in HelasWriter, because it contains fortran-specific
1250 code."""
1251
1252 res = []
1253 loopHelasAmpNumberTreated=[]
1254 for ldiag in loop_matrix_element.get_loop_diagrams():
1255 for lamp in ldiag.get_loop_amplitudes():
1256 if lamp.get('number') in loopHelasAmpNumberTreated:
1257 continue
1258 else:
1259 loopHelasAmpNumberTreated.append(lamp.get('number'))
1260 lcutpart=self['model'].get_particle(lamp['type'])
1261 res.append("ELSEIF (ID.EQ.%d) THEN"%lamp.get('number'))
1262 res.append("#Loop diagram number %d (might be others, just an example)"\
1263 %ldiag.get('number'))
1264 if lcutpart.get('spin')==1:
1265 res.append("DO I=1,1")
1266 elif lcutpart.get('spin')==2 or lcutpart.get('spin')==3:
1267 res.append("DO I=1,4")
1268 else:
1269 raise self.PhysicsObjectError("The L-cut particle type is not supported")
1270
1271
1272
1273
1274
1275 externalWfNumber=1
1276 originalNumbers=[]
1277 couplingNumber=1
1278 originalCouplings=[]
1279 for lwf in lamp.get('wavefunctions'):
1280 if lwf.get('coupling')!=['none']:
1281 originalCouplings.append(lwf.get('coupling'))
1282 couplings=[]
1283 for coup in lwf.get('coupling'):
1284 couplings.append("LC(%d)"%couplingNumber)
1285 couplingNumber=couplingNumber+1
1286 lwf.set('coupling',couplings)
1287 for mother in lwf.get('mothers'):
1288 if not mother.get('is_loop'):
1289 originalNumbers.append(mother.get('number'))
1290 mother.set('me_id',externalWfNumber)
1291 externalWfNumber=externalWfNumber+1
1292
1293 res.append(self.get_wavefunction_call(\
1294 lamp.get_starting_loop_wavefunction()))
1295
1296 res.extend([ self.get_wavefunction_call(wf) for \
1297 wf in lamp.get('wavefunctions') if wf.get('mothers')])
1298
1299
1300
1301 for lwf in lamp.get('amplitudes')[0].get('mothers'):
1302 if lwf.get('mothers'):
1303 last_lwf_number=lwf.get('number')
1304 break
1305 res.append('BUFF(I)=WL(I+4,%d)'%last_lwf_number)
1306
1307 indexMothers=0
1308 indexWfs=0
1309 for lwf in lamp.get('wavefunctions'):
1310 if lwf.get('coupling')!=['none']:
1311 lwf.set('coupling',originalCouplings[indexWfs])
1312 indexWfs=indexWfs+1
1313 for mother in lwf.get('mothers'):
1314 if not mother.get('is_loop'):
1315 mother.set('me_id',originalNumbers[indexMothers])
1316 indexMothers=indexMothers+1
1317 res.append('ENDDO')
1318 if lcutpart.get('spin')==1:
1319 res.append("CALL CLOSE_1(BUFF(1),RES)")
1320 elif lcutpart.get('spin')==2 or lcutpart.get('spin')==3:
1321 res.append("CALL CLOSE_4(BUFF(1),RES)")
1322
1323 res[0]=res[0][4:]
1324
1325 res.append('ENDIF')
1326
1327 return res
1328
1333 """ Version of FortranUFOHelasCallWriter meeting the needs of the optimized
1334 output for loop processes """
1335
1337 """ We overwrite this function here because in the optimized mode one
1338 does not need to call the function set_octet_majorana_coupling_sign
1339 for the wavefunctions of the loop amplitudes. So we directly call
1340 the mother of the mother, namely UFOHelasCallWriter. """
1341
1342 return super(FortranUFOHelasCallWriter, self).get_amplitude_call(
1343 *args,**opts)
1344
1353
1356 """ Return the calls to the helas routines to construct the coefficients
1357 of the polynomial representation of the loop numerator (i.e. Pozzorini
1358 method). Group the coefficients of the loop with same denominator
1359 together if group_loops is set True. The squared_orders can provide the
1360 information of what is the maximum contributing loop amp number."""
1361
1362 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
1363 "%s not valid argument for get_coef_construction_calls" % \
1364 repr(matrix_element)
1365 loop_induced = (not matrix_element.get('processes')[0].get('has_born'))
1366 res = []
1367 sqso_max_lamp = [sqso[1][2] for sqso in squared_orders]
1368
1369 i=0
1370 for ldiag in matrix_element.get_loop_diagrams():
1371 res.append("# Coefficient construction for loop diagram with ID %d"\
1372 %ldiag.get('number'))
1373 for lwf in ldiag.get('loop_wavefunctions'):
1374 res.append(self.get_wavefunction_call(lwf))
1375 for lamp in ldiag.get_loop_amplitudes():
1376
1377
1378
1379 if (not group_loops) or loop_induced:
1380 lamp.set('loop_group_id',i)
1381 i=i+1
1382 create_coef=[
1383 'CREATE_LOOP_COEFS(WL(1,0,1,%(number)d)',
1384 '%(loop_rank)d','%(lcut_size)d',
1385 '%(loop_number)d','%(LoopSymmetryFactor)d',
1386 '%(LoopMultiplier)d']
1387 if not loop_induced:
1388 create_coef.append('%(amp_number)d,H)')
1389 else:
1390 create_coef.append('%(amp_number)d)')
1391
1392 res.append('CALL %(proc_prefix)s'+','.join(create_coef)%{\
1393 'number':lamp.get_final_loop_wavefunction().get('number'),
1394 'loop_rank':lamp.get_analytic_info('wavefunction_rank'),
1395 'lcut_size':lamp.get_lcut_size(),
1396
1397
1398
1399 'loop_number':(lamp.get('loop_group_id')+1),
1400 'amp_number':lamp.get('amplitudes')[0].get('number'),
1401 'LoopSymmetryFactor':lamp.get('loopsymmetryfactor'),
1402 'LoopMultiplier':lamp.get('multiplier')})
1403 res.extend(self.get_sqso_target_skip_code(
1404 lamp.get('amplitudes')[0].get('number'),
1405 sqso_max_lamp, 4000, split_orders, squared_orders,
1406 "# At this point, all loop coefficients needed"+
1407 " for %s are computed."))
1408
1409 coef_merge=['C Grouping of loop diagrams now done directly when '+\
1410 'creating the LOOPCOEFS.']
1411
1412 return res, coef_merge
1413
1414 - def get_loop_CT_calls(self, matrix_element, group_loops=True,
1415 squared_orders=[], split_orders=[]):
1416 """ Return the calls to CutTools interface routines to launch the
1417 computation of the contribution of one loop group. The squared_orders
1418 can provide the information of the maximum reference loop group ID for
1419 each contributing squared loop orders."""
1420
1421 assert isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement), \
1422 "%s not valid argument for get_loop_CT_calls" % \
1423 repr(matrix_element)
1424
1425 res = []
1426
1427 sqso_max_lgroup_refs = [sqso[1][3] for sqso in squared_orders]
1428
1429
1430
1431
1432 if group_loops and matrix_element.get('processes')[0].get('has_born'):
1433
1434 loop_group_refs=[(lamps[1][0],lamps[1][1:]) for lamps in \
1435 matrix_element.get('loop_groups')]
1436 for (lamp_ref, lamps) in loop_group_refs:
1437 res.append("# CutTools call for loop numbers %s"%\
1438 ','.join(['%d'%lamp_ref.get('number'),]+\
1439 ['%d'%lamp.get('number') for lamp in lamps]))
1440 res.append(self.get_amplitude_call(lamp_ref))
1441 res.extend(self.get_sqso_target_skip_code(
1442 lamp_ref.get('loop_group_id'), sqso_max_lgroup_refs, 5000,
1443 split_orders, squared_orders,
1444 "# At this point, all reductions needed for %s are computed."))
1445 else:
1446 for ldiag in matrix_element.get_loop_diagrams():
1447 res.append("# CutTools call for loop # %d"%ldiag.get('number'))
1448 for lamp in ldiag.get_loop_amplitudes():
1449
1450
1451 loop_group_id_tmp = lamp.get('loop_group_id')
1452 lamp.set('loop_group_id',lamp.get('number')-1)
1453 res.append(self.get_amplitude_call(lamp))
1454 lamp.set('loop_group_id',loop_group_id_tmp)
1455
1456 return res
1457
1471
1473 """ Routine for automatic generation of a call to CutTools for loop
1474 amplitudes for the optimized output."""
1475
1476 call = "LOOP%(numLoopLines)s"
1477 if (len(loopamp.get('pairing')) != len(loopamp.get('mothers'))):
1478 call += "%(numMotherWfs)s("
1479 for i in range(len(loopamp.get('pairing'))):
1480 call = call + "%(Pairing{0})d,".format(i)
1481 else:
1482 call += "("
1483 for i in range(len(loopamp.get('mothers'))):
1484 call = call + "%(MotherID{0})d,".format(i+1)
1485 for i in range(len(loopamp.get('wavefunctions'))-2):
1486 call = call + \
1487 "DCMPLX(%(LoopMass{0})s),".format(i+1)
1488 call = call + "%(LoopRank)d,"
1489 call = call + "I_SO,%(loop_group_id)d)"
1490
1491
1492 call_function = lambda amp: 'CALL %(proc_prefix)s'+\
1493 call % amp.get_helas_call_dict(OptimizedOutput=True)
1494 self.add_amplitude(loopamp.get_call_key(), call_function)
1495 return
1496
1498 """ Generate all the helas objects for which no special handlers was
1499 placed in generate_helas_call """
1500
1501 if isinstance(argument, helas_objects.HelasWavefunction):
1502 outgoing = argument.find_outgoing_number()
1503 else:
1504 outgoing = 0
1505
1506 if isinstance(argument, helas_objects.HelasAmplitude) and \
1507 argument.get('type')=='loop':
1508 raise MadGraph5Error('There should not be any helas call '+\
1509 'associated with helas amplitudes of type loop.')
1510
1511
1512 l = [str(l) for l in argument.get('lorentz')]
1513 flag = []
1514 if argument.needs_hermitian_conjugate():
1515 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1516
1517 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1518 argument.get('is_loop')):
1519 flag.insert(0,"L%d"%argument.get_loop_index())
1520
1521
1522 call = 'CALL %(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s)'
1523 arg = {'routine_name': aloha_writers.combine_name(\
1524 '%s' % l[0], l[1:], outgoing, flag, True),
1525 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1526 tuple(range(len(argument.get('coupling'))))
1527 }
1528
1529
1530 if (isinstance(argument,helas_objects.HelasWavefunction) \
1531 and argument.get('is_loop')):
1532 base_wf = "%(WF{0})s,"
1533 else:
1534 base_wf = self.format_helas_object('W(1,','%({0})d')+','
1535
1536
1537 wf = ''
1538 for i in range(len(argument.get('mothers'))):
1539 wf += base_wf.format(i)
1540 arg['wf'] = wf
1541
1542
1543
1544
1545 if isinstance(argument, helas_objects.HelasWavefunction):
1546 if argument['is_loop']:
1547 arg['out'] = 'PL(0,%(out)d),COEFS'
1548 else:
1549 arg['out']=self.format_helas_object('W(1,','%(out)d')
1550 if aloha.complex_mass:
1551 arg['mass'] = "DCMPLX(%(CM)s),"
1552 else:
1553 arg['mass'] = "%(M)s,%(W)s,"
1554
1555 elif argument['type'] == 'base':
1556 arg['mass'] = ''
1557 arg['out'] = self.format_helas_object('AMP(','%(out)d')
1558
1559 else:
1560 arg['mass'] = ''
1561 ampl = "AMPL({0},%(out)d)".format(argument.get_epsilon_order()+1)
1562 arg['out'] = '%s' % ampl
1563 if isinstance(argument,loop_helas_objects.LoopHelasUVCTAmplitude)\
1564 and argument.get_UVCT_couplings()!='1.0d0':
1565
1566 call += "\n %(second_line)s "
1567 arg['second_line'] = ampl+"="+ampl+"*(%(uvct)s)"
1568
1569
1570
1571 call = call % arg
1572 if (isinstance(argument, helas_objects.HelasWavefunction) and \
1573 argument.get('is_loop')):
1574
1575 call += "\nCALL {0}UPDATE_WL_%(loop_mother_rank)d_%(vertex_rank)d("
1576 call += "WL(1,0,1,%(loop_mother_number)d),%(lcut_size)d,COEFS,"
1577 call += "%(in_size)d,%(out_size)d,WL(1,0,1,%(out)d))"
1578
1579 call_function = lambda wf:\
1580 (call%wf.get_helas_call_dict(OptimizedOutput=True,
1581 specifyHel=self.hel_sum)).format('%(proc_prefix)s')
1582
1583
1584 if isinstance(argument, helas_objects.HelasWavefunction):
1585 self.add_wavefunction(argument.get_call_key(), call_function)
1586 else:
1587 self.add_amplitude(argument.get_call_key(), call_function)
1588
1593 """The class for writing Helas calls in C++, starting from
1594 HelasWavefunctions and HelasAmplitudes.
1595
1596 Includes the function generate_helas_call, which automatically
1597 generates the C++ Helas call based on the Lorentz structure of
1598 the interaction."""
1599
1601 """Routine for automatic generation of C++ Helas calls
1602 according to just the spin structure of the interaction.
1603
1604 First the call string is generated, using a dictionary to go
1605 from the spin state of the calling wavefunction and its
1606 mothers, or the mothers of the amplitude, to difenrentiate wich call is
1607 done.
1608
1609 Then the call function is generated, as a lambda which fills
1610 the call string with the information of the calling
1611 wavefunction or amplitude. The call has different structure,
1612 depending on the spin of the wavefunction and the number of
1613 mothers (multiplicity of the vertex). The mother
1614 wavefunctions, when entering the call, must be sorted in the
1615 correct way - this is done by the sorted_mothers routine.
1616
1617 Finally the call function is stored in the relevant
1618 dictionary, in order to be able to reuse the function the next
1619 time a wavefunction with the same Lorentz structure is needed.
1620 """
1621
1622 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1623 not isinstance(argument, helas_objects.HelasAmplitude):
1624 raise self.PhysicsObjectError("get_helas_call must be called with wavefunction or amplitude")
1625
1626 call = ""
1627
1628 call_function = None
1629
1630 if isinstance(argument, helas_objects.HelasAmplitude) and \
1631 argument.get('interaction_id') == 0:
1632 call = "#"
1633 call_function = lambda amp: call
1634 self.add_amplitude(argument.get_call_key(), call_function)
1635 return
1636
1637 if isinstance(argument, helas_objects.HelasWavefunction) and \
1638 not argument.get('mothers'):
1639
1640 call = call + HelasCallWriter.mother_dict[\
1641 argument.get_spin_state_number()].lower()
1642
1643 call = call + 'x' * (6 - len(call))
1644
1645 call = call + "(p[perm[%d]],"
1646 if argument.get('spin') != 1:
1647
1648 call = call + "mME[%d],hel[%d],"
1649 call = call + "%+d,w[%d]);"
1650 if argument.get('spin') == 1:
1651 call_function = lambda wf: call % \
1652 (wf.get('number_external')-1,
1653
1654 (-1) ** (wf.get('state') == 'initial'),
1655 wf.get('me_id')-1)
1656 elif argument.is_boson():
1657 call_function = lambda wf: call % \
1658 (wf.get('number_external')-1,
1659 wf.get('number_external')-1,
1660 wf.get('number_external')-1,
1661
1662 (-1) ** (wf.get('state') == 'initial'),
1663 wf.get('me_id')-1)
1664 else:
1665 call_function = lambda wf: call % \
1666 (wf.get('number_external')-1,
1667 wf.get('number_external')-1,
1668 wf.get('number_external')-1,
1669
1670 - (-1) ** wf.get_with_flow('is_part'),
1671 wf.get('me_id')-1)
1672 else:
1673 if isinstance(argument, helas_objects.HelasWavefunction):
1674 outgoing = argument.find_outgoing_number()
1675 else:
1676 outgoing = 0
1677
1678
1679 l = [str(l) for l in argument.get('lorentz')]
1680 flag = []
1681 if argument.needs_hermitian_conjugate():
1682 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1683
1684
1685
1686 call = '%(routine_name)s(%(wf)s%(coup)s%(mass)s%(out)s);'
1687
1688 arg = {'routine_name': aloha_writers.combine_name(\
1689 '%s' % l[0], l[1:], outgoing, flag,True),
1690 'wf': ("w[%%(%d)d]," * len(argument.get('mothers'))) % \
1691 tuple(range(len(argument.get('mothers')))),
1692 'coup': ("pars->%%(coup%d)s," * len(argument.get('coupling'))) % \
1693 tuple(range(len(argument.get('coupling'))))
1694 }
1695 if isinstance(argument, helas_objects.HelasWavefunction):
1696 arg['out'] = 'w[%(out)d]'
1697 if aloha.complex_mass:
1698 arg['mass'] = "pars->%(CM)s,"
1699 else:
1700 arg['mass'] = "pars->%(M)s,pars->%(W)s,"
1701 else:
1702 arg['out'] = 'amp[%(out)d]'
1703 arg['mass'] = ''
1704
1705 call = call % arg
1706
1707 call_function = lambda wf: self.format_coupling(
1708 call % wf.get_helas_call_dict(index=0))
1709
1710
1711 if isinstance(argument, helas_objects.HelasWavefunction):
1712 self.add_wavefunction(argument.get_call_key(), call_function)
1713 else:
1714 self.add_amplitude(argument.get_call_key(), call_function)
1715
1716 @staticmethod
1721
1727 """The class for writing Helas calls in Python, starting from
1728 HelasWavefunctions and HelasAmplitudes.
1729
1730 Includes the function generate_helas_call, which automatically
1731 generates the Python Helas call based on the Lorentz structure of
1732 the interaction."""
1733
1735 """Return a list of strings, corresponding to the Helas calls
1736 for the matrix element"""
1737
1738 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
1739 "%s not valid argument for get_matrix_element_calls" % \
1740 repr(matrix_element)
1741
1742 me = matrix_element.get('diagrams')
1743 matrix_element.reuse_outdated_wavefunctions(me)
1744
1745 res = []
1746 for diagram in matrix_element.get('diagrams'):
1747 wfs = diagram.get('wavefunctions')
1748 if gauge_check and diagram.get('number') == 1:
1749 gauge_check_wfs = [wf for wf in wfs if not wf.get('mothers') \
1750 and wf.get('spin') == 3 \
1751 and wf.get('mass').lower() == 'zero']
1752 if not gauge_check_wfs:
1753 raise HelasWriterError('no massless spin one particle for gauge check')
1754 gauge_check_wf = wfs.pop(wfs.index(gauge_check_wfs[0]))
1755 res.append(self.generate_helas_call(gauge_check_wf, True)(\
1756 gauge_check_wf))
1757 res.extend([ self.get_wavefunction_call(wf) for wf in wfs ])
1758 res.append("# Amplitude(s) for diagram number %d" % \
1759 diagram.get('number'))
1760 for amplitude in diagram.get('amplitudes'):
1761 res.append(self.get_amplitude_call(amplitude))
1762
1763 return res
1764
1765
1766
1768 """Routine for automatic generation of Python Helas calls
1769 according to just the spin structure of the interaction.
1770 """
1771
1772 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1773 not isinstance(argument, helas_objects.HelasAmplitude):
1774 raise self.PhysicsObjectError("get_helas_call must be called with wavefunction or amplitude")
1775
1776 call_function = None
1777
1778 if isinstance(argument, helas_objects.HelasAmplitude) and \
1779 argument.get('interaction_id') == 0:
1780 call = "#"
1781 call_function = lambda amp: call
1782 self.add_amplitude(argument.get_call_key(), call_function)
1783 return
1784
1785 if isinstance(argument, helas_objects.HelasWavefunction) and \
1786 not argument.get('mothers'):
1787
1788 call = "w[%d] = "
1789
1790 call = call + HelasCallWriter.mother_dict[\
1791 argument.get_spin_state_number()].lower()
1792
1793 call = call + 'x' * (14 - len(call))
1794 call = call + "(p[%d],"
1795 if argument.get('spin') != 1:
1796
1797 if gauge_check and argument.get('spin') == 3 and \
1798 argument.get('mass') == 'ZERO':
1799 call = call + "%s, 4,"
1800 else:
1801 call = call + "%s,hel[%d],"
1802 call = call + "%+d)"
1803 if argument.get('spin') == 1:
1804 call_function = lambda wf: call % \
1805 (wf.get('me_id')-1,
1806 wf.get('number_external')-1,
1807
1808 (-1)**(wf.get('state') == 'initial'))
1809 elif argument.is_boson():
1810 if not gauge_check or argument.get('mass') != 'ZERO':
1811 call_function = lambda wf: call % \
1812 (wf.get('me_id')-1,
1813 wf.get('number_external')-1,
1814 wf.get('mass'),
1815 wf.get('number_external')-1,
1816
1817 (-1)**(wf.get('state') == 'initial'))
1818 else:
1819 call_function = lambda wf: call % \
1820 (wf.get('me_id')-1,
1821 wf.get('number_external')-1,
1822 'ZERO',
1823
1824 (-1)**(wf.get('state') == 'initial'))
1825 else:
1826 call_function = lambda wf: call % \
1827 (wf.get('me_id')-1,
1828 wf.get('number_external')-1,
1829 wf.get('mass'),
1830 wf.get('number_external')-1,
1831
1832 -(-1)**wf.get_with_flow('is_part'))
1833 else:
1834
1835
1836 if isinstance(argument, helas_objects.HelasWavefunction):
1837 outgoing = argument.find_outgoing_number()
1838 else:
1839 outgoing = 0
1840
1841
1842 l = [str(l) for l in argument.get('lorentz')]
1843 flag = []
1844 if argument.needs_hermitian_conjugate():
1845 flag = ['C%d' % i for i in argument.get_conjugate_index()]
1846
1847
1848
1849 call = '%(out)s= %(routine_name)s(%(wf)s%(coup)s%(mass)s)'
1850
1851 arg = {'routine_name': aloha_writers.combine_name(\
1852 '%s' % l[0], l[1:], outgoing, flag, True),
1853 'wf': ("w[%%(%d)d]," * len(argument.get('mothers'))) % \
1854 tuple(range(len(argument.get('mothers')))),
1855 'coup': ("%%(coup%d)s," * len(argument.get('coupling'))) % \
1856 tuple(range(len(argument.get('coupling'))))
1857 }
1858
1859 if isinstance(argument, helas_objects.HelasWavefunction):
1860 arg['out'] = 'w[%(out)d]'
1861 if aloha.complex_mass:
1862 arg['mass'] = "%(CM)s"
1863 else:
1864 arg['mass'] = "%(M)s,%(W)s"
1865 else:
1866 arg['coup'] = arg['coup'][:-1]
1867 arg['out'] = 'amp[%(out)d]'
1868 arg['mass'] = ''
1869
1870 call = call % arg
1871
1872 call_function = lambda wf: call % wf.get_helas_call_dict(index=0)
1873
1874 routine_name = aloha_writers.combine_name(
1875 '%s' % l[0], l[1:], outgoing, flag)
1876
1877
1878 if isinstance(argument, helas_objects.HelasWavefunction):
1879 if not gauge_check:
1880 self.add_wavefunction(argument.get_call_key(), call_function)
1881 else:
1882 self.add_amplitude(argument.get_call_key(), call_function)
1883
1884 return call_function
1885