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 copy 
 29  import logging 
 30  import array 
 31   
 32  logger = logging.getLogger('madgraph.fks_helas_objects') 
 33   
 34   
35 -class FKSHelasMultiProcess(helas_objects.HelasMultiProcess):
36 """class to generate the helas calls for a FKSMultiProcess""" 37
38 - def get_sorted_keys(self):
39 """Return particle property names as a nicely sorted list.""" 40 keys = super(FKSHelasMultiProcess, self).get_sorted_keys() 41 keys += ['real_matrix_elements', ['has_isr'], ['has_fsr']] 42 return keys
43
44 - def filter(self, name, value):
45 """Filter for valid leg property values.""" 46 47 if name == 'real_matrix_elements': 48 if not isinstance(value, helas_objects.HelasMultiProcess): 49 raise self.PhysicsObjectError, \ 50 "%s is not a valid list for real_matrix_element " % str(value)
51
52 - def __init__(self, fksmulti, loop_optimized = False, gen_color =True, decay_ids =[]):
53 """Initialization from a FKSMultiProcess""" 54 55 #swhich the other loggers off 56 loggers_off = [logging.getLogger('madgraph.diagram_generation'), 57 logging.getLogger('madgraph.helas_objects')] 58 old_levels = [logg.level for logg in loggers_off] 59 for logg in loggers_off: 60 logg.setLevel(logging.WARNING) 61 62 self.loop_optimized = loop_optimized 63 64 # generate the real ME's if they are needed. 65 # note that it may not be always the case, e.g. it the NLO_mode is LOonly 66 if fksmulti['real_amplitudes']: 67 logger.info('Generating real emission matrix-elements...') 68 self['real_matrix_elements'] = self.generate_matrix_elements( 69 copy.copy(fksmulti['real_amplitudes']), combine_matrix_elements = False) 70 else: 71 self['real_matrix_elements'] = helas_objects.HelasMatrixElementList() 72 73 self['matrix_elements'] = self.generate_matrix_elements_fks( 74 fksmulti, 75 gen_color, decay_ids) 76 self['initial_states']=[] 77 78 self['has_isr'] = fksmulti['has_isr'] 79 self['has_fsr'] = fksmulti['has_fsr'] 80 self['has_loops'] = len(self.get_virt_matrix_elements()) > 0 81 82 for i, logg in enumerate(loggers_off): 83 logg.setLevel(old_levels[i])
84
85 - def get_used_lorentz(self):
86 """Return a list of (lorentz_name, conjugate, outgoing) with 87 all lorentz structures used by this HelasMultiProcess.""" 88 helas_list = [] 89 for me in self.get('matrix_elements'): 90 helas_list.extend(me.get_used_lorentz()) 91 return list(set(helas_list))
92
93 - def get_used_couplings(self):
94 """Return a list with all couplings used by this 95 HelasMatrixElement.""" 96 coupling_list = [] 97 for me in self.get('matrix_elements'): 98 coupling_list.extend([c for l in me.get_used_couplings() for c in l]) 99 return list(set(coupling_list))
100
101 - def get_matrix_elements(self):
102 """Extract the list of matrix elements""" 103 return self.get('matrix_elements')
104 105
106 - def get_virt_matrix_elements(self):
107 """Extract the list of virtuals matrix elements""" 108 return [me.virt_matrix_element for me in self.get('matrix_elements') \ 109 if me.virt_matrix_element]
110 111
112 - def generate_matrix_elements_fks(self, fksmulti, gen_color = True, 113 decay_ids = []):
114 """Generate the HelasMatrixElements for the amplitudes, 115 identifying processes with identical matrix elements, as 116 defined by HelasMatrixElement.__eq__. Returns a 117 HelasMatrixElementList and an amplitude map (used by the 118 SubprocessGroup functionality). decay_ids is a list of decayed 119 particle ids, since those should not be combined even if 120 matrix element is identical.""" 121 122 fksprocs = fksmulti['born_processes'] 123 assert isinstance(fksprocs, fks_base.FKSProcessList), \ 124 "%s is not valid FKSProcessList" % \ 125 repr(fksprocs) 126 127 # Keep track of already generated color objects, to reuse as 128 # much as possible 129 list_colorize = [] 130 list_color_links =[] 131 list_color_basis = [] 132 list_color_matrices = [] 133 real_me_list = [] 134 me_id_list = [] 135 136 matrix_elements = FKSHelasProcessList() 137 138 for i, proc in enumerate(fksprocs): 139 logger.info("Generating Helas calls for FKS %s (%d / %d)" % \ 140 (proc.born_amp.get('process').nice_string(print_weighted = False).\ 141 replace('Process', 'process'), 142 i + 1, len(fksprocs))) 143 matrix_element_list = [FKSHelasProcess(proc, self['real_matrix_elements'], 144 fksmulti['real_amplitudes'], 145 loop_optimized = self.loop_optimized, 146 decay_ids=decay_ids, 147 gen_color=False)] 148 for matrix_element in matrix_element_list: 149 assert isinstance(matrix_element, FKSHelasProcess), \ 150 "Not a FKSHelasProcess: %s" % matrix_element 151 152 try: 153 # If an identical matrix element is already in the list, 154 # then simply add this process to the list of 155 # processes for that matrix element 156 other = \ 157 matrix_elements[matrix_elements.index(matrix_element)] 158 except ValueError: 159 # Otherwise, if the matrix element has any diagrams, 160 # add this matrix element. 161 if matrix_element.born_matrix_element.get('processes') and \ 162 matrix_element.born_matrix_element.get('diagrams'): 163 matrix_elements.append(matrix_element) 164 165 if not gen_color: 166 continue 167 168 # Always create an empty color basis, and the 169 # list of raw colorize objects (before 170 # simplification) associated with amplitude 171 col_basis = color_amp.ColorBasis() 172 new_amp = matrix_element.born_matrix_element.get_base_amplitude() 173 matrix_element.born_matrix_element.set('base_amplitude', new_amp) 174 colorize_obj = col_basis.create_color_dict_list(new_amp) 175 176 try: 177 # If the color configuration of the ME has 178 # already been considered before, recycle 179 # the information 180 col_index = list_colorize.index(colorize_obj) 181 logger.info(\ 182 "Reusing existing color information for %s" % \ 183 matrix_element.born_matrix_element.get('processes')\ 184 [0].nice_string(print_weighted=False).\ 185 replace('Process', 'process')) 186 except ValueError: 187 # If not, create color basis and color 188 # matrix accordingly 189 list_colorize.append(colorize_obj) 190 col_basis.build() 191 list_color_basis.append(col_basis) 192 col_matrix = color_amp.ColorMatrix(col_basis) 193 list_color_matrices.append(col_matrix) 194 col_index = -1 195 196 logger.info(\ 197 "Processing color information for %s" % \ 198 matrix_element.born_matrix_element.\ 199 get('processes')[0].nice_string(print_weighted=False).\ 200 replace('Process', 'process')) 201 matrix_element.born_matrix_element.set('color_basis', 202 list_color_basis[col_index]) 203 matrix_element.born_matrix_element.set('color_matrix', 204 list_color_matrices[col_index]) 205 else: 206 # this is in order not to handle valueErrors coming from other plaeces, 207 # e.g. from the add_process function 208 other.add_process(matrix_element) 209 210 for me in matrix_elements: 211 me.set_color_links() 212 return matrix_elements
213 214
215 -class FKSHelasProcessList(MG.PhysicsObjectList):
216 """class to handle lists of FKSHelasProcesses""" 217
218 - def is_valid_element(self, obj):
219 """Test if object obj is a valid FKSProcess for the list.""" 220 return isinstance(obj, FKSHelasProcess)
221 222
223 -class FKSHelasProcess(object):
224 """class to generate the Helas calls for a FKSProcess. Contains: 225 -- born ME 226 -- list of FKSHelasRealProcesses 227 -- color links""" 228
229 - def __init__(self, fksproc=None, real_me_list =[], real_amp_list=[], 230 loop_optimized = False, **opts):#test written
231 """ constructor, starts from a FKSProcess, 232 sets reals and color links. Real_me_list and real_amp_list are the lists of pre-genrated 233 matrix elements in 1-1 correspondence with the amplitudes""" 234 235 if fksproc != None: 236 self.born_matrix_element = helas_objects.HelasMatrixElement( 237 fksproc.born_amp, **opts) 238 self.real_processes = [] 239 self.orders = fksproc.born_proc.get('orders') 240 self.perturbation = fksproc.perturbation 241 real_amps_new = [] 242 # combine for example u u~ > t t~ and d d~ > t t~ 243 for proc in fksproc.real_amps: 244 fksreal_me = FKSHelasRealProcess(proc, real_me_list, real_amp_list, **opts) 245 try: 246 other = self.real_processes[self.real_processes.index(fksreal_me)] 247 other.matrix_element.get('processes').extend(\ 248 fksreal_me.matrix_element.get('processes') ) 249 except ValueError: 250 if fksreal_me.matrix_element.get('processes') and \ 251 fksreal_me.matrix_element.get('diagrams'): 252 self.real_processes.append(fksreal_me) 253 real_amps_new.append(proc) 254 fksproc.real_amps = real_amps_new 255 if fksproc.virt_amp: 256 self.virt_matrix_element = \ 257 loop_helas_objects.LoopHelasMatrixElement(fksproc.virt_amp, 258 optimized_output = loop_optimized) 259 else: 260 self.virt_matrix_element = None 261 # self.color_links_info = fksproc.find_color_links() 262 self.color_links = []
263 277
278 - def get_fks_info_list(self):
279 """Returns the list of the fks infos for all processes in the format 280 {n_me, pdgs, fks_info}, where n_me is the number of real_matrix_element the configuration 281 belongs to""" 282 info_list = [] 283 for n, real in enumerate(self.real_processes): 284 pdgs = [l['id'] for l in real.matrix_element.get_base_amplitude()['process']['legs']] 285 for info in real.fks_infos: 286 info_list.append({'n_me' : n + 1,'pdgs' : pdgs, 'fks_info' : info}) 287 return info_list
288 289
290 - def get_lh_pdg_string(self):
291 """Returns the pdgs of the legs in the form "i1 i2 -> f1 f2 ...", which may 292 be useful (eg. to be written in a B-LH order file)""" 293 294 initial = '' 295 final = '' 296 for leg in self.born_matrix_element.get('processes')[0].get('legs'): 297 if leg.get('state'): 298 final += '%d ' % leg.get('id') 299 else: 300 initial += '%d ' % leg.get('id') 301 return initial + '-> ' + final
302 303
304 - def get(self, key):
305 """the get function references to born_matrix_element""" 306 return self.born_matrix_element.get(key)
307
308 - def get_used_lorentz(self):
309 """the get_used_lorentz function references to born, reals 310 and virtual matrix elements""" 311 lorentz_list = self.born_matrix_element.get_used_lorentz() 312 for real in self.real_processes: 313 lorentz_list.extend(real.matrix_element.get_used_lorentz()) 314 if self.virt_matrix_element: 315 lorentz_list.extend(self.virt_matrix_element.get_used_lorentz()) 316 317 return list(set(lorentz_list))
318
319 - def get_used_couplings(self):
320 """the get_used_couplings function references to born, reals 321 and virtual matrix elements""" 322 coupl_list = self.born_matrix_element.get_used_couplings() 323 for real in self.real_processes: 324 coupl_list.extend([c for c in\ 325 real.matrix_element.get_used_couplings()]) 326 if self.virt_matrix_element: 327 coupl_list.extend(self.virt_matrix_element.get_used_couplings()) 328 return coupl_list
329
330 - def get_nexternal_ninitial(self):
331 """the nexternal_ninitial function references to the real emissions if they have been 332 generated, otherwise to the born""" 333 if self.real_processes: 334 (nexternal, ninitial) = self.real_processes[0].matrix_element.get_nexternal_ninitial() 335 else: 336 (nexternal, ninitial) = self.born_matrix_element.get_nexternal_ninitial() 337 nexternal += 1 338 return (nexternal, ninitial)
339
340 - def __eq__(self, other):
341 """the equality between two FKSHelasProcesses is defined up to the 342 color links""" 343 selftag = helas_objects.IdentifyMETag.create_tag(self.born_matrix_element.get('base_amplitude')) 344 othertag = helas_objects.IdentifyMETag.create_tag(other.born_matrix_element.get('base_amplitude')) 345 346 if self.born_matrix_element != other.born_matrix_element or \ 347 selftag != othertag: 348 return False 349 350 reals2 = copy.copy(other.real_processes) 351 for real in self.real_processes: 352 try: 353 reals2.remove(real) 354 except ValueError: 355 return False 356 if not reals2: 357 return True 358 else: 359 return False
360
361 - def add_process(self, other): #test written, ppwj
362 """adds processes from born and reals of other to itself. Note that 363 corresponding real processes may not be in the same order. This is 364 taken care of by constructing the list of self_reals.""" 365 self.born_matrix_element.get('processes').extend( 366 other.born_matrix_element.get('processes')) 367 if self.virt_matrix_element and other.virt_matrix_element: 368 self.virt_matrix_element.get('processes').extend( 369 other.virt_matrix_element.get('processes')) 370 self_reals = [real.matrix_element for real in self.real_processes] 371 for oth_real in other.real_processes: 372 this_real = self.real_processes[self_reals.index(oth_real.matrix_element)] 373 #need to store pdg lists rather than processes in order to keep mirror processes different 374 this_pdgs = [[leg['id'] for leg in proc['legs']] \ 375 for proc in this_real.matrix_element['processes']] 376 for oth_proc in oth_real.matrix_element['processes']: 377 oth_pdgs = [leg['id'] for leg in oth_proc['legs']] 378 if oth_pdgs not in this_pdgs: 379 this_real.matrix_element['processes'].append(oth_proc) 380 this_pdgs.append(oth_pdgs) 381 382 # if p not in self.real_processes[\ 383 # self_reals.index(oth_real.matrix_element)].matrix_element['processes']]) 384 385
386 -class FKSHelasRealProcess(object): #test written
387 """class to generate the Helas calls for a FKSRealProcess 388 contains: 389 -- colors 390 -- charges 391 -- i/j/ij fks, ij refers to the born leglist 392 -- ijglu 393 -- need_color_links 394 -- fks_j_from_i 395 -- matrix element 396 -- is_to_integrate 397 -- leg permutation<<REMOVED""" 398
399 - def __init__(self, fksrealproc=None, real_me_list = [], real_amp_list =[], **opts):
400 """constructor, starts from a fksrealproc and then calls the 401 initialization for HelasMatrixElement. 402 Sets i/j fks and the permutation. 403 real_me_list and real_amp_list are the lists of pre-generated matrix elements in 1-1 404 correspondance with the amplitudes""" 405 406 if fksrealproc != None: 407 self.isfinite = False 408 self.colors = fksrealproc.colors 409 self.charges = fksrealproc.charges 410 self.fks_infos = fksrealproc.fks_infos 411 self.is_to_integrate = fksrealproc.is_to_integrate 412 413 if len(real_me_list) != len(real_amp_list): 414 raise fks_common.FKSProcessError( 415 'not same number of amplitudes and matrix elements: %d, %d' % \ 416 (len(real_amp_list), len(real_me_list))) 417 if real_me_list and real_amp_list: 418 self.matrix_element = copy.deepcopy(real_me_list[real_amp_list.index(fksrealproc.amplitude)]) 419 self.matrix_element['processes'] = copy.deepcopy(self.matrix_element['processes']) 420 else: 421 logger.info('generating matrix element...') 422 self.matrix_element = helas_objects.HelasMatrixElement( 423 fksrealproc.amplitude, **opts) 424 #generate the color for the real 425 self.matrix_element.get('color_basis').build( 426 self.matrix_element.get('base_amplitude')) 427 self.matrix_element.set('color_matrix', 428 color_amp.ColorMatrix( 429 self.matrix_element.get('color_basis'))) 430 #self.fks_j_from_i = fksrealproc.find_fks_j_from_i() 431 self.fks_j_from_i = fksrealproc.fks_j_from_i
432
433 - def get_nexternal_ninitial(self):
434 """Refers to the matrix_element function""" 435 return self.matrix_element.get_nexternal_ninitial()
436
437 - def __eq__(self, other):
438 """Equality operator: 439 compare two FKSHelasRealProcesses by comparing their dictionaries""" 440 return self.__dict__ == other.__dict__
441
442 - def __ne__(self, other):
443 """Inequality operator: 444 compare two FKSHelasRealProcesses by comparing their dictionaries""" 445 return not self.__eq__(other)
446