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 return ((part.get('color'),
365 part.get('mass'), part.get('width'), QCD),)
366
368 """Find symmetric configs by directly comparing the configurations
369 using IdentifySGConfigTag."""
370
371 assert isinstance(subproc_group, group_subprocs.SubProcessGroup),\
372 "Argument to find_symmetry_subproc_group has to be SubProcessGroup"
373
374
375 diagram_numbers = []
376
377
378 symmetry = []
379 permutations = []
380 diagrams = subproc_group.get('mapping_diagrams')
381 nexternal, ninitial = \
382 subproc_group.get('matrix_elements')[0].get_nexternal_ninitial()
383 model = subproc_group.get('matrix_elements')[0].get('processes')[0].\
384 get('model')
385 vert_list = [max(diag.get_vertex_leg_numbers()) for diag in diagrams if \
386 diag.get_vertex_leg_numbers()!=[]]
387 min_vert = min(vert_list) if vert_list!=[] else 0
388
389 for idiag,diag in enumerate(diagrams):
390 diagram_numbers.append(idiag+1)
391 permutations.append(list(range(nexternal)))
392 if diag.get_vertex_leg_numbers()!=[] and \
393 max(diag.get_vertex_leg_numbers()) > min_vert:
394
395 symmetry.append(0)
396 else:
397 symmetry.append(1)
398
399 logger.info("Finding symmetric diagrams for subprocess group %s" % \
400 subproc_group.get('name'))
401
402
403 diagram_tags = []
404
405
406 diagram_classes = []
407 perms = []
408 for idiag, diag in enumerate(diagrams):
409 if diag.get_vertex_leg_numbers()!=[] and \
410 max(diag.get_vertex_leg_numbers()) > min_vert:
411
412 continue
413 tag = IdentifySGConfigTag(diag, model)
414 try:
415 ind = diagram_tags.index(tag)
416 except ValueError:
417 diagram_classes.append([idiag + 1])
418 perms.append([tag.get_external_numbers()])
419 diagram_tags.append(tag)
420 else:
421 diagram_classes[ind].append(idiag + 1)
422 perms[ind].append(tag.get_external_numbers())
423 for inum, diag_number in enumerate(diagram_numbers):
424 if symmetry[inum] == 0:
425 continue
426 idx1 = [i for i, d in enumerate(diagram_classes) if \
427 diag_number in d][0]
428 idx2 = diagram_classes[idx1].index(diag_number)
429
430 if idx2 > 0:
431 symmetry[inum] = -diagram_classes[idx1][0]
432
433 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2],
434 perms[idx1][0])
435 return (symmetry, permutations, [permutations[0]])
436
439 """Find symmetries between the configs in the subprocess group.
440 For each config, find all matrix elements with maximum identical
441 particle factor. Then take minimal set of these matrix elements,
442 and determine symmetries based on these."""
443
444 assert isinstance(subproc_group, group_subprocs.SubProcessGroup),\
445 "Argument to find_symmetry_subproc_group has to be SubProcessGroup"
446
447 matrix_elements = subproc_group.get('matrix_elements')
448
449 contributing_mes, me_config_dict = \
450 find_matrix_elements_for_configs(subproc_group)
451
452 nexternal, ninitial = matrix_elements[0].get_nexternal_ninitial()
453
454 all_symmetry = {}
455 all_perms = {}
456
457 for me_number in contributing_mes:
458 diagram_config_map = dict([(i,n) for i,n in \
459 enumerate(subproc_group.get('diagram_maps')[me_number]) \
460 if n > 0])
461 symmetry, perms, ident_perms = find_symmetry(matrix_elements[me_number])
462
463
464
465 for isym, sym_config in enumerate(symmetry):
466 if sym_config == 0 or isym not in diagram_config_map:
467 continue
468 config = diagram_config_map[isym]
469 if config not in me_config_dict[me_number] or \
470 sym_config < 0 and diagram_config_map[-sym_config-1] not in \
471 me_config_dict[me_number]:
472 symmetry[isym] = 1
473 perms[isym]=list(range(nexternal))
474 if sym_config < 0 and diagram_config_map[-sym_config-1] in \
475 me_config_dict[me_number]:
476 symmetry[-sym_config-1] -= 1
477
478
479 for isym, (perm, sym_config) in enumerate(zip(perms, symmetry)):
480 if sym_config in [0,1] or isym not in diagram_config_map:
481 continue
482 config = diagram_config_map[isym]
483
484 all_perms[config] = perm
485
486 if sym_config > 0:
487 all_symmetry[config] = sym_config
488 else:
489 all_symmetry[config] = -diagram_config_map[-sym_config-1]
490
491
492 for iconf in range(len(subproc_group.get('mapping_diagrams'))):
493 all_symmetry.setdefault(iconf+1, 1)
494 all_perms.setdefault(iconf+1, list(range(nexternal)))
495
496 if all_symmetry[iconf+1] > 1:
497 all_symmetry[iconf+1] = 1
498
499 symmetry = [all_symmetry[key] for key in sorted(all_symmetry.keys())]
500 perms = [all_perms[key] for key in sorted(all_perms.keys())]
501
502 return symmetry, perms, [perms[0]]
503
506 """For each config, find all matrix elements with maximum identical
507 particle factor. Then take minimal set of these matrix elements."""
508
509 matrix_elements = subproc_group.get('matrix_elements')
510
511 n_mes = len(matrix_elements)
512
513 me_config_dict = {}
514
515
516
517 for iconf, diagram_list in \
518 enumerate(subproc_group.get('diagrams_for_configs')):
519
520 if set(diagram_list) == set([0]):
521 continue
522
523 max_ident = max([matrix_elements[i].get('identical_particle_factor') \
524 for i in range(n_mes) if diagram_list[i] > 0])
525 max_mes = [i for i in range(n_mes) if \
526 matrix_elements[i].get('identical_particle_factor') == \
527 max_ident and diagram_list[i] > 0 and max_ident > 1]
528 for me in max_mes:
529 me_config_dict.setdefault(me, [iconf+1]).append(iconf + 1)
530
531
532 for me in me_config_dict:
533 me_config_dict[me] = sorted(set(me_config_dict[me]))
534
535
536
537 def me_sort(me1, me2):
538 return (matrix_elements[me2].get('identical_particle_factor') \
539 - matrix_elements[me1].get('identical_particle_factor'))\
540 or (len(me_config_dict[me2]) - len(me_config_dict[me1]))
541
542 sorted_mes = sorted([me for me in me_config_dict], key=misc.cmp_to_key(me_sort))
543
544
545 latest_me = 0
546 checked_configs = []
547 while latest_me < len(sorted_mes):
548 checked_configs.extend(me_config_dict[sorted_mes[latest_me]])
549 for me in sorted_mes[latest_me+1:]:
550 me_config_dict[me] = [conf for conf in me_config_dict[me] if \
551 conf not in checked_configs]
552 if me_config_dict[me] == []:
553 del me_config_dict[me]
554
555 sorted_mes = sorted([me for me in me_config_dict], me_sort)
556 latest_me += 1
557
558 return sorted_mes, me_config_dict
559