Package madgraph :: Package fks :: Module fks_helas_objects
[hide private]
[frames] | no frames]

Source Code for Module madgraph.fks.fks_helas_objects

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2009 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  """Definitions of the Helas objects needed for the implementation of MadFKS  
 17  from born""" 
 18   
 19   
 20  from __future__ import absolute_import 
 21  import madgraph.core.base_objects as MG 
 22  import madgraph.core.helas_objects as helas_objects 
 23  import madgraph.core.diagram_generation as diagram_generation 
 24  import madgraph.core.color_amp as color_amp 
 25  import madgraph.core.color_algebra as color_algebra 
 26  import madgraph.fks.fks_base as fks_base 
 27  import madgraph.fks.fks_common as fks_common 
 28  import madgraph.loop.loop_helas_objects as loop_helas_objects 
 29  import madgraph.loop.loop_diagram_generation as loop_diagram_generation 
 30  from madgraph import InvalidCmd 
 31  import madgraph.various.misc as misc 
 32  import copy 
 33  import logging 
 34  import array 
 35  import multiprocessing 
 36  import signal 
 37  import tempfile 
 38  import six 
 39  import six.moves.cPickle as cPickle 
 40  import itertools 
 41  import os 
 42  import sys 
 43  from six.moves import zip 
 44  from madgraph import MG5DIR 
 45  pjoin = os.path.join 
 46  logger = logging.getLogger('madgraph.fks_helas_objects') 
 47   
 48   
 49  #functions to be used in the ncores_for_proc_gen mode 
