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