1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Module for calculation of symmetries between diagrams, by
17 evaluating amp2 values for permutations of momenta."""
18
19 from __future__ import division
20
21 from __future__ import absolute_import
22 import array
23 import copy
24 import fractions
25 import itertools
26 import logging
27 import math
28 import os
29 import re
30 import signal
31
32 import aloha.aloha_writers as aloha_writers
33 import aloha.create_aloha as create_aloha
34
35 import madgraph.iolibs.export_python as export_python
36 import madgraph.iolibs.group_subprocs as group_subprocs
37 import madgraph.iolibs.helas_call_writers as helas_call_writer
38 import models.import_ufo as import_ufo
39 import madgraph.iolibs.save_load_object as save_load_object
40
41 import madgraph.core.base_objects as base_objects
42 import madgraph.loop.loop_base_objects as loop_base_objects
43 import madgraph.core.helas_objects as helas_objects
44 import madgraph.loop.loop_helas_objects as loop_helas_objects
45
46 import madgraph.core.color_algebra as color
47 import madgraph.core.color_amp as color_amp
48 import madgraph.core.helas_objects as helas_objects
49 import madgraph.core.diagram_generation as diagram_generation
50
51 import madgraph.various.process_checks as process_checks
52 import madgraph.various.misc as misc
53
54 from madgraph import MG5DIR
55
56 import models.model_reader as model_reader
57 import aloha.template_files.wavefunctions as wavefunctions
58 from aloha.template_files.wavefunctions import \
59 ixxxxx, oxxxxx, vxxxxx, sxxxxx
60 from six.moves import range
61 from six.moves import zip
62
63
64
65
66
67 logger = logging.getLogger('madgraph.various.diagram_symmetry')
74 """Find symmetries between amplitudes by comparing diagram tags
75 for all the diagrams in the process. Identical diagram tags
76 correspond to different external particle permutations of the same
77 diagram.
78
79 Return list of positive number corresponding to number of
80 symmetric diagrams and negative numbers corresponding to the
81 equivalent diagram (for e+e->3a, get [6, -1, -1, -1, -1, -1]),
82 list of the corresponding permutations needed, and list of all
83 permutations of identical particles."""
84
85 if isinstance(matrix_element, group_subprocs.SubProcessGroup):
86 return find_symmetry_subproc_group(matrix_element)
87
88 nexternal, ninitial = matrix_element.get_nexternal_ninitial()
89
90
91 diagram_numbers = []
92
93
94 symmetry = []
95 permutations = []
96 ident_perms = []
97 process = matrix_element.get('processes')[0]
98 base_model = process.get('model')
99
100 if isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement):
101
102
103 FDStructRepo = loop_base_objects.FDStructureList([])
104 base_diagrams = base_objects.DiagramList(
105 [(d.get_contracted_loop_diagram(base_model,FDStructRepo) if
106 isinstance(d,loop_base_objects.LoopDiagram) else d) for d in
107 matrix_element.get('base_amplitude').get('loop_diagrams') \
108 if d.get('type')>0])
109 diagrams = matrix_element.get_loop_diagrams()
110 else:
111 diagrams = matrix_element.get('diagrams')
112 base_diagrams = matrix_element.get_base_amplitude().get('diagrams')
113
114 vert_list = [max(diag.get_vertex_leg_numbers()) for diag in diagrams if \
115 diag.get_vertex_leg_numbers()!=[]]
116 min_vert = min(vert_list) if vert_list!=[] else 0
117
118 for diag in diagrams:
119 diagram_numbers.append(diag.get('number'))
120 permutations.append(list(range(nexternal)))
121 if diag.get_vertex_leg_numbers()!=[] and \
122 max(diag.get_vertex_leg_numbers()) > min_vert:
123
124 symmetry.append(0)
125 else:
126 symmetry.append(1)
127
128
129 if matrix_element.get("identical_particle_factor") == 1:
130 return symmetry, \
131 permutations,\
132 [list(range(nexternal))]
133
134 logger.info("Finding symmetric diagrams for process %s" % \
135 matrix_element.get('processes')[0].nice_string().\
136 replace("Process: ", ""))
137
138
139 diagram_tags = []
140
141
142 diagram_classes = []
143 perms = []
144 for diag, base_diagram in zip(diagrams, base_diagrams):
145 if any([vert > min_vert for vert in
146 diag.get_vertex_leg_numbers()]):
147
148 continue
149
150 tag = diagram_generation.DiagramTag(base_diagram)
151 try:
152 ind = diagram_tags.index(tag)
153 except ValueError:
154 diagram_classes.append([diag.get('number')])
155 perms.append([tag.get_external_numbers()])
156 diagram_tags.append(tag)
157 else:
158 diagram_classes[ind].append(diag.get('number'))
159 perms[ind].append(tag.get_external_numbers())
160
161 for inum, diag_number in enumerate(diagram_numbers):
162 if symmetry[inum] == 0:
163 continue
164 idx1 = [i for i, d in enumerate(diagram_classes) if \
165 diag_number in d][0]
166 idx2 = diagram_classes[idx1].index(diag_number)
167 if idx2 == 0:
168 symmetry[inum] = len(diagram_classes[idx1])
169 else:
170 symmetry[inum] = -diagram_classes[idx1][0]
171
172 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2],
173 perms[idx1][0])
174
175 perm = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][0],
176 perms[idx1][idx2])
177 if not perm in ident_perms:
178 ident_perms.append(perm)
179
180 return (symmetry, permutations, ident_perms)
181
183 """Find symmetries between amplitudes by comparing the squared
184 amplitudes for all permutations of identical particles.
185
186 Return list of positive number corresponding to number of
187 symmetric diagrams and negative numbers corresponding to the
188 equivalent diagram (for e+e->3a, get [6, -1, -1, -1, -1, -1]),
189 list of the corresponding permutations needed, and list of all
190 permutations of identical particles.
191 max_time gives a cutoff time for finding symmetries (in s)."""
192
193
194
195
196 assert isinstance(matrix_element, helas_objects.HelasMatrixElement)
197
198
199 class TimeOutError(Exception):
200 pass
201 def handle_alarm(signum, frame):
202 raise TimeOutError
203
204 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
205 vert_list = [max(diag.get_vertex_leg_numbers()) for diag in \
206 matrix_element.get('diagrams') if diag.get_vertex_leg_numbers()!=[]]
207 min_vert = min(vert_list) if vert_list!=[] else 0
208
209
210 symmetry = []
211 for diag in matrix_element.get('diagrams'):
212
213
214 if diag.get_vertex_leg_numbers()!=[] and \
215 max(diag.get_vertex_leg_numbers()) > min_vert:
216
217 symmetry.append(0)
218 else:
219 symmetry.append(1)
220
221
222 if matrix_element.get("identical_particle_factor") == 1:
223 return symmetry, \
224 [list(range(nexternal))]*len(symmetry),\
225 [list(range(nexternal))]
226
227 logger.info("Finding symmetric diagrams for process %s" % \
228 matrix_element.get('processes')[0].nice_string().\
229 replace("Process: ", ""))
230
231 process = matrix_element.get('processes')[0]
232 base_model = process.get('model')
233 equivalent_process = base_objects.Process({\
234 'legs': base_objects.LegList([base_objects.Leg({
235 'id': wf.get('pdg_code'),
236 'state': wf.get('leg_state')}) \
237 for wf in matrix_element.get_external_wavefunctions()]),
238 'model': base_model})
239
240
241 p, w_rambo = evaluator.get_momenta(equivalent_process)
242
243
244 amp2start = []
245 final_states = [l.get('id') for l in \
246 equivalent_process.get('legs')[ninitial:]]
247 nperm = 0
248 perms = []
249 ident_perms = []
250
251
252 signal.signal(signal.SIGALRM, handle_alarm)
253 signal.alarm(max_time)
254 try:
255 for perm in itertools.permutations(list(range(ninitial, nexternal))):
256 if [equivalent_process.get('legs')[i].get('id') for i in perm] != \
257 final_states:
258
259 continue
260 ident_perms.append([0,1]+list(perm))
261 nperm += 1
262 new_p = p[:ninitial] + [p[i] for i in perm]
263
264 res = evaluator.evaluate_matrix_element(matrix_element, new_p)
265 if not res:
266 break
267 me_value, amp2 = res
268
269 amp2sum = sum(amp2)
270 amp2mag = []
271 for a in amp2:
272 a = a*me_value/max(amp2sum, 1e-30)
273 if a > 0:
274 amp2mag.append(int(math.floor(math.log10(abs(a)))))
275 else:
276 amp2mag.append(0)
277 amp2 = [(int(a*10**(8-am)), am) for (a, am) in zip(amp2, amp2mag)]
278
279 if not perms:
280
281
282 symmetry = [1 for i in range(len(amp2))]
283
284 amp2start = amp2
285
286 perms = [list(range(nexternal)) for i in range(len(amp2))]
287 continue
288
289 for i, val in enumerate(amp2):
290 if val == (0,0):
291
292 symmetry[i] = 0
293 continue
294
295 if val in amp2start[:i]:
296 ind = amp2start.index(val)
297
298
299
300 if symmetry[ind] > 0 and \
301 (symmetry[i] > 0 or \
302 symmetry[i] < 0 and -symmetry[i] > ind + 1):
303 symmetry[i] = -(ind+1)
304 perms[i] = [0, 1] + list(perm)
305 symmetry[ind] += 1
306 except TimeOutError:
307
308 logger.warning("Cancel diagram symmetry - time exceeded")
309
310
311 signal.alarm(0)
312
313 return (symmetry, perms, ident_perms)
314
320 """DiagramTag daughter class to identify diagrams giving the same
321 config. Need to compare state, spin, mass, width, and color.
322 Warning: If changing this tag, then also CanonicalConfigTag in
323 helas_objects.py must be changed!
324 """
325
326 @staticmethod
328 """Returns the end link for a leg needed to identify symmetric
329 configs: ((leg number for initial state, spin, mass,
330 width, color), number)."""
331
332 part = model.get_particle(leg.get('id'))
333
334 state = 0
335 if not leg.get('state'):
336
337 state = leg.get('number')
338
339 if part.get('color') != 1:
340 charge = 0
341 else:
342 charge = abs(part.get('charge'))
343
344 return [((state, part.get('spin'), part.get('color'), charge,
345 part.get('mass'), part.get('width')),
346 leg.get('number'))]
347
348 @staticmethod
350 """Returns the info needed to identify symmetric configs:
351 interaction color, mass, width."""
352
353 inter = model.get_interaction(vertex.get('id'))
354
355 if last_vertex:
356 return (0,)
357 else:
358 part = model.get_particle(vertex.get('legs')[-1].get('id'))
359 try:
360 QCD = inter.get('orders')['QCD']
361 except Exception:
362 QCD = 0
363
364 onshell = vertex.get('legs')[-1].get('onshell')
365 if onshell is True:
366 onshell = 1
367 elif onshell is False:
368 onshell = 0
369 else:
370 onshell = -1
371
372
373
374 return ((part.get('color'),
375 part.get('mass'), part.get('width'), QCD, onshell),)
376
378 """Find symmetric configs by directly comparing the configurations
379 using IdentifySGConfigTag."""
380
381 assert isinstance(subproc_group, group_subprocs.SubProcessGroup),\
382 "Argument to find_symmetry_subproc_group has to be SubProcessGroup"
383
384
385 diagram_numbers = []
386
387
388 symmetry = []
389 permutations = []
390 diagrams = subproc_group.get('mapping_diagrams')
391 nexternal, ninitial = \
392 subproc_group.get('matrix_elements')[0].get_nexternal_ninitial()
393 model = subproc_group.get('matrix_elements')[0].get('processes')[0].\
394 get('model')
395 vert_list = [max(diag.get_vertex_leg_numbers()) for diag in diagrams if \
396 diag.get_vertex_leg_numbers()!=[]]
397 min_vert = min(vert_list) if vert_list!=[] else 0
398
399 for idiag,diag in enumerate(diagrams):
400 diagram_numbers.append(idiag+1)
401 permutations.append(list(range(nexternal)))
402 if diag.get_vertex_leg_numbers()!=[] and \
403 max(diag.get_vertex_leg_numbers()) > min_vert:
404
405 symmetry.append(0)
406 else:
407 symmetry.append(1)
408
409 logger.info("Finding symmetric diagrams for subprocess group %s" % \
410 subproc_group.get('name'))
411
412
413 diagram_tags = []
414
415
416 diagram_classes = []
417 perms = []
418 for idiag, diag in enumerate(diagrams):
419 if diag.get_vertex_leg_numbers()!=[] and \
420 max(diag.get_vertex_leg_numbers()) > min_vert:
421
422 continue
423 tag = IdentifySGConfigTag(diag, model)
424 try:
425 ind = diagram_tags.index(tag)
426 except ValueError:
427 diagram_classes.append([idiag + 1])
428 perms.append([tag.get_external_numbers()])
429 diagram_tags.append(tag)
430 else:
431 diagram_classes[ind].append(idiag + 1)
432 perms[ind].append(tag.get_external_numbers())
433 for inum, diag_number in enumerate(diagram_numbers):
434 if symmetry[inum] == 0:
435 continue
436 idx1 = [i for i, d in enumerate(diagram_classes) if \
437 diag_number in d][0]
438 idx2 = diagram_classes[idx1].index(diag_number)
439
440 if idx2 > 0:
441 symmetry[inum] = -diagram_classes[idx1][0]
442
443 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2],
444 perms[idx1][0])
445 return (symmetry, permutations, [permutations[0]])
446
449 """Find symmetries between the configs in the subprocess group.
450 For each config, find all matrix elements with maximum identical
451 particle factor. Then take minimal set of these matrix elements,
452 and determine symmetries based on these."""
453
454 assert isinstance(subproc_group, group_subprocs.SubProcessGroup),\
455 "Argument to find_symmetry_subproc_group has to be SubProcessGroup"
456
457 matrix_elements = subproc_group.get('matrix_elements')
458
459 contributing_mes, me_config_dict = \
460 find_matrix_elements_for_configs(subproc_group)
461
462 nexternal, ninitial = matrix_elements[0].get_nexternal_ninitial()
463
464 all_symmetry = {}
465 all_perms = {}
466
467 for me_number in contributing_mes:
468 diagram_config_map = dict([(i,n) for i,n in \
469 enumerate(subproc_group.get('diagram_maps')[me_number]) \
470 if n > 0])
471 symmetry, perms, ident_perms = find_symmetry(matrix_elements[me_number])
472
473
474
475 for isym, sym_config in enumerate(symmetry):
476 if sym_config == 0 or isym not in diagram_config_map:
477 continue
478 config = diagram_config_map[isym]
479 if config not in me_config_dict[me_number] or \
480 sym_config < 0 and diagram_config_map[-sym_config-1] not in \
481 me_config_dict[me_number]:
482 symmetry[isym] = 1
483 perms[isym]=list(range(nexternal))
484 if sym_config < 0 and diagram_config_map[-sym_config-1] in \
485 me_config_dict[me_number]:
486 symmetry[-sym_config-1] -= 1
487
488
489 for isym, (perm, sym_config) in enumerate(zip(perms, symmetry)):
490 if sym_config in [0,1] or isym not in diagram_config_map:
491 continue
492 config = diagram_config_map[isym]
493
494 all_perms[config] = perm
495
496 if sym_config > 0:
497 all_symmetry[config] = sym_config
498 else:
499 all_symmetry[config] = -diagram_config_map[-sym_config-1]
500
501
502 for iconf in range(len(subproc_group.get('mapping_diagrams'))):
503 all_symmetry.setdefault(iconf+1, 1)
504 all_perms.setdefault(iconf+1, list(range(nexternal)))
505
506 if all_symmetry[iconf+1] > 1:
507 all_symmetry[iconf+1] = 1
508
509 symmetry = [all_symmetry[key] for key in sorted(all_symmetry.keys())]
510 perms = [all_perms[key] for key in sorted(all_perms.keys())]
511
512 return symmetry, perms, [perms[0]]
513
516 """For each config, find all matrix elements with maximum identical
517 particle factor. Then take minimal set of these matrix elements."""
518
519 matrix_elements = subproc_group.get('matrix_elements')
520
521 n_mes = len(matrix_elements)
522
523 me_config_dict = {}
524
525
526
527 for iconf, diagram_list in \
528 enumerate(subproc_group.get('diagrams_for_configs')):
529
530 if set(diagram_list) == set([0]):
531 continue
532
533 max_ident = max([matrix_elements[i].get('identical_particle_factor') \
534 for i in range(n_mes) if diagram_list[i] > 0])
535 max_mes = [i for i in range(n_mes) if \
536 matrix_elements[i].get('identical_particle_factor') == \
537 max_ident and diagram_list[i] > 0 and max_ident > 1]
538 for me in max_mes:
539 me_config_dict.setdefault(me, [iconf+1]).append(iconf + 1)
540
541
542 for me in me_config_dict:
543 me_config_dict[me] = sorted(set(me_config_dict[me]))
544
545
546
547 def me_sort(me1, me2):
548 return (matrix_elements[me2].get('identical_particle_factor') \
549 - matrix_elements[me1].get('identical_particle_factor'))\
550 or (len(me_config_dict[me2]) - len(me_config_dict[me1]))
551
552 sorted_mes = sorted([me for me in me_config_dict], key=misc.cmp_to_key(me_sort))
553
554
555 latest_me = 0
556 checked_configs = []
557 while latest_me < len(sorted_mes):
558 checked_configs.extend(me_config_dict[sorted_mes[latest_me]])
559 for me in sorted_mes[latest_me+1:]:
560 me_config_dict[me] = [conf for conf in me_config_dict[me] if \
561 conf not in checked_configs]
562 if me_config_dict[me] == []:
563 del me_config_dict[me]
564
565 sorted_mes = sorted([me for me in me_config_dict], me_sort)
566 latest_me += 1
567
568 return sorted_mes, me_config_dict
569