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.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  # Logger for process_checks 
 62  #=============================================================================== 
 63   
 64  logger = logging.getLogger('madgraph.various.diagram_symmetry') 
65 66 #=============================================================================== 67 # find_symmetry 68 #=============================================================================== 69 70 -def find_symmetry(matrix_element):
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 # diagram_numbers is a list of all relevant diagram numbers 88 diagram_numbers = [] 89 # Prepare the symmetry vector with non-used amp2s (due to 90 # multiparticle vertices) 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 # For loop induced processes we consider only the loops (no R2) and 99 # the shrunk diagram instead of the lcut one. 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 # Ignore any diagrams with 4-particle vertices 121 symmetry.append(0) 122 else: 123 symmetry.append(1) 124 125 # Check for matrix elements with no identical particles 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 # diagram_tags is a list of unique tags 136 diagram_tags = [] 137 # diagram_classes is a list of lists of diagram numbers belonging 138 # to the different classes 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 # Only 3-vertices allowed in configs.inc 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 # Order permutations according to how to reach the first perm 169 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2], 170 perms[idx1][0]) 171 # ident_perms ordered according to order of external momenta 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
179 -def find_symmetry_by_evaluation(matrix_element, evaluator, max_time = 600):
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 #if isinstance(matrix_element, group_subprocs.SubProcessGroup): 191 # return find_symmetry_subproc_group(matrix_element, evaluator, max_time) 192 193 assert isinstance(matrix_element, helas_objects.HelasMatrixElement) 194 195 # Exception class and routine to handle timeout 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 # Prepare the symmetry vector with non-used amp2s (due to 206 # multiparticle vertices) 207 symmetry = [] 208 for diag in matrix_element.get('diagrams'): 209 # It used to be hardcoded to three instead of min_vert. Need to check 210 # if it is ok to use the general min_vert instead. 211 if diag.get_vertex_leg_numbers()!=[] and \ 212 max(diag.get_vertex_leg_numbers()) > min_vert: 213 # Ignore any diagrams with 4-particle vertices 214 symmetry.append(0) 215 else: 216 symmetry.append(1) 217 218 # Check for matrix elements with no identical particles 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 # Get phase space point 238 p, w_rambo = evaluator.get_momenta(equivalent_process) 239 240 # Check matrix element value for all permutations 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 # Set timeout for max_time 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 # Non-identical particles permutated 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 # Make a list with (8-pos value, magnitude) to easily compare 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 # This is the first iteration - initialize lists 278 # Initiate symmetry with all 1:s 279 symmetry = [1 for i in range(len(amp2))] 280 # Store initial amplitudes 281 amp2start = amp2 282 # Initialize list of permutations 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 # If amp2 is 0, just set symmetry to 0 289 symmetry[i] = 0 290 continue 291 # Only compare with diagrams below this one 292 if val in amp2start[:i]: 293 ind = amp2start.index(val) 294 # Replace if 1) this amp is unmatched (symmetry[i] > 0) or 295 # 2) this amp is matched but matched to an amp larger 296 # than ind 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 # Symmetry canceled due to time limit 305 logger.warning("Cancel diagram symmetry - time exceeded") 306 307 # Stop the alarm since we're done with this process 308 signal.alarm(0) 309 310 return (symmetry, perms, ident_perms) 311
312 #=============================================================================== 313 # DiagramTag class to identify matrix elements 314 #=============================================================================== 315 316 -class IdentifySGConfigTag(diagram_generation.DiagramTag):
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 344 345 @staticmethod
346 - def vertex_id_from_vertex(vertex, last_vertex, model, ninitial):
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
359 -def find_symmetry_subproc_group(subproc_group):
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 # diagram_numbers is a list of all relevant diagram numbers 367 diagram_numbers = [] 368 # Prepare the symmetry vector with non-used amp2s (due to 369 # multiparticle vertices) 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 # Ignore any diagrams with 4-particle vertices 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 # diagram_tags is a list of unique tags 395 diagram_tags = [] 396 # diagram_classes is a list of lists of diagram numbers belonging 397 # to the different classes 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 # Only include vertices up to min_vert 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 # Note that for subproc groups, we want symfact to be 1 422 if idx2 > 0: 423 symmetry[inum] = -diagram_classes[idx1][0] 424 # Order permutations according to how to reach the first perm 425 permutations[inum] = diagram_generation.DiagramTag.reorder_permutation(perms[idx1][idx2], 426 perms[idx1][0]) 427 return (symmetry, permutations, [permutations[0]])
428
429 430 -def old_find_symmetry_subproc_group(subproc_group):
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 # Go through symmetries and remove those for any diagrams 456 # where this ME is not supposed to contribute 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 # Now update the maps all_symmetry and all_perms 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 # Fill up all_symmetry and all_perms also for configs that have no symmetry 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 # Since we don't want to multiply by symmetry factor here, set to 1 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
496 497 -def find_matrix_elements_for_configs(subproc_group):
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 # Find the MEs with maximum ident factor corresponding to each config. 508 # Only include MEs with identical particles (otherwise no contribution) 509 for iconf, diagram_list in \ 510 enumerate(subproc_group.get('diagrams_for_configs')): 511 # Check if any diagrams contribute to config 512 if set(diagram_list) == set([0]): 513 continue 514 # Add list of MEs with maximum ident factor contributing to this config 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 # Make set of the configs 524 for me in me_config_dict: 525 me_config_dict[me] = sorted(set(me_config_dict[me])) 526 527 # Sort MEs according to 1) ident factor, 2) number of configs they 528 # contribute to 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 # Reduce to minimal set of matrix elements 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 # Re-sort MEs 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