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