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