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