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