50 -def async_generate_real(args):
51 i = args[0] 52 real_amp = args[1] 53 #amplitude generation 54 amplitude = real_amp.generate_real_amplitude() 55 # check that the amplitude has diagrams, otherwise quit here 56 # and return an empty list 57 if not amplitude['diagrams']: 58 msg = "Discarding amplitude with no diagrams%s" % \ 59 (amplitude['process'].nice_string(print_weighted=False).replace('Process ', '')) 60 logger.debug(msg) 61 return [] 62 63 helasreal = helas_objects.HelasMatrixElement(amplitude) 64 logger.info('Generating real %s' % \ 65 real_amp.process.nice_string(print_weighted=False).replace('Process', 'process')) 66 67 # Keep track of already generated color objects, to reuse as 68 # much as possible 69 list_colorize = [] 70 list_color_basis = [] 71 list_color_matrices = [] 72 73 # Now this keeps track of the color matrices created from the loop-born 74 # color basis. Keys are 2-tuple with the index of the loop and born basis 75 # in the list above and the value is the resulting matrix. 76 dict_loopborn_matrices = {} 77 # The dictionary below is simply a container for convenience to be 78 # passed to the function process_color. 79 color_information = { 'list_colorize' : list_colorize, 80 'list_color_basis' : list_color_basis, 81 'list_color_matrices' : list_color_matrices, 82 'dict_loopborn_matrices' : dict_loopborn_matrices} 83 84 helas_objects.HelasMultiProcess.process_color(helasreal,color_information) 85 86 outdata = [amplitude,helasreal] 87 88 output = tempfile.NamedTemporaryFile(delete = False) 89 90 six.moves.cPickle.dump(outdata,output,protocol=2) 91 output.close() 92 93 return [output.name,helasreal.get_num_configs(),helasreal.get_nexternal_ninitial()[0]]
94 95
96 -def async_generate_born(args):
97 i = args[0] 98 born = args[1] 99 born_pdg_list = args[2] 100 loop_orders = args[3] 101 pdg_list = args[4] 102 loop_optimized = args[5] 103 OLP = args[6] 104 realmapout = args[7] 105 106 logger.info('Generating born %s' % \ 107 born.born_amp['process'].nice_string(print_weighted=False).replace('Process', 'process')) 108 #load informations on reals from temp files 109 helasreal_list = [] 110 amp_to_remove = [] 111 for amp in born.real_amps: 112 # if the pdg_list is not there, it has been removed 113 # because there are no diagrams 114 try: 115 idx = pdg_list.index(amp.pdgs) 116 infilename = realmapout[idx] 117 infile = open(infilename,'rb') 118 realdata = cPickle.load(infile) 119 infile.close() 120 amp.amplitude = realdata[0] 121 helasreal_list.append(realdata[1]) 122 123 except ValueError: 124 logger.debug('Removing amplitude: %s' % amp.process.nice_string()) 125 amp_to_remove.append(amp) 126 127 for amp in amp_to_remove: 128 born.real_amps.remove(amp) 129 130 born.link_born_reals() 131 132 for amp in born.real_amps: 133 amp.find_fks_j_from_i(born_pdg_list) 134 135 # generate the virtuals if needed 136 has_loops = False 137 if born.born_amp['process'].get('NLO_mode') == 'all' and OLP == 'MadLoop': 138 myproc = copy.copy(born.born_amp['process']) 139 # take the orders that are actually used by the matrix element 140 ###myproc['orders'] = loop_orders 141 myproc['perturbation_couplings'] = myproc['model']['coupling_orders'] 142 myproc['legs'] = fks_common.to_legs(copy.copy(myproc['legs'])) 143 144 try: 145 myamp = loop_diagram_generation.LoopAmplitude(myproc) 146 has_loops = True 147 born.virt_amp = myamp 148 except InvalidCmd: 149 has_loops = False 150 151 helasfull = FKSHelasProcess(born, helasreal_list, 152 loop_optimized = loop_optimized, 153 decay_ids=[], 154 gen_color=False) 155 156 processes = helasfull.born_me.get('processes') 157 158 max_configs = helasfull.born_me.get_num_configs() 159 160 metag = helas_objects.IdentifyMETag.create_tag(helasfull.born_me.get('base_amplitude')) 161 162 outdata = helasfull 163 164 output = tempfile.NamedTemporaryFile(delete = False) 165 six.moves.cPickle.dump(outdata,output,protocol=2) 166 output.close() 167 168 return [output.name,metag,has_loops,processes,helasfull.born_me.get_num_configs(),helasfull.get_nexternal_ninitial()[0]]
169 170
171 -def async_finalize_matrix_elements(args):
172 173 i = args[0] 174 mefile = args[1] 175 duplist = args[2] 176 177 infile = open(mefile,'rb') 178 me = six.moves.cPickle.load(infile) 179 infile.close() 180 181 #set unique id based on position in unique me list 182 me.get('processes')[0].set('uid', i) 183 184 # Always create an empty color basis, and the 185 # list of raw colorize objects (before 186 # simplification) associated with amplitude 187 col_basis = color_amp.ColorBasis() 188 new_amp = me.born_me.get_base_amplitude() 189 me.born_me.set('base_amplitude', new_amp) 190 colorize_obj = col_basis.create_color_dict_list(new_amp) 191 192 col_basis.build() 193 col_matrix = color_amp.ColorMatrix(col_basis) 194 195 me.born_me.set('color_basis',col_basis) 196 me.born_me.set('color_matrix',col_matrix) 197 198 cannot_combine = [] 199 200 for iother,othermefile in enumerate(duplist): 201 infileother = open(othermefile,'rb') 202 otherme = six.moves.cPickle.load(infileother) 203 infileother.close() 204 # before entering this function, only the born 205 # processes were compared. Now compare the 206 # full ME (born/real/virtual) 207 if otherme == me: 208 me.add_process(otherme) 209 else: 210 cannot_combine.append(othermefile) 211 212 me.set_color_links() 213 214 initial_states=[] 215 for fksreal in me.real_processes: 216 # Pick out all initial state particles for the two beams 217 initial_states.append(sorted(list(set((p.get_initial_pdg(1),p.get_initial_pdg(2)) for \ 218 p in fksreal.matrix_element.get('processes'))))) 219 220 if me.virt_matrix_element: 221 has_virtual = True 222 else: 223 has_virtual = False 224 225 #data to write to file 226 outdata = me 227 228 output = tempfile.NamedTemporaryFile(delete = False) 229 six.moves.cPickle.dump(outdata,output,protocol=2) 230 output.close() 231 232 #data to be returned to parent process (filename plus small objects only) 233 return [output.name,initial_states,me.get_used_lorentz(),me.get_used_couplings(),has_virtual,cannot_combine]
234 235
236 -class FKSHelasMultiProcess(helas_objects.HelasMultiProcess):
237 """class to generate the helas calls for a FKSMultiProcess""" 238
239 - def get_sorted_keys(self):
240 """Return particle property names as a nicely sorted list.""" 241 keys = super(FKSHelasMultiProcess, self).get_sorted_keys() 242 keys += ['real_matrix_elements', ['has_isr'], ['has_fsr'], 243 'used_lorentz', 'used_couplings', 'max_configs', 'max_particles', 'processes'] 244 return keys
245
246 - def filter(self, name, value):
247 """Filter for valid leg property values.""" 248 249 if name == 'real_matrix_elements': 250 if not isinstance(value, helas_objects.HelasMultiProcess): 251 raise self.PhysicsObjectError("%s is not a valid list for real_matrix_element " % str(value))
252
253 - def __init__(self, fksmulti, loop_optimized = False, gen_color =True, decay_ids =[]):
254 """Initialization from a FKSMultiProcess""" 255 256 #swhich the other loggers off 257 loggers_off = [logging.getLogger('madgraph.diagram_generation'), 258 logging.getLogger('madgraph.helas_objects')] 259 old_levels = [logg.level for logg in loggers_off] 260 for logg in loggers_off: 261 logg.setLevel(logging.WARNING) 262 263 self.loop_optimized = loop_optimized 264 265 self['used_lorentz'] = [] 266 self['used_couplings'] = [] 267 self['processes'] = [] 268 269 self['max_particles'] = -1 270 self['max_configs'] = -1 271 272 if not fksmulti['ncores_for_proc_gen']: 273 # generate the real ME's if they are needed. 274 # note that it may not be always the case, e.g. it the NLO_mode is LOonly 275 if fksmulti['real_amplitudes']: 276 logger.info('Generating real emission matrix-elements...') 277 self['real_matrix_elements'] = self.generate_matrix_elements( 278 copy.copy(fksmulti['real_amplitudes']), combine_matrix_elements = False) 279 else: 280 self['real_matrix_elements'] = helas_objects.HelasMatrixElementList() 281 282 self['matrix_elements'] = self.generate_matrix_elements_fks( 283 fksmulti, 284 gen_color, decay_ids) 285 self['initial_states']=[] 286 self['has_loops'] = len(self.get_virt_matrix_elements()) > 0 287 288 else: 289 self['has_loops'] = False 290 #more efficient generation 291 born_procs = fksmulti.get('born_processes') 292 born_pdg_list = [[l['id'] for l in born.born_amp['process']['legs']] \ 293 for born in born_procs ] 294 loop_orders = {} 295 for born in born_procs: 296 for coup, val in fks_common.find_orders(born.born_amp).items(): 297 try: 298 loop_orders[coup] = max([loop_orders[coup], val]) 299 except KeyError: 300 loop_orders[coup] = val 301 pdg_list = [] 302 real_amp_list = [] 303 for born in born_procs: 304 for amp in born.real_amps: 305 if not pdg_list.count(amp.pdgs): 306 pdg_list.append(amp.pdgs) 307 real_amp_list.append(amp) 308 309 #generating and store in tmp files all output corresponding to each real_amplitude 310 real_out_list = [] 311 realmapin = [] 312 for i,real_amp in enumerate(real_amp_list): 313 realmapin.append([i,real_amp]) 314 315 # start the pool instance with a signal instance to catch ctr+c 316 original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) 317 if six.PY3: 318 ctx = multiprocessing.get_context('fork') 319 else: 320 ctx = multiprocessing 321 if fksmulti['ncores_for_proc_gen'] < 0: # use all cores 322 pool = ctx.Pool(maxtasksperchild=1) 323 else: 324 pool = ctx.Pool(processes=fksmulti['ncores_for_proc_gen'],maxtasksperchild=1) 325 signal.signal(signal.SIGINT, original_sigint_handler) 326 327 logger.info('Generating real matrix elements...') 328 import time 329 try: 330 # the very large timeout passed to get is to be able to catch 331 # KeyboardInterrupts 332 modelpath = born_procs[0].born_amp['process']['model'].get('modelpath') 333 #modelpath = self.get('processes')[0].get('model').get('modelpath') 334 with misc.TMP_variable(sys, 'path', sys.path + [pjoin(MG5DIR, 'models'), modelpath]): 335 realmapout = pool.map_async(async_generate_real,realmapin).get(9999999) 336 except KeyboardInterrupt: 337 pool.terminate() 338 raise KeyboardInterrupt 339 340 # sometimes empty output from map_async can be there if the amplitude has no diagrams 341 # these empty entries need to be discarded 342 for rout, ramp, rpdg in zip(list(realmapout), list(real_amp_list), list(pdg_list)): 343 if not rout: 344 realmapout.remove(rout) 345 real_amp_list.remove(ramp) 346 pdg_list.remove(rpdg) 347 realmapout = [r for r in realmapout if r] 348 349 realmapfiles = [] 350 for realout in realmapout: 351 realmapfiles.append(realout[0]) 352 353 logger.info('Generating born and virtual matrix elements...') 354 #now loop over born and consume reals, generate virtuals 355 bornmapin = [] 356 OLP=fksmulti['OLP'] 357 for i,born in enumerate(born_procs): 358 bornmapin.append([i,born,born_pdg_list,loop_orders,pdg_list,loop_optimized,OLP,realmapfiles]) 359 360 try: 361 bornmapout = pool.map_async(async_generate_born,bornmapin).get(9999999) 362 except KeyboardInterrupt: 363 pool.terminate() 364 raise KeyboardInterrupt 365 366 configs_list = [bout[4] for bout in bornmapout] 367 nparticles_list = [bout[5] for bout in bornmapout] 368 369 #remove real temp files 370 for realtmp in realmapout: 371 os.remove(realtmp[0]) 372 373 memapout = [] 374 while bornmapout: 375 logger.info('Collecting infos and finalizing matrix elements, %d left...' \ 376 % (len(bornmapout))) 377 unique_me_list = [] 378 duplicate_me_lists = [] 379 for bornout in bornmapout: 380 mefile = bornout[0] 381 metag = bornout[1] 382 has_loops = bornout[2] 383 self['has_loops'] = self['has_loops'] or has_loops 384 processes = bornout[3] 385 self['processes'].extend(processes) 386 unique = True 387 for ime2,bornout2 in enumerate(unique_me_list): 388 mefile2 = bornout2[0] 389 metag2 = bornout2[1] 390 if metag==metag2: 391 duplicate_me_lists[ime2].append(mefile) 392 unique = False 393 break; 394 if unique: 395 unique_me_list.append(bornout) 396 duplicate_me_lists.append([]) 397 398 memapin = [] 399 not_combined = [] 400 for i,bornout in enumerate(unique_me_list): 401 mefile = bornout[0] 402 memapin.append([i,mefile, duplicate_me_lists[i]]) 403 404 try: 405 memapout.append(pool.map_async(async_finalize_matrix_elements,memapin).get(9999999)) 406 except KeyboardInterrupt: 407 pool.terminate() 408 raise KeyboardInterrupt 409 410 # check the matrix element that were marked as 411 # duplicate but could not be combined 412 for meout in memapout[-1]: 413 not_combined += meout[5] 414 415 #remove born+virtual temp files 416 for bornout in bornmapout[:]: 417 mefile = bornout[0] 418 if not mefile in not_combined: 419 os.remove(mefile) 420 bornmapout.remove(bornout) 421 422 pool.close() 423 pool.join() 424 425 # now we can flatten out memapout 426 memapout = sum(memapout, []) 427 428 #set final list of matrix elements (paths to temp files) 429 matrix_elements = [] 430 for meout in memapout: 431 matrix_elements.append(meout[0]) 432 433 self['matrix_elements']=matrix_elements 434 435 #cache information needed for output which will not be available from 436 #the matrix elements later 437 initial_states = [] 438 for meout in memapout: 439 me_initial_states = meout[1] 440 for state in me_initial_states: 441 initial_states.append(state) 442 443 # remove doubles from the list 444 checked = [] 445 for e in initial_states: 446 if e not in checked: 447 checked.append(e) 448 initial_states=checked 449 450 self['initial_states']=initial_states 451 452 helas_list = [] 453 for meout in memapout: 454 helas_list.extend(meout[2]) 455 self['used_lorentz']=list(set(helas_list)) 456 457 coupling_list = [] 458 for meout in memapout: 459 coupling_list.extend([c for l in meout[3] for c in l]) 460 self['used_couplings'] = list(set(coupling_list)) 461 462 has_virtuals = False 463 for meout in memapout: 464 if meout[4]: 465 has_virtuals = True 466 break 467 self['has_virtuals'] = has_virtuals 468 469 # configs_list and nparticles_list have already 470 # been initialised with the born infos after 471 # async_generate_born 472 for meout in realmapout: 473 configs_list.append(meout[1]) 474 self['max_configs'] = max(configs_list) 475 476 for meout in realmapout: 477 nparticles_list.append(meout[2]) 478 self['max_particles'] = max(nparticles_list) 479 480 self['has_isr'] = fksmulti['has_isr'] 481 self['has_fsr'] = fksmulti['has_fsr'] 482 483 logger.info('... Done') 484 485 for i, logg in enumerate(loggers_off): 486 logg.setLevel(old_levels[i])
487 488
489 - def get_used_lorentz(self):
490 """Return a list of (lorentz_name, conjugate, outgoing) with 491 all lorentz structures used by this HelasMultiProcess.""" 492 493 if not self['used_lorentz']: 494 helas_list = [] 495 for me in self.get('matrix_elements'): 496 helas_list.extend(me.get_used_lorentz()) 497 self['used_lorentz'] = list(set(helas_list)) 498 499 return self['used_lorentz']
500 501
502 - def get_used_couplings(self):
503 """Return a list with all couplings used by this 504 HelasMatrixElement.""" 505 506 if not self['used_couplings']: 507 coupling_list = [] 508 for me in self.get('matrix_elements'): 509 coupling_list.extend([c for l in me.get_used_couplings() for c in l]) 510 self['used_couplings'] = list(set(coupling_list)) 511 512 return self['used_couplings']
513 514
515 - def get_processes(self):
516 """Return a list with all couplings used by this 517 HelasMatrixElement.""" 518 519 if not self['processes']: 520 process_list = [] 521 for me in self.get('matrix_elements'): 522 process_list.extend(me.born_me.get('processes')) 523 self['processes'] = process_list 524 525 return self['processes']
526 527
528 - def get_max_configs(self):
529 """Return max_configs""" 530 531 if self['max_configs'] < 0: 532 try: 533 self['max_configs'] = max([me.get_num_configs() \ 534 for me in self['real_matrix_elements']]) 535 except (ValueError, MG.PhysicsObject.PhysicsObjectError): 536 pass 537 self['max_configs'] = max(self['max_configs'],\ 538 max([me.born_me.get_num_configs() \ 539 for me in self['matrix_elements']])) 540 return self['max_configs']
541 542
543 - def get_max_particles(self):
544 """Return max_paricles""" 545 546 if self['max_particles'] < 0: 547 self['max_particles'] = max([me.get_nexternal_ninitial()[0] \ 548 for me in self['matrix_elements']]) 549 550 return self['max_particles']
551 552
553 - def get_matrix_elements(self):
554 """Extract the list of matrix elements""" 555 return self.get('matrix_elements')
556 557
558 - def get_virt_matrix_elements(self):
559 """Extract the list of virtuals matrix elements""" 560 return [me.virt_matrix_element for me in self.get('matrix_elements') \ 561 if me.virt_matrix_element]
562 563
564 - def generate_matrix_elements_fks(self, fksmulti, gen_color = True, 565 decay_ids = []):
566 """Generate the HelasMatrixElements for the amplitudes, 567 identifying processes with identical matrix elements, as 568 defined by HelasMatrixElement.__eq__. Returns a 569 HelasMatrixElementList and an amplitude map (used by the 570 SubprocessGroup functionality). decay_ids is a list of decayed 571 particle ids, since those should not be combined even if 572 matrix element is identical.""" 573 574 fksprocs = fksmulti['born_processes'] 575 assert isinstance(fksprocs, fks_base.FKSProcessList), \ 576 "%s is not valid FKSProcessList" % \ 577 repr(fksprocs) 578 579 # Keep track of already generated color objects, to reuse as 580 # much as possible 581 list_colorize = [] 582 list_color_links = [] 583 list_color_basis = [] 584 list_color_matrices = [] 585 real_me_list = [] 586 me_id_list = [] 587 588 matrix_elements = FKSHelasProcessList() 589 590 for i, proc in enumerate(fksprocs): 591 logger.info("Generating Helas calls for FKS %s (%d / %d)" % \ 592 (proc.get_born_nice_string().\ 593 replace('Process', 'process'), 594 i + 1, len(fksprocs))) 595 matrix_element_list = [\ 596 FKSHelasProcess(proc, self['real_matrix_elements'], 597 [amp for amp in fksmulti['real_amplitudes'] if amp['diagrams']], 598 loop_optimized = self.loop_optimized, 599 decay_ids=decay_ids, 600 gen_color=False)] 601 602 for matrix_element in matrix_element_list: 603 assert isinstance(matrix_element, FKSHelasProcess), \ 604 "Not a FKSHelasProcess: %s" % matrix_element 605 606 try: 607 # If an identical matrix element is already in the list, 608 # then simply add this process to the list of 609 # processes for that matrix element 610 other = \ 611 matrix_elements[matrix_elements.index(matrix_element)] 612 except ValueError: 613 # Otherwise, if the matrix element has any diagrams, 614 # add this matrix element. 615 if matrix_element.born_me.get('processes') and \ 616 matrix_element.born_me.get('diagrams'): 617 matrix_elements.append(matrix_element) 618 619 if not gen_color: 620 continue 621 622 # Always create an empty color basis, and the 623 # list of raw colorize objects (before 624 # simplification) associated with amplitude 625 col_basis = color_amp.ColorBasis() 626 new_amp = matrix_element.born_me.get_base_amplitude() 627 matrix_element.born_me.set('base_amplitude', new_amp) 628 colorize_obj = col_basis.create_color_dict_list(new_amp) 629 630 try: 631 # If the color configuration of the ME has 632 # already been considered before, recycle 633 # the information 634 col_index = list_colorize.index(colorize_obj) 635 logger.info(\ 636 "Reusing existing color information for %s" % \ 637 matrix_element.born_me.get('processes')\ 638 [0].nice_string(print_weighted=False).\ 639 replace('Process', 'process')) 640 except ValueError: 641 # If not, create color basis and color 642 # matrix accordingly 643 list_colorize.append(colorize_obj) 644 col_basis.build() 645 list_color_basis.append(col_basis) 646 col_matrix = color_amp.ColorMatrix(col_basis) 647 list_color_matrices.append(col_matrix) 648 col_index = -1 649 650 logger.info(\ 651 "Processing color information for %s" % \ 652 matrix_element.born_me.get('processes')[0].\ 653 nice_string(print_weighted=False).\ 654 replace('Process', 'process')) 655 matrix_element.born_me.set('color_basis', list_color_basis[col_index]) 656 matrix_element.born_me.set('color_matrix', list_color_matrices[col_index]) 657 else: 658 # this is in order not to handle valueErrors coming from other plaeces, 659 # e.g. from the add_process function 660 other.add_process(matrix_element) 661 662 for me in matrix_elements: 663 me.set_color_links() 664 return matrix_elements
665 666
667 -class FKSHelasProcessList(MG.PhysicsObjectList):
668 """class to handle lists of FKSHelasProcesses""" 669
670 - def is_valid_element(self, obj):
671 """Test if object obj is a valid FKSProcess for the list.""" 672 return isinstance(obj, FKSHelasProcess)
673 674
675 -class FKSHelasProcess(object):
676 """class to generate the Helas calls for a FKSProcess. Contains: 677 -- born ME 678 -- list of FKSHelasRealProcesses 679 -- color links 680 -- charges 681 -- extra MEs used as counterterms 682 """ 683
684 - def __init__(self, fksproc=None, real_me_list =[], real_amp_list=[], 685 loop_optimized = False, **opts):#test written
686 """ constructor, starts from a FKSProcess, 687 sets reals and color links. Real_me_list and real_amp_list are the lists of pre-genrated 688 matrix elements in 1-1 correspondence with the amplitudes""" 689 690 if fksproc != None: 691 self.born_me = helas_objects.HelasMatrixElement(fksproc.born_amp, **opts) 692 693 self.real_processes = [] 694 self.extra_cnt_me_list = [] 695 self.perturbation = fksproc.perturbation 696 self.charges_born = fksproc.get_charges() 697 real_amps_new = [] 698 699 for extra_cnt in fksproc.extra_cnt_amp_list: 700 self.extra_cnt_me_list.append(helas_objects.HelasMatrixElement(extra_cnt,gen_color=True)) 701 702 # combine for example u u~ > t t~ and c c~ > t t~ 703 if fksproc.ncores_for_proc_gen: 704 # new NLO (multicore) generation mode 705 for real_me, proc in zip(real_me_list,fksproc.real_amps): 706 fksreal_me = FKSHelasRealProcess(proc, real_me, **opts) 707 try: 708 other = self.real_processes[self.real_processes.index(fksreal_me)] 709 other.matrix_element.get('processes').extend(\ 710 fksreal_me.matrix_element.get('processes') ) 711 except ValueError: 712 if fksreal_me.matrix_element.get('processes') and \ 713 fksreal_me.matrix_element.get('diagrams'): 714 self.real_processes.append(fksreal_me) 715 real_amps_new.append(proc) 716 else: 717 #old mode 718 for proc in fksproc.real_amps: 719 if proc.amplitude['diagrams']: 720 fksreal_me = FKSHelasRealProcess(proc, real_me_list, real_amp_list, **opts) 721 try: 722 other = self.real_processes[self.real_processes.index(fksreal_me)] 723 other.matrix_element.get('processes').extend(\ 724 fksreal_me.matrix_element.get('processes') ) 725 except ValueError: 726 if fksreal_me.matrix_element.get('processes') and \ 727 fksreal_me.matrix_element.get('diagrams'): 728 self.real_processes.append(fksreal_me) 729 real_amps_new.append(proc) 730 731 fksproc.real_amps = real_amps_new 732 if fksproc.virt_amp: 733 self.virt_matrix_element = \ 734 loop_helas_objects.LoopHelasMatrixElement(fksproc.virt_amp, 735 optimized_output = loop_optimized) 736 else: 737 self.virt_matrix_element = None 738 self.color_links = []
739 740 754
755 - def get_fks_info_list(self):
756 """Returns the list of the fks infos for all processes in the format 757 {n_me, pdgs, fks_info}, where n_me is the number of real_matrix_element the configuration 758 belongs to""" 759 info_list = [] 760 for n, real in enumerate(self.real_processes): 761 pdgs = [l['id'] for l in real.matrix_element.get_base_amplitude()['process']['legs']] 762 for info in real.fks_infos: 763 info_list.append({'n_me' : n + 1,'pdgs' : pdgs, 'fks_info' : info}) 764 return info_list
765 766
767 - def get_lh_pdg_string(self):
768 """Returns the pdgs of the legs in the form "i1 i2 -> f1 f2 ...", which may 769 be useful (eg. to be written in a B-LH order file)""" 770 771 initial = '' 772 final = '' 773 for leg in self.born_me.get('processes')[0].get('legs'): 774 if leg.get('state'): 775 final += '%d ' % leg.get('id') 776 else: 777 initial += '%d ' % leg.get('id') 778 return initial + '-> ' + final
779 780
781 - def get(self, key):
782 """the get function references to the born 783 matrix element 784 """ 785 return self.born_me.get(key)
786 787
788 - def get_used_lorentz(self):
789 """the get_used_lorentz function references to born, reals 790 and virtual matrix elements""" 791 lorentz_list = self.born_me.get_used_lorentz() 792 for real in self.real_processes: 793 lorentz_list.extend(real.matrix_element.get_used_lorentz()) 794 if self.virt_matrix_element: 795 lorentz_list.extend(self.virt_matrix_element.get_used_lorentz()) 796 797 return list(set(lorentz_list))
798 799
800 - def get_used_couplings(self):
801 """the get_used_couplings function references to born, reals 802 and virtual matrix elements""" 803 coupl_list = self.born_me.get_used_couplings() 804 for real in self.real_processes: 805 coupl_list.extend([c for c in\ 806 real.matrix_element.get_used_couplings()]) 807 if self.virt_matrix_element: 808 coupl_list.extend(self.virt_matrix_element.get_used_couplings()) 809 return coupl_list
810
811 - def get_nexternal_ninitial(self):
812 """the nexternal_ninitial function references to the real emissions if they have been 813 generated, otherwise to the born""" 814 if self.real_processes: 815 (nexternal, ninitial) = self.real_processes[0].matrix_element.get_nexternal_ninitial() 816 else: 817 (nexternal, ninitial) = self.born_me.get_nexternal_ninitial() 818 nexternal += 1 819 return (nexternal, ninitial)
820
821 - def __eq__(self, other):
822 """the equality between two FKSHelasProcesses is defined up to the 823 color links""" 824 #first compare the born 825 selftag = helas_objects.IdentifyMETag.\ 826 create_tag(self.born_me.get('base_amplitude')) 827 othertag = helas_objects.IdentifyMETag.\ 828 create_tag(other.born_me.get('base_amplitude')) 829 830 if selftag != othertag: 831 return False 832 833 # now the virtuals 834 if self.virt_matrix_element != other.virt_matrix_element: 835 return False 836 837 # now the reals 838 reals2 = copy.copy(other.real_processes) 839 840 for real in self.real_processes: 841 try: 842 reals2.remove(real) 843 except ValueError: 844 return False 845 846 if not reals2: 847 return True 848 else: 849 return False
850 851
852 - def __ne__(self, other):
853 """Inequality operator 854 """ 855 return not self.__eq__(other)
856 857
858 - def add_process(self, other): #test written, ppwj
859 """adds processes from born and reals of other to itself. Note that 860 corresponding real processes may not be in the same order. This is 861 taken care of by constructing the list of self_reals. 862 """ 863 # first add the born process 864 #need to store pdg lists rather than processes in order to keep mirror processes different 865 this_pdgs = [[leg['id'] for leg in proc['legs']] \ 866 for proc in self.born_me['processes']] 867 for oth_proc in other.born_me['processes']: 868 oth_pdgs = [leg['id'] for leg in oth_proc['legs']] 869 if oth_pdgs not in this_pdgs: 870 self.born_me['processes'].append(oth_proc) 871 this_pdgs.append(oth_pdgs) 872 873 # then the virtuals (if generated) 874 if self.virt_matrix_element and other.virt_matrix_element: 875 self.virt_matrix_element.get('processes').extend( 876 other.virt_matrix_element.get('processes')) 877 878 # finally the reals 879 self_reals = [real.matrix_element for real in self.real_processes] 880 for oth_real in other.real_processes: 881 882 try: 883 #there should be a 1to1 correspondence between real emission 884 ####this_real = self.real_processes[self_reals.index(oth_real.matrix_element)] 885 this_real = self.real_processes[self.real_processes.index(oth_real)] 886 except ValueError: 887 raise fks_common.FKSProcessError('add_process: error in combination of real MEs') 888 #need to store pdg lists rather than processes in order to keep mirror processes different 889 this_pdgs = [[leg['id'] for leg in proc['legs']] \ 890 for proc in this_real.matrix_element['processes']] 891 for oth_proc in oth_real.matrix_element['processes']: 892 oth_pdgs = [leg['id'] for leg in oth_proc['legs']] 893 if oth_pdgs not in this_pdgs: 894 this_real.matrix_element['processes'].append(oth_proc) 895 this_pdgs.append(oth_pdgs) 896 897 898
899 -class FKSHelasRealProcess(object): #test written
900 """class to generate the Helas calls for a FKSRealProcess 901 contains: 902 -- colors 903 -- charges 904 -- i/j/ij fks, ij refers to the born leglist 905 -- ijglu 906 -- need_color_links 907 -- fks_j_from_i 908 -- matrix element 909 -- is_to_integrate 910 -- leg permutation<<REMOVED""" 911
912 - def __init__(self, fksrealproc=None, real_me_list = [], real_amp_list =[], **opts):
913 """constructor, starts from a fksrealproc and then calls the 914 initialization for HelasMatrixElement. 915 Sets i/j fks and the permutation. 916 real_me_list and real_amp_list are the lists of pre-generated matrix elements in 1-1 917 correspondance with the amplitudes""" 918 919 if fksrealproc != None: 920 self.isfinite = False 921 self.colors = fksrealproc.colors 922 self.charges = fksrealproc.charges 923 self.fks_infos = fksrealproc.fks_infos 924 self.is_to_integrate = fksrealproc.is_to_integrate 925 926 # real_me_list is a list in the old NLO generation mode; 927 # in the new one it is a matrix element 928 if type(real_me_list) == list and len(real_me_list) != len(real_amp_list): 929 raise fks_common.FKSProcessError( 930 'not same number of amplitudes and matrix elements: %d, %d' % \ 931 (len(real_amp_list), len(real_me_list))) 932 if type(real_me_list) == list and real_me_list and real_amp_list: 933 self.matrix_element = copy.deepcopy(real_me_list[real_amp_list.index(fksrealproc.amplitude)]) 934 self.matrix_element['processes'] = copy.deepcopy(self.matrix_element['processes']) 935 936 elif type(real_me_list) == helas_objects.HelasMatrixElement: 937 #new NLO generation mode 938 assert fksrealproc.process in real_me_list['processes'], \ 939 "Inconsistent input in FKSHelasRealProcess\nfksrealproc: %s\nME: %s" % \ 940 (fksrealproc.process.nice_string(), 941 ' - '.join([p.nice_string() for p in real_me_list['processes']])) 942 self.matrix_element = real_me_list 943 944 else: 945 946 if real_me_list and real_amp_list: 947 self.matrix_element = copy.deepcopy(real_me_list[real_amp_list.index(fksrealproc.amplitude)]) 948 self.matrix_element['processes'] = copy.deepcopy(self.matrix_element['processes']) 949 else: 950 logger.info('generating matrix element...') 951 self.matrix_element = helas_objects.HelasMatrixElement( 952 fksrealproc.amplitude, **opts) 953 #generate the color for the real 954 self.matrix_element.get('color_basis').build( 955 self.matrix_element.get('base_amplitude')) 956 self.matrix_element.set('color_matrix', 957 color_amp.ColorMatrix( 958 self.matrix_element.get('color_basis'))) 959 #self.fks_j_from_i = fksrealproc.find_fks_j_from_i() 960 self.fks_j_from_i = fksrealproc.fks_j_from_i
961
962 - def get_nexternal_ninitial(self):
963 """Refers to the matrix_element function""" 964 return self.matrix_element.get_nexternal_ninitial()
965
966 - def __eq__(self, other):
967 """Equality operator: 968 compare two FKSHelasRealProcesses by comparing their dictionaries""" 969 970 for key in [k for k in self.__dict__.keys() if k not in ['fks_infos', 'charges']]: 971 if self.__dict__[key] != other.__dict__[key]: 972 return False 973 974 # special care for the fks_infos, ignore the various PDG ids 975 if (len(self.fks_infos) != len(other.fks_infos)): 976 return False 977 978 tocheck_info = [k for k in self.fks_infos[0].keys() if k not in ['ij_id', 'underlying_born']] 979 for selfinfo, otherinfo in zip(self.fks_infos, other.fks_infos): 980 if len(selfinfo['underlying_born']) != len(otherinfo['underlying_born']): 981 return False 982 for key in tocheck_info: 983 if selfinfo[key] != otherinfo [key]: 984 return False 985 986 return True
987 988
989 - def __ne__(self, other):
990 """Inequality operator: 991 compare two FKSHelasRealProcesses by comparing their dictionaries""" 992 return not self.__eq__(other)
993