Package madgraph :: Package various :: Module diagram_symmetry
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.diagram_symmetry

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2010 The MadGraph5_aMC@NLO Development team and Contributors 
  4  # 
  5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
  6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
  7  # high-energy processes in the Standard Model and beyond. 
  8  # 
  9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
 10  # distribution. 
 11  # 
 12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
 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  # Logger for process_checks 
 58  #=============================================================================== 
 59   
 60  logger = logging.getLogger('madgraph.various.diagram_symmetry') 
61 62 #=============================================================================== 63 # find_symmetry 64 #=============================================================================== 65 66 -def find_symmetry(matrix_element):
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 # diagram_numbers is a list of all relevant diagram numbers 84 diagram_numbers = [] 85 # Prepare the symmetry vector with non-used amp2s (due to 86 # multiparticle vertices) 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 # Ignore any diagrams with 4-particle vertices 100 symmetry.append(0) 101 else: 102 symmetry.append(1) 103 104 # Check for matrix elements with no identical particles 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 # diagram_tags is a list of unique tags 115 diagram_tags = [] 116 # diagram_classes is a list of lists of diagram numbers belonging 117 # to the different classes 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 # Only 3-vertices allowed in configs.inc 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 # Order permutations according to how to reach the first perm 147 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2], 148 perms[idx1][0]) 149 # ident_perms ordered according to order of external momenta 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
157 -def find_symmetry_by_evaluation(matrix_element, evaluator, max_time = 600):
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 #if isinstance(matrix_element, group_subprocs.SubProcessGroup): 169 # return find_symmetry_subproc_group(matrix_element, evaluator, max_time) 170 171 assert isinstance(matrix_element, helas_objects.HelasMatrixElement) 172 173 # Exception class and routine to handle timeout 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 # Prepare the symmetry vector with non-used amp2s (due to 182 # multiparticle vertices) 183 symmetry = [] 184 for diag in matrix_element.get('diagrams'): 185 if max(diag.get_vertex_leg_numbers()) > 3: 186 # Ignore any diagrams with 4-particle vertices 187 symmetry.append(0) 188 else: 189 symmetry.append(1) 190 191 # Check for matrix elements with no identical particles 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 # Get phase space point 211 p, w_rambo = evaluator.get_momenta(equivalent_process) 212 213 # Check matrix element value for all permutations 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 # Set timeout for max_time 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 # Non-identical particles permutated 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 # Make a list with (8-pos value, magnitude) to easily compare 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 # This is the first iteration - initialize lists 251 # Initiate symmetry with all 1:s 252 symmetry = [1 for i in range(len(amp2))] 253 # Store initial amplitudes 254 amp2start = amp2 255 # Initialize list of permutations 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 # If amp2 is 0, just set symmetry to 0 262 symmetry[i] = 0 263 continue 264 # Only compare with diagrams below this one 265 if val in amp2start[:i]: 266 ind = amp2start.index(val) 267 # Replace if 1) this amp is unmatched (symmetry[i] > 0) or 268 # 2) this amp is matched but matched to an amp larger 269 # than ind 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 # Symmetry canceled due to time limit 278 logger.warning("Cancel diagram symmetry - time exceeded") 279 280 # Stop the alarm since we're done with this process 281 signal.alarm(0) 282 283 return (symmetry, perms, ident_perms) 284
285 #=============================================================================== 286 # DiagramTag class to identify matrix elements 287 #=============================================================================== 288 289 -class IdentifySGConfigTag(diagram_generation.DiagramTag):
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 317 318 @staticmethod
319 - def vertex_id_from_vertex(vertex, last_vertex, model, ninitial):
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
332 -def find_symmetry_subproc_group(subproc_group):
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 # diagram_numbers is a list of all relevant diagram numbers 340 diagram_numbers = [] 341 # Prepare the symmetry vector with non-used amp2s (due to 342 # multiparticle vertices) 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 # Ignore any diagrams with 4-particle vertices 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 # diagram_tags is a list of unique tags 365 diagram_tags = [] 366 # diagram_classes is a list of lists of diagram numbers belonging 367 # to the different classes 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 # Only include vertices up to min_vert 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 # Note that for subproc groups, we want symfact to be 1 392 if idx2 > 0: 393 symmetry[inum] = -diagram_classes[idx1][0] 394 # Order permutations according to how to reach the first perm 395 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2], 396 perms[idx1][0]) 397 return (symmetry, permutations, [permutations[0]])
398
399 400 -def old_find_symmetry_subproc_group(subproc_group):
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 # Go through symmetries and remove those for any diagrams 426 # where this ME is not supposed to contribute 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 # Now update the maps all_symmetry and all_perms 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 # Fill up all_symmetry and all_perms also for configs that have no symmetry 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 # Since we don't want to multiply by symmetry factor here, set to 1 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
466 467 -def find_matrix_elements_for_configs(subproc_group):
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 # Find the MEs with maximum ident factor corresponding to each config. 478 # Only include MEs with identical particles (otherwise no contribution) 479 for iconf, diagram_list in \ 480 enumerate(subproc_group.get('diagrams_for_configs')): 481 # Check if any diagrams contribute to config 482 if set(diagram_list) == set([0]): 483 continue 484 # Add list of MEs with maximum ident factor contributing to this config 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 # Make set of the configs 494 for me in me_config_dict: 495 me_config_dict[me] = sorted(set(me_config_dict[me])) 496 497 # Sort MEs according to 1) ident factor, 2) number of configs they 498 # contribute to 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 # Reduce to minimal set of matrix elements 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 # Re-sort MEs 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