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 aloha.aloha_writers as aloha_writers
22 """Class for the error of this module """
23 pass
24
29 """Language independent base class for writing Helas calls. The
30 calls are stored in two dictionaries, wavefunctions and
31 amplitudes, with entries being a mapping from a set of spin,
32 incoming/outgoing states and Lorentz structure to a function which
33 writes the corresponding wavefunction/amplitude call (taking a
34 HelasWavefunction/HelasAmplitude as argument)."""
35
36
37
38 mother_dict = {1: 'S', 2: 'O', -2: 'I', 3: 'V', 5: 'T'}
39
41
42 self['model'] = base_objects.Model()
43 self['wavefunctions'] = {}
44 self['amplitudes'] = {}
45
46 - def filter(self, name, value):
77
79 """Return process property names as a nicely sorted list."""
80
81 return ['model', 'wavefunctions', 'amplitudes']
82
84 """Return a list of strings, corresponding to the Helas calls
85 for the matrix element"""
86
87 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
88 "%s not valid argument for get_matrix_element_calls" % \
89 repr(matrix_element)
90
91 res = []
92 for diagram in matrix_element.get('diagrams'):
93 res.extend([ self.get_wavefunction_call(wf) for \
94 wf in diagram.get('wavefunctions') ])
95 res.append("# Amplitude(s) for diagram number %d" % \
96 diagram.get('number'))
97 for amplitude in diagram.get('amplitudes'):
98 res.append(self.get_amplitude_call(amplitude))
99
100 return res
101
113
115 """Return a list of strings, corresponding to the Helas calls
116 for the matrix element"""
117
118 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
119 "%s not valid argument for get_matrix_element_calls" % \
120 repr(matrix_element)
121
122 res = []
123 for diagram in matrix_element.get('diagrams'):
124 res.append("# Amplitude(s) for diagram number %d" % \
125 diagram.get('number'))
126 for amplitude in diagram.get('amplitudes'):
127 res.append(self.get_amplitude_call(amplitude))
128
129 return res
130
132 """Return the function for writing the wavefunction
133 corresponding to the key"""
134
135 try:
136 call = self["wavefunctions"][wavefunction.get_call_key()](\
137 wavefunction)
138 return call
139 except KeyError:
140 return ""
141
143 """Return the function for writing the amplitude
144 corresponding to the key"""
145
146 try:
147 call = self["amplitudes"][amplitude.get_call_key()](amplitude)
148 return call
149 except KeyError:
150 return ""
151
153 """Set the function for writing the wavefunction
154 corresponding to the key"""
155
156 assert isinstance(key, tuple), \
157 "%s is not a valid tuple for wavefunction key" % key
158
159 assert callable(function), \
160 "%s is not a valid function for wavefunction string" % function
161
162 self.get('wavefunctions')[key] = function
163 return True
164
166 """Set the function for writing the amplitude
167 corresponding to the key"""
168
169 assert isinstance(key, tuple), \
170 "%s is not a valid tuple for amplitude key" % str(key)
171
172 assert callable(function), \
173 "%s is not a valid function for amplitude string" % str(function)
174
175
176 self.get('amplitudes')[key] = function
177 return True
178
180 """Return the model name"""
181 return self['model'].get('name')
182
183
193
201 """The class for writing Helas calls in Fortran, starting from
202 HelasWavefunctions and HelasAmplitudes.
203
204 Includes the function generate_helas_call, which automatically
205 generates the Fortran Helas call based on the Lorentz structure of
206 the interaction."""
207
208
209
210 self_dict = {1: 'H', 2: 'F', -2: 'F', 3: 'J', 5: 'U'}
211
212 sort_wf = {'O': 0, 'I': 1, 'S': 2, 'T': 3, 'V': 4}
213 sort_amp = {'S': 0, 'V': 2, 'T': 1, 'O': 3, 'I': 4}
214
216 """Set up special Helas calls (wavefunctions and amplitudes)
217 that can not be done automatically by generate_helas_call"""
218
219 super(FortranHelasCallWriter, self).default_setup()
220
221
222
223
224
225
226 key = ((3, 3, 5, 3), ('A',))
227 call = lambda wf: \
228 "CALL UVVAXX(W(1,%d),W(1,%d),%s,zero,zero,zero,W(1,%d))" % \
229 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'),
230 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'),
231 wf.get('coupling')[0],
232 wf.get('number'))
233 self.add_wavefunction(key, call)
234
235 key = ((3, 5, 3, 1), ('A',))
236 call = lambda wf: \
237 "CALL JVTAXX(W(1,%d),W(1,%d),%s,zero,zero,W(1,%d))" % \
238 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'),
239 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'),
240 wf.get('coupling')[0],
241 wf.get('number'))
242 self.add_wavefunction(key, call)
243
244 key = ((3, 3, 5), ('A',))
245 call = lambda amp: \
246 "CALL VVTAXX(W(1,%d),W(1,%d),W(1,%d),%s,zero,AMP(%d))" % \
247 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'),
248 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'),
249 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'),
250 amp.get('coupling')[0],
251 amp.get('number'))
252 self.add_amplitude(key, call)
253
254
255
256 key = ((3, 3, 3, 3, 1), ('gggg3',))
257 call = lambda wf: \
258 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
259 (FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'),
260 FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'),
261 FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'),
262 wf.get('coupling')[0],
263 wf.get('number'))
264 self.add_wavefunction(key, call)
265 key = ((3, 3, 3, 3), ('gggg1',))
266 call = lambda amp: \
267 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
268 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'),
269 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'),
270 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'),
271 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'),
272 amp.get('coupling')[0],
273 amp.get('number'))
274 self.add_amplitude(key, call)
275 key = ((3, 3, 3, 3, 1), ('gggg2',))
276 call = lambda wf: \
277 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
278 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'),
279 FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'),
280 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'),
281 wf.get('coupling')[0],
282 wf.get('number'))
283 self.add_wavefunction(key, call)
284 key = ((3, 3, 3, 3), ('gggg2',))
285 call = lambda amp: \
286 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
287 (FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'),
288 FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'),
289 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'),
290 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'),
291 amp.get('coupling')[0],
292 amp.get('number'))
293 self.add_amplitude(key, call)
294 key = ((3, 3, 3, 3, 1), ('gggg1',))
295 call = lambda wf: \
296 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \
297 (FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'),
298 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'),
299 FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'),
300 wf.get('coupling')[0],
301 wf.get('number'))
302 self.add_wavefunction(key, call)
303 key = ((3, 3, 3, 3), ('gggg3',))
304 call = lambda amp: \
305 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \
306 (FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'),
307 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'),
308 FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'),
309 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'),
310 amp.get('coupling')[0],
311 amp.get('number'))
312 self.add_amplitude(key, call)
313
314
315
316 key = ((1, 3, 3, 3, 3), ('',))
317 call = lambda wf: \
318 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
319 (wf.get('mothers')[0].get('number'),
320 wf.get('mothers')[1].get('number'),
321 wf.get('mothers')[2].get('number'),
322 wf.get('coupling')[0],
323 wf.get('mass'),
324 wf.get('width'),
325 wf.get('number'))
326 self.add_wavefunction(key, call)
327
328 key = ((3, 3, 3, 1, 4), ('',))
329 call = lambda wf: \
330 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
331 (wf.get('mothers')[0].get('number'),
332 wf.get('mothers')[1].get('number'),
333 wf.get('mothers')[2].get('number'),
334 wf.get('coupling')[0],
335 wf.get('mass'),
336 wf.get('width'),
337 wf.get('number'))
338 self.add_wavefunction(key, call)
339
340 key = ((1, 3, 3, 3), ('',))
341 call = lambda amp: \
342 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \
343 (amp.get('mothers')[0].get('number'),
344 amp.get('mothers')[1].get('number'),
345 amp.get('mothers')[2].get('number'),
346 amp.get('mothers')[3].get('number'),
347 amp.get('coupling')[0],
348 amp.get('number'))
349 self.add_amplitude(key, call)
350
351
352
353 key = ((1, 3, 3, 3, 1), ('',))
354 call = lambda wf: \
355 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
356 (wf.get('mothers')[0].get('number'),
357 wf.get('mothers')[1].get('number'),
358 wf.get('mothers')[2].get('number'),
359 wf.get('coupling')[0],
360 wf.get('mass'),
361 wf.get('width'),
362 wf.get('number'))
363 self.add_wavefunction(key, call)
364
365 key = ((3, 3, 3, 1, 4), ('',))
366 call = lambda wf: \
367 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \
368 (wf.get('mothers')[0].get('number'),
369 wf.get('mothers')[1].get('number'),
370 wf.get('mothers')[2].get('number'),
371 wf.get('coupling')[0],
372 wf.get('mass'),
373 wf.get('width'),
374 wf.get('number'))
375 self.add_wavefunction(key, call)
376
377 key = ((1, 3, 3, 3), ('',))
378 call = lambda amp: \
379 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \
380 (amp.get('mothers')[0].get('number'),
381 amp.get('mothers')[1].get('number'),
382 amp.get('mothers')[2].get('number'),
383 amp.get('mothers')[3].get('number'),
384 amp.get('coupling')[0],
385 amp.get('number'))
386 self.add_amplitude(key, call)
387
388
389 key = ((-2, 2, 5), ('',))
390 call = lambda amp: \
391 "CALL IOTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
392 (amp.get('mothers')[0].get('number'),
393 amp.get('mothers')[1].get('number'),
394 amp.get('mothers')[2].get('number'),
395 amp.get('coupling')[0],
396 amp.get('mothers')[0].get('mass'),
397 amp.get('number'))
398 self.add_amplitude(key, call)
399
400 key = ((-2, 2, 5, 3), ('',))
401 call = lambda wf: \
402 "CALL UIOXXX(W(1,%d),W(1,%d),%s,%s,%s,%s,W(1,%d))" % \
403 (wf.get('mothers')[0].get('number'),
404 wf.get('mothers')[1].get('number'),
405 wf.get('coupling')[0],
406 wf.get('mothers')[0].get('mass'),
407 wf.get('mass'),
408 wf.get('width'),
409 wf.get('number'))
410 self.add_wavefunction(key, call)
411
412 key = ((3,3,3,5),('',))
413 call = lambda amp: \
414 "CALL VVVTXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),1d0,%s,AMP(%d))" % \
415 (amp.get('mothers')[0].get('number'),
416 amp.get('mothers')[1].get('number'),
417 amp.get('mothers')[2].get('number'),
418 amp.get('mothers')[3].get('number'),
419 amp.get('coupling')[0],
420 amp.get('number'))
421 self.add_amplitude(key, call)
422
423 key = ((3,3,5),('',))
424 call = lambda amp: \
425 "CALL VVTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \
426 (amp.get('mothers')[0].get('number'),
427 amp.get('mothers')[1].get('number'),
428 amp.get('mothers')[2].get('number'),
429 amp.get('coupling')[0],
430 amp.get('mothers')[0].get('mass'),
431 amp.get('number'))
432 self.add_amplitude(key, call)
433
434
436 """Return the function for writing the wavefunction
437 corresponding to the key. If the function doesn't exist,
438 generate_helas_call is called to automatically create the
439 function."""
440
441 if wavefunction.get('spin') == 1 and \
442 wavefunction.get('interaction_id') != 0:
443
444
445
446
447 wavefunction.set_scalar_coupling_sign(self['model'])
448
449 val = super(FortranHelasCallWriter, self).get_wavefunction_call(wavefunction)
450
451 if val:
452 return val
453
454
455
456 if len(wavefunction.get('mothers')) > 3:
457 raise self.PhysicsObjectError, \
458 """Automatic generation of Fortran wavefunctions not
459 implemented for > 3 mothers"""
460
461 self.generate_helas_call(wavefunction)
462 return super(FortranHelasCallWriter, self).get_wavefunction_call(\
463 wavefunction)
464
466 """Return the function for writing the amplitude corresponding
467 to the key. If the function doesn't exist, generate_helas_call
468 is called to automatically create the function."""
469
470 val = super(FortranHelasCallWriter, self).get_amplitude_call(amplitude)
471
472 if val:
473 return val
474
475
476
477 if len(amplitude.get('mothers')) > 4:
478 raise self.PhysicsObjectError, \
479 """Automatic generation of Fortran amplitudes not
480 implemented for > 4 mothers"""
481
482 self.generate_helas_call(amplitude)
483 return super(FortranHelasCallWriter, self).get_amplitude_call(amplitude)
484
486 """Routine for automatic generation of Fortran Helas calls
487 according to just the spin structure of the interaction.
488
489 First the call string is generated, using a dictionary to go
490 from the spin state of the calling wavefunction and its
491 mothers, or the mothers of the amplitude, to letters.
492
493 Then the call function is generated, as a lambda which fills
494 the call string with the information of the calling
495 wavefunction or amplitude. The call has different structure,
496 depending on the spin of the wavefunction and the number of
497 mothers (multiplicity of the vertex). The mother
498 wavefunctions, when entering the call, must be sorted in the
499 correct way - this is done by the sorted_mothers routine.
500
501 Finally the call function is stored in the relevant
502 dictionary, in order to be able to reuse the function the next
503 time a wavefunction with the same Lorentz structure is needed.
504 """
505
506 if not isinstance(argument, helas_objects.HelasWavefunction) and \
507 not isinstance(argument, helas_objects.HelasAmplitude):
508 raise self.PhysicsObjectError, \
509 "get_helas_call must be called with wavefunction or amplitude"
510
511 call = "CALL "
512
513 call_function = None
514
515 if isinstance(argument, helas_objects.HelasAmplitude) and \
516 argument.get('interaction_id') == 0:
517 call = "#"
518 call_function = lambda amp: call
519
520 self.add_amplitude(argument.get_call_key(), call_function)
521 return
522
523 if isinstance(argument, helas_objects.HelasWavefunction) and \
524 not argument.get('mothers'):
525
526 call = call + HelasCallWriter.mother_dict[\
527 argument.get_spin_state_number()]
528
529 call = call + 'X' * (11 - len(call))
530 call = call + "(P(0,%d),"
531 if argument.get('spin') != 1:
532
533 call = call + "%s,NHEL(%d),"
534 call = call + "%+d*IC(%d),W(1,%d))"
535 if argument.get('spin') == 1:
536 call_function = lambda wf: call % \
537 (wf.get('number_external'),
538
539 (-1) ** (wf.get('state') == 'initial'),
540 wf.get('number_external'),
541 wf.get('number'))
542 elif argument.is_boson():
543 call_function = lambda wf: call % \
544 (wf.get('number_external'),
545 wf.get('mass'),
546 wf.get('number_external'),
547
548 (-1) ** (wf.get('state') == 'initial'),
549 wf.get('number_external'),
550 wf.get('number'))
551 else:
552 call_function = lambda wf: call % \
553 (wf.get('number_external'),
554 wf.get('mass'),
555 wf.get('number_external'),
556
557 - (-1) ** wf.get_with_flow('is_part'),
558 wf.get('number_external'),
559 wf.get('number'))
560 else:
561
562 if isinstance(argument, helas_objects.HelasWavefunction):
563 call = call + \
564 FortranHelasCallWriter.self_dict[\
565 argument.get_spin_state_number()]
566
567 mother_letters = FortranHelasCallWriter.sorted_letters(argument)
568
569
570
571 lor_name = argument.get('lorentz')[0]
572
573
574 if len(lor_name) > 3 and lor_name[:2] == "WW":
575 if lor_name[:4] == "WWWW":
576 mother_letters = "WWWW"[:len(mother_letters)]
577 if lor_name[:4] == "WWVV":
578 mother_letters = "W3W3"[:len(mother_letters)]
579 lor_name = lor_name[4:]
580
581 call = call + mother_letters
582 call = call + lor_name
583
584
585 if argument.needs_hermitian_conjugate():
586 call = call + 'C'
587
588 assert len(call) < 12, "Call to Helas routine %s should be maximum 6 chars" \
589 % call[5:]
590
591
592 call = call + 'X' * (11 - len(call)) + '('
593
594 call = call + "W(1,%d)," * len(argument.get('mothers'))
595
596 call = call + "%s,"
597
598
599 if isinstance(argument, helas_objects.HelasWavefunction):
600
601 if argument.get('lorentz') == 'WWVV':
602
603 call = call + "1D0,"
604 elif argument.get('lorentz') == 'WWWW':
605
606 call = call + "0D0,"
607 elif argument.get('spin') == 3 and \
608 [wf.get('spin') for wf in argument.get('mothers')] == \
609 [3, 3, 3]:
610
611
612 call = call + "DUM0,"
613
614 call = call + "%s,%s,"
615
616 call = call + "W(1,%d))"
617 else:
618
619
620 if argument.get('lorentz') == 'WWVV':
621
622 call = call + "1D0,"
623 elif argument.get('lorentz') == 'WWWW':
624
625 call = call + "0D0,"
626 elif [wf.get('spin') for wf in argument.get('mothers')] == \
627 [3, 3, 3, 3]:
628
629
630 call = call + "DUM0,"
631
632 call = call + "AMP(%d))"
633
634 if isinstance(argument, helas_objects.HelasWavefunction):
635
636 if len(argument.get('mothers')) == 2:
637 call_function = lambda wf: call % \
638 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
639 get('number'),
640 FortranHelasCallWriter.sorted_mothers(wf)[1].\
641 get('number'),
642 ','.join(wf.get_with_flow('coupling')),
643 wf.get('mass'),
644 wf.get('width'),
645 wf.get('number'))
646 else:
647 call_function = lambda wf: call % \
648 (FortranHelasCallWriter.sorted_mothers(wf)[0].\
649 get('number'),
650 FortranHelasCallWriter.sorted_mothers(wf)[1].\
651 get('number'),
652 FortranHelasCallWriter.sorted_mothers(wf)[2].\
653 get('number'),
654 ','.join(wf.get_with_flow('coupling')),
655 wf.get('mass'),
656 wf.get('width'),
657 wf.get('number'))
658 else:
659
660 if len(argument.get('mothers')) == 3:
661 call_function = lambda amp: call % \
662 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
663 get('number'),
664 FortranHelasCallWriter.sorted_mothers(amp)[1].\
665 get('number'),
666 FortranHelasCallWriter.sorted_mothers(amp)[2].\
667 get('number'),
668
669 ','.join(amp.get('coupling')),
670 amp.get('number'))
671 else:
672 call_function = lambda amp: call % \
673 (FortranHelasCallWriter.sorted_mothers(amp)[0].\
674 get('number'),
675 FortranHelasCallWriter.sorted_mothers(amp)[1].\
676 get('number'),
677 FortranHelasCallWriter.sorted_mothers(amp)[2].\
678 get('number'),
679 FortranHelasCallWriter.sorted_mothers(amp)[3].\
680 get('number'),
681 ','.join(amp.get('coupling')),
682 amp.get('number'))
683
684
685 if isinstance(argument, helas_objects.HelasWavefunction):
686 self.add_wavefunction(argument.get_call_key(), call_function)
687 else:
688 self.add_amplitude(argument.get_call_key(), call_function)
689
690
691
692 @staticmethod
710
711 @staticmethod
713 """Gives a list of mother wavefunctions sorted according to
714 1. The order of the particles in the interaction
715 2. Cyclic reordering of particles in same spin group
716 3. Fermions ordered IOIOIO... according to the pairs in
717 the interaction."""
718
719 assert isinstance(arg, (helas_objects.HelasWavefunction, helas_objects.HelasAmplitude)), \
720 "%s is not a valid HelasWavefunction or HelasAmplitude" % repr(arg)
721
722 if not arg.get('interaction_id'):
723 return arg.get('mothers')
724 my_pdg_code = 0
725 my_spin = 0
726 if isinstance(arg, helas_objects.HelasWavefunction):
727 my_pdg_code = arg.get_anti_pdg_code()
728 my_spin = arg.get_spin_state_number()
729
730 sorted_mothers, my_index = arg.get('mothers').sort_by_pdg_codes(\
731 arg.get('pdg_codes'), my_pdg_code)
732
733
734 partner = None
735 if isinstance(arg, helas_objects.HelasWavefunction) and arg.is_fermion():
736
737 if my_index % 2 == 0:
738
739 partner_index = my_index
740 else:
741
742 partner_index = my_index - 1
743 partner = sorted_mothers.pop(partner_index)
744
745 if partner.get_spin_state_number() > 0:
746 my_index = partner_index
747 else:
748 my_index = partner_index + 1
749
750
751 for i in range(0, len(sorted_mothers), 2):
752 if sorted_mothers[i].is_fermion():
753
754 if sorted_mothers[i].get_spin_state_number() > 0 and \
755 sorted_mothers[i + 1].get_spin_state_number() < 0:
756
757 sorted_mothers = sorted_mothers[:i] + \
758 [sorted_mothers[i+1], sorted_mothers[i]] + \
759 sorted_mothers[i+2:]
760 elif sorted_mothers[i].get_spin_state_number() < 0 and \
761 sorted_mothers[i + 1].get_spin_state_number() > 0:
762
763 pass
764 else:
765
766 break
767
768
769 if partner:
770 sorted_mothers.insert(partner_index, partner)
771
772 same_spin_mothers = []
773 if isinstance(arg, helas_objects.HelasWavefunction):
774
775 same_spin_index = -1
776 i=0
777 while i < len(sorted_mothers):
778 if abs(sorted_mothers[i].get_spin_state_number()) == \
779 abs(my_spin):
780 if same_spin_index < 0:
781
782 same_spin_index = i
783 same_spin_mothers.append(sorted_mothers.pop(i))
784 else:
785 i += 1
786
787
788 if same_spin_mothers:
789 same_spin_mothers = same_spin_mothers[my_index - same_spin_index:] \
790 + same_spin_mothers[:my_index - same_spin_index]
791
792
793 sorted_mothers = sorted_mothers[:same_spin_index] + \
794 same_spin_mothers + sorted_mothers[same_spin_index:]
795
796
797 return helas_objects.HelasWavefunctionList(sorted_mothers)
798
804 """The class for writing Helas calls in Fortran, starting from
805 HelasWavefunctions and HelasAmplitudes.
806
807 Includes the function generate_helas_call, which automatically
808 generates the Fortran Helas call based on the Lorentz structure of
809 the interaction."""
810
811
832
845
853 """The class for writing Helas calls in Fortran, starting from
854 HelasWavefunctions and HelasAmplitudes.
855
856 Includes the function generate_helas_call, which automatically
857 generates the Fortran Helas call based on the Lorentz structure of
858 the interaction."""
859
861 """Routine for automatic generation of Fortran Helas calls
862 according to just the spin structure of the interaction.
863 """
864
865 if not isinstance(argument, helas_objects.HelasWavefunction) and \
866 not isinstance(argument, helas_objects.HelasAmplitude):
867 raise self.PhysicsObjectError, \
868 "get_helas_call must be called with wavefunction or amplitude"
869
870 call = "CALL "
871
872 call_function = None
873
874 if isinstance(argument, helas_objects.HelasAmplitude) and \
875 argument.get('interaction_id') == 0:
876 call = "#"
877 call_function = lambda amp: call
878 self.add_amplitude(argument.get_call_key(), call_function)
879 return
880
881 if isinstance(argument, helas_objects.HelasWavefunction) and \
882 not argument.get('mothers'):
883
884 call = call + HelasCallWriter.mother_dict[\
885 argument.get_spin_state_number()]
886
887 call = call + 'X' * (11 - len(call))
888 call = call + "(P(0,%d),"
889 if argument.get('spin') != 1:
890
891 call = call + "%s,NHEL(%d),"
892 call = call + "%+d*IC(%d),W(1,%d))"
893 if argument.get('spin') == 1:
894 call_function = lambda wf: call % \
895 (wf.get('number_external'),
896
897 (-1) ** (wf.get('state') == 'initial'),
898 wf.get('number_external'),
899 wf.get('number'))
900 elif argument.is_boson():
901 call_function = lambda wf: call % \
902 (wf.get('number_external'),
903 wf.get('mass'),
904 wf.get('number_external'),
905
906 (-1) ** (wf.get('state') == 'initial'),
907 wf.get('number_external'),
908 wf.get('number'))
909 else:
910 call_function = lambda wf: call % \
911 (wf.get('number_external'),
912 wf.get('mass'),
913 wf.get('number_external'),
914
915 - (-1) ** wf.get_with_flow('is_part'),
916 wf.get('number_external'),
917 wf.get('number'))
918 else:
919
920
921 if isinstance(argument, helas_objects.HelasWavefunction):
922 outgoing = argument.find_outgoing_number()
923 else:
924 outgoing = 0
925
926
927 l = [str(l) for l in argument.get('lorentz')]
928 flag = ['C%d' % i for i in argument.get('conjugate_indices')]
929 routine_name = aloha_writers.combine_name(
930 '%s' % l[0], l[1:], outgoing, flag)
931 call = 'CALL %s' % (routine_name)
932
933
934 call = call + '('
935
936 call = call + "W(1,%d)," * len(argument.get('mothers'))
937
938 call = call + "%s,"
939
940 if isinstance(argument, helas_objects.HelasWavefunction):
941
942 call = call + "%s, %s, W(1,%d))"
943
944 call_function = lambda wf: call % \
945 (tuple([mother.get('number') for mother in wf.get('mothers')]) + \
946 (','.join(wf.get_with_flow('coupling')),
947 wf.get('mass'),
948 wf.get('width'),
949 wf.get('number')))
950 else:
951
952 call += "AMP(%d))"
953 call_function = lambda amp: call % \
954 (tuple([mother.get('number')
955 for mother in amp.get('mothers')]) + \
956 (','.join(amp.get('coupling')),
957 amp.get('number')))
958
959
960 if isinstance(argument, helas_objects.HelasWavefunction):
961 self.add_wavefunction(argument.get_call_key(), call_function)
962 else:
963 self.add_amplitude(argument.get_call_key(), call_function)
964
972 """The class for writing Helas calls in C++, starting from
973 HelasWavefunctions and HelasAmplitudes.
974
975 Includes the function generate_helas_call, which automatically
976 generates the C++ Helas call based on the Lorentz structure of
977 the interaction."""
978
980 """Routine for automatic generation of C++ Helas calls
981 according to just the spin structure of the interaction.
982
983 First the call string is generated, using a dictionary to go
984 from the spin state of the calling wavefunction and its
985 mothers, or the mothers of the amplitude, to difenrentiate wich call is
986 done.
987
988 Then the call function is generated, as a lambda which fills
989 the call string with the information of the calling
990 wavefunction or amplitude. The call has different structure,
991 depending on the spin of the wavefunction and the number of
992 mothers (multiplicity of the vertex). The mother
993 wavefunctions, when entering the call, must be sorted in the
994 correct way - this is done by the sorted_mothers routine.
995
996 Finally the call function is stored in the relevant
997 dictionary, in order to be able to reuse the function the next
998 time a wavefunction with the same Lorentz structure is needed.
999 """
1000
1001 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1002 not isinstance(argument, helas_objects.HelasAmplitude):
1003 raise self.PhysicsObjectError, \
1004 "get_helas_call must be called with wavefunction or amplitude"
1005
1006 call = ""
1007
1008 call_function = None
1009
1010 if isinstance(argument, helas_objects.HelasAmplitude) and \
1011 argument.get('interaction_id') == 0:
1012 call = "#"
1013 call_function = lambda amp: call
1014 self.add_amplitude(argument.get_call_key(), call_function)
1015 return
1016
1017 if isinstance(argument, helas_objects.HelasWavefunction) and \
1018 not argument.get('mothers'):
1019
1020 call = call + HelasCallWriter.mother_dict[\
1021 argument.get_spin_state_number()].lower()
1022
1023 call = call + 'x' * (6 - len(call))
1024
1025 call = call + "(p[perm[%d]],"
1026 if argument.get('spin') != 1:
1027
1028 call = call + "mME[%d],hel[%d],"
1029 call = call + "%+d,w[%d]);"
1030 if argument.get('spin') == 1:
1031 call_function = lambda wf: call % \
1032 (wf.get('number_external')-1,
1033
1034 (-1) ** (wf.get('state') == 'initial'),
1035 wf.get('number')-1)
1036 elif argument.is_boson():
1037 call_function = lambda wf: call % \
1038 (wf.get('number_external')-1,
1039 wf.get('number_external')-1,
1040 wf.get('number_external')-1,
1041
1042 (-1) ** (wf.get('state') == 'initial'),
1043 wf.get('number')-1)
1044 else:
1045 call_function = lambda wf: call % \
1046 (wf.get('number_external')-1,
1047 wf.get('number_external')-1,
1048 wf.get('number_external')-1,
1049
1050 - (-1) ** wf.get_with_flow('is_part'),
1051 wf.get('number')-1)
1052 else:
1053
1054
1055 if isinstance(argument, helas_objects.HelasWavefunction):
1056 outgoing = argument.find_outgoing_number()
1057 else:
1058 outgoing = 0
1059
1060
1061 l = [str(l) for l in argument.get('lorentz')]
1062 flag = ['C%d' % i for i in argument.get('conjugate_indices')]
1063 routine_name = aloha_writers.combine_name(
1064 '%s' % l[0], l[1:], outgoing, flag)
1065 call = '%s' % (routine_name)
1066
1067
1068 call = call + '('
1069
1070 call = call + "w[%d]," * len(argument.get('mothers'))
1071
1072 call = call + "%s,"
1073
1074 if isinstance(argument, helas_objects.HelasWavefunction):
1075
1076 call = call + "pars->%s, pars->%s, w[%d]);"
1077
1078 call_function = lambda wf: call % \
1079 (tuple([mother.get('number')-1 for mother in wf.get('mothers')]) + \
1080 (','.join(CPPUFOHelasCallWriter.format_coupling(\
1081 wf.get_with_flow('coupling'))),
1082 wf.get('mass'),
1083 wf.get('width'),
1084 wf.get('number')-1))
1085 else:
1086
1087 call += "amp[%d]);"
1088 call_function = lambda amp: call % \
1089 (tuple([mother.get('number')-1
1090 for mother in amp.get('mothers')]) + \
1091 (','.join(CPPUFOHelasCallWriter.format_coupling(\
1092 amp.get('coupling'))),
1093 amp.get('number')-1))
1094
1095
1096 if isinstance(argument, helas_objects.HelasWavefunction):
1097 self.add_wavefunction(argument.get_call_key(), call_function)
1098 else:
1099 self.add_amplitude(argument.get_call_key(), call_function)
1100
1101 @staticmethod
1113
1119 """The class for writing Helas calls in Python, starting from
1120 HelasWavefunctions and HelasAmplitudes.
1121
1122 Includes the function generate_helas_call, which automatically
1123 generates the Python Helas call based on the Lorentz structure of
1124 the interaction."""
1125
1127 """Return a list of strings, corresponding to the Helas calls
1128 for the matrix element"""
1129
1130 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \
1131 "%s not valid argument for get_matrix_element_calls" % \
1132 repr(matrix_element)
1133
1134 res = []
1135 for diagram in matrix_element.get('diagrams'):
1136 wfs = diagram.get('wavefunctions')
1137 if gauge_check and diagram.get('number') == 1:
1138 gauge_check_wfs = [wf for wf in wfs if not wf.get('mothers') \
1139 and wf.get('spin') == 3 \
1140 and wf.get('mass').lower() == 'zero']
1141 if not gauge_check_wfs:
1142 raise HelasWriterError, \
1143 'no massless spin one particle for gauge check'
1144 gauge_check_wf = wfs.pop(wfs.index(gauge_check_wfs[0]))
1145 res.append(self.generate_helas_call(gauge_check_wf, True)(\
1146 gauge_check_wf))
1147 res.extend([ self.get_wavefunction_call(wf) for wf in wfs ])
1148 res.append("# Amplitude(s) for diagram number %d" % \
1149 diagram.get('number'))
1150 for amplitude in diagram.get('amplitudes'):
1151 res.append(self.get_amplitude_call(amplitude))
1152
1153 return res
1154
1155
1156
1158 """Routine for automatic generation of Python Helas calls
1159 according to just the spin structure of the interaction.
1160 """
1161
1162 if not isinstance(argument, helas_objects.HelasWavefunction) and \
1163 not isinstance(argument, helas_objects.HelasAmplitude):
1164 raise self.PhysicsObjectError, \
1165 "get_helas_call must be called with wavefunction or amplitude"
1166
1167 call_function = None
1168
1169 if isinstance(argument, helas_objects.HelasAmplitude) and \
1170 argument.get('interaction_id') == 0:
1171 call = "#"
1172 call_function = lambda amp: call
1173 self.add_amplitude(argument.get_call_key(), call_function)
1174 return
1175
1176 if isinstance(argument, helas_objects.HelasWavefunction) and \
1177 not argument.get('mothers'):
1178
1179 call = "w[%d] = "
1180
1181 call = call + HelasCallWriter.mother_dict[\
1182 argument.get_spin_state_number()].lower()
1183
1184 call = call + 'x' * (14 - len(call))
1185 call = call + "(p[%d],"
1186 if argument.get('spin') != 1:
1187
1188 if gauge_check and argument.get('spin') == 3 and \
1189 argument.get('mass') == 'ZERO':
1190 call = call + "%s, 4,"
1191 else:
1192 call = call + "%s,hel[%d],"
1193 call = call + "%+d)"
1194 if argument.get('spin') == 1:
1195 call_function = lambda wf: call % \
1196 (wf.get('number')-1,
1197 wf.get('number_external')-1,
1198
1199 (-1)**(wf.get('state') == 'initial'))
1200 elif argument.is_boson():
1201 if not gauge_check or argument.get('mass') != 'ZERO':
1202 call_function = lambda wf: call % \
1203 (wf.get('number')-1,
1204 wf.get('number_external')-1,
1205 wf.get('mass'),
1206 wf.get('number_external')-1,
1207
1208 (-1)**(wf.get('state') == 'initial'))
1209 else:
1210 call_function = lambda wf: call % \
1211 (wf.get('number')-1,
1212 wf.get('number_external')-1,
1213 'ZERO',
1214
1215 (-1)**(wf.get('state') == 'initial'))
1216 else:
1217 call_function = lambda wf: call % \
1218 (wf.get('number')-1,
1219 wf.get('number_external')-1,
1220 wf.get('mass'),
1221 wf.get('number_external')-1,
1222
1223 -(-1)**wf.get_with_flow('is_part'))
1224 else:
1225
1226
1227 if isinstance(argument, helas_objects.HelasWavefunction):
1228 outgoing = argument.find_outgoing_number()
1229 else:
1230 outgoing = 0
1231
1232
1233 l = [str(l) for l in argument.get('lorentz')]
1234 flag = ['C%d' % i for i in argument.get('conjugate_indices')]
1235 routine_name = aloha_writers.combine_name(
1236 '%s' % l[0], l[1:], outgoing, flag)
1237
1238
1239 if isinstance(argument, helas_objects.HelasWavefunction):
1240 call = 'w[%d] = '
1241 else:
1242 call = 'amp[%d] = '
1243 call += '%s' % routine_name
1244
1245
1246 call = call + '('
1247
1248 call = call + "w[%d]," * len(argument.get('mothers'))
1249
1250 call = call + "%s"
1251
1252 if isinstance(argument, helas_objects.HelasWavefunction):
1253
1254 call = call + ",%s, %s)"
1255
1256 call_function = lambda wf: call % \
1257 ((wf.get('number')-1,) + \
1258 tuple([mother.get('number')-1 for mother in \
1259 wf.get('mothers')]) + \
1260 (','.join(wf.get_with_flow('coupling')),
1261 wf.get('mass'),
1262 wf.get('width')))
1263 else:
1264 call = call + ")"
1265
1266 call_function = lambda amp: call % \
1267 ((amp.get('number')-1,) + \
1268 tuple([mother.get('number')-1
1269 for mother in amp.get('mothers')]) + \
1270 (','.join(amp.get('coupling')),))
1271
1272
1273 if isinstance(argument, helas_objects.HelasWavefunction):
1274 if not gauge_check:
1275 self.add_wavefunction(argument.get_call_key(), call_function)
1276 else:
1277 self.add_amplitude(argument.get_call_key(), call_function)
1278
1279 return call_function
1280