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

Source Code for Module madgraph.fks.fks_base

  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 objects needed for the implementation of MadFKS""" 
 17   
 18  import madgraph.core.base_objects as MG 
 19  import madgraph.core.helas_objects as helas_objects 
 20  import madgraph.core.diagram_generation as diagram_generation 
 21  import madgraph.core.color_amp as color_amp 
 22  import madgraph.core.color_algebra as color_algebra 
 23  import madgraph.loop.loop_diagram_generation as loop_diagram_generation 
 24  import madgraph.fks.fks_common as fks_common 
 25  import copy 
 26  import logging 
 27  import array 
 28  import madgraph.various.misc as misc 
 29  from madgraph import InvalidCmd 
 30   
 31  logger = logging.getLogger('madgraph.fks_base') 
 32   
 33   
34 -class NoBornException(Exception): pass
35 36 #=============================================================================== 37 # FKS Process 38 #===============================================================================
39 -class FKSMultiProcess(diagram_generation.MultiProcess): #test written
40 """A multi process class that contains informations on the born processes 41 and the reals. 42 """ 43
44 - def default_setup(self):
45 """Default values for all properties""" 46 super(FKSMultiProcess, self).default_setup() 47 self['born_processes'] = FKSProcessList() 48 if not 'OLP' in self.keys(): 49 self['OLP'] = 'MadLoop'
50
51 - def get_sorted_keys(self):
52 """Return particle property names as a nicely sorted list.""" 53 keys = super(FKSMultiProcess, self).get_sorted_keys() 54 keys += ['born_processes', 'real_amplitudes', 'real_pdgs', 'has_isr', 55 'has_fsr', 'OLP'] 56 return keys
57
58 - def filter(self, name, value):
59 """Filter for valid leg property values.""" 60 61 if name == 'born_processes': 62 if not isinstance(value, FKSProcessList): 63 raise self.PhysicsObjectError, \ 64 "%s is not a valid list for born_processes " % str(value) 65 66 if name == 'real_amplitudes': 67 if not isinstance(value, diagram_generation.AmplitudeList): 68 raise self.PhysicsObjectError, \ 69 "%s is not a valid list for real_amplitudes " % str(value) 70 71 if name == 'real_pdgs': 72 if not isinstance(value, list): 73 raise self.PhysicsObjectError, \ 74 "%s is not a valid list for real_amplitudes " % str(value) 75 76 if name == 'OLP': 77 if not isinstance(value,str): 78 raise self.PhysicsObjectError, \ 79 "%s is not a valid string for OLP " % str(value) 80 81 return super(FKSMultiProcess,self).filter(name, value)
82
83 - def __init__(self, *arguments, **options):
84 """Initializes the original multiprocess, then generates the amps for the 85 borns, then generate the born processes and the reals. 86 Real amplitudes are stored in real_amplitudes according on the pdgs of their 87 legs (stored in pdgs, so that they need to be generated only once and then reicycled 88 """ 89 90 #swhich the other loggers off 91 loggers_off = [logging.getLogger('madgraph.diagram_generation'), 92 logging.getLogger('madgraph.loop_diagram_generation')] 93 old_levels = [logg.level for logg in loggers_off] 94 for logg in loggers_off: 95 logg.setLevel(logging.WARNING) 96 97 self['real_amplitudes'] = diagram_generation.AmplitudeList() 98 self['pdgs'] = [] 99 100 if 'OLP' in options.keys(): 101 self['OLP']=options['OLP'] 102 del options['OLP'] 103 104 105 try: 106 # Now generating the borns for the first time. 107 super(FKSMultiProcess, self).__init__(*arguments,**options) 108 except diagram_generation.NoDiagramException as error: 109 # If no born, then this process most likely does not have any. 110 raise NoBornException, "Born diagrams could not be generated for the "+\ 111 self['process_definitions'][0].nice_string().replace('Process',\ 112 'process')+". Notice that aMC@NLO does not handle loop-induced"+\ 113 " processes yet, but you can still use MadLoop if you want to "+\ 114 "only generate them."+\ 115 " For this, use the 'virt=' mode, without multiparticle labels." 116 117 #check limitation of FKS 118 if arguments and isinstance(arguments, MG.Process): 119 myprocdef = arguments[0] 120 misc.sprint( myprocdef.keys()) 121 if myprocdef['perturbation_couplings']!=['QCD']: 122 raise InvalidCmd("FKS for reals only available in QCD for now, you asked %s" \ 123 % ', '.join(myprocdef['perturbation_couplings'])) 124 elif myprocdef.get_ninitial()==1: 125 raise InvalidCmd("At this stage aMC@NLO cannot handle decay process.\n"+\ 126 " Only Leading Order (loop-induced and tree level) decay are supported.") 127 128 #check process definition(s): 129 # a process such as g g > g g will lead to real emissions 130 # (e.g: u g > u g g ) which will miss some corresponding born, 131 # leading to non finite results 132 perturbation = [] 133 for procdef in self['process_definitions']: 134 soft_particles = [] 135 # do not warn for decay processes 136 if [ i['state'] for i in procdef['legs']].count(False) == 1: 137 continue 138 for pert in procdef['perturbation_couplings']: 139 if pert not in perturbation: 140 perturbation.append(pert) 141 soft_particles.extend(\ 142 fks_common.find_pert_particles_interactions(\ 143 procdef['model'], pert)['soft_particles']) 144 soft_particles_string = ', '.join( \ 145 [procdef['model'].get('particle_dict')[id][\ 146 {True:'name', False:'antiname'}[id >0] ] \ 147 for id in sorted(soft_particles, reverse=True)]) 148 for leg in procdef['legs']: 149 if any([id in soft_particles for id in leg['ids']]) \ 150 and sorted(leg['ids']) != soft_particles: 151 logger.warning(('%s can have real emission processes ' + \ 152 'which are not finite.\nTo avoid this, please use multiparticles ' + \ 153 'when generating the process and be sure to include all the following ' + \ 154 'particles in the multiparticle definition:\n %s' ) \ 155 % (procdef.nice_string(), soft_particles_string) ) 156 break 157 for procdef in self['process_definitions']: 158 procdef.set('orders', diagram_generation.MultiProcess.find_optimal_process_orders(procdef)) 159 160 amps = self.get('amplitudes') 161 for i, amp in enumerate(amps): 162 logger.info("Generating FKS-subtracted matrix elements for born process%s (%d / %d)" \ 163 % (amp['process'].nice_string(print_weighted=False).replace(\ 164 'Process', ''), 165 i + 1, len(amps))) 166 167 born = FKSProcess(amp) 168 self['born_processes'].append(born) 169 born.generate_reals(self['pdgs'], self['real_amplitudes']) 170 171 born_pdg_list = [[l['id'] for l in born.born_proc['legs']] \ 172 for born in self['born_processes'] ] 173 174 for born in self['born_processes']: 175 for real in born.real_amps: 176 real.find_fks_j_from_i(born_pdg_list) 177 178 if amps: 179 if self['process_definitions'][0].get('NLO_mode') == 'all': 180 self.generate_virtuals() 181 182 elif not self['process_definitions'][0].get('NLO_mode') in ['all', 'real','LOonly']: 183 raise fks_common.FKSProcessError(\ 184 "Not a valid NLO_mode for a FKSMultiProcess: %s" % \ 185 self['process_definitions'][0].get('NLO_mode')) 186 187 # now get the total number of diagrams 188 n_diag_born = sum([len(amp.get('diagrams')) 189 for amp in self.get_born_amplitudes()]) 190 n_diag_real = sum([len(amp.get('diagrams')) 191 for amp in self.get_real_amplitudes()]) 192 n_diag_virt = sum([len(amp.get('loop_diagrams')) 193 for amp in self.get_virt_amplitudes()]) 194 195 if n_diag_virt == 0 and n_diag_real ==0 and \ 196 not self['process_definitions'][0].get('NLO_mode') == 'LOonly': 197 raise fks_common.FKSProcessError( 198 'This process does not have any correction up to NLO in %s'\ 199 %','.join(perturbation)) 200 201 logger.info(('Generated %d subprocesses with %d real emission diagrams, ' + \ 202 '%d born diagrams and %d virtual diagrams') % \ 203 (len(self['born_processes']), n_diag_real, n_diag_born, n_diag_virt)) 204 205 for i, logg in enumerate(loggers_off): 206 logg.setLevel(old_levels[i]) 207 208 self['has_isr'] = any([proc.isr for proc in self['born_processes']]) 209 self['has_fsr'] = any([proc.fsr for proc in self['born_processes']])
210
211 - def add(self, other):
212 """combines self and other, extending the lists of born/real amplitudes""" 213 self['born_processes'].extend(other['born_processes']) 214 self['real_amplitudes'].extend(other['real_amplitudes']) 215 self['pdgs'].extend(other['pdgs']) 216 self['has_isr'] = self['has_isr'] or other['has_isr'] 217 self['has_fsr'] = self['has_fsr'] or other['has_fsr'] 218 self['OLP'] = other['OLP']
219
220 - def get_born_amplitudes(self):
221 """return an amplitudelist with the born amplitudes""" 222 return diagram_generation.AmplitudeList([born.born_amp \ 223 for born in self['born_processes']])
224
225 - def get_virt_amplitudes(self):
226 """return an amplitudelist with the virt amplitudes""" 227 return diagram_generation.AmplitudeList([born.virt_amp \ 228 for born in self['born_processes'] if born.virt_amp])
229
230 - def get_real_amplitudes(self):
231 """return an amplitudelist with the real amplitudes""" 232 return self.get('real_amplitudes')
233 234
235 - def generate_virtuals(self):
236 """For each process among the born_processes, creates the corresponding 237 virtual amplitude""" 238 239 # If not using MadLoop, then the LH order file generation and processing 240 # will be entirely done during the output, so nothing must be done at 241 # this stage yet. 242 if self['OLP']!='MadLoop': 243 logger.info("The loop matrix elements will be generated by "+\ 244 '%s at the output stage only.'%self['OLP']) 245 return 246 247 # determine the orders to be used to generate the loop 248 loop_orders = {} 249 for born in self['born_processes']: 250 for coup, val in fks_common.find_orders(born.born_amp).items(): 251 try: 252 loop_orders[coup] = max([loop_orders[coup], val]) 253 except KeyError: 254 loop_orders[coup] = val 255 256 for i, born in enumerate(self['born_processes']): 257 logger.info('Generating virtual matrix elements using MadLoop:') 258 myproc = copy.copy(born.born_proc) 259 # take the orders that are actually used bu the matrix element 260 myproc['orders'] = loop_orders 261 myproc['legs'] = fks_common.to_legs(copy.copy(myproc['legs'])) 262 logger.info('Generating virtual matrix element with MadLoop for process%s (%d / %d)' \ 263 % (myproc.nice_string(print_weighted = False).replace(\ 264 'Process', ''), 265 i + 1, len(self['born_processes']))) 266 myamp = loop_diagram_generation.LoopAmplitude(myproc) 267 if myamp.get('diagrams'): 268 born.virt_amp = myamp
269 270
271 -class FKSRealProcess(object):
272 """Contains information about a real process: 273 -- fks_infos (list containing the possible fks configs for a given process 274 -- amplitude 275 -- is_to_integrate 276 -- leg permutation<<REMOVED!. 277 """ 278
279 - def __init__(self, born_proc, leglist, ij, ijglu, 280 perturbed_orders = ['QCD']): #test written
281 """Initializes the real process based on born_proc and leglist. 282 Stores the fks informations into the list of dictionaries fks_infos 283 """ 284 self.fks_infos = [] 285 for leg in leglist: 286 if leg.get('fks') == 'i': 287 i_fks = leg.get('number') 288 # i is a gluon or a photon 289 need_color_links = leg.get('massless') \ 290 and leg.get('spin') == 3 \ 291 and leg.get('self_antipart') 292 if leg.get('fks') == 'j': 293 j_fks = leg.get('number') 294 self.fks_infos.append({'i' : i_fks, 295 'j' : j_fks, 296 'ij' : ij, 297 'ij_glu': ijglu, 298 'need_color_links' : need_color_links}) 299 300 self.process = copy.copy(born_proc) 301 orders = copy.copy(born_proc.get('orders')) 302 # compute the weighted order if not present 303 if not 'WEIGHTED' in orders: 304 orders['WEIGHTED'] = sum([v * born_proc.get('model').get('order_hierarchy')[o] \ 305 for o, v in orders.items()]) 306 307 for order in perturbed_orders: 308 try: 309 orders[order] +=1 310 except KeyError: 311 pass 312 orders['WEIGHTED'] += born_proc.get('model').get('order_hierarchy')[order] 313 314 self.process.set('orders', orders) 315 legs = [(leg.get('id'), leg) for leg in leglist] 316 self.pdgs = array.array('i',[s[0] for s in legs]) 317 if 'QCD' in perturbed_orders: 318 self.colors = [leg['color'] for leg in leglist] 319 # in QCD, charges are irrelevant ! 320 self.charges = [0. for leg in leglist] 321 self.perturbation = 'QCD' 322 else: 323 self.colors = [leg['color'] for leg in leglist] 324 self.charges = [leg['charge'] for leg in leglist] 325 self.perturbation = 'QED' 326 self.process.set('legs', MG.LegList(leglist)) 327 self.process.set('legs_with_decays', MG.LegList()) 328 self.amplitude = diagram_generation.Amplitude() 329 self.is_to_integrate = True 330 self.is_nbody_only = False 331 self.fks_j_from_i = {} 332 333
334 - def generate_real_amplitude(self):
335 """generates the real emission amplitude starting from self.process""" 336 self.amplitude = diagram_generation.Amplitude(self.process) 337 return self.amplitude
338 339
340 - def find_fks_j_from_i(self, born_pdg_list): #test written
341 """Returns a dictionary with the entries i : [j_from_i], if the born pdgs are in 342 born_pdg_list""" 343 fks_j_from_i = {} 344 dict = {} 345 for i in self.process.get('legs'): 346 fks_j_from_i[i.get('number')] = [] 347 if i.get('state'): 348 for j in [l for l in self.process.get('legs') if \ 349 l.get('number') != i.get('number')]: 350 ijlist = fks_common.combine_ij(i, j, self.process.get('model'), dict,\ 351 pert=self.perturbation) 352 for ij in ijlist: 353 born_leglist = fks_common.to_fks_legs( 354 copy.deepcopy(self.process.get('legs')), 355 self.process.get('model')) 356 born_leglist.remove(i) 357 born_leglist.remove(j) 358 born_leglist.insert(ij.get('number') - 1, ij) 359 born_leglist.sort(pert = self.perturbation) 360 if [l['id'] for l in born_leglist] in born_pdg_list: 361 fks_j_from_i[i.get('number')].append(\ 362 j.get('number')) 363 364 self.fks_j_from_i = fks_j_from_i 365 return fks_j_from_i 366 367
368 - def get_leg_i(self): #test written
369 """Returns leg corresponding to i fks. 370 An error is raised if the fks_infos list has more than one entry""" 371 if len(self.fks_infos) > 1: 372 raise fks_common.FKSProcessError(\ 373 'get_leg_i should only be called before combining processes') 374 return self.process.get('legs')[self.fks_infos[0]['i'] - 1] 375
376 - def get_leg_j(self): #test written
377 """Returns leg corresponding to j fks. 378 An error is raised if the fks_infos list has more than one entry""" 379 if len(self.fks_infos) > 1: 380 raise fks_common.FKSProcessError(\ 381 'get_leg_j should only be called before combining processes') 382 return self.process.get('legs')[self.fks_infos[0]['j'] - 1] 383 384
385 -class FKSProcessList(MG.PhysicsObjectList):
386 """Class to handle lists of FKSProcesses.""" 387
388 - def is_valid_element(self, obj):
389 """Test if object obj is a valid FKSProcess for the list.""" 390 return isinstance(obj, FKSProcess)
391 392
393 -class FKSProcess(object):
394 """The class for a FKS process. Starts from the born process and finds 395 all the possible splittings.""" 396
397 - def __init__(self, start_proc = None, remove_reals = True):
398 """initialization: starts either from an amplitude or a process, 399 then init the needed variables. 400 remove_borns tells if the borns not needed for integration will be removed 401 from the born list (mainly used for testing)""" 402 403 self.splittings = {} 404 self.reals = [] 405 self.fks_dirs = [] 406 self.leglist = [] 407 self.myorders = {} 408 self.pdg_codes = [] 409 self.colors = [] # color 410 self.charges = [] # charge 411 self.nlegs = 0 412 self.fks_ipos = [] 413 self.fks_j_from_i = {} 414 self.real_amps = [] 415 self.remove_reals = remove_reals 416 self.nincoming = 0 417 self.virt_amp = None 418 self.perturbation = 'QCD' 419 420 if not remove_reals in [True, False]: 421 raise fks_common.FKSProcessError(\ 422 'Not valid type for remove_reals in FKSProcess') 423 424 if start_proc: 425 if isinstance(start_proc, MG.Process): 426 pertur = start_proc['perturbation_couplings'] 427 if pertur: 428 self.perturbation = sorted(pertur)[0] 429 self.born_proc = fks_common.sort_proc(start_proc,pert = self.perturbation) 430 # filter in Amplitude will legs sorted in bornproc 431 bornproc = copy.copy(self.born_proc) # deepcopy might let T -> array 432 assert bornproc==self.born_proc 433 self.born_amp = diagram_generation.Amplitude(bornproc) 434 elif isinstance(start_proc, diagram_generation.Amplitude): 435 pertur = start_proc.get('process')['perturbation_couplings'] 436 if pertur: 437 self.perturbation = sorted(pertur)[0] 438 self.born_proc = fks_common.sort_proc(start_proc.get('process'),\ 439 pert = self.perturbation) 440 # filter in Amplitude will legs sorted in bornproc 441 bornproc = copy.copy(self.born_proc) 442 assert bornproc == self.born_proc 443 self.born_amp = diagram_generation.Amplitude(bornproc) 444 else: 445 raise fks_common.FKSProcessError(\ 446 'Not valid start_proc in FKSProcess') 447 self.born_proc.set('legs_with_decays', MG.LegList()) 448 449 self.leglist = fks_common.to_fks_legs( 450 self.born_proc['legs'], self.born_proc['model']) 451 self.nlegs = len(self.leglist) 452 self.pdg_codes = [leg.get('id') for leg in self.leglist] 453 if self.perturbation == 'QCD': 454 self.colors = [leg.get('color') for leg in self.leglist] 455 # in QCD, charge is irrelevant but impact the combine process ! 456 self.charges = [0. for leg in self.leglist] 457 color = 'color' 458 zero = 1 459 elif self.perturbation == 'QED': 460 self.colors = [leg.get('color') for leg in self.leglist] 461 self.charges = [leg.get('charge') for leg in self.leglist] 462 color = 'charge' 463 zero = 0. 464 # special treatment of photon is needed ! 465 self.isr = set([leg.get(color) for leg in self.leglist if not leg.get('state')]) != set([zero]) 466 self.fsr = set([leg.get(color) for leg in self.leglist if leg.get('state')]) != set([zero]) 467 for leg in self.leglist: 468 if not leg['state']: 469 self.nincoming += 1 470 self.orders = self.born_amp['process']['orders'] 471 # this is for cases in which the user specifies e.g. QED=0 472 if sum(self.orders.values()) == 0: 473 self.orders = fks_common.find_orders(self.born_amp) 474 475 self.ndirs = 0 476 # generate reals, when the mode is not LOonly 477 # when is LOonly it is supposed to be a 'fake' NLO process 478 # e.g. to be used in merged sampels at high multiplicities 479 if self.born_proc['NLO_mode'] != 'LOonly': 480 for order in self.born_proc.get('perturbation_couplings'): 481 self.find_reals(order)
482 483
484 - def generate_real_amplitudes(self, pdg_list, real_amp_list):
485 """generates the real amplitudes for all the real emission processes, using pdgs and real_amps 486 to avoid multiple generation of the same amplitude""" 487 488 for amp in self.real_amps: 489 try: 490 amp.amplitude = real_amp_list[pdg_list.index(amp.pdgs)] 491 except ValueError: 492 pdg_list.append(amp.pdgs) 493 real_amp_list.append(amp.generate_real_amplitude())
494 495
496 - def combine_real_amplitudes(self):
497 """combines real emission processes if the pdgs are the same, combining the lists 498 of fks_infos""" 499 pdgs = [] 500 real_amps = [] 501 old_real_amps = copy.copy(self.real_amps) 502 for amp in old_real_amps: 503 try: 504 real_amps[pdgs.index(amp.pdgs)].fks_infos.extend(amp.fks_infos) 505 except ValueError: 506 real_amps.append(amp) 507 pdgs.append(amp.pdgs) 508 509 self.real_amps = real_amps
510 511 512
513 - def generate_reals(self, pdg_list, real_amp_list, combine=True): #test written
514 """For all the possible splittings, creates an FKSRealProcess. 515 It removes double counted configorations from the ones to integrates and 516 sets the one which includes the bosn (is_nbody_only). 517 if combine is true, FKS_real_processes having the same pdgs (i.e. real amplitude) 518 are combined together 519 """ 520 521 born_proc = copy.copy(self.born_proc) 522 born_proc['orders'] = self.orders 523 for i, list in enumerate(self.reals): 524 # i is a gluon or photon,i.e. g(a) > ffx or gg 525 if self.leglist[i]['massless'] and self.leglist[i]['spin'] == 3: 526 ijglu = i + 1 527 else: 528 ijglu = 0 529 for l in list: 530 ij = self.leglist[i].get('number') 531 self.real_amps.append(FKSRealProcess( \ 532 born_proc, l, ij, ijglu,\ 533 perturbed_orders = [self.perturbation])) 534 self.find_reals_to_integrate() 535 if combine: 536 self.combine_real_amplitudes() 537 self.generate_real_amplitudes(pdg_list, real_amp_list) 538 self.link_born_reals()
539 540 550 551
552 - def find_reals(self, pert_order):
553 """finds the FKS real configurations for a given process""" 554 if range(len(self.leglist)) != [l['number']-1 for l in self.leglist]: 555 raise fks_common.FKSProcessError('Disordered numbers of leglist') 556 557 if [ i['state'] for i in self.leglist].count(False) == 1: 558 decay_process=True 559 else: 560 decay_process=False 561 562 for i in self.leglist: 563 i_i = i['number'] - 1 564 self.reals.append([]) 565 if decay_process and not i['state']: 566 self.splittings[i_i]=[] 567 else: 568 self.splittings[i_i] = fks_common.find_splittings(i, self.born_proc['model'], {}, pert_order) 569 for split in self.splittings[i_i]: 570 self.reals[i_i].append( 571 fks_common.insert_legs(self.leglist, i, split,pert=pert_order))
572 573 574
575 - def find_reals_to_integrate(self): #test written
576 """Finds double countings in the real emission configurations, sets the 577 is_to_integrate variable and if "self.remove_reals" is True removes the 578 not needed ones from the born list. 579 """ 580 #find the initial number of real configurations 581 ninit = len(self.real_amps) 582 remove = self.remove_reals 583 584 for m in range(ninit): 585 for n in range(m + 1, ninit): 586 real_m = self.real_amps[m] 587 real_n = self.real_amps[n] 588 if len(real_m.fks_infos) > 1 or len(real_m.fks_infos) > 1: 589 raise fks_common.FKSProcessError(\ 590 'find_reals_to_integrate should only be called before combining processes') 591 592 i_m = real_m.fks_infos[0]['i'] 593 j_m = real_m.fks_infos[0]['j'] 594 i_n = real_n.fks_infos[0]['i'] 595 j_n = real_n.fks_infos[0]['j'] 596 if j_m > self.nincoming and j_n > self.nincoming: 597 if (real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] \ 598 and \ 599 real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']) \ 600 or \ 601 (real_m.get_leg_i()['id'] == real_n.get_leg_j()['id'] \ 602 and \ 603 real_m.get_leg_j()['id'] == real_n.get_leg_i()['id']): 604 if i_m > i_n: 605 print real_m.get_leg_i()['id'], real_m.get_leg_j()['id'] 606 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: 607 self.real_amps[m].is_to_integrate = False 608 else: 609 self.real_amps[n].is_to_integrate = False 610 elif i_m == i_n and j_m > j_n: 611 print real_m.get_leg_i()['id'], real_m.get_leg_j()['id'] 612 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: 613 self.real_amps[m].is_to_integrate = False 614 else: 615 self.real_amps[n].is_to_integrate = False 616 # in case of g(a) > ffx splitting, keep the lowest ij 617 elif i_m == i_n and j_m == j_n and \ 618 not real_m.get_leg_j()['self_antipart'] and \ 619 not real_m.get_leg_i()['self_antipart']: 620 if real_m.fks_infos[0]['ij'] > real_n.fks_infos[0]['ij']: 621 real_m.is_to_integrate = False 622 else: 623 real_n.is_to_integrate = False 624 else: 625 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: 626 self.real_amps[n].is_to_integrate = False 627 else: 628 self.real_amps[m].is_to_integrate = False 629 # self.real_amps[m].is_to_integrate = False 630 elif j_m <= self.nincoming and j_n == j_m: 631 if real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] and \ 632 real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']: 633 if i_m > i_n: 634 self.real_amps[n].is_to_integrate = False 635 else: 636 self.real_amps[m].is_to_integrate = False 637 if remove: 638 newreal_amps = [] 639 for real in self.real_amps: 640 if real.is_to_integrate: 641 newreal_amps.append(real) 642 self.real_amps = newreal_amps 643