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